Thursday, April 4, 2013

Putting the scene under the spotlight

Implementing spot lights is pretty simple, once you have point lights in place. It is possible to use the same lights list to store spot light information and process the spot lights in the same light loop for forward lighting.

Following is the update to the structure:


struct sLight //name changed from Point light to Light
{
float3 Position;
float3 Color;
float3 SpecularColor;
float3 Direction;
float attenExp;
float size;
float lightConeScale;
float lightConeOffset;
};

Direction, lightConeScale and lightConeOffset are the new parameters added for the spot light. We can use the same parameters for the point lights and make sure it's effects get Zeroed out when you calculate the lighting. I'll explain how to do this later.

Light Cone Scale and Offset, are special parameters used for getting light attenuation with inner cone angle and outer cone angle. The attenuation will start only after the inner cone angle and will completely fade out once we reach the outer cone angle. This is how we calculate the scale and offset parameters for the spot light.


const float cosOuterAngle = cos(pLight->GetOuterAngle());
float lightConeScale = 1.0f / max(cos(pLight->GetInnerAngle()) - cosOuterAngle, 0.000001f);
float ightConeOffset = -cosOuterAngle * this->lightConeScale;

The following are the changes in the light shader:


for(int i=0; i<numLights; i++)
{
sLight currentLight = g_Lights[i];
float3 posToLightVector = currentLight.Position - worldPos;
float dist = sqrt(dot(posToLightVector, posToLightVector));
float3 normalizedLightVec = posToLightVector / dist;
float NDotL = dot(normalizedLightVec, worldNormal); //Diffuse lighting
float atten = pow(saturate((currentLight.size - dist) / currentLight.size), currentLight.attenExp);
float angularFallOff = saturate(dot(normalizedLightVec, -currentLight.Direction) * currentLight.lightConeScale + currentLight.lightConeOffset);
accumColor += saturate(g_Lights[i].Color * NDotL * atten * angularFallOff);
}

The angular falloff reduces the intensity of the light when we move from inner cone angle the outer cone angle. You can add intensity as an option, but the only issue with that is you should make sure you use an HDR target.

For point lights to use the same structure, you have to make sure the angularFallOff calculation is set to one. For that you have to set Scale = 0.0f, and Offset = 1.0f, and direction can be set to any value.

Following is the result when adding one white point light and 4 spot lights:


Next Stop: Either Capsule Lights, Area Lights .. or .. Deferred Lighting



No comments: