Lighting & Shading

By default, OpenGL renders the colour of a primitive depending on the value set at the vertices by glColor*(). This produces a very artificial view of the scene. In reality, the apparent color of objects depends on three things;

  1. The material of the object (material colour, shininess)
  2. The light falling on the object (colour & type of light)
  3. Relative position and orientation of the surface to the light(s) & to the viewer.

In order to display lighting effects, lighting needs to be enabled (lighting is disabled by default).

OpengGL allows us to set various properties of lights in the scene. GLSL will use these settings in a lighting model to attempt the render each part of the scene accurately given the various material and lighting settings.

 

Rough Definitions

Ambient light: Light bouncing around a scene (usually assumed constant throughout a scene).

Diffuse Light: Light direct from a light source.

Specular Reflection: Very bright intense spot of light reflected from shiny objects.

Specular Reflection

There are two settings to consider for specular reflection;

  1. Colour of bright spot (this should be white for most materials).
  2. Size of the specular spot (shininess). Smooth surfaces have a wide dull specular spot, polished surfaces have a small bright spot.

A list of relectivity settings for some materials is available here.

 

 

Creating Light Sources

OpenGL supports at least 8 individual light sources (known as GL_LIGHTo, GL_LIGHT1, ..., GL_LIGHT7).

The most important properties of a light are it's colour and position. The following code gives GL_LIGHT0 a Blue colour and moves it high on the y-axis;

GLfloat light_color[]={0.0, 0.0, 1.0, 1.0};
GLfloat light_position[]={0.0, 10.0, 0.0, 1.0};


glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color); // set color of diffuse component
glLightfv(GL_LIGHT0, GL_SPECULAR, light_color); // set color of specular component


glLightfv(GL_LIGHT0, GL_POSITION, position);   // set position

The function glLight*() can be used to set many more light settings, such as attenuation, spot light properties, additional ambient light.

Lights in camera space vs model space

More specifically, when glLight*() is called to specify the position or the direction of a light source, the position or direction is transformed by the current modelview matrix and stored in eye coordinates.

Moving Light Sources

Now suppose you want to rotate or translate the light position so that the light moves relative to a stationary object. One way to do this is to set the light position after the modeling transformation, which is itself changed specifically to modify the light position.

Surface Orientation (specifying vertex normals)

An important factor in calculating the appearance of a surface with respect to light sources is the relative orientation of the surface. A normal vector a is a vector perpendicular to a surface. A normal vector should be specified for each vertex. OpenGL performs lighting calculations for each vertex and interpolates the vertex lighting across the polygon to which it belongs.

Each vertex needs a surface normal vector

Specifying a normal for a vertex is simple, just call glNormal*() before specifying the vertex;

  GLfloat normalA[]={1.0,1.0,0.0);  // fill an array with 3 components of a vector
  
  glNormal3fv(normalA); 		// specify the current normal
  glVertex3f(1.0,2.0,5.0);	// specify a vertex
  

Calculating Surface Normals

 

void NormalVector(GLfloat p1[3], GLfloat p2[3], GLfloat p3[3], GLfloat n[3]){
	
	GLfloat v1[3],v2[3]; // two vectors
	
	//calculate two vectors lying on the surface
	// v1=p2-p1
	// v2=p3-p2
	
	for(int i=0;i<3;i++){
		v1[i]=p2[i]-p1[i];
		v2[i]=p3[i]-p2[i];
	}
	
	// calculate cross product of two vectors ( n= v1 x v2)
	n[0]=v1[1]*v2[2] - v2[1]*v1[2];
	n[1]=v1[2]*v2[0] - v2[2]*v1[0];
	n[2]=v1[0]*v2[1] - v2[0]*v1[1];
	
} //done

 

OpenGL Programming Guide (Red Book) Chapter 6 - Lighting