Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specular lighting appears on both eye-facing and rear sides of object

I am writing a small test of Phong shading, and am hitting my head against a brick wall trying to get the specular component working. It appears to work correctly, except that the specular light is applied to both the front & rear of the object. (The object itself is transparent, with faces sorted CPU-side manually.)

Note that the diffuse component works perfectly (only shows up on the side facing the light source) – which would seem to rule out a problem with the normals arriving at the fragment shader, I think.

As I understand, the specular component is proportional to the cos of the angle between the eye vector & the reflected light vector.

To keep things ultra simple, my test code tries to do this in world space. Camera position and light vector are hard-coded (sorry) as (0,0,4) and (-0.707, 0, -0.707) respectively. The eye vector is therefore (0,0,4) - fragPosition.

Since the model matrix only performs rotation, the vertex shader simply transforms the vertex normal by the model matrix. (Note: this is not good practice as many types of transformation do not preserve normal orthogonality. Generally for the normal matrix, you should use the inverse transpose of the top-left 3x3 of the model matrix.) To keep things simple, the fragment shader operates on a single float colour channel, and skips the specular exponent (/uses an exponent of 1).

Vertex shader:

#version 140

uniform mat4 mvpMtx;
uniform mat4 modelMtx;

in vec3 inVPos;
in vec3 inVNormal;

out vec3 normal_world;
out vec3 fragpos_world;

void main(void) {
  gl_Position = mvpMtx * vec4(inVPos, 1.0);
  normal_world = vec3(modelMtx * vec4(inVNormal, 0.0));
  fragpos_world = vec3(modelMtx * vec4(inVPos, 1.0)); 
}

Fragment shader:

#version 140

uniform float
    uLightS,
    uLightD,
    uLightA;

uniform float uObjOpacity;

in vec3 normal_world, fragpos_world;
out vec4 fragOutColour;

void main(void) {

    vec3 vN = normalize(normal_world);
    vec3 vL = vec3(-0.707, 0, -0.707);

    // Diffuse:
    // refl in all directions is proportional to cos(angle between -light vector & normal)
    // i.e. proportional to -l.n
    float df = max(dot(-vL, vN), 0.0);

    // Specular:
    // refl toward eye is proportional to cos(angle between eye & reflected light vectors)
    // i.e. proportional to r.e
    vec3 vE = normalize(vec3(0, 0, 4) - fragpos_world);
    vec3 vR = reflect(vL, vN);
    float sf = max(dot(vR, vE), 0.0);

    float col = uLightA + df*uLightD + sf*uLightS;

    fragOutColour = vec4(col, col, col, uObjOpacity);

}

I can’t find an error here; can anyone explain why the specular component appears on the rear as well as the light-facing side of the object?

Many thanks.

like image 378
ASpence Avatar asked Nov 15 '13 18:11

ASpence


People also ask

What does specular mean in lighting?

Specular lighting identifies the bright specular highlights that occur when light hits an object surface and reflects back toward the camera. Specular lighting is more intense than diffuse light and falls off more rapidly across the object surface.

What are specular highlights caused by?

The incident light hits the object and creates the specular highlight and the light is reflected off the object toward the viewers eye. As with a normal reflection the angle of incidence is equal to the angle of reflection (See: Specular Reflection). The specular highlight is often seen on a curved surface as a spot.

What is the difference between ambient diffuse and specular reflection?

The reflection of light can be roughly categorized into two types of reflection: specular reflection is defined as light reflected from a smooth surface at a definite angle, and diffuse reflection, which is produced by rough surfaces that tend to reflect light in all directions (as illustrated in Figure 1).

What is specular shading?

Specular highlights show the places on the object where the light sources are reflected at consistent angles; reflections on an object show, among other things, light bounced from surrounding objects. Specular highlights depend directly on the view (camera), not the position of the light, like diffuse shading does.


1 Answers

Your specular contribution is actually going to be the same for front and back faces because GLSL reflect is insensitive to the sign of the normal. From this reference:

reflect(I, N) = I - 2.0 * dot(N, I) * N

so flipping the sign of N introduces two minus signs which cancel. In words, what reflect does is to reverse the sign of the component of I which is along the same axis as N. This doesn't depend on which way N is facing.

If you want to remove the specular component from your back faces I think you'll need to explcitly check your dot(vE,vN).

like image 50
Mike Dinsdale Avatar answered Sep 20 '22 00:09

Mike Dinsdale