PDA

View Full Version : Per pixel light projection off - cannot figure why



karx11erx
04-20-2008, 02:59 AM
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):

http://www.descent2.de/images/temp/light-problem-1.jpg

http://www.descent2.de/images/temp/light-problem-2.jpg

http://www.descent2.de/images/temp/light-problem-3.jpg

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

Here the viewer is the light source:
http://www.descent2.de/images/temp/light-problem-4.jpg

Light source at the left periphery of the viewer's fov:
http://www.descent2.de/images/temp/light-problem-5.jpg

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;\r\n"\
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;
}

Lord crc
04-20-2008, 06:48 AM
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.

karx11erx
04-20-2008, 11:24 AM
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. :)