
Roberto Toldo,
<nome.cognome@univr.it >
Hit the space bar for next slide
OpenGL provides for a depth buffer to render images with hidden surfaces eliminated. The depth buffer is configurable, meaning not only can its use be optimized for hidden surface elimination, it can be used for additional operations as well.
The depth buffer contains a set of values, each of which relates to a pixel on the screen. Use of the depth buffer is enabled with glEnable(GL_DEPTH_TEST).
Points, lines, polygons, and characters are reduced during rendering to pixels, each with its own color and x and y coordinates. Also, when the depth buffer is enabled, a z coordinate is computed for each pixel. This coordinate effectively specifies the distance from pixel to eye.
Before a pixel's color is written to the framebuffer, its z value is compared with the value already stored in the depth buffer. If the incoming pixel is nearer (that is, if it has a lower z value), its color is written into the framebuffer and its z value is written into the depth buffer. If it is farther (that is, if it has a greater z value), the incoming color and z value are discarded. Thus, at any point in the drawing, the values in the depth buffer represent the distance to the item which currently is closest to the eye. By first clearing the depth buffer to the maximum depth value and then rendering all primitives using the depth buffer algorithm, an image including only the nearest surfaces to the eye is produced.
Mathematically, z coordinates are treated just like x and y coordinates. After transformation, clipping, and perspective division, they occupy the range
-1.0 through 1.0, corresponding to the near and far clipping planes. Just as you specify a viewport transformation to map x and y from this range to a window's boundaries, so must you specify a mapping of z coordinates. The default mapping of 0,1 maps the near plane to 0 and the far plane to 1. With this mapping, the depth buffer range is fully utilized.
This mapping can be changed. glDepthRange(nearClip, farClip) specifies a linear mapping of the normalized z coordinates in this range to window z coordinates. For example, the call
glDepthRange(0.0, 0.5);
will cause OpenGL to use only half of the depth buffer range. Regardless of the actual depth buffer implementation, window coordinate depth values are treated as though they range from 0.0 through 1.0 (like color components). Thus, the values accepted by glDepthRange are both clamped to this range before they are accepted.
Recall also that each depth buffer location must be initialized to its farthest value prior to rendering. Set the initialization value by calling glClearDepth(depth), then call glClear to clear the buffer to that value. On some systems, performance is increased if the depth buffer and the framebuffer are initialized at the same time. To accomplish this, pass both GL_COLOR_BUFFER_BIT and GL_DEPTH_BUFFER_BIT in the same glClear call.
glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );
It was previously asserted that a depth buffer value, in effect, specifies the distance from pixel to eye. While this is true, the relationship between distance and z is linear only in an orthographic projection. In the case of a perspective projection, the relationship is non-linear, sometimes very much so.
The degree of non-linearity is controlled by the ratio of far to near in the perspective call. The greater the ratio, the greater the non-linearity.
When the projection matrix is defined by
gluPerspective(fovy, aspect, nearClip, farClip);
and the z viewport transformation is defined by
glDepthRange(near vp, farvp);
then zeye and zscreen are related by the following equations:


In practice, non-linearity increases depth buffer precision in a small range adjacent to the near clipping plane and reduces precision throughout the rest of the viewing volume. While some precision increase near the viewer can be desirable, the effect of substantial non-linearity is to defeat depth buffer operation throughout much of the viewing volume. Experience shows that ratios greater than 1000 have this undesired result.
The ratio of far to near is most easily controlled by simply moving the near clipping plane away from the eye position. Note that changing near in the perspective call has no effect on the projection of x and y and so has little effect on the resulting image. Instead, its effect is limited to the position of the near clipping plane and the projection of Z values. Because of this, you should always move the near plane as far from the eye as possible.
At the completion of this lecture, you will be able to

Notes:
Modeling transformations take object coordinates to world coordinates; viewing transformations take world coordinates to eye coordinates; the projection transformation takes eye coordinates to normalized device coordinates (NDCs); and the viewport transformation takes NDCs to window coordinates.
Viewing transformations are simply a group of modeling transformations. They are typically done right after the first glPushMatrix in our drawScene to set up where our eye is located and where it is looking.
You have already seen an example of a viewing transformation. Earlier examples used glTranslatef(0.0, 0.0, -distance) to position the objects within our viewing volume. This is just a simple viewing transformation to position the eye so that it is no longer in the middle of the scene.

