Lab (9) - Light and Shadow
Objectives:

To learn to create shadow

In the last few classes we talked about different  views and we learned how projection can be used to create shadow. To cast a shadow of a polygon, we move the origin to the light source (Lx,Ly,Lz), find the coordinates of x and z when y is -Ly along the ray from the light source to a given vertex, then translate back to where we were. We calculated our own projection matrix, as shown in 5.10.  You can use your own 4x4 matrices in OpenGL by creating a one-dimensional array m with the 4x4 array entries listed in column-major order (ordered by columns rather than the usual order by rows). Then glMultMatrix(m) will apply the transformation.

Following is a short program which illustrates shadows by having a light source rotate around a cube. Every time the light makes a complete circle, it is raised by a short distance (thus casting shorter shadows). Here's the program:

// By Late Dr. Mark Harris
#include <math.h>
#include <GL/glut.h>
typedef GLfloat point3[3];
GLfloat LightRadius=4;
GLfloat LightHeight=2;
GLfloat Lx=LightRadius,Ly=LightHeight,Lz=0;
double PI,PI2;
GLfloat m[16]={
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,0};

GLfloat t=0;
// List all vertices in array and reference later by index
point3 p[8]={
{0,0,0},
{0,0,1},
{1,0,1},
{1,0,0},
{0,1,0},
{0,1,1},
{1,1,1},
{1,1,0}
};

void drawPoint(int i,int shadow){
// Draw point i in color i
if(shadow)glColor3f(0,0,0);
else glColor3fv(p[i]);
glVertex3fv(p[i]);
}

void drawFace(int i1,int i2,int i3,int i4, int shadow){
// draw a face of the cube
glBegin(GL_POLYGON);
drawPoint(i1,shadow);
drawPoint(i2,shadow);
drawPoint(i3,shadow);
drawPoint(i4,shadow);
glEnd();
}
void myinit(void)
{
PI=atan(1.0)*4;
PI2=2*PI;
m[7]=-1/Ly;
/* attributes */
glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
glColor3f(0.0, 0.0, 0.0); /* draw in black */
/* set up viewing */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double w=.1;
glFrustum(-w,w,-w,w,.2,10);
}

void drawCube(int shadow)
{
drawFace(0,3,2,1,shadow); //bottom
drawFace(1,2,6,5,shadow); //front
drawFace(2,3,7,6,shadow); //right side
drawFace(0,1,5,4,shadow); //left side
drawFace(3,0,4,7,shadow); //back side
drawFace(4,5,6,7,shadow); //top
}

void display( void )
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); /*clear the window */
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(4,2,4,0,0,0,0,1,0);
drawCube(0);
glTranslatef(Lx,Ly,Lz); //translate back
glMultMatrixf(m);
glTranslatef(-Lx,-Ly,-Lz);
drawCube(1);
glFlush(); /* clear buffers */
glutSwapBuffers();
}

void idle()
{
t+=.1;
Lx=LightRadius*cos(t);
Ly=LightHeight;
Lz=LightRadius*sin(t);
m[7]=-1/Ly;
if(t>=PI2){
t-=PI2;
LightHeight+=.5;
}
glutPostRedisplay();
}

void main(int argc, char** argv)
{
/* Standard GLUT initialization */
glutInit(&argc,argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(500,500); /* 500 x 500 pixel window */
glutInitWindowPosition(0,0); /* place window top left on display */
glutCreateWindow("Cube"); /* window title */
glutDisplayFunc(display); /* display callback invoked when window opened */
glutIdleFunc(idle);
myinit(); /* set attributes */
glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
glEnable(GL_SMOOTH); /* Enable smooth shading and color interpolation */
glutMainLoop(); /* enter event loop */
}

Here's a sample image from the resulting animation:

shadow

We have talked about lighting models in class and will work on = matrieces that heps us set the lighting soon.

A real light source is very complex. A light bulb emits light of = various wavelengths from various points, and the cumulative effect at a target = involves lots of integral calculus.

We approximate light sources using one of three types:

Ambient lighting is a global approximation to uniform lighting. For = example, if we have many fluorescent bulbs in the ceiling, the net effect might = be uniform lighting. It is much faster to simply set a given light = intensity at all points than to integrate over all the light sources.