#### Archived

This topic is now archived and is closed to further replies.

# Tips on how to calculate vertex normals that gives a nice smooth surface shading?

This topic is 5477 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi I need some general help with vertex normal calculations. Well I have calculated vertex normal per triangle basis, in other words I have used one vertex normal to all of the vertexs on a triangle. But as is known this doesn''t give you a smooth shade across a surface. So I tried to calculate vertex normals that gives you a nice smooth shading surface, but I think I failed because the vertex normals are pointing way of the target. I used the dot product to get the angle between two triangles calculated normal, but the problem is when you have a vertex shared with more than two tirangles. How do I get an average normal if the vertex is shared by more than two faces. I made some pre calculation on paper and thought of the code, but my way seems to weird and to slow to perform. So if there are any tips that someone can give me please help me. I should say that math isn''t my stongest area, but I like programming and especially gameprogramming so I want to learn these things. Thank you for any help possible.

##### Share on other sites
Calculate the normals for each face first.
Then, for each vertex, add all the normals for the faces that shares that vertex, and renormalize the result.

##### Share on other sites
First, you need to find all the faces that connect at a specific point. Then you can average the normals for the faces that touch that point. Really easy if you are using indices.

A problem with that is that sharp faces will be lit wrong. One solution is to check if the angle between two faces is beyond a certain threshold, and average them together only if the angle is less than a certain value (45 defrees for example would work well for most meshes).

Make sure you normalize your vertex normals.

##### Share on other sites
quote:
Original post by tok_junior
Calculate the normals for each face first.
Then, for each vertex, add all the normals for the faces that shares that vertex, and renormalize the result.

Uh a little confused a different approach than I planned, or I just understand in the wrong way. Uh I think I need to loonk into this a little more. Thx I try what you suggested.

##### Share on other sites
quote:
Original post by drslush
First, you need to find all the faces that connect at a specific point. Then you can average the normals for the faces that touch that point. Really easy if you are using indices.

A problem with that is that sharp faces will be lit wrong. One solution is to check if the angle between two faces is beyond a certain threshold, and average them together only if the angle is less than a certain value (45 defrees for example would work well for most meshes).

Make sure you normalize your vertex normals.

Hmm I think I understand where you are going. I thought one of a similar approach, but my way was to complicated and as I said before weird. Thx I'll try

Something like this?
What I do below is go through every face in an object and calculate a normal for every vertex in a face. Then I add together the vertex normals for every shared face. Uh well the code may be much simpler to understand than my explanations.

void CalculateVertexNormals(){	int x = 0;	vertex zeroVertex;	zeroVertex.x = 0;	zeroVertex.y = 0;	zeroVertex.z = 0;	zeroVertex.count = 0;	vertex tempVector;	std::vector<vertex>::iterator pTempNormalVertex;	std::vector<vertex>::iterator pTempVertex1;	std::vector<vertex>::iterator pTempVertex2;	std::vector<vertex>::iterator pTempVertex3;	int tempVal = 0;	vertex temp;	// Go through every object in the model	for(std::vector<OBJ_DATA>::iterator j = ModelA.MODEL_DATA.begin(); j != ModelA.MODEL_DATA.end(); j++)	{		for(x = 0; x < j->VERTEX_NUM; x++)		{			zeroVertex.VertexID = x;			j->OBJVERTEXNORMAL_LIST.push_back(zeroVertex);		}		// Go through every face in this objcet and calculate normals to vertex values		for(std::vector<face>::iterator FACE = j->OBJFACE_LIST.begin(); FACE != j->OBJFACE_LIST.end(); FACE++)		{			// Get the vertex values of this face			pTempVertex1 = (j->OBJVERTEX_LIST.begin()+FACE->a);			pTempVertex2 = (j->OBJVERTEX_LIST.begin()+FACE->b);			pTempVertex3 = (j->OBJVERTEX_LIST.begin()+FACE->c);			// Calculate the curent faces vertexs crossproducts			//---------------------------------------------------------			pTempNormalVertex = (j->OBJVERTEXNORMAL_LIST.begin()+FACE->a);	// Get a pointer to this vertex from the vertex normal list			tempVector = CrossProduct(*pTempVertex1, *pTempVertex2, *pTempVertex3);	// Do the cross product			tempVector.x *= -1;			tempVector.y *= -1;			tempVector.z *= -1;			//temp = tempVector;			//NormalizeVector(temp);			pTempNormalVertex->x += tempVector.x;			pTempNormalVertex->y += tempVector.y;			pTempNormalVertex->z += tempVector.z;			pTempNormalVertex->count++;			pTempNormalVertex = (j->OBJVERTEXNORMAL_LIST.begin()+FACE->b);	// Get a pointer to this vertex from the vertex normal list			tempVector = CrossProduct(*pTempVertex2, *pTempVertex1, *pTempVertex3);	// Do the cross product			//temp = tempVector;			//NormalizeVector(temp);			pTempNormalVertex->x += tempVector.x;			pTempNormalVertex->y += tempVector.y;			pTempNormalVertex->z += tempVector.z;			pTempNormalVertex->count++;			pTempNormalVertex = (j->OBJVERTEXNORMAL_LIST.begin()+FACE->c);	// Get a pointer to this vertex from the vertex normal list			tempVector = CrossProduct(*pTempVertex3, *pTempVertex2, *pTempVertex1);	// Do the cross product						//temp = tempVector;			//NormalizeVector(temp);			pTempNormalVertex->x += tempVector.x;			pTempNormalVertex->y += tempVector.y;			pTempNormalVertex->z += tempVector.z;			pTempNormalVertex->count++;		}	}	// END OF CROSS PRODUCT CALCULATIONS	for(std::vector<OBJ_DATA>::iterator OBJ = ModelA.MODEL_DATA.begin(); OBJ != ModelA.MODEL_DATA.end(); OBJ++)	{		for(x = 0; x < OBJ->VERTEX_NUM; x++)		{			pTempNormalVertex = (OBJ->OBJVERTEXNORMAL_LIST.begin()+x);			pTempNormalVertex->x /= pTempNormalVertex->count;			pTempNormalVertex->y /= pTempNormalVertex->count;			pTempNormalVertex->z /= pTempNormalVertex->count;			NormalizeVector(*pTempNormalVertex);		}	}}

[edited by - LionheartAdi on June 16, 2003 3:57:23 PM]

##### Share on other sites
this has been asked too many times in the past. USE THE @#%!ing SEARCH BUTTON!

##### Share on other sites
Looks like you have the right idea. One thing you might want to consider is creating a class for your vectors and overload operators. Your code will look much cleaner and easier to read.

##### Share on other sites
AP, how many questions are ever asked on this forum that haven''t been asked before? Seriously...

##### Share on other sites
quote:
Original post by drslush
Looks like you have the right idea. One thing you might want to consider is creating a class for your vectors and overload operators. Your code will look much cleaner and easier to read.

Great thanks drslush. The vertex component is a structure values which hold just X,Y,Z and it''s used to import vertex data from ASE files. I wanted to keep the code amount low(lazy me). Then I convert the ASCI data to an another file format in to binary form. In other words lazt , but thanks again for the help. Now I can continue my code.

##### Share on other sites
Making a class and overloading operators would probably reduce the amount of code, plus it wouldn''t cost any speed, since you can inline them.

Glad to hear you got it working.

• 32
• 12
• 10
• 9
• 9
• ### Forum Statistics

• Total Topics
631352
• Total Posts
2999483
×