PDA

View Full Version : Light on both sides of a polygon



Esben
12-01-2009, 08:45 AM
I am rendering a minigolf course with white walls on the edges:

In my init function I am enabling light, using color tracking to keep colors on polygons and turning on a single light:


glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHT0);


In my "light" function I am setting a global light and setting a diffuse light for GL_LIGHT0:


GLfloat global_ambient[] = { 0.4, 0.4, 0.4, 1 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
GLfloat diffuse[] = { 1, 1, 1, 1 };
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
GLfloat light_position[] = { 1, 1, 1, 1 };
glLightfv(GL_LIGHT0, GL_POSITION, light_position);


and then I'm drawing the walls:


glBegin( GL_QUADS);
glNormal3f(normal.x, normal.y, normal.z);
glVertex3f(v1.x, v1.y, v1.z);
glVertex3f(v2.x, v2.y, v2.z);
glVertex3f(v3.x, v3.y, v3.z);
glVertex3f(v4.x, v4.y, v4.z);
glEnd();


Where "normal" is the normal vector of the wall and v1-v4 are the vertices of the wall. v1-v4 are given in a counter-clockwise order, when viewing the wall from outside the course.

The problem is that if I try to move the diffuse light away from the course (using the light_position variable), both sides of the wall are lit by this light.. I would like it to be just the one side, that is, the one that is facing towards the light. Can you tell me what I am doing wrong?

Aleksandar
12-01-2009, 09:09 AM
Add this line in the function where you define lighting model

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);

Esben
12-01-2009, 09:24 AM
Add this line in the function where you define lighting model

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);

Thanks for your response :)

I am not sure I have a function that defines the lighting model but if I add the line in my light function (which is called in every frame), like this:



glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); // new

GLfloat global_ambient[] = { 0.4, 0.4, 0.4, 1 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
GLfloat diffuse[] = { 1, 1, 1, 1 };
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
GLfloat light_position[] = { 1, 1, 1, 1 };
glLightfv(GL_LIGHT0, GL_POSITION, light_position);


..there is no change. The wall is still lit on both sides. Any other suggestions?

Aleksandar
12-01-2009, 11:13 AM
You shouldn't call glLightModel*() functions in every frame. Everything else, except light position, can be called just once, in the initialization code. But that is not the problem.

Everything seams correct. Maybe something else that you didn't post as a code creates the problem...

overlay
12-01-2009, 01:05 PM
My understanding of glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE) is different:

According to the spec, when this flag is FALSE, the front material is used on the back face as well but the lighting equation use the same normal. So the backface will be lit.

If this flag is TRUE, then a back face material will be used and the normal used during the lighting equation will be the opposite of the one from the front back, so it is likely to be dark if the front side is lit and lit is the front side is dark.

So you'd better have this flag ON in your case.

Note the lighting equation has an ambient component that does not depend on the normal, so if neither the scene ambient nor the material ambient are null, you will have some ambient lighting (true also if you have an emission component).

Make sure all material components are null on the backface, including the ambient one.

ref: Spec 2.1 page 63 section "Lighting may operate in two-sided mode...". Also see the lighting equation page 62.

Aleksandar
12-02-2009, 03:23 AM
Well, overlay, it is time to change your misunderstanding of FFP lighting. ;)

According to the spec, when this flag is FALSE, the front material is used on the back face as well but the lighting equation use the same normal. So the backface will be lit.
Not true! LIGHT_MODEL_TWO_SIDE does not affect material properties.


If this flag is TRUE, then a back face material will be used and the normal used during the lighting equation will be the opposite of the one from the front back, so it is likely to be dark if the front side is lit and lit is the front side is dark.
Not true, again! LIGHT_MODEL_TWO_SIDE means that lighting calculation inverts normals when deals with back-side of the polygons. The front side has the same lighting as LIGHT_MODEL_TWO_SIDE is disabled.


Note the lighting equation has an ambient component that does not depend on the normal, so if neither the scene ambient nor the material ambient are null, you will have some ambient lighting (true also if you have an emission component).
Again NOT TRUE! The ambient components of the light sources multiply the ambient component of the material. In addition to that, global ambient light also has an impact. Maybe global ambient lighting creates that effect you have mentioned. If back side is always lighted, that it is the cause. Try to decrease ambient component of the material.


Make sure all material components are null on the backface, including the ambient one.
No need for that.


ref: Spec 2.1 page 63 section "Lighting may operate in two-sided mode...". Also see the lighting equation page 62.
I didn't see the spec, but I'll check it later. I really doubt that something wrong is written there.

