Light and Shading

Hi all,

I am using GL_TRIANGLE_STRIP to create a 3D image in OpenGL using C++. I have enabled LIGHT0, assigned it diffuse, specular and ambience values and positioned it where I need it. However it is not shading my 3D object, the object is being lit the same in all areas. Any Idea why this is happening ?

Thanks !

are your normals set properly (or at all)? have you enabled GL_LIGHTING? post some code.

jebus

I set my lighting values using the following,

// Apply Lighting model to the scene
void lightScene()
{
//Create a lighting model and store in a
//display list
if(ptrLight == NULL) ptrLight = new Light;

//Light Properties Directional Light source
ptrLight->setPosition(200.0, 200.0, 50.0);

// Lighting
glLightfv(GL_LIGHT0, GL_POSITION, (const float *) ptrLight->getPositionv());

glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
}

I haven’t set my Normals though. Excuse my ignorance but what effect does this have ? Do I need to set these for each vertex in my 3D Object or just for each Polyline etc ? Any sample code ?

Thanks !

Normals can be set by face, or by vertex, depending on how you render your objects. If you are doing it in intermediate mode, its done by face, if you are doing it in coordinate arrays they are done by vertex. Also remember the normals MUST be unit one. If not you get some “interesting” render results.

each vertex has a normal. however, if you set only one normal, opengl will use that normal for every vertex in your scene. it all biols down to what kind of shading you want. for flat shading, each polygon could have it’s own normal. for more smooth shading, each vertex should have it’s own normal. to set the normal, call glNormal before any glVertex call. for a simple flat shaded cube, there would be six calls to glNormal, one for each face of the cube:

glNormal3f(1,0,0);
draw_right_face();
glNormal3f(0,1,0);
draw_top_face();
glNormal3f(-1,0,0);
draw_left_face();
glNormal3f(0,-1,0);
draw_bottom_face();
glNormal3f(0,0,1);
draw_front_face();
glNormal3f(0,0,-1);
draw_back_face();

for a smooth shaded cube, it’s a little more difficult. you’d need a different normal for each vertex in the cube, resulting in 8 calls to glNormal, with some extra computation for getting the normal values. to get a vertex normal, you could average the normals for the faces for which that vertex is a part of.

please excuse shoddy ASCII art


/ T /|
/____/ |
| |R|
|F_|/

the front, top and right faces all share a vertex. to get the normal for that vertex you must average the normals for T F and R. these normal values tell opengl how to light/color the verices in your scene. good luck.

jebus

Thanks a lot for your help,

I’ve a simple loop that draws out my GL_TRIANGLE_STRIP using an array of doubles as so,

for (int k = 0; k < contourCounter; k++)
{
glBegin(GL_TRIANGLE_STRIP);

glColor3f(0.0,0.75,0.75);

//Loops for the number of vertex’s in each polyline (contour)
for(int m = 0; m < (numVertex[k] * 2); m++)
{
glVertex3f(triangleList[k][m].x,
triangleList[k][m].y,
0.0);
}

glEnd();

glFlush();
}

So would I have to define glNormal3f for all vertices within this loop ? These are contour lines so they very irregular objects, there are no real front or back faces so how would I go about averaging, or would I need to ?

Thanks again!

for the example you gave, since all your vertices lie on the XY plane (all z values are 0), then all the normals should be (0,0,1) (out of the screen) is this a flat object you are drawing?

jebus

Apologies I gave you the wrong code sample, this is the code I use. The vertices lie on the x,y plane and z is the hight value. It is a 3D model of terrain,

for (int k = 0; k < contourCounter; k++)
{
glBegin(GL_TRIANGLE_STRIP);

glColor3f(1.0,1.0,1.0);

for (int m = 0; m < (numVertex[k]*2); m++)
{
glVertex3f(triangleList[k][m].x,
triangleList[k][m].y,
triangleList[k][m].z);
}

glEnd();

glFlush();
}

if you are making some kind of file format to store your vertex values, you could computer the normals once, then store them in the file as well. so in your case, the terrain looks like this:

±-±-+ + - vertex
|\ |\ |
| | |
±-±-+
|\ |\ |
| | |
±-±-+

here’s where it gets tricky. in my terrain, i use triangle strips. my loop looks like this (i use xz plane and y for height):

loop (x=0 → xmax)
{
begin(TRIANGLE_STRIP)
loop (z=0 → zmax)
{
normal (nval, nval[hgt_val[x,z]], nval[z])
vertex (x, hgt_val[x,z], z)
normal (nval[x+1], nval[hgt_val[x+1,z]], nval[z])
vertex (x+1, hgt_val[x+1,z], z)
}
end
}

this is major pseudo-code (obviously ) i precompute my normals and store them in the file with my vertex data. for a heightfield of dimensions nxm, (n-2)x(m-2) vertices get transformed and lit twice, but this is not an issue, since computing these values is done prior to rendering.

FYI, i produce my heightmap data in photoshop, drawing a square grayscale image and saving it in RAW format. pixel in the image (or byte in the file) is a y-value that corresponds to the height. very handy!

jebus

I’m reading in files in DXF format. They are 2D contour maps produced by a system called OCAD. The dxf file simply holds the x and y values of the map, i.e.

y
| __
| / _
| | / \ |
| | _/ |

\ /

------------- x

No you’ll have to excuse my crap ascii sketch :wink:

So I read these in, and use a calculation on the placement of the contours to determine the height (z value of each map).

I get what you are saying regarding how to define the glNormal value for each vertex and storing the normal at the same time as the vertices. What do you use to calculate each normal value however ?

Thanks Jebus !

normal calculation is as follows (you’re really testing my artwork today )

A
+
|\ polygon ABC
|
|
|
±—+
B C

polygon normal = (B - A) X (C - A)

where X is the cross product

the above only works if the polygon is drawn counter-clockwise.

jebus