CS 4465 - Lab (7)
Views

Our goals in this lab are:
• To learn about different views
Preparation
Use the same computer you have used before.  You will complete this lab during the lab hour.

Views
I am sure you have read section 5.1.  If you didn't you will have difficulty with this part of the lab.  You can ask the instructor for a handout on this, read it, and then try to answer.  Classify each of the following as parallel or perspective, and as dimetric, isometric, 1-point, 2-point, or 3-point projections:
 1 2 3 4 5

1. 2-point perspective
2. dimetric parallel
3. 1-point perspective
4. isometric parallel
5. 3-point perspective

We categorize projections as parallel or perspective depending on whether we specify a view direction (with a viewer "infinitely far away") or a fixed view position. In the parallel case, we call the projection orthographic if the projection plane is orthogonal to the view direction, and oblique otherwise. Common architectural orthographic projections are the front, side and plan views. Other orthographic views are called axonometric. The special case in which the three axis directions make the same angle with the projection direction is called isometric. If only two axes make the same angle, the projection is called dimetric. The general case in which no principal face is parallel to the projection plane is called an axonometric orthographic projection (which includes both the dimetric and isometric as special cases).

We classify perspective projections as one-point, two-point, or three-point depending on the number of "vanishing points". In a one-point projection, only one of the principal axes intersects the projection plane. In a 2-point projection, two axes intersect the projection plane. The general case (most likely if a rectangular solid is rotated to a random position) is the 3-point projection in which all principal axes intersect the projection plane.

In OpenGL we can use glOrtho to fix parallel orthographic projection, and glFrustum to determine a perspective projection. (There are alternatives in OpenGL as well.) Both functions should be proceeded by

glMatrixMode(GL_PROJECTION);

This is because any matrix operations in OpenGL will affect either the MODELVIEW or PROJECTION matrices (which ultimately get multiplied to determine the final projection), and it is important to be in the right mode when changing a matrix.

glOrtho and glFrustum each take six parameters specifying the x-, y- and z-ranges. glOrtho just defines a box; the z-coordinates of points within this box are discarded to obtain the projection. glOrtho is different: the first four parameters determine the front rectangle of a frustum (a truncated pyramid) associated with the smaller of the two z-values. The corresponding x- and y-bounds for the back face are larger in proportion to the distance of the back plane from the eye position.

Let's look at a cube from a variety of positions. The cube is blue on front, purple on the right, and green on top. Here's a not-very-interesting head-on view:

Here's the code that generated it:

#include <GL/glut.h>
typedef GLfloat point3[3];

// 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}
};

point3 p2[8]; //a copy of the first cube centered at the origin

void drawPoint(int i){
// Draw point i
glVertex3fv(p2[i]);
}

void drawFace(int i1,int i2,int i3,int i4){
// draw a face of the cube
// use color of first point for entire face
glBegin(GL_POLYGON);
glColor3fv(p[i1]);
drawPoint(i1);
drawPoint(i2);
drawPoint(i3);
drawPoint(i4);
glEnd();
}

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

void myinit(void)
{
int i,j;
for(i=0;i<8;i++)for(j=0;j<3;j++)p2[i][j]=p[i][j]-.5;
/* attributes */
glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
/* set up viewing */
glMatrixMode(GL_PROJECTION);
// The z-range can be crude, just so it includes area of interest
// The x- and y-ranges need to be "tighter"
glOrtho(-1,1,-1,1,-10,10);
}
void display( void )
{
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); /*clear the window */
glTranslatef(0,0,-2); //pull back from the cube
drawCube();
glFlush(); /* clear buffers */
}

void main(int argc, char** argv)
{
/* Standard GLUT initialization */
glutInit(&argc,argv);
glutInitDisplayMode (GLUT_RGB|GLUT_DEPTH); /* default, not needed */
glutInitWindowSize(250,250); /* 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 */
myinit(); /* set attributes */
glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
glutMainLoop(); /* enter event loop */
}

Activity (1)
Cut and paste the above code and run it. then, change the part of the code in red font to:
glTranslatef(0,0,-2);
glRotatef(-45,0,1,0);

we get this image of two faces:

To see three faces we need to add another transformation:

glTranslatef(0,0,-2);
glRotatef(34,1,0,0);
glRotatef(-45,0,1,0);

we get:

Now let's see if we can cook up one-point, two-point and three-point perspective projections. The following program gives the same front view as the first orthographic projection above:

#include <GL/glut.h>
typedef GLfloat point3[3];

GLfloat w=.3; //x- and y- bounds for frustum

// 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}
};

point3 p2[8]; //a copy of the first cube centered at the origin

void drawPoint(int i){
// Draw point i
glVertex3fv(p2[i]);
}

void drawFace(int i1,int i2,int i3,int i4){
// draw a face of the cube
// use color of first point for entire face
glBegin(GL_POLYGON);
glColor3fv(p[i1]);
drawPoint(i1);
drawPoint(i2);
drawPoint(i3);
drawPoint(i4);
glEnd();
}

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

void myinit(void)
{
int i,j;
for(i=0;i<8;i++)for(j=0;j<3;j++)p2[i][j]=p[i][j]-.5;
/* attributes */
glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
/* set up viewing */
glMatrixMode(GL_PROJECTION);
glFrustum(-w,w,-w,w,.4,8);
}
void display( void )
{
glMatrixMode(GL_MODELVIEW);
glTranslatef(0,0,-2);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); /*clear the window */
drawCube();
glFlush(); /* clear buffers */
}

void main(int argc, char** argv)
{
/* Standard GLUT initialization */
glutInit(&argc,argv);
glutInitDisplayMode (GLUT_RGB|GLUT_DEPTH); /* default, not needed */
glutInitWindowSize(250,250); /* 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 */
myinit(); /* set attributes */
glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
glutMainLoop(); /* enter event loop */
}

If we change

glBegin(GL_POLYGON);
glColor3fv(p[i1]);

in drawFace to

glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
glBegin(GL_POLYGON);
glColor3f(0,0,0);

we obtain an image which shows that this is a one-point projection. (Only one set of edges converges to a point).

Now let's move around the corner to get a two point projection:.  To get a two-point view similar to the one shown below, you need to add the following line immediately after the line shown in red font above:

glRotatef(-45,0,1,0);

Finally, let's add one more transformation to obtain a view from above:
glTranslatef(0,0,-2);
glRotatef(34,1,0,0);
glRotatef(-45,0,1,0);

Here's the wire frame:

and here's the full-color version:.  How do we get this?  I am sure you can figure this out by looking at the steps you have gone through so far.

If you want a good source of detailed information in "positioning the camera" in OpenGL, see Chapter 3 of the Red Book.

Activity (2)
In the last lab you found the color of different sides of the cube. Without changing the geometry, using transformations (rotation, translation, or scaling)
only create the following image:

Challenging
Now that you have learned about different views, make the cube rotate around the line that goes through its center parallel to y-axis.