Last active
April 15, 2016 05:33
-
-
Save prime31/6cb6dad540f99896cb68447dc2a364db to your computer and use it in GitHub Desktop.
2D deferred lighting implementation (first pass, not optimized)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ##### ##### ##### ##### ##### ##### ##### | |
// ##### ##### 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