Directional Lighting ?

All, I’m trying to add a single directional light source to my scene, the idea is that this will mimic the Sun and illuminate selected objects to give them some concept of depth and 3D context. My problem is that when the scene is rendered the output is not what I expect. It’s tough to describe so follow this URL for a screen shot (small jpeg) http://www.thecompass.co.uk/light1.jpg I’ve put two sections of code below, the first is how I’ve set up my lighting, the second is how each face (triangle) that makes up the 3D model is drawn.

The end effect I want to achieve is really just to light the model, in balance with other non-lit objects in my scene hence the background ambient light, and pick-out or highlight parts of the model to give a good perception of 3D. I’m not sure about the positioning of my light source “GL_LIGHT0” and this may well be the problem, truth is I’m not really sure where to put it or how to position to achieve my desired result ?

Thanks in advance for any help/pointers.
Ewan

= set up lighting ==============================================

GLfloat background_light[] = {0.43, 0.43, 0.43, 1.0};
GLfloat ambient_light[] = {0.2, 0.2, 0.2, 1.0};
GLfloat diffuse_light[] = {1.0, 1.0, 1.0, 1.0};
GLfloat specular_light[] = {1.0, 1.0, 1.0, 1.0};

/* directional light pointing down negative Z ? */
GLfloat light_position[] = {0.0, 0.0, 1.0, 0.0};

GLfloat shininess_material[] = {50.0};
GLfloat specular_material[] = {1.0, 1.0, 1.0, 1.0};

/* this is just a default value, this material property is

  • overwritten when the polygon model is generated, see below */
    GLfloat diffuse_material[] = {1.0, 1.0, 1.0, 1.0};

/* only do this once */
if (lighting() && !LightingGlSet)
{
glMaterialfv(GL_FRONT, GL_SHININESS, shininess_material);
glMaterialfv(GL_FRONT, GL_SPECULAR, specular_material);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, diffuse_material);

/* use some background ambient light */
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, background_light);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_light);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_light);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular_light);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);

LightingGlSet = TRUE;
}

================================================================

In my scene only some models require lighting effects to be applied
so GL_LIGHTING is turned off and on as required.

= draw each face of the model ==================================

glEnable(GL_LIGHTING);

/* now for each triangle in my model, draw vertices and the normal */
glBegin(GL_POLYGON);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
my_material_colour);
glVertex3f(x1, y1, z1);
glVertex3f(x2, y2, z2);
glVertex3f(x3, y3, z3);

 nx = (x2-x1)*(x2-x3);
 ny = (y2-y1)*(y2-y3);
 nz = (z2-z1)*(z2-z3);
 nl = sqrt((nx*nx)+(ny*ny)+(nz*nz));
       
 nx = (nl>0.0) ? (nx/nl) : nx;
 ny = (nl>0.0) ? (ny/nl) : ny;
 nz = (nl>0.0) ? (nz/nl) : nz;

glNormal3f(nx,ny,nz);
glEnd();

/* when all faces processed turn of lighting */
glDisable(GL_LIGHTING);

================================================================

[This message has been edited by Ewan (edited 12-01-2000).]

[This message has been edited by Ewan (edited 12-01-2000).]

I’ve seen something similar to the effect you are seeing, though from the code snippet I can only suggest that you declare the normal for a vertex before declaring the vertex. This is a requirement of the OGL state machine.
Like so:
glNormal3f(x,y,z);
glTexCoord2f(a,b);
glVertex3f(x,y,z);

<shrug>

My 2 cents…

Glossifah

Yes, the normals need to be defined before the actual vertex(ices). The last normal you defined will be applied to all following vertices until the next normal is defined.

So i’m doing things arse end first <bg>

Thanks, i’ll give this a try.
Ewan

Also note that if you specify only one normal for each face (by doing a cross-product of two vectors that lay on the plane defined by the face), you will get the same result whether you use GL_SMOOTH or GL_FLAT for polygon shading (it will be flat shading, but slower with GL_SMOOTH).

Originally posted by Moz:
Also note that if you specify only one normal for each face (by doing a cross-product of two vectors that lay on the plane defined by the face), you will get the same result whether you use GL_SMOOTH or GL_FLAT for polygon shading (it will be flat shading, but slower with GL_SMOOTH).

So in my code above i’m using a single normal for each face (triangle), is that why each face has a uniform colour when it is rendered (see the image url above)?

To get a smoother colouring on each face i.e. more like smooth shading then flat, how should i callulate/specify my normals ? I can take a hit in speed/performance in favour of good quality rendering.

Thanks
Ewan

To make the lighting smooth, you will need to use vertex normals rather than face normals. The vertex normal for each vertex is just the normalized vector sum of the unit face normals of each face the vertex is an element of. Although, in this case you may also want to add in some heuristics to prevent adding face normals that are of wildly different directions. That is if a vertex is a member of two or more faces that have very different normals, then you may need to calculate multiple vertex normals for a vertex and use the appropriate normal given the particular face you are drawing.

All, thanks for the advice i followed your directions and now my lighting looks ‘sweet’…

Thanks
Ewan

>>Also note that if you specify only one normal for each face, you will get the same result whether you use GL_SMOOTH or GL_FLAT for polygon shading…

Well, not entirely correct. For directional lights it is, but not for positional lights (felt like at least mentioning it :stuck_out_tongue: ). Consider the following example:
You place the light close to one of a triangle’s vertex. This will light this vertex more that the other two vertices, and you will have a smooth shaded triangle from a darker edge (the edge ‘far’ from the light) to a more lit vertex (the one near the light), if GL_SMOOTH is set of course. This is because the light is shining more directly ‘from above’ on the nearest vertex, and the light is shining from a more narrow angle on the two other vertices, and therefore they get darker.
But in common situations, where the light is’n placed so close to the triangles, you generally dont see this effect, but mathematically it’s still there.

Autant pour moi .

PS: In this case, you may also want to take attenuation (if used) into account .

Ah yeah, attenuation… This will also cause smooth shaded triangles when though you are using only one normal per triangle. Bah, off topic, but anyways