Skip to content

Commit bc5ff93

Browse files
committed
update mesh function
1 parent 3988b0b commit bc5ff93

File tree

5 files changed

+194
-27
lines changed

5 files changed

+194
-27
lines changed

docs/npoptix_geometry.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Create, load, update plot
1111
.. automethod:: plotoptix.NpOptiX.update_data_2d
1212
.. automethod:: plotoptix.NpOptiX.set_surface
1313
.. automethod:: plotoptix.NpOptiX.update_surface
14+
.. automethod:: plotoptix.NpOptiX.set_mesh
15+
.. automethod:: plotoptix.NpOptiX.update_mesh
1416
.. automethod:: plotoptix.NpOptiX.load_mesh_obj
1517
.. automethod:: plotoptix.NpOptiX.load_merged_mesh_obj
1618
.. automethod:: plotoptix.NpOptiX.set_displacement

plotoptix/_load_lib.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ def _load_optix_win():
157157
optix.get_geometry_size.argtypes = [c_wchar_p]
158158
optix.get_geometry_size.restype = c_int
159159

160+
optix.get_faces_count.argtypes = [c_wchar_p]
161+
optix.get_faces_count.restype = c_int
162+
160163
optix.get_surface_size.argtypes = [c_wchar_p, POINTER(c_uint), POINTER(c_uint)]
161164
optix.get_surface_size.restype = c_bool
162165

@@ -172,10 +175,10 @@ def _load_optix_win():
172175
optix.setup_psurface.argtypes = [c_wchar_p, c_wchar_p, c_int, c_int, c_void_p, c_void_p, c_void_p, c_bool, c_bool, c_bool]
173176
optix.setup_psurface.restype = c_uint
174177

175-
optix.setup_mesh.argtypes = [c_wchar_p, c_wchar_p, c_int, c_int, c_int, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p]
178+
optix.setup_mesh.argtypes = [c_wchar_p, c_wchar_p, c_int, c_int, c_int, c_int, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p, c_bool]
176179
optix.setup_mesh.restype = c_uint
177180

178-
optix.update_mesh.argtypes = [c_wchar_p, c_int, c_int, c_int, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p]
181+
optix.update_mesh.argtypes = [c_wchar_p, c_int, c_int, c_int, c_int, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p]
179182
optix.update_mesh.restype = c_uint
180183

181184
optix.load_mesh_obj.argtypes = [c_wchar_p, c_wchar_p, c_wchar_p, c_void_p, c_bool]
@@ -663,6 +666,8 @@ def update_geometry(self, name, n_primitives, pos, c, r, u, v, w):
663666

664667
def get_geometry_size(self, name): return self._optix.get_geometry_size(name)
665668

