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