Light Prepass test in Direct3D11 (2)

I have implemented light prepass in Direct3D11. Here are some screenshots.



Light Pre-pass test in D3D11


Diffuse light component in Light buffer


Specular light component in Light buffer


Normal component of G-Buffer


And I have pasted the D3D11 HLSL shader codes below.

//--------------------------------------------------------------------------------------
//
// Dx11Common.hlsl ( hanecci 2012/02/28 )
//
//--------------------------------------------------------------------------------------

#define DX11_MAX_POINT_LIGHT_NUM     16

//--------------------------------------------------------------------------------------

cbuffer cbTransformMatrix : register( b0 )
{
    float4x4        mWorldViewProjectionMatrix : packoffset( c0 );
    float4x4        mWorldViewMatrix           : packoffset( c4 );
    float4x4        mProjectionMatrix          : packoffset( c8 );
    float4x4        mWorldMatrix               : packoffset( c12 );
    float4x4        mViewProjectionMatrix      : packoffset( c16 );
    float4          mCameraWorldPos            : packoffset( c20 );
};

static float cMaterialSpecularExponent = 10;

cbuffer cbPerMaterial : register( b1 )
{
    float             mEnableTexture        ;
    float             mEnableDiffuseTexture ;
    float             mEnableNormalTexture  ;
    float             mEnableSpecularTexture;

    float             mEnableDirectionalLight;
    float             mEnablePointLight;

    float             mEnableDiffuseLighting;
    float             mEnableSpecularLighting;
};

//--------------------------------------------------------------------------------------

static const float3 cAmbientLightColor             = float3( 0.05f, 0.05f, 0.05f );

static const float3 cDirectionalLightWorldDir      = float3( 0.0f, -1.0f, 0.0f );
static const float3 cDirectionalLightDiffuseColor  = float3( 1.0f, 1.0f, 1.0f );
static const float3 cDirectionalLightSpecularColor = float3( 1.0f, 1.0f, 1.0f );

static const float  cDirectionalLightDiffuseScale  = 0.5f;
static const float  cDirectionalLightSpecularScale = 0.5f;

//--------------------------------------------------------------------------------------
// Textures and Samplers
//--------------------------------------------------------------------------------------

SamplerState mLinearSampler0  : register( s0 );
SamplerState mLinearSampler1  : register( s1 );

Texture2D    mDiffuseTexture  : register( t0 );
Texture2D    mNormalTexture   : register( t1 );
Texture2D    mPositionTexture : register( t2 );
Texture2D    mSpecularTexture : register( t3 );
Texture2D    mLightTexture    : register( t4 );

//--------------------------------------------------------------------------------------

struct PointLight
{
    float  mEnable;
    float3 mPosition;

    float4 mDiffuseColor;
    float4 mSpecularColor;

    float  mRadius;
    float3 mAttenuation;
};

static const int cMaxPointLightNum = DX11_MAX_POINT_LIGHT_NUM ;

StructuredBuffer<PointLight> mPointLightBuffer : register( t5 );

//--------------------------------------------------------------------------------------

void
getGBufferSurfaceAttributes( in  float2 screenPos,
                             out float3 normal,
                             out float3 position )
{
    int3 sampleIndices = int3( screenPos.xy, 0 );

    normal   = mNormalTexture.Load( sampleIndices ).xyz;
    position = mPositionTexture.Load( sampleIndices ).xyz;
}

//--------------------------------------------------------------------------------------

void
getGBufferMaterialAttributes( in  float2 screenPos,
                              out float4 diffuseAlbedo,
                              out float4 specularAlbedo )
{
    int3 sampleIndices = int3( screenPos.xy, 0 );

    diffuseAlbedo  = mDiffuseTexture.Load( sampleIndices ).xyzw;
    specularAlbedo = mSpecularTexture.Load( sampleIndices ).xyzw;
}

//--------------------------------------------------------------------------------------

float4
getLightTextureAttributes( in float2 screenPos )
{
    int3 sampleIndices = int3( screenPos.xy, 0 );

    return mLightTexture.Load( sampleIndices );
}

//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//
// GBufferDx11.hlsl ( hanecci 2012/02/28 )
//
//--------------------------------------------------------------------------------------

#include "Dx11Common.h"

//--------------------------------------------------------------------------------------