GLvoid gluLookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz )

Notes:
The eye point (eyex , eyey, eye z) is specified in world coordinates.
The reference point (centerx, center y, centerz) indicates the center of the scene (where we want to look).
The vector (upx, up y, upz) defines which direction is up. The up vector must not be parallel to the line of sight from the eye to the reference point.

Notes:
Often, programmers construct a scene around the origin or some other convenient location, then they want to look at it from an arbitrary point to get a good view of it. As its name suggests, the gluLookAt() utility routine is designed for just this purpose.
gluLookAt() is really a set of modeling transformations grouped together
glMatrixMode( GL_MODELVIEW )
...
glPushMatrix();
/* Position the eye on the +z axis,
* look at ( xRef, yRef, zRef ),
* and define +y to be `up'
*/
gluLookAt( 0.0, 0.0, 10.0, xRef, yRef, zRef,
0.0, 1.0, 0.0 );
glPushMatrix();
/* modeling transformation */
/* draw object */
glPopMatrix();
...
glPopMatrix();
/* lookat.c - use input from the keyboard to control the viewpoint
*
* F1 key - print help information
* Left Arrow Key - move the reference point to the left
* Right Arrow Key - move the reference point to the right
* Up Arrow Key - move the reference point up
* Down Arrow Key - move the reference point down
* Escape key - exit the program
*/
#include <GL/glut.h> /* includes gl.h, glu.h */
#include <math.h>
#include <stdio.h> /* for printf */
/* Function Prototypes */
GLvoid initgfx( GLvoid );
GLvoid drawScene( GLvoid );
GLvoid reshape( GLsizei, GLsizei );
GLvoid keyboard( GLubyte, GLint, GLint );
GLvoid specialkeys( GLint, GLint, GLint );
void printHelp( char * );
/* Global Definitions */
#define KEY_ESC 27 /* ascii value for the escape key */
/* Global Variables */
static GLdouble xRef = 0.0, yRef = 0.0;
static char *progname;
GLvoid
main( int argc, char *argv[] )
{
GLsizei width, height;
glutInit( &argc, argv );
width = glutGet( GLUT_SCREEN_WIDTH );
height = glutGet( GLUT_SCREEN_HEIGHT );
glutInitWindowPosition( 4, height / 4 );
glutInitWindowSize( (width / 2) - 4, height / 2 );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutCreateWindow( argv[0] );
initgfx();
glutKeyboardFunc( keyboard );
glutSpecialFunc( specialkeys );
glutReshapeFunc( reshape );
glutDisplayFunc( drawScene );
progname = argv[0];
printHelp( progname );
glutMainLoop();
}
void
printHelp( char *progname )
{
fprintf(stdout, "\n%s - uses keyboard input to control the "
"location of the reference point point\n\n"
"F1 Key - print Help information\n"
"Left Arrow Key - move reference point to the left\n"
"Right Arrow Key - move reference point to the right\n"
"Up Arrow Key - move reference point up\n"
"Down Arrow Key - move reference point down\n"
"Escape Key - exit the program\n\n",
progname);
}
GLvoid
initgfx( GLvoid )
{
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glShadeModel( GL_FLAT );
glEnable( GL_DEPTH_TEST );
}
GLvoid
reshape( GLsizei width, GLsizei height )
{
GLdouble aspect;
glViewport( 0, 0, width, height );
aspect = (GLdouble) width / (GLdouble) height;
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 45.0, aspect, 1.0, 20.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
specialkeys( GLint key, GLint x, GLint y )
{
switch (key) {
case GLUT_KEY_F1: /* print Help */
printHelp( progname );
break;
case GLUT_KEY_LEFT: /* move reference point to the left */
xRef -= 0.5;
if (xRef < -4.0) xRef = -4.0;
glutPostRedisplay();
break;
case GLUT_KEY_RIGHT: /* move reference point to the right */
xRef += 0.5;
if (xRef > 4.0) xRef = 4.0;
glutPostRedisplay();
break;
case GLUT_KEY_UP: /* move reference point up */
yRef += 0.5;
if (yRef > 3.0) yRef = 3.0;
glutPostRedisplay();
break;
case GLUT_KEY_DOWN: /* move reference point down */
yRef -= 0.5;
if (yRef < -3.0) yRef = -3.0;
glutPostRedisplay();
break;
}
}
GLvoid
drawScene( GLvoid )
{
static GLfloat upperArmColor[] = { 1.0, 0.0, 0.0 };
static GLfloat lowerArmColor[] = { 0.8, 0.5, 0.5 };
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
/* Move the reference point */
gluLookAt( 0.0, 0.0, 8.0, xRef, yRef, 0.0, 0.0, 1.0, 0.0 );
XYaxes();
/* Draw the shoulder at the new origin */
glTranslatef( 1.0, 0.0, 0.0 );
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 */
glTranslatef( 1.0, 0.0, 0.0 );
glRotatef( 45.0, 0.0, 0.0, 1.0 );
glTranslatef( 1.0, 0.0, 0.0 );
glColor3fv( lowerArmColor );
WireBox( 2.0, 0.4, 1.0 );
glPopMatrix();
glutSwapBuffers();
}
Notes:
This program draws a simple scene and uses the arrow keys to change the location of the eye.
Note: This program calls gluLookAt() before drawing anything in drawScene(). It also uses glPushMatrix()/glPopMatrix() to save and restore the original identity matrix.
Notes:
The gluLookAt routine is particularly useful when you want to pan across a scene (for example, a landscape).
View your model as if it were encased in a glass sphere centered around the origin
void polarView(GLfloat distance, GLfloat azimuth,
GLfloat incidence, GLfloat twist)
{
glTranslatef(0.0, 0.0, -distance);
glRotatef(-twist, 0.0, 0.0, 1.0);
glRotatef(-incidence, 1.0, 0.0, 0.0);
glRotatef(-azimuth, 0.0, 0.0, 1.0);
}

Notes:
The polarView() function shown emulates the IRIS GL polarview() function.
Notes:
This is one way to figure out how far away from your objects you want to be. Basically, you are just finding the size of the bounding box for your scene.



/* polarView.c - show how to combine modeling transformations to
* view objects as though they are encased in a glass ball
*
* F1 key - print help information
* Left Arrow Key - increment the azimuth angle
* Right Arrow Key - decrement the azimuth angle
* Up Arrow Key - increment the incidence angle
* Down Arrow Key - decrement the incidence angle
* t Key - increment the twist angle
* T Key - decrement the twist angle
* R Key - reset viewpoint
* Escape key - exit the program
*/
#include <GL/glut.h> /* includes gl.h, glu.h */
#include <math.h>
#include <stdio.h> /* for printf */
/* Function Prototypes */
GLvoid initgfx( GLvoid );
GLvoid drawScene( GLvoid );
GLvoid reshape( GLsizei, GLsizei );
GLvoid keyboard( GLubyte, GLint, GLint );
GLvoid specialkeys( GLint, GLint, GLint );
void resetView( GLvoid );
void polarView( GLfloat, GLfloat, GLfloat, GLfloat);
void printHelp( char * );
/* Global Definitions */
#define KEY_ESC 27 /* ascii value for the escape key */
/* Global Variables */
static char *progname;
static GLfloat beamWidth = 2.0, beamHeight = 0.4, beamDepth = 1.0;
static GLfloat nearClip, farClip, distance, twistAngle, incAngle, azimAngle;
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 | GLUT_DEPTH | GLUT_DOUBLE );
glutCreateWindow( argv[0] );
initgfx();
glutKeyboardFunc( keyboard );
glutSpecialFunc( specialkeys );
glutReshapeFunc( reshape );
glutDisplayFunc( drawScene );
progname = argv[0];
printHelp( argv[0] );
glutMainLoop();
}
void
printHelp( char *progname )
{
fprintf(stdout, "\n%s - combine modeling transformations to \n"
"view objects as though encased in a glass ball\n\n"
"Axes: X - red, Y - green, Z - blue\n\n"
"F1 Key - print Help information\n"
"Left Arrow Key - increment the azimuth angle\n"
"Right Arrow Key - decrement the azimuth angle\n"
"Up Arrow Key - increment the incidence angle\n"
"Down Arrow Key - decrement the incidence angle\n"
"<t> Key - increment the twist angle\n"
"<T> Key - decrement the twist angle\n"
"<R> Key - reset viewpoint\n"
"Escape Key - exit the program\n\n",
progname);
}
GLvoid
initgfx( GLvoid )
{
GLfloat maxObjectSize;
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glShadeModel( GL_FLAT );
glEnable( GL_DEPTH_TEST );
/* Maximum size of all the objects in your scene */
maxObjectSize = sqrt( ((2*beamWidth) * (2*beamWidth)) +
((2*beamHeight) * (2*beamHeight)) +
(beamDepth * beamDepth) );
/* Set up nearClip and farClip so that */
/* ( farClip - nearClip ) > maxObjectSize, */
/* and determine the viewing distance (adjust for zooming) */
nearClip = 1.0;
farClip = nearClip + 8*maxObjectSize;
resetView();
}
GLvoid
reshape( GLsizei width, GLsizei height )
{
GLdouble aspect;
glViewport( 0, 0, width, height );
aspect = (GLdouble) width / (GLdouble) height;
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 45.0, aspect, nearClip, farClip );
glMatrixMode( GL_MODELVIEW );
}
GLvoid
keyboard( GLubyte key, GLint x, GLint y )
{
switch (key) {
case 'R':
resetView();
glutPostRedisplay();
break;
case 't':
twistAngle = fmod( (twistAngle + 5.0), 360.0 );
glutPostRedisplay();
break;
case 'T':
twistAngle = fmod( (twistAngle - 5.0), 360.0 );
glutPostRedisplay();
break;
case KEY_ESC: /* Exit whenever the Escape key is pressed */
exit(0);
}
}
GLvoid
specialkeys( GLint key, GLint x, GLint y )
{
switch (key) {
case GLUT_KEY_F1: /* print Help */
printHelp( progname );
break;
case GLUT_KEY_LEFT:
azimAngle = fmod( (azimAngle + 5.0), 360.0 );
glutPostRedisplay();
break;
case GLUT_KEY_RIGHT:
azimAngle = fmod( (azimAngle - 5.0), 360.0 );
glutPostRedisplay();
break;
case GLUT_KEY_UP:
incAngle = fmod( (incAngle + 5.0), 360.0 );
glutPostRedisplay();
break;
case GLUT_KEY_DOWN:
incAngle = fmod( (incAngle - 5.0), 360.0 );
glutPostRedisplay();
break;
}
}
void
resetView( GLvoid )
{
distance = nearClip + (farClip - nearClip) / 2.0;
twistAngle = 0.0; /* rotation of viewing volume (camera) */
incAngle = 0.0;
azimAngle = 0.0;
}
void
polarView( GLfloat distance, GLfloat azimuth, GLfloat incidence,
GLfloat twist)
{
glTranslatef( 0.0, 0.0, -distance);
glRotatef( -twist, 0.0, 0.0, 1.0);
glRotatef( -incidence, 1.0, 0.0, 0.0);
glRotatef( -azimuth, 0.0, 0.0, 1.0);
}
GLvoid
drawScene( GLvoid )
{
static GLfloat upperArmColor[] = { 1.0, 0.0, 0.0 };
static GLfloat lowerArmColor[] = { 0.8, 0.5, 0.5 };
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
polarView( distance, azimAngle, incAngle, twistAngle );
XYZaxes();
/* Draw the shoulder centered at the new origin */
glTranslatef( 1.0, 0.0, 0.0 );
glColor3fv( upperArmColor );
WireBox( beamWidth, beamHeight, beamDepth );
/* Draw the lower arm at the end of the upper arm and
* rotate it 45 degrees */
glTranslatef( 1.0, 0.0, 0.0 );
glRotatef( 45.0, 0.0, 0.0, 1.0 );
glTranslatef( 1.0, 0.0, 0.0 );
glColor3fv( lowerArmColor );
WireBox( beamWidth, beamHeight, beamDepth );
glPopMatrix();
glutSwapBuffers();
}
Notes:
This program is similar to lookat.c, but it uses the polarView function to set the location of the eye.
The left and right arrow keys control azimuth angle, and the up and down arrow keys control the incidence angle.
Note: The program calculates the size of the robot arm in initgfx() and uses this to determine where to put the far clipping plane.
As with gluLookAt(), polarView() is called before rendering anything, and glPushMatrix/glPopMatrix are used to save and restore the resulting viewing transformation.
void glutMouseFunc( void (*func)(int button, int state, int x, int y) )
Notes:

