Assignment 7- Due Friday April 18

Diffuse lighting

Send the program as an e-mail attachment and submit  a hard copy in class.  You will not see the colors on the black and white printout.  Please visit the web page.

The program below shows a recursively-generated sphere (obtained by subdividing the faces of a tetrahedron) with random colors on the polygonal faces. The command line parameter, an integer in the range 0 - 5, specifies the recursion level. You can set the command line under Project, Settings, Debug, Program arguments. Here's a resulting image with the parameter set to 3:

color_sphere

Your mission is to simulate diffuse lighting from a light source at direction <1,1,1> from the center of the sphere. The strongest light, illuminating the sphere "head on", should be pure red; the portion in shadow should be black. All other faces should be illuminated with an intermediate shade of red. Here's what you should end up with:

sphere

Diffuse lighting takes the intensity from the angle between the surface normal and the light source; the location of the viewer doesn't matter. The intensity is proportional to the cosine of the angle between the normal and the light vector. This is just the dot product of the normalized vectors in the two directions, and is easy to calculate. In the case of a sphere, the direction of the normal is from the center to a given point on the surface. Since we'll be using a constant color across each triangular face, we'll use a single normal for each triangle. In general, you would take the cross product of two edges of the triangle to obtain the normal, but in this special case you can obtain the same effect by using the vector from the origin to the center of the triangle (the average of the three vertices). You will have to normalize this vector. Then use the dot product of this vector with the light vector to get the cosine of the light angle, which can be used as the red component of the color. Clamp this value to [0,1]; in other words, a negative cosine indicates that the triangle is in shadow and should be black. You shouldn't get values greater than 1 from the cosine function.

This isn't a hard assignment; you'll be adding just a few lines of code to the program below.

Here's the multi-colored version of the program:

/* Recursive subdivision of tetrahedron (Angel) */

#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>


typedef float point[3];

/* initial tetrahedron */

point v[]={{0.0, 0.0, 1.0}, {0.0, 0.942809, -0.33333},
          {-0.816497, -0.471405, -0.333333}, {0.816497, -0.471405, -0.333333}};

int n;

void normal(point p)
{

/* normalize a vector */

    float d =0.0;
    int i;
    for(i=0; i<3; i++) d+=p[i]*p[i];
    d=sqrt(d);
    if(d>0.0) for(i=0; i<3; i++) p[i]/=d;
}

void triangle( point a, point b, point c)

/* display one triangle */
{
        glBegin(GL_POLYGON);
                glColor3ub(rand()%256,rand()%256,rand()%256);
                glVertex3fv(a);
                glVertex3fv(b);
                glVertex3fv(c);
        glEnd();
}

void divide_triangle(point a, point b, point c, int m)
{

/* triangle subdivision using vertex numbers
righthand rule applied to create outward pointing faces */

    point v1, v2, v3;
    int j;
    if(m>0)
    {
        for(j=0; j<3; j++) v1[j]=a[j]+b[j];
        normal(v1);
        for(j=0; j<3; j++) v2[j]=a[j]+c[j];
        normal(v2);
        for(j=0; j<3; j++) v3[j]=b[j]+c[j];
         normal(v3);
        divide_triangle(a, v1, v2, m-1);
        divide_triangle(c, v2, v3, m-1);
        divide_triangle(b, v3, v1, m-1);
        divide_triangle(v1, v3, v2, m-1);
    }
    else(triangle(a,b,c)); /* draw triangle at end of recursion */
}

void tetrahedron( int m)
{

/* Apply triangle subdivision to faces of tetrahedron */

    divide_triangle(v[0], v[1], v[2], m);
    divide_triangle(v[3], v[2], v[1], m);
    divide_triangle(v[0], v[3], v[1], m);
    divide_triangle(v[0], v[2], v[3], m);
}

void display(void)
{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
    tetrahedron(n);
    glFlush();
}


void myReshape(int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        glOrtho(-1.0, 1.0, -1.0 * (GLfloat) h / (GLfloat) w,
            1.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0);
    else
        glOrtho(-1.0 * (GLfloat) w / (GLfloat) h,
            1.0 * (GLfloat) w / (GLfloat) h, -1.0, 1.0, -10.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
    display();
}


void myinit()
{
    glShadeModel(GL_FLAT); /*enable flat shading */
    glEnable(GL_DEPTH_TEST); /* enable z buffer */

    glClearColor (1.0, 1.0, 1.0, 1.0);
    glColor3f (0.0, 0.0, 0.0);
}


void
main(int argc, char **argv)
{
    if(argc<2)n=4;
    else n=atoi(argv[1]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(500, 500);
    glutCreateWindow("sphere");
    myinit();
    glutReshapeFunc(myReshape);
    glutDisplayFunc(display);
    glutMainLoop();
}
Turn in documented hardcopy of your program at the start of class and email your source before class as well. I'll count off for inadequate documentation.