5
votes

I have a triangulated polyhedron (not necessarily convex) and the following information:

A list of the position of each vertex. A list of the vertex triples that define each face. A list of the vertex normals (Here the vertex normals are vectors from each vertex that are calculated by averaging face normals (see below) around each vertex).

I would like to calculate the list of face normals (The normalized vectors perpendicular to the plane of each face, pointing outward).

2
That is nice, why didn't you calculate it if you wanted to ? Did you use the Newell's method (opengl.org/wiki/Calculating_a_Surface_Normal) ?mmgp
I would like to be able to use this, but I don't know which way is "out" of the polyhedron, and so I can't deteremine in what order to take the cross product. Ideally there should be some way using the vertex nromals to determine which cross product is correct, but I'm just not sure how.user1873329
One way to locally define an orientation is to consider a PCA from a k-neighborhood (a set of the k points closest to a given point), but this may not give a globally consistent orientation. I also remember several works from Nina Amenta regarding estimation by Voronoi poles and other methods, have you checked this author or anything related ?mmgp
A simple suggestion is to average the 3 normals that you already have at each vertex. If that value is not precise enough, then compute the face normal yourself, and keep the orientation that matches the normal computed by averaging.nbonneel

2 Answers

5
votes

You can simply determines the orientation of crossed normal by dot it with one of vertex normal or average of all 3 vertices.

Here is the pseudo code:

Vec3 CalcNormalOfFace( Vec3 pPositions[3], Vec3 pNormals[3] )
{
    Vec3 p0 = pPositions[1] - pPositions[0];
    Vec3 p1 = pPositions[2] - pPositions[0];
    Vec3 faceNormal = crossProduct( p0, p1 );

    Vec3 vertexNormal = pNormals[0]; // or you can average 3 normals.
    float dot = dotProduct( faceNormal, vertexNormal );

    return ( dot < 0.0f ) ? -faceNormal : faceNormal;
}
0
votes

Native three.js code to do this with three vertices a, b and c:

You can get a, b and c from your THREE.Face3 and geometry vertices:

var a = geometry.vertices[ face.a ];
var b = geometry.vertices[ face.b ];
var c = geometry.vertices[ face.c ];

and then you do:

var normal = new THREE.Vector3().crossVectors( 
    new THREE.Vector3().subVectors( b, a ), 
    new THREE.Vector3().subVectors( c, a ) 
).normalize();

But there are also convenience methods in the THREE.Geometry class to do vertex and face calculations for you: computeVertexNormals and computeFaceNormals.