PDA

View Full Version : Lighting and normals not working correctly



PascalM123
08-22-2010, 11:26 AM
Dear forum,

I have a problem concerning lighting and normals. I've got several files with multiples classes for a physics engine and a main-file in which everything is called. I have a scene class containing all the shapes (like planes and spheres etc.) and every time I need to draw the shapes, I call a draw function in that scene class.

The problem is that when I draw objects outside the main-function (the scene class has a member function that loops through all the shapes, looks up their types and then calls a draw function in that shape class to do the actual drawing) the lighting is not working and inside the main it is working. Without GLSL shapes like spheres are totally lit and with GLSL they are partially lit and partially black. What is the solution to this problem?

Regards,
PascalM123

DmitryM
08-22-2010, 07:14 PM
No specific problem set - no specific answer.

Post your shader code + GL initialization & draw code.
Screenshots could be useful as well.

PascalM123
08-23-2010, 02:17 AM
You are right, some of the code is posted below.

In the main:

void display(void) {
glClearColor(0.0, 0.2, 0.4, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(eye.x, eye.y, eye.z, eye.x + camera_forward.x,
eye.y + camera_forward.y, eye.z + camera_forward.z, 0, 1, 0);

shader.bind();
/* Draw every shape in the scene */
scene.draw_shapes();
shader.unbind();

/* Random sphere */
glTranslatef(0,10,0);
glutSolidSphere(4, 32, 32);

glFlush();
glutSwapBuffers();
}

/* Initialize polygons, light and enables */
void init(void) {
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_CULL_FACE);
glShadeModel(GL_SMOOTH);

/* Setup lighting variables */
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
float ambientColor[] = { 0.0, 0.0, 0.0, 0.0 };
float diffuseColor[] = { 1.0, 1.0, 1.0, 0.0 };
float specularColor[] = { 0.2, 0.2, 0.2, 0.0 };
float position[] = { -200.0, 400.0, 200.0, 1.0 };
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientColor);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseColor);
glLightfv(GL_LIGHT0, GL_SPECULAR, specularColor);
glLightfv(GL_LIGHT0, GL_POSITION, position);

old_time = 0.0;
/* Initialize bullit settings */
bullit.set_mass(0.2);
bullit.set_velocity(10,15,0);
bullit.set_acceleration(0,-10,0);
bullit.set_drag(0.9);
bullit.set_position(-80,50,0);
scene.add_shape(&bullit);

scene.add_shape(&ground);

shader.init("GLSL/shader.vert", "GLSL/shader.frag");
}

This is the draw function from the scene in scene.cpp:

/* Draw all shapes */
void Scene::draw_shapes() {
for(int i = 0; i < shapes.size(); i++) {
if(shapes[i]->get_type() == SPHERE) {
Sphere sphere = *((Sphere *) shapes[i]);
sphere.draw();
}
else if(shapes[i]->get_type() == PLANE) {
Plane plane = *((Plane *) shapes[i]);
plane.draw();
}
}
}

And this is the draw function in sphere.cpp:

/* Draw the sphere */
void Sphere::draw() {
glColor3f(color.x, color.y, color.z);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 32, 32);
glPopMatrix();
}

PascalM123
08-23-2010, 04:20 AM
And not to forget, the .vert and .frag files:

shader.vert:

varying vec3 normal;
varying vec3 light_pos;

/* This is the main-function of the vertex shader */
void main() {
normal = normalize(gl_NormalMatrix * gl_Normal);
light_pos = gl_LightSource[0].position.xyz;

gl_FrontColor = gl_Color;

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
shader.frag

varying vec3 normal;
varying vec3 light_pos;

/* This is the main-function of the fragment shader */
void main() {

float diffuse_value = max(dot(normal, light_pos), 0.0);
gl_FragColor = gl_Color * diffuse_value;
}

DmitryM
08-23-2010, 04:29 AM
Normalize 'light_pos' in the fragment shader before making a dot product.

Edit2:
Also, the vertex shader should take in account vertex position for the light vector calculation:


light_pos = (gl_LightSource[0].position - gl_ModelviewMatrix * gl_Vertex).xyz;

PascalM123
08-23-2010, 04:40 AM
I've posted the vert and frag-files. The problem is that I do not think that the GLSL-code contains the problem. When I'm using GLSL, the random drawn sphere has correct shades but the shapes added to the scene don't have correct shades.

When I'm not using GLSL the random drawn sphere also has fine shades and the other shapes not.

With GLSL, spheres are fully lit on one half and black on the other half, without GLSL, spheres are just totally lit.

PascalM123
08-23-2010, 10:13 AM
I have some new information regarding the problem:

If I comment out the part glColor3f(color.x, color.y, color.z) in sphere.cpp, you can see the shades, but when I am using glColor3f, there are no shades, just a sphere with one color.

If I use GLSL without glColor3f, the spheres are half white, half black and with glColor3f they are half the color specified and half black.

Is this information of any use?

Regards,
PascalM123

DmitryM
08-23-2010, 10:39 AM
First, tell me if the fix that I suggested works or not. What is the result?

PascalM123
08-24-2010, 01:45 AM
I'm sorry, I've missed the edit.

I'm trying to incorporate the piece of code, but it gives an incompatible types in assignment in assignment error, I'll take a look in the code to check the error.

Edit: Nope, incorporating that piece of code did not give another shading model.

DmitryM
08-24-2010, 06:12 AM
Did you normalize the light_pos in a fragment shader? Post the 'fixed' code here.

PascalM123
08-24-2010, 06:26 AM
When I normalized the light_pos variable, the shading on the spheres actually worked! As I think of it now, it's actually quit logical that the light_pos should be normalized.

I do have another question related to this problem. I have an application that runs with 60 frames per second and when I'm not using GLSL the application runs smooth, but with GLSL it does not. Is there an explanation for this?

Thanks your help!
PascalM123

shader.vert:

varying vec3 normal;
varying vec3 light_pos;

/* This is the main-function of the vertex shader */
void main() {
normal = normalize(gl_NormalMatrix * gl_Normal);

light_pos = (gl_LightSource[0].position - gl_ModelViewMatrix * gl_Vertex).xyz;

gl_FrontColor = gl_Color;

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

shader.frag:

varying vec3 normal;
varying vec3 light_pos;

/* This is the main-function of the fragment shader */
void main() {
vec3 norm_light = normalize(light_pos);

float diffuse_value = max(dot(normal, norm_light), 0.0);
gl_FragColor = gl_Color * diffuse_value;
}

DmitryM
08-24-2010, 07:08 AM
I'm glad you finally got it working. Sorry for the post edits, but you should pay more attention to what people (only me in this case) write/advice to you.

The fps smoothness lost in GLSL is a weird issue. Are you sure the fps is still 60?

PascalM123
08-24-2010, 08:15 AM
I've checked the frame per second, but when I/m using GLSL, the difference between 2 frames is circa 0.18 seconds and without GLSL it is 0.016 seconds.

I'm using glutTimerFunc with the first argument 100.0/6.0.