420 likes | 619 Views
95.4002. Mirrors. Implementing “Mirrors”. Many problems to resolve (we’ll consider each as we encounter them). Reflected O 1 is visible. objects already behind should not appear in front. O 1. O 2. Reflected O 2 should not be visible. Example: The Back of the Mirror.
E N D
95.4002 Mirrors
Implementing “Mirrors” • Many problems to resolve (we’ll consider each as we encounter them). ReflectedO1 is visible objectsalready behindshould notappear in front O1 O2 Reflected O2should not be visible
Implementing “Mirrors” • Strategy: Draw all objects twice. • Once normally. • Once reflected and clipped to mirror region. Use reflection transformation R O2 is not visible O1 O2 Warning: We Will Find Out That We Have To Do It In The Other Order
Recall: W versus W-1 • Vehicle’s W maps from local to world. • Vehicle’s W-1maps back from world to local. W Mirror z-axispoints behindmirror W-1 Treat mirror like a vehicle…
To “Reflect” an Object About The Mirror • Replace the object’s local to world transformation W by WR where WM is the mirror’s local to world transf.. Sz=-1is the transf.. that scales z by -1; i.e., scale by x = 1.0, y = 1.0, z = -1.0. R = WM-1 Sz=-1 WM Explanation on next page.
Explaining the “Reflect” Transformation • Why replacing W by WR mirrors the object. W object in world coordinates. WWM-1 object in mirror’s local coordinates WWM-1Sz=-1 makes front go behind and vice versa (flips sign of z). WWM-1Sz=-1WMback to world coordinates. R = WM-1 Sz=-1 WM IF WM converts local to world, THEN WM-1 converts world to local
A Side-Effect of the “Reflect” Transformation • A front-facing face becomes back facing (and vice-versa). Will this be afront or backface? 2 1 1 2 front tnorf 4 4 3 3 This must be counteracted.
Solution: Flip Face Visibility • Two possible solutions: • Flip which faces must be culled using • glCullFace (GL_BACK); //or GL_FRONT • Flip polygon vertex ordering; i.e., clockwise to anti-clockwise (or vice versa) • glFrontFace (GL_CW); //or GL_CCW
Reflected Back Objects Become Visible Too? • Must eliminate those objects that WERE behind (after the reflection, they are in front). Before After behind in front (not wanted)
Solution: Clip Undesired Objects Positive side drawsNegative side disappears • Approach: • Use a clipping plane • glEnable (GL_CLIP_PLANE0); glClipPlane (GL_CLIP_PLANE0, plane); • But be careful • PLANES BEHAVE LIKE LIGHTS. They are • transformed from local to camera • coordinates and then stay UNCHANGED • relative to the camera EVEN IF THE • CAMERA IS MOVED.
Let’s Look At A Top View To See Where The Plane is Relative To The Camera a mirror islike a vehicle Where is the planeNORMAL relative to the mirror? negative z clipping plane Mirror withM and M-1 Where is the planerelative to the camera? pointing toward camera Camera with C and C-1
Clipping Plane Details Plane = [Nx,Ny,Nz,-N.P0] Mirror z-axispoints behindmirror • Plane at mirror center P0=[0,0,0] relative to mirror local coordinates P = {0,0,1,0} , -N.P0=0 • Plane in world coordinates P*M • Plane as seen by camera P*MC-1 Mirror withM and M-1 Camera with C and C-1
Tell Renderer To Clip Undesired Objects • Solution: Specify plane in local coordinates • Set up stack to contain MC-1 (M is mirror transformation, C is camera). • glPushMatrix (); //Assuming C-1 is already on stack • glMultMatrix (mirrorLocalToWorld); //M Gldouble localPlane = {0.0, 0.0, 1.0, 0.0}; //Normal is -ve z-axis (to keep what mirror sees). glClipPlane (GL_CLIP_PLANE0, localPlane); • glPopMatrix (); //restore Clipping plane points in direction that is KEPT..
Another Problem: Won’t Z-Buffering Screw up? • We need to render objects twice, once normally and once reflected-and-with-back-objects-clipped. • What about objects obscured by mirror? Isn’t O3closerthan reflected O1? O2 Solution: Draw INSIDE first and OUTSIDE last… O1 O3 Reflected O1
Partial solution: I Call It Hardening The Mirror • IN MIRROR ONLY, PASS1: Render all objects reflectedand back clipped (exclude mirror; reflected O1 drawn but not O2 or O3). Get just . • Render mirror but disable coloringto harden it(z-buffer works; everythingin mirror get mirror’sz-depth). • PASS2: Render all objects normally(exclude mirror; O1, O2 and O3 will be drawn properly z-buffered). Get both O2 O1 O3 (O1+O2) +
Rendering The Mirror • Disable coloring but permit z-buffering. • glColorMask (0, 0, 0, 0); //Disable coloring; 0 for false. • Render the mirror as if there were something to draw. • … render mirror polygon ... • Enable coloring once again. • glColorMask (1, 1, 1, 1); //Enable coloring; 1 for true.
One Remaining Problem (Drawing only INSIDE) • How do we draw ONLY inside the mirror. If not done, reflected O2 will be visible! O1 O2 Reflected O2 should not be visible • Solution should handle arbitrary shaped mirrors.
How to Clip To Mirror Interior • Need to mask area by rendering the mirror first without coloring or z-buffering (to handle arbitrary mirror shapes). • Then need to render reflected objects only inside the masked area. should notbe visible O1 O2
Using Stencil Functions/Operations • The stencil buffer has available a fixed number of bits per screen pixel; e.g., 8 bits. • These bits can all be set to any integer value; e.g. 0 or 255. • Some of these bits can be ignored with suitable masks; e.g., 0x0F only looks at the right 4 bits.
Using Stencil Functions/Operations • How Stencil Buffer is Used (Done in Hardware) • If stencil test passes, drawing is allowed. • Stencil buffer changed according to operation. • glStencilFunc (operation, data, mask) QUERY: Do masked stencil buffer bits at point being drawn satisfy “data operation bits”; i.e., 5< bits. Example: glStencilFunc (GL_LESS, 5, 0x0F); • glStencilOp (failRule, passZfailRule, passZpassRule) MODIFICATION: bits := rule (bits) Example rule: GL_INCR, GL_ZERO. ORDER IS BACKWARD
Sample Stencil Functions/Operations • glStencilFunc (function, data, mask) GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL TEST: Do masked stencil bits satisfy “5< stencil bits” Example: glStencilFunc (GL_LESS, 5, 0x0F); • glStencilOp (iffails, ifpassesButZfails, ifpassesAndZpasses) GL_KEEP, GL_ZERO, GL_INCR, GL_DECR, GL_REPLACE (by data), GL_INVERT MODIFICATION: bits := rule (bits)Except for replace
Sample Stencil Functions/Operations • glStencilMask (mask) Controls which bits are changed by glStencilOp. Default is: all bits; i.e., mask = 0xffffffff ~0 equivalent to 0xffffffff Not needed here but other applications might.
Creating a Mask (4 steps: first 2) • Enable the stencil buffer glEnable (GL_STENCIL_TEST); glClearStencil (0); //The fill value to use. glClear (GL_STENCIL_BUFFER_BIT); //Now fill. • Disable coloring and z-buffering glColorMask (0, 0, 0, 0); //Disable coloring; 0 for false. glDisable (GL_DEPTH_TEST); The stencil buffer can perform masking.
Creating a Mask (4 steps: last 2) • Ensure that any drawn location replaces stencil bits (currently 0) by 1. glStencilFunc (GL_NEVER, 1 “variable”, ~0 “mask”); //On anything, fail the test (so nothing draws). glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); //ifF, ifPButZfails, ifPAndZpasses //Always replace bits that fail by 1. • Render mirror as if it were a normal object • … render mirror ... All mirror bits NOW 1.
Rendering Inside the Mask • Re-enable coloring and depth buffering. • glColorMask (1, 1, 1, 1); //Enable coloring; 1 for true.glEnable (GL_DEPTH_TEST); • Don’t allow stencil bits to change anymore. • glStencilFunc (GL_EQUAL, 1, ~0); //On 1 pass the test and keep bits unchanged. • glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); • Render reflected objects as discussed earlier • … render reflected objects …
Implementing “Mirrors” • So many steps (perhaps a summary is needed). ReflectedO1 is visible objectsalreadybehind O1 O2 ReflectedO2 is not visible
Implementing “Mirrors” (Summary) • Create stencil mask from mirror face • Disable coloring and z-buffering. Enable stencil buffering to set to 1 when drawing. Set up mirror and render it to make mirror bits 1. • In mirror, render reflected world (no mirror) • Enable coloring and z-buffering (stencil still enabled). Set up stencil buffer to not change bits. Set up reflection matrix and back clipping plane. Flip front/back facing test.Renderwhole world (mirror excluded). Disable stencil buffering and clipping plane. Restore front/back facing test.
Implementing “Mirrors” (Summary) • Render mirror to “harden it” • Disable coloring but NOT z-buffering. Set up mirror and render it. • Alternative: use blending and draw mostly transparent but slightly colored mirror. • Outside mirror, render world (no mirror) • Enable coloring.Render whole world (mirror excluded).
95.4002 Mirrors UsingSide Clipping Planes(Instead of a Stencil Buffer)
Clipping Plane Approach • Advantages: Not all cards support stencil buffers (today, they probably all do…). Better reason: stencil buffer also useful for shadows (conflict). • Disadvantages: • Can’t handle unusual shapes since number of clipping planes is limited (currently, 6 is limit and 1 is needed for clipping out back side objects; so really only have 5). • Recursivelyclipped mirrors can end up with many more sides than 4… (must approximate with 5). See next slide…
Recursive Mirrors More Difficult • When more than 5 planes are needed to represent sub-mirrors, there are artifacts. Imagine that PART of the yellow mirror is visible inside mirror1. 6 planes needed to bound it (one more than allowed)… mirror2 seen inside mirror1has 6 sides AFTER CLIPPING mirror1
95.4002 Recursive Mirrors
Recursive Mirrors • Main idea • Use a counter incrementing as you go deeper/decrementing as you come back. First mirror at 1, inside ones at 2, inside those at 3, … alternating front/back facing order… • For the stencil buffer approach, make mask that matches counter. • For planes approach, compute new planes pushing old ones onto a stack (activate only top INNERMOST ones).
Interactions with Visibility visibility cameraposition • Consider reflected frustum. mirror Region 1 portal virtual(reflected)camera Region 4 Region 2 portal Region 3 camera
Visibility in Recursive Mirrors • Should adjust the frustum by narrowing onto mirror (need not be exact… JUST contain). • Reflect the narrowed frustum. • When drawing world in mirror, take reflected frustum visibility into account. and visibility camera position (a point in front of mirror; not the camera position nor the reflected camera position) if you are computing region visibility. Why: Because The Region You Are In Must Be Where The Front of the Mirror is Located
Recursive Mirrors: Reflections • Camera must be reflected in such a way that routines that make use of the camera for drawing special effects do not know it was done(e.g., coronas, lens flares, sun flares, sprites, etc make use of camera position) • When camera is asked for position, it returns it’s virtual reflected position (notvisibility position). • Lights on player get reflected; so they must be recomputed…
95.4002 Implementing Remote Cameras By Drawing into a Texture
Much Simpler Than A Mirror • Switch to the remote camera. • Render world normally. • Copy what you drew onto a texture. • Switch back to the normal camera. • Draw the mirror’s “face” using the new texture bits. Display Normalcamera Remotecamera
Drawing into Restricted Area Of Color Buffer glPushAttrib (GL_VIEWPORT_BIT); //draw glEnable (GL_SCISSOR_TEST); //into glScissor (0, 0, 64, 64); //top-left glViewport (0, 0, 64, 64); //part glClearColor (0.0f, 0.0f, 0.0f, 1.0f); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); Setup new camera matrix, etc. Draw whatever you want to draw. glPopMatrix(); glDisable (GL_SCISSOR_TEST); glPopAttrib();
Moving Color Buffer To Your Texture Select/activate a texture handle to draw into. Then … glCopyTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, 0, 0, 64, 64, 0); Problem: It’s very slow to copy from aback buffer to a texture. Can draw directly into a second back buffer that is simultaneously a texture New cards support frame buffers (back buffers built from textures that can be drawn with).