Materials and Lightning - Everything looks flat

Hi,

I am trying to render some models and would like to add some lightning to it.

So I added the following lines to my project:

            float[] light_position = { 10.0f, 1.0f, 1.0f, 0.0f };
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, light_position);
            Gl.glEnable(Gl.GL_LIGHTING);
            Gl.glEnable(Gl.GL_LIGHT0); 

Before I start rendering I set the material properties with the following function:

 
        private void SetMaterial(B3DMaterial m)
        {
            if (m == null)
            {
                m = new B3DMaterial();
            }
            Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_AMBIENT, m.AmbientColor);
            Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_DIFFUSE, m.DiffuseColor);
            Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_SPECULAR, m.SpecularColor);
            Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_EMISSION, m.EmissiveColor);
            float s = m.Shininess;
            s *= 128;
            Gl.glMaterialf(Gl.GL_FRONT, Gl.GL_SHININESS, s);
        }
 

(The B3DMaterial is a wrapper class that contains the properties of the material.)

During the rendering there is a rotation of my objects. When I watch the restult I slowly see the model light up when it enters the light and see it darken when it leaves the light again.

But the strange thing is that all parts of the model have the same colour during this process. In other words my objects appear to be flat. What am I doing wrong?

This is probably something obvious I am missing. I am a real beginner and it is the first time I tried to render material properties.

Thank you in advance!

You probably forgot to supply normals for your polygons.

Yes indeed I have not supplied normals.
… But there are also no normals mentioned in the X3D file I got supplied.
How am I supposed to draw them then?

Should I write some function to calculate them or is there a standard function for this?

Thank you for your fast and good reply so far!

Do them yourself, it’s no biggie.
Lighthouse3D has a good introduction to normals

or maybe this will help a little, it’s copypasted from my own engine so you have to rewrite it a little for it to work.
all vars are floats(exept for vr)

v1[0]=g3ds.vert[vr[1]][0] - g3ds.vert[vr[2]][0];
v2[0]=g3ds.vert[vr[0]][0] - g3ds.vert[vr[2]][0];

v1[1]=g3ds.vert[vr[1]][1] - g3ds.vert[vr[2]][1];
v2[1]=g3ds.vert[vr[0]][1] - g3ds.vert[vr[2]][1];
	
v1[2]=g3ds.vert[vr[1]][2] - g3ds.vert[vr[2]][2];
v2[2]=g3ds.vert[vr[0]][2] - g3ds.vert[vr[2]][2];
	
nv[0]=(v1[1]*v2[2])-(v1[2]*v2[1]);
nv[1]=(v1[2]*v2[0])-(v1[0]*v2[2]);
nv[2]=(v1[0]*v2[1])-(v1[1]*v2[0]);
				

normalize(nv,-1); 

Thanks zeoverland ! That’s great stuff. I had been reading the opengl “redbook”. But it was not that clear there. Looks indeed easy now!

There’s just one more thing you can maybe give me some advice on.

glBegin(GL_TRIANGLES);
for(int i=0;i<pointcollection.Length;i++){
glVertex3f(pointscollection[i]);
}
glEnd();

I used to draw point per point. Like the code above. But I guess I will now have to draw 3 points at a time, like this:

glBegin(GL_TRIANGLES);
for(int i=0;i<pointcollection.Length-2;i+=3){
glVertex3f(pointscollection[i]);
glVertex3f(pointscollection[i+1]);
glVertex3f(pointscollection[i+2]);
//...and compute normals based on [i][i+1][i+2];
glNormal3f(...);
}
glEnd();

Or can I also set (equal or different) normals for each points of a vertex?

So that I would get the following code:

glBegin(GL_TRIANGLES);
for(int i=0;i<pointcollection.Length;i++){
glVertex3f(pointscollection[i]);
glNormal3f(normalcollection[i]);
}
glEnd();

Each normal is set per vertex when you call glVertex to the last value set by glNormal.
So use the last one, but set the normal first.

glBegin(GL_TRIANGLES);
for(int i=0;i<pointcollection.Length;i++){
glNormal3f(normalcollection[i]);
glVertex3f(pointscollection[i]);
}
glEnd();

Eventually you will also learn how to smothly blend the normals with each other giving your geometry a more rounded apperance, but that is a whole other issue.

Thank you all! It is starting to work pretty well. Especially when I split up the faces first in several triangles. The more triangles the nicer it looks :slight_smile: . Also I’ve been avereging the normals with the normals of their neighbours, this also seems to help.

Eventually you will also learn how to smothly blend the normals with each other giving your geometry a more rounded apperance, but that is a whole other issue.

That’s a usual practice? The last hyperlinks you people gave me were really helpful. Is there also a good tutorial on how to get started blending the normals?

Thank you all!

Yes it’s a usual practice.
You need to average all normals that share the same vertic as you said you where doing, personally i am also discarding normals (from being ingluded in the average of the current normal) based on the dotproduct of the two normals, if it’s over 0.707 i don’t use them for averaging.

this will alow you to still have both sharp edges and smooth polygons with the same algothitm.

Just keep experimenting and you will eventually get it.

Just another example

		glBegin( GL_TRIANGLES );
		{
			for ( int j = 0; j < Meshes[i].NumTriangles; j++ )
			{
				const int triangleIndex = Meshes[i].TriangleIndices[j];
				const MS3DModel::Triangle * pTri = &(Triangles[triangleIndex]);
 
				for ( int k = 0; k < 3; k++ )
				{
					const int index = pTri->VertexIndices[k];
 
					glNormal3fv( pTri->VertexNormals[k] );
					glTexCoord2f( pTri->Textures1[k], pTri->Textures2[k] );
					glVertex3fv( Vertices[index].Location );
				}
			}
		}
		glEnd();
	}