669+
def get_faces_count(self, name): return self._optix.get_faces_count(name)
670+
666671
def get_surface_size(self, name, x_ref, z_ref):
667672
return self._optix.get_surface_size_ptr(name,
668673
IntPtr.__overloads__[Int64](cast(x_ref, c_void_p).value),
@@ -697,21 +702,26 @@ def setup_psurface(self, name, material, u_size, v_size, pos, norm, c, wrap_u, w
697702
IntPtr.__overloads__[Int64](c),
698703
wrap_u, wrap_v, make_normals)
699704

700-
def setup_mesh(self, name, material, n_vtx, n_tri, n_norm, pos, c, vidx, norm, nidx):
701-
return self._optix.setup_mesh_ptr(name, material, n_vtx, n_tri, n_norm,
705+
def setup_mesh(self, name, material, n_vtx, n_tri, n_norm, n_uv, pos, c, vidx, norm, nidx, uvmap, uvidx, make_normals):
706+
return self._optix.setup_mesh_ptr(name, material, n_vtx, n_tri, n_norm, n_uv,
702707
IntPtr.__overloads__[Int64](pos),
703708
IntPtr.__overloads__[Int64](c),
704709
IntPtr.__overloads__[Int64](vidx),
705710
IntPtr.__overloads__[Int64](norm),
706-
IntPtr.__overloads__[Int64](nidx))
711+
IntPtr.__overloads__[Int64](nidx),
712+
IntPtr.__overloads__[Int64](uvmap),
713+
IntPtr.__overloads__[Int64](uvidx),
714+
make_normals)
707715

708-
def update_mesh(self, name, n_vtx, n_tri, n_norm, pos, c, vidx, norm, nidx):
709-
return self._optix.update_mesh_ptr(name, n_vtx, n_tri, n_norm,
716+
def update_mesh(self, name, n_vtx, n_tri, n_norm, n_uv, pos, c, vidx, norm, nidx, uvmap, uvidx):
717+
return self._optix.update_mesh_ptr(name, n_vtx, n_tri, n_norm, n_uv,
710718
IntPtr.__overloads__[Int64](pos),
711719
IntPtr.__overloads__[Int64](c),
712720
IntPtr.__overloads__[Int64](vidx),
713721
IntPtr.__overloads__[Int64](norm),
714-
IntPtr.__overloads__[Int64](nidx))
722+
IntPtr.__overloads__[Int64](nidx),
723+
IntPtr.__overloads__[Int64](uvmap),
724+
IntPtr.__overloads__[Int64](uvidx))
715725

716726
def load_mesh_obj(self, file_name, mesh_name, material, color, make_normals):
717727
return self._optix.load_mesh_obj_ptr(file_name, mesh_name, material,

plotoptix/bin/RnD.SharpOptiX.dll

1 KB
Binary file not shown.

plotoptix/bin/rndSharpOptiX7.dll

0 Bytes
Binary file not shown.

plotoptix/npoptix.py

Lines changed: 174 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3863,29 +3863,29 @@ def set_mesh(self, name: str, pos: Any, faces: Any,
38633863
make_normals: bool = False) -> None:
38643864
"""Create new mesh geometry.
38653865
3866-
Data is provided in form of arrays: vertices :math:`[x, y, z]`, with the shape
3867-
``(n, 3)``, and faces (triplets of vertex indices), with the shape ``(n, 3)``
3868-
or ``(m)`` where ``m = 3*n``. Data features can be visualized with color (array
3869-
of RGB values assigned to the mesh vertices, shape ``(n, 3)``).
3870-
3871-
Mesh ``normals`` can be provided as an array of 3D vectors. Mappng of normals to
3872-
faces can be provided as an array of ``nidx`` indexes. If mapping is not provided
3873-
then face vertex data is used (requires same number of vertices and normal vectors).
3874-
3875-
Smooth shading normals can be pre-calculated if ``make_normals=True`` and normals
3876-
data is not provided.
3877-
3878-
Texture UV mapping ``uvmap`` can be provided as an array of 2D vectors. Mappng of
3879-
UV coordinates to faces can be provided as an array of ``uvidx`` indexes. If mapping
3880-
is not provided then face vertex data is used (requires same number of vertices
3881-
and UV points).
3882-
3866+
Data is provided as vertices :math:`[x, y, z]`, with the shape ``(n, 3)``, and faces
3867+
(triplets of vertex indices), with the shape ``(n, 3)`` or ``(m)`` where :math:`m = 3*n`.
3868+
Data features can be visualized with color (array of RGB values assigned to the mesh
3869+
vertices, shape ``(n, 3)``).
3870+
3871+
Mesh ``normals`` can be provided as an array of 3D vectors. Mappng of normals to
3872+
faces can be provided as an array of ``nidx`` indexes. If mapping is not provided
3873+
then face vertex data is used (requires same number of vertices and normal vectors).
3874+
3875+
Smooth shading normals can be pre-calculated if ``make_normals=True`` and normals
3876+
data is not provided.
3877+
3878+
Texture UV mapping ``uvmap`` can be provided as an array of 2D vectors. Mappng of
3879+
UV coordinates to faces can be provided as an array of ``uvidx`` indexes. If mapping
3880+
is not provided then face vertex data is used (requires same number of vertices
3881+
and UV points).
3882+
38833883
Parameters
38843884
----------
38853885
name : string
38863886
Name of the new surface geometry.
38873887
pos : array_like
3888-
XYZ values of mesh vertices.
3888+
XYZ values of the mesh vertices.
38893889
faces : array_like
38903890
Mesh faces as indices (triplets) to the ``pos`` array.
38913891
c : Any, optional
@@ -3999,7 +3999,7 @@ def set_mesh(self, name: str, pos: Any, faces: Any,
39993999
self._logger.info("...done, handle: %d", g_handle)
40004000
self.geometry_names[g_handle] = name
40014001
self.geometry_handles[name] = g_handle
4002-
self.geometry_sizes[name] = pos.shape[0] * pos.shape[1]
4002+
self.geometry_sizes[name] = n_vertices
40034003
else:
40044004
msg = "Mesh setup failed."
40054005
self._logger.error(msg)
@@ -4011,6 +4011,161 @@ def set_mesh(self, name: str, pos: Any, faces: Any,
40114011
finally:
40124012
self._padlock.release()
40134013

4014+
def update_mesh(self, name: str,
4015+
pos: Optional[Any] = None,
4016+
faces: Optional[Any] = None,
4017+
c: Optional[Any] = None,
4018+
normals: Optional[Any] = None,
4019+
nidx: Optional[Any] = None,
4020+
uvmap: Optional[Any] = None,
4021+
uvidx: Optional[Any] = None) -> None:
4022+
"""Update data of an existing mesh geometry.
4023+
4024+
All data or only some of arrays may be uptated. If vertices and faces are left
4025+
unchanged then other arrays sizes should match the sizes of the mesh, i.e. ``c``
4026+
shape should match existing ``pos`` shape, ``nidx`` and ``uvidx`` shapes should
4027+
match ``faces`` shape or if index mapping is not provided then ``normals`` and
4028+
``uvmap`` shapes should match ``pos`` shape.
4029+
4030+
Parameters
4031+
----------
4032+
name : string
4033+
Name of the new surface geometry.
4034+
pos : array_like, optional
4035+
XYZ values of the mesh vertices.
4036+
faces : array_like, optional
4037+
Mesh faces as indices (triplets) to the ``pos`` array.
4038+
c : Any, optional
4039+
Colors of mesh vertices. Single value means a constant gray level.
4040+
3-component array means a constant RGB color. Array of the shape
4041+
``(n, 3)`` will set individual color for each vertex,
4042+
interpolated on face surfaces; ``n`` has to be equal to the vertex
4043+
number in ``pos`` array.
4044+
normals : array_like, optional
4045+
Normal vectors.
4046+
nidx : array_like, optional
4047+
Normal to face mapping, existing mesh ``faces`` is used if not provided.
4048+
uvmap : array_like, optional
4049+
Texture UV coordinates.
4050+
uvidx : array_like, optional
4051+
Texture UV to face mapping, existing mesh ``faces`` is used if not provided.
4052+
"""
4053+
4054+
if name is None: raise ValueError()
4055+
if not isinstance(name, str): name = str(name)
4056+
4057+
4058+
if not name in self.geometry_handles:
4059+
msg = "Mesh %s does not exists yet, use set_mesh() instead." % name
4060+
self._logger.error(msg)
4061+
if self._raise_on_error: raise ValueError(msg)
4062+
return
4063+
4064+
m_vertices = self._optix.get_geometry_size(name)
4065+
m_faces = self._optix.get_faces_count(name)
4066+
size_changed = False
4067+
4068+
pos_ptr = 0
4069+
n_vertices = 0
4070+
if pos is not None:
4071+
if not isinstance(pos, np.ndarray): pos = np.ascontiguousarray(pos, dtype=np.float32)
4072+
assert len(pos.shape) == 2 and pos.shape[0] > 2 and pos.shape[1] == 3, "Required vertex data shape is (n,3), where n >= 3."
4073+
if pos.dtype != np.float32: pos = np.ascontiguousarray(pos, dtype=np.float32)
4074+
if not pos.flags['C_CONTIGUOUS']: pos = np.ascontiguousarray(pos, dtype=np.float32)
4075+
if pos.shape[0] != m_vertices: size_changed = True
4076+
pos_ptr = pos.ctypes.data
4077+
n_vertices = pos.shape[0]
4078+
m_vertices = n_vertices
4079+
4080+
faces_ptr = 0
4081+
n_faces = 0
4082+
if faces is not None:
4083+
if not isinstance(faces, np.ndarray): faces = np.ascontiguousarray(faces, dtype=np.int32)
4084+
if faces.dtype != np.int32: faces = np.ascontiguousarray(faces, dtype=np.int32)
4085+
if not faces.flags['C_CONTIGUOUS']: faces = np.ascontiguousarray(faces, dtype=np.int32)
4086+
assert (len(faces.shape) == 2 and faces.shape[1] == 3) or (len(faces.shape) == 1 and (faces.shape[0] % 3 == 0)), "Required index shape is (n,3) or (m), where m is a multiple of 3."
4087+
faces_ptr = faces.ctypes.data
4088+
n_faces = faces.size // 3
4089+
m_faces = n_faces
4090+
4091+
c_ptr = 0
4092+
c_const = None
4093+
if size_changed and c is None: c = np.ascontiguousarray([0.94, 0.94, 0.94], dtype=np.float32)
4094+
if c is not None:
4095+
if isinstance(c, float) or isinstance(c, int): c = np.full(3, c, dtype=np.float32)
4096+
if not isinstance(c, np.ndarray): c = np.ascontiguousarray(c, dtype=np.float32)
4097+
if len(c.shape) == 1 and c.shape[0] == 3:
4098+
c_const = c
4099+
cm = np.zeros((m_vertices, 3), dtype=np.float32)
4100+
cm[:,:] = c
4101+
c = cm
4102+
assert c.shape[0] == m_vertices, "Colors shape must be (n,3), with n matching the number of mesh vertices."
4103+
if c.dtype != np.float32: c = np.ascontiguousarray(c, dtype=np.float32)
4104+
if not c.flags['C_CONTIGUOUS']: c = np.ascontiguousarray(c, dtype=np.float32)
4105+
c_ptr = c.ctypes.data
4106+
4107+
n_ptr = 0
4108+
n_normals = 0
4109+
if normals is not None:
4110+
if not isinstance(normals, np.ndarray): normals = np.ascontiguousarray(normals, dtype=np.float32)
4111+
if nidx is None:
4112+
assert normals.shape[0] == m_vertices, "If normal index data not provided, normals shape must be (n,3), with n matching the mesh vertex positions shape."
4113+
else:
4114+
assert len(normals.shape) == 2 and normals.shape[0] > 2 and normals.shape[1] == 3, "Required normals data shape is (n,3), where n >= 3."
4115+
if normals.dtype != np.float32: normals = np.ascontiguousarray(normals, dtype=np.float32)
4116+
if not normals.flags['C_CONTIGUOUS']: normals = np.ascontiguousarray(normals, dtype=np.float32)
4117+
n_ptr = normals.ctypes.data
4118+
n_normals = normals.shape[0]
4119+
make_normals = False
4120+
4121+
nidx_ptr = 0
4122+
if nidx is not None:
4123+
if not isinstance(nidx, np.ndarray): nidx = np.ascontiguousarray(nidx, dtype=np.int32)
4124+
if nidx.dtype != np.int32: nidx = np.ascontiguousarray(nidx, dtype=np.int32)
4125+
if not nidx.flags['C_CONTIGUOUS']: nidx = np.ascontiguousarray(nidx, dtype=np.int32)
4126+
assert (len(nidx.shape) == 2 and nidx.shape[0] == m_faces) or (len(nidx.shape) == 1 and nidx.shape[0] == 3 * m_faces), "Required same shape of normal index and face index arrays."
4127+
nidx_ptr = nidx.ctypes.data
4128+
4129+
uv_ptr = 0
4130+
n_uv = 0
4131+
if uvmap is not None:
4132+
if not isinstance(uvmap, np.ndarray): uvmap = np.ascontiguousarray(uvmap, dtype=np.float32)
4133+
if uvidx is None:
4134+
assert uvmap.shape[0] == m_vertices, "If UV index data not provided, uvmap shape must be (n,2), with n matching the number of mesh vertices."
4135+
else:
4136+
assert len(uvmap.shape) == 2 and uvmap.shape[0] > 2 and uvmap.shape[1] == 2, "Required UV data shape is (n,2), where n >= 3."
4137+
if uvmap.dtype != np.float32: uvmap = np.ascontiguousarray(uvmap, dtype=np.float32)
4138+
if not uvmap.flags['C_CONTIGUOUS']: uvmap = np.ascontiguousarray(uvmap, dtype=np.float32)
4139+
uv_ptr = uvmap.ctypes.data
4140+
n_uv = uvmap.shape[0]
4141+
4142+
uvidx_ptr = 0
4143+
if uvidx is not None:
4144+
if not isinstance(uvidx, np.ndarray): uvidx = np.ascontiguousarray(uvidx, dtype=np.int32)
4145+
if uvidx.dtype != np.int32: uvidx = np.ascontiguousarray(uvidx, dtype=np.int32)
4146+
if not uvidx.flags['C_CONTIGUOUS']: uvidx = np.ascontiguousarray(uvidx, dtype=np.int32)
4147+
assert (len(uvidx.shape) == 2 and uvidx.shape[0] == m_faces) or (len(uvidx.shape) == 1 and uvidx.shape[0] == 3 * m_faces), "Required same shape of UV index and face index arrays."
4148+
uvidx_ptr = uvidx.ctypes.data
4149+
4150+
try:
4151+
self._padlock.acquire()
4152+
self._logger.info("Update mesh %s...", name)
4153+
g_handle = self._optix.update_mesh(name, n_vertices, n_faces, n_normals, n_uv, pos_ptr, faces_ptr, c_ptr, n_ptr, nidx_ptr, uv_ptr, uvidx_ptr)
4154+
4155+
if (g_handle > 0) and (g_handle == self.geometry_handles[name]):
4156+
self._logger.info("...done, handle: %d", g_handle)
4157+
self.geometry_sizes[name] = m_vertices
4158+
else:
4159+
msg = "Mesh update failed."
4160+
self._logger.error(msg)
4161+
if self._raise_on_error: raise RuntimeError(msg)
4162+
4163+
except Exception as e:
4164+
self._logger.error(str(e))
4165+
if self._raise_on_error: raise
4166+
finally:
4167+
self._padlock.release()
4168+
40144169

40154170
def load_mesh_obj(self, file_name: str, mesh_name: Optional[str] = None,
40164171
c: Any = np.ascontiguousarray([0.94, 0.94, 0.94], dtype=np.float32),

0 commit comments

Comments
 (0)