Rendering deferred lights using Stencil culling algorithm
Yuriy O'Donnell, March 14th, 2009 Updated July 12, 2011
This algorithm works for all lights regardless of whether camera is inside the light volume or not.
However, it will only work well on PC hardware. It will not work on PS3 or 360, where setting up early Stencil culling functionality needs some special attention.
Each light volume (low poly sphere) is rendered it two passes.
- Front (near) faces only
- Colour write is disabled
- Z-write is disabled
- Z function is 'Less/Equal'
- Z-Fail writes non-zero value to Stencil buffer (for example, 'Increment-Saturate')
- Stencil test result does not modify Stencil buffer
This pass creates a Stencil mask for the areas of the light volume that are not occluded by scene geometry.
- Back (far) faces only
- Colour write enabled
- Z-write is disabled
- Z function is 'Greater/Equal'
- Stencil function is 'Equal' (Stencil ref = zero)
- Always clears Stencil to zero
This pass is where lighting actually happens. Every pixel that passes Z and Stencil tests is then added to light accumulation buffer.
Diagram below shows effects of Z and Stencil tests:
- Blue -- pixels which pass Z test in Pass 1 (their near faces are closer than any world geometry). They leave Stencil at zero.
- Red -- pixels which pass Z test in Pass 2 (their far faces are further than any world geometry). However, some red pixels fail Stencil test.
- Green -- Pixels which pass Z and Stencil tests in Pass 2 and therefore get rendered into light accumulation buffer.
Light 1 has both near and far faces in front of all world geometry. It will pass Z test for near face, but will fail Z test for far face. Therefore it's pixel shader will not run.
Light 2 will fail Z test for near face, write non-zero value to Stencil and then fail Stencil test for far face. Again, no pixels will get through.
Light 3 will behave like Light 2 in the bottom part, but top part will pass both Z and Stencil tests and therefore will get rendered.
If camera is inside a light volume, near faces will not get rendered. Stencil value will be zero for back faces and so only Z test will decide if pixel shader should run.
You should be able to inspect it using NVIDIA PerfHUD.
WASD -- up/down/left/right EQ -- forward/back ZX -- rotate Arrows/Left mouse button -- look around Space -- animate lights