2
votes

I have a diffuse+specular equation in my pixel shader, and it works pretty well except for this one issue:

When I change this: float attenuation = 1.0f / d*d;

To this: float attenuation = 1.0f / ( d*d );

My model is no longer lit, and is instead the color of my ambient intensity. I find this extremely strange. The reason I want parentheses is so I can use a different attenuation function such as ( 1 + 0.045*d + 0.0075*d*d ).

Here is my entire pixel shader:

void ps( in v2p input, out float4 final_color : SV_TARGET )
{
    float3 ambient_intensity = float3( 0.3f, 0.3f, 0.3f );
    float3 diffuse_color = float3( 0.8f, 0.8f, 0.8f);
    float3 specular_color = float3( 1.0f, 1.0f , 1.0f );

    float3 tmp_light;
    tmp_light.x = light_vector.x;
    tmp_light.y = light_vector.y;
    tmp_light.z = light_vector.z;

    float3 norm_light = normalize( tmp_light );

    float3 tmp_pos;
    tmp_pos.x = input.pos.x;
    tmp_pos.y =  input.pos.y;
    tmp_pos.z = input.pos.z;

    float3 tmp_norm;
    tmp_norm.x = input.norm.x;
    tmp_norm.y = input.norm.y;
    tmp_norm.z = input.norm.z;

    float3 tmp_cam = float3( 0.0f, 0.0f, -20.0f ); // todo: make this stuff work right in cbuffer

    // light intensity
    float d = distance( tmp_light, tmp_pos );

    float attenuation = 1.0f / d*d;
    float3 pointlight = attenuation*light_color;

    // diffuse lighting 
    float diffuse = max( dot( tmp_norm, norm_light) , 0.0f );
    float3 diffuse_final = diffuse_color*ambient_intensity + diffuse_color*pointlight*diffuse;

    // specular lighting
    float3 reflect_vect = 2*dot( tmp_norm, norm_light )*tmp_norm - norm_light;
    float ref_max = max( dot( reflect_vect, normalize(tmp_cam) ), 0.0f );
    float spec_exponent = pow ( ref_max, 1.0f );

    float3 spec_final;
    if( dot( tmp_norm, norm_light ) <= 0 )
    {
        spec_final = float3( 0.0f, 0.0f, 0.0f );
    }
    if( dot( tmp_norm, norm_light ) > 0 )
    {
        spec_final = specular_color*pointlight*spec_exponent;
    }

    final_color = float4(  diffuse_final + spec_final, 1.0f );
}

Without parentheses: http://i48.tinypic.com/357rmnq.png

With parentheses: http://i45.tinypic.com/70jscy.png

1
* and / have the same precedence so they are evaluated left-to-right. It means that 1.0 / d * d is the same than (1.0 / d) * d. I do not know then what this calculus means (it just returns 1.0), that¡s why I do not make this an answer.SJuan76
That's true, so it was a logic error on my part. So now the mystery is why my model isn't lit with quadratic attenuation. My light is definitely close enough (it always starts at the origin and I can move it freely around) so it shouldn't be unlit. Can anyone spot an error in my lighting equation? My equation is according to the one discussed in "Mathematics for 3D Game Programming and Computer Graphics"Phillip Clark

1 Answers

0
votes

The line float attenuation = 1.0f / d*d; is equal to float attenuation = 1.0f; and that's why you get shaded object with no attenuation.

Assuming your object is placed near the origin and is small compared to its distance to the camera, you get an attenuation close to zero when using float attenuation = 1.0f / (d*d);. That's because the d is around 20.0 and the attenuation is 1.0 / 400.0 = 0.0025. So the only visible light on the model is the ambient one. In fact, this is correct - the point light has just a very high attenuation and thus has got almost no impact on the object. Try some other attenuation function, for example 1.0f / (0.003*d*d), and you'll see the difference.