Chapter 6: Introduction to OpenGL
What Is OpenGL?
OpenGL is a software interface to graphics hardware. This interface consists of about 150
distinct commands that you use to specify the objects and operations needed to produce
interactive three-dimensional applications.
OpenGL is designed as a streamlined, hardware-independent interface to be implemented on
many different hardware platforms. To achieve these qualities, no commands for performing
windowing tasks or obtaining user input are included in OpenGL; instead, you must work
through whatever windowing system controls the particular hardware you're using. Similarly,
OpenGL doesn't provide high-level commands for describing models of three-dimensional
objects. Such commands might allow you to specify relatively complicated shapes such as
automobiles, parts of the body, airplanes, or molecules. With OpenGL, you must build up your
desired model from a small set of geometric primitives - points, lines, and polygons.
A sophisticated library that provides these features could certainly be built on top of OpenGL.
The OpenGL Utility Library (GLU) provides many of the modeling features, such as quadric
surfaces and NURBS curves and surfaces. GLU is a standard part of every OpenGL
implementation. Also, there is a higher-level, object-oriented toolkit, Open Inventor, which is
built atop OpenGL, and is available separately for many implementations of OpenGL.
Example of OpenGL code: White Rectangle on a Black Background
1
#include <whateverYouNeed.h>
main() {
InitializeAWindowPlease();
glClearColor (0.0, 0.0, 0.0, 0.0);
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
glBegin(GL_POLYGON);
glVertex3f (0.25, 0.25, 0.0);
glVertex3f (0.75, 0.25, 0.0);
glVertex3f (0.75, 0.75, 0.0);
glVertex3f (0.25, 0.75, 0.0);
glEnd();
glFlush();
UpdateTheWindowAndCheckForEvents();
}
The first line of the main() routine initializes a window on the screen: The
InitializeAWindowPlease() routine is meant as a placeholder for window system-specific
routines, which are generally not OpenGL calls. The next two lines are OpenGL commands that
clear the window to black: glClearColor() establishes what color the window will be cleared to,
and glClear() actually clears the window. Once the clearing color is set, the window is cleared to
that color whenever glClear() is called. This clearing color can be changed with another call to
glClearColor(). Similarly, the glColor3f() command establishes what color to use for drawing
objects - in this case, the color is white. All objects drawn after this point use this color, until it's
changed with another call to set the color.
2
The next OpenGL command used in the program, glOrtho(), specifies the coordinate system
OpenGL assumes as it draws the final image and how the image gets mapped to the screen. The
next calls, which are bracketed by glBegin() and glEnd(), define the object to be drawn - in this
example, a polygon with four vertices. The polygon's "corners" are defined by the glVertex3f()
commands. As you might be able to guess from the arguments, which are (x, y, z) coordinates,
the polygon is a rectangle on the z=0 plane.
Finally, glFlush() ensures that the drawing commands are actually executed rather than stored in
a buffer awaiting additional OpenGL commands. The
UpdateTheWindowAndCheckForEvents() placeholder routine manages the contents of the
window and begins event processing.
OpenGL Command Syntax
OpenGL commands use the prefix gl and initial capital letters for each word making up the
command name (recall glClearColor(), for example). Similarly, OpenGL defined constants
begin with GL_, use all capital letters, and use underscores to separate words (like
GL_COLOR_BUFFER_BIT).
OpenGL as a State Machine
OpenGL is a state machine. You put it into various states (or modes) that then remain in effect
until you change them. You can set the current color to white, red, or any other color, and
thereafter every object is drawn with that color until you set the current color to something else.
The current color is only one of many state variables that OpenGL maintains. Others control
such things as the current viewing and projection transformations, line and polygon stipple
patterns, polygon drawing modes, pixel-packing conventions, positions and characteristics of
lights, and material properties of the objects being drawn. Many state variables refer to modes
that are enabled or disabled with the command glEnable() or glDisable().
Each state variable or mode has a default value, and at any point you can query the system for
each variable's current value. Typically, you use one of the six following commands to do this:
3
glGetBooleanv(), glGetDoublev(), glGetFloatv(), glGetIntegerv(), glGetPointerv(), or
glIsEnabled(). Which of these commands you select depends on what data type you want the
answer to be given in. Some state variables have a more specific query command (such as
glGetLight*(), glGetError(), or glGetPolygonStipple()). In addition, you can save a collection
of state variables on an attribute stack with glPushAttrib() or glPushClientAttrib(), temporarily
modify them, and later restore the values with glPopAttrib() or glPopClientAttrib(). For
temporary state changes, you should use these commands rather than any of the query
commands, since they're likely to be more efficient.
OpenGL Rendering Pipeline
Most implementations of OpenGL have a similar order of operations, a series of processing
stages called the OpenGL rendering pipeline.
The following diagram shows the Henry Ford assembly line approach, which OpenGL takes to
processing data. Geometric data (vertices, lines, and polygons) follow the path through the row
of boxes that includes evaluators and per-vertex operations, while pixel data (pixels, images, and
bitmaps) are treated differently for part of the process. Both types of data undergo the same final
steps (rasterization and per-fragment operations) before the final pixel data is written into the
framebuffer.
4
Display Lists - All data, whether it describes geometry or pixels, can be saved in a display list
for current or later use. (The alternative to retaining data in a display list is processing the data
immediately - also known as immediate mode.) When a display list is executed, the retained data
is sent from the display list just as if it were sent by the application in immediate mode.
Evaluators - All geometric primitives are eventually described by vertices. Parametric curves
and surfaces may be initially described by control points and polynomial functions called basis
functions. Evaluators provide a method to derive the vertices used to represent the surface from
the control points. The method is a polynomial mapping, which can produce surface normal,
texture coordinates, colors, and spatial coordinate values from the control points.
Per-Vertex Operations - For vertex data, next is the "per-vertex operations" stage, which
converts the vertices into primitives. Some vertex data (for example, spatial coordinates) are
transformed by 4 x 4 floating-point matrices. Spatial coordinates are projected from a position in
the 3D world to a position on your screen.
If advanced features are enabled, this stage is even busier. If texturing is used, texture
coordinates may be generated and transformed here. If lighting is enabled, the lighting
calculations are performed using the transformed vertex, surface normal, light source position,
material properties, and other lighting information to produce a color value.
Primitive Assembly - Clipping, a major part of primitive assembly, is the elimination of
portions of geometry which fall outside a half-space, defined by a plane. Point clipping simply
passes or rejects vertices; line or polygon clipping can add additional vertices depending upon
how the line or polygon is clipped.
In some cases, this is followed by perspective division, which makes distant geometric objects
appear smaller than closer objects. Then viewport and depth (z coordinate) operations are
applied. If culling is enabled and the primitive is a polygon, it then may be rejected by a culling
test. Depending upon the polygon mode, a polygon may be drawn as points or lines.
5
The results of this stage are complete geometric primitives, which are the transformed and
clipped vertices with related color, depth, and sometimes texture-coordinate values and
guidelines for the rasterization step.
Pixel Operations - While geometric data takes one path through the OpenGL rendering pipeline,
pixel data takes a different route. Pixels from an array in system memory are first unpacked from
one of a variety of formats into the proper number of components. Next the data is scaled,
biased, and processed by a pixel map. The results are clamped and then either written into texture
memory or sent to the rasterization step.
If pixel data is read from the frame buffer, pixel-transfer operations (scale, bias, mapping, and
clamping) are performed. Then these results are packed into an appropriate format and returned
to an array in system memory.
There are special pixel copy operations to copy data in the framebuffer to other parts of the
framebuffer or to the texture memory. A single pass is made through the pixel transfer operations
before the data is written to the texture memory or back to the framebuffer.
Texture Assembly - An OpenGL application may wish to apply texture images onto geometric
objects to make them look more realistic. If several texture images are used, it's wise to put them
into texture objects so that you can easily switch among them.
Some OpenGL implementations may have special resources to accelerate texture performance.
There may be specialized, high-performance texture memory. If this memory is available, the
texture objects may be prioritized to control the use of this limited and valuable resource.
6
Rasterization - Rasterization is the conversion of both geometric and pixel data into fragments.
Each fragment square corresponds to a pixel in the framebuffer. Line and polygon stipples, line
width, point size, shading model, and coverage calculations to support antialiasing are taken into
consideration as vertices are connected into lines or the interior pixels are calculated for a filled
polygon. Color and depth values are assigned for each fragment square.
Fragment Operations - Before values are actually stored into the framebuffer, a series of
operations are performed that may alter or even throw out fragments. All these operations can be
enabled or disabled.
The first operation which may be encountered is texturing, where a texel (texture element) is
generated from texture memory for each fragment and applied to the fragment. Then fog
calculations may be applied, followed by the scissor test, the alpha test, the stencil test, and the
depth-buffer test (the depth buffer is for hidden-surface removal). Failing an enabled test may
end the continued processing of a fragment's square. Then, blending, dithering, logical operation,
and masking by a bitmask may be performed. Finally, the thoroughly processed fragment is
drawn into the appropriate buffer, where it has finally advanced to be a pixel and achieved its
final resting place.
OpenGL-Related Libraries
OpenGL provides a powerful but primitive set of rendering commands, and all higher-level
drawing must be done in terms of these commands. Also, OpenGL programs have to use the
underlying mechanisms of the windowing system. A number of libraries exist to allow you to
simplify your programming tasks, including the following:
i) GLUT is the OpenGL Utility Toolkit, a window system independent toolkit for writing
OpenGL programs. It implements a simple windowing application programming interface
(API) for OpenGL. GLUT makes it considerably easier to learn about and explore
OpenGL Programming.
ii) GLX is used on Unix OpenGL implementation to manage interaction with the X Window
System and to encode OpenGL onto the X protocol stream for remote rendering.
7
iii) GLU is the OpenGL Utility Library. This is a set of functions to create texture mipmaps
from a base image, map coordinates between screen and object space, and draw quadric
surfaces and NURBS.
iv) DRI is the Direct Rendering Infrastructure for coordinating the Linux kernel, X window
system, 3D graphics hardware and an OpenGL-based rendering engine.
Coordinate System
A coordinate system is a system which uses one or more numbers, or coordinates, to uniquely
determine the position of a point or other geometric element. The order of the coordinates is
significant and they are sometimes identified by their position in an ordered tuple and sometimes
by a letter, as in 'the x-coordinate'. In elementary mathematics the coordinates are taken to be
real numbers, but in more advanced applications coordinates can be taken to be complex
numbers or elements of a more abstract system such as a commutative ring. The use of a
coordinate system allows problems in geometry to be translated into problems about numbers
and vice versa; this is the basis of analytic geometry.
An example in everyday use is the system of assigning longitude and latitude to geographical
locations. In physics, a coordinate system used to describe points in space is called a frame of
reference.
World coordinate system- The world coordinate system contains the simulated world (the
scene to be rendered) in other words represents a coordinate system in given units, that
represents a given application program of the world. Also known as the "universe" or
sometimes "model" coordinate system. This is the base reference system for the overall
model, ( generally in 3D ), to which all other model coordinates relate.
Cartesian Coordinate system - specifies each point uniquely in a plane by a pair of
numerical coordinates, which are the signed distances from the point to two fixed
perpendicular directed lines, measured in the same unit of length.
Screen coordinates system: The grid or bit map a computer uses to turn monitor pixels on
and off. This 2D coordinate system refers to the physical coordinates of the pixels on the
computer screen, based on current screen resolution. ( E.g. 1024x768 )
8
Object Coordinate System - When each object is created in a modelling program, the
modeller must pick some point to be the origin of that particular object, and the
orientation of the object to a set of model axes. For example when modelling a desk, the
modeller might choose a point in the center of the desk top for the origin, or the point in
the center of the desk at floor level, or the bottom of one of the legs of the desk. When
this object is moved to a point in the world coordinate system, it is really the origin of the
object ( in object coordinate system ) that is moved to the new world coordinates, and all
other points in the model are moved by an equal amount. Note that while the origin of the
object model is usually somewhere on the model itself, it does not have to be. For
example, the origin of a doughnut or a tire might be in the vacant space in the middle.
Hierarchical Coordinate Systems - Sometimes objects in a scene are arranged in a
hierarchy, so that the "position" of one object in the hierarchy is relative to its parent in
the hierarchy scheme, rather than to the world coordinate system. For example, a hand
may be positioned relative to an arm, and the arm relative to the torso. When the arm
moves, the hand moves with it, and when the torso moves, all three objects move
together.
Viewpoint Coordinate System - Also known as the "camera" coordinate system. This
coordinate system is based upon the viewpoint of the observer, and changes as they
change their view. Moving an object "forward" in this coordinate system moves it along
the direction that the viewer happens to be looking at the time.
Model Window Coordinate System - Not to be confused with desktop windowing
systems ( MS Windows or X Windows ), this coordinate system refers to the subset of
the overall model world that is to be displayed on the screen. Depending on the viewing
parameters selected, the model window may be rectalinear or a distorted viewing
frustrum of some kind.
Viewport Coordinate System - This coordinate system refers to a subset of the screen
space where the model window is to be displayed. Typically the viewport will occupy the
entire screen window, or even the entire screen, but it is also possible to set up multiple
smaller viewports within a single screen window.
9
10