Newsgroups: comp.graphics
From: sloan@willis.cis.uab.edu (Kenneth Sloan)
Subject: Surface Normals (summary)
Date: 6 Sep 91 02:00:35 GMT

Recall the assumptions: you are given a shared vertex, and its neighbors in a polygonal (triangular) mesh. The problem is to estimate the surface normal at the shared vertex. Here are the methods submitted in response to my query, in roughly the order received:

Method 0: `weight-by-area'
Add up the normals of each polygon sharing a vertex, then normalize. While it was unstated by the people who submitted this method, it was clear that the `normals of each polygon' have magnitudes which are proportional to their areas (in some sense). If the `polygons' are triangles, then these `weighted normals' are simply computed as the cross-products of the successive vectors formed by the shared vertex and it's neighbors. Re-arrange terms, optimize the code, and you get the formula presented in many texts. A possible problem with this method is that the result is independent of the location of the shared vertex. A major advantage is that it can be made to run very fast.

Method 1: `weight-uniformly'
Add up normalized face normals, then normalize. This is more expensive, unless you already compute and store (normalized) face normals for each polygon (triangle). It is reported to work a bit better than `weight-by-area'.

Method 2: `least squares'
Fit a plane to all of the vertices. Variation: fit the plane to all of the vertices *except* the shared vertex.

Method 3: `eigenvalues'
Compute moments, form a scatter matrix, and extract eigenvalues and eigenvectors. The eigenvector corresponding to the smallest eigenvalue is the (unnormalized) surface normal. Variations as above - either with or without the shared vertex.

Method 4: `independent derivatives'
Intended only for dense meshes - use 2 independent directional derivative estimators.

Method 5: `weight-by-angle'
Compute normalized face normals for the neighboring polygons, and weight each normal by the angle formed at the shared vertex.

Method 6: `weight-by-inverse-area'
As above, but weight the normals by inverse area. This method appears to have been independently invented by myself and Andrew Glassner, circa 1985. I am particularly interested in pointers to published literature which discusses this method. The idea here is that small triangles have all of their vertices close to the shared vertex, and "know" more about the local surface normal than the far-off vertices forming large triangles. It turns out (see the forthcoming paper) that this is also relatively easy to compute.

Thanks to all. (very) preliminary results indicate that `weight-by-area' is the most accurate method. But, this is very preliminary (i.e., see the forthcoming paper).

If there are any other methods out there that were `too obvious to mention', I'd still like to hear about them.