Open GL Super Bible
Finding a NormalFigure 913 presents another polygon that is not simply lying in one of the axis planes. The normal vector pointing away from this surface is more difficult to guess, so we need an easy way to calculate the normal for any arbitrary polygon in 3D coordinates.
You can easily calculate the normal vector for any polygon consisting of at least three points that lie in a single plane (a flat polygon). Figure 914 shows three points, P1, P2, and P3, that you can use to define two vectors: vector V1 from P1 to P2, and vector V2 from P1 to P2. Mathematically, two vectors in threedimensional space define a plane (your original polygon lies in this plane). If you take the cross product of those two vectors (written mathematically as V1 X V2, the resulting vector is perpendicular to that plane (or normal). Figure 915 shows the vector V3 derived by taking the cross product of V1 and V2.
Don’t worry if you don’t know how to take the cross product of two vectors; all you need is the function in Listing 93. To use this function, pass it an array containing any three vertices from your polygon (specify in counterclockwise winding order), and an array that will contain the normal vector on return. The constant values x, y, and z are provided for your benefit if you want to see how the function works. Listing 93 Function to calculate a normal vector with any three vertices from a polygon // Points p1, p2, & p3 specified in counterclockwise order void calcNormal(float v[3][3], float out[3]) { float v1[3],v2[3]; static const int x = 0; static const int y = 1; static const int z = 2; // Calculate two vectors from the three points v1[x] = v[0][x]  v[1][x]; v1[y] = v[0][y]  v[1][y]; v1[z] = v[0][z]  v[1][z]; v2[x] = v[1][x]  v[2][x]; v2[y] = v[1][y]  v[2][y]; v2[z] = v[1][z]  v[2][z]; // Take the cross product of the two vectors to get // the normal vector which will be stored in out[] out[x] = v1[y]*v2[z]  v1[z]*v2[y]; out[y] = v1[z]*v2[x]  v1[x]*v2[z]; out[z] = v1[x]*v2[y]  v1[y]*v2[x]; // Normalize the vector (shorten length to one) ReduceToUnit(out); } Setting Up a SourceNow that you understand the requirements of setting up your polygons to receive and interact with a light source, it’s time to turn on the lights! Listing 94 shows the SetupRC() function from the example program LITJET. Part of the setup process for this sample program creates a light source and places it to the upperleft, slightly behind the viewer. The light source GL_LIGHT0 has its ambient and diffuse components set to the intensities specified by the arrays ambientLight[], and diffuseLight[].This results in a moderate white light source. GLfloat ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f }; GLfloat diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f }; … … // Setup and enable light 0 glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight); glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight); The light is positioned by this code: GLfloat lightPos[] = { 50.f, 50.0f, 100.0f, 1.0f }; … … glLightfv(GL_LIGHT0,GL_POSITION,lightPos); Here lightPos[] contains the position of the light. The last value in this array is 1.0, which specifies that the designated coordinates are the position of the light source. If the last value in the array is 0.0, it indicates that the light is an infinite distance away along the vector specified by this array. We’ll touch more on this later. Finally, the light source GL_LIGHT0 is enabled: glEnable(GL_LIGHT0); Listing 94 Light and rendering context setup for LITJET // This function does any needed initialization on the rendering // context. Here it sets up and initializes the lighting for // the scene. void SetupRC() { // Light values and coordinates GLfloat ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f }; GLfloat diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f }; Glfloat lightPos[] = { 50.f, 50.0f, 100.0f, 1.0f }; glEnable(GL_DEPTH_TEST); // Hidden surface removal glFrontFace(GL_CCW); // Counter clockwise polygons face out glEnable(GL_CULL_FACE); // Do not calculate inside of jet // Enable lighting glEnable(GL_LIGHTING); // Setup and enable light 0 glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight); glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight); glLightfv(GL_LIGHT0,GL_POSITION,lightPos); glEnable(GL_LIGHT0); // Enable color tracking glEnable(GL_COLOR_MATERIAL); // Set Material properties to follow glColor values glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // Light blue background glClearColor(0.0f, 0.0f, 1.0f, 1.0f ); } Setting the Material PropertiesNotice in Listing 94 that color tracking is enabled, and the properties to be tracked are the ambient and diffuse reflective properties for the front surface of the polygons. This is just as it was defined in the AMBIENT sample program: // Enable color tracking glEnable(GL_COLOR_MATERIAL); // Set Material properties to follow glColor values glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
