
Roberto Toldo,
<nome.cognome@univr.it >
Hit the space bar for next slide
Previous sections described how objects in a 3D world can be viewed. Given a viewing volume, these objects were clipped and projected onto a projection plane. The contents of the projection plane are the `snapshot' of the 3D world. This section describes the transition from the projection plane to the 2D display screen.
The default viewport is usually all you need. The lower left corner of the viewport defaults to the lower left corner of the window, which is (0,0) in window coordinates. The upper right corner is determined by the size of the window. Therefore, when you open a window, the initial viewport is
glViewport(0, 0, width, height);
where width and height match the size of the window.
Suppose you want to do something fancier within a window. Using the camera analogy again, suppose you put a certain lens on your camera (your projection transformation). Then, you take a picture and develop the film to make slides. A slide is a projection plane, a `snapshot' of the 3D world.
Now, you use a slide projector to display the slide on a wall. You can think of the wall as being analogous to your display screen. If you consider the wall to be your display screen, then the area of the wall which your slide covers is its viewport. By rolling the projector closer to, or further away from, the wall you can reduce or enlarge the display of the slide. This reduction and enlargement is analogous to changing the viewport.
More technically stated, the area within a window where an image is displayed is the viewport. The location of the viewport is specified by window coordinates. The left, right, bottom and top clipping borders of the projection plane are mapped to the corresponding boundaries of the viewport.
Ideally, the aspect ratio of the projection plane is the same as the aspect ratio for the viewport. In this ideal case, the mapping between projection plane and viewport is a simple reduction or enlargement. However, if the aspect ratios of projection plane and viewport are different, there will be distortions. For example, if the viewport is taller and/or thinner than the projection plane, the height of the displayed object will exaggerated. If the viewport is shorter and/or wider than the projection plane, the displayed object will extend its width.
At the completion of this lecture, you will be able to
The order in which modeling transformations are executed is important.
For example
glTranslatef( 1.0, 0.0, 0.0 );
glRotatef( 60.0, 0.0, 0.0, 1.0 );
is not the same as
glRotatef( 60.0, 0.0, 0.0, 1.0 );
glTranslatef( 1.0, 0.0, 0.0 );
/* order.c - illustrate what happens when the order
* of the modeling transformations is
*
* glTranslate( ... );
* glRotate( ... );
* versus
* glRotate( ... );
* glTranslate( ... );
*
* <o> key - toggle order of transformations
* 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 rotateFirst = GL_TRUE;
void
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) - 4, 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 the effect of transformation order\n\n"
"<o> key - toggle order of transformations\n"
"Escape Key - exit the program\n\n",
progname);
fprintf(stdout, "order is Rotate-Translate\n");
}
GLvoid
initgfx( GLvoid )
{
glClearColor( 0.0, 0.0, 1.0, 1.0 );
glShadeModel( GL_FLAT );
}
GLvoid
keyboard( GLubyte key, GLint x, GLint y )
{
switch (key) {
case 'o': /* toggle transformation order */
rotateFirst = !rotateFirst;
fprintf(stdout, "order is %s\n",
(rotateFirst?"Rotate-Translate":"Translate-Rotate"));
glutPostRedisplay();
break;
case KEY_ESC: /* Exit whenever the Escape key is pressed */
exit(0);
}
}
GLvoid
drawScene( GLvoid )
{
glClear( GL_COLOR_BUFFER_BIT );
glPushMatrix();
if ( rotateFirst ) {
/* Do a rotation first, then a translation */
glRotatef( 60.0, 0.0, 0.0, 1.0 );
glTranslatef( 1.0, 0.0, 0.0 );
} else {
/* Do a translation first, then a rotation */
glTranslatef( 1.0, 0.0, 0.0 );
glRotatef( 60.0, 0.0, 0.0, 1.0 );
}
Checkerboard();
/* Draw X-Y axis -- X is red, Y is green */
XYaxes();
glPopMatrix();
glFlush();
}
Notes:
This program renders a checkerboard under the effect of a translation and a rotation. Press the <o> key to toggle the order of the transformations.
glTranslatef( 4.0, 2.0, 0.0 ); glRotatef( 90.0, 0.0, 0.0, 1.0 ); glVertex3f( 1.0, 2.0, 3.0 );

Notes:
In many cases, the order will be

glPushMatrix(); |
![]() |
glTranslatef( 4.0, 2.0, 0.0 ); |
![]() |
glScalef( 1.0, 0.5, 1.0 ); |
![]() |
| glRotatef( 45.0, 0.0, 0.0, 1.0 ); | ![]() |
| draw_unit_square_box(); | ![]() |
| glPopMatrix(); | ![]() |
Draw two boxes to represent the upper and lower segments of a robot arm.

Step 1: Move to the center of the upper arm
Step 2: Draw box
Step 3: Move to the elbow
Step 4: Rotate 45 degrees about the elbow
Step 5: Move to the center of the lower arm
Step 6: Draw box
Notes:
Each box is drawn centered around the current origin.
/* robot_arm.c - draw a robot arm by composing modeling
* transformations
*
* 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 */
void
main( int argc, char *argv[] )
{
GLsizei width, height;
glutInit( &argc, argv );
width = glutGet( GLUT_SCREEN_WIDTH );
height = glutGet( GLUT_SCREEN_HEIGHT );
glutInitWindowPosition( 0, height / 4 );
glutInitWindowSize( (width / 2) - 4, height / 2 );
glutInitDisplayMode( GLUT_RGBA );
glutCreateWindow( argv[0] );
initgfx();
glutKeyboardFunc( keyboard );
glutDisplayFunc( drawScene );
printHelp( argv[0] );
glMatrixMode( GL_PROJECTION );
gluPerspective( 45.0, (GLdouble) width/(GLdouble)height,1.0,20.0 );
glMatrixMode( GL_MODELVIEW );
glutMainLoop();
}
void
printHelp( char *progname )
{
fprintf(stdout, "\n%s - renders a robot arm\n\n"
"Escape Key - exit the program\n\n",
progname);
}
GLvoid
initgfx( GLvoid )
{
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glShadeModel( GL_FLAT );
}
GLvoid
keyboard( GLubyte key, GLint x, GLint y )
{
switch (key) {
case KEY_ESC: /* Exit whenever the Escape key is pressed */
exit(0);
}
}
GLvoid
drawScene( GLvoid )
{
static GLfloat upperArmColor[] = { 0.5, 0.5, 0.8 };
static GLfloat lowerArmColor[] = { 0.5, 0.8, 0.5 };
glClear( GL_COLOR_BUFFER_BIT );
glPushMatrix();
/* translate into the viewing volume */
glTranslatef( 0.0, 0.0, -8.0 );
XYaxes();
glPushAttrib( GL_LINE_BIT );
glLineWidth( 2.0 );
/* Draw the upper arm with the shoulder
* on the Z axis */
/* Step 1: move to the center of the upper arm */
glTranslatef( 1.0, 0.0, 0.0 );
/* Step 2: draw the upper arm */
glColor3fv( upperArmColor );
WireBox( 2.0, 0.4, 1.0 );
/* Draw the lower arm at the end of the upper arm and
* rotate it 45 degrees */
/* Step 3: move to the elbow */
glTranslatef( 1.0, 0.0, 0.0 );
/* Step 4: rotate the lower arm 45 degrees */
glRotatef( 45.0, 0.0, 0.0, 1.0 );
/* Step 5: move to the center of the lower arm */
glTranslatef( 1.0, 0.0, 0.0 );
/* Step 6: draw the lower arm */
glColor3fv( lowerArmColor );
WireBox( 2.0, 0.4, 1.0 );
glPopAttrib();
glPopMatrix();
glFlush();
}
Notes:
This program creates a robot arm using two boxes.
Because the box is drawn centered at the current origin, we need to translate half of a box width to get the edge of the box on the z axis.
After drawing the upper arm, we translate to the elbow and rotate 45 degrees before drawing the lower arm.
Once again, we have to translate half of a box width in order to draw the lower arm so that its edge meets at the elbow.
Independent models undergo independent transformations.

Notes:
Push/pop is used to isolate the rest of the program from the effects of a set of transformations.
Transformations accumulate.

Notes:
First, the coordinate system is rotated and a tetrahedron is drawn. Then, because transformations accumulate, the beam is translated in the newly rotated coordinate system.
Each model is affected by separate transformations.

Notes:
First, the coordinate system is rotated and a tetrahedron is drawn. Then the previous matrix is restored, and the beam is translated relative to the original coordinate system.

Step 1: Move to the center of the upper arm
Step 2: Draw box
Step 3: Move to the elbow
Step 4: Rotate 45 degrees about the elbow
Step 5: Move to the center of the lower arm
Step 6: Draw box
Step 7: How do you position the third arm?
glMatrixMode( GL_PROJECTION ) |
![]() |
gluPerspective(45.0,1.0,1.0,20.0) |
![]() |
glMatrixMode( GL_MODELVIEW ) |
![]() |
glPushMatrix() |
![]() |
glTranslatef( 0.0, 0.0, -8.0 ) |
![]() |
glTranslatef( 1.0, 0.0, 0.0 ) /* Draw the upper arm */ WireBox( 2.0, 0.4, 1.0 ); |
![]() |
glTranslatef( 1.0, 0.0, 0.0 ) |
![]() |
glPushMatrix(); |
![]() |
glRotatef( 45.0, 0.0, 0.0, 1.0 ) |
![]() |
glTranslatef( 1.0, 0.0, 0.0 ); /* Draw the upper claw */ WireBox( 2.0, 0.4, 1.0 ); |
![]() |
glPopMatrix() |
![]() |
glPushMatrix(); |
![]() |
glRotatef( -45.0, 0.0, 0.0, 1.0 ) |
![]() |
glTranslatef( 1.0, 0.0, 0.0 ); /* Draw the lower claw */ WireBox( 2.0, 0.4, 1.0 ); |
![]() |
glPopMatrix() |
![]() |
glPopMatrix() |
![]() |
/* robot_claw.c - draw a robot claw by using the modelview stack
* to save transformations so that we can get back to the elbow.
*
* 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 */
void
main( int argc, char *argv[] )
{
GLsizei width, height;
glutInit( &argc, argv );
width = glutGet( GLUT_SCREEN_WIDTH );
height = glutGet( GLUT_SCREEN_HEIGHT );
glutInitWindowPosition( (width / 2) + 4, height / 4 );
glutInitWindowSize( (width / 2) - 4, height / 2 );
glutInitDisplayMode( GLUT_RGBA );
glutCreateWindow( argv[0] );
initgfx();
glutKeyboardFunc( keyboard );
glutDisplayFunc( drawScene );
printHelp( argv[0] );
glMatrixMode( GL_PROJECTION );
gluPerspective( 45.0, (GLdouble) width/ (GLdouble)height, 1.0, 20.0 );
glMatrixMode( GL_MODELVIEW );
glutMainLoop();
}
void
printHelp( char *progname )
{
fprintf(stdout, "\n%s - renders a robot claw\n\n"
"Escape Key - exit the program\n\n",
progname);
}
GLvoid
initgfx( GLvoid )
{
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glShadeModel( GL_FLAT );
}
GLvoid
keyboard( GLubyte key, GLint x, GLint y )
{
switch (key) {
case KEY_ESC: /* Exit whenever the Escape key is pressed */
exit(0);
}
}
GLvoid
drawScene( GLvoid )
{
static GLfloat upperArmColor[] = { 0.5, 0.5, 0.8 };
static GLfloat lowerArmColor[] = { 0.5, 0.8, 0.5 };
glClear( GL_COLOR_BUFFER_BIT );
/* Save the Identity matrix that's on the ModelView
* matrix stack */
glPushMatrix();
/* translate into the viewing volume */
glTranslatef( 0.0, 0.0, -8.0 );
XYaxes();
glPushAttrib( GL_LINE_BIT );
glLineWidth( 2.0 );
/* Draw the upper arm with the shoulder
* on the Z axis */
/* Step 1: move to the center of the upper arm */
glTranslatef( 1.0, 0.0, 0.0 );
/* Step 2: draw the upper arm */
glColor3fv( upperArmColor );
WireBox( 2.0, 0.4, 1.0 );
/* Draw the lower arm at the end of the upper arm and
* rotate it 45 degrees */
/* Step 3: move to the elbow */
glTranslatef( 1.0, 0.0, 0.0 );
/* Save the current matrix so we can get back to the elbow */
glPushMatrix();
/* Step 4: rotate the lower arm 45 degrees */
glRotatef( 45.0, 0.0, 0.0, 1.0 );
/* Step 5: move to the center of the lower arm */
glTranslatef( 1.0, 0.0, 0.0 );
/* Step 6: draw the upper claw */
glColor3fv( lowerArmColor );
WireBox( 2.0, 0.4, 1.0 );
/* Discard the last transformations, and retrieve
* the previous current matrix */
glPopMatrix();
/* Save the current matrix so we can get back to the elbow */
glPushMatrix();
/* Step 4: rotate the lower arm -45 degrees */
glRotatef( -45.0, 0.0, 0.0, 1.0 );
/* Step 5: move to the center of the lower arm */
glTranslatef( 1.0, 0.0, 0.0 );
/* Step 6: draw the lower claw */
glColor3fv( lowerArmColor );
WireBox( 2.0, 0.4, 1.0 );
glPopMatrix();
glPopAttrib();
glPopMatrix();
glFlush();
}
Notes:
This program is the same as robot_arm.c, except that we draw a third box to create a claw.
We surround all of the code in drawScene() with glPushMatrix() and glPopMatrix(). This is so that the transformations do not accumulate on the ModelView stack every time drawScene() is called.We also call glPushMatrix() and glPopMatrix() to draw the two pieces of the claw. This is much easier than trying to backtrack to the elbow.
| Function | Description |
| glutSolidSphere glutWireSphere |
Renders a sphere centered at the modeling coordinate origin |
| glutSolidCube glutWireCube |
Renders a cube centered at the modeling coordinate origin |
| glutSolidCone glutWireCone |
Renders a cone oriented along the z axis; the base is at z=0 and the top is at z=height |
| glutSolidTorus glutWireTorus |
Renders a torus centered at the modeling coordinate origin |
| glutSolidDodecahedron glutWireDodecahedron |
Renders a 12-sided regular object centered at the modeling coordinate origin; radius is 1.0 |
| glutSolidOctahedron glutWireOctahedron |
Renders an 8-sided regular object centered at the modeling coordinate origin; radius is 1.0 |
| glutSolidIcosahedron glutWireIcosahedron |
Renders a 20-sided regular object centered at the modeling coordinate origin; radius is sqrt(3) |
| glutSolidTetrahedron glutWireTetrahedron |
Renders a 4-sided regular object centered at the modeling coordinate origin; radius is sqrt(3) |
| glutSolidTeapot glutWireTeapot |
Renders a teapot centered at the modeling coordinate origin |
Notes:
See the GLUT Quick Reference at the end of this module for a description of the parameters for these functions.

