PDA

View Full Version : Compute vertex normals for TRIANGLE_STRIP



Rapthor
01-09-2007, 02:01 AM
Hello,

I have to compute vertex normals for combined TRIANGLE_STRIPs. The combination results in grounds (terrain) consisting of those TRIANGLE_STRIPs.

I wonder how I will be able to compute a normal for each vertex.

Because computing a normal for each triangle only would result in per triangle lighting. I prefer per vertex lighting to have smooth edges between the triangles.

Please help me, am I right with this statement?

The next question: How do I compute a normal for each vertex in a TRIANGLE_STRIP?

Thanks in advance.

Zengar
01-09-2007, 02:57 AM
Exacly the same way you compute the normal for ordinary triangles... You could average the normals of triangles that share the same vertex and store the result as that vertex normal. This may give you smooth edges, but you should make sure that you model has no sharp edges.

jide
01-09-2007, 04:05 AM
For about your statement, I'm actually pretty sure you can't do any per face normals with triangle strips. For that point to be true, all the strip needs to represent the same surface flat plane, which obviously is not the case for terrains.

Rapthor
01-09-2007, 04:46 AM
Hm ... are you sure I can't use per face normals?

The following example shows, how I am building 2 faces consisting of 2 triangles using an index array and TRIANGLE_STRIPs.

0 2
.-.
I/I
.-.
1 3

So there are 4 vertices.

This is the code I'd use to compute the first triangle's (0,1,2) normal:

Vertex vec0, vec1, vec2, vecA, vecB;
float x,y,z;

// spanning vectors
x = vec1.X - vec0.X;
y = vec1.Y - vec0.Y;
z = vec1.Z - vec0.Z;
vecA = new Vertex(x,y,z); // the first spanning v.

x = vec2.X - vec0.X;
y = vec2.Y - vec0.Y;
z = vec2.Z - vec0.Z;
vecB = new Vertex(x,y,z); // the second spanning v.

// cross product of spanning vectors
x = vecA.Y * vecB.Z - vecA.Z * vecB.Y;
y = vecA.X * vecB.Z - vecA.Z * vecB.X;
z = vecA.X * vecB.Y - vecA.Y * vecB.X;

new Vertex(x,y,z); // the resulting normal

Is this okay? So how do I compute the normal of the second triangle and then build the average of both?

Zengar
01-09-2007, 05:24 AM
You can't have per-face normals because vertices are shared between faces. OpenGL interpolates the vertex normal across the face to perform lighting (not really corrent, as only color will be interpolated). Because of this, the only one possibility to get per-face normals is to specify the same normal for each vertex of the face. You can't do it in your case, as vertices are shared.

Averaging the normals

step 1:
set all normals to (0,0,0)

for all faces:
for all face vertices set vertex normal to the sum of vertex normal and face normal

step 2:
for all vertices normalize the normal

Ready!

Rapthor
01-09-2007, 05:33 AM
In other words, I can't have a smooth lightened terrain consisting of triangle strips?

The steps you described are only suitable when using triangles instead of strips?

Zengar
01-09-2007, 06:28 AM
Rapthor, strips *are* triangles, only defined in a more compact way. Vertices 0,1,2 are a triangle; 1,2,3 another one etc.

jide
01-09-2007, 07:06 AM
Of course you can have smooth terrain with strips, this is the way to do: per vertex normals are made for that point.

Also, using index array with strips is not really a need.

And as others said, lineary interpolate all face normals for each vertex and you'll have something really acceptable in most of situations.
For more accurate normals you'll need a parametric representation of your surface.

Overmind
01-10-2007, 02:21 AM
Even with triangle strips, most vertices of a typical terrain are referenced at least twice, so an index still saves some vertex duplication.

jide
01-10-2007, 02:29 AM
You're right, I just have forgotten this point.

Rapthor
01-10-2007, 08:59 AM
Ok, I did it. Now my terrain looks good even with triangle strips.

Hydra
12-11-2007, 01:23 PM
Here's a quick and dirty way to compute per vertex terrain normals from the height field itself...no polygons needed...

terrainNormal[i][j].x = z[i-1][j] - z[i+1][j];
terrainNormal[i][j].y = z[i][j-1] - z[i][j+1];
terrainNormal[i][j].z = 100.0f;
Normalize(terrainNormal[i][j]);

This is also a slick way to shade an overhead view of height fields that have a height per pixel...:)