PDA

View Full Version : Very simple shader problem!



doublex_3
12-30-2006, 07:33 AM
Right I'll dive straight in here, basically I'm trying to write a simple diffuse lighting shader, using the 'dot product of incident beam and normal' method, but have been having some problems, so to try elimate them I've written a simple shader to show what my normals are doing:

vertex shader:

varying vec3 normal;
void main()
{
normal = normalize(gl_Normal);
gl_Position = ftransform();
} fragment shader:

varying vec3 normal;
void main()
{
vec3 n=normalize(normal);
vec4 color = vec4(n.xyz,1.0);
gl_FragColor = color;
}Basically the idea is to colour a polygon based on where its normal is pointing, which does work fine, but when I rotate the model, the colours do not change, indicating that these aren't the normals in 'world space' (sorry if I get terminology wrong, I'm new to the 3d scene really).

This is causing the model's lighting to not depend on its orientation, which is obviously wrong.

Just in case it helps, the code regarding the rotation of the model is:

void drawPlayer(){
glPushMatrix();
glTranslatef(player.x, player.y, player.z);
glRotatef(-player.rotation/PIOVER180,0,1,0);
glPushMatrix();
glRotatef(180,0,1,0); //stands the model upright
if(model.bLoaded==true){model.draw();}
glPopMatrix();
glPopMatrix();I had a suggestion before to replace normalize(gl_Normal) with normalize(gl_NormalMatrix * gl_Normal), but I have found that this then makes the normal direction dependant on the viewing angle, which will produce incorrect diffuse lighting.

Any help would be much appreciated, I'm completely stumped on this one. I've tried implementing many different shaders I've sourced from around the net, but nothing works so far. :(

Komat
12-30-2006, 08:48 AM
Originally posted by doublex_3:
I had a suggestion before to replace normalize(gl_Normal) with normalize(gl_NormalMatrix * gl_Normal), but I have found that this then makes the normal direction dependant on the viewing angle, which will produce incorrect diffuse lighting.
That suggestion was right. The resulting normal after the multiplication with the gl_NormalMatrix is expressed in the eye space so it is dependent on camera position. This is correct if you have the light position/direction also expressed in the eye space and if you will do the lighting calculations in that space like fixed function lighting does.

If you wish to do the calculations in world space, you have to provide the shader with model matrix and with inverse transpose of 3x3 part of model matrix and use those matrices to calculate world space position and normal.

doublex_3
12-30-2006, 10:50 AM
Thanks Komat, that makes complete sense - also sounds look a good idea as I can't see the point of transforming things needlessly into world space to do the calculations. Only problem is it's still not working...

In my initialization code:

float light_position[] = {1,-1,0,0};
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);My vertex shader:

varying vec3 normal;
void main()
{
normal = normalize(gl_Normal);
gl_Position = ftransform();
} And my fragment shader:

varying vec3 normal;
void main()
{
vec3 n = normalize(normal);
float intensity = dot(normalize(gl_LightSource[0].position.xyz), n);

gl_FragColor = vec4(1.0) * intensity;
}I thought that opengl passes the light's position in eye space coordinates, so doesn't need any transformation?
But this code isn't working, the intensity still depends on the viewing angle.

In an attempt to transform (the possibly world space) light coordinates into eye space, I've tried replacing the 'intensity=.....' line with:

float intensity = dot(normalize((gl_ModelViewMatrix * gl_LightSource[0].position).xyz), n);But again the viewing angle affects the intensity. This is driving me to insanity!
I've also checked through my code and there are no transformations happening to the projection matrix so that shouldn't be causing problems. Thanks again for the help Komat ;) Any more ideas?

Komat
12-30-2006, 12:16 PM
The light position you specify trough the glLightfv is transformed to eye space by by multiplying it by modelview matrix set at time this call was made and the eye space result is stored. Because of this there is no need for additional transformation within the shader.

This also means that if the view part of modelview matrix changes, the stored position is not correct anymore and need to be set again. You have to set the light position each time position or orientation of your camera changes even if the light world space position remains the same. Of course unless you wish that the light maintains the same position relative to the camera.

doublex_3
12-30-2006, 01:18 PM
Thanks Komat you're a god!

I've FINALLY got this working :D
After much fiddling about after your last comment, I realised that the glutLookAt() call is modifying the modelview matrix, so my glLightfv call needs to go after, not before....
:D :D :D :D :D :D :D
Look out specular and ambient lighting, here I come...

Vexator
12-31-2006, 03:50 AM
try to avoid using the built-in uniforms like gl_LightSource[n].position.. it's better to send such data manually.