def loadImageAsPlane(self, filepath, yresolution = 600): tex = loader.loadTexture(filepath) # @UndefinedVariable tex.setBorderColor(Vec4(0,0,0,0)) tex.setWrapU(Texture.WMBorderColor) tex.setWrapV(Texture.WMBorderColor) cm = CardMaker(filepath + ' card') cm.setFrame(-tex.getOrigFileXSize(), tex.getOrigFileXSize(), -tex.getOrigFileYSize(), tex.getOrigFileYSize()) card = NodePath(cm.generate()) card.setTexture(tex) card.setScale(card.getScale()/ yresolution) card.flattenLight() # apply scale return card
def loadImageAsPlane(filepath, yresolution = 600): tex = loader.loadTexture(filepath) tex.setBorderColor(Vec4(0,0,0,0)) tex.setWrapU(Texture.WMBorderColor) tex.setWrapV(Texture.WMBorderColor) cm = CardMaker(filepath + ' card') cm.setFrame(-tex.getOrigFileXSize(), tex.getOrigFileXSize(), -tex.getOrigFileYSize(), tex.getOrigFileYSize()) card = NodePath(cm.generate()) card.setTransparency(TransparencyAttrib.MAlpha) card.setTexture(tex) card.setZ(card.getZ()+0.018) card.setScale(card.getScale()/ yresolution) card.flattenLight() # apply scale return card
def test_door_setup(self): parent_np = NodePath('parent_np') parent_np.setPosHpr(0, 10, .5, 180, 0, 0) door_origin = parent_np.attachNewNode('door_origin') door_origin.setPos(10, -25, .5) block = 4 color = Vec4(.842, .167, .361, 1) # Set up door_np nodes door_np = NodePath('door_np') left_hole = door_np.attachNewNode('door_0_hole_left') right_hole = door_np.attachNewNode('door_0_hole_right') left_door = door_np.attachNewNode('door_0_left') right_door = door_np.attachNewNode('door_0_right') door_flat = door_np.attachNewNode('door_0_flat') door_trigger = door_np.attachNewNode('door_0_trigger') DNADoor.setupDoor(door_np, parent_np, door_origin, self.store, block, color) # Check if the nodes attributes and parents are correct self.assertEqual(door_np.getPos(door_origin), Point3(0, 0, 0)) self.assertEqual(door_np.getHpr(door_origin), Point3(0, 0, 0)) self.assertEqual(door_np.getScale(door_origin), Point3(1, 1, 1)) def verify_color(color1, color2): self.assertAlmostEqual(color1.getX(), color2.getX(), places=4) self.assertAlmostEqual(color1.getY(), color2.getY(), places=4) self.assertAlmostEqual(color1.getZ(), color2.getZ(), places=4) self.assertAlmostEqual(color1.getW(), color2.getW(), places=4) verify_color(color, door_np.getColor()) self.assertEqual(left_hole.getParent(), door_flat) self.assertEqual(left_hole.getName(), 'doorFrameHoleLeft') self.assertEqual(right_hole.getParent(), door_flat) self.assertEqual(right_hole.getName(), 'doorFrameHoleRight') self.assertEqual(left_door.getParent(), parent_np) self.assertEqual(left_door.getName(), 'leftDoor') verify_color(color, right_door.getColor()) self.assertEqual(right_door.getParent(), parent_np) self.assertEqual(right_door.getName(), 'rightDoor') verify_color(color, right_door.getColor()) self.assertEqual(door_trigger.getParent(), parent_np) self.assertEqual(door_trigger.getName(), 'door_trigger_%d' % block) store_np = self.store.getDoorPosHprFromBlockNumber(block) self.assertFalse(store_np.isEmpty()) # Testing the pos is a pain because of decimal precision pos = store_np.getPos() self.assertAlmostEqual(pos.getX(), -10, places=2) self.assertAlmostEqual(pos.getY(), 35, places=2) self.assertAlmostEqual(pos.getZ(), 1, places=2) # Sometimes getH() returns -180 and others 180 # Test the modulus (better than abs I guess) self.assertEqual(store_np.getH() % 180, 0)
class Transform(Component): """Each game object has exactly one of these. A transform holds data about position, rotation, scale and parent relationship. In Panity this is a wrapper for a NodePath. """ def __init__(self, game_object, name): # Component class sets self.game_object = game_object Component.__init__(self, game_object) self.node = NodePath(name) self.node.setPythonTag("transform", self) @classmethod def getClassSerializedProperties(cls): """Return all special property attributes in a dict. Only attributes derived from SerializedProperty are respected. On transform component this method always returns local position, -rotation and scale only. """ d = {} d["local_position"] = Transform.local_position d["local_euler_angles"] = Transform.local_euler_angles d["local_scale"] = Transform.local_scale return d def getSerializedProperties(self): """Return all properties for serialization. In the case of transform this only returns local position, -rotation and -scale, which are required to restore the state of the node. """ d = {} d["local_position"] = self.local_position d["local_euler_angles"] = self.local_euler_angles d["local_scale"] = self.local_scale return d # We use the panda node to save the name on it for better debugging and # efficient finding of nodes with NodePath().find() @SerializedPropertyDecorator def name(self): return self.node.getName() @name.setter def name(self, name): if name == "render": name = "_render" self.node.setName(name) @SerializedPropertyDecorator def position(self): return self.node.getPos(self.root.node) @position.setter def position(self, position): self.node.setPos(self.root.node, *position) @SerializedPropertyDecorator def local_position(self): return self.node.getPos() @local_position.setter def local_position(self, position): self.node.setPos(*position) @SerializedPropertyDecorator def euler_angles(self): return self.node.getHpr(self.root.node) @euler_angles.setter def euler_angles(self, angles): self.node.setHpr(self.root.node, *angles) @SerializedPropertyDecorator def local_euler_angles(self): return self.node.getHpr() @local_euler_angles.setter def local_euler_angles(self, angles): self.node.setHpr(*angles) @SerializedPropertyDecorator def rotation(self): return self.node.getQuat(self.root.node) @rotation.setter def rotation(self, quaternion): self.node.setQuat(self.root.node, *quaternion) @SerializedPropertyDecorator def local_rotation(self): return self.node.getQuat() @local_rotation.setter def local_rotation(self, quaternion): self.node.setQuat(*quaternion) @SerializedPropertyDecorator def local_scale(self): return self.node.getScale() @local_scale.setter def local_scale(self, scale): self.node.setScale(*scale) @SerializedPropertyDecorator def parent(self): p = self.node.getParent() if p.isEmpty() or p.getName() == "render": return self elif p.hasPythonTag("transform"): return p.getPythonTag("transform") @parent.setter def parent(self, parent): self.node.wrtReparentTo(parent.node) @SerializedPropertyDecorator def root(self): if self.parent is not self: return self.parent.root() else: return self def destroy(self): """Ultimately remove this transform. Warning: this might cause errors for other components on this game object. Use this only when removing the whole GameObject. """ self.node.removeNode() def getChildren(self): """Return children as Transforms.""" # this requires the __iter__() method return [c for c in self] def __iter__(self): """Iterate over children nodes and yield the transform instances.""" for child in self.node.getChildren(): if child.hasPythonTag("transform"): yield child.getPythonTag("transform") def __str__(self): r = "Transform for '{}'\n".format(self.name) r += "local position: {}\n".format(self.local_position) r += "local rotation: {}\n".format(self.local_euler_angles) r += "local scale: {}\n".format(self.local_scale) return r
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)
class MapObject(MapWritable): ObjectName = "object" def __init__(self, id): MapObjectInit.start() MapWritable.__init__(self, base.document) self.temporary = False self.id = id self.selected = False self.classname = "" self.parent = None self.children = {} self.boundingBox = BoundingBox(Vec3(-0.5, -0.5, -0.5), Vec3(0.5, 0.5, 0.5)) self.boundsBox = Box() self.boundsBox.addView(GeomView.Lines, VIEWPORT_3D_MASK, state = BoundsBox3DState) self.boundsBox.addView(GeomView.Lines, VIEWPORT_2D_MASK, state = BoundsBox2DState) self.boundsBox.generateGeometry() self.collNp = None self.group = None self.properties = {} # All MapObjects have transform self.addProperty(OriginProperty(self)) self.addProperty(AnglesProperty(self)) self.addProperty(ScaleProperty(self)) self.addProperty(ShearProperty(self)) self.np = NodePath(ModelNode(self.ObjectName + ".%i" % self.id)) self.np.setPythonTag("mapobject", self) self.applyCollideMask() # Test bounding volume at this node and but nothing below it. self.np.node().setFinal(True) MapObjectInit.stop() def getClassName(self): return self.classname def isWorld(self): return False def r_findAllParents(self, parents, type): if not self.parent or self.parent.isWorld(): return if type is None or isinstance(self.parent, type): parents.append(self.parent) self.parent.r_findAllParents(parents, type) def findAllParents(self, type = None): parents = [] self.r_findAllParents(parents, type) return parents def findTopmostParent(self, type = None): parents = self.findAllParents(type) if len(parents) == 0: return None return parents[len(parents) - 1] def r_findAllChildren(self, children, type): for child in self.children.values(): if type is None or isinstance(child, type): children.append(child) child.r_findAllChildren(children, type) def findAllChildren(self, type = None): children = [] self.r_findAllChildren(children, type) return children def applyCollideMask(self): self.np.setCollideMask(LEGlobals.ObjectMask) def setTemporary(self, flag): self.temporary = flag # Returns the bounding volume of the object itself, not including children objects. def getObjBounds(self, other = None): if not other: other = self.np.getParent() return self.np.getTightBounds(other) # Returns the min and max points of the bounds of the object, not including children. def getBounds(self, other = None): if not other: other = self.np.getParent() mins = Point3() maxs = Point3() self.np.calcTightBounds(mins, maxs, other) return [mins, maxs] def findChildByID(self, id): if id == self.id: return self if id in self.children: return self.children[id] for child in self.children.values(): ret = child.findChildByID(id) if ret is not None: return ret return None def hasChildWithID(self, id): return id in self.children def copy(self, generator): raise NotImplementedError def paste(self, o, generator): raise NotImplementedError def clone(self): raise NotImplementedError def unclone(self, o): raise NotImplementedError # # Base copy and paste functions shared by all MapObjects. # Each specific MapObject must implement the functions above for their # specific functionality. # def copyProperties(self, props): newProps = {} for key, prop in props.items(): newProp = prop.clone(self) newProp.setValue(prop.getValue()) newProps[key] = newProp self.updateProperties(newProps) def copyBase(self, other, generator, clone = False): if clone and other.id != self.id: parent = other.parent setPar = other.parent is not None and other.parent.hasChildWithID(other.id) and other.parent.children[other.id] == other if setPar: other.reparentTo(NodePath()) other.id = self.id if setPar: other.reparentTo(parent) other.parent = self.parent for child in self.children.values(): if clone: newChild = child.clone() else: newChild = child.copy(generator) newChild.reparentTo(other) other.setClassname(self.classname) other.copyProperties(self.properties) other.selected = self.selected def pasteBase(self, o, generator, performUnclone = False): if performUnclone and o.id != self.id: parent = self.parent setPar = self.parent is not None and self.parent.hasChildWithID(self.id) and self.parent.children[self.id] == self if setPar: self.reparentTo(NodePath()) self.id = o.id if setPar: self.reparentTo(parent) for child in o.children.values(): if performUnclone: newChild = child.clone() else: newChild = child.copy(generator) newChild.reparentTo(self) self.setClassname(o.classname) self.copyProperties(o.properties) self.selected = o.selected def getName(self): return "Object" def getDescription(self): return "Object in a map." def addProperty(self, prop): self.properties[prop.name] = prop # Returns list of property names with the specified value types. def getPropsWithValueType(self, types): if isinstance(types, str): types = [types] props = [] for propName, prop in self.properties.items(): if prop.valueType in types: props.append(propName) return props def getPropNativeType(self, key): prop = self.properties.get(key, None) if not prop: return str return prop.getNativeType() def getPropValueType(self, key): prop = self.properties.get(key, None) if not prop: return "string" return prop.valueType def getPropDefaultValue(self, prop): if isinstance(prop, str): prop = self.properties.get(prop, None) if not prop: return "" return prop.defaultValue def getPropertyValue(self, key, asString = False, default = ""): prop = self.properties.get(key, None) if not prop: return default if asString: return prop.getSerializedValue() else: return prop.getValue() def getProperty(self, name): return self.properties.get(name, None) def updateProperties(self, data): for key, value in data.items(): if not isinstance(value, ObjectProperty): # If only a value was specified and not a property object itself, # this is an update to an existing property. prop = self.properties.get(key, None) if not prop: continue oldValue = prop.getValue() val = prop.getUnserializedValue(value) # If the property has a min/max range, ensure the value we want to # set is within that range. if (not prop.testMinValue(val)) or (not prop.testMaxValue(val)): # Not within range. Use the default value val = prop.defaultValue prop.setValue(val) else: # A property object was given, simply add it to the dict of properties. prop = value oldValue = None val = prop.getValue() self.properties[prop.name] = prop self.propertyChanged(prop, oldValue, val) def propertyChanged(self, prop, oldValue, newValue): if oldValue != newValue: self.send('objectPropertyChanged', [self, prop, newValue]) def setAbsOrigin(self, origin): self.np.setPos(base.render, origin) self.transformChanged() def setOrigin(self, origin): self.np.setPos(origin) self.transformChanged() def getAbsOrigin(self): return self.np.getPos(base.render) def getOrigin(self): return self.np.getPos() def setAngles(self, angles): self.np.setHpr(angles) self.transformChanged() def setAbsAngles(self, angles): self.np.setHpr(base.render, angles) self.transformChanged() def getAbsAngles(self): return self.np.getHpr(base.render) def getAngles(self): return self.np.getHpr() def setScale(self, scale): self.np.setScale(scale) self.transformChanged() def setAbsScale(self, scale): self.np.setScale(base.render, scale) self.transformChanged() def getAbsScale(self): return self.np.getScale(base.render) def getScale(self): return self.np.getScale() def setShear(self, shear): self.np.setShear(shear) self.transformChanged() def setAbsShear(self, shear): self.np.setShear(base.render, shear) self.transformChanged() def getAbsShear(self): return self.np.getShear(base.render) def getShear(self): return self.np.getShear() def transformChanged(self): self.recalcBoundingBox() self.send('objectTransformChanged', [self]) def showBoundingBox(self): self.boundsBox.np.reparentTo(self.np) def hideBoundingBox(self): self.boundsBox.np.reparentTo(NodePath()) def select(self): self.selected = True self.showBoundingBox() #self.np.setColorScale(1, 0, 0, 1) def deselect(self): self.selected = False self.hideBoundingBox() #self.np.setColorScale(1, 1, 1, 1) def setClassname(self, classname): self.classname = classname def fixBounds(self, mins, maxs): # Ensures that the bounds are not flat on any axis sameX = mins.x == maxs.x sameY = mins.y == maxs.y sameZ = mins.z == maxs.z invalid = False if sameX: # Flat horizontal if sameY and sameZ: invalid = True elif not sameY: mins.x = mins.y maxs.x = maxs.y elif not sameZ: mins.x = mins.z maxs.x = maxs.z if sameY: # Flat forward/back if sameX and sameZ: invalid = True elif not sameX: mins.y = mins.x maxs.y = maxs.x elif not sameZ: mins.y = mins.z maxs.y = maxs.z if sameZ: if sameX and sameY: invalid = True elif not sameX: mins.z = mins.x maxs.z = maxs.x elif not sameY: mins.z = mins.y maxs.z = maxs.y return [invalid, mins, maxs] def recalcBoundingBox(self): if not self.np: return # Don't have the picker box or selection visualization contribute to the # calculation of the bounding box. if self.collNp: self.collNp.stash() self.hideBoundingBox() # Calculate a bounding box relative to ourself mins, maxs = self.getBounds(self.np) invalid, mins, maxs = self.fixBounds(mins, maxs) if invalid: mins = Point3(-8) maxs = Point3(8) self.boundingBox = BoundingBox(mins, maxs) self.boundsBox.setMinMax(mins, maxs) if self.selected: self.showBoundingBox() if self.collNp: self.collNp.unstash() self.collNp.node().clearSolids() self.collNp.node().addSolid(CollisionBox(mins, maxs)) self.collNp.hide(~VIEWPORT_3D_MASK) self.send('mapObjectBoundsChanged', [self]) def removePickBox(self): if self.collNp: self.collNp.removeNode() self.collNp = None def delete(self): if not self.temporary: # Take the children with us for child in list(self.children.values()): child.delete() self.children = None # if we are selected, deselect base.selectionMgr.deselect(self) if self.boundsBox: self.boundsBox.cleanup() self.boundsBox = None self.removePickBox() if not self.temporary: self.reparentTo(NodePath()) self.np.removeNode() self.np = None self.properties = None self.metaData = None self.temporary = None def __clearParent(self): if self.parent: self.parent.__removeChild(self) self.np.reparentTo(NodePath()) self.parent = None def __setParent(self, other): if isinstance(other, NodePath): # We are reparenting directly to a NodePath, outside of the MapObject tree. self.parent = None self.np.reparentTo(other) else: self.parent = other if self.parent: self.parent.__addChild(self) self.np.reparentTo(self.parent.np) else: # If None was passed, assume base.render self.np.reparentTo(base.render) def reparentTo(self, other): # If a NodePath is passed to this method, the object will be placed under the specified node # in the Panda3D scene graph, but will be taken out of the MapObject tree. If None is passed, # the object will be parented to base.render and taken out of the MapObject tree. # # Use reparentTo(NodePath()) to place the object outside of both the scene graph and the # MapObject tree. self.__clearParent() self.__setParent(other) def __addChild(self, child): self.children[child.id] = child #self.recalcBoundingBox() def __removeChild(self, child): if child.id in self.children: del self.children[child.id] #self.recalcBoundingBox() def doWriteKeyValues(self, parent): kv = CKeyValues(self.ObjectName, parent) self.writeKeyValues(kv) for child in self.children.values(): child.doWriteKeyValues(kv) def writeKeyValues(self, keyvalues): keyvalues.setKeyValue("id", str(self.id)) # Write out our object properties for name, prop in self.properties.items(): prop.writeKeyValues(keyvalues) def readKeyValues(self, keyvalues): for i in range(keyvalues.getNumKeys()): key = keyvalues.getKey(i) value = keyvalues.getValue(i) if MetaData.isPropertyExcluded(key): continue # Find the property with this name. prop = self.properties.get(key, None) if not prop: # Prop wasn't explicit or part of FGD metadata (if it's an Entity) continue nativeValue = prop.getUnserializedValue(value) # Set the value! self.updateProperties({prop.name: nativeValue})
class FaceDetection(DirectObject): def __init__(self): #Muestra un texto en pantalla, utilizando la interfaz 2D de Panda3D. #Posteriormente se actualizara con otros datos, por eso se mantiene la referencia self.title = OnscreenText(text="prueba 1", style=1, fg=(0,0,0,1), pos=(0.8,-0.95), scale = .07) #Lee los datos de configuracion de los clasificadores HAAR. En este caso, para deteccion de rostros en posicion frontal self.cascade = cv.Load("haarcascades\\haarcascade_frontalface_alt.xml") #Utiliza por defecto la camara para obtener las imagenes, y no guarda un archivo self.cameraHelper = CameraHelper(True, False, "d:\\face-detection.avi") #Crea una textura para utilizar como fondo, donde se mostraran las imagenes de video #CardMaker en realidad es un poligono rectangular, que es util para asociarlo al renderer2D, ya que #podremos hacer que ocupe toda la pantalla y mostrar nuestras imagenes como fondo. self.cardMaker = CardMaker("My Fullscreen Card"); self.cardMaker.setFrameFullscreenQuad() #Agrega el rectangulo al renderer render2dp. Asi como existe render2d, existe uno adicional que es utilizado #en general para casos donde necesita mostrarse un fondo, sea estatico o de video. El render2d estandar, #por el contrario, se usa para mostrar informacion al usuario que siempre debe ser visible self.card = NodePath(self.cardMaker.generate()) self.card.reparentTo(render2dp) #Le da baja prioridad para que los objetos dibujados posteriormente siempre se vean sobre ella base.cam2dp.node().getDisplayRegion(0).setSort(-20) #Crea un rectangulo que se utilizara para mostrar la imagen superpuesta sobre la cara self.faceMaker = CardMaker("Face Texture"); self.faceImage = NodePath(self.faceMaker.generate()) self.faceImage.setTexture(loader.loadTexture("margarita-glass3.png")) self.faceImage.reparentTo(aspect2d) #self.faceImage.reparentTo(render2d) self.faceImage.setTransparency(TransparencyAttrib.MAlpha) self.setup_handlers() self.setup_lights() self.count = 0 #Establece un fondo negro #base.setBackgroundColor(0, 0, 0) #Carga el objeto tetera (incluido con Panda3D), y lo ubica en el mundo #self.teapot = loader.loadModel('models/teapot') #self.teapot.reparentTo(base.render) #self.teapot.setPos(-10, -10, -10) #Coloca la camara en el origen de coordenadas, y hace que apunte hacia la tetera #camera.setPos(0, 0, 0) #camera.lookAt(-10, -10, -10) taskMgr.add(self.onFrameChanged, "frameChange") def exitApplication(self): self.cameraHelper = None sys.exit() def setup_handlers(self): #Deshabilita el manejo por defecto del mouse base.disableMouse() #Agrega un gestor que al recibir el mensaje de que se presiono ESC, sale del programa self.accept("escape", self.exitApplication) def setup_lights(self): #Crea una luz ambiente, para que los objetos tengan una iluminacion base por defecto self.ambientLight = AmbientLight("ambientLight") self.ambientLight.setColor(Vec4(.8, .8, .75, 1)) render.setLight(render.attachNewNode(self.ambientLight)) #Crea una luz direccional, que va a permitir destacar la profundidad de los objetos self.directionalLight = DirectionalLight("directionalLight") self.directionalLight.setDirection(Vec3(0, 0, -2.5)) self.directionalLight.setColor(Vec4(0.9, 0.8, 0.9, 1)) render.setLight(render.attachNewNode(self.directionalLight)) def onFrameChanged(self, task): #Captura un cuadro del origen indicado image = self.cameraHelper.captureFrame() #Si no quedan imagenes para mostrar, sale del programa (por ejemplo, se termina el video grabado) if image == None: return Task.done nuevaImagen = self.detectFaces(image) #Crea una textura utilizando la imagen capturada por OpenCV texture = self.createTexture(image) #En caso de que haya ocurrido un error, utilizar la imagen previa if texture != None: self.oldTexture = texture #Muestra la captura como fondo de la imagen self.card.setTexture(self.oldTexture) return Task.cont def createTexture(self, image): (width, height) = cv.GetSize(image) #Panda3D interpreta las imagenes al reves que OpenCV (verticalmente invertidas), por lo que es necesario tener esto en cuenta cv.Flip(image, image, 0) #OpenCV permite convertir la representacion interna de las imagenes a un formato descomprimido que puede ser guardado en un archivo. #Esto puede utilizarse desde Panda3D para tomar la imagen y utilizarla como una textura. imageString = image.tostring() #PTAUchar es una clase que permite tomar un bloque de datos y utilizarlo desde componentes de Panda3D (en particular es util para texturas) imagePointer = PTAUchar.emptyArray(0) imagePointer.setData(imageString) try: self.count += 1 #Crea un nuevo objeto textura texture = Texture('image' + str(self.count)) #Establece propiedades de la textura, como tamanio, tipo de datos y modelo de color. Las imagenes de OpenCV las estamos manejando #como RGB, donde cada canal es de 8bits (un numero entero) texture.setup2dTexture(width, height, Texture.TUnsignedByte, Texture.FRgb) #Indicamos que utilice el bloque de datos obtenido anteriormente como origen de datos para la textura texture.setRamImage(CPTAUchar(imagePointer), MovieTexture.CMOff) except: texture = None return texture def detectFaces(self, image): #Tamanio minimo de los rostros a detectar minFaceSize = (20, 20) #Escala a aplicar a la imagen para reducir tiempo de procesamiento imageScale = 2 haarScale = 1.2 minNeighbors = 2 haarFlags = 0 (screenWidth, screenHeight) = cv.GetSize(image) aspectRatio = float(screenWidth) / screenHeight #Crea imagenes temporales para la conversion a escala de grises y el escalado de la imagen grayImage = cv.CreateImage((image.width,image.height), 8, 1) smallImage = cv.CreateImage((cv.Round(image.width / imageScale), cv.Round (image.height / imageScale)), 8, 1) #Convierte la imagen capturada a escala de grises cv.CvtColor(image, grayImage, cv.CV_BGR2GRAY) #Crea una version de tamanio reducido para reducir el tiempo de procesamiento cv.Resize(grayImage, smallImage, cv.CV_INTER_LINEAR) #Ecualiza la imagen, con el fin de mejorar el contraste cv.EqualizeHist(smallImage, smallImage) #Detecta los rostros existentes en la imagen, y calcula el tiempo utilizado para hacerlo t = cv.GetTickCount() faces = cv.HaarDetectObjects(smallImage, self.cascade, cv.CreateMemStorage(0), haarScale, minNeighbors, haarFlags, minFaceSize) t = cv.GetTickCount() - t #Crea una imagen nueva donde se va a dibujar el cuadrado sin mostrar el fondo nuevaImagen = cv.CreateImage((image.width,image.height), 8, 3) pt1 = (int(0 * imageScale), int(0 * imageScale)) pt2 = (int((image.width) * imageScale), int((image.height) * imageScale)) cv.Rectangle(nuevaImagen, pt1, pt2, cv.RGB(118, 152, 141), -1, 8, 0) print "detection time = %gms" % (t/(cv.GetTickFrequency()*1000.)) if faces: for ((x, y, w, h), n) in faces: #Calcula los puntos de inicio y fin del rectangulo detectado pt1 = (int(x * imageScale), int(y * imageScale)) pt2 = (int((x + w) * imageScale), int((y + h) * imageScale)) #Dibuja un rectangulo en la imagen origen, para destacar el rostro detectado #cv.Rectangle(nuevaImagen, pt1, pt2, cv.RGB(255, 0, 0), 3, 8, 0) cv.Rectangle(image, pt1, pt2, cv.RGB(255, 0, 0), 3, 8, 0) #Calcula la posicion del objeto a mostrar en Panda3D #Se utiliza aspect2d, ya que permite tener independencia de dimensiones entre ancho y alto (con render2d la imagen se veria comprimida) #En aspect2d, la coordenada x corre desde -aspectRatio hasta aspectRatio. La coordenada y corre desde -1 a 1. # #En este caso en que utilizamos 2D, es mas notoria la necesidad de definir correctamente el "centro" de nuestros modelos. #Esto se realiza en los programas de modelado, pero afectara el posicionamiento dentro de nuestra aplicacion #position = (float(x) * imageScale, float(y + h) * imageScale) #position = (position[0] - screenWidth / 2, position[1] - screenHeight / 2) #position = (2 * aspectRatio * position[0] / screenWidth, 2 * (-position[1] / screenHeight), 0) position = (float(x) * imageScale, float(y) * imageScale) position = (position[0] - screenWidth / 2, position[1] - screenHeight / 2) position = (2 * aspectRatio * position[0] / screenWidth, 2 * (-position[1] / screenHeight), 0) #Ubica el centro del objeto en la posicion correcta self.faceImage.setPos(position[0], 0, position[1]) texture = self.faceImage.getTexture() #self.faceImage.setScale(2 * imageScale * float(w) / texture.getXSize(), 1, 2 * imageScale * float(h) / texture.getYSize()) self.faceImage.setScale(imageScale * float(w) / texture.getXSize(), 1, imageScale * float(h) / texture.getYSize()) print self.faceImage.getScale() return nuevaImagen
class DirectionHandle(PandaNode, MouseEventListener): geomNode = makeGeomNode() clickableGeomNode = makeClickableGeom() def __init__(self, parent, color, hpr, dim): PandaNode.__init__(self, dim+'handle') self.path = NodePath(self) self.parent = parent self.dim = dim arrow = GeomNode('gnode') arrow.addGeomsFrom(self.geomNode) arrownp = self.path.attachNewNode(arrow) arrownp.hide(BitMask32(1)) clickNode = ClickableNode('clicknode') clickNode.setDepthLevel(0.5) clickNode.addMouseListener(self) clicknp = self.path.attachNewNode(clickNode) clickgeom = clicknp.attachNewNode(GeomNode('clicknode')) clickgeom.hide(BitMask32(7)) clickgeom.node().addGeomsFrom(self.clickableGeomNode) linesegs = LineSegs() linesegs.setColor(color) linesegs.setThickness(2) linesegs.moveTo(Vec3(0, 0, -30)) linesegs.drawTo(Vec3(0, 0, -0.5)) linesegs.moveTo(Vec3(0, 0, 0.5)) linesegs.drawTo(Vec3(0, 0, 30)) lines = self.path.attachNewNode(linesegs.create()) lines.show(BitMask32(1)) lines.hide(BitMask32(2|4|8|16)) lines.setBin('opaque', 30, 100) lines.setAntialias(AntialiasAttrib.MNone) self.path.setColor(color) self.path.setHpr(hpr) self.mDownPos = Vec2() def mouseEntered(self, event): self.path.setColorScale(2, 2, 2, 2) def mouseExited(self, event): self.path.setColorScale(1, 1, 1, 1) def mousePressed(self, event): self.parent.beginTransformation() lens = base.cam.node().getLens() scale = Mat4.scaleMat(self.path.getScale(base.camera)) descale = Mat4() descale.invertAffineFrom(scale) mvMat = descale * self.path.getMat(base.camera) origin = Point3(mvMat.xformPoint(Point3())) dir = Vec3(mvMat.xformVec(Vec3(0, 0, 1))) xprod = dir.cross(origin) planeNorm = xprod.cross(dir) planeNorm.normalize() d = planeNorm.dot(origin) self.dir = dir self.origin = origin self.planeNorm = planeNorm self.d = d self.lens = lens self.fromCam = base.camera.getMat(self.parent.path) * scale transl = self.mouse2Vec(event.pos) self.origin = transl + self.origin def mouseMoved(self, event): transl = self.fromCam.xformVec(self.mouse2Vec(event.pos)) self.parent.transform(Mat4.translateMat(transl)) def mouse2Vec(self, mpos): ray = Vec3() ray.xz = self.lens.getFilmSize() ray.x = mpos.x * ray.x / 2 ray.z = mpos.y * ray.z / 2 ray.y = self.lens.getFocalLength() ray.normalize() k = self.d/(ray.dot(self.planeNorm)) return self.dir * (ray*k - self.origin).dot(self.dir)
class RotationHandle(PandaNode, MouseEventListener): geomNode = makeRotationGeomNode() def __init__(self, parent, color, hpr, dim): PandaNode.__init__(self, dim+'rotHandle') self.path = NodePath(self) self.parent = parent self.dim = dim circle = GeomNode('gnode') circle.addGeomsFrom(self.geomNode) self.clickable = ClickableNode('clickable') self.clickable.addChild(circle) self.clickable.addMouseListener(self) circlenp = self.path.attachNewNode(self.clickable) self.path.setColor(color) self.path.setHpr(hpr) self.mDownPos = Vec2() def mouseEntered(self, event): self.path.setColorScale(2, 2, 2, 2) def mouseExited(self, event): self.path.setColorScale(1, 1, 1, 1) def mousePressed(self, event): self.parent.beginTransformation() self.lens = base.cam.node().getLens() scale = Mat4.scaleMat(self.path.getScale(base.camera)) descale = Mat4() descale.invertAffineFrom(scale) mvMat = descale * self.path.getMat(base.camera) self.origin = Point3(mvMat.xformPoint(Point3())) self.planeNorm = Vec3(mvMat.xformVec(Vec3(0, 0, 1))) self.planeNorm.normalize() self.d = self.planeNorm.dot(self.origin) self.fromCam = base.camera.getMat(self.parent.path) * scale self.dir = Vec3(self.mouse2Vec(event.pos)) self.dir.normalize() def mouseMoved(self, event): transl = Vec3(self.mouse2Vec(event.pos)) transl.normalize() angle = self.dir.signedAngleDeg(transl, self.planeNorm) axis = Vec3() setattr(axis, self.dim, 1) self.parent.transform(Mat4.rotateMatNormaxis(angle, axis)) def mouse2Vec(self, mpos): ray = Vec3() ray.xz = self.lens.getFilmSize() ray.x = mpos.x * ray.x / 2 ray.z = mpos.y * ray.z / 2 ray.y = self.lens.getFocalLength() ray.normalize() k = self.d/ray.dot(self.planeNorm) return ray*k - self.origin
class DirectionHandle(PandaNode, MouseEventListener): geomNode = makeGeomNode() clickableGeomNode = makeClickableGeom() def __init__(self, parent, color, hpr, dim): PandaNode.__init__(self, dim + 'handle') self.path = NodePath(self) self.parent = parent self.dim = dim arrow = GeomNode('gnode') arrow.addGeomsFrom(self.geomNode) arrownp = self.path.attachNewNode(arrow) arrownp.hide(BitMask32(1)) clickNode = ClickableNode('clicknode') clickNode.setDepthLevel(0.5) clickNode.addMouseListener(self) clicknp = self.path.attachNewNode(clickNode) clickgeom = clicknp.attachNewNode(GeomNode('clicknode')) clickgeom.hide(BitMask32(7)) clickgeom.node().addGeomsFrom(self.clickableGeomNode) linesegs = LineSegs() linesegs.setColor(color) linesegs.setThickness(2) linesegs.moveTo(Vec3(0, 0, -30)) linesegs.drawTo(Vec3(0, 0, -0.5)) linesegs.moveTo(Vec3(0, 0, 0.5)) linesegs.drawTo(Vec3(0, 0, 30)) lines = self.path.attachNewNode(linesegs.create()) lines.show(BitMask32(1)) lines.hide(BitMask32(2 | 4 | 8 | 16)) lines.setBin('opaque', 30, 100) lines.setAntialias(AntialiasAttrib.MNone) self.path.setColor(color) self.path.setHpr(hpr) self.mDownPos = Vec2() def mouseEntered(self, event): self.path.setColorScale(2, 2, 2, 2) def mouseExited(self, event): self.path.setColorScale(1, 1, 1, 1) def mousePressed(self, event): self.parent.beginTransformation() lens = base.cam.node().getLens() scale = Mat4.scaleMat(self.path.getScale(base.camera)) descale = Mat4() descale.invertAffineFrom(scale) mvMat = descale * self.path.getMat(base.camera) origin = Point3(mvMat.xformPoint(Point3())) dir = Vec3(mvMat.xformVec(Vec3(0, 0, 1))) xprod = dir.cross(origin) planeNorm = xprod.cross(dir) planeNorm.normalize() d = planeNorm.dot(origin) self.dir = dir self.origin = origin self.planeNorm = planeNorm self.d = d self.lens = lens self.fromCam = base.camera.getMat(self.parent.path) * scale transl = self.mouse2Vec(event.pos) self.origin = transl + self.origin def mouseMoved(self, event): transl = self.fromCam.xformVec(self.mouse2Vec(event.pos)) self.parent.transform(Mat4.translateMat(transl)) def mouse2Vec(self, mpos): ray = Vec3() ray.xz = self.lens.getFilmSize() ray.x = mpos.x * ray.x / 2 ray.z = mpos.y * ray.z / 2 ray.y = self.lens.getFocalLength() ray.normalize() k = self.d / (ray.dot(self.planeNorm)) return self.dir * (ray * k - self.origin).dot(self.dir)
class RotationHandle(PandaNode, MouseEventListener): geomNode = makeRotationGeomNode() def __init__(self, parent, color, hpr, dim): PandaNode.__init__(self, dim + 'rotHandle') self.path = NodePath(self) self.parent = parent self.dim = dim circle = GeomNode('gnode') circle.addGeomsFrom(self.geomNode) self.clickable = ClickableNode('clickable') self.clickable.addChild(circle) self.clickable.addMouseListener(self) circlenp = self.path.attachNewNode(self.clickable) self.path.setColor(color) self.path.setHpr(hpr) self.mDownPos = Vec2() def mouseEntered(self, event): self.path.setColorScale(2, 2, 2, 2) def mouseExited(self, event): self.path.setColorScale(1, 1, 1, 1) def mousePressed(self, event): self.parent.beginTransformation() self.lens = base.cam.node().getLens() scale = Mat4.scaleMat(self.path.getScale(base.camera)) descale = Mat4() descale.invertAffineFrom(scale) mvMat = descale * self.path.getMat(base.camera) self.origin = Point3(mvMat.xformPoint(Point3())) self.planeNorm = Vec3(mvMat.xformVec(Vec3(0, 0, 1))) self.planeNorm.normalize() self.d = self.planeNorm.dot(self.origin) self.fromCam = base.camera.getMat(self.parent.path) * scale self.dir = Vec3(self.mouse2Vec(event.pos)) self.dir.normalize() def mouseMoved(self, event): transl = Vec3(self.mouse2Vec(event.pos)) transl.normalize() angle = self.dir.signedAngleDeg(transl, self.planeNorm) axis = Vec3() setattr(axis, self.dim, 1) self.parent.transform(Mat4.rotateMatNormaxis(angle, axis)) def mouse2Vec(self, mpos): ray = Vec3() ray.xz = self.lens.getFilmSize() ray.x = mpos.x * ray.x / 2 ray.z = mpos.y * ray.z / 2 ray.y = self.lens.getFocalLength() ray.normalize() k = self.d / ray.dot(self.planeNorm) return ray * k - self.origin
class TQGraphicsNodePath: """ Anything that fundamentally is a only a graphics object in this engine should have these properties. Kwargs: TQGraphicsNodePath_creation_parent_node : this is assigned in the constructor, and after makeObject and the return of the p3d Nodepath, each TQGraphicsNodePath object has to call set_p3d_node """ def __init__(self, **kwargs): """ """ self.TQGraphicsNodePath_creation_parent_node = None self.p3d_nodepath = NodePath("empty") self.p3d_nodepath_changed_post_init_p = False self.p3d_parent_nodepath = NodePath("empty") self.node_p3d = None self.p3d_nodepath.reparentTo(self.p3d_parent_nodepath) self.apply_kwargs(**kwargs) def apply_kwargs(self, **kwargs): """ """ if 'color' in kwargs: TQGraphicsNodePath.setColor(self, kwargs.get('color')) else: TQGraphicsNodePath.setColor(self, Vec4(1., 1., 1., 1.)) def attach_to_render(self): """ """ # assert self.p3d_nodepath # self.p3d_nodepath.reparentTo(render) assert self.p3d_nodepath self.reparentTo(engine.tq_graphics_basics.tq_render) def attach_to_aspect2d(self): """ """ # assert self.p3d_nodepath # self.p3d_nodepath.reparentTo(aspect2d) assert self.p3d_nodepath self.reparentTo(engine.tq_graphics_basics.tq_aspect2d) def _set_p3d_nodepath_plain_post_init(p3d_nodepath): """ """ self.p3d_nodepath = p3d_nodepath self.p3d_nodepath_changed_post_init_p = True @staticmethod def from_p3d_nodepath(p3d_nodepath, **tq_graphics_nodepath_kwargs): """ factory """ go = TQGraphicsNodePath(**tq_graphics_nodepath_kwargs) go.set_p3d_nodepath(p3d_nodepath) return go def set_parent_node_for_nodepath_creation( self, TQGraphicsNodePath_creation_parent_node): """ when calling attachNewNode_p3d, a new node pat is generated. E.g.: To attach a line to render (3d world) is different than attaching it to aspect2d (2d GUI plane), since the aspect2d children are not directly affected by camera movements Args: - TQGraphicsNodePath_creation_parent_node : the NodePath to attach the TQGraphicsNodePath to (e.g. render or aspect2d in p3d) """ # self.set_parent_node_for_nodepath_creation(self.TQGraphicsNodePath_creation_parent_node) self.TQGraphicsNodePath_creation_parent_node = TQGraphicsNodePath_creation_parent_node def set_p3d_nodepath(self, p3d_nodepath, remove_old_nodepath=True): """ """ self.p3d_nodepath = p3d_nodepath def get_p3d_nodepath(self): """ """ return self.p3d_nodepath def set_render_above_all(self, p): """ set render order to be such that it renders normally (false), or above all (true) Args: p: True or False to enable or disable the 'above all' rendering mode """ try: if p == True: self.p3d_nodepath.setBin("fixed", 0) self.p3d_nodepath.setDepthTest(False) self.p3d_nodepath.setDepthWrite(False) else: self.p3d_nodepath.setBin("default", 0) self.p3d_nodepath.setDepthTest(True) self.p3d_nodepath.setDepthWrite(True) except NameError: # if p3d_nodepath is not yet defined print("NameError in set_render_above_all()") def remove(self): """ """ self.p3d_nodepath.removeNode() def setPos(self, *args, **kwargs): """ """ return self.p3d_nodepath.setPos(*args, **kwargs) def getPos(self): """ """ return self.p3d_nodepath.getPos() def setScale(self, *args, **kwargs): """ """ return self.p3d_nodepath.setScale(*args, **kwargs) def getScale(self): """ """ return self.p3d_nodepath.getScale() def setMat(self, *args, **kwargs): """ """ return self.p3d_nodepath.setMat(*args, **kwargs) def setMat_normal(self, mat4x4_normal_np): """ normal convention (numpy array), i.e. convert to forrowvecs convention for p3d setMat call """ return self.p3d_nodepath.setMat(math_utils.to_forrowvecs(mat4x4_normal_np)) def getMat(self, *args, **kwargs): """ """ return self.p3d_nodepath.getMat(*args, **kwargs) def getMat_normal(self, *args, **kwargs): """ """ return math_utils.from_forrowvecs(self.p3d_nodepath.getMat(*args, **kwargs)) def setTexture(self, *args, **kwargs): """ """ return self.p3d_nodepath.setTexture(*args, **kwargs) def setColor(self, *args, **kwargs): """ """ return self.p3d_nodepath.setColor(*args, **kwargs) def setTwoSided(self, *args, **kwargs): """ """ return self.p3d_nodepath.setTwoSided(*args, **kwargs) def setRenderModeWireframe(self, *args, **kwargs): """ """ return self.p3d_nodepath.setRenderModeWireframe(*args, **kwargs) def reparentTo(self, *args, **kwargs): """ """ new_args = list(args) new_args[0] = new_args[0].p3d_nodepath return self.p3d_nodepath.reparentTo(*new_args, **kwargs) def reparentTo_p3d(self, *args, **kwargs): """ input a p3d nodepath directly """ # new_args = list(args) # new_args[0] = new_args[0].p3d_nodepath return self.p3d_nodepath.reparentTo(*args, **kwargs) def get_node_p3d(self): """ """ # return self.p3d_nodepath.node() return self.node_p3d def set_node_p3d(self, node_p3d): """ not available in p3d NodePath class """ self.node_p3d = node_p3d def setRenderModeFilled(self, *args, **kwargs): """ """ return self.p3d_nodepath.setRenderModeFilled(*args, **kwargs) def setLightOff(self, *args, **kwargs): """ """ return self.p3d_nodepath.setLightOff(*args, **kwargs) def show(self): """ """ return self.p3d_nodepath.show() def hide(self): """ """ return self.p3d_nodepath.hide() def setRenderModeThickness(self, *args, **kwargs): """ """ return self.p3d_nodepath.setRenderModeThickness(*args, **kwargs) def removeNode(self): """ """ return self.p3d_nodepath.removeNode() def setHpr(self, *args, **kwargs): """ """ return self.p3d_nodepath.setHpr(*args, **kwargs) def showBounds(self): """ """ return self.p3d_nodepath.showBounds() def setCollideMask(self, *args, **kwargs): """ """ return self.p3d_nodepath.setCollideMask(*args, **kwargs) def getParent_p3d(self, *args, **kwargs): """ """ return self.p3d_nodepath.getParent(*args, **kwargs) def wrtReparentTo(self, *args, **kwargs): """ """ return self.p3d_nodepath.wrtReparentTo(*args, **kwargs) def setBin(self, *args, **kwargs): """ """ return self.p3d_nodepath.setBin(*args, **kwargs) def setDepthTest(self, *args, **kwargs): """ """ return self.p3d_nodepath.setDepthTest(*args, **kwargs) def setDepthWrite(self, *args, **kwargs): """ """ return self.p3d_nodepath.setDepthWrite(*args, **kwargs) def get_children_p3d(self, *args, **kwargs): """ """ return self.p3d_nodepath.get_children(*args, **kwargs) def attachNewNode_p3d(self, *args, **kwargs): """ """ return self.p3d_nodepath.attachNewNode(*args, **kwargs) def lookAt(self, *args, **kwargs): """ """ return self.p3d_nodepath.lookAt(*args, **kwargs) def setLight(self, *args, **kwargs): """ """ return self.p3d_nodepath.setLight(*args, **kwargs) def setAntialias(self, *args, **kwargs): """ """ return self.p3d_nodepath.setAntialias(*args, **kwargs) def getRelativeVector(self, *args, **kwargs): """ """ return self.p3d_nodepath.getRelativeVector(*args, **kwargs) def setTransparency(self, *args, **kwargs): """ """ return self.p3d_nodepath.setTransparency(*args, **kwargs) def getHpr(self, *args, **kwargs): """ """ return self.p3d_nodepath.getHpr(*args, **kwargs) def setHpr(self, *args, **kwargs): """ """ return self.p3d_nodepath.setHpr(*args, **kwargs) def getTightBounds(self, *args, **kwargs): """ """ return self.p3d_nodepath.getTightBounds(*args, **kwargs) def showTightBounds(self, *args, **kwargs): """ """ return self.p3d_nodepath.showTightBounds(*args, **kwargs)