Shadow

We looked more closely at shadows today, covering the material in 5.9 of our text. 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, shown on page 234 of our text. 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:

We talked about lighting models.

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.

Please read chapter 6 through 6.3.2.