Soft spoltlight

From XNAWiki
Jump to: navigation, search

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;
}