Lab(9) - Graphics

Objectives:

    To Learn about lighting and material properties

General summary on how to add light to a scene:

These are the steps required to add lighting to your scene (RED-Book):

    Define normal vectors for each vertex of all the objects. These normals determine the orientation of the object relative to the light sources.

    Create, select, and position one or more light sources.

    Create and select a lighting model, which defines the level of global ambient light and the effective location of the viewpoint (for the purposes of lighting calculations).

    Define material properties for the objects in the scene.

We need vertex normals (which are required for the smooth shading used by OpenGL). As I mentioned in class, we could take the cross product of two vectors in the plane of a polygon and use this for the normal at all the vertices of the polygon. However, if we're using a fixed light direction this will give exactly the same lighting at each interior point. We could instead come up with different normals at all the vertices. The way to estimate these is to average the normals of all polygons (usually triangles) which meet at a given vertex.  

Let's look at a tetrahedron with vertices at (0,0,0), (1,0,0), (0,1,0), and (0,0,1) again. What would the normal be at the origin? One way to compute the normal is to find two vectors and compute their cross products, right?  

So, for the three faces that meet (left, right, and bottom) the normals are vectors:

box







n(left) = - i + 0 j + 0 k
n(right) = 0 i + 0 j - k
n(bottom) = 0 i - j + 0 k






 <-1,0,0>, <0,-1,0> and <0,0,-1>, so the normal would be in the direction <-1,-1,-1>. (We'd divide the three components by sqrt(3) if we want the normal 'normalized'). Try finding the normals at the other three vertices. Then try lighting the tetrahedron using the four normals you've estimated. The result should be a rounded tetrahedron, much less stark than that obtained with uniform lighting on each face. There are other ways to get surface normals. In the case of a mathematically defined surface, such as a sphere, we can calculate the precise normal at each point. In third semester calculus you learn about finding the "gradient vector" to get the normal this way. If we have a surface z = f(x,y), then differentiating the function with respect to x gets the tangent slope in the x direction, and differentiating with respect to y gets the tangent slope in the y direction. The cross product of the two resulting tangent vectors obtains the normal vector. 

There are a few predefined shapes -- spheres, cylinders, toruses -- available in OpenGL. Here's a program which rotates a light in a circle at a fixed height above a torus:

/* A shiny torus illuminated by a light source rotating
overhead. */
#include <math.h>
#include <GL/glut.h>
double t = 0;
const double PI2= 2*3.14159265; // 2 PI

// This is global so that it can be changed in the idle function
GLfloat light_position[] = { 2.0, 4.0, 0};

void display()
{
int i;
glClearColor(1,1,1,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,2,4,0,0,0,0,1,0);
glRotatef(90,1,0,0); // flip the torus on its side
// Torus inner radius .5, outer radius 1
// 20 latitudes and 20 longitudes, sort of
glutSolidTorus(.5,1,20,20);
glFlush();
glutSwapBuffers();
}

void myinit()
{

GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 50.0 };
GLfloat mat_amb_diff[] = { 0.1, 0.5, 0.8, 1.0 };
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
mat_amb_diff);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST); /* enable z buffer */
glMatrixMode(GL_PROJECTION);
// gluPerspective is an alternative to glFrustum in which
// the 'lens' is specified by angle and aspect ratio rather
// than frustum coordinates
// The near and far planes have the same meaning as before.
gluPerspective( /* field of view in degree */ 40.0,
/* aspect ratio */ 1.0,
/* Z near */ 1.0, /* Z far */ 10);
glMatrixMode(GL_MODELVIEW);
}

void idle(){
light_position[0]=2*cos(t);
light_position[2]=2*sin(t);
t+=.1;
if(t>PI2)t-=PI2;
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glutPostRedisplay();
}

int main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitWindowSize(800,600);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB|GLUT_DEPTH);
glutInitWindowPosition(100,100);
glutCreateWindow("Cubes");
glutDisplayFunc(display);
glutIdleFunc(idle);
myinit();
glutMainLoop();
return 0;
}

Here's a typical snapshot:

torus

Our specular light is all white -- if we change it to red, then our blue-green torus will reflect very little of it. The animation in the idle call back changes the position of the light. In OpenGL, you can define several light sources -- up to 8. The shininess of the material is 50 -- this translate roughly to the exponent of the cosine of the angle between the viewer and the ray reflected from the light source. If we reduce this number, the surfaces appears softer, more like plastic than metal.

Lab Activity (1)
Try the above code with four different value sets for values in the following line:

GLfloat light_position[] = { 2.0, 4.0, 0}; 

        1) Light at the center (0, 0, 0),
        2) Keep only the x component and set the rest to 0,
        3) Keep only the y component and set the rest to 0, and
        4) Set the z component to any value that creates a desirable image and set the rest to 0.

Based on your observations you have made by running the above 4 cases, can you make a conclusion on the effect of light
source position on the appearance of the object.

Lab Activity (2)
Modify the code such that the above torus appears in red.  A quick way to do this is to make a change in the:
            GLfloat mat_amb_diff[] = { 0.1, 0.5, 0.8, 1.0 };

If you have done it a different way, let me know.

Lab Activity (3)
Change the color back to blue.  You should try fiddling with the parameters in this program to get a feel for what they do.  Here is what you will create next.  To create this shape, you will add a new torus that is smaller than the one above and will rotate it 90 degree.  You need to play with the dimension a bit and find out which axis to rotate around.


img2

Lab Activity (4)
Here is what you create next.  To create this one, you will use two different material for the two toruses that you had created in the previous section.

two-color

You need to change the program so that by changing an option, you can create the following two views:
    1) Top view of this object, and
    2) Side view of your choice, left or right.
 
Keep all three options in the program such that by setting a flag value, one can get one of these three views. Submit an electronic copy of the program with all options in it.  Leave a comment at the location of the flag that changes the views, so I can test your program.  You may use different functions for each views, as you wish.  Submit a hard copy of the program and snap shots of the three views.

You need to mail me this program.  Please make sure your name appears at  the top.  Please also make sure to send the program as an attachment and have Torus on the subject line.

Challenging
Make the entire thing rotate around the y axis like a UFO.