Wednesday, September 8, 2010

Light Pre-Pass Rendering

This is my implementation of Light Pre-Pass Rendering. 


It's a deferred lighting technique (similar to deferred shading, but without the need for big G-Buffers) - Basically, in a first pass you render depth and normals, then accumulate lighting values of all lights into a light buffer rendertarget (using the normals stored in the first pass) and finally in the third step you compose the lighting info with your material info (textures, etc.) during forward rendering.

You should check the presentations by Wolfgang Engel and others for more background info, the method is currently very popular on PS3/XBox (Uncharted, Resistance2, LBP, Blur, to name a few).

Some notes on the code:
  • the ZN pre-pass stores depth and view-space normals packed in a single ARGB8888 rendertarget using 2x8-bit components each
  • to encode the normals I use the old N.z = sqrt(1-dot(N.xy, N.xy) trick which is not 1oo% correct, but works OK for now
  • to en/decode the depth values I came up with the following formulas, didn't check yet if there are better solutions (Note: farZ = cameraFarPlane / 256.0) :
float2 EncodeFloat16(float v) { 
    float fac = v / 256.0f; 
    float fra = frac(fac); 
    return float2((fac-fra) / farZ, fra); 
} 

float DecodeFloat16(float2 v) { 
    return (v.x * farZ + v.y) * 256.0f; 
} 
  • compositing the lighting info in the second (forward) geometry pass is done in linear color space: textures are converted from gamma2 to gamma1 during texture fetch, and the final result is converted back to gamma2 for display
  • the ZN ARGB8888 packing of course causes some artifacts, but it's still acceptable in my current test scenes

No comments:

Post a Comment