From a631177547d3777ff2bb3423e546a02396c3a6d8 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 1 Mar 2005 04:54:15 +0000 Subject: [PATCH] *** empty log message *** --- direct/src/showbase/MirrorDemo.py | 113 ++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100755 direct/src/showbase/MirrorDemo.py diff --git a/direct/src/showbase/MirrorDemo.py b/direct/src/showbase/MirrorDemo.py new file mode 100755 index 0000000000..198d060b53 --- /dev/null +++ b/direct/src/showbase/MirrorDemo.py @@ -0,0 +1,113 @@ +"""This file demonstrates one way to create a mirror effect in Panda. +Call setupMirror() to create a mirror in the world that reflects +everything in front of it. + +The approach taken here is to create an offscreen buffer with its own +camera that renders its view into a texture, which is then applied to +the mirror geometry. The mirror's camera is repositioned each frame +with a task to keep it always on the opposite side of the mirror from +the main camera. + +This demonstrates the basic interface for offscreen +render-to-a-texture in Panda. Similar approaches can be used for +related effects, such as a remote spy camera presenting its view onto +a closed-circuit television screen. + +In this example the mirror itself is always perfectly flat--it's just +a single polygon, after all--but small distortions of the mirror +surface are possible, like a funhouse mirror. However, the reflection +itself is always basically planar; for more accurate convex +reflections, you will need to use a sphere map or a cube map.""" + +from pandac.PandaModules import * +from direct.task import Task + +def setupMirror(name, width, height): + # The return value is a NodePath that contains a rectangle that + # reflects render. You can reparent, reposition, and rotate it + # anywhere you like. + + root = render.attachNewNode(name) + + # Create a polygon to be the visible representation of the mirror. + cm = CardMaker('mirror') + cm.setFrame(-width / 2.0, width / 2.0, -height / 2.0, height / 2.0) + cm.setHasUvs(1) + card = root.attachNewNode(cm.generate()) + + # Create a PlaneNode to represent the mirror's position, for + # computing where the mirror's camera belongs each frame. + plane = Plane(Vec3(0, -1, 0), Point3(0, 0, 0)) + planeNode = PlaneNode('mirrorPlane') + planeNode.setPlane(plane) + planeNP = root.attachNewNode(planeNode) + + # Now create an offscreen buffer for rendering the mirror's point + # of view. The parameters here control the resolution of the + # texture. + buffer = base.win.makeTextureBuffer(name, 256, 256) + #buffer.setClearColor(base.win.getClearColor()) + buffer.setClearColor(VBase4(0, 0, 1, 1)) + + # Set up a display region on this buffer, and create a camera. + dr = buffer.makeDisplayRegion() + camera = Camera('mirrorCamera') + lens = PerspectiveLens() + lens.setFilmSize(width, height) + camera.setLens(lens) + cameraNP = planeNP.attachNewNode(camera) + dr.setCamera(cameraNP) + + # Since the reflection matrix will reverse the vertex-winding + # order of all the polygons in the world, we have to tell the + # camera to reverse the direction of its face culling. We also + # tell it not to draw (to clip) anything behind the mirror plane. + camera.setInitialState(RenderState.make( + CullFaceAttrib.makeReverse(), + ClipPlaneAttrib.make(ClipPlaneAttrib.OAdd, planeNode))) + + # Create a visible representation of the camera so we can see it. + cameraVis = loader.loadModel('camera.egg') + if not cameraVis.isEmpty(): + cameraVis.reparentTo(cameraNP) + + # Spawn a task to keep that camera on the opposite side of the + # mirror. + ul = + def moveCamera(task, cameraNP = cameraNP, plane = plane, + planeNP = planeNP, card = card, lens = lens, + width = width, height = height): + # Set the camera to the mirror-image position of the main camera. + cameraNP.setMat(base.camera.getMat(planeNP) * plane.getReflectionMat()) + + # And reset the frustum to exactly frame the mirror's corners. + # This is a minor detail, but it helps to provide a realistic + # reflection and keep the subject centered. + ul = cameraNP.getRelativePoint(card, Point3(-width / 2.0, 0, height / 2.0)) + ur = cameraNP.getRelativePoint(card, Point3(width / 2.0, 0, height / 2.0)) + ll = cameraNP.getRelativePoint(card, Point3(-width / 2.0, 0, -height / 2.0)) + lr = cameraNP.getRelativePoint(card, Point3(width / 2.0, 0, -height / 2.0)) + lens.setFrustumFromCorners(ul, ur, ll, lr, Lens.FCCameraPlane | Lens.FCOffAxis | Lens.FCAspectRatio) + + return Task.cont + + # Add it with a fairly high priority to make it happen late in the + # frame, after the avatar controls (or whatever) have been applied + # but before we render. + taskMgr.add(moveCamera, name, priority = 40) + + # Now apply the output of this camera as a texture on the mirror's + # visible representation. + card.setTexture(buffer.getTexture()) + + return root + +def showFrustum(np): + # Reveal the frustum for a particular camera. + cameraNP = np.find('**/+Camera') + camera = cameraNP.node() + lens = camera.getLens() + geomNode = GeomNode('frustum') + geomNode.addGeom(lens.makeGeometry()) + cameraNP.attachNewNode(geomNode) +