I'm trying to implement light attenuation in a Phong shader. The pixel/fragment shader does the following calculation (per light source):
float3 refl = reflect(e, n);
float dist = length(L.xyz);
float3 l = normalize(L.xyz);
float attn = 1.0 / (1.0 + 1.0 / 30 * dist + 1.0 / 700 * dist * dist);
d += saturate(dot(n,l)) * gLightColor[i].xyz * attn.xxx;
s += pow(saturate(dot(-refl, l)), power) * gLightColor[i].xyz;
where:
- e is the normalized eye vector
- n is the normal to the surface
- L is the (non-normalized) light vector
- d is the diffuse color
- s is the specular color
For simplicity, I'm ignoring the effect of attenuation on the specular color and using some built in attenuation coefficients. Generally, I get the correct behavior:
As I increase the distance between the light source and the object, the reduction in intensity becomes not smooth:
I'm getting rings instead of a gradient. Is this a matter of floating point precision? How can I get a smooth intensity change at all distances?
Using D3D 9 and HLSL shader model 3.