Skip to main content
GameDev.net gamedev.net
🔒 Locked

Calculating Mesh Normals

Started by sonka May 1, 2007 at 11:54 AM 8 replies 4.6k views
Original Post
sonka
sonka
Hi! After calculating normals of a terrain, I want to do the same with my .3ds model. I've found a topic in the forum and in it somebody wrote this algorithm:

for each vertex in the mesh
  find all the triangles that has the vertex
    calculate its surface normal
    add it to a variable
  end
  avarage the variable, and normalize it
end
Based on the algorithm above, I wrote this function:

void Mesh3ds::CreateNormals( void ) {
	if (!VertexCount || !TriangleCount) return;
	crVec3 normal, v1, v2;

	Normals = new crVec3[VertexCount];

	normal = crVec3( 0, 0, 0 );

	int k=0;
	for(unsigned long i=0; i<VertexCount; i++) {
		for(unsigned long f=0; f<TriangleCount; f++) {
			if (Triangles[f].a == i ) {
					v1 = Vertices[Triangles.b] - Vertices[Triangles.a];
					v2 = Vertices[Triangles.c] - Vertices[Triangles.a];
			}

			if (Triangles[f].b == i ) {
					v1 = Vertices[Triangles.a] - Vertices[Triangles.b];
					v2 = Vertices[Triangles.c] - Vertices[Triangles.b];
			}

			if (Triangles[f].c == i ) {
					v1 = Vertices[Triangles.a] - Vertices[Triangles.c];
					v2 = Vertices[Triangles.b] - Vertices[Triangles.c];
			}

				normal += normalize(cross( v1, v2 ));
				k++;
		}
		Normals = normalize (normal/float(k));
		k=0;
	}

}
I tried not to divide it with k, and when adding to 'normal', not to normalize it. ( normal += cross(v1, v2); then Normals = normalize(normal); ) But it does not work. I don't have any idea about this, please help!
haemonculus
haemonculus
you have to set v1 and v2 in clock or counter clock order as are your triangles.
you have to change the part:
if (Triangles[f].b == i ) {					v1 = Vertices[Triangles.a] - Vertices[Triangles.b];					v2 = Vertices[Triangles.c] - Vertices[Triangles.b];			}

to
if (Triangles[f].b == i ) {					v1 = Vertices[Triangles.c] - Vertices[Triangles.b];					v2 = Vertices[Triangles.a] - Vertices[Triangles.b];			}

that's the part that goes against the clock order.
the cross product changes the direction if the 2 vectors are in another order, so the sum of the normals is wrong.

if the clock order is another, you get normals, that are facing inside the mesh but thats not as big a problem.
best you let your program show the normals ;)
Palidine
Palidine
for each vertex in the mesh  find all the triangles that has the vertex    calculate its surface normal    add it to a variable  end  avarage the variable, and normalize itend


You don't need the average the variable step. just add all the normal vectors of the adjacent triangles together and normalize that.

I also found that the best way to do this for an old project the first time I did it was to draw the normals after the finding the normals part. That made it pretty trivial to debug.

-me
treeway
treeway
the normal of a triangle is the cross product of any two of its vertices (it doesnt matter which ones).
sipickles
sipickles
Are you using DirectX?

The D3DX library has functions to do this. See:

D3DXLoadMeshFromX
D3DXComputeNormals
D3DXComputeTangents

etc

:)

Simon
sonka
sonka
Thank you for your replies!
I'm using OpenGL, so I cannot enjoy the DirectX integrated functions :)

I modified my function to this:
void Mesh3ds::CreateNormals( void ) {	if (!VertexCount || !TriangleCount) return;	crVec3 normal, v1, v2;	Normals = new crVec3[VertexCount];	normal = crVec3( 0, 0, 0 );	for(unsigned long i=0; i<VertexCount; i++) {		for(unsigned long f=0; f<TriangleCount; f++) {			if (Triangles[f].a == i ) {					v1 = Vertices[Triangles.b] - Vertices[Triangles.a];					v2 = Vertices[Triangles.c] - Vertices[Triangles.a];			}			if (Triangles[f].b == i ) {					v1 = Vertices[Triangles.c] - Vertices[Triangles.b];					v2 = Vertices[Triangles.a] - Vertices[Triangles.b];			}			if (Triangles[f].c == i ) {					v1 = Vertices[Triangles.a] - Vertices[Triangles.c];					v2 = Vertices[Triangles.b] - Vertices[Triangles.c];			}				normal += cross( v1, v2 );		}		Normals = normalize (normal);	}}


But it also gives straaaaange results :S
Of course, I'm drawing the normals, that is from I know they aren't pointing to the right way. And somewhere I've got three normals per vertex !!
noisecrime
noisecrime
Looks like you're simply forgetting to reset the normal at the start of each vertex loop. At the moment it gets initialised once outside the vertex loop, and from then on each consecutive vertex checked will continue to add its face normals to the normal vector, instead of just those faces that include the vertex index.


ThrustGoblin
ThrustGoblin
When you are assigning v1 and v2, you're using i as an index into Triangles[] when you should be using f.

Cheers :)
Vorpy
Vorpy
If you see three normals coming out of one vertex, then either there is something wrong with your normal rendering or there are actually multiple vertexes in the same spot (which can be used to get sharper corners and edges).
sonka
sonka
Hey, thanks for your replies guys! I have finally made it!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.