averaging face normals

I have created a class that reads a 3d studio asc file into a standard format ( list of verticies , list of faces , list of models) and i have successfully calculated the normals for the faces. this works fine when i render the model but I want to be able to make it look smooth.

i have written a piece of code to calculate vertex normals based on the average of the normals for each of the faces that share a particulatr vertex.

this gives me a horrible result (all the faces are shaded in a very strange way) and i cant work out whats wrong.

can anyone help?

kev.

here is the code:

void C3DImportedASCObject::CalculateVertexNormals()
{
if(m_numModels > -1) {
for(int ii=0; ii<=m_numModels; ii++) {
for(int jj=0; jj<m_model[ii].numFaces; jj++) {

			// set the vertex normal to the sum of all the shared face normals
			for(int kk=0; kk&lt;3; kk++) {
				m_model[ii].faceList[jj].vertex[kk]-&gt;normal[0] +=
							m_model[ii].faceList[jj].normal[0];
				m_model[ii].faceList[jj].vertex[kk]-&gt;normal[1] +=
							m_model[ii].faceList[jj].normal[1];
				m_model[ii].faceList[jj].vertex[kk]-&gt;normal[2] +=
							m_model[ii].faceList[jj].normal[2];

				m_model[ii].faceList[jj].vertex[kk]-&gt;m_numSharedFaces++;
			}
		}

		// average the vertex normals
		for(int ll=0;ll&lt;m_model[ii].numVertices;ll++) {
			m_model[ii].vertexList[ll].normal[0] = m_model[ii].vertexList[ll].normal[0] / 
				m_model[ii].vertexList[ll].m_numSharedFaces;
			m_model[ii].vertexList[ll].normal[1] = m_model[ii].vertexList[ll].normal[1] / 
				m_model[ii].vertexList[ll].m_numSharedFaces;
			m_model[ii].vertexList[ll].normal[2] = m_model[ii].vertexList[ll].normal[2] / 
				m_model[ii].vertexList[ll].m_numSharedFaces;
		
			Normalise(m_model[ii].vertexList[ll].normal[0],
					  m_model[ii].vertexList[ll].normal[1],
					  m_model[ii].vertexList[ll].normal[2]);
		}

	}
}

}

You don’t have to divide the vertex normals by the number of shared faces before the normalization. The direction of the vector stays the same, so you only need to normalize.

Anyway, your method seems to be ok. It is possible that
a) your rendering code does something wrong
b) ‘Normalise’ function is not working correctly (not likely, your face normal calculation works)
c) the face normals haven’t been calculated before the vertex normal calculation (not likely)

So, I’d say it’s a.

Hmm, doesn’t .ASC files contain vertexnormals? I’m pretty sure it does. If so, there is no need to calculate your own normals

Think I have some code at home for importing .ASC files with vertexnormals.

the .asc file has AB:1 BC:1 CA:1 for every face - this is the only info i havent used to construct my model and i’m not sure what it means.

i’ve tried it without dividing by the number of faces and it still messes up.

this is the code for the draw:

void CGLImportedASCObject: raw()
{
float normal[3];
for(int nn=0;nn<=m_numModels;nn++) {
for(int ii=0;ii<m_model[nn].numFaces;ii++)
{
glBegin(GL_TRIANGLES);
float surface[] =
{(float)m_model[nn].faceList[ii].colour[0]/255,
(float)m_model[nn].faceList[ii].colour[1]/255,
(float)m_model[nn].faceList[ii].colour[2]/255,
(float)m_model[nn].faceList[ii].colour[3]/255};

			glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,surface);
			
			// Used for face normals 
			// glNormal3fv(m_model[nn].faceList[ii].normal); 
			
			for(int jj=0; jj&lt;3; jj++)
			{
				// Used for vertex normals
				glNormal3fv(m_model[nn].faceList[ii].vertex[jj]-&gt;normal);
				glVertex3fv(m_model[nn].faceList[ii].vertex[jj]-&gt;point);
			}
		glEnd();
	}
}

}

any ideas?

I can’t find any BIG bug in your code but here is an advice for normals troubles :

When you display your model, display the normals as well (scale them if you want to see something !).

That would be something like that :

glBegin(GL_LINES);
glVertex3d(v.x,v.y,v.z);
glVertex3d(v.x+scalen.x,v.y+scalen.y,v.z+scale*n.z);
glEnd();

If there is a big inconsistency in your normals, you will immediately see it.

If your normals seems OK, perhaps it’s a lighting problem…

Eric

Oops, forgot something : did you specify glShadeModel(GL_SMOOTH) somewhere in your code ???

Eric

to create vertex normals there are two basic approaches, imo: use smoothing groups and don’t use soothing groups

SG’s are a way to identify surfaces into meshes.
a cube has 6 surfaces, a sphere has one, a cylinder has 3 surfaces…
a torus have one surface, like the sphere.

surfaces can be made of any number of polygons, and vertex normals for a given SG have to be evaluated separately from the other polygons, not belonging to the same SG.

this leads to the fact that vertices that lay on the seam between two different SG have more than one normal.

if your model is, for simplicity, a sphere (any object with a single surface), you don’t have to mess with SG’s.

if your model is more complex, to say, a cube with a cylinder coming out the center of a cube’s face, then you can’t simply average normals from faces wich share a vertex.

you will get wrong lighting.

if your model is complex, you have to care abous SG’s, and it’s a bit complex…

to avoid troubles, i suggest you to use 3D studio MAX scene ascii export files (.ASE): they have multiple normals for vertices.

Dolo//\ightY

Originally posted by kevin:
the .asc file has AB:1 BC:1 CA:1 for every face - this is the only info i havent used to construct my model and i’m not sure what it means.

These are boolean flags used to determine which edges to draw when rendering a wireframe of the model.

Originally posted by Eric:
[b]Oops, forgot something : did you specify glShadeModel(GL_SMOOTH) somewhere in your code ???

Eric[/b]

Agraaaaaaaaahah - i cant believe i have been so dumb!

I was trying to render it with vertex normals and i forgot to change the shade model from flat to smooth. i’ve changed it to smooth and it works just fine! - thanks for all your help.