Fragment lighting fail

Started by
7 comments, last by weezl 12 years, 11 months ago
Hey there,

i've started implementing fragment lighting, as it is explained on http://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/lighting.php (using the single point light source code)
that results in this: http://dl.dropbox.com/u/12237727/lightfail.PNG

while at first it doesn't seem so bad, notice that the actual light source is the orange ball floating above the cubes (located at (0, 10, 0), origin is where the red sphere lies). Though the polygons are lit differently regardless in which direction they are facing.

since nehe is using basically the same shader code in one of his tutorials, i can probably assume that it isnt the shader codes fault.
my guess is that some matrix transformation is off, screwing with the normals, or orientation of the cubes.

each cube has its own matrix which is multiplied upon the matrix stack of the modelview when they are rendered. but from what i understand that should be taken care of in the vertex shader from the above sample.
Advertisement
Are you using OpenGL's lighting model (setting up GL_LIGHT0 parameters etc.) or your own? If the former, make sure you have the light position set up outside any push / pop matrix calls for other objects so that the position is correct (the current model view matrix is used when you specify GL_POSITION).
Post shader code? (I'd make a random guess at not using the gl_NormalMatrix to transform the normals, but 'tis just a guess without code.)
Actually i tried both, using the GL_LIGHT0 position parameter and passing the lightposition as uniform vector to the fragment shader. Both yield the same result.


//game code
/* I tried loading the identity matrix before setting the light
* parameter to make sure the current view matrix is the default,
* after you mentioned the matrix would apply to the light position
* result was the same though*/
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();

sphere.Position = LightPosition = new Vector(0, Calc.Sin(Time.Total*3) * 10, 0);

GL.Light(LightName.Light0, LightParameter.Position, LightPosition);
GL.UseProgram(program);

int loc = GL.GetUniformLocation(program, "lightpos");
GL.Uniform3(loc, 1, LightPosition);


Here's the code as from http://www.opengl.or...rs/lighting.php, with some modifications for only using diffuse lighting

//VS
varying vec3 N;
varying vec3 v;

void main(void)
{
v = vec3(gl_ModelViewMatrix * gl_Vertex);
N = normalize(gl_NormalMatrix * gl_Normal);

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}



//FS
varying vec3 N;
varying vec3 v;

uniform vec3 lightpos;

void main (void)
{
vec3 L = normalize(lightpos - v); // tested using lightpos and gl_LightSource[0].position.xyz

//calculate Diffuse Term:
vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);
Idiff = clamp(Idiff, 0.0, 1.0);

gl_FragColor = Idiff;
}
v and n are in view space (N might be in screen space, can't recall whatspace the NormalMatrix transforms to). What space is lightpos in? Whatever you do, make sure they are all in the same space. I'm guessing that lightpos is in world space.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

i think im all confused with all those spaces being called differently everywhere...

so, yes, i think the light is in worldspace.. now what is viewspace and how would i transform the lights position into viewspace then?
Here's a few names for every space, no doubt there are even more. Names on the same line mean the same thing:

Model Space, Object Space, Local Space
World Space
Camera Space, View Space
Projection Space, Screen Space

OpenGL uses the ModelView matrix and the Projection matrix, the ModelViewMatrix should transform from model space to view space, so a better name would be WorldView matrix IMHO. The Projection matrix transforms from view space to projection space, and won't change very often. This is why it's kept separate.

From the code you posted it's obvious that to calculate the L vector you use a light position in world space (because you aren't applying any transformation on it in your code), and a vertex position in view space (because you use the gl_ModelViewMatrix to transform it).

One way to fix your problem would be to calculate the L vector in the vertex shader by transforming gl_Vertex with a WorldMatrix you provide yourself, then read and normalize it in the fragment shader. This would also require you to transform your normals to word space instead of view space. Another solution is to transform your light position to view space before sending it to OpenGL.

I see some more problems in the fragment shader, but let's try to get the spaces right first ;)
So, from what i gather is the light position is in world space and needs to be converted to view space. since view space is the camera space i use the camera transform (lookat matrix) and load it prior to assigning the light0 position, since the current modelview matrix will apply to the light position.


GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref Game.Camera.Transform);

LightPosition = new Vector(0,Calc.Sin(Time.Total*3)*10,0);
GL.Light(LightName.Light0, LightParameter.Position, LightPosition);


this however changes nothing in the outcome.

The other way you mentioned
>>One way to fix your problem would be to calculate the L vector in the vertex shader by transforming gl_Vertex with a WorldMatrix you provide yourself, then read and normalize it in the fragment shader.
not sure i understand it :P
When you transform a vertex or normal by the modelview matrix (normal matrix is just the inverse transpose of the modelview), the vertex would be in eye space and the normal will be in eye space.
The modelview matrix is = camera_matrix * object_matrix


For your light, it must be in eye space as well. So, you need to do
light_eyespace = camera_matrix * light_position

I would do that operation in my C++ and upload to the shader.

PS: I am assuming you are using your own uniforms. I suggest that you don't use GL built-in stuff.

For information on spaces http://www.opengl.org/wiki/Vertex_Transformation
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
http://dl.dropbox.com/u/12237727/lightsuccess.PNG

\o/

thanks for all the help! :D

now i can finally start at wrapping it all together nice and tight and progress on it

This topic is closed to new replies.

Advertisement