meta data for this page
  •  

Deferred rendering

The SpeedTree SDK comes with example deferred rendering shaders (as well as forward). In comparison to a traditional forward rendering system, integration of SpeedTree into a given engine can be much easier since lighting is handled after the render targets are written; no agreement has to exist between the two systems. Only the format and content of the G-buffer need to agree.

Example G-buffer

The SpeedTree reference application uses an example G-buffer to demonstrate what a complete pipeline might look like with a SpeedTree integration. We fully expect that your G-buffer configuration will not match with our example layout, but it's easy to configure it to match your own format. Specific details of the example G-buffer are best illustrated in [SDK Install Path]/SampleForest/Shaders/Include/gbuffer_example.h.

The example uses two color channels:

struct SExampleGBuffer
{
    float4  m_vRenderTarget0    ST_RENDER_TARGET0;
    float4  m_vRenderTarget1    ST_RENDER_TARGET1;
};

A packing and unpacking function are provided, each operating with these components:

struct SGBufferComponents
{
    float3      m_vColor;
    float       m_fOpacity;
    float3      m_vNormal;
    float       m_fGloss;
    float3      m_vSubsurface;
    float       m_fAO;
    int         m_iGeometryType;
};

The packing function:

void PackGBuffer(ST_REFVAR(SExampleGBuffer) sGBuffer, SGBufferComponents sIn)
{
    // render target 0
    float3 vAdjustedSubsurface = saturate(sIn.m_vSubsurface);
    float fSubsurfaceScale = max(vAdjustedSubsurface.r, max(vAdjustedSubsurface.g, vAdjustedSubsurface.b));
    vAdjustedSubsurface /= max(1.0e-5, fSubsurfaceScale);
 
    sGBuffer.m_vRenderTarget0 = float4(Utility_PackInteger2(float2(sIn.m_vColor.r, vAdjustedSubsurface.r),
                                                            float2(64, 4)) / 256,
                                       Utility_PackInteger2(float2(sIn.m_vColor.g, vAdjustedSubsurface.g),
                                                            float2(64, 4)) / 256,
                                       Utility_PackInteger2(float2(sIn.m_vColor.b, vAdjustedSubsurface.b),
                                                            float2(64, 4)) / 256,
                                       sIn.m_fOpacity);
 
    // render target 1
    sGBuffer.m_vRenderTarget1.rg = Utility_PackNormalIntoFloat2_Spheremap(sIn.m_vNormal);
    sGBuffer.m_vRenderTarget1.b = Utility_PackInteger2(float2(fSubsurfaceScale, sIn.m_fAO), 
                                                       float2(16, 16)) / 256;
    sGBuffer.m_vRenderTarget1.a = Utility_PackInteger2(float2(sIn.m_fGloss, 
                                   float(sIn.m_iGeometryType) / ST_GEOMETRY_TYPE_MAX), float2(32, 8)) / 256;
}

The unpacking function:

void UnpackGBuffer(ST_REFVAR(SGBufferComponents) sOut, SExampleGBuffer sGBuffer)
{
    float2 vColorR = Utility_UnpackInteger2(sGBuffer.m_vRenderTarget0.r * 256, float2(64, 4));
    float2 vColorG = Utility_UnpackInteger2(sGBuffer.m_vRenderTarget0.g * 256, float2(64, 4));
    float2 vColorB = Utility_UnpackInteger2(sGBuffer.m_vRenderTarget0.b * 256, float2(64, 4));
    float2 vUnpack1 = Utility_UnpackInteger2(sGBuffer.m_vRenderTarget1.b * 256, float2(16, 16));
    float2 vUnpack2 = Utility_UnpackInteger2(sGBuffer.m_vRenderTarget1.a * 256, float2(32, 8));
 
    sOut.m_vColor = float3(vColorR.x, vColorG.x, vColorB.x);
    sOut.m_fOpacity = sGBuffer.m_vRenderTarget0.a;
    sOut.m_vNormal = Utility_UnpackNormalFromFloat2_Spheremap(sGBuffer.m_vRenderTarget1.xy);
    sOut.m_fGloss = vUnpack2.x;
    sOut.m_vSubsurface = float3(vColorR.y, vColorG.y, vColorB.y) * vUnpack1.x;
    sOut.m_fAO = vUnpack1.y;
    sOut.m_iGeometryType = int(round(vUnpack2.y * ST_GEOMETRY_TYPE_MAX));
}