CS155 Computer Graphics

OpenGL Tutorial 2

In this OpenGL tutorial we'll explore the OpenGL Lighting Model. (For a more thorough treatment of the OpenGL lighting model refer to Woo etal, Ch 5.)
  1. Create a project:
    In VC7, create a new Visual C++ Project. Select "Win32 Console Project"as the template. Create the project on your desktop with the name "MyOpenGL2." You'll be presented with an "Applications Settings" window where you should choose "Empty Project."

    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.

  2. Lighting: Specify light
    The first step is to specify the light. Add the following code to the init() function.
    	
    	GLfloat white[] = {1,1,1,1};				// light color
    	GLfloat lightPosition[]={1,1,-8,1};			// light position
    	glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);	// setlight position
    	glLightfv(GL_LIGHT0, GL_DIFFUSE, white);		// set diffuse light color
    	glLightfv(GL_LIGHT0, GL_SPECULAR, white);		// set specular light color
    	glEnable(GL_LIGHT0);
    	glEnable(GL_LIGHTING);
    
    The glLightfv() 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(). (See Woo for a full description of argument specifications.)

    The lines
    	GLfloat lightPosition[]={x,y,z, type};		
    	glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
    
    specify the type of light and its position/direction. If type=1, the light is a point light while type=0 specifies a directional light. For a point light, (x,y,z) specifies the position of the light. For a directional light, < x,y,z > is the light direction. (I know... I'm just the messenger!)

    	glLightfv(GL_LIGHT0, GL_DIFFUSE, white);		// set diffuse light color
    	glLightfv(GL_LIGHT0, GL_SPECULAR, white);		// set specular light color
    
    Sets the color of our light. Note that OpenGL lighting is more flexible than the model we used for raytracing in that a light can provide different colors for diffuse and specular.

    The last two lines enable the light we've defined as GL_LIGHT0 and lighting in general.

  3. Lighting: Specify material properties
    The next step is to specify the material properties of the sphere. Replace the glColor3f()command in display() with the following code:
    	
    	GLfloat white[] = {1,1,1,1};			// white
    	GLfloat purple[] = {1,0,1,1};			// purple
    	
    	glMaterialfv(GL_FRONT, GL_DIFFUSE, purple);
    	glMaterialfv(GL_FRONT, GL_SPECULAR, white);
    	glMateriali(GL_FRONT,GL_SHININESS,50);	
    
    
    Just as with colors, the most recently defined properties apply to an object when it is drawn.

    < Recompile your code and run it. You should now see the effects of lighting.


  4. Lighting: Attenuation
    Next lets add some attenuation for our light. Add the following to your init function:
    	
    	float const=1.0;						// constant attenuation
    	float linear=0.5;						// linear attenuation
    	float quadratic=0.0;						// quadratic attenuation
    	glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, const);		// set constant attenuation term
    	glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, const);		// set linear attenuation term
    	glLightf(GL_LIGHT0, GL_QUQADRATIC_ATTENUATION, const);		// set quadratic attenuation term
    
    Note that we are using glLightf, where the f signifies a float argument.
    Recompile and see what happens. Adjust the attenuation parameter to get some nice fall off on the sphere.


  5. Lighting: Transforms
    Light positions can be transformed in the same way as vertices. Add the following lines after the translate transform in display.
    	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.

  6. Lighting triangles strips:
    Next create a "ground" for your scene; i.e. a flat surface the sphere will sit on. To do this, we will use a new primitive call a GL_TRIANGLE_STRIP. Add the following after your sphere:
    	
    	glBegin(GL_TRIANGLE_STRIP);
    		glVertex3f(-20.0,-1.0,-40.0);
    		glVertex3f(-20.0,-1.0,0.0);
    		glVertex3f(20.0,-1.0,-40.0);
    		glVertex3f(20.0,-1.0,0.0);
    	glEnd();
    
    Recompile and run your program.

    There are several issues with the current code that need to be fixed. First, OpenGL computes the color at vertices then interpolates across the triangle. In order to do this, OpenGL needs surface normals (just as you did in the ray tracer). You can define a normal by glNormalf(vx,vy,vz). OpenGL keeps track of the the most recently defined normal and uses it When you create a vertex by a call like glVertexf(-10,-5,10). Since the normal to our floor is <0,1,0> it suffices to call glNormalf(0,1,0) immediately before the call to glBegin(GL_TRIANGLE,STRIP).

    The second problem is the position of the vertices relative to the light. Because of the distance between the light and the vertices and the attenuation factor the light is very low at the vertices. Removing the attenuation won't help much though. That is because, Just like in the ray tracer, the lighting calculation includes a term of that is the dot product between the direction of the incident light and the surface normals. Since the vertices of the floor triangles are relatively far from the position of the light, the light falls on the vertices at a steep angle and the dot product is small. To fix this, Modify your ground to comprise several several triangle strips, each with many smaller triangles. Recompile and run your program.


Updated 10/10