OpenGL Examples[1]
OpenGL Examples[1]
Here are some OpenGL example programs, presented in an order in which new topics are added in each
successive example. Many of these are modi cations of programs in the OpenGL Red Book.
CONTENTS
Triangle • Tetrahedron • Torus • Sierpinski2D • Sierpinski3D • Spinning Square • Interactive Robot Arm • Color Cube Flyby • Comet Ride • Lit
Solids • Phases of the Moon • Bouncing Balls • Flight Simulator • Fish Bitmaps • Checkered Triangles
Triangle
Introductory program; just a static picture of a colored
triangle.
Shows how to use GLUT.
Has minimal structure: only main() and a display
callback.
Uses only the default viewing parameters (in fact, it
never mentions viewing at all). This is an orthographic
view volume with bounds of -1..1 in all three dimensions.
Draws only using glColor and glVertex within glBegin
and glEnd in the display callback.
Uses only the GL_POLYGON drawing mode.
Illustrates glClear and glFlush .
triangle.cpp
// A simple introductory program; its main window contains a static picture
// of a triangle, whose three vertices are red, green and blue. The program
// illustrates viewing with default viewing parameters only.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
// Set every pixel in the frame buffer to the current clear color.
glClear(GL_COLOR_BUFFER_BIT);
// Initializes GLUT, the display mode, and main window; registers callbacks;
// enters the main event loop.
int main(int argc, char**
char argv) {
// Tell GLUT that whenever the main window needs to be repainted that it
// should call the function display().
glutDisplayFunc(display);
Tetrahedron
Displays a static picture of a tetrahedron sitting on a grid
" oor".
Sets up a viewing volume at the beginning of the
program. Uses glFrustum in order to make a perspective
projection.
Shows that you have to de ne the viewing volume when
the matrix mode is GL_PROJECTION .
Draws the object in the display callback using GL_LINES
and GL_TRIANGLE_STRIP modes.
De nes the object at the origin then moves it INTO the
view volume.
Shows that the rotations and translations that move the
object into the view volume must be performed when the matrix mode is GL_MODELVIEW .
Shows that if you are not doing animation it is best to de ne the transformations that position and orient the
object should be done only once, and not inside the display callback.
Shows that transformations are cumulative.
Shows that before setting up view volumes or object transformations, you usually want to do a
glLoadIdentity or else transforamtions from previous manipulations will accumulate.
Does backface culling as a very cheap way to do hidden surface removal. This does not work in all cases.
tetrahedron.cpp
// This is a simple introductory program; its main window contains a static
// picture of a tetrahedron, whose top vertex is white and whose bottom
// vertices are red, green and blue. The program illustrates viewing by
// defining an object at a convenient location, then transforming it so that
// it lies within the view volume. This is a lousy way to do things (it's
// easier to use gluLookAt()), but it's nice to see how viewing is done at
// a very low level.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
// Clears the window and draws the tetrahedron. The tetrahedron is easily
// specified with a triangle strip, though the specification really isn't very
// easy to read.
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
}
// Sets up global attributes like clear color and drawing color, enables and
// initializes any needed modes (in this case we want backfaces culled), and
// sets up the desired projection and modelview matrices. It is cleaner to
// define these operations in a function separate from main().
void init() {
// Set the current clear color to sky blue and the current drawing color to
// white.
glClearColor(0.1, 0.39, 0.88, 1.0);
glColor3f(1.0, 1.0, 1.0);
// Tell the rendering engine not to draw backfaces. Without this code,
// all four faces of the tetrahedron would be drawn and it is possible
// that faces farther away could be drawn after nearer to the viewer.
// Since there is only one closed polyhedron in the whole scene,
// eliminating the drawing of backfaces gives us the realism we need.
// THIS DOES NOT WORK IN GENERAL.
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// Set the camera lens so that we have a perspective viewing volume whose
// horizontal bounds at the near clipping plane are -2..2 and vertical
// bounds are -1.5..1.5. The near clipping plane is 1 unit from the camera
// and the far clipping plane is 40 units away.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-2, 2, -1.5, 1.5, 1, 40);
// Initializes GLUT, the display mode, and main window; registers callbacks;
// does application initialization; enters the main event loop.
int main(int argc, char**
char argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(80, 80);
glutInitWindowSize(800, 600);
glutCreateWindow("A Simple Tetrahedron");
glutDisplayFunc(display);
init();
glutMainLoop();
}
Torus
Display a static picture of a torus and the coordinate
system axes.
Instead of using a primitive GL function (such as
glOrtho or glFrustum ) to set the viewing volume, it
instead uses gluPerspective . gluPerspective must be
done when the matrix mode is GL_PROJECTION .
Instead of using translates and rotates to position the
objects into the view volume, it instead uses gluLookAt
to position and orient the camera so that it is looking at
the objects. gluLookAt must be done when the matrix
mode is GL_MODELVIEW .
Shows that the combination of gluPerspective and
gluLookAt is considerably more intuitive than the more primitive mechanism of glFrustum and plain object
transformations.
Draws the torus using the fancy glutWireTorus function (which internally calls glVertex a zillion times).
torus.cpp
// This is a simple introductory program; its main window contains a static
// picture of a torus. The program illustrates viewing by choosing a camera
// setup with gluLookAt(), which is conceptually simpler than transforming
// objects to move into a predefined view volume.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
glClear(GL_COLOR_BUFFER_BIT);
// Draw a white torus of outer radius 3, inner radius 0.5 with 15 stacks
// and 30 slices.
glColor3f(1.0, 1.0, 1.0);
glutWireTorus(0.5, 3, 15, 30);
// Draw a red x-axis, a green y-axis, and a blue z-axis. Each of the
// axes are ten units long.
glBegin(GL_LINES);
glColor3f(1, 0, 0); glVertex3f(0, 0, 0); glVertex3f(10, 0, 0);
glColor3f(0, 1, 0); glVertex3f(0, 0, 0); glVertex3f(0, 10, 0);
glColor3f(0, 0, 1); glVertex3f(0, 0, 0); glVertex3f(0, 0, 10);
glEnd();
glFlush();
}
// Sets up global attributes like clear color and drawing color, and sets up
// the desired projection and modelview matrices.
void init() {
// Set the current clear color to black and the current drawing color to
// white.
glClearColor(0.0, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
// Initializes GLUT, the display mode, and main window; registers callbacks;
// does application initialization; enters the main event loop.
int main(int argc, char**
char argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(80, 80);
glutInitWindowSize(800, 600);
glutCreateWindow("A Simple Torus");
glutDisplayFunc(display);
init();
glutMainLoop();
}
Sierpinski2D
Draws 100000 points of a Sierpinski Gasket.
Draws with GL_POINTS.
Illustrates poor programming practice: the display
callback contains long-running code. We get away with it
here because we only have to generate 100000 points.
The program will appear to hang if you wanted to draw,
say, twenty million points.
Ilustrates some C++, namely a struct with a member
function.
Note that the glFlush call is made after all 100000
points have been drawn, not after each point.
sierpinski2d.cpp
// This program generates a Sierpinski gasket with 10000 points.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cstdlib>
// Draws a Sierpinski triangle with a fixed number of points. (Note that the
// number of points is kept fairly small because a display callback should
// NEVER run for too long.
void display() {
glClear(GL_COLOR_BUFFER_BIT);
// Compute and plot 100000 new points, starting (arbitrarily) with one of
// the vertices. Each point is halfway between the previous point and a
// randomly chosen vertex.
static Point p = vertices[0];
glBegin(GL_POINTS);
for (int k = 0; k < 100000; k++) {
p = p.midpoint(vertices[rand() % 3]);
glVertex2f(p.x, p.y);
}
glEnd();
glFlush();
}
// Set up the viewing volume: 500 x 500 x 1 window with origin lower left.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 500.0, 0.0, 500.0, 0.0, 1.0);
}
// Initializes GLUT, the display mode, and main window; registers callbacks;
// does application initialization; enters the main event loop.
int main(int argc, char**
char argv) {
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(40, 40);
glutCreateWindow("Sierpinski Triangle");
glutDisplayFunc(display);
init();
glutMainLoop();
}
Sierpinski3D
Draws points in the iteration of a 3-D Sierpinski Gasket
for as long as the program runs.
Illustrates the right way to perfom long-running drawing:
in bursts during the idle time callback. The display
callback doesn't do any drawing, other than clearing the
windows (er, color buffer, I mean).
Uses depth buffering so that points that would appear
behind points already drawn will not themselves be
drawn.
Shows that depth buffering must be done by specifying
the GL_DEPTH ag in glutInitDisplayMode and enable
GL_DEPTH_TEST .
Illustrates the reshape callback, which is absolutely essential for preserving the aspect ratio of the drawing.
Shows that in order to preserve the aspect ration of the drawing, you set up the camera (in this case using
gluPerspective ) every time the window is reshaped. Note that the reshape callback is automatically called by
GLUT shortly after the windowing system creates your window, so you don't need to force a call to a camera
setup at the beginning of your program.
Sets colors based on depth to make the picture look pretty cool.
sierpinski3d.cpp
// This program is a modification and extension of an early program in Edward
// Angel's book, Interactive Computer Graphics: A top-down approach using
// OpenGL. It plots the 3-D Sierpinski Tetrahedron using colors in a nice
// way.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cstdlib>
// Handles reshape requests by setting the the viewport to exactly match the
// pixel coordinates, so we can draw in the whole window. Then sets up a
// simple perspective viewing volume to ensure that the pyramid will never
// be distorted when the window is reshaped. The particular settings chosen
// ensure that the vertical extent of the pyramid will always be visible.
void reshape(GLint w, GLint h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(100.0, GLfloat(w)/GLfloat(h), 10.0, 1500.0);
}
// Draws the "next 500 points". The function contains locally the definitions
// of the vertices and the current point as static objects so that their values
// are retained between calls.
void generateMorePoints() {
// The tetrahedron has four vertices. We also have to keep track of the
// current point during the plotting.
static Point vertices[4] = {
Point(-250, -225, -200),
Point(-150, -225, -700),
Point(250, -225, -275),
Point(0, 450, -500)
};
static Point lastPoint = vertices[0];
// Here is the code to draw the "next 500 points". The closer the point is
// to the camera, the brighter we make it. The coloring technique is a
// quick hack which (unprofessionally) depends on the fact that the range
// of z-coordinates in the tetrahedron run from -200 to -700. By adding
// 700 to any z-value and then dividing by 500, we get values in the range
// 0 to 1 - just perfect for coloring.
glBegin(GL_POINTS);
for (int i = 0; i <= 500; i++) {
lastPoint = lastPoint.midpoint(vertices[rand() % 4]);
GLfloat intensity = (700 + lastPoint.z) / 500.0;
glColor3f(intensity, intensity, 0.25);
glVertex3f(lastPoint.x, lastPoint.y, lastPoint.z);
}
glEnd();
glFlush();
}
// Initializes GLUT, the display mode, and main window; registers callbacks;
// does application initialization; enters the main event loop.
int main(int argc, char**
char argv) {
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("Sierpinski Tetrahedron");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(generateMorePoints);
init();
glutMainLoop();
}
Spinning Square
Animates a spinning square.
Illustrates animation with double buffering. This requires
passing GLUT_DOUBLE to glutInitDisplayMode ,
generating the parameters for the next animation frame
in the timer callback which posts a redisplay request,
and nishing off the display callback with a call to
glutSwapBuffers .
Shows that it is better to accumulate transformation
parameters, rather than the transformations themselves,
when doing cyclical animation.
Illustrates the mouse callback.
Shows that callbacks can be removed. In this case, the
idle callback gets removed.
Shows that maintaining the aspect ratio of a drawing when an orthographic projection is used is a bigger pain
than doing so with a perspective projection using gluPerspective .
spinningsquare.cpp
// This program demonstrates double buffering for flicker-free animation.
// It spins a white square on a black background. It comes from Chapter 1
// of the OpenGL Programming Guide, but I made some minor changes, and did
// the animation properly, using timers, not the idle function. Start the
// animation with the left mouse button and stop it with the right.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
// This global variable keeps track of the current orientation of the square.
// It is better to maintain the "state" of the animation globally rather
// than trying to successively accumulate transformations. Over a period of
// time the approach of accumulating transformation matrices generally
// degrades due to rounding errors.
static GLfloat currentAngleOfRotation = 0.0;
// Handles the window reshape event by first ensuring that the viewport fills
// the entire drawing surface. Then we use a simple orthographic projection
// with a logical coordinate system ranging from -50..50 in the smaller of
// the width or height, and scale the larger dimension to make the whole
// window isotropic.
void reshape(GLint w, GLint h) {
glViewport(0, 0, w, h);
GLfloat aspect = (GLfloat)w / (GLfloat)h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h) {
// width is smaller, go from -50 .. 50 in width
glOrtho(-50.0, 50.0, -50.0/aspect, 50.0/aspect, -1.0, 1.0);
} else {
// height is smaller, go from -50 .. 50 in height
glOrtho(-50.0*aspect, 50.0*aspect, -50.0, 50.0, -1.0, 1.0);
}
}
// Handles the display callback as follows: first clears the window, then draws
// a 50 x 50 rectangle centered at the origin and rotated the correct number
// of degrees around the vector <0,0,1>. This function ends with a
// 'glutSwapBuffers' call because when the display mode is double buffered,
// drawing takes place on the back buffer; we have to call glutSwapBuffers()
// to show what we have drawn.
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(currentAngleOfRotation, 0.0, 0.0, 1.0);
glRectf(-25.0, -25.0, 25.0, 25.0);
glFlush();
glutSwapBuffers();
}
// Handles the timer by incrementing the angle of rotation and requesting the
// window to display again, provided the program is in the spinning state.
// Since the timer function is only called once, it sets the same function to
// be called again.
void timer(int v) {
if (spinning) {
currentAngleOfRotation += 1.0;
if (currentAngleOfRotation > 360.0) {
currentAngleOfRotation -= 360.0;
}
glutPostRedisplay();
}
glutTimerFunc(1000/FPS, timer, v);
}
// Handles mouse events as follows: when the left button is pressed, generate
// new animation frames while the application is idle; when the right button
// is pressed, remove any idle-time callbacks, thus stopping the animation.
void mouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
spinning = true;
true
} else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
spinning = false;
false
}
}
// Initializes GLUT, the display mode, and main window; registers callbacks;
// enters the main event loop.
int main(int argc, char**
char argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(80, 80);
glutInitWindowSize(800, 500);
glutCreateWindow("Spinning Square");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutTimerFunc(100, timer, 0);
glutMouseFunc(mouse);
glutMainLoop();
}
robotarm.cpp
// This program is from the OpenGL Programming Guide. It shows a robot arm
// that you can rotate by pressing the arrow keys.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
// The robot arm is specified by (1) the angle that the upper arm makes
// relative to the x-axis, called shoulderAngle, and (2) the angle that the
// lower arm makes relative to the upper arm, called elbowAngle. These angles
// are adjusted in 5 degree increments by a keyboard callback.
static int shoulderAngle = 0, elbowAngle = 0;
// Handles the keyboard event: the left and right arrows bend the elbow, the
// up and down keys bend the shoulder.
void special(int key, int,
int int)
int {
switch (key) {
case GLUT_KEY_LEFT: (elbowAngle += 5) %= 360; break;
break
case GLUT_KEY_RIGHT: (elbowAngle -= 5) %= 360; break;
break
case GLUT_KEY_UP: (shoulderAngle += 5) %= 360; break;
break
case GLUT_KEY_DOWN: (shoulderAngle -= 5) %= 360; break;
break
default:
default return;
return
}
glutPostRedisplay();
}
// Displays the arm in its current position and orientation. The whole
// function is bracketed by glPushMatrix and glPopMatrix calls because every
// time we call it we are in an "environment" in which a gluLookAt is in
// effect. (Note that in particular, replacing glPushMatrix with
// glLoadIdentity makes you lose the camera setting from gluLookAt).
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// Draw the upper arm, rotated shoulder degrees about the z-axis. Note that
// the thing about glutWireBox is that normally its origin is in the middle
// of the box, but we want the "origin" of our box to be at the left end of
// the box, so it needs to first be shifted 1 unit in the x direction, then
// rotated.
glRotatef((GLfloat)shoulderAngle, 0.0, 0.0, 1.0);
glTranslatef(1.0, 0.0, 0.0);
wireBox(2.0, 0.4, 1.0);
// Now we are ready to draw the lower arm. Since the lower arm is attached
// to the upper arm we put the code here so that all rotations we do are
// relative to the rotation that we already made above to orient the upper
// arm. So, we want to rotate elbow degrees about the z-axis. But, like
// before, the anchor point for the rotation is at the end of the box, so
// we translate <1,0,0> before rotating. But after rotating we have to
// position the lower arm at the end of the upper arm, so we have to
// translate it <1,0,0> again.
glTranslatef(1.0, 0.0, 0.0);
glRotatef((GLfloat)elbowAngle, 0.0, 0.0, 1.0);
glTranslatef(1.0, 0.0, 0.0);
wireBox(2.0, 0.4, 1.0);
glPopMatrix();
glFlush();
}
// Handles the reshape event by setting the viewport so that it takes up the
// whole visible region, then sets the projection matrix to something reason-
// able that maintains proper aspect ratio.
void reshape(GLint w, GLint h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(65.0, GLfloat(w)/GLfloat(h), 1.0, 20.0);
}
// Initializes GLUT, the display mode, and main window; registers callbacks;
// does application initialization; enters the main event loop.
int main(int argc, char**
char argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(80, 80);
glutInitWindowSize(800, 600);
glutCreateWindow("Robot Arm");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutSpecialFunc(special);
init();
glutMainLoop();
}
colorcube.cpp
// This program is a flyby around the RGB color cube. One intersting note
// is that because the cube is a convex polyhedron and it is the only thing
// in the scene, we can render it using backface culling only. i.e., there
// is no need for a depth buffer.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cmath>
// The cube has opposite corners at (0,0,0) and (1,1,1), which are black and
// white respectively. The x-axis is the red gradient, the y-axis is the
// green gradient, and the z-axis is the blue gradient. The cube's position
// and colors are fixed.
namespace Cube {
GLint vertices[NUM_VERTICES][3] = {
{0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1},
{1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1}};
GLint faces[NUM_FACES][4] = {
{1, 5, 7, 3}, {5, 4, 6, 7}, {4, 0, 2, 6},
{3, 7, 6, 2}, {0, 1, 3, 2}, {0, 4, 5, 1}};
GLfloat vertexColors[NUM_VERTICES][3] = {
{0.0, 0.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 1.0, 0.0}, {0.0, 1.0, 1.0},
{1.0, 0.0, 0.0}, {1.0, 0.0, 1.0}, {1.0, 1.0, 0.0}, {1.0, 1.0, 1.0}};
void draw() {
glBegin(GL_QUADS);
for (int i = 0; i < NUM_FACES; i++) {
for (int j = 0; j < 4; j++) {
glColor3fv((GLfloat*)&vertexColors[faces[i][j]]);
glVertex3iv((GLint*)&vertices[faces[i][j]]);
}
}
glEnd();
}
}
// Display and Animation. To draw we just clear the window and draw the cube.
// Because our main window is double buffered we have to swap the buffers to
// make the drawing visible. Animation is achieved by successively moving our
// camera and drawing. The function nextAnimationFrame() moves the camera to
// the next point and draws. The way that we get animation in OpenGL is to
// register nextFrame as the idle function; this is done in main().
void display() {
glClear(GL_COLOR_BUFFER_BIT);
Cube::draw();
glFlush();
glutSwapBuffers();
}
// We'll be flying around the cube by moving the camera along the orbit of the
// curve u->(8*cos(u), 7*cos(u)-1, 4*cos(u/3)+2). We keep the camera looking
// at the center of the cube (0.5, 0.5, 0.5) and vary the up vector to achieve
// a weird tumbling effect.
void timer(int v) {
static GLfloat u = 0.0;
u += 0.01;
glLoadIdentity();
gluLookAt(8*cos(u), 7*cos(u)-1, 4*cos(u/3)+2, .5, .5, .5, cos(u), 1, 0);
glutPostRedisplay();
glutTimerFunc(1000/60.0, timer, v);
}
Comet Ride
Animates the sun and earth from the point of view of a
comet.
Is another yby with a prede ned ight path.
Flies around a scene with multiple objects which
themselves are moving.
The objects are the sun and the earth, drawn as wire
spheres.
Animation again uses simplistic timer functions.
cometride.cpp
// This program does a little solar system simulation from the point of view
// of a comet. Here there is a yellow sun and a blue planet; the planet
// spins on its own axis and it rotates around the sun. The viewer is
// sitting on a comet and is always facing the sun.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cmath>
// In the GLUT library someone put the polar regions on the z-axis - yech!!
// We fixed it so that they are on the y-axis. We do this by rotating -90
// degrees about the x-axis which brings (0,0,1) to (0,1,0).
void myWireSphere(GLfloat radius, int slices, int stacks) {
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
glutWireSphere(radius, slices, stacks);
glPopMatrix();
}
// In our solar system simulation we keep track of the current "year" and
// current "day" in global variables. Actually we just make the planet go
// around the sun in increments of 5 degrees (the "year") and rotate the
// planet on its own axis in increments of 10 degrees (the "day").
static int year = 0, day = 0;
// Draw planet: a blue sphere of radius 0.2, 2 units away from sun, with
// a white "pole" for its axis.
glRotatef((GLfloat)year, 0.0, 1.0, 0.0);
glTranslatef (2.0, 0.0, 0.0);
glRotatef((GLfloat)day, 0.0, 1.0, 0.0);
glColor3f(0.0, 0.0, 1.0);
myWireSphere(0.2, 15, 15);
glColor3f(1, 1, 1);
glBegin(GL_LINES);
glVertex3f(0, -0.3, 0);
glVertex3f(0, 0.3, 0);
glEnd();
glPopMatrix();
glFlush();
glutSwapBuffers();
}
void timer(int v) {
u += du;
day = (day + 1) % 360;
year = (year + 2) % 360;
glLoadIdentity();
gluLookAt(20*cos(u/8.0)+12,5*sin(u/8.0)+1,10*cos(u/8.0)+2, 0,0,0, 0,1,0);
glutPostRedisplay();
glutTimerFunc(1000/60, timer, v);
}
Lit Solids
Displays a static picture of three cyan solids lit by a
single yellow light source.
Shows that lighting, like depth buffering, is something
that must be enabled.
Uses ambient, diffuse and specular parameters for
lighting.
Uses a directional light source, as opposed to a point
light source.
Illustrates three of the GLUT easy shape functions.
Each object is independently moved into the viewing
volume, showing the importance of glPushMatrix and
glPopMatrix .
litsolids.cpp
// This program shows three cyan objects illuminated with a single yellow
// light source. It illustrates several of the lighting parameters.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
// Clears the window and depth buffer and draws three solids.
//
// The solids are placed so that they either sit or float above the x-z plane;
// therefore note one of the first things that is done is to rotate the whole
// scene 20 degrees about x to turn the top of the scene toward the viewer.
// This lets the viewer see how the torus goes around the cone.
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// Make a torus floating 0.5 above the x-z plane. The standard torus in
// the GLUT library is, perhaps surprisingly, a stack of circles which
// encircle the z-axis, so we need to rotate it 90 degrees about x to
// get it the way we want.
glPushMatrix();
glTranslatef(-0.75, 0.5, 0.0);
glRotatef(90.0, 1.0, 0.0, 0.0);
glutSolidTorus(0.275, 0.85, 16, 40);
glPopMatrix();
glPopMatrix();
glFlush();
}
// We don't want the scene to get distorted when the window size changes, so
// we need a reshape callback. We'll always maintain a range of -2.5..2.5 in
// the smaller of the width and height for our viewbox, and a range of -10..10
// for the viewbox depth.
void reshape(GLint w, GLint h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
GLfloat aspect = GLfloat(w) / GLfloat(h);
glLoadIdentity();
if (w <= h) {
// width is smaller, so stretch out the height
glOrtho(-2.5, 2.5, -2.5/aspect, 2.5/aspect, -10.0, 10.0);
} else {
// height is smaller, so stretch out the width
glOrtho(-2.5*aspect, 2.5*aspect, -2.5, 2.5, -10.0, 10.0);
}
}
moon.cpp
// In this program the camera orbits a lit moon to simulate the phases of the
// moon.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cmath>
// A class for the moon. A moon is really just an OpenGL display list. The
// display list is created with create(), and the draw() method calls it.
// The reason we don't create the display list in the constructor is that
// clients may want to declare moon objects before the call to initializing
// OpenGL.
//
// The moon is a sphere of radius 1 centered at the origin, built from 25
// slices and 25 stacks, lit with GL_LIGHT0 as a directional light pointing
// along <1,1,1>.
class Moon {
int displayListId;
public:
public
void create() {
displayListId = glGenLists(1);
glNewList(displayListId, GL_COMPILE);
GLfloat direction[] = {-1.0, -1.0, -1.0, 0.0};
glLightfv(GL_LIGHT0, GL_POSITION, direction);
glutSolidSphere(1.0, 25, 25);
glEndList();
}
void draw() {
glCallList(displayListId);
}
};
// Clears the window (and the depth buffer) and draws the moon as viewed from
// the current position of the orbiter.
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
double x, y, z;
orbiter.getPosition(x, y, z);
gluLookAt(x, y, z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
moon.draw();
glPopMatrix();
glutSwapBuffers();
}
Bouncing Balls
Shows balls bouncing on a checkerboard.
Features a point light source.
Moves the camera in response to key presses.
bouncingballs.cpp
// This application shows balls bouncing on a checkerboard, with no respect
// for the laws of Newtonian Mechanics. There's a little spotlight to make
// the animation interesting, and arrow keys move the camera for even more
// fun.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cmath>
// Colors
GLfloat WHITE[] = {1, 1, 1};
GLfloat RED[] = {1, 0, 0};
GLfloat GREEN[] = {0, 1, 0};
GLfloat MAGENTA[] = {1, 0, 1};
// A ball. A ball has a radius, a color, and bounces up and down between
// a maximum height and the xz plane. Therefore its x and z coordinates
// are fixed. It uses a lame bouncing algorithm, simply moving up or
// down by 0.05 units at each frame.
class Ball {
double radius;
GLfloat* color;
double maximumHeight;
double x;
double y;
double z;
int direction;
public:
public
Ball(double r, GLfloat* c, double h, double x, double z):
radius(r), color(c), maximumHeight(h), direction(-1),
y(h), x(x), z(z) {
}
void update() {
y += direction * 0.05;
if (y > maximumHeight) {
y = maximumHeight; direction = -1;
} else if (y < radius) {
y = radius; direction = 1;
}
glPushMatrix();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
glTranslated(x, y, z);
glutSolidSphere(radius, 30, 30);
glPopMatrix();
}
};
// Draws one frame, the checkerboard then the balls, from the current camera
// position.
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(camera.getX(), camera.getY(), camera.getZ(),
checkerboard.centerx(), 0.0, checkerboard.centerz(),
0.0, 1.0, 0.0);
checkerboard.draw();
for (int i = 0; i < sizeof balls / sizeof(Ball);
sizeof i++) {
balls[i].update();
}
glFlush();
glutSwapBuffers();
}
// Moves the camera according to the key pressed, then ask to refresh the
// display.
void special(int key, int,
int int)
int {
switch (key) {
case GLUT_KEY_LEFT: camera.moveLeft(); break;
break
case GLUT_KEY_RIGHT: camera.moveRight(); break;
break
case GLUT_KEY_UP: camera.moveUp(); break;
break
case GLUT_KEY_DOWN: camera.moveDown(); break;
break
}
glutPostRedisplay();
}
Flight Simulator
Is a yby that is controlled by user interaction (the previous ybys moved the camera along a predermined
orbit).
Makes use of several supporting modules:
geometry.h: a module de ning basic classes for points, lines, planes and rays.
ship.h: a class representing the control of an interactive spaceship: you can set its position, speed,
orientation, and direction in different ways. Uses real mathematics!
landscape.h and landscape.cpp: a class for fractal landscapes.
cockpit.h: a class with a draw method which renders a ship's cockpit, sort of.
Illustrates rendering a scene in which different parts of the scene use different projections and views.
Fish Bitmaps
A rst program illustrating bitmaps, drawing twenty
instances of a sh bitmap at random positions in a
window.
Uses only the default settings for all pixel store settings,
so the program is not very fancy.
fish.cpp
// Shows a trivial use of OpenGL bitmaps, so trivial in fact, that it uses
// nothing but the default settings for glPixelStore*.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cstdlib>
// A fish bitmap, size is 27x11, but all rows must have a multiple of 8 bits,
// so we define it like it is 32x11.
GLubyte fish[] = {
0x00, 0x60, 0x01, 0x00,
0x00, 0x90, 0x01, 0x00,
0x03, 0xf8, 0x02, 0x80,
0x1c, 0x37, 0xe4, 0x40,
0x20, 0x40, 0x90, 0x40,
0xc0, 0x40, 0x78, 0x80,
0x41, 0x37, 0x84, 0x80,
0x1c, 0x1a, 0x04, 0x80,
0x03, 0xe2, 0x02, 0x40,
0x00, 0x11, 0x01, 0x40,
0x00, 0x0f, 0x00, 0xe0,
};
// Clears the window then plots 20 fish bitmaps in random colors at random
// positions.
void display() {
glClear(GL_COLOR_BUFFER_BIT);
for (int i = 0; i < 20; i++) {
glColor3f(randomFloat(), randomFloat(), randomFloat());
glRasterPos3f(randomFloat(), randomFloat(), 0.0);
glBitmap(27, 11, 0, 0, 0, 0, fish);
}
glFlush();
}
Checkered Triangles
A rst program illustration of textures.
Illustrates how to construt textures "by hand"
Illustrates some pixel store and texture settings.
checkeredtriangles.cpp
// This application is a trivial illustration of texture mapping. It draws
// several triangles, each with a texture mapped on to it. The same texture
// is used for each triangle, but the mappings vary quite a bit so it looks as
// if each triangle has a different texture.
#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cstdlib>
// Draws three textured triangles. Each triangle uses the same texture,
// but the mappings of texture coordinates to vertex coordinates is
// different in each triangle.
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glTexCoord2f(0.5, 1.0); glVertex2f(-3, 3);
glTexCoord2f(0.0, 0.0); glVertex2f(-3, 0);
glTexCoord2f(1.0, 0.0); glVertex2f(0, 0);