Skip to content

Instantly share code, notes, and snippets.

@prime31
Last active April 15, 2016 05:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save prime31/6cb6dad540f99896cb68447dc2a364db to your computer and use it in GitHub Desktop.
Save prime31/6cb6dad540f99896cb68447dc2a364db to your computer and use it in GitHub Desktop.
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();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment