
Roberto Toldo,
<nome.cognome@univr.it >
Hit the space bar for next slide
OpenGL can accept the data (points, lines, polygons, etc.) for a 3D model but must ultimately show the model on a 2D display. The challenge is to show a 2D drawing on the screen which is recognizable as a 3D model. We say that the 3D model is `projected' onto the screen. The computer has a center of projection (or eye), which `sees' the 3D models in the world. We will learn how to control and adjust the characteristics of the eye and the appearance of an object.
First, we'll discuss OpenGL commands that adjust how much the computer's eye can see. We'll focus a narrow and wide view. You might think of the eye as a camera with an amazing zoom lens.
Second, we'll move the camera (or eye) around the world. We'll learn commands to point it in different directions.
Once the camera is set on its tripod and will no longer move, we can transform the 3D models.
Each 3D transformation can be represented by a 4 x 4 matrix. The IRIS Geometry Engines transforms all geometric data (vertices of points, lines, and polygons) by multiplying each vertex by the accumulated matrices.
Imagine yourself with a camera and a versatile lens. You adjust the lens to have a very narrow field of view. You can zoom in on a single leaf on a tree. You can also adjust the lens for a wider field of view. Now you can take a snapshot of the entire tree. With another adjustment, you can shoot a picture of the entire forest.
What you are doing is adjusting the restrictions and capabilities of your vision. You are changing the shape of the portion of the world which your vision can grasp. This portion of the world is technically termed the viewing volume. The line along which you look (or point the camera) generally goes down the center of this viewing volume, and is called the line of sight. We will describe two types of viewing volumes.
First, is a pyramid shape with the `eye' (or center of projection) at the pointed tip of the pyramid. The pyramid shape (or `frustum') represents the portion of the world the eye can see with a perspective projection.
Second, is a simple rectangular box. Any 3D models which lie within the box will be shown with an orthographic parallel projection.
First, we'll examine the more natural example of perspective projection. Perspective is more natural because it simulates how people actually see. The classic example of perspective is standing on a set of railroad tracks and looking down the tracks. The two tracks appear to become closer the further they are from you. Obviously, they don't actually become closer. The diminishing distance between the tracks is an illusion caused by viewing the world with perspective.
Foley, van Dam, et al, call this illusion of depth `perspective foreshortening'. Sizes and distances diminish as one gets further from the center of projection. An object which is very close to the eye will occupy a large amount of the viewing field. An object of the same size that is further away will occupy much less of the field. The more distant object will be projected as much smaller than the nearer object, despite the fact that they are the same size.
Only objects which are inside the viewing volume are displayed. Objects or parts of objects which are too far left, right, up or down to be inside the viewing volume are clipped from the scene.
Clipping does not only take place in two dimensions (left, right, top and bottom), but can also take place in the third dimension. When an object passes further than a certain distant plane (the far clipping plane), from the eye, it disappears. It isn't a gradual thing at all. On one side of the clipping plane, lines are drawn. As soon as they pierce the plane, they're gone.
There is also a corresponding near clipping plane. When objects get closer to the center of projection than the near clipping plane, they disappear. This means that the viewing volume is actually a truncated, not pointed, pyramid. In textbooks, the near and far clipping planes are often termed the hither and yon planes.
A parallel projection is different from a perspective projection. Unlike perspective, parallel projection does not have a familiar analogy with human vision to which it can be compared. The key difference is when viewing with perspective, an object that is far away from the near clipping plane (and thus, the center of projection), it appears small. If the object is moved towards the near clipping plane, it will appear larger. If the same object is viewed with a parallel projection, it will not change size at all. This effect is, in part, because the viewing volumes for perspective and parallel projections are completely different shapes. For a parallel projection, the viewing volume is a rectangular box, not the truncated pyramid used for perspective.
With perspective, the viewing field becomes larger as distance from the center of projection increases. With parallel projection, the size of the viewing field stays constant. No matter how close an object is to the front or back of the parallel projection viewing volume, the object will occupy the same percentage of the viewing field. In a practical sense, this means that parallel projections preserve size and parallelism of the objects in the scene. This is especially useful for drafting applications when users want sizes and parallelism to be exactly as they appear on the screen.
A parallel projection is orthographic if the direction of projection (the way the eye is looking, flipped 180o) is normal to the projection plane. For our purposes, an orthographic parallel projection is one in which the line of sight is perpendicular to the near and far clipping planes.
gluPerspective, glFrustum, glOrtho, and gluOrtho2 are four OpenGL calls which set up projection transformations. They differ in the types of projections they set up, and in the way the viewing volumes are specified.
gluPerspective and glFrustum both set up perspective projections.
glFrustum allows you to set up a non-symmetric viewing volume. The first four parameters left, right, bottom, and top are the dimensions of the near clipping plane. The last two, near and far, are the distances from the eye to the near and far clipping planes, respectively. Although you can set up a symmetric viewing volume with glFrustum, you can also set up a non-symmetric one.
gluPerspective is similar to glFrustum, but takes slightly different arguments, and creates a viewing volume that is symmetric about the line of sight in x and y. The first argument, fovy, is the field of view in the y dimension. It is expressed as an angle in degrees, and specifies the angle the viewing volume makes in y. The second, aspect, is the aspect ratio between the field of view in x and y. Multiplying fovy by aspect gives you the field of view in x. As above, near and far, are the distances from the eye to the near and far clipping planes. near must be positive and less than far.
glOrtho and gluOrtho2 set up orthographic projections. glOrtho takes six parameters: the left, right, bottom, top, near, and far edges of the orthographic viewing volume. gluOrtho2 is a special case of glOrtho. The first four parameters are the same, but the near and far clipping planes are set to -1.0 and 1.0 respectively.
If someone asked you to create a two-dimensional graph, you would draw two perpendicular axes. The positive x axis would extend to the right; the positive y axis, upwards. You are instinctively familiar with this Cartesian coordinate system.

With three dimensions, you must be concerned with the positive z axis, the third dimension. The positive z axis could be on either side of the x,y plane. Both orientations of the z axis are useful in different situations.
When the positive z axis is `behind' the x,y plane, the coordinate system is left-handed. Left-handedness comes from a method of using the left hand as a memory aid. To use this memory aid, hold your left hand flat. Extend your thumb and index finger until they are perpendicular to one another. Your thumb represents the positive x axis; your index finger, the y axis. Now your palm faces in the direction of the positive z axis.

The right-handed coordinate system is the opposite of the left-handed. The positive z axis is `in front of' the x,y plane.

By convention, the left and right-handed coordinate systems are used in different situations. Projection transformations (glOrtho, gluOrtho2, gluPerspective and glFrustum) are left-handed. In OpenGL, projection transformations are the only significant operations which take place in a left-handed coordinate system.
Viewing transformations, modeling transformations, and any drawing commands (for example to draw polygons) are located in the right-handed coordinate system. We will describe viewing and modeling transformations in upcoming sections.
Let's return to our camera analogy and concern ourselves with the scene which we will photograph. Where will we position the 3D objects for our photo? How will we move those objects?
The solution lies with another set of operations, modeling transformations. Modeling transformations affect the location, orientation, and size of the 3D geometric models. (Modeling transformations are alternatively called object transformations.)
Although people often talk about modeling transformations as though they move the object, it is more convenient to think of modeling transformations as moving an object's coordinate system. Any object that you create has an origin, an x, y, and z axis. If you draw your object without doing any modeling transformations, the object's origin and the world origin are at the same place. The object's axes coincide with the world axes. If you perform modeling transformations before drawing an object, it is as if you have transformed the object's origin and axes. When you finally draw the object, it will be drawn with respect to its new, moved coordinate system.
Let us examine modeling transformations one at a time. We'll look at each transformation independently: rotate, scale and translate. In the following section we will discuss how to composite these simple transformations into more complex transformations.
Rotating an object is a natural motion done by spinning it around an axis. For example, a gymnast can rotate around a raised bar. That horizontal bar is an x axis. The rotation transformation preserves the size of an object. A rotated object does not get larger, smaller, or distorted.
The two OpenGL commands for the rotation transformation are glRotatef and glRotated. Both commands take four arguments: an angle and a vector describing the axis of rotation. The angle is in degrees of rotation. A positive rotation angle is a counterclockwise rotation, as you look down the positive rotation axis to the origin. The glRotatef command expects its arguments to be of type GLfloat. The glRotated command expects its arguments to be of type GLdouble.
At the completion of this module, you will be able to
#ifndef _DEBUG
printf("%f",value);
#endif _DEBUG
assert( this );
void sort_array(int* const myarray)
{
assert( myarray );
assert( sizeof(myarray) > sizeof(int*) );
for( unsigned int x = 0; x < sizeof(myarray)-1; x++ )
if( myarray[x] < myarray[y] ) swap(myarray[x], myarray[y]);
}
The part of a window that you can render into is called the viewport.

Notes:
The dashed line represents the initial viewport when the window is created.
You can change the size of the viewport using glViewport().
GLvoid glViewport( GLint x, GLint y,
GLsizei width, GLsizei height )

Notes:
Viewports are always rectangular.
Window coordinates are in pixel units. The lower left corner of the viewport is located relative to the lower left corner of the window.
Use glutGet() to retrieve the width and height of the window.
int width = glutGet( GLUT_WINDOW_WIDTH );
int height = glutGet( GLUT_WINDOW_HEIGHT );


Notes:
After the modeling, viewing and projection transformations have been applied to the original vertex coordinates (world coordinates), the values are divided by the w coordinate to get normalized device coordinates.
Lastly, the normalized device coordinates are transformed to window coordinates by applying the viewport transformation.
The square is mapped to a rectangle, because the viewport is wider than it is high. This accounts for the stretching effect on the circle.
/* viewport.c - Demonstrates how to separate a window into two drawing
* areas using glViewport(). It creates two viewports that divide
* the window in half. In each half, a rectangle the size of the
* viewing volume is rendered. In one half it also renders a square
* grid. Note how the mapping of the viewing volume to the viewport
* affects the shape of the grid.
*
* SPACE key - toggle which viewport the grid is drawn in
* Escape Key - exit program
*/
#include <GL/glut.h> /* includes gl.h, glu.h */
#include <stdio.h>
/* Function Prototypes */
GLvoid initgfx( GLvoid );
GLvoid keyboard( GLubyte, GLint, GLint );
GLvoid drawScene( GLvoid );
void printHelp( char * );
/* Global Definitions */
#define KEY_ESC 27 /* ascii value for the escape key */
/* Global Variables */
static GLboolean grid_in_bottom = GL_TRUE;
GLvoid
main( int argc, char *argv[] )
{
GLsizei width, height;
glutInit( &argc, argv );
width = glutGet( GLUT_SCREEN_WIDTH );
height = glutGet( GLUT_SCREEN_HEIGHT );
glutInitWindowPosition( width / 4, height / 4 );
glutInitWindowSize( width / 2, height / 2 );
glutInitDisplayMode( GLUT_RGBA );
glutCreateWindow( argv[0] );
initgfx();
glutKeyboardFunc( keyboard );
glutDisplayFunc( drawScene );
printHelp( argv[0] );
glMatrixMode( GL_PROJECTION );
glOrtho( -2.0, 2.0, -2.0, 2.0, -1.0, 1.0 );
glMatrixMode( GL_MODELVIEW );
glutMainLoop();
}
void
printHelp( char *progname )
{
fprintf(stdout, "\n%s - demonstrates how the viewport controls \n"
"what portion of the window will be rendered into\n\n"
"SPACE key - toggle which viewport the grid is drawn in\n"
"Escape Key - exit the program\n\n",
progname);
}
GLvoid
initgfx( GLvoid )
{
glClearColor( 1.0, 0.0, 1.0, 1.0 ); /* magenta */
glShadeModel( GL_FLAT );
}
GLvoid
keyboard( GLubyte key, GLint x, GLint y )
{
switch (key) {
case ' ': /* toggle grid location */
grid_in_bottom = !grid_in_bottom;
glutPostRedisplay();
break;
case KEY_ESC: /* Exit when the Escape key is pressed */
exit(0);
}
}
/* Draw a square grid */
GLvoid
drawSquareGrid( GLvoid )
{
GLfloat x, y;
glBegin( GL_LINES );
for ( x = -1.0; x < 1.1; x += 0.1 ) {
glVertex2f( x, -1.0 );
glVertex2f( x, 1.0 );
}
for ( y = -1.0; y < 1.1; y += 0.1 ) {
glVertex2f( -1.0, y );
glVertex2f( 1.0, y );
}
glEnd();
}
GLvoid
drawScene( GLvoid )
{
GLsizei width, height;
static GLfloat blueColor[] = { 0.0, 0.0, 1.0 };
static GLfloat greenColor[] = { 0.0, 1.0, 0.0 };
glClear( GL_COLOR_BUFFER_BIT );
/* Get the current window size */
width = glutGet(GLUT_WINDOW_WIDTH);
height = glutGet(GLUT_WINDOW_HEIGHT);
/* Create the first viewport - the bottom half of the screen */
glViewport( 0, 0, width, height / 2.0 );
/* Draw a blue rectangle that fills the entire viewing volume */
glColor3fv( blueColor );
glRectf( -2.0, -2.0, 2.0, 2.0 );
if (grid_in_bottom) {
glColor3f( 1.0, 1.0, 1.0 );
drawSquareGrid();
}
/* Create the second viewport - the top half of the screen */
glViewport( 0, height / 2.0, width, height / 2.0 );
/* Draw a green rectangle that fills the entire viewing volume */
glColor3fv( greenColor );
glRectf( -2.0, -2.0, 2.0, 2.0 );
if (!grid_in_bottom) {
glColor3f( 0.0, 0.0, 0.0 );
drawSquareGrid();
}
glFlush();
}
Notes:
This program creates a square world and draws two squares in it, one green and one blue. Each square fills the entire world.
However, because it restricts the viewport to cover only half of the world, it appears as though it is drawing two rectangles, each of which only covers half the world.

This program also renders a square grid into one of the viewports. Press the <SPACE> to toggle which viewport the grid is rendered into.
Even though the grid is square, it is wider than it is tall because the viewport aspect ratio is two to one.
Every rectangular area has an aspect ratio.
glutInitWindowSize( width, height )
glOrtho( left, right, bottom, top, nearClip, farClip )
glViewport( x, y, width, height )
Notes:
The viewing volume and viewport need to have the same aspect ratio to avoid distortion in your scene.
void glutReshapeFunc( void (*func)(int width,
int height) )
void
reshape( int width, int height )
{
/* update viewport */
/* reset viewing volume */
}
Notes:
The program never explicitly calls this function. It is called by the glut library when the window is reshaped.
If no reshape function is specified, a default reshape function will be called. This function simply calls glViewport(0, 0, width, height).
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( ... );
glMatrixMode( GL_MODELVIEW );
Notes:
Use this in your reshape routine to set the aspect ratio of the viewing volume, so it matches the aspect ratio of the viewport.
/* aspect.c - draw a grid, using glutReshapeFunc() to handle
* window resizes (taking into account the aspect ratio).
*
* Escape Key - exit program
*/
#include <GL/glut.h> /* includes gl.h, glu.h */
#include <stdio.h>
/* Function Prototypes */
GLvoid initgfx( GLvoid );
GLvoid keyboard( GLubyte, GLint, GLint );
GLvoid drawScene( GLvoid );
GLvoid reshape( GLsizei, GLsizei );
void printHelp( char * );
/* Global Definitions */
#define KEY_ESC 27 /* ascii value for the escape key */
GLvoid
main( int argc, char *argv[] )
{
GLsizei width, height;
glutInit( &argc, argv );
width = glutGet( GLUT_SCREEN_WIDTH );
height = glutGet( GLUT_SCREEN_HEIGHT );
glutInitWindowPosition( width / 4, height / 4 );
glutInitWindowSize( width / 2, height / 2 );
glutInitDisplayMode( GLUT_RGBA );
glutCreateWindow( argv[0] );
initgfx();
glutReshapeFunc( reshape );
glutKeyboardFunc( keyboard );
glutDisplayFunc( drawScene );
printHelp( argv[0] );
glutMainLoop();
}
void
printHelp( char *progname )
{
fprintf(stdout, "\n%s - demonstrates one way to make the aspect "
"ratio of the viewport\nand the viewing volume match\n\n"
"Escape Key - exit the program\n\n",
progname);
}
GLvoid
initgfx( GLvoid )
{
glClearColor( 0.0, 0.0, 1.0, 1.0 );
glShadeModel( GL_FLAT );
}
GLvoid
reshape( GLsizei width, GLsizei height )
{
GLdouble aspect, left, right, bottom, top;
glViewport( 0, 0, width, height );
/* compute aspect ratio */
aspect = (GLdouble) width / (GLdouble) height;
/* make sure the window goes from [-2.0, 2.0] in the
smallest dimension */
if ( aspect < 1.0 ) {
left = -2.0;
right = 2.0;
bottom = -2.0 * ( 1.0 / aspect );
top = 2.0 * ( 1.0 / aspect );
} else {
left = -2.0 * aspect;
right = 2.0 * aspect;
bottom = -2.0;
top = 2.0;
}
glMatrixMode( GL_PROJECTION );
/* Reset world coordinates first ... */
glLoadIdentity();
/* Then set them to what we want based on the new aspect ratio */
glOrtho( left, right, bottom, top, -1.0, 1.0 );
glMatrixMode( GL_MODELVIEW );
}
GLvoid
keyboard( GLubyte key, GLint x, GLint y )
{
switch (key) {
case KEY_ESC: /* Exit when the Escape key is pressed */
exit(0);
}
}
GLvoid
drawScene( GLvoid )
{
GLfloat x, y;
static GLfloat whiteColor[] = { 1.0, 1.0, 1.0 };
glClear( GL_COLOR_BUFFER_BIT );
glColor3fv( whiteColor );
glBegin( GL_LINES );
for ( x = -1.0; x < 1.1; x += 0.1 ) {
glVertex2f( x, -1.0 );
glVertex2f( x, 1.0 );
}
for ( y = -1.0; y < 1.1; y += 0.1 ) {
glVertex2f( -1.0, y );
glVertex2f( 1.0, y );
}
glEnd();
glFlush();
}
Notes:
This program draws a square grid in a window, even if the window is not square.
The call to glutReshapeFunc() sets up the reshape handler. This function is called when the window is resized. It adjusts the aspect ratio of the world so that the grid is always square.
Notice the code in reshape(). First it sets up the viewport to be the same size as the newly resized window. Then it calculates the aspect ratio, and adjusts the left, right, top, and bottom parameters so the aspect ratio will be one. After switching to the projection matrix stack, it calls glLoadIdentity() to clear the current viewing volume, and glOrtho() to set the new viewing volume.
Notes:
* Indicates an optional laboratory exercise.
int glutGet( GLUT_WINDOW_WIDTH ) int glutGet( GLUT_WINDOW_HEIGHT )
Returns the width or height of the current window.
void glViewport( GLint x, GLint y, GLsizei width, GLsizei height )
Specifies the affine transformation of x and y from
normalized device coordinates to window coordinates.
void glutReshapeFunc( void (*reshape)(int width, int height) )
Specifies the function to be called when the window is resized. It is used to update the viewport and viewing volume as the window changes size or aspect ratio.
Using your knowledge about viewports and stack matrices, you have to add a sort of control panel in the bottom of the window. In this control panel you have to:
chmod +x melite3bif you want a successful execution of the program.