class StaticGeometricModel(object): """ load an object as a static geometric model -> changing pos, rot, color, etc. are not allowed there is no extra elements for this model, thus is much faster author: weiwei date: 20190312 """ def __init__(self, initor=None, name="defaultname", btransparency=True, btwosided=False): """ :param initor: path type defined by os.path or trimesh or nodepath :param btransparency :param name """ if isinstance(initor, StaticGeometricModel): self._objpath = copy.deepcopy(initor.objpath) self._objtrm = copy.deepcopy(initor.objtrm) self._objpdnp = copy.deepcopy(initor.objpdnp) self._name = copy.deepcopy(initor.name) self._localframe = copy.deepcopy(initor.localframe) else: # make a grandma nodepath to separate decorations (-autoshader) and raw nodepath (+autoshader) self._name = name self._objpdnp = NodePath(name) if isinstance(initor, str): self._objpath = initor self._objtrm = da.trm.load(self._objpath) objpdnp_raw = da.trimesh_to_nodepath(self._objtrm, name='pdnp_raw') objpdnp_raw.reparentTo(self._objpdnp) elif isinstance(initor, da.trm.Trimesh): self._objpath = None self._objtrm = initor objpdnp_raw = da.trimesh_to_nodepath(self._objtrm) objpdnp_raw.reparentTo(self._objpdnp) elif isinstance(initor, o3d.geometry.PointCloud ): # TODO should pointcloud be pdnp or pdnp_raw self._objpath = None self._objtrm = da.trm.Trimesh(np.asarray(initor.points)) objpdnp_raw = da.nodepath_from_points(self._objtrm.vertices, name='pdnp_raw') objpdnp_raw.reparentTo(self._objpdnp) elif isinstance( initor, np.ndarray): # TODO should pointcloud be pdnp or pdnp_raw self._objpath = None if initor.shape[1] == 3: self._objtrm = da.trm.Trimesh(initor) objpdnp_raw = da.nodepath_from_points( self._objtrm.vertices) elif initor.shape[1] == 7: self._objtrm = da.trm.Trimesh(initor[:, :3]) objpdnp_raw = da.nodepath_from_points( self._objtrm.vertices, initor[:, 3:].tolist()) objpdnp_raw.setRenderMode(RenderModeAttrib.MPoint, 3) else: # TODO depth UV? raise NotImplementedError objpdnp_raw.reparentTo(self._objpdnp) elif isinstance(initor, o3d.geometry.TriangleMesh): self._objpath = None self._objtrm = da.trm.Trimesh( vertices=initor.vertices, faces=initor.triangles, face_normals=initor.triangle_normals) objpdnp_raw = da.trimesh_to_nodepath(self._objtrm, name='pdnp_raw') objpdnp_raw.reparentTo(self._objpdnp) elif isinstance(initor, NodePath): self._objpath = None self._objtrm = None # TODO nodepath to trimesh? objpdnp_raw = initor objpdnp_raw.reparentTo(self._objpdnp) else: self._objpath = None self._objtrm = None objpdnp_raw = NodePath("pdnp_raw") objpdnp_raw.reparentTo(self._objpdnp) if btransparency: self._objpdnp.setTransparency(TransparencyAttrib.MDual) if btwosided: self._objpdnp.getChild(0).setTwoSided(True) self._localframe = None @property def name(self): # read-only property return self._name @property def objpath(self): # read-only property return self._objpath @property def objpdnp(self): # read-only property return self._objpdnp @property def objpdnp_raw(self): # read-only property return self._objpdnp.getChild(0) @property def objtrm(self): # read-only property # 20210328 comment out, allow None # if self._objtrm is None: # raise ValueError("Only applicable to models with a trimesh!") return self._objtrm @property def localframe(self): # read-only property return self._localframe @property def volume(self): # read-only property if self._objtrm is None: raise ValueError("Only applicable to models with a trimesh!") return self._objtrm.volume def set_rgba(self, rgba): self._objpdnp.setColor(rgba[0], rgba[1], rgba[2], rgba[3]) def get_rgba(self): return da.pdv4_to_npv4( self._objpdnp.getColor()) # panda3d.core.LColor -> LBase4F def clear_rgba(self): self._objpdnp.clearColor() def set_scale(self, scale=[1, 1, 1]): self._objpdnp.setScale(scale[0], scale[1], scale[2]) self._objtrm.apply_scale(scale) def get_scale(self): return da.pdv3_to_npv3(self._objpdnp.getScale()) def set_vert_size(self, size=.005): self.objpdnp_raw.setRenderModeThickness(size * 1000) def attach_to(self, obj): if isinstance(obj, ShowBase): # for rendering to base.render self._objpdnp.reparentTo(obj.render) elif isinstance(obj, StaticGeometricModel ): # prepared for decorations like local frames self._objpdnp.reparentTo(obj.objpdnp) elif isinstance(obj, mc.ModelCollection): obj.add_gm(self) else: print( "Must be ShowBase, modeling.StaticGeometricModel, GeometricModel, CollisionModel, or CollisionModelCollection!" ) def detach(self): self._objpdnp.detachNode() def remove(self): self._objpdnp.removeNode() def show_localframe(self): self._localframe = gen_frame() self._localframe.attach_to(self) def unshow_localframe(self): if self._localframe is not None: self._localframe.remove() self._localframe = None def copy(self): return copy.deepcopy(self)