Click to See Complete Forum and Search --> : Normals to triangles


disruptive
April 29th, 2008, 05:55 PM
I wish to construct normals to a surface from triangles. I have the triangulation and can calculate the normals based on the cross product of the edges. However there is an issue with direction. I wish all the normals to point say in the case of a sphere outwards. How do programmers in reality ensure that these normals are in the same direction....

Thanks

Zachm
April 29th, 2008, 11:52 PM
Actually, normals are usually calculated for each vertex sperately and not for an entire triangle. Ofcourse, this is application and model dependant.

For a sphere as you suggested, it is easy, since you can set the normal of each vertex v of sphere with center c to be: v-c (and don't forget to normalize).

For an arbitrary surface or mesh, you can use something like this code:

vector3 ComputeFaceNormal(const vector3 &v1, const vector3 &v2, const vector3 &v3)
{

vector3 u = v2 - v1;
vector3 v = v3 - v1;

return u.CrossProduct(v);
}

void ComputeBlendedNormals(void)
{
int faceNum; //Holds the current face num
vector3 normal; //Holds the current vertex blended normal.
vector3 faceNormal; //Holds the current face normal
unsigned int i; //Loop index
unsigned int face[3]; //Holds the current face vertex indices.

for(faceNum = 0; faceNum < m_NumFaces; ++faceNum)
{
face[0] = m_FaceIdxs[faceNum*3];
face[1] = m_FaceIdxs[faceNum*3+1];
face[2] = m_FaceIdxs[faceNum*3+2];

faceNormal = ComputeFaceNormal(m_Vertices[face[0]],
m_Vertices[face[1]],
m_Vertices[face[2]]);

//compute for every vertex in the face its blended normal
for(i=0;i<3;i++)
{
normal = ComputeVertexBlendedNormal(face[i], faceNormal);
m_Normals[face[i]] = normal;
}
}
}

vector3 ComputeVertexBlendedNormal(unsigned int vertexNum, vector3 &vNormal)
{

unsigned int face[3]; //Holds the current tested faces
int faceNum; //Holds the current face number that we test.
vector3 faceNormal; //Holds the current face normal
vector3 blendNormal; //Holds the result blended normal

for(faceNum=0; faceNum < m_NumFaces; ++faceNum)
{
face[0] = m_FaceIdxs[faceNum*3];
face[1] = m_FaceIdxs[faceNum*3+1];
face[2] = m_FaceIdxs[faceNum*3+2];
//if this is a neighbor face
if((face[0]==vertexNum)||(face[1]==vertexNum)||(face[2]==vertexNum))
{
faceNormal = ComputeFaceNormal(m_Vertices[face[0]],
m_Vertices[face[1]],
m_Vertices[face[2]]);

if( (vNormal * faceNormal) >= 0.71)
{
blendNormal = vNormal+faceNormal;
}
}
}

blendNormal = blendNormal - vNormal; //we added twice the normal of the vertex
blendNormal.Normalize();

return blendNormal;
}


This code can be tweaked for better performance but basically it calculates a normal for each vertex of a mesh, based on it's neighboring vertices, so the result will be a smoother shading.

Regards,
Zachm

disruptive
April 30th, 2008, 05:47 AM
Thanks

Where does the line:

vNormal * faceNormal) >= 0.71

come from?

Zachm
April 30th, 2008, 06:13 AM
0.71 ~= cos(45) (degrees)

This is actually just a threshold measure - the minimal angle between 2 neighboring faces normals to allow blend of those normals. You can play with it to get a stronger / lighter blend.

Regards,
Zachm