struct VS_INPUT
{
    float4 vPosition    : POSITION;
    float3 vNormal      : NORMAL;
    float2 vTexcoord0   : TEXCOORD0;

#ifdef DX11_ENABLE_NORMAL_MAP
    float3 vTangent     : TANGENT;

  #ifdef DX11_ENABLE_BITANGENT
      float3 vBitangent : BITANGENT;
  #endif

#endif

};

//--------------------------------------------------------------------------------------

struct VS_OUTPUT
{
    float4 vPositionCS  : SV_Position;
    float2 vTexcoord0   : TEXCOORD;
    float3 vNormalWS    : NORMALWS;
    float3 vPositionWS  : POSITIONWS;

#ifdef DX11_ENABLE_NORMAL_MAP
    float3 vTangentWS   : TANGENTWS;
    float3 vBitangentWS : BITANGENTWS;
#endif

};

//--------------------------------------------------------------------------------------

struct PS_INPUT
{
    float4 vPositionSS : SV_Position;
    float2 vTexcoord0  : TEXCOORD;
    float3 vNormalWS   : NORMALWS;
    float3 vPositionWS : POSITIONWS;

#ifdef DX11_ENABLE_NORMAL_MAP
    float3 vTangentWS   : TANGENTWS;
    float3 vBitangentWS : BITANGENTWS;
#endif

};

//--------------------------------------------------------------------------------------

struct PS_OUTPUT
{
    float4 vNormal         : SV_Target0;
    float4 vPosition       : SV_Target1;

#ifdef DX11_ENABLE_MATERIAL_GBUFFER
    float4 vDiffuseAlbedo  : SV_Target2;
    float4 vSpecularAlbedo : SV_Target3;
#endif

};

//--------------------------------------------------------------------------------------

VS_OUTPUT MainVS( VS_INPUT vs_input )
{
    VS_OUTPUT vs_output;

    vs_output.vPositionWS = mul( vs_input.vPosition, mWorldMatrix ).xyz;
    vs_output.vNormalWS   = normalize( mul( vs_input.vNormal, ( float3x3 ) mWorldMatrix ) );
    vs_output.vPositionCS = mul( vs_input.vPosition, mWorldViewProjectionMatrix );

    vs_output.vTexcoord0  = vs_input.vTexcoord0;

#ifdef DX11_ENABLE_NORMAL_MAP
    float3 tangentWS     = normalize( mul ( vs_input.vTangent.xyz,
                                          ( float3x3 ) mWorldMatrix ) );
    vs_output.vTangentWS = tangentWS;

    #ifdef DX11_ENABLE_BITANGENT
      float3 bitangentWS  = normalize( mul ( vs_input.vBitangent.xyz,
                                           ( float3x3 ) mWorldMatrix ) );

    #else
      float3 bitangentWS  = normalize( cross( vs_output.vNormalWS, tangentWS ) );
    #endif

    vs_output.vBitangentWS = bitangentWS;
#endif

    return vs_output;
}

//--------------------------------------------------------------------------------------

PS_OUTPUT MainPS( PS_INPUT ps_input )
{
    PS_OUTPUT ps_output;

    ps_output.vPosition       = float4( ps_input.vPositionWS, posAlpha );

#ifdef DX11_ENABLE_NORMAL_MAP
    if ( mEnableNormalTexture == 1.0f )
    {
        float3x3 tangentFrameWS = float3x3( normalize( ps_input.vTangentWS   ),
                                            normalize( ps_input.vBitangentWS ),
                                            normalize( ps_input.vNormalWS ) );
        float3 normalTS   = mNormalTexture.Sample( mLinearSampler0, ps_input.vTexcoord0 ).rgb;
        normalTS          = normalize( normalTS * 2.0f - 1.0f );

        float3 normalWS   = mul( normalTS, tangentFrameWS );
        ps_output.vNormal = float4( normalWS, normalAlpha );
    }
    else
    {
#endif

    float3 normalWS   = normalize( ps_input.vNormalWS );
    ps_output.vNormal = float4( normalWS, normalAlpha );

#ifdef DX11_ENABLE_NORMAL_MAP
    }
#endif



#ifdef DX11_ENABLE_MATERIAL_GBUFFER
    float4 diffuseAlbedo   = float4( 1.0f, 1.0f, 1.0f, 1.0f );
    if ( mEnableDiffuseTexture == 1.0f )
    {
        diffuseAlbedo = 
            mDiffuseTexture.Sample( mLinearSampler0,
                                    ps_input.vTexcoord0 );
    }
    ps_output.vDiffuseAlbedo = diffuseAlbedo;

    float4 specularAlbedo = float4( 1.0f, 1.0f, 1.0f, 1.0f );
    if ( mEnableSpecularTexture == 1.0f )
    {
        specularAlbedo = 
            mSpecularTexture.Sample( mLinearSampler0, ps_input.vTexcoord0 );
    }
    specularAlbedo.w = cMaterialSpecularExponent;

    ps_output.vSpecularAlbedo = specularAlbedo;
#endif

    return ps_output;
}

