CS 381 Fall 2012  >  Lecture Notes for Thursday, October 11, 2012

CS 381 Fall 2012
Lecture Notes for Thursday, October 11, 2012

Details of Lighting

Light and Paint Colors

To compute the color of the light reflected from a Lambertian surface, we need to know the intrinsic color of the surface: the paint color. We also need to know the light-source color. In our lighting code, we took the paint color from gl_Color, and we assume the light-source color was white.

If we wish to vary the light-source color, then we can compute the apparent surface color by multiplying the Lambert cosine by by a vector formed by the coordinatewise product of the light-source color with the paint color. In GLSL, this coordinatewise product is performed by the “*” operator.

[GLSL]

vec4 finalcolor = lambcos * lightcolor * paintcolor;

Positioning Light Sources

Light comes from somewhere. How does the shader tell where? We have hard-coded the light-source position into the shader. It would be nicer to specify the position in the application. Then, we could pass it to the shaders in a uniform variable. However, the light source is essentially an object (although perhaps not a visible object); it would be convenient to move it around the same way we move other objects, using the model/view transformation.

The tricky part is that the light source is in a different place from the object it lights; we need to use a different model/view transformation to position it. But our current code only allows for a single model/view transformation.

Fortunately, there is an OpenGL command involved in the FFP lighting that passes a light-source position through the current model/view transformation—that is, the transformation as it is at the time the lighting command is executed, not as it is when the primitive is drawn. I mostly avoid the FFP lighting facilities, but this one function is very useful.

The command is glLight*. Usually we call glLightfv. This takes three parameters.

Which light source
One of GL_LIGHT0, GL_LIGHT1, etc. Use GL_LIGHT0 if you have only one light source.
What property of the light source is being specified
Use GL_POSITION to set a light source’s position.
The new value for the property
For GL_POSITION this parameter is a 4-item array of GLfloat values. It gives the light-source position in object coordinates, in homogeneous form. Since we are treating the light source as an object, and positioning it with the model/view transformation, we generally place the light source at the origin: \(\langle 0,0,0,1 \rangle\) in homogeneous coordinates.

The resulting code might be something like this.

[C++]

// The camera transformation should already have been done

glPushMatrix();
glTranslated(1., 2., 3.);  // Light source at (1, 2, 3)
GLfloat origin4[] = { 0., 0., 0., 1. };
glLightfv(GL_LIGHT0, GL_POSITION, origin4);
glPopMatrix();

// Now draw an object, using a different transformation

In a shader, light source information is given in the array gl_LightSource, which is uniform. Each array item is a struct giving information about a particular light source. The information for light source 0 (GL_LIGHT0) is given in item 0, etc. We will ignore most of the struct members, but a couple of them are useful. In particular, each array item has a member position, which gives the light-source position, as a vec4, in homogeneous form.

[GLSL]

vec4 lightpos4 = gl_LightSource[0].position;
vec3 lightpos = lightpos4.xyz / lightpos4.w;  // Don't forget to convert!

Note that the above value has already been modified by applying the model/view transformation at the time of the glLight* call.

Drawing at the Light-Source Position

It would be nice to have some visible representation of our light source—perhaps a glowing ball.

It is easy to draw something at the light-source position, since we have already set up the model/view transformation. Just draw right after the glLight* command. Note that we probably want to turn shaders off when we do this.

[C++]

...
glLightfv(GL_LIGHT0, GL_POSITION, origin4);
glUseProgramObjectARB(0);      // Shaders off
glColor3d(1., 1., 1.);         // white
glutSolidSphere(0.1, 20, 15);  // A glowing ball
glPopMatrix();

// Now draw an object, using a different transformation

Lighting Function

It is a good idea to move the lighting computations into a separate function in our shader. For our current illumination model, we need five parameters: light color, paint color, light position, vertex position, and surface normal. We can pass the first two as vec4 values, and the last three as vec3 values, with the surface normal already normalized. Our return value can be the apparent surface color: a vec4.

[GLSL]

vec4 lambertLight(vec4 lightcolor,
                  vec4 paintcolor,
                  vec3 lightpos,
                  vec3 vertpos,
                  vec3 surfnorm)  // Normalized
{
    ...

Application useshaders.cpp and the shaders in lambertvert_shaders.zip were modified in line with the above ideas.

General Review

The Midterm Exam will cover all course material so far; see the posted lecture notes.

A short general review was done in class.


CS 381 Fall 2012: Lecture Notes for Thursday, October 11, 2012 / Updated: 11 Oct 2012 / Glenn G. Chappell / ggchappell@alaska.edu