4/14/04

We started with Quiz 6:

Consider the unit cube with vertices (0,0,0), (1,0,0), (1,0,1), (0,0,1), (0,1,0), (1,1,0), (1,1,1), (0,1,1).

(a) What normal should be specified on the face containing the first 4 of these points if the cube is to be displayed with sharp edges?

These four points all have y-coordinate 0, so this is the bottom of the cube. The normal is <0,-1,0>.

(b) How would you calculate normals if you want the 6 faces of the cube to blend smoothly into one another? Give a specific normal as an example.

Give a different normal at each vertex, obtained by averaging the normals of three faces meeting at that vertex. For example, at (1,1,1) the normal vector would point in the direction <1,1,1>.

The idea was to understand the role of normal specification in drawing polyhedrons. If you specify a normal only once for a polygon, the polygon will be uniformly shaded. If you specify a normal for each vertex, obtained for example by averaging the normals of all polygons meeting at that vertex, the shading will blend along the edges. Here are images of a cube with (1) a single normal specified for each face, and (2) normals for each vertex, averaging the normals of the three faces meeting at the vertex:

Here are the programs which generated the two images. Note the use of the gluPerspective function -- it's a replacement for the glFrustum function which easier to use. You specify the camera's angle of vision rather than worrying about ratios of the near distance to the dimensions of the x-y rectangle being viewed. Try experimenting with the angle! Larger values give wide-angle lenses; smaller values give telephoto lenses.

Program 1:

#include <GL/glut.h>
typedef GLfloat point3[3];
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}
};

point3 n[6]={ // normals for each face
{0,-1,0},
{0,0,1},
{1,0,0},
{0,0,-1},
{0,1,0},
{-1,0,0}
};
void drawPoint(int i){
glVertex3fv(p[i]);
}
void drawFace(int i1,int i2,int i3,int i4,int k){
glBegin(GL_POLYGON);
glNormal3fv(n[k]); // use normal for this face
drawPoint(i1);
drawPoint(i2);
drawPoint(i3);
drawPoint(i4);
glEnd();
}

void drawCube(){
drawFace(0,3,2,1,0);
drawFace(1,2,6,5,1);
drawFace(2,3,7,6,2);
drawFace(3,0,4,7,3);
drawFace(4,5,6,7,4);
drawFace(5,4,0,1,5);
}

void display( void )
{
glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); /*clear the window */
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(1.5,2,4,.5,.5,.5,0,1,0);
drawCube();
glFlush(); /* clear buffers */
}

void main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
glutInitWindowSize(500, 500);
glutCreateWindow("Cube");
glutDisplayFunc(display);

GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 50.0 };
GLfloat light_position[] = { 1.0, 2.0, 3.0};
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
GLfloat mat_amb_diff_red[] = { 1, 0, 0, 1.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,mat_amb_diff_red);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST); /* enable z buffer */
glEnable(GL_NORMALIZE);
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, /* Z far */ 100);
glMatrixMode(GL_MODELVIEW);
glutMainLoop();
}

Program 2:

#include <GL/glut.h>
typedef GLfloat point3[3];
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){
glVertex3fv(p[i]);
}
void makeNormal(int i){
// make each vertex normal point from middle of cube to itself
double x,y,z;
x=p[i][0]-.5;
y=p[i][1]-.5;
z=p[i][2]-.5;
glNormal3f(x,y,z);
drawPoint(i);
}

void drawFace(int i1,int i2,int i3,int i4,int k){
glBegin(GL_POLYGON);
makeNormal(i1);
makeNormal(i2);
makeNormal(i3);
makeNormal(i4);
glEnd();
}

void drawCube(){
drawFace(0,3,2,1,0);
drawFace(1,2,6,5,1);
drawFace(2,3,7,6,2);
drawFace(3,0,4,7,3);
drawFace(4,5,6,7,4);
drawFace(5,4,0,1,5);
}

void display( void )
{
glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); /*clear the window */
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(1.5,2,4,.5,.5,.5,0,1,0);
drawCube();
glFlush(); /* clear buffers */
}

void main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
glutInitWindowSize(500, 500);
glutCreateWindow("Cube");
glutDisplayFunc(display);

GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 50.0 };
GLfloat light_position[] = { 1.0, 2.0, 3.0};
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
GLfloat mat_amb_diff_red[] = { 1, 0, 0, 1.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,mat_amb_diff_red);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST); /* enable z buffer */
glEnable(GL_NORMALIZE);
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, /* Z far */ 100);
glMatrixMode(GL_MODELVIEW);
glutMainLoop();
}