Soft spoltlight
From XNAWiki
Soft spotlights
HLSL code fragment for efficent soft spotlights.
This version allows 12 spotlights in a scene, but you can increase that by using standard multi-pass techniques.
//========================================================================================================//
//= Spotlight routine
//========================================================================================================//
float SpotLightShader( int n, float3 lightDir)
{
float3 l = normalize(lightDir);
float atten = saturate(1.0f - dot(lightDir, lightDir));
float2 cosAngles = cos(float2(spotlights[n].spotOuterCone, spotlights[n].spotInnerCone) * 0.5f);
float spotDot = dot(-l, normalize(spotlights[n].direction));
float spotEffect = smoothstep(cosAngles[0], cosAngles[1], spotDot);
atten *= spotEffect;
return atten;
}It is fed the following structure.
struct SpotLight
{
float3 direction;
float3 position;
float4 colour;
float spotInnerCone; // spot light inner cone (theta) angle
float spotOuterCone; // spot light outer cone (phi) angle
float radius; // applies to point and spot lights only
};
The pixel shader itself is fairly simple. Note I have placed a colour variable in the spotlight structure though for my needs I assumed white light. You should add this if you so require.
float4 Spotlight(VertexShaderOutput input) : COLOR0
{
float4 result=float4(0,0,0,0);
float4 diffuseColor;
float3 N=normalize(input.WorldNormal);
if (TextureEnabled)
{
diffuseColor = tex2D(diffuseSampler, input.TexCoords);
}else{
diffuseColor = input.Colour;
}
for (int n=0; n<n_spotlights; n++)
{
float3 Dp = (spotlights[n].position-input.WorldPosition)/ spotlights[n].radius;
float intensity=SpotLightShader(n,Dp);
float nDotL = saturate(dot(N, -normalize(spotlights[n].direction)));
result+=(intensity*spotlights[n].colour*diffuseColor)*nDotL;
}
return result;
}