Classify each of the following as parallel or perspective, and as dimetric, isometric, 1point, 2point, or 3point projections:
1. 

2. 

3. 

4. 

5. 
The answers are:
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 pespective projections as onepoint, twopoint, or threepoint depending on the number of "vanishing points". In a onepoint projection, only one of the principal axes intersects the projection plane. In a 2point projection, two axes intersect the projection plane. The general case (most likely if a rectangular solid is rotated to a random position) is the 3point 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);
glLoadIdentity();
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 zranges. glOrtho just defines a box; the zcoordinates 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 zvalues. The corresponding x and ybounds 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 notveryinteresting headon 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);
glLoadIdentity();
// The zrange can be crude, just so it includes area of interest
// The x and yranges need to be "tighter"
glOrtho(1,1,1,1,10,10);
}
void display( void )
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BITGL_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_RGBGLUT_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 hiddensurfaceremoval */
glutMainLoop(); /* enter event loop */
}
If I change the boldface code 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 onepoint, twopoint and threepoint 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);
glLoadIdentity();
glFrustum(w,w,w,w,.4,8);
}
void display( void )
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0,0,2);
glClear(GL_COLOR_BUFFER_BITGL_DEPTH_BUFFER_BIT); /*clear the window */
drawCube();
glFlush(); /* clear buffers */
}
void main(int argc, char** argv)
{
/* Standard GLUT initialization */
glutInit(&argc,argv);
glutInitDisplayMode (GLUT_RGBGLUT_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 hiddensurfaceremoval */
glutMainLoop(); /* enter event loop */
}
If we change
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 onepoint projection. (Only one set of edges converges to a point).
Now let's move around the corner to get a two point projection:
Here's the code which replaces the code in bold:
glTranslatef(0,0,2);
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 fullcolor version:
If you want a good source of detailed information in "positioning the camera" in OpenGL, see Chapter 3 of the Red Book.
Please read Chapter 5 through section 5.4.