Use glutSolidSphere() to draw the Sun, Earth and Moon. Use 0.7 for the radius of the sun, 0.4 for the earth, and 0.2 for the moon.
Use modeling transformations to position the spheres as shown above.
Notes:
glutSolidSphere draws the sphere so that the north pole is on the z axis. (To see this, you can use glutWireSphere instead). Rotate all of your spheres 90 degrees along the x axis to get them oriented correctly.
Use the distances shown above to determine how far to translate for each orbit. For now, do not worry about where to position the earth and moon in their respective orbits.
Include the following commands in the exercise
Do not worry about function parameters initially. The order of the commands is more important. You can go back and fill in the parameters.


Make the sun yellow, the earth blue and the moon gray.
Add code to toggle between wireframe and solid spheres when the <SPACE>
key is pressed.
* Apply modeling transformations to your shapes. Be sure to save and restore the matrix stack when you want independent transformations.
* Model a simple 3D object, such as a cube or tetrahedron.
Notes:
* Indicates an optional laboratory exercise.

Models for the frame and a wheel are rendered using the functions drawFrame() and drawWheel().

Order of the commands is more important than function parameters.
| Wireframe and Solid Shapes | Notes |
|---|---|
void glutWireSphere(
GLdouble radius,
GLint slices,
GLint stacks )
void glutSolidSphere(
GLdouble radius,
GLint slices,
GLint stacks )
|
radius = radius of sphere slices = number of subdivisions around the z axis (like longitude) stacks = number of subdivisions along the z axis (like latitude) |
void glutWireCube( GLdouble size ) void glutSolidCube( GLdouble size ) |
size = length of each side of the cube |
void glutWireCone(
GLdouble base,
GLdouble height,
GLint slices,
GLint stacks )
void glutSolidCone(
GLdouble base,
GLdouble height,
GLint slices,
GLint stacks )
|
base = radius of base of cone height = height of cone slices = number of subdivisions around the z axis (like longitude) stacks = number of subdivisions along the z axis (like latitude) |
void glutWireTorus(
GLdouble innerradius,
GLdouble outerradius,
GLint nsides,
GLint rings )
void glutSolidTorus(
GLdouble innerradius,
GLdouble outerradius,
GLint nsides,
GLint rings )
|
innerradius = inner radius of torus outerradius = outer radius of torus nsides = number of sides for each radial section rings = number of radial divisions for the torus |
void glutWireIcosahedron( void ) void glutSolidIcosahedron( void ) |
radius is 1.0 |
void glutWireOctahedron( void ) void glutSolidOctahedron( void ) |
radius is 1.0 |
void glutWireTetrahedron( void ) void glutSolidTetrahedron( void ) |
radius is sqrt(3) |
void glutWireDodecahedron( void ) void glutSolidDodecahedron( void ) |
radius is sqrt(3) |
void glutWireTeapot( GLdouble size ) void glutSolidTeapot( GLdouble size ) |
size = relative size of teapot |
GLvoid gluLookAt( GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GLdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble upZ)gluLookAt defines a viewing transformation that:
Notes:
Call gluLookAt, before drawing in the ModelView stack with identity matrix loaded. In this way the Viewing transformation is applied after all your modeling transformation.
Using your knowledge about gluPerspective, gluLookAt, and 3D model provided by glut you have to
#include "eliteutils.h"in the beginning of the program and use this function call
#include "coriolis.h"
drawEliteObject(coriolis_numberOfFaces, coriolis_vertex, coriolis_face, coriolis_material)to draw the satellite.
renderBitmapString(GLUT_BITMAP_HELVETICA_18, "whatYouWant")where GLUT_BITMAP_HELVETICA_18 is an example of font and "whatYouWant" is an example of string that you can replace with what you pefer.
chmod +x melite4bif you want a successful execution of the program.