3
\$\begingroup\$

I coded my first glsl shader which manage diffuse and specular effects of a directional light. This is the fragment shader.

#version 120

//matrix
uniform mat4 model_matrix;

//directional light position in world coordinates
uniform vec3 light_position;
uniform vec3 eye;

//send to fragment shader
varying vec4 color;
varying vec4 normal;
varying vec4 vertex;

void main()
{

    float light_diffuse_intensity;
    float light_specular_intensity;
    float light_mod;

    vec3 world_normal;  
    vec3 world_vertex;  
    vec3 world_reflec;
    vec3 vertex_to_light;
    vec3 vertex_to_eye;

    world_normal = (model_matrix * normal).xyz; 
    world_vertex = (model_matrix * vertex).xyz;

    vertex_to_light = light_position - world_vertex; //vector from vertex to light 
    vertex_to_eye = eye - world_vertex; //vector from vertex to eye 
    world_reflec = 2 * dot(vertex_to_light, normalize(world_normal.xyz)) * normalize(world_normal) - vertex_to_light; //reflection of vertex_to_light

    light_diffuse_intensity = dot(normalize(vertex_to_light), normalize(world_normal.xyz)); //computing angle between light and normal
    light_specular_intensity = dot(normalize(vertex_to_eye), normalize(world_reflec)); //computing angle between eye and reflection

    if (light_diffuse_intensity > 0){
        light_mod = light_diffuse_intensity;
        light_specular_intensity = pow(light_specular_intensity, 8.0);
    }
    else{ 
        light_specular_intensity = 0;
    }

    gl_FragColor = vec4(mix(color.rgb * light_diffuse_intensity, vec3(1.0,1.0,1.0), light_specular_intensity), 1.0);

}

As you can see from the screenshot below, in the first screen, where I look at the sphere from the direction of the light, the border of the sphere is white because of the specular effect. However if the shader were correct it should not look like that. It should be white only in the middle of the sphere.

In the second screen, I look at both the sphere and the source of the directional light (the yellow sun) and everything looks just fine.

I cannot find the error in my shader, could someone help please?

Thank you very much!

image of the error

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

One solution

Use an odd number in your power function (or some other function that keeps the sign of your previous specular intensity):

light_specular_intensity = pow(light_specular_intensity, 9.0);
light_specular_intensity = pow(light_specular_intensity, 7.0);

There may be other ways to perform the math such that you may still use an even power.

The problem

Your power function is (mathemtically) creating a phantom light behind the ball, and that's the reflection you're seeing along the edge. For clarity, I've added some parenthesis to this line:

world_reflec = 2 * 
    (
        dot(vertex_to_light, normalize(world_normal.xyz)) 
        * normalize(world_normal) 
    )
    - vertex_to_light; //reflection of vertex_to_light

When the camera aligns with the light, for the pixels on the edge, dot(vertex_to_light, world.normal.xyz) will yield nearly zero. So the value of world_reflec will be rough equal to -1 * vertex_to_light. And because vertex_to_eye and vertex_to_light are nearly equal, that means that this line:

light_specular_intensity = dot(normalize(vertex_to_eye), normalize(world_reflec));

...will yield a value of light_specular_intensity of almost -1. And then this line:

// (light_diffuse_intensity > 0) == true
light_specular_intensity = pow(light_specular_intensity, 8.0);

...will strip off the negative and give you a value near 1. That causes specular illumination.

\$\endgroup\$
2
  • \$\begingroup\$ This was the problem, great!! Thanks! However if I use light_specular_intensity = pow(light_specular_intensity, 9.0); the problem does not get solved. Is it possible that pow() does not remember the sign? If I rewrite the code like this if(light_specular_intensity > 0) light_specular_intensity = pow(light_specular_intensity,8); else light_specular_intensity = 0; it works perfectly. \$\endgroup\$
    – Marco
    Jul 28, 2013 at 10:38
  • 1
    \$\begingroup\$ @Marco Huh...so I got the problem right, but my solution didn't work? I'm surprised, but I'm glad your alternate method fixed it. \$\endgroup\$ Jul 28, 2013 at 15:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .