Browse Source

*** empty log message ***

David Rose 21 years ago
parent
commit
a631177547
1 changed files with 113 additions and 0 deletions
  1. 113 0
      direct/src/showbase/MirrorDemo.py

+ 113 - 0
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)
+