Esben
12-02-2009, 04:06 AM
You shouldn't call glLightModel*() functions in every frame. Everything else, except light position, can be called just once, in the initialization code. But that is not the problem.

Everything seams correct. Maybe something else that you didn't post as a code creates the problem...

Okay, I now have everything except light-positioning in the init function, which is only called once. Init:



glEnable ( GL_LIGHTING);
glEnable( GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glShadeModel( GL_SMOOTH);
glEnable( GL_LIGHT0);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);

// global light
GLfloat global_ambient[] = { 0.4, 0.4, 0.4, 1 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);

// GL_LIGHT0
GLfloat diffuse[] = { 1, 1, 1, 1 };
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);


I believe I've posted every piece of code, that has to do with lighting.. What else can I look for?

Esben
12-02-2009, 04:09 AM
Maybe global ambient lighting creates that effect you have mentioned. If back side is always lighted, that it is the cause. Try to decrease ambient component of the material.

I didn't notice this suggestion before posting, sorry! How do I decrease the ambient component of the material?

Esben
12-02-2009, 04:32 AM
To make the problem clear, I have taken some screenshots of a simple minigolf hole. The diffuse light is placed to the right of the hole when viewing from the ball towards the cup/flag. Notice how the ball and the flag are lit correctly (only on the right side) but that the wall to the right isn't (lit on both sides). The ball is made using GLUT while the flag is a model I have loaded from a file. The walls, as explained earlier, are simple quads.

http://img228.imageshack.us/i/mini1.png/

http://img228.imageshack.us/i/mini2.png/

Edit: Hmmmm, I am not sure how to display images inside the post itself....

ZbuffeR
12-02-2009, 05:49 AM
From the screenshots it looks like the walls have reversed normals.

glNormal3f(normal.x, normal.y, normal.z);

-> check they point toward the exterior

Aleksandar
12-02-2009, 06:08 AM
I think that problem is not in normals, but in a material. I have just noticed the strange way you define material properties. I'll explain it later...

overlay
12-02-2009, 11:10 AM
To Aleksandar:

Reading the spec slower, if the flag is FALSE, the back color will be the same as the front color, result of the lighting equations. So I was wrong for the first statement.

Still, if the flag is TRUE, the back color is computed, using BACK material properties, quoting the spec "a back color is computed with a second set of material parameters (the back material)."

I think you misunderstood me when I said "it is likely to be dark if the front side is lit". "it" stands for the "back face". So your comment about what I said is exactly what I said.


Yes, I forgot to mention the ambient of the light, still it does not depend on the normal.

Aleksandar
12-02-2009, 12:08 PM
Sorry, overlay!

I'm very busy this week, and don't have time even to slowly read comments, but I'm always ready for quarreling. ;)
I swear that I'll read posts more carefully next time.

I didn't understand the second statement and that's why I said so. There is a tiny error (you have written "is" instead of "if") and in the hurry I missed the point. Yes, it is correct that two sides are differently lighted. Sorry again!

It is also true that ambient lighting effect does not depend on normals.

Aleksandar
12-02-2009, 01:10 PM
Maybe ZbuffeR is right. Why don't you post coordinates of the normal and the quad? On that way we will eliminate problem of normals. I hope you didn't use nonuniform scaling. If you did, don't forget to renormalize normals, or activate automatic normalization.

And now, let's back to materials... You have enable GL_COLOR_MATERIAL. Personally, I don't like that function because, although it enables fast changing of one material property by tracking color-change, it is not good for fine material tuning.

Than you have set a global ambient lighting to 0.4, which is pretty high. Global ambient lighting serves to emulate refraction of light from surrounding surfaces (which will be very expensive to calculate other way, using radiosity algorithm for example). In the open space, it should be 0.0. In the room it is higher. But if you set it to a very high value, your scene will be washed up. The default value is 0.2.

You have set just a diffuse component of GL_LIGHT0, and leave other parameters to their defaults. Do you know what the default values are? (You have set the diffuse component of the LIGHT0 to its already preset value, so you can skip even that.)

FFP lighting is per vertex. You have a "local" source of light, probably near to the pool, and very "big" quads. The lighting is not correct in those conditions. Try to subdivide quads.

Esben
12-03-2009, 03:34 AM
If this flag is TRUE, then a back face material will be used and the normal used during the lighting equation will be the opposite of the one from the front back, so it is likely to be dark if the front side is lit and lit is the front side is dark.

So you'd better have this flag ON in your case.

It turned out, that this solved my problem. I need to have two-sided lighting calculations turned on to get different lighting on front and back: glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE)

Thanks!