# Calculating Vertex-Normals [Solved]

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

## Recommended Posts

Hello, I have a terrain (heightmap) and the standard OGL lighting in place. It works fine, but now I want to switch away from using face normals and start to use vertex normals (I believe that's how the "better" ones are called, right?). I am talking about the normals, that will actually give a blurred look, and not this flat, blocky look: I do use this function to calculate my face normals:
void get_face_normal ( float *norm, float pointa[3], float pointb[3], float pointc[3] )
// gets the normal of a face
{
float vect[2][3];
int a,b;
float point[3][3];

for ( a = 0; a < 3; ++a )
// copies points into point[][]
{
point[0][a]=pointa[a];
point[1][a]=pointb[a];
point[2][a]=pointc[a];
}

for ( a = 0; a < 2; ++a )
// calculates vectors from point[0] to point[1]
{
for ( b = 0; b < 3; ++b )
// and point[0] to point[2]
{
vect[a] = point[2-a] - point[0];
}
}

// calculates vector at 90° to 2 vectors
cross_product ( norm, vect[0], vect[1] );

// makes the vector length 1
normalize ( norm );
}


Now how would I best move on to using those vertex normals? I know that I'll have three normals for one polygon then and that I somehow need to average something, but nothing more. Heck, I don't even know if "vertex normals" is the correct word... Any help/links to articles would be great! [Edited by - d h k on November 6, 2005 10:49:00 AM]

##### Share on other sites
There're simple ways to do so, and there are accurate ways. However, look at this www.gamedev.net/community/forums/topic.asp?topic_id=354136 thread. It has started 5 days ago and discusses several ways w/ pros and cons on computing vertex normals.

The simple way is to average the normals of all faces adjacent to the vertex. But also here meanings exist of whether or not, and if, how to weight the normals in dependence to the participation of the face to the vertex.

Quote:
 Orignal post by d h kHeck, I don't even know if "vertex normals" is the correct word...

Yes, "vertex normal" is a valid term for what you mean.

##### Share on other sites
Thanks for your help. I was hoping for an easier way, as the thread seems to be quite... advanced. ;)

Anyways, is there any other tutorial/code snippet than the "Normal Computations For A Heightfield" out there? This one confuses me with all those DirectX terms. I can't seem to find anymore.

##### Share on other sites
Quote:
 Original post by d h kThanks for your help. I was hoping for an easier way, as the thread seems to be quite... advanced. ;)Anyways, is there any other tutorial/code snippet than the "Normal Computations For A Heightfield" out there? This one confuses me with all those DirectX terms. I can't seem to find anymore.

In theory, getting the normals you want is very easy. The 'algorithm' is as follows:
- for every vertex in your model:
- sum the face normals (component wise) for avery triangle containing the vertex
- devide the summed normal (component wise) by the number of triangles containing the vertex to get the normal for the vertex

And that's it. Determining the list of triangles that contain a specific vertex can be tricky if your datatstructure does not support it (in that case you should probably redesign the way in which your terrain data is stored).

Tom

##### Share on other sites
Thanks for your help. I understand what you mean, but am having troubles actually implementing it...

for ( int x = 0; x &lt; ( MAP_SIZE - STEP_SIZE ); x += STEP_SIZE )	// loop through horizontal data	{		for ( int z = 0; z &lt; ( MAP_SIZE - STEP_SIZE ); z += STEP_SIZE )		// loop through vertical data		{			float	vertex1[3];			float	vertex2[3];			float	vertex3[3];			float	vertex4[3];			float	normal1[3];			float	normal2[3];			float	normal3[3];			float	normal4[3];			// get vertex data			vertex1[0] = ( float ) x;										vertex1[1] = get_height ( ( float ) x, ( float ) z );				vertex1[2] = ( float ) z;			vertex2[0] = ( float ) x;													vertex2[1] = get_height ( ( float ) x, ( float ) z + STEP_SIZE );  			vertex2[2] = ( float ) z + STEP_SIZE;			vertex3[0] = ( float ) x + STEP_SIZE; 			vertex3[1] = get_height ( ( float ) x + STEP_SIZE, ( float ) z + STEP_SIZE ); 			vertex3[2] = ( float ) z + STEP_SIZE;			vertex4[0] = ( float ) x + STEP_SIZE; 			vertex4[1] = get_height ( ( float ) x + STEP_SIZE, ( float ) z ); 			vertex4[2] = ( float ) z;			// calculate normals			get_face_normal ( normal1, vertex1, vertex2, vertex3 );			get_face_normal ( normal2, vertex1, vertex3, vertex4 );			normal1[0] *= -1;			normal1[1] *= -1;			normal1[2] *= -1;			normal2[0] *= -1;			normal2[1] *= -1;			normal2[2] *= -1;			// draw the first triangle			glNormal3f ( normal1[0], normal1[1], normal1[2] );			glTexCoord2f ( 0.0f, 0.0f );			glVertex3f ( vertex1[0], vertex1[1], vertex1[2] );			glTexCoord2f ( 1.0f, 0.0f );			glVertex3f ( vertex2[0], vertex2[1], vertex2[2] );			glTexCoord2f ( 1.0f, 1.0f );			glVertex3f ( vertex3[0], vertex3[1], vertex3[2] );			// draw the second triangle			glNormal3f ( normal2[0], normal2[1], normal2[2] );			glTexCoord2f ( 0.0f, 0.0f );			glVertex3f ( vertex1[0], vertex1[1], vertex1[2] );			glTexCoord2f ( 1.0f, 0.0f );			glVertex3f ( vertex3[0], vertex3[1], vertex3[2] );			glTexCoord2f ( 0.0f, 1.0f );			glVertex3f ( vertex4[0], vertex4[1], vertex4[2] );		}	}

This is what I have to draw my terrain. So I need to calculate normal1 at vertex1, normal2 at vertex2, normal3 at vertex3 and normal4 at vertex4, right? I am quite confused at the moment, sorry for that. Could anybody explain just a little more?

##### Share on other sites
Quote:
 Original post by d h kThanks for your help. I understand what you mean, but am having troubles actually implementing it...*** Source Snippet Removed ***This is what I have to draw my terrain. So I need to calculate normal1 at vertex1, normal2 at vertex2, normal3 at vertex3 and normal4 at vertex4, right? I am quite confused at the moment, sorry for that. Could anybody explain just a little more?

No problem :)

As you can see, each cross-point has a single normal, eventhough such a point is shared by 6 triangles. From your screenshot, it looks that your surface is similar, in the sense that each vertex is part of 6 triangles. Looking through your drawing code, it seems you draw 2 triangles at a time. That's probably where your confusion comes from, because in that function you don't have the information of the other 4 triangles that is required to calculate the vertex normals.

To solve your problem, you'll probably have to pre-calculate the vertex normals, because doing this during the rendering phase is inconvenient (and not too good for performance either). To achieve this, I suggest you create a datastructure that contains vertex, normal, texturecoordinate and connectivity data (which vertices belong to which triangles and vice versa) and a function that draws such a structure using OpenGL. This datastructure will make it easier to calculate the desired vertex normals and can be re-used for all your other models as well (assuming that eventually you want something to populate your empty terrain :).

EDIT: Combining an OpenGL VBO with the connectivity data required to calculate the normals, would be an efficient choice for this datastructure.

Tom

##### Share on other sites
The simplest algorithm is as follows:

For each vertex, find the faces adjacent to it. For each of that faces get the face normal (e.g. by cross product computation). Summarize the normals of all of those faces, and re-normalize the sum. So you've computed the simple average of all normals.

When rendering, push the belonging vertex normal just before pushing the vertex point (in a pseude-code)
for each vertex v do {   VertexNormal n = { 0,0,0 };   for each face f adjacent to v do {      n += f.getNormal();   }   n.normalize();   glNormal(n);   glVertex3f(v.point());}

##### Share on other sites
Thanks a lot to both of you, I appreciate it, especially since terrain is going to be an important part of my project. I'll implement it right away.

