Per pixel light projection off - cannot figure why

Hi,

am fighting with implementing per pixel lighting in the OpenGL port of an old legacy game (Descent), and I am having a problem I cannot figure how to fix: Depending on the angle between the viewer and a light source, the light cast by the light source “seems to wander around”. It seems to depend on how big the angle of the viewer’s forward vector is off from the unit vector (ie. {1,0,0} or {0,1,0} or {0,0,1}). I cannot figure for the love of God how to fix that. Please help me with this.

Here are a few pics to illustrate the problem (the walls are parallel to the unit vectors):

Here is the same problem with a spotlight used as headlight:

Here the viewer is the light source:

Light source at the left periphery of the viewer’s fov:

Here is the related code.

Setting up the camera:


void SetCamera (fVector *vViewerPos, fMatrix *mViewerOrient)
{
glLoadIdentity ();
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity ();
glScalef (0.75f, 1.0f, -0.421875);   //don't ask me, that's from the original game code (x probably compensates for the screen aspect ratio)
glMultMatrixf (mViewerOrient);
glTranslatef (-vViewerPos.x, -vViewerPos.y, -vViewerPos.z);
}

Vertex shader (hint: transforming the normal with gl_NormalMatrix fails for unknown reasons):


#define LIGHTS 5
varying vec3 normal;
varying vec3 lightVec [LIGHTS];
void main() {
vec4 vertPos;
normal = normalize (vec3 (gl_ModelViewMatrix * vec4 (gl_Normal, 0.0)));
vertPos = gl_ModelViewMatrix * gl_Vertex;
int i;
for (i = 0; i < LIGHTS; i++) {
   lightVec [i] = vec3 (gl_LightSource [i].position - vertPos);
   }
gl_Position = ftransform();
gl_TexCoord [0] = gl_MultiTexCoord0;
"\
gl_FrontColor = gl_Color;
}

Fragment shader:


#define LIGHTS 5
uniform sampler2D btmTex;
varying vec3 normal;
varying vec3 lightVec [LIGHTS];
void main() {
   vec3 halfV;
   float att, dist, NdotL, NdotHV;
   vec4 color = gl_Color;
   vec4 btmColor = texture2D (btmTex, gl_TexCoord [0].xy);
   vec3 n = normalize (normal);
   int i;
   for (i = 0; i < LIGHTS; i++) {
      NdotL = max (dot (n, normalize (lightVec [i])), 0.0);
      if (NdotL >= 0.0) {
         att = 1.0 + gl_LightSource [i].linearAttenuation * dist + gl_LightSource [i].quadraticAttenuation * dist * dist;
         color += (gl_LightSource [i].diffuse * sqrt (NdotL) + gl_LightSource [i].ambient) / att;
         }
      }
   color = min (color, vec4 (2.0, 2.0, 2.0, 2.0));
   gl_FragColor = btmColor * color;
   }

If the modelview matrix contains non-uniform scaling, then it won’t transform your normals correctly. See http://www.lighthouse3d.com/opengl/glsl/index.php?normalmatrix for a good explanation of why.

Thank you very much. I had written that using gl_NormalMatrix doesn’t work for me, but I was wrong. I think I had another bug in my shader programs that made me think that. Thanks again. :slight_smile: