GLSL Per-Vertex Phong Shader - correct maths?

Hello,
i am totally new to 3D Graphics in general and OpenGL in particular and currently learning the Basics of GLSL. I want to implement a per Vertex Phong Shader with the classical ADS Lighting model.

Diffuse and Ambient works as expected but i have trouble with the Specular component.

This is my GLSL Code for the entire Shader - the part probably problematic is the Function “GetSpecularColor”:


//
// Vertex Shader
//
//

#version 130

uniform mat4 mModel;
uniform mat4 mView;
uniform mat4 mProjection;

uniform vec4 vEyePosition; // In Model space
uniform vec4 vDiffuseLightPosition; // In Model space

in vec4 vVertexPosition;
in vec3 vVertexNormal;

smooth out vec4 vVaryingColor;

/*
 * Returns the Specular Color at the current Vertex
 */

vec4 GetSpecularColor()
{
    // Transform the Vertex and corresponding Normal into Model space
    vec4 vTransformedNormal = mModel * vec4( vVertexNormal, 1 );
    vec4 vTransformedVertex = mModel * vVertexPosition;

    // Get the directional vector to the light and to the camera
    // originating from the vertex position
    //
    // vLightDirection is interesting. Why do i need to write it in this way?
    // The direction would be vDiffuseLighePosition - vTransformedVertex, but
    // if i do it in this way the result is weird....
    vec4 vLightDirection = normalize( vTransformedVertex - vDiffuseLightPosition );
    vec4 vCameraDirection = normalize( vEyePosition - vTransformedVertex );

    // Calculate the reflection vector between the incoming light and the
    // normal (incoming angle = outgoing angle)
    vec4 vReflection = reflect( vLightDirection, vTransformedNormal );

    // Calculate specular component
    // Based on the dot product between the reflection vector and the camer
    // direction
    float spec = pow( max( 0.0, dot( vCameraDirection, vReflection )), 32 );

    return vec4( spec, spec, spec, 1.0 );
}

/*
 * Returns the Ambient Color at the current Vertex
 */
vec4 GetAmbientColor()
{
    // Ambient material is 0.2/0/0
    // Ambient light is 0.2/0.2/0.2
    return vec4( 0.2, 0, 0, 1.0 ) * vec4( 0.2, 0.2, 0.2, 1.0 );
}

/*
 * Returns the Diffuse Color at the current Vertex
 */
vec4 GetDiffuseColor()
{
    // Transform the normal from Object to Model space
    // we also normalize the vector just to be sure ...
    vec4 vTransformedNormal = normalize( mModel * vec4( vVertexNormal, 1 ));

    // Get direction of light in Model space
    vec4 vLightDirection = normalize( vDiffuseLightPosition - vTransformedNormal );

    // Calculate Diffuse intensity
    float fDiffuseIntensity = max( 0.0, dot( vTransformedNormal, vLightDirection ));

    // Calculate resulting Color
    vec4 vDiffuseColor;
    vDiffuseColor.xyz = vec3( 1.0, 0.0, 0.0 ) * fDiffuseIntensity;
    vDiffuseColor.a = 1.0;

    return vDiffuseColor;
}

void main(void) 
{
    vec4 ambientColor = GetAmbientColor();
    vec4 diffuseColor = GetDiffuseColor();
    vec4 specularColor = GetSpecularColor();

    vVaryingColor = ambientColor + diffuseColor + specularColor;

    gl_Position = mProjection * mView * mModel * vVertexPosition;
}

First of all please let me explain a few things i assumed in my code:

  • [li]I like to keep the Model, View and Projection matrices alone[]I also like to do the maths in model space[]and lust but not least i like to supply “camera” and light position in model space (REALLY like to think in model space :-))

And now for the question:

  • [li]Is my specular lighting correct? I don’t think so, because even if it looks kind of correct in the graphical output it’s not clear to my why.[*] Take a look at the Function “GetSpecularColor” and the declaration of vLightDirection - if i write it exactly the opposite way (which would yield the direction) the specular lighting is totally screwed…

If you want to try out for yourself, heres the entire code for the test project:
http://hotfile.com/dl/111334776/b34b17d/gltest011.tar.bz2.html

Here’s the graphical output of my test project:

Thank you,
Tom

(did not read your code)
The resulting image looks like a perfectly good vertex shading.

An advice : make it per pixel as soon as you can ! It will be easier to spot subtle errors. And will be much nicer to the eye.
Or at least tesselate a lot more your torus, otherwise it will be hard to see if the specular part is correct or not.

Hello,
ZbuffeR, thank you for your reply - i think i have found the problem.

vLightDirection is the Direction of the Light as seen from the Vertex. The opposite, -vLightDirection is the position of the vertex as seen from the light.

When i rewrite my GLSL Shader to:


    // Get the directional vector to the light and to the camera
    // originating from the vertex position
    vec4 vLightDirection = normalize( vDiffuseLightPosition - vTransformedVertex );
    vec4 vCameraDirection = normalize( vEyePosition - vTransformedVertex );

and then use:


    // Calculate the reflection vector between the incoming light and the
    // normal (incoming angle = outgoing angle)
    // We have to use the invert of the light direction because "reflect"
    // expects the incident vector as its first parameter
    vec4 vReflection = reflect( -vLightDirection, vTransformedNormal );

everything works as expected. Can someone tell me if the built-in “reflect” function expects the normalized direction of the vertex as seen from the light source as it’s first parameter?

Thanks,
Tom

Can someone tell me if the built-in “reflect” function expects the normalized direction of the vertex as seen from the light source as it’s first parameter?

In the OpenGL Shading Language 4.10 Quick Reference Card - Page 8 the equation is R = I - 2 * dot(N,I) * N. So the unit vector I should point from the light position to the vertex position.

If it was the inverse, from the vertex position to the light position, the equation is R = 2 * dot(N,I) * N - I.

Not relevant to the original question, but the vector I does not need to be a unit vector. reflect will preserve the length of the incident vector.

  • Chris

Hello,
thank you all for your replies!
Tom