PDA

View Full Version : Calculate polygon normal



Frumpy
04-09-2001, 01:39 PM
How do I calculate the normal for a polygon (4 to 9 verticies) floating in a 3D world? The polygon may or may not be parallel to XY, XZ or YZ planes.

pleopard
04-09-2001, 02:08 PM
A polygon (face) with 3 vertices is the only polygon with an accurately defined surface normal. Break your surface up into 3 sided faces (e.g. 3 vertex per face). The normal(s) for a single face can be computed as follows:

Assuming that we have 3 points {p1, p2, p3} defining the X,Y,Z coordinates of a point in space ...

1) Create a vector v12 spanning from p1 to p2 (v12 = p2 - p1). Create a vector v23 spanning from p2 to p3 (v23 = p3-p2). Create a third vector v31 spanning from p3 to p1 (v31 = p1 - p3).

2) Create a vector n1 by crossing v12 with v23 (n1 = v12 X v23). This vector n1 is the face normal at the point p2. Create a vector n2 by crossing v23 with v31 (n2 = v23 X v31). The vector n2 is the face normal at the point p3. Create another normal by crossing v31 with v12 (n3 = v31 X v12). The normal n3 is the surface normal at point p1.

Unitize the vertex normals n1, n2, and n3 by dividing them by their magnitudes. The resulting vectors are the surface normals you will need for smooth shading the face. You can average the normals (n = (n1+n2+n3)/3) to get an approximate face normal for the overall face. The resulting vector n can also be used in shading the face but the resulting rendering will not be as smooth as it will be when using n1, n2, and n3 separately.

For adjacent faces, simply compute the vertex normals for each polygon using a given vertex and average them.

I hope that helps, I have a deadline I am working on so I won't be able to come back here to help for a day or so so good luck!

Frumpy
04-09-2001, 02:40 PM
Thanks for the reply but how very painful. Is there no easier method?

pleopard
04-09-2001, 03:00 PM
Sorry but that's the math required. If it were easy then anyone could do it and we wouldn't be compensated so well http://www.opengl.org/discussion_boards/ubb/smile.gif

The up-side is that you only have to do it one time and that the code required lends itself to re-use. Write a function or a class that does it for you, test it out, and tuck it away in your toolbox. It will come in handy for years to come. The code that I use is derived from a simple model viewing program I wrote back in 1987 using gl (notice no 'OpenGL :P)

coredump
04-09-2001, 03:08 PM
you can also find them by setting up 3 matrices using 3 known points on the polygon:

|1 y1 z1|
A = |1 y2 z2|
|1 y3 z3|

|x1 1 z1|
B = |x2 1 z2|
|x3 1 z3|

|x1 y1 1|
C = |x2 y2 1|
|x3 y3 1|

then the vector (A, B, C) is the normal to the plane.

b

MWinckler
04-10-2001, 05:15 AM
Originally posted by pleopard:
A polygon (face) with 3 vertices is the only polygon with an accurately defined surface normal. Break your surface up into 3 sided faces (e.g. 3 vertex per face). The normal(s) for a single face can be computed as follows:

Assuming that we have 3 points {p1, p2, p3} defining the X,Y,Z coordinates of a point in space ...

1) Create a vector v12 spanning from p1 to p2 (v12 = p2 - p1). Create a vector v23 spanning from p2 to p3 (v23 = p3-p2). Create a third vector v31 spanning from p3 to p1 (v31 = p1 - p3).

2) Create a vector n1 by crossing v12 with v23 (n1 = v12 X v23). This vector n1 is the face normal at the point p2. Create a vector n2 by crossing v23 with v31 (n2 = v23 X v31). The vector n2 is the face normal at the point p3. Create another normal by crossing v31 with v12 (n3 = v31 X v12). The normal n3 is the surface normal at point p1.

Unitize!


As you already stated that it doesn't make sense to talk
about face normals for polygons with more than three vertices, I don't get the point of computing **all three** normals. As three vertices always lie in a plane, all three normals should be equal (up to rounding error) so computing one of them is really enough.

tsuraan
04-10-2001, 11:21 AM
MWinckler:

You don't need to do normals for each vertex if you don't want to, for the reason that you stated, but if you are approximating some surface with triangle strips, you might want to do normal smoothing, where the normal of each vertex is averaged with the normals of the vertices of adjacent triangles, so that the lighting will smooth the surface rather than giving it a faceted look. If that run-on sentence scared you, just make fun of me. I can take it http://www.opengl.org/discussion_boards/ubb/smile.gif

martin_marinov
04-12-2001, 06:57 AM
Hi
this is some actual code for doing the job.
here (*this)(i) returns a refence to the i-th vertex which is standart 3d point class supporting basic vector operations. Skip template definitions. The idea is just to iterate through the vertices to find the normals at every vertex. It is done by evaluating the cross product of the edge vectors, joining at the vertex. These two vectors form a plane, which normal is exactly the one you need for every vertex.


template <class _Vertex, class _Link>
void CSdPoly<_Vertex, _Link>::CalcNormals() const
{
top_int i;
for ( i = 0; i < m_nVertsCount; ++i)
{
const_cast<_MyType&>(*this)(i).Normalize();
}

C3DVector prev ( (*this)(0) - (*this)(m_nVertsCount - 1) );
for (i = 0; i < m_nVertsCount; ++i)
{
top_int nNextId = GetRelId(i, 1);
C3DVector next((*this)(nNextId) - (*this)(i));

m_normals[i] = prev^next;
prev = next;
}
}

Hope this helps
Martin

pleopard
04-12-2001, 08:43 AM
Originally posted by MWinckler:
As you already stated that it doesn't make sense to talk
about face normals for polygons with more than three vertices, I don't get the point of computing **all three** normals. As three vertices always lie in a plane, all three normals should be equal (up to rounding error) so computing one of them is really enough.


DOH! I have no clue what I was thinking about, you are absolutely correct. You can compute one of the vertex normals and it will be parallel to the others. The [runtime] vertex normal can be computed by retrieving such a normal from all faces using a given vertex and averaging them all together.

Thanks for catching that... http://www.opengl.org/discussion_boards/ubb/smile.gif