The mouse location is reported in window coordinates.
void glutMotionFunc( void (*func)(int x, int y) )
/* mouse.c - use the mouse to control the location of the viewpoint
*
* Escape key - exit the program
* Left Mouse Button - change incidence and azimuth angles
* Middle Mousebutton - change the twist angle based on
* horizontal mouse movement
* Right Mousebutton - zoom in and out based on vertical
* mouse movement
* R Key - reset viewpoint
*/
#include <GL/glut.h> /* includes gl.h, glu.h */
#include <math.h>
#include <stdio.h> /* for printf */
/* Function Prototypes */
GLvoid initgfx( GLvoid );
GLvoid drawScene( GLvoid );
GLvoid reshape( GLsizei, GLsizei );
GLvoid keyboard( GLubyte, GLint, GLint );
GLvoid mouse( GLint, GLint, GLint, GLint );
GLvoid motion( GLint, GLint );
void resetView( GLvoid );
void polarView( GLfloat, GLfloat, GLfloat, GLfloat);
void printHelp( char * );
/* Global Definitions */
#define KEY_ESC 27 /* ascii value for the escape key */
/* Global Variables */
enum actions { MOVE_EYE, TWIST_EYE, ZOOM, MOVE_NONE };
static GLint action;
static GLdouble xStart = 0.0, yStart = 0.0;
static GLfloat beamWidth = 2.0, beamHeight = 0.4, beamDepth = 1.0;
static GLfloat nearClip, farClip, distance, twistAngle, incAngle, azimAngle;
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 | GLUT_DEPTH | GLUT_DOUBLE );
glutCreateWindow( argv[0] );
initgfx();
glutMouseFunc( mouse );
glutMotionFunc( motion );
glutKeyboardFunc( keyboard );
glutReshapeFunc( reshape );
glutDisplayFunc( drawScene );
printHelp( argv[0] );
glutMainLoop();
}
void
printHelp( char *progname )
{
fprintf(stdout, "\n%s - use the mouse to control the viewpoint\n\n"
"Axes: X - red, Y - green, Z - blue\n\n"
"Left Mousebutton - move eye position\n"
"Middle Mousebutton - change twist angle\n"
"Right Mousebutton - move up / down to zoom in / out\n"
"<R> Key - reset viewpoint\n"
"Escape Key - exit the program\n",
progname);
}
GLvoid
initgfx( GLvoid )
{
GLfloat maxObjectSize;
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glShadeModel( GL_FLAT );
glEnable( GL_DEPTH_TEST );
/* Maximum size of all the objects in your scene */
maxObjectSize = sqrt( ((2*beamWidth) * (2*beamWidth)) +
((2*beamHeight) * (2*beamHeight)) +
(beamDepth * beamDepth) );
/* Set up nearClip and farClip so that */
/* ( farClip - nearClip ) > maxObjectSize, */
/* and determine the viewing distance (adjust for zooming) */
nearClip = 1.0;
farClip = nearClip + 8*maxObjectSize;
resetView();
}
GLvoid
reshape( GLsizei width, GLsizei height )
{
GLdouble aspect;
glViewport( 0, 0, width, height );
aspect = (GLdouble) width / (GLdouble) height;
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 45.0, aspect, nearClip, farClip );
glMatrixMode( GL_MODELVIEW );
}
GLvoid
keyboard( GLubyte key, GLint x, GLint y )
{
switch (key) {
case 'R':
resetView();
glutPostRedisplay();
break;
case KEY_ESC: /* Exit whenever the Escape key is pressed */
exit(0);
}
}
GLvoid
mouse( GLint button, GLint state, GLint x, GLint y )
{
static GLint buttons_down = 0;
if (state == GLUT_DOWN) { /* most recent button down wins */
buttons_down++;
switch (button) {
case GLUT_LEFT_BUTTON:
/* in case there are only two mouse
* buttons, shift-left is equivalent to the
* middle mouse button
*/
if (glutGetModifiers() == GLUT_ACTIVE_SHIFT)
action = TWIST_EYE;
else
action = MOVE_EYE;
break;
case GLUT_MIDDLE_BUTTON:
action = TWIST_EYE;
break;
case GLUT_RIGHT_BUTTON:
action = ZOOM;
break;
}
/* Update the saved mouse position */
xStart = x;
yStart = y;
} else {
if (--buttons_down == 0)
action = MOVE_NONE; /* no more buttons down */
}
}
GLvoid
motion( GLint x, GLint y )
{
switch (action) {
case MOVE_EYE:
/* Adjust the eye position based on the mouse position */
azimAngle += (GLdouble) (x - xStart);
incAngle -= (GLdouble) (y - yStart);
break;
case TWIST_EYE:
/* Adjust the eye twist based on the mouse position */
twistAngle = fmod(twistAngle+(x - xStart), 360.0);
break;
case ZOOM:
/* Adjust the eye distance based on the mouse position */
distance -= (GLdouble) (y - yStart)/10.0;
break;
default:
printf("unknown action %d\n", action);
}
/* Update the stored mouse position for later use */
xStart = x;
yStart = y;
glutPostRedisplay();
}
void
resetView( GLvoid )
{
distance = nearClip + (farClip - nearClip) / 2.0;
twistAngle = 0.0; /* rotation of viewing volume (camera) */
incAngle = 0.0;
azimAngle = 0.0;
}
void
polarView( GLfloat distance, GLfloat azimuth, GLfloat incidence,
GLfloat twist)
{
glTranslatef( 0.0, 0.0, -distance);
glRotatef( -twist, 0.0, 0.0, 1.0);
glRotatef( -incidence, 1.0, 0.0, 0.0);
glRotatef( -azimuth, 0.0, 0.0, 1.0);
}
GLvoid
drawScene( GLvoid )
{
static GLfloat upperArmColor[] = { 1.0, 0.0, 0.0 };
static GLfloat lowerArmColor[] = { 0.8, 0.5, 0.5 };
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
polarView( distance, azimAngle, incAngle, twistAngle );
XYZaxes();
/* Draw the shoulder centered at the new origin */
glTranslatef( 1.0, 0.0, 0.0 );
glColor3fv( upperArmColor );
WireBox( beamWidth, beamHeight, beamDepth );
/* Draw the lower arm at the end of the upper arm and
* rotate it 45 degrees */
glTranslatef( 1.0, 0.0, 0.0 );
glRotatef( 45.0, 0.0, 0.0, 1.0 );
glTranslatef( 1.0, 0.0, 0.0 );
glColor3fv( lowerArmColor );
WireBox( beamWidth, beamHeight, beamDepth );
glPopMatrix();
glutSwapBuffers();
}
Notes:
This program is the same program as polarView.c, except that it uses the mouse buttons to control the location and orientation of the viewpoint.
The left button moves the eye position and the right button changes the zoom. With a three button mouse, the middle button changes the twist angle. With a two button mouse, the twist angle is changed by holding down the Shift key while pressing the left mouse button.
When any mouse button is pressed, mouse() records the current mouse location, and sets the action flag (MOVE_EYE, TWIST_EYE, ZOOM) which is used by the motion() callback. If the left button was pressed, mouse() calls glutGetModifiers(). If GLUT_ACTIVE_SHIFT is returned, the action flag is set to TWIST_EYE rather than MOVE_EYE.
When the user moves the mouse with any mouse button down, motion() is called. This callback checks whether the action flag is set. If so, it grabs the current location of the mouse and compares in against the last saved values. It then adjusts the view parameter specified by the action flag by the difference between the changes in the x and y positions.
When the mouse button is released, the mouse() callback sets the action flag to MOVE_NONE to indicate that the program should stop tracking the location of the mouse.
Notes:
* Indicates an optional laboratory exercise.
Hint: The polarView transformation works well for the solar system program. You might want to set the initial value for the incidence angle to -30 degrees.
void gluLookAt( GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GLdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble upZ )
Creates a viewing matrix derived from an eye point, a reference point
indicating the center of the scene, and an up vector. The matrix maps
the reference point to the negative z axis and the eye point to the
origin, so that, when a typical projection matrix is used, the center
of the scene maps to the center of the viewport. Similarly, the
direction described by the up vector projected onto the viewing plane
is mapped to the positive y axis so that it points upward in the
viewport.
void glutMouseFunc( void (*mouse)(int button, int state, int x, int y) )
Sets up a callback function to handle mouse button events.
void glutMotionFunc( void (*motion)(int x, int y) )
Sets up a callback function to handle mouse motion events.
Download the class camera.cpp
and the relative header file camera.h.
Using this class you can move the perspective camera as a hypothetical pilot drive a
spaceship.
For compiling you need
camera.cpp,
camera.h,
coriolis.h,
eliteutils.h, and
eliteutils.c in the same directory.
In this version there are new details: