PDA

View Full Version : Finding Normals for Analytic Surfaces

miroslav_karpis
11-10-2008, 11:17 AM
Hi All,

I'm new to OpenGL and am just now reading the RedBook. I'm having a problem to understand the algorythm for calculating normals (for analytic surfaces)in Appendix F.
Please do you know about some example maybe simpler explanation? (was having math but couple of years ago :p)

trinitrotoluene
11-10-2008, 11:49 AM
First take the equation of a plane: ax + by + cz - d = 0, a,b,c and d are constant. To find the normal you need to calculate the gradient (http://en.wikipedia.org/wiki/Gradient) of the function. So N_x = df/dx = a,N_y = df/dy = b,N_z = df/dz = c. Then you have to normalize the result to have a unit length vector for correct lighting. So divide each component by the length of the result by sqrt(a*a + b*b + c*c). Notice that the normal is independent of the position of the point on the plane.
For a sphere or ellipsoid ax² + by² + cz² - r² = 0. The value of unnormalized normal is: N_x = 2ax,N_y = 2by N_z = 2cz. Of course here the normal is dependent of the position of a vertex on the sphere. So for example take a sphere with the equation x² + y² + z² - 1 = 0 => a = b = c = r = 1, and a point p (1,0,0) the resulting unnormalized normal is N = (2*1*1,2*1*0,2*1*0) = (2,0,0).

miroslav_karpis
11-10-2008, 11:29 PM
thanks a lot but am still not 100% 'in the game'.
As I understand than every polygon should have its own normal point. Am I right?

I have found following example. Can I use it?
//************************************************** *****************
// Function: CalculateVectorNormal
//
// Purpose: Given three points of a 3D plane, this function calculates
// the normal vector of that plane.
//
// Parameters:
// fVert1[] == array for 1st point (3 elements are x, y, and z).
// fVert2[] == array for 2nd point (3 elements are x, y, and z).
// fVert3[] == array for 3rd point (3 elements are x, y, and z).
//
// Returns:
// fNormalX == X vector for the normal vector
// fNormalY == Y vector for the normal vector
// fNormalZ == Z vector for the normal vector
//
//
// History: Date Author Reason
// 3/22/95 GGB Created
//************************************************** ********************

GLvoid CalculateVectorNormal(GLfloat fVert1[], GLfloat fVert2[],

GLfloat fVert3[], GLfloat *fNormalX,
GLfloat *fNormalY, GLfloat *fNormalZ)
{
GLfloat Qx, Qy, Qz, Px, Py, Pz;

Qx = fVert2[0]-fVert1[0];
Qy = fVert2[1]-fVert1[1];
Qz = fVert2[2]-fVert1[2];
Px = fVert3[0]-fVert1[0];
Py = fVert3[1]-fVert1[1];
Pz = fVert3[2]-fVert1[2];

*fNormalX = Py*Qz - Pz*Qy;
*fNormalY = Pz*Qx - Px*Qz;
*fNormalZ = Px*Qy - Py*Qx;

}

//and here is the function call:

glBegin(GL_POLYGON);
glVertex3fv(fVert1);
glVertex3fv(fVert2);
glVertex3fv(fVert3);
glVertex3fv(fVert4);

// Calculate the vector normal coming out of the 3D polygon.
CalculateVectorNormal(fVert1, fVert2, fVert3, &fNormalX,
&fNormalY, &fNormalZ);
// Set the normal vector for the polygon
glNormal3f(fNormalX, fNormalY, fNormalZ);
glEnd();

I found the example here (http://support.microsoft.com/kb/131130)

miroslav_karpis
11-11-2008, 04:13 AM
two more questions:
- how to calculate normal for a vertex?
- how to calculate normal for a triangle?

trinitrotoluene
11-11-2008, 06:04 AM
To compute a normal for a vertex you need another at least 2 adjacent vertex that are not co-linear to be able to compute the crossproduct (http://en.wikipedia.org/wiki/Cross_product) to find a normal. So for example take a triangle with vertices A =(0.0,0.0,0.0) B = (1.0,0.0,0.0) and C = (0.0,1.0,0.0). The first vector is V1 = B-A = (1.0,0.0,0.0), the second vector is V2 = C-A = (0.0,1.0,0.0).The cross product between V1 and V2 is (0,0,1).In the general case we need to normalize the result to have a vector of unit length. Notice that vector V1 and V2 are tangent of the surface. Now we need to find a vector that is perpendicular, that is the normal. By definition the cross product result of two vectors is perpendicular. Because here we deal with a single triangle we can apply the same normal to vertex B and C.Anyway if you decide to compute the normal for B and C you will obtain the same result as for A. Finally here we don't compute the normal analytically but geometrically. In case of a triangle in a mesh like a sphere, we could compute more than one normal for a vertex and average the result (smoothing the normal). Example if we compute 3 normals for a vertex than the unnormalized normal is (N1 + N2 + N3)/3.Advice: if you do that you must ensure that when you compute the crossproduct you use the same winding to avoid generating normal that can be in opposite direction or in too much different direction.Remember AxB = -BxA.

trinitrotoluene
11-11-2008, 06:27 AM
In you previous post:
Here Q and P are the two tangent vector that I tell you before and fNormal is the result of the crossproduct of PxQ.

Qx = fVert2[0]-fVert1[0];
Qy = fVert2[1]-fVert1[1];
Qz = fVert2[2]-fVert1[2];
Px = fVert3[0]-fVert1[0];
Py = fVert3[1]-fVert1[1];
Pz = fVert3[2]-fVert1[2];

Ok I notice in your code above that you call glNormal after the glVertex call. This is in wrong order. OpenGL is a state machine so when you call glVertex, the state machine take the current normal and apply it to the vertex. So place the glNormal3f(fNormalX, fNormalY, fNormalZ); call before the glVertex calls. That is:

// Calculate the vector normal coming out of the 3D polygon.
CalculateVectorNormal(fVert1, fVert2, fVert3, &amp;fNormalX, &amp;fNormalY, &amp;fNormalZ);
// Set the normal vector for the polygon

glBegin(GL_POLYGON);
glNormal3f(fNormalX, fNormalY, fNormalZ);
glVertex3fv(fVert1);
glVertex3fv(fVert2);
glVertex3fv(fVert3);
glVertex3fv(fVert4);
glEnd();

and all fVert1,fVert2,fVert3,fVert4 will have the same normal.

I hope that my explanation are easy to understand.

Edit: Verify if the computed fNormal is unit length, this is very important for correct lighting. I don't see that you normalize it in your code.

miroslav_karpis
11-11-2008, 01:38 PM
trinitrotoluene@: many thanks

trinitrotoluene
11-11-2008, 01:43 PM
Good to know that my explanation helped you.