PDA

View Full Version : Calculating Normals



David W. Allor
04-29-2010, 05:17 PM
Hi! I'm new to OpenGL and I'm trying to learn it on my own. I've been searching for days for a working example of calculating normals in C++. I can't get any of the examples I've found to work. When I run the code below, it shows a spinning pyramid, but the sides of the pyramid grow lighter and darker randomly rather than as they face the light. Maybe I'm giving the points in the wrong order, or maybe the math is wrong. Has anyone dealt with this before?

void Normal(
float p1_0,
float p1_1,
float p1_2,
float p2_0,
float p2_1,
float p2_2,
float p3_0,
float p3_1,
float p3_2
)
{

float v1[3], v2[3];
GLfloat normal[3];

v1[0] = p1_0 - p2_0;
v1[1] = p1_1 - p2_1;
v1[2] = p1_2 - p2_2;

v2[0] = p3_0 - p2_0;
v2[1] = p3_1 - p2_1;
v2[2] = p3_2 - p2_2;

normal[0]=v1[1]*v2[2] - v1[2]*v2[1];
normal[1]=v1[2]*v2[0] - v1[0]*v2[2];
normal[2]=v1[0]*v2[1] - v1[1]*v2[0];

glNormal3f(normal[0],normal[1],normal[2]);

}

void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

//Add ambient light
GLfloat ambientColor[] = {0.2f, 0.2f, 0.2f, 1.0f}; //Color (0.2, 0.2, 0.2)
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);

//Add positioned light
GLfloat lightColor0[] = {0.5f, 0.5f, 0.5f, 1.0f}; //Color (0.5, 0.5, 0.5)
GLfloat lightPos0[] = {4.0f, 0.0f, 8.0f, 1.0f}; //Positioned at (4, 0, 8)
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);

//Add directed light
GLfloat lightColor1[] = {0.5f, 0.2f, 0.2f, 1.0f}; //Color (0.5, 0.2, 0.2)
//Coming from the direction (-1, 0.5, 0.5)
GLfloat lightPos1[] = {-1.0f, 0.5f, 0.5f, 0.0f};
glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor1);
glLightfv(GL_LIGHT1, GL_POSITION, lightPos1);

glPushMatrix(); //Save the current state of transformations

glTranslatef(0.0f, 0.0f, -3.0f); //Move to the center of the pyramid

glRotatef(_angle, 0.2f, 1.0f, 0.1f); //Rotate about the the vector (1, 2, 3)

glBegin(GL_TRIANGLES);

//Pyramid
Normal(
0.0f, 0.7f, 0.0f, //top
0.5f, 0.0f, -0.5f, //bottom-right
-0.5f, 0.0f, -0.5f //bottom-left
);
glVertex3f(0.0f, 0.7f, 0.0f); //top
glVertex3f(0.5f, 0.0f, -0.5f); //bottom-right
glVertex3f(-0.5f, 0.0f, -0.5f); //bottom-left

Normal(
0.0f, 0.7f, 0.0f, //top
0.5f, 0.0f, 0.5f, //bottom-right
-0.5f, 0.0f, 0.5f //bottom-left
);
glVertex3f(0.0f, 0.7f, 0.0f);
glVertex3f(0.5f, 0.0f, 0.5f);
glVertex3f(-0.5f, 0.0f, 0.5f);

Normal(
0.0f, 0.7f, 0.0f, //top
0.5f, 0.0f, 0.5f, //bottom-right
0.5f, 0.0f, -0.5f //bottom-left
);
glVertex3f(0.0f, 0.7f, 0.0f);
glVertex3f(0.5f, 0.0f, 0.5f);
glVertex3f(0.5f, 0.0f, -0.5f);

Normal(
0.0f, 0.7f, 0.0f, //top
-0.5f, 0.0f, 0.5f, //bottom-right
-0.5f, 0.0f, -0.5f //bottom-left
);
glVertex3f(0.0f, 0.7f, 0.0f);
glVertex3f(-0.5f, 0.0f, 0.5f);
glVertex3f(-0.5f, 0.0f, -0.5f);

glEnd();

glBegin(GL_QUADS);

//Bottom
Normal(
0.5f, 0.0f, 0.5f, //top-right
0.5f, 0.0f, -0.5f, //bottom-right
-0.5f, 0.0f, -0.5f //bottom-left
);
glVertex3f(0.5f, 0.0f, 0.5f); //top-right
glVertex3f(0.5f, 0.0f, -0.5f); //bottom-right
glVertex3f(-0.5f, 0.0f, -0.5f); //bottom-left
glVertex3f(-0.5f, 0.0f, 0.5f); //top-left

glEnd();

glPopMatrix(); //Undo the move to the center of the triangle

glutSwapBuffers();
}

Yomboprime
04-29-2010, 07:12 PM
I've revised your Normal() function and seems ok. You should try with simpler geometry, like a quad in the x-y plane, and giving it a normal manually (in the z axis), to see if it spins and shows ok..

And, normally you should store your geometry in a data structure and compute the normal only once for each triangle. If not, then it's a waste of cpu. But i assume you're begginning with opengl so it's okay. But if you're just learning it, i advise you to learn the new way of opengl (version 3.0 and above). The functions you're using are now deprecated (but also, it's much harder to learn opengl the new way than the old way...)

David W. Allor
04-30-2010, 11:49 AM
I figured out the problem. When you calculate normals, you have to give the points in the correct order. I was looking at all of the triangles from the camera view, so I was calculating the inside, rather than outside, normals for two of the faces. The key is to switch the left and right of the faces facing towards negative z and negative x and then change the order in which the points are given to the function that calculates the normals.

I guess this was supposed to be a no-brainer, so I haven't seen this solution anywhere. That might mean that most people figure it out more easily, but hopefully someone who has the same problem will find this post.

It Works!!

Fugitive
05-02-2010, 04:55 PM
No actually someone else had the same problem earlier that I pointed out, only that they had back-face culling hiding the wrong faces. Its a common error.