//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//
// Dx11LightBuffer.hlsl ( hanecci 2012/02/28 )
//
//--------------------------------------------------------------------------------------

#include "Dx11Common.h"

//--------------------------------------------------------------------------------------

struct VS_Input
{
    float4 vPosition  : POSITION;
};

//--------------------------------------------------------------------------------------

struct PS_Input
{
    float4 vPosition  : SV_Position;
};

//--------------------------------------------------------------------------------------

PS_Input MainVS( VS_Input vs_input )
{
    PS_Input ps_input   = ( PS_Input ) 0;
    ps_input.vPosition  = vs_input.vPosition;

    return ps_input;
}

//--------------------------------------------------------------------------------------

float4
calcDirectionalLighting( float3 surfaceWorldPos,
                         float3 surfaceWorldNormal,
                         float3 lightWorldDir,
                         float3 lightDiffuseColor,
                         float  lightDiffuseScale,
                         float  lightSpecularScale,
                         float  specularExponent )
{
    float4 color        = float4( 0.0f, 0.0f, 0.0f, 0.0f );

    float3 lightDir     = - lightWorldDir;

    float dotValue      = saturate( dot( lightDir, surfaceWorldNormal ) );

    // Diffuse lighting
    float3 diffuseColor = float3( 0.0f, 0.0f, 0.0f );
    float specularValue = 0.0f;
    
    if ( mEnableDiffuseLighting )
    {
        diffuseColor = dotValue * lightDiffuseScale * lightDiffuseColor;
    }

    // Specular lighting
    if ( mEnableSpecularLighting )
    {
        float3 eyeWorldDir =
            normalize( mCameraWorldPos.xyz - surfaceWorldPos );

        float3 halfDir =
            normalize( ( eyeWorldDir + lightDir ) );

        float dotValue = 
            max( dot( surfaceWorldNormal, halfDir ), 0.0f );

        specularValue =
            lightSpecularScale * pow( dotValue, specularExponent );
    }

    color.xyz = diffuseColor;
    color.w   = specularValue;

    return color;
}

//--------------------------------------------------------------------------------------

// Blinn-Phong
float4
calcPointLighting( float3 surfaceWorldPos,
                   float3 surfaceWorldNormal,
                   float specularExponent )
{
    float4 color = float4( 0.0f, 0.0f, 0.0f, 0.0f );

    // Specular lighting
    float3 eyeWorldDir = float3( 0.0f, 0.0f, 0.0f );

    if ( mEnableSpecularLighting )
    {
        eyeWorldDir = normalize( mCameraWorldPos.xyz - surfaceWorldPos );
    }

    for ( int index = 0; index < cMaxPointLightNum; index++ )
    {
        float enableLight         = mPointLightBuffer[ index ].mEnable;
        float3 lightWorldPos      = mPointLightBuffer[ index ].mPosition;

        float3 lightDiffuseColor  = mPointLightBuffer[ index ].mDiffuseColor.xyz;
        float3 lightSpecularColor = mPointLightBuffer[ index ].mSpecularColor.xyz;

        float lightRadius         = mPointLightBuffer[ index ].mRadius;
        float3 lightAttenuation   = mPointLightBuffer[ index ].mAttenuation.xyz;

        float3 lightWorldPosVec = lightWorldPos - surfaceWorldPos;
        float3 lightWorldDir    = normalize( lightWorldPosVec );
        float dotValue          = max( dot( lightWorldDir, surfaceWorldNormal ), 0.0f );

        float3 diffuseColor  = float3( 0.0f, 0.0f, 0.0f );
        float  specularValue = 0.0f;

        // dist
        float lightWorldDist    = length( lightWorldPosVec );

        float attenuation = 1.0f / ( 
                                     lightAttenuation.z * lightWorldDist * lightWorldDist
                                     );

        attenuation      *= saturate( sign( lightRadius - lightWorldDist ) );

        float lightScale  = ( enableLight * dotValue * attenuation );

        if ( mEnableDiffuseLighting )
        {
            diffuseColor = lightDiffuseColor;
        }

        if ( mEnableSpecularLighting )
        {
            float3 halfDir =
                normalize( ( eyeWorldDir + lightWorldDir ) );

            float specularDotValue = 
                max( dot( surfaceWorldNormal, halfDir ), 0 );

            specularValue = 
                lightScale * pow( specularDotValue,
                                  specularExponent );
        }

        color.xyz += lightScale * diffuseColor;
        color.w   += specularValue;
    }

    return color;
}

//--------------------------------------------------------------------------------------

float4
MainPS( PS_Input ps_input ) : SV_Target
{
    float3 worldNormal;
    float3 worldPosition;

    getGBufferSurfaceAttributes( ps_input.vPosition.xy,
                                 worldNormal,
                                 worldPosition );

    float4 color  = float4( 0.0f, 0.0f, 0.0f, 0.0f );

    float specularExponent = cMaterialSpecularExponent;

    if ( mEnableDirectionalLight )
    {
        color.xyzw += calcDirectionalLighting( worldPosition,
                                               worldNormal,
                                               cDirectionalLightWorldDir,
                                               cDirectionalLightDiffuseColor,
                                               cDirectionalLightDiffuseScale,
                                               cDirectionalLightSpecularScale,
                                               specularExponent );
    }

    if ( mEnablePointLight )
    {
        color.xyzw += calcPointLighting( worldPosition,
                                         worldNormal,
                                         specularExponent );
    }

    color = saturate( color );

    return color;
}

//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//
// Dx11LightPrepass.hlsl ( hanecci 2012/02/28 )
//
//--------------------------------------------------------------------------------------

#include "Dx11Common.h"

//--------------------------------------------------------------------------------------

struct VS_Input
{
    float3 vPosition  : POSITION;
    float3 vNormal    : NORMAL;
    float2 vTexcoord0 : TEXCOORD0;
};

//--------------------------------------------------------------------------------------

struct VS_Output
{
    float4 vPosition   : SV_POSITION;
    float2 vTexcoord0  : TEXCOORD0;
};

//--------------------------------------------------------------------------------------

struct PS_Input
{
    float4 vScreenPos  : SV_POSITION;
    float2 vTexcoord0  : TEXCOORD0;
};

//--------------------------------------------------------------------------------------

struct PS_Output
{
    float4 vColor      : SV_Target0;
};

//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------

VS_Output
MainVS( VS_Input vs_input )
{
    VS_Output vs_output;

    float4 pos           = float4( vs_input.vPosition.xyz, 1.0f );
    vs_output.vPosition  = mul( pos,
                                mWorldViewProjectionMatrix );
    vs_output.vTexcoord0 = vs_input.vTexcoord0;

    return vs_output;
}

//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------

PS_Output
MainPS( PS_Input ps_input )
{
    PS_Output ps_output;

    float4 lightVec4       = getLightTextureAttributes( ps_input.vScreenPos.xy );

    float4 diffuseAlbedo   = float4( 1.0f, 1.0f, 1.0f, 1.0f );
    if ( mEnableDiffuseTexture == 1.0f )
    {
        diffuseAlbedo.rgb = 
            mDiffuseTexture.Sample( mLinearSampler0,
                                    ps_input.vTexcoord0 ).rgb;
    }

    float4 specularAlbedo = float4( 1.0f, 1.0f, 1.0f, 1.0f );
    if ( mEnableSpecularTexture == 1.0f )
    {
        specularAlbedo = 
            mSpecularTexture.Sample( mLinearSampler0,
                                     ps_input.vTexcoord0 );
    }

    float4 color = float4( 0.0f, 0.0f, 0.0f, 1.0f );

    float3 diffuseLight  = lightVec4.xyz * diffuseAlbedo.xyz;
    float3 specularLight = lightVec4.w   * specularAlbedo.xyz;

    color.rgb            = saturate( diffuseLight + specularLight );

    ps_output.vColor     = color;

    return ps_output;
}

//--------------------------------------------------------------------------------------