class SpotLight(Light, DebugObject): """ This light type simulates a SpotLight. It has a position and an orientation. """ def __init__(self): """ Creates a new spot light. """ Light.__init__(self) DebugObject.__init__(self, "SpotLight") self.typeName = "SpotLight" self.nearPlane = 0.5 self.radius = 30.0 self.spotSize = Vec2(30, 30) # Used to compute the MVP self.ghostCamera = Camera("PointLight") self.ghostCamera.setActive(False) self.ghostLens = PerspectiveLens() self.ghostLens.setFov(130) self.ghostCamera.setLens(self.ghostLens) self.ghostCameraNode = NodePath(self.ghostCamera) self.ghostCameraNode.reparentTo(Globals.render) self.ghostCameraNode.hide() def getLightType(self): """ Internal method to fetch the type of this light, used by Light """ return LightType.Spot def _updateLens(self): """ Internal method which gets called when the lens properties changed """ for source in self.shadowSources: source.rebuildMatrixCache() def cleanup(self): """ Internal method which gets called when the light got deleted """ self.ghostCameraNode.removeNode() Light.cleanup(self) def setFov(self, fov): """ Sets the field of view of the spotlight """ assert(fov > 1 and fov < 180) self.ghostLens.setFov(fov) self._updateLens() def setPos(self, pos): """ Sets the position of the spotlight """ self.ghostCameraNode.setPos(pos) Light.setPos(self, pos) def lookAt(self, pos): """ Makes the spotlight look at the given position """ self.ghostCameraNode.lookAt(pos) def _computeAdditionalData(self): """ Internal method to recompute the spotlight MVP """ self.ghostCameraNode.setPos(self.position) projMat = self.ghostLens.getProjectionMat() modelViewMat = Globals.render.getTransform(self.ghostCameraNode).getMat() self.mvp = modelViewMat * projMat def _computeLightBounds(self): """ Recomputes the bounds of this light. For a SpotLight, we for now use a simple BoundingSphere """ self.bounds = BoundingSphere(Point3(self.position), self.radius * 2.0) def setNearFar(self, near, far): """ Sets the near and far plane of the spotlight """ self.nearPlane = near self.radius = far self.ghostLens.setNearFar(near, far) self._updateLens() def _updateDebugNode(self): """ Internal method to generate new debug geometry. """ debugNode = NodePath("SpotLightDebugNode") # Create the inner image cm = CardMaker("SpotLightDebug") cm.setFrameFullscreenQuad() innerNode = NodePath(cm.generate()) innerNode.setTexture(Globals.loader.loadTexture("Data/GUI/Visualization/SpotLight.png")) innerNode.setBillboardPointEye() innerNode.reparentTo(debugNode) innerNode.setPos(self.position) innerNode.setColorScale(1,1,0,1) # Create the outer lines lineNode = debugNode.attachNewNode("lines") currentNodeTransform = render.getTransform(self.ghostCameraNode).getMat() currentCamTransform = self.ghostLens.getProjectionMat() currentRelativeCamPos = self.ghostCameraNode.getPos(render) currentCamBounds = self.ghostLens.makeBounds() currentCamBounds.xform(self.ghostCameraNode.getMat(render)) p = lambda index: currentCamBounds.getPoint(index) # Make a circle at the bottom frustumBottomCenter = (p(0) + p(1) + p(2) + p(3)) * 0.25 upVector = (p(0) + p(1)) / 2 - frustumBottomCenter rightVector = (p(1) + p(2)) / 2 - frustumBottomCenter points = [] for idx in xrange(64): rad = idx / 64.0 * math.pi * 2.0 pos = upVector * math.sin(rad) + rightVector * math.cos(rad) pos += frustumBottomCenter points.append(pos) frustumLine = self._createDebugLine(points, True) frustumLine.setColorScale(1,1,0,1) frustumLine.reparentTo(lineNode) # Create frustum lines which connect the origin to the bottom circle pointArrays = [ [self.position, frustumBottomCenter + upVector], [self.position, frustumBottomCenter - upVector], [self.position, frustumBottomCenter + rightVector], [self.position, frustumBottomCenter - rightVector], ] for pointArray in pointArrays: frustumLine = self._createDebugLine(pointArray, False) frustumLine.setColorScale(1,1,0,1) frustumLine.reparentTo(lineNode) # Create line which is in the direction of the spot light startPoint = (p(0) + p(1) + p(2) + p(3)) * 0.25 endPoint = (p(4) + p(5) + p(6) + p(7)) * 0.25 line = self._createDebugLine([startPoint, endPoint], False) line.setColorScale(1,1,1,1) line.reparentTo(lineNode) # Remove the old debug node self.debugNode.node().removeAllChildren() # Attach the new debug node debugNode.reparentTo(self.debugNode) # self.debugNode.flattenStrong() def _initShadowSources(self): """ Internal method to init the shadow sources """ source = ShadowSource() source.setResolution(self.shadowResolution) source.setLens(self.ghostLens) self._addShadowSource(source) def _updateShadowSources(self): """ Recomputes the position of the shadow source """ self.shadowSources[0].setPos(self.position) self.shadowSources[0].setHpr(self.ghostCameraNode.getHpr()) def __repr__(self): """ Generates a string representation of this instance """ return "SpotLight[]"
("id", ("object", "matrix")))(("mypanda2", mymatrix)) do_spawn = dragonfly.std.transistor(("id", ("object", "matrix")))() connect(v_spawn, do_spawn) connect(do_spawn, pandaspawn.spawn_matrix) key_z = dragonfly.io.keyboardsensor_trigger("Z") connect(key_z, do_spawn) main = myhive().getinstance() main.build("main") main.scene.import_mesh_EGG("models/environment") a = NodePath("") a.setScale(0.25) a.setPos(-8, 42, 0) mat = a.getMat() m = (mat.getRow3(3), mat.getRow3(0), mat.getRow3(1), mat.getRow3(2)) main.scene.add_model_MATRIX(matrix=m) main.scene.import_mesh_EGG("models/panda-model") a = NodePath("") a.setScale(0.005) mat = a.getMat() m = (mat.getRow3(3), mat.getRow3(0), mat.getRow3(1), mat.getRow3(2)) main.scene.add_actor_MATRIX(matrix=m, entityname="mypanda") main.scene.import_mesh_EGG("models/panda-walk4") main.scene.add_animation("walk") main.scene.import_mesh_EGG("models/panda-model") a = NodePath("") a.setScale(0.005)
connect(walk, animation.animation_name) key_w = dragonfly.io.keyboardsensor_trigger("W") connect(key_w, animation.loop) key_s = dragonfly.io.keyboardsensor_trigger("S") connect(key_s, animation.stop) main = myhive().getinstance() main.build("main") main.scene.import_mesh_EGG("models/environment") a = NodePath("") a.setScale(0.25) a.setPos(-8, 42, 0) mat = a.getMat() m = (mat.getRow3(3), mat.getRow3(0), mat.getRow3(1), mat.getRow3(2)) main.scene.add_model_MATRIX(matrix=m) main.scene.import_mesh_EGG("models/panda-model") a = NodePath("") a.setScale(0.005) mat = a.getMat() m = (mat.getRow3(3), mat.getRow3(0), mat.getRow3(1), mat.getRow3(2)) main.scene.add_actor_MATRIX(matrix=m, entityname="mypanda") main.scene.import_mesh_EGG("models/panda-walk4") main.scene.add_animation("walk") main.place() main.close() main.init()
class Solid(MapObject): ObjectName = "solid" def __init__(self, id): MapObject.__init__(self, id) self.np = NodePath(SolidGeomNode("solid.%i" % id)) self.np.setPythonTag("mapobject", self) self.np.node().setFinal(True) self.coll3D = self.np.attachNewNode(CollisionNode("coll3D")) self.coll3D.setCollideMask(LEGlobals.ObjectMask | LEGlobals.FaceMask | LEGlobals.Mask3D) #self.coll2D = self.np.attachNewNode(CollisionNode("coll2D")) #self.coll2D.setCollideMask(LEGlobals.ObjectMask | LEGlobals.FaceMask | LEGlobals.Mask2D) # CollisionSolid -> SolidFace self.faceCollSolids = {} self.geomIndices = {} self.faces = [] self.pickRandomColor() self.addProperty(VisOccluder(self)) def pickRandomColor(self): # Picks a random shade of blue/green for this solid. self.setColor(LEUtils.getRandomSolidColor()) def setColor(self, color): self.color = color for face in self.faces: face.setColor(color) def getFaceFromCollisionSolid(self, solid): return self.faceCollSolids[solid] def addFaceGeom(self, geom, state): index = self.np.node().getNumGeoms() self.geomIndices[geom] = index self.np.node().addGeom(geom, state) return index def setFaceGeomState(self, geom, state): index = self.geomIndices[geom] self.np.node().setGeomState(index, state) def alignTexturesToFaces(self): for face in self.faces: face.alignTextureToFace() def alignTexturesToWorld(self): for face in self.faces: face.alignTextureToWorld() def copy(self, generator): s = Solid(generator.getNextID()) self.copyBase(s, generator) for face in self.faces: f = face.copy(generator) f.setSolid(s) s.faces.append(f) s.generateFaces() return s def generateFaces(self): for face in self.faces: face.generate() if not self.temporary: self.createFaceCollisions() def writeKeyValues(self, keyvalues): MapObject.writeKeyValues(self, keyvalues) # Write or faces or "sides" for face in self.faces: faceKv = CKeyValues("side", keyvalues) face.writeKeyValues(faceKv) def readKeyValues(self, kv): MapObject.readKeyValues(self, kv) numChildren = kv.getNumChildren() for i in range(numChildren): child = kv.getChild(i) if child.getName() == "side": face = SolidFace(solid=self) face.readKeyValues(child) self.faces.append(face) self.createVerticesFromFacePlanes() self.createFaceCollisions() # Creates the collision objects that will be tested against for selecting solid faces. def createFaceCollisions(self): self.coll3D.node().clearSolids() #self.coll2D.node().clearSolids() self.faceCollSolids = {} for face in self.faces: numVerts = len(face.vertices) # Tris in 3D for ray->face selection for i in range(1, numVerts - 1): poly = CollisionPolygon(face.vertices[i + 1].pos, face.vertices[i].pos, face.vertices[0].pos) self.coll3D.node().addSolid(poly) self.faceCollSolids[poly] = face # Lines in 2D for box->edge selection #for i in range(len(face.vertices)): # a = face.vertices[i].pos # b = face.vertices[(i+1) % numVerts].pos # if a == b: # continue # segment = CollisionSegment(a, b) # self.coll2D.node().addSolid(segment) # self.faceCollSolids[face][1].append(segment) def createVerticesFromFacePlanes(self): for i in range(len(self.faces)): face = self.faces[i] w = Winding.fromPlaneAndRadius(face.plane) for j in range(len(self.faces)): if i == j: continue other = self.faces[j] # # Flip the plane, because we want to keep the back side. # w.splitInPlace(-other.plane) w.roundPoints() # The final winding is the face for j in range(len(w.vertices)): face.vertices.append(SolidVertex(w.vertices[j], face)) face.calcTextureCoordinates(True) face.generate() def showClipVisRemove(self): for face in self.faces: face.showClipVisRemove() def showClipVisKeep(self): for face in self.faces: face.showClipVisKeep() def showBoundingBox(self): for face in self.faces: face.show3DLines() def hideBoundingBox(self): for face in self.faces: face.hide3DLines() def select(self): MapObject.select(self) for face in self.faces: face.select() def deselect(self): MapObject.deselect(self) for face in self.faces: face.deselect() def getAbsSolidOrigin(self): avg = Point3(0) for face in self.faces: avg += face.getAbsOrigin() avg /= len(self.faces) return avg def setToSolidOrigin(self): # Moves the solid origin to median of all face vertex positions, # and transforms all faces to be relative to the median position. # Resets angles, scale, and shear. origin = self.getAbsSolidOrigin() self.setAbsOrigin(origin) self.setAbsAngles(Vec3(0)) self.setAbsScale(Vec3(1)) self.setAbsShear(Vec3(0)) mat = self.np.getMat(NodePath()) mat.invertInPlace() for face in self.faces: face.xform(mat) def getName(self): return "Solid" def getDescription(self): return "Convex solid geometry." def delete(self): MapObject.delete(self) self.coll3D.removeNode() self.coll3D = None #self.coll2D.removeNode() #self.coll2D = None self.faceCollSolids = None for face in self.faces: face.delete() self.faces = None self.color = None # Splits this solid into two solids by intersecting against a plane. def split(self, plane, generator, temp=False): back = front = None # Check that this solid actually spans the plane classifications = [] for face in self.faces: classify = face.classifyAgainstPlane(plane) if classify not in classifications: classifications.append(classify) if PlaneClassification.Spanning not in classifications: if PlaneClassification.Back in classifications: back = self elif PlaneClassification.Front in classifications: front = self return [False, back, front] backPlanes = [plane] flippedFront = Plane(plane) flippedFront.flip() frontPlanes = [flippedFront] for face in self.faces: classify = face.classifyAgainstPlane(plane) if classify != PlaneClassification.Back: frontPlanes.append(face.getWorldPlane()) if classify != PlaneClassification.Front: backPlanes.append(face.getWorldPlane()) back = Solid.createFromIntersectingPlanes(backPlanes, generator, False, temp) front = Solid.createFromIntersectingPlanes(frontPlanes, generator, False, temp) if not temp: # copyBase() will set the transform to what we're copying from, but we already # figured out a transform for the solids. Store the current transform so we can # set it back. bTrans = back.np.getTransform() fTrans = front.np.getTransform() self.copyBase(back, generator) self.copyBase(front, generator) back.np.setTransform(bTrans) front.np.setTransform(fTrans) unionOfFaces = front.faces + back.faces for face in unionOfFaces: face.material = self.faces[0].material.clone() face.setMaterial(face.material.material) face.alignTextureToFace() # Restore textures (match the planes up on each face) for orig in self.faces: for face in back.faces: classify = face.classifyAgainstPlane(orig.getWorldPlane()) if classify != PlaneClassification.OnPlane: continue face.material = orig.material.clone() face.setMaterial(face.material.material) face.alignTextureToFace() break for face in front.faces: classify = face.classifyAgainstPlane(orig.getWorldPlane()) if classify != PlaneClassification.OnPlane: continue face.material = orig.material.clone() face.setMaterial(face.material.material) face.alignTextureToFace() break back.generateFaces() front.generateFaces() if not temp: back.recalcBoundingBox() front.recalcBoundingBox() return [True, back, front] @staticmethod def createFromIntersectingPlanes(planes, generator, generateFaces=True, temp=False): solid = Solid(generator.getNextID()) solid.setTemporary(temp) for i in range(len(planes)): # Split the winding by all the other planes w = Winding.fromPlaneAndRadius(planes[i]) for j in range(len(planes)): if i != j: # Flip the plane, because we want to keep the back. w.splitInPlace(-planes[j]) # Round vertices a bit for sanity w.roundPoints() # The final winding is the face face = SolidFace(generator.getNextFaceID(), Plane(planes[i]), solid) for j in range(len(w.vertices)): face.vertices.append(SolidVertex(w.vertices[j], face)) solid.faces.append(face) if not temp: solid.setToSolidOrigin() # Ensure all faces point outwards origin = Point3(0) for face in solid.faces: # The solid origin should be on or behind the face plane. # If the solid origin is in front of the face plane, flip the face. if face.plane.distToPlane(origin) > 0: face.flip() if generateFaces: solid.alignTexturesToFaces() solid.generateFaces() if not temp: solid.recalcBoundingBox() return solid
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 Handle(PandaNode, MouseEventListener): def __init__(self): PandaNode.__init__(self, 'PositionHandle') CameraController.getInstance().addEventHandler(EVT_CAMERA_MOVE, self._fixScale) self.path = NodePath(self) self.xHandle = DirectionHandle(self, Vec4(1, 0, 0, 0.6), Vec3(0, 0, 90), 'x') self.addChild(self.xHandle) self.yHandle = DirectionHandle(self, Vec4(0, 1, 0, 0.6), Vec3(0, -90, 0), 'y') self.addChild(self.yHandle) self.zHandle = DirectionHandle(self, Vec4(0, 0, 1, 0.6), Vec3(0, 0, 0), 'z') self.addChild(self.zHandle) self.hHandle = RotationHandle(self, Vec4(0, 0, 1, 0.6), Vec3(0, 0, 0), 'z') self.addChild(self.hHandle) NodePath(self.hHandle).setScale(1.02) self.pHandle = RotationHandle(self, Vec4(0, 1, 0, 0.6), Vec3(0, -90, 0), 'y') self.addChild(self.pHandle) NodePath(self.pHandle).setScale(0.98) self.rHandle = RotationHandle(self, Vec4(1, 0, 0, 0.6), Vec3(0, 0, 90), 'x') self.addChild(self.rHandle) self._tPressed() self.path.setTransparency(1) self.path.setBin('transparent', 30, 50) #self.path.setDepthTest(False) self.path.setLightOff() self.path.setRenderModeThickness(2) self.setClients([]) self.evtWatcher = DirectObject.DirectObject() self.evtWatcher.accept(base.win.getWindowEvent(), self._windowEventHandler) self.evtWatcher.accept('r', self._rPressed) self.evtWatcher.accept('t', self._tPressed) self.originalPos = self.path.getPos() self.fLenPx = base.cam.node().getLens().getFocalLength() * base.win.getXSize() self._fixScale() def _rPressed(self): self.xHandle.path.stash() self.yHandle.path.stash() self.zHandle.path.stash() self.hHandle.path.unstash() self.pHandle.path.unstash() self.rHandle.path.unstash() def _tPressed(self): self.xHandle.path.unstash() self.yHandle.path.unstash() self.zHandle.path.unstash() self.hHandle.path.stash() self.pHandle.path.stash() self.rHandle.path.stash() def setClients(self, clients, center=Vec3()): if clients: self.path.show(BitMask32(1|4|16)) self.path.setPos(center) self._fixScale() else: self.path.hide(BitMask32(1|2|4|8|16)) self.clients = [[client, None] for client in clients] def beginTransformation(self): self.originalMat = Mat4(Mat4.identMat()) self.originalMat.setRow(3, self.path.getMat(render).getRow(3)) self.originalMatInv = Mat4() self.originalMatInv.invertAffineFrom(self.originalMat) for i in xrange(len(self.clients)): print 'Their matrix * My matrix' print self.clients[i][0].getMat(self.path) * self.path.getMat() print 'Total matrix:' print self.clients[i][0].getMat() #self.clients[i][1] = self.clients[i][0].getMat(self.path) self.clients[i][1] = (self.clients[i][0].getMat() * self.originalMatInv) def transform(self, xform): transl = Mat4(Mat4.identMat()) transl.setRow(3, xform.getRow3(3)) self.path.setMat(render, transl * self.originalMat) self._fixScale() xform.setRow(3, Vec3()) for client, originalMat in self.clients: #client.setMat(self.path, originalMat * xform) client.setMat(originalMat * xform * transl * self.originalMat) def _fixScale(self, camera=base.camera): myPos = self.path.getPos() dist = (camera.getPos() - myPos).length() self.path.setScale(dist * HANDLE_SIZE / self.fLenPx) def _windowEventHandler(self, window): self.fLenPx = (base.cam.node().getLens().getFocalLength() * window.getXSize()) self._fixScale()
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 Handle(PandaNode, MouseEventListener): def __init__(self): PandaNode.__init__(self, 'PositionHandle') CameraController.getInstance().addEventHandler(EVT_CAMERA_MOVE, self._fixScale) self.path = NodePath(self) self.xHandle = DirectionHandle(self, Vec4(1, 0, 0, 0.6), Vec3(0, 0, 90), 'x') self.addChild(self.xHandle) self.yHandle = DirectionHandle(self, Vec4(0, 1, 0, 0.6), Vec3(0, -90, 0), 'y') self.addChild(self.yHandle) self.zHandle = DirectionHandle(self, Vec4(0, 0, 1, 0.6), Vec3(0, 0, 0), 'z') self.addChild(self.zHandle) self.hHandle = RotationHandle(self, Vec4(0, 0, 1, 0.6), Vec3(0, 0, 0), 'z') self.addChild(self.hHandle) NodePath(self.hHandle).setScale(1.02) self.pHandle = RotationHandle(self, Vec4(0, 1, 0, 0.6), Vec3(0, -90, 0), 'y') self.addChild(self.pHandle) NodePath(self.pHandle).setScale(0.98) self.rHandle = RotationHandle(self, Vec4(1, 0, 0, 0.6), Vec3(0, 0, 90), 'x') self.addChild(self.rHandle) self._tPressed() self.path.setTransparency(1) self.path.setBin('transparent', 30, 50) #self.path.setDepthTest(False) self.path.setLightOff() self.path.setRenderModeThickness(2) self.setClients([]) self.evtWatcher = DirectObject.DirectObject() self.evtWatcher.accept(base.win.getWindowEvent(), self._windowEventHandler) self.evtWatcher.accept('r', self._rPressed) self.evtWatcher.accept('t', self._tPressed) self.originalPos = self.path.getPos() self.fLenPx = base.cam.node().getLens().getFocalLength( ) * base.win.getXSize() self._fixScale() def _rPressed(self): self.xHandle.path.stash() self.yHandle.path.stash() self.zHandle.path.stash() self.hHandle.path.unstash() self.pHandle.path.unstash() self.rHandle.path.unstash() def _tPressed(self): self.xHandle.path.unstash() self.yHandle.path.unstash() self.zHandle.path.unstash() self.hHandle.path.stash() self.pHandle.path.stash() self.rHandle.path.stash() def setClients(self, clients, center=Vec3()): if clients: self.path.show(BitMask32(1 | 4 | 16)) self.path.setPos(center) self._fixScale() else: self.path.hide(BitMask32(1 | 2 | 4 | 8 | 16)) self.clients = [[client, None] for client in clients] def beginTransformation(self): self.originalMat = Mat4(Mat4.identMat()) self.originalMat.setRow(3, self.path.getMat(render).getRow(3)) self.originalMatInv = Mat4() self.originalMatInv.invertAffineFrom(self.originalMat) for i in xrange(len(self.clients)): print 'Their matrix * My matrix' print self.clients[i][0].getMat(self.path) * self.path.getMat() print 'Total matrix:' print self.clients[i][0].getMat() #self.clients[i][1] = self.clients[i][0].getMat(self.path) self.clients[i][1] = (self.clients[i][0].getMat() * self.originalMatInv) def transform(self, xform): transl = Mat4(Mat4.identMat()) transl.setRow(3, xform.getRow3(3)) self.path.setMat(render, transl * self.originalMat) self._fixScale() xform.setRow(3, Vec3()) for client, originalMat in self.clients: #client.setMat(self.path, originalMat * xform) client.setMat(originalMat * xform * transl * self.originalMat) def _fixScale(self, camera=base.camera): myPos = self.path.getPos() dist = (camera.getPos() - myPos).length() self.path.setScale(dist * HANDLE_SIZE / self.fLenPx) def _windowEventHandler(self, window): self.fLenPx = (base.cam.node().getLens().getFocalLength() * window.getXSize()) self._fixScale()
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)