##### Share on other sites
When most model formats export data, they do so like this for each polygon:
numsides vertex1id vertex2id vertex3id ...
Anyway, given this, the easiest approach would be not to look for faces using a vertex, but to do the following:

2. Calculate the face normal
3. Add it to the normal of each vertex making up that face (if you look at the example line above, this is really easy)
4. After that's done, normalize all the vertex normals

So you don't have to go looking for faces which share a vertex at all. I personally found this approach much easier to implement.

##### Share on other sites
i am going to go ahead and post my vertex normals function that i use. at the offset i should advise that you create a normals class to do all your stuff.. such as cross product and so forth. in some screenshots that i have posted in the past such as here and here , you can see the work of vertex normals. since ill assume you know how do cross product and all that stuff i will just go ahead and give you sample code with a simple data structure. hope this helps!

//class.h i define a few variables of type data
struct data{ double x; double y; double z;};data *terrain;data *normals

//in class.cpp i calculate what my xsize and ysize will be then allocate memory equally for my terrain and normals, then i store the x,y,z pairs in my terrain array. i have found its also helpful when storing your data to calculate the number of vertices you will have total which you can get by x_size * y_size * 3. you can read what your x,y & z values are through a file on disk or if your values are predefined you can do it manually.
terrain = new data[x_size * y_size * 3];normals = new data[x_size * y_size * 3];for(int i = 0; i < y_size; i++){ for(int j = 0; j < x_size; j++)  terrain[count].x = num_x; terrain[count].y = num_y; terrain[count].z = num_z;}

//in class.cpp you can call a load normals function that will load the normals in per vertex. i have a CVector class that is included in a header file that instantiates variables in the class for doing cross product, subtraction and addition of vectors as well as many other things. you can see some of them at work here.

void load_normals();{ int count; CVector V4; CVector V5; CVector V6;  for(int a = 0; a < ysize; a++)  {   for(int b = 0; b < x_size; b++)     {      if(count < x_size)      {       CVector V2(terrain[((a+1)*x_size)+b+1].x, terrain[((a+1)*x_size)+b+1].y, terrain[((a+1)*x_size)+b+1].z);       CVector V1(terrain[((a+1)*x_size)+b].x, terrain[((a+1)*x_size)+b].y, terrain[((a+1)*x_size)+b].z);       V4 = V2 - V1;       CVector V0(terrain[((a)*x_size)+b].x, terrain[((a)*x_size)+b].y, terrain[((a)*x_size)+b].z);       CVector V3(V1);       V5 = V0 - V3;       count++;      }     else if(count == x_size)      {              CVector V2(terrain[((a)*x_size)+b-1].x, terrain[((a)*x_size)+b-1].y, terrain[((a)*x_size)+b-1].z);       CVector V1(terrain[((a)*x_size)+b].x, terrain[((a)*x_size+b].y, terrain[((a)*x_size)+b].z);       V4 = V2 - V1;       CVector V0(terrain[((a+1)*x_size)+b].x, terrain[((a+1)*x_size)+b].y, terrain[((a+1)*x_size)+b].z);       CVector V3(V1);       V5 = V0 - V3;       count = 0;      }	  	        V6 = V5.Cross(V4);  //cross product      V6.normalize();     //normailizing to the unit vector = 1    //now lets store the normals after calculating them     normals[(a*x_size)+b].x = -V6.x;     normals[(a*x_size)+b].y = -V6.y;     normals[(a*x_size)+b].z = -V6.z;   } //end b  } //end a} //end load_normals()

now you have your terrain and normals stored and you are set up to draw your stuff. obviously my code could be lengthed by doing extra checking among all the vertices, to have some slight better results in the shading between vertices, but this works pretty well and i hope you understand it. so now you are read to do:

glNormal3f(normals[count].x, normals[count].y, normals[count].z)
glVertex3f(terrain[count].x, terrain[count].y, terrain[count].z)

or just however you decide to do this part.

again i hope this helps and i welcome comments!

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 12
• 14
• 10
• 14
• 24