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:
[ul][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 :-))[/ul][/li]
And now for the question:
[ul][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…[/ul][/li]
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