
Roberto Toldo,
<nome.cognome@univr.it >
Hit the space bar for next slide
In previous sections, we discussed projection transformations. In particular, we described the viewing volume, either a rectangular box or a pyramid-shaped viewing frustum. This section describes how to move the viewing volume to see the world from different points of view.
To use the camera analogy, the projection transformation describes the type of lens to use. That camera is fixed onto a tripod. The viewing transformation describes where you put the tripod in the world and where you choose to point it.
The viewing transformation commands, polarView and gluLookAt, are commands which compose their transformation on the current matrix stack. They should be used when the ModelView matrix stack is active.
By default, the `camera' (center of projection) is positioned at the origin, (0.0, 0.0, 0.0) and pointed down the negative half of the z axis. The camera is not `twisted' (tilted).
Let's try an exercise to visualize this. This is really an exercise; body movements and all. Stick your right hand straight out to your right side (parallel to the ground). If you are looking north, your right hand should be pointing east. Your right hand is the x axis. Now raise your left hand over your head. Your left hand forms the y axis. Now pretend that you are a camera. Your head is at the origin of the world, (0.0, 0.0, 0.0). You are now looking down the negative z axis. Imagine the numbers: -1.0, -2.0, -3.0, in front of your face. Behind your head are the numbers: 1.0, 2.0, 3.0. You see a viewing volume that is in the default viewing position.
There are nine parameters for the gluLookat utility command. The first three (eyex, eyey, eyez) define the location for the viewpoint, or in other words, "Where you put the camera." The next three parameters (centerx, centery, centerz) define a 3D reference point, or in other words, "Where you aim the camera." The viewpoint and the reference point define the line of sight. Finally, the last three parameters (upx, upy, upz) define the up vector, or in other words, "Which way is up", relative to the camera.
An alternative to the gluLookat utility command is to write your own viewing transformation. A useful viewing transformation to create is one that simulates the IRIS GL polarview() command.
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);
}
There are four parameters for this polarView command: distance, azimuth, incidence and twist. The first three parameters, distance, azimuth, and incidence, move the viewpoint. distance is the distance (a floating point value) from the origin. azimuth is the azimuthal angle in the x, y plane, measured counterclockwise from the y axis. incidence is the incidence angle in the y, z plane, measured counterclockwise from the z axis. Finally, twist rotates, or tilts, the viewpoint counterclockwise around the line of sight. Each angle is expressed in degrees.
Setting up a scene in 3D is something like taking a photograph. The first step in taking a photo is to select a lens for the camera. In effect, by selecting a lens, you are choosing how much of the world to view, or setting up a viewing volume. This is analogous to giving a projection transformation in a program. After selecting the proper lens, you position the camera (or the eye) somewhere in space, and you decide where to point your camera (point your line of sight). In a 3D program, this is the same as doing a viewing transformation. Finally, in taking a photo, you position the objects you wish to photograph somewhere in the scene. This is analogous to a modeling transformation.
At the completion of this lecture, you will be able to
Notes:
Up to this point, most of our objects have looked flat, even though they have been rendered in 3D. Lighting is what gives most objects their 3D appearance.
OpenGL approximates light and lighting as if light can be broken into separate red, green and blue components. The color of a light is characterized by the amount of R, G and B it emits.
Material properties represent the percent of incoming RGB that an object reflects. The actual color of an object depends on its material properties, and the color of the light sources. For example, a magenta ball reflects incoming red and blue light, but will appear red if lit only by red light, or blue if lit only by blue light.
To perform basic lighting, you will need to
GLvoid glEnable( GLenum option ) GLvoid glDisable( GLenum option )
GLvoid glEnable( GLenum option ) GLvoid glDisable( GLenum option )
0 <= n < maxLights
Notes:
The value <n> can be from 0 to the number of supported lights minus one. An OpenGL implementation is required to support at least eight lights, but can have more. To find the number of lights an implementation supports use:
glGetIntegerv( GL_MAX_LIGHTS, &maxLights );
It is a common error to forget to turn on a specific light. If your scene is unexpectedly dark, check to see if you have enabled a light.
Adding a light is expensive, so use no more than necessary.
Imagine that you have a small mirror positioned at your vertex; a normal specifies which direction the face of the mirror is pointing

Notes:
In more technical terms, a normal is a vector that points in the direction perpendicular to the tangent of a surface.
For some objects, finding the normal is very straightforward.

GLvoid glNormal3f( GLfloat nx, GLfloat ny, GLfloat nz )
Notes:
| Scalar Forms | Vector Forms |
|---|---|
| glNormal3b( nx, ny, nz ) | glNormal3bv( v ) |
| glNormal3s( nx, ny, nz ) | glNormal3sv( v ) |
| glNormal3i( nx, ny, nz ) | glNormal3iv( v ) |
| glNormal3f( nx, ny, nz ) | glNormal3fv( v ) |
| glNormal3d( nx, ny, nz ) | glNormal3dv( v ) |
If every vertex in a primitive has the same normal, it is called a face normal
glBegin( GL_TRIANGLES );
glNormal3f( 0.0, 0.0, 1.0 );
glVertex2f( 0.0, 1.0 );
glVertex2f( -0.866, -0.50 );
glVertex2f( 0.866, -0.50 );
glEnd();

Notes:
If you know the vertices of a primitive in your model, you can compute the face normal using the vector cross product. This method only works if your primitive is planar.
Triangle vertices are always coplanar, so they make good primitives for tessellated surfaces.
If you are rendering many flat-shaded, lit polygons, set glShadeModel(GL_FLAT) for better performance.
If every vertex in a primitive has a different normal, they are called vertex normals
glBegin( GL_TRIANGLES );
glNormal3f( 0.0, 0.0, 1.0 );
glVertex2f( 0.0, 1.0 );
glNormal3f( 0.455, 0.796, 0.398 );
glVertex2f( -0.866, -0.50 );
glNormal3f( 0.162, 0.566, 0.808 );
glVertex2f( 0.866, -0.50 );
glEnd();

You can tell OpenGL to automatically normalize the normal vectors that you specify in your program
GLvoid glEnable( GLenum option ) GLvoid glDisable( GLenum option )
Notes:
When automatic normalization is enabled, OpenGL normalizes every normal vector whether or not it is already unit length. It is better to do your own normalization where it is needed; otherwise, OpenGL spends time normalizing everything (even things that are already normalized).
In many cases, GL_RESCALE_NORMAL can operate faster than renormalization, while resulting in the same unit normals. Rescaling may be used when the ModelView has been rotated or uniformly scaled. Do not use rescaling if there are non-uniform scales in the ModelView; the results will be incorrect.
Whenever possible, use unit length normal vectors and avoid using glScale*() with lighting.
/* normals.c - Show the effect of lighting on a flat surface
* when using face normals and vertex normals. The red
* lines represent the directions of the normal vectors.
*
* Left Mousebutton - move eye position
* Middle Mousebutton - change twist angle
* Right Mousebutton - move up / down to zoom in / out
* Escape Key - exit the program
*/
#include <GL/glut.h> /* includes gl.h, glu.h */
#include "3d.h"
#include <math.h>
#include <stdio.h>
/* 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 );
GLvoid drawNormal( GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat );
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 fovy, nearClip, farClip, distance, twistAngle, incAngle, azimAngle;
void
main( int argc, char *argv[] )
{
GLsizei width, height;
glutInit( &argc, argv );
/* create a window that is 1/4 the size of the screen */
width = glutGet( GLUT_SCREEN_WIDTH );
height = glutGet( GLUT_SCREEN_HEIGHT );
glutInitWindowPosition( width / 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 - demonstrate face and vertex normals\n\n"
"Left Mousebutton - move eye position\n"
"Middle Mousebutton - change twist angle\n"
"Right Mousebutton - move up / down to zoom in / out\n"
"Escape Key - exit the program\n\n",
progname);
}
GLvoid
initgfx( GLvoid )
{
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glEnable( GL_DEPTH_TEST );
fovy = 60.0; /* field of view in Y */
nearClip = 3.0; /* Near clipping plane location */
farClip = 12.0; /* Far clipping plane location */
resetView();
/* Turn on a default light */
glEnable( GL_LIGHT0 );
}
GLvoid
keyboard( GLubyte key, GLint x, GLint y )
{
switch (key) {
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) {
switch (button) {
case GLUT_LEFT_BUTTON:
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;
}
}
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 = 60.0;
azimAngle = 0.0;
fovy = 60.0; /* Field of view in Y angle */
}
GLvoid
reshape( GLsizei width, GLsizei height )
{
GLdouble aspect;
glViewport( 0, 0, width, height );
aspect = (GLdouble) width / (GLdouble) height;
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( fovy, aspect, nearClip, farClip );
glMatrixMode( GL_MODELVIEW );
}
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
drawNormal( GLfloat px, GLfloat py, GLfloat pz,
GLfloat nx, GLfloat ny, GLfloat nz )
{
GLdouble normal[3], cross[3], zaxis[3];
GLdouble angle;
#define DegreesToRadians (M_PI / (GLfloat) 180.0)
glColor3f( 1.0, 0.0, 0.0 );
glPushMatrix();
glTranslatef( px, py, pz );
glBegin( GL_LINES );
glVertex3f( 0.0, 0.0, 0.0 );
glVertex3f( nx, ny, nz );
glEnd();
/* normalize the normal vector */
normal[0] = nx; normal[1] = ny; normal[2] = nz;
normalize( normal );
/* determine angle between z axis and normal */
zaxis[0] = 0; zaxis[1] = 0; zaxis[2] = 1;
angle = acos( dot3( zaxis, normal ) )/DegreesToRadians;
if ( angle != 0.0 ) {
/* find the axis of rotation */
crossprod( zaxis, normal, cross );
glRotatef( angle, cross[0], cross[1], cross[2] );
}
/* move to end of normal vector */
glTranslatef( 0.0, 0.0, 1.0 );
glutSolidCone( 0.05, 0.1, 8, 8 );
glPopMatrix();
}
GLvoid
drawScene( GLvoid )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
polarView( distance, azimAngle, incAngle, twistAngle );
/* Draw a lit flat-shaded triangle on the left */
glPushMatrix();
glTranslatef( -2.0, 0.0, 0.0 );
/* Turn on lighting computations */
glEnable( GL_LIGHTING );
glBegin( GL_TRIANGLES );
glNormal3f( 0.0, 0.0, 1.0 );
glVertex2f( 0.0, 1.0 );
glVertex2f( -0.866, -0.50 );
glVertex2f( 0.866, -0.50 );
glEnd();
/* Turn off lighting computations */
glDisable( GL_LIGHTING );
/* Draw an unlit line representing the face normal */
drawNormal( 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 );
glPopMatrix();
/* Draw a lit, smooth-shaded triangle on the right */
glPushMatrix();
glTranslatef( 2.0, 0.0, 0.0 );
/* Turn on lighting computations */
glEnable( GL_LIGHTING );
glBegin( GL_TRIANGLES );
glNormal3f( 0.0, 0.0, 1.0 );
glVertex2f( 0.0, 1.0 );
glNormal3f( 0.455, 0.796, 0.398 );
glVertex2f( -0.866, -0.50 );
glNormal3f( 0.162, 0.566, 0.808 );
glVertex2f( 0.866, -0.50 );
glEnd();
/* Turn off lighting computations */
glDisable( GL_LIGHTING );
/* Draw unlit lines representing the vertex normals */
drawNormal( 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 );
drawNormal( -0.866, -0.50, 0.0, 0.455, 0.796, 0.398 );
drawNormal( 0.866, -0.50, 0.0, 0.162, 0.566, 0.808 );
glPopMatrix();
glPopMatrix();
glutSwapBuffers();
}
Notes:
This program draws two triangles. The triangle on the left is given a single face normal, and therefore, it is rendered as a flat-shaded triangle. Each vertex in the triangle on the right is given a different normal, so the colors between each vertex are interpolated. In other words, the triangle on the right is smooth-shaded.
The drawNormal() function just draws an unlit arrow representing the normal vector. It is useful for showing where the normal is pointed.
Notice that GL_LIGHT0 is enabled in initgfx() but this does not turn on lighting. The program turns lighting on only when it needs it (to draw the triangles in drawScene()) and then turns it off to draw the normals.
An object has five properties that describe its appearance

Notes:
An object has five material properties that describe its appearance.
GLvoid glMaterialf( GLenum face, GLenum pname,
const GLfloat param )
GLvoid glMaterialfv( GLenum face, GLenum pname,
const GLfloat *params )
Notes:
For GL_DIFFUSE, GL_AMBIENT, GL_AMBIENT_AND_DIFFUSE, GL_EMISSION, and GL_SPECULAR you must specify an array of RGBA color values.
GL_AMBIENT_AND_DIFFUSE sets ambient and diffuse colors to the same values with one function call. It is provided for convenience since the ambient and diffuse material properties are often set to the same value.
GL_SHININESS takes a single value ranging from 0 (dull) to 128 (shiny). The default value is 0. The shininess and specular properties work together; shininess controls the specular highlight concentration. Since shininess is set with a single value, you can use glMaterialf() to specify it.
/* materials.c - Use material properties to change the color and
* reflection models for some objects
*
* 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
* Escape key - exit the program
*/
#include <GL/glut.h> /* includes gl.h, glu.h */
#include <math.h>
#include <stdio.h>
/* 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 fovy, 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 / 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 - demonstrate lighting material properties\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\n",
progname);
}
GLvoid
initgfx( GLvoid )
{
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glEnable( GL_DEPTH_TEST );
fovy = 60.0; /* field of view in Y */
nearClip = 3.0; /* Near clipping plane location */
farClip = 12.0; /* Far clipping plane location */
resetView();
/* Turn on a default light */
glEnable( GL_LIGHT0 );
}
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) {
switch (button) {
case GLUT_LEFT_BUTTON:
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;
}
}
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 = 60.0;
azimAngle = 0.0;
fovy = 60.0; /* Field of view in Y angle */
}
GLvoid
reshape( GLsizei width, GLsizei height )
{
GLdouble aspect;
glViewport( 0, 0, width, height );
aspect = (GLdouble) width / (GLdouble) height;
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( fovy, aspect, nearClip, farClip );
glMatrixMode( GL_MODELVIEW );
}
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 )
{
/* Define a few materials properties */
GLfloat redAmbient[] = { 0.3, 0.1, 0.1, 1.0 };
GLfloat redDiffuse[] = { 1.0, 0.0, 0.0, 1.0 };
GLfloat blueAmbient[] = { 0.1, 0.1, 0.3, 1.0 };
GLfloat blueDiffuse[] = { 0.0, 0.0, 1.0, 1.0 };
GLfloat yellowDiffuse[] = { 1.0, 1.0, 0.0, 1.0 };
GLfloat yellowEmission[] = { 0.6, 0.6, 0.0, 1.0 };
GLfloat defaultEmission[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat whiteSpecular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat greenSpecular[] = { 0.0, 1.0, 0.0, 1.0 };
GLfloat defaultSpecular[] = { 0.0, 0.0, 0.0, 1.0 };
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
polarView( distance, azimAngle, incAngle, twistAngle );
XYZaxes();
glEnable( GL_LIGHTING );
glMaterialfv( GL_FRONT, GL_EMISSION, defaultEmission );
/* Set properties for a very shiny red material,
* with a green highlight */
glMaterialfv( GL_FRONT, GL_AMBIENT, redAmbient );
glMaterialfv( GL_FRONT, GL_DIFFUSE, redDiffuse );
glMaterialfv( GL_FRONT, GL_SPECULAR, greenSpecular );
glMaterialf( GL_FRONT, GL_SHININESS,
128.0 ); /* tight distribution */
glPushMatrix();
glTranslatef( -2.0, 1.5, 0.0 );
glutSolidSphere( 0.7, 31, 31 );
glPopMatrix();
/* Set properties for a dull blue material with
* a small white highlight */
glMaterialfv( GL_FRONT, GL_AMBIENT, blueAmbient );
glMaterialfv( GL_FRONT, GL_DIFFUSE, blueDiffuse );
glMaterialfv( GL_FRONT, GL_SPECULAR, whiteSpecular );
glMaterialf( GL_FRONT, GL_SHININESS,
20.0 ); /* not very shiny */
glPushMatrix();
glTranslatef( 2.5, 0.0, 0.0 );
glutSolidTorus( 0.25, 0.75, 16, 31 );
glPopMatrix();
/* Set properties for a dull yellow glowing material.
* Shininess property will be the same as the previous
* material since it is not set differently. */
glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, yellowDiffuse);
glMaterialfv( GL_FRONT, GL_EMISSION, yellowEmission );
glMaterialfv( GL_FRONT, GL_SPECULAR, defaultSpecular );
glPushMatrix();
glTranslatef( 0.0, 2.0, 2.0 );
glutSolidCube( 0.5 );
glPopMatrix();
glDisable( GL_LIGHTING );
glPopMatrix();
glutSwapBuffers();
}
Notes:
This program draws three objects: a shiny red sphere with a green highlight, a dull blue torus with a white highlight, and a glowing yellow cube.
Notice the material declarations at the beginning of drawScene(). These are the material properties used for the objects in the scene.
Note: If you do not set a material property for an object, it uses either the default value, or the value set with the previous call to glMaterial*() for that property.
glEnable(GL_COLOR_MATERIAL)
GLvoid glColorMaterial( GLenum face, GLenum property )
Notes:
Legal values for face are GL_FRONT, GL_BACK, and GL_FRONT_AND_BACK (default).
Legal values for property are GL_DIFFUSE, GL_AMBIENT, GL_SPECULAR, GL_EMISSION, and GL_AMBIENT_AND_DIFFUSE (default).
GLfloat redDiffuse = { 1.0, 0.0, 0.0 };
GLfloat blueDiffuse = { 0.0, 0.0, 1.0 };
/* set the property and face to be
* affected by glColor*() calls */
glColorMaterial( GL_FRONT, GL_DIFFUSE );
/* enable fast material changes */
glEnable( GL_COLOR_MATERIAL );
/* change the diffuse material property to red */
glColor3fv( redDiffuse );
drawRedMaterialObjects();
/* change the diffuse material property to blue */
glColor3fv( blueDiffuse );
drawBlueMaterialObjects();
/* don't forget to disable fast material changes */
glDisable( GL_COLOR_MATERIAL );
Notes:
Note that changes can still be made to other materials using glMaterial*().
Be sure to turn off GL_COLOR_MATERIAL when not needed; otherwise, all of your glColor*() calls get interpreted as material changes, even if lighting is disabled.
/* colorMaterial.c - demonstrates using glColorMaterial to quickly
* change material properties.
*
* Escape key - exit the program
*/
#include <GL/glut.h> /* includes gl.h, glu.h */
#include <math.h>
#include <stdio.h>
/* Function Prototypes */
GLvoid initgfx( GLvoid );
GLvoid drawScene( GLvoid );
GLvoid reshape( GLsizei, GLsizei );
GLvoid keyboard( GLubyte, 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 GLdouble fovy, nearClip, farClip;
static GLfloat distance, twistAngle, incAngle, azimAngle;
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) - 4, height / 2 );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutCreateWindow( argv[0] );
initgfx();
glutKeyboardFunc( keyboard );
glutReshapeFunc( reshape );
glutDisplayFunc( drawScene );
printHelp( argv[0] );
glutMainLoop();
}
void
printHelp( char *progname )
{
fprintf(stdout, "\n%s - demonstrate fast material changes\n\n"
"Escape key - exit the program\n\n", progname);
}
GLvoid
initgfx( GLvoid )
{
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 10.0 };
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
/* changing AMBIENT and DIFFUSE properties to the same value
* for the front face only
*/
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glEnable( GL_DEPTH_TEST );
fovy = 60.0; /* field of view in Y */
nearClip = 3.0; /* Near clipping plane location */
farClip = 12.0; /* Far clipping plane location */
resetView();
}
GLvoid
keyboard( GLubyte key, GLint x, GLint y )
{
switch (key) {
case KEY_ESC:
exit(0);
}
}
void
resetView( GLvoid )
{
distance = nearClip + (farClip - nearClip) / 2.0;
twistAngle = 0.0; /* rotation of viewing volume (camera) */
incAngle = 0.0;
azimAngle = 0.0;
}
GLvoid
reshape( GLsizei width, GLsizei height )
{
GLdouble aspect;
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
aspect = (GLdouble) width / (GLdouble) height;
gluPerspective( fovy, aspect, nearClip, farClip );
glMatrixMode( GL_MODELVIEW );
}
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 )
{
int i, slices = 8;
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
polarView( distance, azimAngle, incAngle, 0 );
for ( i = 0; i < slices; i++ )
{
/* change ambient and diffuse material properties
* using GL_COLOR_MATERIAL mode
*/
glColor3f( i/10.0, i/10.0, 1.0 - i/10.0 );
glPushMatrix();
glRotatef( i * 360.0/slices, 0, 0, 1 );
glTranslatef( 1.5, 0.0, 0.0 );
glRotatef( i * 360.0/slices, 0, 1, 0 );
glutSolidTorus( 0.25, 0.75, 8, 15 );
glPopMatrix();
}
glPopMatrix();
glutSwapBuffers();
}
Notes:
Note the call to glColorMaterial() in initgfx() to indicate that both the ambient and diffuse properties should be changed for the front faces whenever you call glColor*().
Also note that you need to enable GL_COLOR_MATERIAL to make this take effect.
Because GL_COLOR_MATERIAL is enabled for the ambient and diffuse properties, the calls to glColor3f() in drawScene() change the ambient and diffuse property of each torus in the ring.
This lab has two parts: tutorial, and programming.
GLvoid glLightfv( GLenum light, GLenum pname,
const GLfloat *params )
0 <= n < maxLights
GL_DIFFUSE, GL_AMBIENT, GL_SPECULAR
GL_POSITION
GL_SPOT_DIRECTION, GL_SPOT_EXPONENT GL_SPOT_CUTOFF
GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION GL_QUADRATIC_ATTENUATION
Notes:
The value <n> can be from 0 to the maximum number of supported lights minus one. An OpenGL implementation is required to support at least eight lights, but can have more. To find the maximum number of lights an implementation supports use:
glGetIntegerv( GL_MAX_LIGHTS, &maxLights );
Vector and scalar forms:
| Scalar Forms | Vector Forms |
|---|---|
| glLightf( light, pname, val ) | glLightfv( light, pname, *v ) |
| glLighti( light, pname, val ) | glLightiv( light, pname, *v ) |
Scalar forms can only be used for setting the spotlight exponent and cutoff, and the attenuation constants.
This module covers only how to set light position and intensities.
GLvoid glGetLightfv(GLenum light, GLenum pname,
GLfloat *params)
Notes:
The values returned by GL_POSITION and GL_SPOT_DIRECTION are in eye coordinates.
GLvoid glLightfv( GLenum light, GL_POSITION,
const GLfloat *params )
Notes:
For an infinitely distant light, the direction of the light is assumed to be from the point (x, y, z) toward the origin. Never set the infinite light direction to (0,0,0,0), as it will be undefined. The rays from the light are assumed to be parallel. The sun is an example of a real-world infinite light. By the time the light gets to Earth, its rays are effectively parallel.
An example of a local light would be a light bulb. By default, the light radiates in all directions from the position specified by (x, y, z). (You will see how to make the light only radiate in one direction later in this module.)
Local light sources are much more compute intensive than infinite light sources.
Notes:
The colors across the face of a smooth-shaded polygon are determined by the colors calculated for the vertices. Because of this, you probably want to avoid using large polygons with local lights.
Note: If you locate the light near the middle of the polygon, the vertices might be too far away to receive much light making the whole polygon look darker than you intended. To avoid this problem, break up large polygons into smaller ones.
To create a light source that moves with your viewpoint, bind the light before your viewing transformation
glPushMatrix();
/* bind light */
glLightfv( GL_LIGHT0, GL_POSITION,
lightPosition );
/* viewing transformation */
polarView( ... );
/* draw objects */
glPopMatrix();

To fix the light source at the same position as the eye, set the light position to (0,0,1,0) for an infinite light or (0,0,0,1) for a local light
Notes:
Since the light is often coming from the same direction as the eye, it can be thought of as a head light. The materials.c program is an example of this.
To create a light source that stays at a fixed position in your scene, bind the light after your viewing transformation
glPushMatrix();
/* viewing transformation */
polarView( ... );
/* bind light */
glLightfv( GL_LIGHT0, GL_POSITION,
lightPosition );
/* draw objects */
glPopMatrix();

Notes:
By binding the light after the viewing transformation, the position of the light is not affected by where the eye is. It stays at the same place in the scene.
/* lightPosition.c - demonstrates how the light position is affected by
* the modelview matrix
*
* 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
* <l> key - toggle light binding
* Escape key - exit the program
*/
#include <GL/glut.h> /* includes gl.h, glu.h */
#include <math.h>
#include <stdio.h>
/* 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 lighttypes { EYE_LIGHT, SCENE_LIGHT };
static GLint lightpos;
enum actions { MOVE_EYE, TWIST_EYE, ZOOM, MOVE_NONE };
static GLint action;
static GLdouble xStart = 0.0, yStart = 0.0;
static GLfloat fovy, nearClip, farClip;
static GLfloat 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 / 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 - demonstrate how the modelview matrix "
"affects the light position\n\n"
"Left Mousebutton - move eye position\n"
"Middle Mousebutton - change twist angle\n"
"Right Mousebutton - move up / down to zoom in / out\n"
"<l> Key - toggle light binding\n"
"Escape Key - exit the program\n\n",
progname);
if ( lightpos == EYE_LIGHT )
printf("Light position attached to Viewpoint\n");
else if ( lightpos == SCENE_LIGHT )
printf("Light position fixed in scene\n");
}
GLvoid
initgfx( GLvoid )
{
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glEnable( GL_DEPTH_TEST );
fovy = 60.0; /* field of view in Y */
nearClip = 3.0; /* Near clipping plane location */
farClip = 12.0; /* Far clipping plane location */
resetView();
lightpos = EYE_LIGHT;
/* Turn on a default light */
glEnable( GL_LIGHT0 );
}
GLvoid
keyboard( GLubyte key, GLint x, GLint y )
{
switch (key) {
case 'l': /* toggle light position */
if ( lightpos == EYE_LIGHT ) {
lightpos = SCENE_LIGHT;
printf("Light position fixed in scene\n");
} else if ( lightpos == SCENE_LIGHT ) {
lightpos = EYE_LIGHT;
printf("Light position attached to viewpoint\n");
}
glutPostRedisplay();
break;
case KEY_ESC: /* Exit when 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) {
switch (button) {
case GLUT_LEFT_BUTTON:
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;
}
}
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 = 60.0;
azimAngle = 0.0;
fovy = 60.0; /* Field of view in Y angle */
}
GLvoid
reshape( GLsizei width, GLsizei height )
{
GLdouble aspect;
glViewport( 0, 0, width, height );
aspect = (GLdouble) width / (GLdouble) height;
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( fovy, aspect, nearClip, farClip );
glMatrixMode( GL_MODELVIEW );
}
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 )
{
/* Define a few materials properties */
GLfloat redAmbient[] = { 0.3, 0.1, 0.1, 1.0 };
GLfloat redDiffuse[] = { 1.0, 0.0, 0.0, 1.0 };
GLfloat blueAmbient[] = { 0.1, 0.1, 0.3, 1.0 };
GLfloat blueDiffuse[] = { 0.0, 0.0, 1.0, 1.0 };
GLfloat yellowDiffuse[] = { 1.0, 1.0, 0.0, 1.0 };
GLfloat yellowEmission[] = { 0.6, 0.6, 0.0, 1.0 };
GLfloat defaultEmission[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat whiteSpecular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat greenSpecular[] = { 0.0, 1.0, 0.0, 1.0 };
GLfloat defaultSpecular[] = { 0.0, 0.0, 0.0, 1.0 };
/* infinite light */
GLfloat lightPosition[] = { 0.0, 0.0, 1.0, 0.0 };
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
if ( lightpos == EYE_LIGHT ) {
/* By setting the light position before the viewing
* transformation, the light moves with the eye.
* (In other words, it is always in the same
* position relative to the viewpoint.)
*/
glLightfv( GL_LIGHT0, GL_POSITION, lightPosition);
}
polarView( distance, azimAngle, incAngle, twistAngle );
XYZaxes();
if ( lightpos == SCENE_LIGHT ) {
/* By setting the light positions after the
* viewing transformation, the light(s) will
* be fixed in the scene.
*/
glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );
}
glEnable( GL_LIGHTING );
glMaterialfv( GL_FRONT, GL_EMISSION, defaultEmission );
/* Set properties for a shiny red material,
* with a green highlight */
glMaterialfv( GL_FRONT, GL_AMBIENT, redAmbient );
glMaterialfv( GL_FRONT, GL_DIFFUSE, redDiffuse );
glMaterialfv( GL_FRONT, GL_SPECULAR, greenSpecular );
glMaterialf( GL_FRONT, GL_SHININESS, 128.0 );
glPushMatrix();
glTranslatef( -2.0, 1.5, 0.0 );
glutSolidSphere( 0.7, 31, 31 );
glPopMatrix();
/* Set properties for a dull blue material with
* a small white highlight */
glMaterialfv( GL_FRONT, GL_AMBIENT, blueAmbient );
glMaterialfv( GL_FRONT, GL_DIFFUSE, blueDiffuse );
glMaterialfv( GL_FRONT, GL_SPECULAR, whiteSpecular );
glMaterialf( GL_FRONT, GL_SHININESS, 20.0 );
glPushMatrix();
glTranslatef( 2.5, 0.0, 0.0 );
glutSolidTorus( 0.25, 0.75, 16, 31 );
glPopMatrix();
/* Set properties for a yellow glowing material */
glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, yellowDiffuse);
glMaterialfv( GL_FRONT, GL_EMISSION, yellowEmission );
glMaterialfv( GL_FRONT, GL_SPECULAR, defaultSpecular );
glPushMatrix();
glTranslatef( 0.0, 2.0, 2.0 );
glutSolidCube( 0.5 );
glPopMatrix();
glDisable( GL_LIGHTING );
glPopMatrix();
glutSwapBuffers();
}
Notes:
This program demonstrates how the modelview matrix affects the light position. Pressing the <l> key toggles between a light fixed in the scene and a light that moves with the viewpoint.
The program enables the default light (a white light with a white specular component) in initgfx(). In drawScene(), the light is specified as an infinite light shining from the positive z direction (0, 0, 1) toward the origin.
The program begins with the light attached to the eye. It binds the light before the viewing transformation. The light is always coming from the position of the eye, towards the scene, no matter where the viewpoint is located. Notice how the sides of the objects facing the screen are always lit.
When the <l> key is pressed, the program toggles the light position so that the light is fixed in the scene. It does this by binding the light after the viewing transformations, but before the modeling transformations. This forces the light to always be positioned at the same location within the scene. Note that as the viewpoint moves, the same side of the sphere is always lit.
To create a light source that moves in your scene, bind the light after your viewing transformation and give the light source its own modeling transformations
/* viewing transformation */
polarView( ... );
glPushMatrix();
/* light transformations */
glRotatef( ... );
glTranslatef( ... );
/* bind light */
glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );
/* draw a small (unlit) white sphere to
* represent the light in our scene. */
glColor3f( 1.0, 1.0, 1.0 );
glutSolidSphere( 0.07, 4, 7 );
glPopMatrix();
glEnable( GL_LIGHTING );
Notes:
If desired, you can create an object to represent the light source.
Note: This code segment does not enable lighting until after drawing the object that represents the light. Therefore, the object representing the light is not lit.
The call to glEnable() does not affect the positioning of the light source itself. The position of the light source is only affected by the ModelView matrix. It does not depend on whether lighting is actually enabled when glLightfv() is called.
GLvoid glLightModelfv(GLenum pname, const GLfloat *params)
| pname | Default Value | Description |
|---|---|---|
| GL_LIGHT_MODEL_AMBIENT | (0.2, 0.2, 0.2, 1.0) | Specifies global ambient illumination; not from any particular light source |
| GL_LIGHT_MODEL_LOCAL_VIEWER | 0.0 (infinite) | Specifies whether viewer is local to the scene or an infinite distance away |
| GL_LIGHT_MODEL_TWO_SIDE | 0.0 (one-sided) | Specifies whether to perform lighting calculations for both the front and back surfaces |
Notes:
GL_LIGHT_MODEL_AMBIENT specifies the ambient light color when no lights are on. It represents light that is not from any particular source. The default value {0.2, 0.2, 0.2, 1.0} yields a small amount of white ambient light. So, even if you do not add a specific light source to your scene, you can still see the objects in the scene.
GL_LIGHT_MODEL_LOCAL_VIEWER changes the assumptions made about the location of the viewpoint. (It does not actually move the viewpoint).
/* movingLight.c - Set up a light that moves independent
* of the objects in the scene.
*
* 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
* <a> key - toggle light animation
* <m> key - toggle local/infinite viewer
* Escape key - exit the program
*/
#include <GL/glut.h> /* includes gl.h, glu.h */
#include <math.h>
#include <stdio.h>
/* Function Prototypes */
GLvoid initgfx( GLvoid );
GLvoid animate( GLvoid );
GLvoid visibility( GLint );
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 */
static GLfloat lightAngle = 0.0; /* controls light rotation */
static GLboolean animateLight = GL_TRUE;
static GLboolean localLight = GL_FALSE;
enum actions { MOVE_EYE, TWIST_EYE, ZOOM, MOVE_NONE };
static GLint action;
static GLdouble xStart = 0.0, yStart = 0.0;
static GLfloat fovy, 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 / 4, height / 4 );
glutInitWindowSize( (width / 2) - 4, height / 2 );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutCreateWindow( argv[0] );
initgfx();
glutIdleFunc( animate );
glutVisibilityFunc( visibility );
glutMouseFunc( mouse );
glutMotionFunc( motion );
glutKeyboardFunc( keyboard );
glutReshapeFunc( reshape );
glutDisplayFunc( drawScene );
printHelp( argv[0] );
glutMainLoop();
}
void
printHelp( char *progname )
{
fprintf(stdout, "\n%s - demonstrate how to add a moving light\n\n"
"Left Mousebutton - move eye position\n"
"Middle Mousebutton - change twist angle\n"
"Right Mousebutton - move up / down to zoom in / out\n"
"<a> Key - toggle light animation\n"
"<m> Key - toggle local/infinite viewer\n"
"Escape Key - exit the program\n\n",
progname);
}
GLvoid
initgfx( GLvoid )
{
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glEnable( GL_DEPTH_TEST );
nearClip = 2.0; /* Near clipping plane location */
farClip = 15.0; /* Far clipping plane location */
resetView();
/* Turn on a default light */
glEnable( GL_LIGHT0 );
}
GLvoid
keyboard( GLubyte key, GLint x, GLint y )
{
GLfloat infinite[] = {0.0};
GLfloat local[] = {1.0};
switch (key) {
case 'a': /* toggle light animation */
animateLight = !animateLight;
if ( animateLight )
glutIdleFunc(animate);
else
glutIdleFunc(NULL);
glutPostRedisplay();
break;
case 'm': /* toggle lighting model */
localLight = !localLight;
if ( localLight )
{
glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local);
printf("local viewer ON\n");
}
else
{
glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, infinite);
printf("local viewer OFF\n");
}
glutPostRedisplay();
break;
case KEY_ESC: /* Exit when 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) {
switch (button) {
case GLUT_LEFT_BUTTON:
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;
}
}
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 = 60.0;
azimAngle = 0.0;
fovy = 60.0; /* Field of view in Y angle */
}
GLvoid
reshape( GLsizei width, GLsizei height )
{
GLdouble aspect;
glViewport( 0, 0, width, height );
aspect = (GLdouble) width / (GLdouble) height;
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( fovy, aspect, nearClip, farClip );
glMatrixMode( GL_MODELVIEW );
}
GLvoid
animate( GLvoid )
{
/* update the rotation of the light for each scene */
lightAngle = fmod( (lightAngle + 2.0), 360.0 );
/* Tell GLUT to redraw the scene */
glutPostRedisplay();
}
GLvoid
visibility( int state )
{
if (state == GLUT_VISIBLE && animateLight) {
glutIdleFunc( animate );
} else {
glutIdleFunc( NULL );
}
}
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 )
{
/* Define a few materials properties */
GLfloat redAmbient[] = { 0.3, 0.1, 0.1, 1.0 };
GLfloat redDiffuse[] = { 1.0, 0.0, 0.0, 1.0 };
GLfloat blueAmbient[] = { 0.1, 0.1, 0.3, 1.0 };
GLfloat blueDiffuse[] = { 0.0, 0.0, 1.0, 1.0 };
GLfloat defaultEmission[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat whiteSpecular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat greenSpecular[] = { 0.0, 1.0, 0.0, 1.0 };
GLfloat defaultSpecular[] = { 0.0, 0.0, 0.0, 1.0 };
/* local light */
GLfloat lightPosition[] = { 0.0, 0.0, 0.0, 1.0 };
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
polarView( distance, azimAngle, incAngle, twistAngle );
XYZaxes();
/* Animate the light with its own set of transformations */
glPushMatrix();
glRotatef( lightAngle, 0.0, 1.0, 1.0 );
glTranslatef( 2.7, 0.0, 0.0 );
/* By giving the light position its own modeling
* transformations (due to the glPushMatrix()
* and glPopMatrix() calls), the light moves
* independently of the objects in the scene.
*/
glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );
/* draw a small (unlit) white sphere to
* represent the light in our scene.
*/
glColor3f( 1.0, 1.0, 1.0 );
glutSolidSphere( 0.07, 4, 7);
glPopMatrix();
glEnable( GL_LIGHTING );
glMaterialfv( GL_FRONT, GL_EMISSION, defaultEmission );
/* Set properties for a shiny red material,
* with a green highlight */
glMaterialfv( GL_FRONT, GL_AMBIENT, redAmbient );
glMaterialfv( GL_FRONT, GL_DIFFUSE, redDiffuse );
glMaterialfv( GL_FRONT, GL_SPECULAR, greenSpecular );
glMaterialf( GL_FRONT, GL_SHININESS, 128.0 );
glPushMatrix();
glTranslatef( -2.5, 0.5, 0.0 );
glutSolidSphere( 0.7, 31, 31 );
glPopMatrix();
glPushMatrix();
glTranslatef( 1.0, 2.0, 2.0 );
glutSolidSphere( 0.9, 31, 31 );
glPopMatrix();
/* Set properties for a dull blue material with
* a small white highlight */
glMaterialfv( GL_FRONT, GL_AMBIENT, blueAmbient );
glMaterialfv( GL_FRONT, GL_DIFFUSE, blueDiffuse );
glMaterialfv( GL_FRONT, GL_SPECULAR, whiteSpecular );
glMaterialf( GL_FRONT, GL_SHININESS, 20.0 );
glPushMatrix();
glTranslatef( 2.5, 0.0, 0.0 );
glutSolidTorus( 0.25, 0.75, 16, 31 );
glPopMatrix();
glDisable( GL_LIGHTING );
glPopMatrix();
glutSwapBuffers();
}
Notes:
This program demonstrates how the position of the light can be made to move in a scene. By giving the light source its own transformations, it acts like any other object in the scene. The program uses a small, (unlit) white sphere to represent the light, but the light source would still behave the same way even if the program did not create an object to represent it.
Run movingLight and try to stop the light inside the torus. Then move around so the torus is sideways (so you cannot see the sphere). What is odd about this scene? The light still shines on the sphere even though it is blocked by the torus.
OpenGL lighting does not do any checking for objects that obscure one another. You would have to do your own ray tracing for this.
Light sources do not contribute to the ambient lighting in a scene unless you so specify.
GLvoid glLightfv( GLenum light, GL_AMBIENT,
const GLfloat *params )
Notes:
The GL_AMBIENT parameter refers to the RGBA intensity of the ambient light that a particular light source adds to the scene.
By default, light sources do not contribute to the ambient lighting in a scene. That is, the default ambient intensity is (0.0, 0.0, 0.0, 1.0) for all lights.
GLvoid glLightfv( GLenum light, GL_DIFFUSE,
const GLfloat *params )

Notes:
The color components specified for lights mean something different than for materials. For a light, the numbers correspond to a percentage of full intensity for each color. For example, if the R, G, and B values for a light's color are all 1.0, the light is the brightest possible white. If the values are 0.5, the color is still white but only at half intensity so it appears gray. If R=G=1 and B=0 (full red and green with no blue), the light appears yellow.
The GL_DIFFUSE parameter probably most closely correlates with what you naturally think of as "the color of a light." It defines the RGBA color of the diffuse light that a particular light source adds to a scene.
By default, GL_DIFFUSE is (1.0, 1.0, 1.0, 1.0) for GL_LIGHT0, which produces a bright white light.
The default value for any other light (GL_LIGHT1, ... , GL_LIGHTn) is (0.0, 0.0, 0.0, 0.0), which produces no light.
GLvoid glLightfv( GLenum light, GL_SPECULAR,
const GLfloat *params )

Notes:
The GL_SPECULAR parameter affects the color of the specular highlight on an object. Typically, a real-world object (such as a glass bottle) has a specular highlight that is the color of the light shining on it, which is often white.
Therefore, to create a realistic effect, set the GL_SPECULAR parameter to the same value as the GL_DIFFUSE parameter.
By default, GL_SPECULAR is (1.0, 1.0, 1.0, 1.0) for GL_LIGHT0, which produces a bright, white specular component.
The default value for any other light (GL_LIGHT1, ... , GL_LIGHTn) is (0.0, 0.0, 0.0, 0.0), which produces no specular component.
The color at each vertex is the sum of

