Hi,
I’m pondering how to create good normals for any given triangulated mesh. The standard approach “just average all face normals that meet at a vertex” just doesn’t cut it.
One common answer to this is “don’t average normals of faces that meet at a sharp edge”. Well, I want to compute vertex normals. One vertex can be shared by many faces, even ones that don’t share an edge. So the edge-answer seems wrong to me.
I’m now doing:
1. weld the mesh
2. compute per-triangle face normals
2. for each vertex
build a list of triangles that index the vertex
3. for each vertex V's triangle-list
for each triangle T1 in the list
find all others T2 in the list
if ((T1 dot T2)<creaseAngle)
remember in T1 and T2 that they are allowed to be averaged at V
4. finally, average the normals that are allowed to be averaged
5. distribute the averaged normals to the faces they belong to
This works well for sharp features but unfortunately, there are cases where it just fails
Is there some well known algorithm that handles all (most) cases?
I have been searching the web, but did’t find anything useful.
Instead of introducing a discontinuity (if < creaseangle) try taking in account the area of the face, as a weight for its normal, instead of blindly averaging.
This helped solve my problems on chamfered boxes.
With large square face, axis aligned, had each corner vertex shared with long thin rectangles and a very small triangle, the naive “just average all face normals that meet at a vertex” gave poor results.
Yeah, tried that, but blindly weighting won’t solve you even the simplest box. Discontinuities are absolutely wanted, but only where “it makes sense”… but that is what the algorithm has to find out… somehow.
It’s been a while since I messed with this. In my opinion, there’s not the one way to do it. If your input data is just a cloud of triangles, no more info given, you won’t get satisfying results without at least building the adjacency graph, finding “good” edge loops and then using this edge info to find “good” vertex normals. There are plenty of ambiguous corner cases involved. Just think of an edge sharing more than two triangles for example. So this will fail, too. But separating surfaces by finding continuous edge loops gives at least visually pleasing results. And since you just generated the edges, you can use them for rendering, of course.
Mhhm, what is a edge loop? What makes it a “good one”?
Is it a (ordered) list of triangles that all meet at a vertex?
What would this algorithm do with the top vertex of a cone?
The term “edge loop” is normally used to describe an ordered sequence of triangle edges, where the first and last vertex are the same. In particular the outer boundary of a surface describes an edge loop and each inner boundary (aka hole) also describes an edge loop.
What I propose is to find sequences of edges within the adjacency graph, that could possibly be good edge loops. They are good, if they match some kind of criteria, for example that crease angle, but you can make this as complicated as you want. You just don’t check it per edge, but try to find sequences of edges that match. Obviously, this problem is very hard to solve. It’s route finding within the adjacency graph. But you didn’t ask for fastest methods, did you?
The top vertex of a cone would (should) be detected as some kind of singularity - it’s one of the corner cases. You detect the discontinuity at this vertex (some triangles forming a sharp angle) but you don’t find any sharp triangle edges. So this vertex is an edge loop of it’s own. It not only starts where it ends, but also has zero length.
Ah, this kind of stuff make programming fun. (But only if there’s no deadline waiting for you. )
for each vertex
build a list of triangles that index the vertex
for each vertex V’s triangle-list
for each triangle T1 in the list
find all others T2 in the list
if ((T1 dot T2)<creaseAngle)
remember in T1 and T2 that they are allowed to be averaged at V
finally, average the normals that are allowed to be averaged
distribute the averaged normals to the faces they belong to
A crease angle only makes sense between two triangles sharing an edge.
So, you probably shouldn’t be testing two triangles that don’t share an edge.