This page contains links to simple OpenGL programs. Each program is intended to illustrate a small number of features of OpenGL in a simple way.
These examples were written when processors and graphics cards were slower than they are now. You may find that some of them run rather fast. You can slow them down by running them in a very large window or, better, by adding features to the source code.
OpenGL comes in three parts: the Graphics Library (GL); the GL utilities (GLU); and the GL Utility Toolkit (GLUT). If you are using a recent MS operating system (Windows NT, 95, or 2000), you already have GL and GLU but you will have to download GLUT. Suitable links are given at the bottom of this page.
This is a simple program that uses the basic GLUT callback functions but does not do much else. You may want to learn GLUT by starting with this program, stripping out the code that you don't need, and putting your own code in.
A common complaint about graphics programs is that they have poor "style" - in particular, there are often many global variables in a graphics program.
OpenGL, like many other graphics APIs, uses callback functions. Since the parameters and result type of a callback function are defined by the API, the easiest way to provide communication between callback functions is to use global variables.
With languages such as FORTRAN and C, there were no obvious alternatives. By using an object oriented language such as C++ in conjunction with OpenGL, however, we can eliminate most of the global variables and construct programs which have better encapsulation and are easier to read. Of course, the global variables have not disappeared altogether: the new programs have global objects, instead! But we can at least keep the number of objects - or pointers to objects - small.
The example program illustrates the basic idea and also shows how to make use of inheritance in graphics programming. It has an abstract base class, Drawable, that provides common operations but no implementation (or a default implementation) for those operations. Two other classes, Sphere and Cone, are derived from the base class.
The user can create new instances of Sphere and Cone by entering 'n', select one of the objects by entering a digit ('1', '2',..., '9'), and then move the selected object. The program uses a global pointer to the list of objects and a global pointer to the current object.
The program can easily be extended in (at least) two ways: you can add classes for objects of different shapes, and you can add member functions to extend the capabilities of the objects. More importantly, the program provides a simple example of a readable graphics program.
OpenGL features used: double buffering; depth buffer; keyboard callback.
The example program provides a very simple application of the lighting primitives of OpenGL. The graphic image consists of two spheres and a movable light. The left sphere is red and has a dull surface; the right sphere is blue and has a shiny surface.
The light source is visible and you can move it with the mouse.
OpenGL features used: lighting; material properties; depth buffer; mouse, keyboard, and resizing callbacks.
This is a more complicated program that enables you to experiment with different lighting effects. There are a number of parameters involved in lighting - ambient, diffuse, and specular characteristics of both the material and the light source - and many of the parameters may have red, green, and blue components.
The program displays a simple scene, consisting of a cone and a sphere, and a light source. The lighting parameters are displayed as text on the screen. You use the keyboard to choose which parameters you want to control, and then move the mouse to change their values.
OpenGL features used: lighting, material properties; bit-mapped characters.
In principle, OpenGL can display a surface of almost unlimited complexity. In practice, complex surfaces can take up a lot of time - the time required to program them and the time required to render them. There are a number of tricks that we can use to convey the illusion of a complex surface without doing all the programming.
The example program shows a "terrain" illuminated by a moving "sun". The terrain is constructed in a straightforward way: it consists of rectangles in a plane. To make it interesting, the program computes surface normals that deviate from the true perpendicular in a random way. When the surface is illuminated, it seems to have an irregular texture.
This idea, applied systematically and with detailed calculation, is called "bump mapping"; it has been used to create the effect of surfaces with small irregularities, such as oranges and leather.
The sun is also visible from time to time. An OpenGL light source provides "light" but does not itself appear in the image. To obtain the effect of a visible light source such as the sun, we have to introduce a body to represent the sun - a sphere is quite suitable - and illuminate it from a point between the sun and the viewer. Since light from this source must not reach any other part of the scene, we then move the source to the position of the sun and render the scene.
This program uses another useful shortcut: glClearColor() is used to set the background colour to a sky colour corresponding to the time of day, rather than the default (black).
OpenGL features used: material properties; "fake" normals; background colour; moving light source; mouse, keyboard, and resizing callbacks.
The main purpose of this program is to demonstrate various ways of using gluLookAt(). The program shows a car moving around a circular track. You can select different viewpoints by pressing the function keys "F1", "F2", etc.
The viewpoints simulate: a static "camera"; panning cameras; stationary and moving cameras mounted on the car; cameras that fixed relative to the car although not actually on it; and cameras which view the scene from the air, either in "balloon" mode (the camera is stationary but points at different parts of the scene) or in "helicopter" mode (the camera moves around, but always looks at the same point). There is also a "movie" mode, in which the viewpoint is changed at random intervals.
The car is modelled using quadric surfaces - tapered cylinders and disks. The circular track and the "grass" inside it are also disks. The houses that dot the landscape consist of rectangles and triangles.
The trick to writing a program like this is to have a very clear idea of what coordinate systems there are and which one you are currently in. The principle reference frames in this program are the circular track (origin at centre, Z axis pointing upwards) and the car (origin at centre of back of car, X axis pointing in direction of motion, and Z axis pointing upwards).
The coordinate systems move with respect to one another as the car moves around the track. One origin moves in a circle around the other origin and, because the car must appear to move along its own axis, the coordinate systems rotate with respect to each other as well.
The camera may be stationary with respect to one frame and moving with respect to the other, or moving with respect to both frames. The simplest case is when the camera is fixed with respect to the scenery. Suppose the moving object is at (X,Y):
gluLookAt(...); // fixed arguments draw_scenery(); transform(...); // move origin to (X,Y) draw_car();
If the camera stays in the same place with respect to the scenery, but moves ("pans") to follow a moving object, the sequence of calls is the same, but gluLookAt() has variable arguments.
gluLookAt(...); // look towards (X,Y) draw_scenery(); transform(...); // move origin to (X,Y) draw_car();
Now suppose that the camera is fixed to the moving object. The arguments to gluLookAt() are constant and the moving object is rendered without transformation. We move the origin to (-X,-Y) before rendering the scenery:
gluLookAt(...); // fixed arguments draw_car(); transform(...); // move origin to (-X,-Y) draw_scenery();
The program shows the view from a camera that is attached to the car but is always pointing at a particular stationary object (a house, in fact). The camera must rotate to compensate for the motion of the car. Assume that the direction of the car is DIR:
rotate(-dir) gluLookAt(...); // look towards house draw_car(); rotate(dir); transform(...); // move origin to (-X,-Y) draw_scenery();
For any viewpoint, you can obtain a "zoom" effect by presing the left and right arrow keys, and you can move the camera up and down using the up and down arrow keys. Optionally, you can add a small amount of random vertical motion to the car, giving the effect of a bumpy road.
OpenGL features used: quadrics; look-at and perspective transformations; model-building with triangles and quadrilaterals; callbacks for function keys; fog.
There are many ways of providing multiple windows in OpenGL, and this program illustrates one of the simpler ways. The main program defines two windows, each with its own display callback function. There is an idle callback function that simply updates global variables (!).
Only one of the windows is active at any given time. Both windows display wire cubes, and the idle function changes the orientation of both cubes, but only the cube in the active window rotates. You can change the active window either from the keyboard (enter '1' or '2') or by moving the mouse - the active window is the one that contains the mouse cursor.
OpenGL features used: two graphics windows; keyboard and idle callback functions.
Here is another way of using multiple windows. This program displays the same scene from three different viewpoints. Each window has its own mouse function. Since the mouse provides two inputs (up/down and left/right), there are six inputs altogether.
Each window is provided with three callback functions, for the display, the mouse, and the keyboard. The display and keyboard functions are the same for each window; the mouse functions are different.
When a change occurs, glutPostRedisplay() must be called for each window. The display callback function uses glutGetWindow() to decide which viewpoint to present. After gluLookAt() has set the viewpoint, the code does not depend on the window.
OpenGL features used: three graphics windows; keyboard and mouse callback functions.
The fourth component of a colour in OpenGL (the "alpha" component) determines how the colour will be applied. The new colour of the pixel is a mixture of the given colour and the previous colour at the pixel, where alpha is the proportion of the given colour.
The alpha component allows the colour of an object to blend into whatever is behind the object. This is useful, but there is an important point to note. When we draw opaque objects with OpenGL, the order in which they are rendered (that is, the order in which the respective function calls appear in the program) doesn't matter, because the depth buffer ensures that the closest object at a particular pixel is the one that we see. If one or more of the objects at a pixel are partly transparent, however, the order does matter: we must draw opaque objects first, and then transparent objects.
The example program provides a rather simple application of the alpha component. It draws a blue icosahedron inside a grey "glass" cube. The icosahedron is slightly transparent (alpha = 0.8) giving it a jewel-like effect (if you use your imagination). You control the transparency of the cube by pressing keys: '0' is completely transparent (and therefore invisible) and '9' is almost opaque.
The alpha factor alone is not very convincing. The illusion is improved by using a highly-specular surface for the cube. The combination of transparency and reflection gives the appearance of glass (if you use your imagination).
OpenGL features used: material properties with high specular coefficients; moving light; variable alpha values; keyboard, idle, and resizing callback functions.
OpenGL does not provide much in the way of advanced features. Instead, and as an API should, it provides a rich set of basic tools that enable us to obtain complex effects. For example, OpenGL does not provide a function for reflection. It does provide, however, a "stencil buffer" that enables us to update parts of the scene selectively, and basic transformations that enable us to draw both a scene and its mirror image.
Here is a simple recipe for creating a reflection.
- Part of the scene will be the surface of the mirror. For example, the mirror might be a rectangle viewed obliquely. Store the shape corresponding to the surface of the mirror in the stencil buffer.
- Set the stencilling function so that only objects outside the surface of the mirror are drawn.
- Draw the scene.
- Set the stencilling function so that only objects inside the surface of the mirror are drawn.
- Reflect the scene in the mirror. The transformation is as follows: translate the origin to the centre of the mirror; use a scaling transformation to reflect; translate back to the original position.
- Draw the scene again.
Step 5 is easy to do if the mirror is normal to one of the principle axes. In the example program, the mirror lies in the YZ plane and the X axis is normal to it. The reflection is performed by the transformation glScalef(-1,1,0).
OpenGL features used: stencil buffer and stencil functions; translation and scaling; mouse, idle, keyboard, and resizing callback functions.
This program demonstrates an effect used by Alfred Hitchcock in his movies Vertigo, Marnie, and possibly others. The camera tracks and zooms simultaneously, so that one plane remains fixed in size while objects at other distances expand or contract.
OpenGL features used: updating projection matrix in display function.
A program that simulates a vibrating string. The string is modelled by small weights attached to a light elastic thread. Each weight is constrained to move vertically. The console window provides instructions.
Visualization of the lines of force between two particles with the same charge.
A program that simulates the motion of the sun, earth, and moon. This program shows how to use the OpenGL matrix stack to simplify visualizations of relative motion.
Simulates the effects of Newtonian gravitation on three bodies — sun, planet, moon.
This is a simple program that demonstrates the use of OpenGL with the Windows API.
This is a more elaborate Windows program that demonstrates animation.
- You can download the GLUT libraries and demonstration programs from Nate Robbins' site.
- Nate Robbins has also prepared an excellent set of OpenGL tutorials.
- Graphics Gems. This web page is based on the series of five books called Graphics Gems. There is a lot of good stuff here, some of it quite advanced.
- The Journal of Graphics Tools has now taken over the role of the Graphics Gems series.
- Silicon Graphics.
- OpenGL at Silicon Graphics.
- Fastgraph is a commercial graphics package for DOS and Windows. FastGraph is not an implementation of OpenGL: it provides a completely different set of functions.