Notes:
See the module summary for a more detailed description of each of the terms.
/* lightIntensity.c - Use light properties to change the intensity
* of the light in our scene.
*
* 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
* <a> Key - toggle ambient light intensity on/off
* <d> Key - toggle diffuse light intensity on/off
* <s> Key - toggle specular light intensity on/off
* <R> Key - reset viewpoint
* Escape key - exit the program
*/
#include <GL/glut.h> /* includes gl.h, glu.h */
#include <math.h>
#include <stdio.h>
/* 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 );
GLvoid toggleAmbient( GLvoid );
GLvoid toggleDiffuse( GLvoid );
GLvoid toggleSpecular( GLvoid );
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 fovy, nearClip, farClip;
static GLfloat distance, twistAngle, incAngle, azimAngle;
static GLfloat angle = 0.0;
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 | 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 - demonstrate light intensity properties\n\n"
"Left Mousebutton - move eye position\n"
"Middle Mousebutton - change twist angle\n"
"Right Mousebutton - move up / down to zoom in / out\n"
"<a> Key - toggle ambient light intensity on/off\n"
"<d> Key - toggle diffuse light intensity on/off\n"
"<s> Key - toggle specular light intensity on/off\n"
"<R> Key - reset viewpoint\n"
"Escape Key - exit the program\n\n",
progname);
}
GLvoid
initgfx( GLvoid )
{
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glEnable( GL_DEPTH_TEST );
fovy = 60.0; /* field of view in Y */
nearClip = 3.0; /* Near clipping plane location */
farClip = 12.0; /* Far clipping plane location */
resetView();
/* Turn on a default light */
glEnable( GL_LIGHT0 );
}
GLvoid
toggleAmbient( GLvoid )
{
/* Set up intensities for the light */
static GLfloat ambientIntensity[] = { 0.2, 0.0, 0.2, 1.0 };
static GLfloat defaultAmbient[] = { 0.0, 0.0, 0.0, 1.0 };
static GLboolean useDefault = GL_TRUE;
useDefault = !useDefault;
if (useDefault)
glLightfv( GL_LIGHT0, GL_AMBIENT, defaultAmbient );
else
glLightfv( GL_LIGHT0, GL_AMBIENT, ambientIntensity );
}
GLvoid
toggleDiffuse( GLvoid )
{
static GLfloat diffuseIntensity[] = { 0.0, 0.1, 1.0, 1.0 };
static GLfloat defaultDiffuse[] = { 1.0, 1.0, 1.0, 1.0 };
static GLboolean useDefault = GL_TRUE;
useDefault = !useDefault;
if (useDefault)
glLightfv( GL_LIGHT0, GL_DIFFUSE, defaultDiffuse );
else
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuseIntensity );
}
GLvoid
toggleSpecular( GLvoid )
{
static GLfloat specularIntensity[] = { 1.0, 0.0, 1.0, 1.0 };
static GLfloat defaultSpecular[] = { 1.0, 1.0, 1.0, 1.0 };
static GLboolean useDefault = GL_TRUE;
useDefault = !useDefault;
if (useDefault)
glLightfv( GL_LIGHT0, GL_SPECULAR, defaultSpecular );
else
glLightfv( GL_LIGHT0, GL_SPECULAR, specularIntensity );
}
GLvoid
keyboard( GLubyte key, GLint x, GLint y )
{
switch (key) {
case 'a': /* toggle ambient intensity */
toggleAmbient();
break;
case 'd': /* toggle Diffuse intensity */
toggleDiffuse();
break;
case 's': /* toggle Specular intensity */
toggleSpecular();
break;
case 'R':
resetView();
glutPostRedisplay();
break;
case KEY_ESC: /* Exit whenever the Escape key is pressed */
exit(0);
}
glutPostRedisplay();
}
GLvoid
mouse( GLint button, GLint state, GLint x, GLint y )
{
static GLint buttons_down = 0;
if (state == GLUT_DOWN) {
switch (button) {
case GLUT_LEFT_BUTTON:
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;
}
}
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 = 60.0;
azimAngle = 0.0;
fovy = 60.0; /* Field of view in Y angle */
}
GLvoid
reshape( GLsizei width, GLsizei height )
{
GLdouble aspect;
glViewport( 0, 0, width, height );
aspect = (GLdouble) width / (GLdouble) height;
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( fovy, aspect, nearClip, farClip );
glMatrixMode( GL_MODELVIEW );
}
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 )
{
/* Define a few materials properties */
GLfloat redAmbient[] = { 0.3, 0.1, 0.1, 1.0 };
GLfloat redDiffuse[] = { 1.0, 0.0, 0.0, 1.0 };
GLfloat blueAmbient[] = { 0.1, 0.1, 0.3, 1.0 };
GLfloat blueDiffuse[] = { 0.0, 0.0, 1.0, 1.0 };
GLfloat yellowDiffuse[] = { 1.0, 1.0, 0.0, 1.0 };
GLfloat yellowEmission[] = { 0.6, 0.6, 0.0, 1.0 };
GLfloat defaultEmission[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat whiteSpecular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat greenSpecular[] = { 0.0, 1.0, 0.0, 1.0 };
GLfloat defaultSpecular[] = { 0.0, 0.0, 0.0, 1.0 };
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
polarView( distance, azimAngle, incAngle, twistAngle );
XYZaxes();
glEnable( GL_LIGHTING );
glMaterialfv( GL_FRONT, GL_EMISSION, defaultEmission );
/* Set properties for a shiny red material,
* with a green highlight */
glMaterialfv( GL_FRONT, GL_AMBIENT, redAmbient );
glMaterialfv( GL_FRONT, GL_DIFFUSE, redDiffuse );
glMaterialfv( GL_FRONT, GL_SPECULAR, greenSpecular );
glMaterialf( GL_FRONT, GL_SHININESS, 128.0 );
glPushMatrix()
glTranslatef( -2.0, 1.5, 0.0 );
glutSolidSphere( 0.7, 31, 31 );
glPopMatrix();
/* Set properties for a dull blue material with
* a small white highlight */
glMaterialfv( GL_FRONT, GL_AMBIENT, blueAmbient );
glMaterialfv( GL_FRONT, GL_DIFFUSE, blueDiffuse );
glMaterialfv( GL_FRONT, GL_SPECULAR, whiteSpecular );
glMaterialf( GL_FRONT, GL_SHININESS, 20.0 );
glPushMatrix();
glTranslatef( 2.5, 0.0, 0.0 );
glutSolidTorus( 0.25, 0.75, 16, 31 );
glPopMatrix();
/* Set properties for a yellow glowing material */
glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, yellowDiffuse);
glMaterialfv( GL_FRONT, GL_EMISSION, yellowEmission );
glMaterialfv( GL_FRONT, GL_SPECULAR, defaultSpecular );
glPushMatrix();
glTranslatef( 0.0, 2.0, 2.0 );
glutSolidCube( 0.5 );
glPopMatrix();
glDisable( GL_LIGHTING );
glPopMatrix();
glutSwapBuffers();
}
Notes:
When the diffuse, ambient and specular intensities are not the default, the objects are affected as follows:
Sphere -- the diffuse intensity is mostly green and the diffuse reflectance is all red, so no diffuse light is reflected. However, the ambient light intensity and the ambient reflectance both have some red and blue in them, so the object will look dark purple. There will be no specular highlight since the specular intensity is red and blue, and the specular reflectance is green.
Torus -- the diffuse reflectance is all blue, so the torus will reflect 100% blue diffuse intensity and none of the green, making it look blue. The ambient reflectance will be somewhat purple. The specular highlight should be purple.
Cube -- the diffuse reflectance is yellow (red and green) and the diffuse intensity is mostly blue, with a bit of green. The object should look green; however, the yellow emission forces it to be yellow. Because the ambient reflectance is the default (0.2, 0.2, 0.2), the edges that don't face the eye are grayish. It uses the default specular intensity (black) so there is no specular highlight.
This lab has two parts: tutorials, and programming.
Notes:
* Indicates an optional laboratory exercise.
GLvoid glEnable( GL_LIGHTING ) GLvoid glDisable( GL_LIGHTING )
Turn lighting calculations on or off.
GLvoid glEnable( GL_LIGHT<n> ) GLvoid glDisable( GL_LIGHT<n> )
Enable or disable light source n.
GLvoid glLight[if]( GLenum light, GLenum pname, TYPE param ) GLvoid glLight[if]v( GLenum light, GLenum pname, TYPE *param )
Specify light source properties. light is GL_LIGHT<n>. pname
is one of GL_SPOT_EXPONENT, GL_SPOT_CUTOFF, GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION,
and GL_QUADRATIC_ATTENUATION.
GLvoid glEnable( GL_NORMALIZE ) GLvoid glDisable( GL_NORMALIZE )
Enable or disable automatic normalization of normal vectors.
GLvoid glNormal3[bsidf]( TYPE nx, TYPE ny, TYPE nz ) GLvoid glNormal3[bsidf]v( const TYPE *v )
Specify a normal vector, which becomes the normal for all successive
vertices until the next call to glNormal3*(). Causes the color
of each vertex to be computed if lighting is active.
GLvoid glMaterial[if]( GLenum face, GLenum pname, TYPE param ) GLvoid glMaterial[if]v( GLenum face, GLenum pname, TYPE *param )
Specify material reflection properties. face can be GL_FRONT, GL_BACK,
or GL_FRONT_AND_BACK. For glMaterial[if], pname
must be GL_SHININESS. For glMaterial[if]v, pname
can be GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION, GL_SHININESS, GL_AMBIENT_AND_DIFFUSE,
or GL_COLOR_INDEXES.
GLvoid glEnable( GL_COLOR_MATERIAL ) GLvoid glDisable( GL_COLOR_MATERIAL )
Enable or disable fast material changes via glColorMaterial().
GLvoid glColorMaterial( GLenum face, GLenum property )
Makes all subsequent glColor*() calls affect material properties. Often faster than using glMaterial*() when changing only one property rapidly. Valid face values are the same as for glMaterial*. property can be GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION, or GL_AMBIENT_AND_DIFFUSE.
Download the new version of eliteutils.h
and eliteutils.c. Here is the new
version of drawEliteObject (called drawEliteObject2) used to draw coriolis using
lighting with the Non-Photorealistic Rendering (NPR).
Our new version of mElite has to use lighting. New features to add (emphasised in the
the proposed solution code with the word "NEW" in the comments) are: