prime31
4/15/2016 - 5:30 AM

2D deferred lighting implementation (first pass, not optimized)

2D deferred lighting implementation (first pass, not optimized)

// ##### ##### ##### ##### ##### ##### #####
// ##### ##### Common Uniforms   ##### #####
// ##### ##### ##### ##### ##### ##### #####

float4x4 _objectToWorld;
float4x4 _worldToView;
float4x4 _projection; // viewToCamera?
float4x4 _screenToWorld; // this is used to compute the world-position

// color of the light 
float3 _color;

// this is the position of the light
float3 _lightPosition;

// how far does this light reach
float _lightRadius;

// control the brightness of the light
float _lightIntensity;

// normal map
SamplerState _normalMap;


// ##### ##### ##### ##### ##### ##### #####
// ##### Spot light uniforms     ##### #####
// ##### ##### ##### ##### ##### ##### #####
float _coneAngle;
float2 _lightDirection;


// ##### ##### ##### ##### ##### ##### #####
// ##### Directional light uniforms    #####
// ##### ##### ##### ##### ##### ##### #####
// direction of the light
float3 _dirLightDirection;

// specular intentity
float _specularIntensity;

// specular power
float _specularPower;


// ##### ##### ##### ##### ##### ##### #####
// ##### Final combine uniforms        #####
// ##### ##### ##### ##### ##### ##### #####
SamplerState _colorMap;
SamplerState _lightMap;
float3 _ambientColor;



// ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####
// ##### ##### Clear GBuffer     ##### ##### ##### ##### ##### ##### #####
// ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####

struct PixelMultiTextureOut
{
    float4 color : COLOR0;
    float4 normal : COLOR1;
};


float4 clearGBufferVert( float4 position:POSITION0 ) : POSITION0
{
    return position;
}


PixelMultiTextureOut clearGBufferPixel( float4 position:POSITION0 )
{
    PixelMultiTextureOut output;

    // black color
    output.color = 0.0f;
    output.color.a = 0.0f;

    // when transforming 0.5f into [-1,1], we will get 0.0f
    output.normal.rgb = 0.5f;
    output.normal.a = 1.0f;

    return output;
}


// ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####
// ##### ##### Point Light 		 ##### ##### ##### ##### ##### ##### #####
// ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####

struct VertexPointSpotOut
{
    float4 position 		: POSITION0;
    float4 screenPosition 	: TEXCOORD1;
	float4 world			: TEXCOORD3;
};


VertexPointSpotOut pointLightVert( float4 position:POSITION0 )
{
    VertexPointSpotOut output;

    // process geometry coordinates
    float4 worldPosition = mul( position, _objectToWorld );
    float4 viewPosition = mul( worldPosition, _worldToView );
    output.position = mul( viewPosition, _projection );

    output.screenPosition = position;
    output.world = output.position;

    return output;
}


float4 pointLightPixel( VertexPointSpotOut input ) : COLOR0
{
    float2 screenPos = input.world.xy / input.world.w;
    float2 screenSpaceTexCoord = 0.5f * float2( screenPos.x, -screenPos.y ) + 0.5f;

    // obtain screen position
    input.screenPosition.xy /= input.screenPosition.w;

    // get normal data from the normalMap
    float4 normalData = tex2D( _normalMap, screenSpaceTexCoord );

    // tranform normal back into [-1,1] range
    float3 normal = 2.0f * normalData.xyz - 1.0;
    normal.y *= -1.0;

    // screen-space position
    float4 position = float4( screenPos, 0.0, 1.0 ); // optional future change: add depth texture and stick the value here

    // transform to world space
    position = mul( position, _screenToWorld );

    // surface-to-light vector
    float3 lightVector = _lightPosition - position.xyz;

    // compute attenuation based on distance - linear attenuation
    float attenuation = saturate( 1.0f - length( lightVector ) / _lightRadius );

    // normalize light vector
    lightVector = normalize( lightVector ); 

    // compute diffuse light
    float NdL = max( 0, dot( normal, lightVector ) );
    float3 diffuseLight = NdL * _color.rgb;

    // take into account attenuation and lightIntensity.
    float4 result = attenuation * _lightIntensity * float4( diffuseLight.rgb, 1.0 );
    return result;
}



// ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####
// ##### ##### Spot Light        ##### ##### ##### ##### ##### ##### #####
// ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####

VertexPointSpotOut spotLightVert( float4 position:POSITION0 )
{
    VertexPointSpotOut output;

    // process geometry coordinates
    float4 worldPosition = mul( position, _objectToWorld );
    float4 viewPosition = mul( worldPosition, _worldToView );
    output.position = mul( viewPosition, _projection );

    output.screenPosition = position;
    output.world = output.position;

    return output;
}


float4 spotLightPixel( VertexPointSpotOut input ) : COLOR0
{
    float2 screenPos = input.world.xy / input.world.w;
    float2 screenSpaceTexCoord = 0.5f * float2( screenPos.x, -screenPos.y ) + 0.5f;

    // obtain screen position
    input.screenPosition.xy /= input.screenPosition.w;

    // get normal data from the normalMap
    float4 normalData = tex2D( _normalMap, screenSpaceTexCoord );

    // tranform normal back into [-1,1] range
    float3 normal = 2.0f * normalData.xyz - 1.0;
    normal.y *= -1.0;

    // screen-space position
    float4 position = float4( screenPos, 0.0, 1.0 ); // optional future change: add depth texture and stick the value here

    // transform to world space
    position = mul( position, _screenToWorld );

    // surface-to-light vector
    float3 lightVector = _lightPosition - position.xyz;

    // compute attenuation based on distance - linear attenuation
    float attenuation = saturate( 1.0f - length( lightVector ) / _lightRadius );

    // normalize light vector
    lightVector = normalize( lightVector );


    // spotlight cone calculations
    float phi = cos( radians( _coneAngle * 0.5 ) );

    // the angle away from the light's direction
    float rho = -dot( lightVector.xy, normalize( _lightDirection ) );
    float spotAttenuation = max( 0, ( ( rho - phi ) / ( 1.0 - phi ) ) );
    attenuation *= spotAttenuation;


    // compute diffuse light
    float NdL = max( 0, dot( normal, lightVector ) );
    float3 diffuseLight = NdL * _color.rgb;

    // take into account attenuation and lightIntensity.
    float4 result = attenuation * _lightIntensity * float4( diffuseLight.rgb, 1.0 );
    return result;
}



// ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####
// ##### ##### Directional Light       ##### ##### ##### ##### ##### #####
// ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####

struct VertexPosTexCoordsOutput
{
    float4 position : POSITION0;
    float2 texCoord : TEXCOORD0;
};


VertexPosTexCoordsOutput directionalLightVert( float4 position:POSITION0, float2 texCoord:TEXCOORD0 )
{
    VertexPosTexCoordsOutput output;

    output.position = position;
    output.texCoord = texCoord;

    return output;
}


float4 directionalLightPixel( VertexPosTexCoordsOutput input ) : COLOR0
{
    // get normal data from the normalMap
    float4 normalData = tex2D( _normalMap, input.texCoord );

    // tranform normal back into [-1,1] range
    float3 normal = 2.0f * normalData.xyz - 1.0f;
    normal.y *= -1.0;

    // we dont need to worry about converting to world space since directional lights dont care
    // surface-to-light vector
    float3 lightVector = -normalize( _dirLightDirection );

    // compute diffuse light
    float NdL = max( 0, dot( normal, lightVector ) );
    float3 diffuseLight = NdL * _color.rgb;

    // reflection vector
    float3 reflectionVector = normalize( reflect( -lightVector, normal ) );

    // camera-to-surface vector
    float3 halfVec = float3( 0, 0, 1 );

    // compute specular light. R.V^n
    float specularLight = _specularIntensity * pow( saturate( dot( reflectionVector, halfVec ) ), _specularPower );

    // output the two lights
    return float4( diffuseLight.rgb + specularLight, 1.0 );
}



// ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####
// ##### ##### Final combine     ##### ##### ##### ##### ##### ##### #####
// ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####

VertexPosTexCoordsOutput finalCombineVert( float4 position:POSITION0, float2 texCoord:TEXCOORD0 )
{
    VertexPosTexCoordsOutput output;

    output.position = position;
    output.texCoord = texCoord;

    return output;
}

float4 finalCombinePixel( VertexPosTexCoordsOutput input ) : COLOR0
{
    float3 diffuseColor = tex2D( _colorMap, input.texCoord ).rgb;
    float4 light = tex2D( _lightMap, input.texCoord );
    float3 diffuseLight = light.rgb;

    // compute ambient light
    float3 ambient = diffuseColor * _ambientColor;

    float4 result = float4( ( diffuseColor * diffuseLight + ambient ), 1 );
    return result;
}


// ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####
// ##### ##### Techniques        ##### ##### ##### ##### ##### ##### #####
// ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####

technique ClearGBuffer
{
    pass Pass1
    {
	VertexShader = compile vs_2_0 clearGBufferVert();
        PixelShader = compile ps_2_0 clearGBufferPixel();
    }
}

technique DeferredPointLight
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 pointLightVert();
        PixelShader = compile ps_2_0 pointLightPixel();
    }
}

technique DeferredSpotLight
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 spotLightVert();
        PixelShader = compile ps_2_0 spotLightPixel();
    }
}

technique DeferredDirectionalLight
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 directionalLightVert();
        PixelShader = compile ps_2_0 directionalLightPixel();
    }
}

technique FinalCombine
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 finalCombineVert();
        PixelShader = compile ps_2_0 finalCombinePixel();
    }
}