now.. this works, ok. but light it's not smoothed. i'm trying to compute also vertex normals. (i'm testing my engine with tubolar surfaces so i have almost all vertex shared with more then one triangles)

3 Answers
3

"Best" is pretty subjective -- it's going to involve weighing what you need out of the algorithm versus it's inputs, runtime complexity and other properties.

That said, both your approach and the linked FlipCode approach are reasonable in terms of producing usable results (you could quite simply copy your 'face normals' to each vertex, if you are not sharing actual vertex instances between triangles, which I'm unclear on from your code). Other techniques include weighting the contribution of each face normal by the size of the angle made with each face shared by the vertex.

You are correct in that the FlipCode approach appears suboptimal as written, but it could just be poorly specified: it's a little unclear whether or not it intends to suggest the second loop traverse all faces in the model, versus the handful of faces that share the vertex in question. If you have the adjacency information to reduce the search space of the second loop, it becomes less of a concern. Of course you may not have that adjacency information -- this is sort of what I mean by considering what inputs you have available to your algorithm.

If you don't just want to copy the face normal into the vertices, or you are sharing vertices and don't want to split them, you could:

sorry english is not my first lang so mayebe i've explained ina bad way what i want.. i don't have yet vertex normals! i've edited my answer a bit, hope now i more clear
–
nkintFeb 10 '11 at 23:51

It's okay, I understood you didn't have vertex normals. The pseudocode I provided will compute them for you by first setting each vertex's normal to (0,0,0) and then summing up the face normals for each face the vertex touches (and re-normalizing, of course).
–
Josh Petrie♦Feb 11 '11 at 0:15

4

You shouldn't normalize normals in this way. You should normalize after all summations in another foreach. If there is for example 10 triangles with the same normal, but last is with different (result normal should be almost equal to normal from 10 triangles), then you will have this, when summing the last one: set vertex nromal = normalize((1,0,0)+(0,0,1)) and that is (0.5,0,0.5), which is wrong. I hope that I haven't confused you.
–
zacharmarzFeb 11 '11 at 8:22

Josh Petrie has right. If you want to compute vertex normals, you should weight triangle contribution by angle. But you can use naive solution and just sum all normals from all faces around vertex.

So you just compute all face normals and normalize them. Then set all vertex normals to zero. Then for each face (triangle) add its normal to all of its vertices. Then normalize all vertex normals. And it's done.

It's not too correct but it could be enough.

And your face normal calculation above - it's correct but you should aware, which side normal heads. It could head up or down. It depends on cross product - AxB is not the same as BxA - it gives you opposite vector.

Let us assume that we have a cube made from 6 rectangles. We already know that the vertex normal for a cube is not the normalized sum of the connection faces because of the sharp edge. If you build a map of vertex value and it's different vertex normals for a cube you end up with 3 normals for each vertex.

Keeping the above point in mind this is how I calculate vertex normals(I have tested it and am using it).

Each face keep track of the vertex normals to use since two faces may share a vertex does not mean the vertex normal will be the same for each face.

Let us assume we are trying to calculate the vertex normal for vert when rendering face2.

vert is shared by face0,face1,face2,face3 and face4. All the above face are neighbours in order and face0 and face4 connect to form a loop.

The vertex normal for vert is the sum of all the connected neighbour chain to face2 normalized. The chain stops if the angle between two neighboured faces is more that 0.8 radians(angle == arccos(crossProduct(faceA.surface_normal, faceB.surface_normal))).

if the angle between face0 and face1 is more than 0.8 radian and the
angle between face3 and face4 is more than 0.8 radian than the vertex normal for vert when rendering face2 is normalize(surfnormal1+surfnormal2+surfnormal3).