Download openGL2.cpp to
the project folder. Open the file from the VC7 interface and right-click to add it to the project.
Build the project and run it. The application opens two windows; one is a console window and the
other is an OpenGL window. The latter shows a purple sphere, though it looks more like a circle because
there is no lighting in the scene. We'll add that next.
// enable light0 and lighting glEnable(GL_LIGHT0); glEnable(GL_LIGHTING);Recompile the program and run it. You should now see lighting effects but only grayscale colors. When lighting is disable, OpenGL uses the current color as specified by the glColor command to color objects. When lighting is enabled, there are two ways to specify colors. The first is just use the current color, but you have to tell OpenGL to do this. After the light is specified in init(), add the following
glEnable(GL_COLOR_MATERIAL);Recompile and run the program. You should now see lighting effects and color!
OpenGL supports a (system-dependent) fixed number of lights named GL_LIGHT0, GL_LIGHT1, .... , GL_LIGHTn. The default position for a light is at (0,0,1) but we can change it. Add the following to init()
// set position of light0
GLfloat lightPosition[]={1,1,2,1}; // light position
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); // setlight position
You should notice that the light has moved to the right and up.
The function glLightv() used to is used to set various state variables with respects to the lights. The command takes three arguments. The first is the light number, which should be one of the OpenGL constants GL_LIGHTi. The second is the lighting parameter to be set, also one of the OpenGL constants. The final argument is the value the parameter should be set to. In this case, the value is a vector of floats, as specified by the fv (f for float and v for vector) in the command glLightfv().
Note the position vector has a 4th element. This specifies the type of light; when set to 1 it specifies a point light and when set to 0 it specifies a directional light. (Don't blame me, I'm just the messenger.) If you change lightPosition[3] to 0, you will see a difference.
GL_LIGHT0 is special in that it has a default color, which is white. In fact, OpenGL allows us to set the ambient, diffuse, and specular properties of the light separately. Add the following code to init().
// set color of light0
GLfloat red[] = {1,0,0,0}; // light color
glLightfv(GL_LIGHT0, GL_DIFFUSE, red); // set diffuse light color
glLightfv(GL_LIGHT0, GL_SPECULAR, red); // set specular light color
Also change the light back to a point light (by setting
lightPosition[3]=1). Now the sphere should appear red except in the
back where it is only lit
by ambient light.
Change the code to set the light color to white:
// set color of light0
GLfloat white[] = {1,1,1,0}; // light color
glLightfv(GL_LIGHT0, GL_DIFFUSE, white); // set diffuse light color
glLightfv(GL_LIGHT0, GL_SPECULAR, white); // set specular light color
This should look the same as when we didn't specify any color for the light, since the default for GL_LIGHT0 is white.
Add the following just before the triangle strip is drawn.
glNormal3f(0,1,0);
This illustrates a common problem that can arise in OpenGL programs,
inconsistent behavior. (In this case a change in the color of the
triangle strip when the
sphere code is removed.) This results when OpenGL is using some state
variable that you have not explicitly specified. (In this case, the
normal.)
Many OpenGL state variables have good defaults, but some, .e.g. normals,
have no obvious right value. So always set your normals!
// draw Triangle
float red[]={1,0,0,0};
float blue[]={0,0,1,0};
glNormal3f(0,0,1);
glBegin(GL_TRIANGLES);
glColor4fv(green);
glVertex3f(-5.0,0,-20.0);
glColor4fv(red);
glVertex3f(5.0,0,-20.0);
glColor4fv(blue);
glVertex3f(0.0,2.0,-20.0);
glEnd();
The color at any point on the triangle is interpolated based on the
distance of that point to each of the vertices. Interpolation is the
default
approach to coloring geometric primitives. Add the line
glShadeModel(GL_FLAT);before the new triangle. In flat shading mode no interpolation is performed. There are rules about which vertex color is used to color a primitive in flat shading mode, but you will typically use smooth shading. To avoid problems it is best to explicitly define the shading model. Remove the line you entered above and add the following to the init function:
//rasterization properties glShadeModel(GL_SMOOTH);(Note, we put this in init() because this is what we want as the default mode.)
GLfloat white[] = {1,1,1,0}; // white
GLfloat purple[] = {1,0,1,0}; // purple
glMaterialfv(GL_FRONT, GL_DIFFUSE, purple);
glMaterialfv(GL_FRONT, GL_SPECULAR, white);
glMateriali(GL_FRONT,GL_SHININESS,50);
You should now see a shiny purple sphere (with white highlights).
float constant=1.0; // constant attenuation float linear=0.5; // linear attenuation float quadratic=0.0; // quadratic attenuation glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, constant); // set constant attenuation term glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, linear); // set linear attenuation term glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, quadratic); // set quadratic attenuation termNote that we are using glLightf, where the f signifies a float argument.
GLfloat lightPosition[]={1,1,-8,1}; // light position
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); // setlight position
The light position is now transformed by the translate command.
Recompile and rerun your program. You should see a big change in the
lighting. You may think that OpenGL realizes that the sphere is
occluding the light. Unfortunately, OpenGL is not that smart --
in fact shadows are quite difficult to achieve in OpenGL (we'll talk
more about that in a future tutorial). We'll explore what
is going on here next but remove the two lines we
happened in the next section but remove the two lines you added above
before going on.