Using the Stencil Buffer Advanced D 3 D
Using the Stencil Buffer Advanced D 3 D Programming Sim Dietrich SDietrich@nvidia. com
Overview • • What is a Stencil Buffer? Direct 3 D Stencil Pipeline Stencil Comparison Function Stencil Operations Example - Masking a Car Interior Example - Depth Complexity Example - Shadow / Light Volumes
What is a Stencil Buffer? • Stencil bits are stored with the Z Buffer • Typically consists of 1 or 8 bits • Stencil allows apps to ‘tag’ various regions of the frame buffer • Can be used for shadow/light volumes, masking, reflections and measuring depth complexity
Stencil Pipeline & STENCIL_REF STENCIL_FAIL STENCIL_MASK Fail & Stencil Buffer Stencil Write Mask Stencil Test Pixel Rejected Pass STENCIL_ZFAIL Fail Depth Test Pixel Rejected & & Pass Pixel Accepted & STENCIL_PASS
Stencil Comparison Function • D 3 DCMPFUNC ( Just like Depth Test ) • • D 3 DCMP_NEVER D 3 DCMP_LESS D 3 DCMP_EQUAL D 3 DCMP_LESSEQUAL D 3 DCMP_GREATER D 3 DCMP_NOTEQUAL D 3 DCMP_GREATEREQUAL D 3 DCMP_ALWAYS – D 3 DSTENCIL_WRITEMASK – Limits updates to bits of the stencil buffer
Stencil Operations • Set for each of three cases – STENCIL_FAIL ( Failed Stencil Test, pixel is dropped ) – STENCIL_ZFAIL ( Passed Stencil, Failed Z ) – STENCIL_PASS ( Passed Both Stencil and Z ) • D 3 DSTENCILOP_KEEP – Leave current stencil value alone
Stencil Operations (cont. ) • D 3 DSTENCILOP_ZERO – Set Stencil to Zero • D 3 DSTENCILOP_REPLACE – Set to Stencil Reference Value • D 3 DSTENCILOP_INCRSAT – Add one to Stencil, clamp to maximum value • D 3 DSTENCILOP_DECRSAT – Minus one from Stencil, clamp to Zero
Stencil Operations (cont. ) • D 3 DSTENCILOP_INVERT – If bit is 1, make it 0 – If bit is 0, make it 1 • D 3 DSTENCILOP_INCR – Add 1 to stencil, wrap to 0 • D 3 DSTENCILOP_DECR – Minus 1 from stencil, wrap to maximum value • Maximum Value is 2(# of Stencil Bits) - 1
Example - Masking a Car Interior • Imagine a in-car view of a driving game • Why re-draw the car’s interior each frame? • Stencil can be used to Mask it • Clear Stencil Buffer to 0 when Z buffer is cleared • Set Stencil Compare Function D 3 DCMP_ALWAYS • Set Stencil Operation for STENCIL_PASS to D 3 DSTENCILOP_INCRSAT • Set Stencil Write Mask to 0 x. FF • Draw car interior, thereby setting stencil >= 1 for each pixel it covers
Masking a Car Interior (cont. ) – Now draw the rest of the scene • Set Stencil Reference Value to Zero • Set Stencil Compare Function: D 3 DCMP_EQUAL • Set Stencil Operation for STENCIL_PASS ( for passing both Z and Stencil Tests ) to D 3 DSTENCILOP_KEEP – This tells the card to only draw where it sees a Zero in the Stencil Buffer – The car interior was drawn with stencil of 1 or higher, so it will not be overwritten.
Measuring Depth Complexity • Depth Complexity is the average # of times a pixel is redrawn in one scene • Determines the maximum performance limit at various resolutions • Maximum Frame Rate <= ( Fill Rate ) / ( Depth Complexity * Resolution ) • Stencil can be used to count each time a pixel is drawn, thereby measuring Depth Complexity of any scene
Measuring Depth Complexity – Clear Stencil Buffer to 0 when Z buffer is cleared – Set Stencil Compare Function to D 3 DCMP_ALWAYS – Set Stencil Operation for STENCIL_PASS and STENCIL_ZFAIL to D 3 DSTENCILOP_INCRSAT – Set Stencil Write Mask to 0 x. FF – Draw scene, thereby setting stencil >= 1 for each pixel drawn
Measuring Depth Complexity • Stencil Buffer now holds a count of how many times each pixel was drawn • Lock and read back the stencil buffer • Sum all stencil buffer values and divide by resolution of the viewport • That number is the scene’s depth complexity • Set the Z Fail operation to INCRSAT to count Z rejected pixels
Shadow and Light Volumes • Many shadow algorithms project on to the floor or ground plane • They don’t handle objects that are inside another object’s shadow • To handle this case, apps have to test vertices against the shadowed area • Stencil and depth buffer can perform perpixel intersection calculations instead
Shadow And Light Volumes • Shadow volumes are best used when the shadow-casting object is simple, and the shadowed geometry is complex • Think of the volume of light that is blocked by an object from the light direction • Find the silhouette of our shadowing object – Use the lowest detail level model if possible • Create a volume from the silhouette’s projection from the light direction
Shadow Volume Example
Shadow and Light Volumes • We want the stencil bit for the shadow volume to be ‘ 1’ for each pixel that should be darkened, and Zero for all others • We can use the depth buffer to perform an intersection operation, and record the result in the stencil buffer • We draw the back and front faces of the shadow volume into the stencil buffer only
Shadow and Light Volumes • We want to mark all pixels that are inside the shadow volume – In front of the back faces of the shadow volume – In back of the front faces of the shadow volume • So, a pixel inside the shadow volume should cause the first depth test to fail, and the second one to pass. Other cases will pass or fail or twice.
Setting Up the Stencil Pipeline • Here is the process : – Clear the Stencil Buffer to 0 with Depth clear – Render entire lighted scene as usual – Set the Stencil Mask for the light’s bit (ie 0 x 01) – Set the Stencil Write Mask for the light’s bit ( ie 0 x 01 ) • We can have a separate bit for each light that casts shadows, up to the number of stencil bits, unless we wish perform multiple stencil passes for more lights
Setting Up the Stencil Pipeline – Set the Stencil Comparison Function to D 3 DCMP_ALWAYS – Set the Stencil Z Fail to D 3 DSTENCILOP_INVERT – Set the Stencil Pass Function to D 3 DSTENCILOP_KEEP – The Stencil Fail function is a don’t care, because we set the stencil test to always pass – Set the Stencil Reference value to 0 x. FF
Shadow and Light Volumes • Set cull mode to D 3 DCULL_NONE • We need the both back and front faces of the shadow volume to be ‘drawn’ into the stencil buffer • We don’t want them in the frame buffer, so set the alpha blend mode to – D 3 DRENDERSTATE SRCBLEND = D 3 DBLEND_ZERO – D 3 DRENDERSTATE DESTBLEND = D 3 DBLEND_ONE
Shadow And Light Volumes • Turn off Z writes – D 3 DRENDERSTATE_ZWRITEENABLE = FALSE • ‘Draw’ the Shadow volume • The stencil buffer will now contain a 1 at the appropriate bit for each pixel in the scene that lies within the shadow volume
Scene before Shadow Volume Depth =. 6 Stencil = 0 + Z Axis Depth =. 5 Stencil = 0 Light Vector Occluding Object Depth =. 4 Stencil = 0 + X Axis
After Front Face of Volume Depth =. 6 Stencil = 0 + Z Axis Depth =. 5 Stencil = 0 Light Vector Occluding Object Depth =. 4 Stencil = 1 Front Face of Shadow Volume + X Axis
After Back Face of Volume Depth =. 6 Stencil = 0 + Z Axis Depth =. 5 Stencil = 1 Light Vector Occluding Object Depth =. 4 Stencil = 0 Back Face of Shadow Volume + X Axis
Shadow And Light Volumes • Now, we need to apply an effect to these pixels. . . • Set up the stencil tests to only affect pixels that correspond to the appropriate stencil bit for our light • Set the Stencil Comparison Function to D 3 DCMP_EQUAL – Set the Stencil Mask value to match the light’s bit ( ie 0 x 01 )
Shadow and Light Volumes – Set the Stencil Write Mask to match the light’s bit ( ie 0 x 01 ) – Set the Alpha Blend function for our effect • Make the rectangle out of the light color and use – ONE, ONE for a Volumetric Additive effect – ZERO, SRCALPHA for a Darkening Shadow – ONE, ZERO for a color replacement effect • Draw the rectangle and the effect is composited into the scene
Handling Multiple Lights • We can use as many lights as the stencil buffer has bits, ie 1 or 8. • We could handle more with multiple stencil passes, by changing which bits refer to which lights • We need to do one blend operation per light • We can do the all volumes for one light by using a big enough rectangle
Handling Complex Volumes • If your geometry produces a selfintersecting volume, INVERT won’t work • Instead, you can render the volume’s back faces with ZFAIL set to INCRSAT, and the volume’s front faces with DECRSAT • Pixels in the volume will have non-zero stencil bits • But, multiple lights require more passes
Caveats • When clipping your volume, make sure it remains closed - You need an even number of intersections with the shadow volume to avoid being darkened • If the viewer is inside a shadow volume, there will be only one intersection with that volume, thus reversing what is in or out of shadow, unless you cap your volume with a polygon at the near clipping plane
Caveats • We can draw the front or back faces of the volume instead of the screen-aligned rectangle, but it is likely to be more expensive, and really should be sorted for some blending effects • The shadow volume is capped at the view frustum, which means that shadows can be cast onto more than one wall if not clipped to the first wall.
Other Approaches • One fundamental problem with the ‘darkening’ approach presented here is that it is a purely pixel-space process. You have lost all information about materials, fog, etc. The advantage is that you render the scene only once. • An alternative is to re-render the stencilmarked pixels within the shadow volume with the light turned off for more accuracy
Other Approaches • A more accurate way to simulate objects in shadow is to avoid lighting them with the blocked lights to begin with, rather than just darkening them after the fact – Render flat-shaded scene into depth buffer only – Careful with alpha-tested transparent texures – Render shadow volume into stencil – Render textured scene with the light ON to everywhere but shadowed area – Render scene with light OFF to shadowed area
Other Approaches • For a smoother shadow edge on the floor or walls, connect a scaled-up version of the shadow volume to the original shadow volume. Set the Alpha on the original vertices to 0 xff and the Alpha on the scaled up version to 0 and connect them. • Note that this only works for surfaces that you cap the volume to ( like walls or a floor ), not for intermediate objects in the shadow volume
Questions ? ? ? ? Sim Dietrich SDietrich@nvidia. com www. nvidia. com ?
- Slides: 35