, and each
component word within a name has its first letter capitalized. The
following examples illustrate this naming convention: glClear (), glCopyPixels
() and glPolygonMode ().
Certain functions require arguments
that are constant values specifying a parameter name, a value for a
parameter, a particular mode, etc. All such constants begin with the
letters GL, component words in the constant are written in
capital letters, and the underscore (_) is used as a separator between
the words. A few examples of the several hundred constants available
in OpenGL are GL_CCW, GL_RGB, and GL_AMBIENT_AND_DIFFUSE.
A variety of data types for ANSI C
implementations can be used in OpenGL functions. Some examples are
GLfloat, GLubyte, GLbitfield,
and GLvoid.
Some arguments of OpenGL
functions can be assigned values using a vector that lists a set
of data values. This is an option for specifying a list of values
as a pointer to an array, rather than specifying each element of
the list explicitly as a parameter argument. A typical example of
the use of this option is in specifying xyz coordinate values.
RELATED LIBRARIES AND ROUTINES
In addition to the basic, or
core, library of functions, a set of "macro" routines
that use core functions are available in the OpenGL Utility
Library (GLU). These routines provide methods for setting up
viewing projection matrices, describing complex objects with line
and polygon approximations, surface rendering, and other complex
tasks. In particular, GLU provides methods for displaying
quadrics using linear-equation approximations.
There are a number of
window-system libraries that support OpenGL functions. The OpenGL
Extension to the X Window System (GLX) provides a set of routines
that are prefixed with the letters glX. The WGL
routines provide a Microsoft Windows-to-OpenGL interface. These
routines are prefixed with the letters wgl. The PGL
routines, which are prefixed with pgl, provide
a Presentation Manager to OpenGL interface for the IBM OS/2. And
the GLUT (OpenGL Utility Toolkit) routines, prefixed with glut,
provide a toolkit that is independent of any window system. This
set of routines also contains methods for describing and
rendering quadric curves and surfaces.
An object-oriented toolkit
based on OpenGL, called Open Inventor, provides routines and
predefined object shapes for interactive three-dimensional
applications. This toolkit is written in C++.
HEADER FILES
#include
<GL/gl.h> |
Includes
the OpenGL core header file. This file is required by all
OpenGL applications. |
#include
<GL/glu.h> |
Includes
the OpenGL Utility Library header file. This file is
needed by most OpenGL applications. |
And we would also need a window
interface library. Alternatively, we can just include the GLUT
header file:
#include
<GL/glut.h> |
Includes
the OpenGL Utility Toolkit header file. This statement
automatically includes gl.h,
glu.h, and glx.h.
And with Microsoft Windows, it includes the appropriate
header file to access WGL. |
SETTING UP DISPLAY WINDOWS USING GLUT
glutInit (options); |
Initializes GLUT and
specifies command-line options for the window system in
use. This function should be called before any other GLUT
routine. |
glutInitWindowPosition (x, y); |
Specifies the screen
position for one corner of the window. |
glutInitWindowSize (w, h); |
Specifies the width
(w) and height (h) for the window in pixels (integer
values). |
glutCreateWindow (string); |
Opens a window with
the previously specified size, position, and other
properties. The specified text string may be displayed in
the window title bar, depending on the options available
in the window system. |
Various options for the window
are set with the glutInitDisplayMode function. These options include the
color mode and single or double buffering. The default is RGB
color mode with single buffering.
SETTING THE WINDOW COLOR
Background color for a window
is set with the functions glClearColor and glClear. For
example, the following two statements set the background color to
black (the default), then this color is applied to the color
buffer which displays the window with the specified color.
glClearColor (0.0, 0.0, 0.0, 0.0);
glClear (GL_COLOR_BUFFER_BIT);
In the glClearColor
function, the first three parameters set the RGB color components
in the range from 0 to 1. The fourth parameter is used to set an
"alpha value", as discussed in the section Attributes
of Output Primitives, Color.
WINDOW COORDINATES AND SCREEN DISPLAY AREA
There are a number of options
for setting viewing parameters and generating a screen display of
a scene. The various options for generating views of
two-dimensional and three-dimensional scenes are discussed in the
section on Viewing Transformations.
For a two-dimensional
application, we can obtain a screen display of a defined scene
with the following code segment which sets up a coordinate
"viewing" range and specifies an area of the screen for
displaying the scene.
glViewport (xvmin, yvmin, vpWidth, vpHeight);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluOrtho2D (xwmin, xwmax, ywmin, ywmax);
The first command above defines
the rectangular screen area (called the "viewport")
that is to be used for the display of the scene. All parameters
in the glViewport function are assigned integer screen
coordinate values, and the lower left corner of the viewport is
displayed at screen position(xvmin,
yvmin) in the display
"window" set up by the window manager. The second
command sets the mode for matrix operations. In this case, we
want to project a scene description to the screen. The third
command initializes the transformation matrix for these
operations to the identity matrix. And the fourth and last
command defines the range of coordinates that will map to the
viewport, with coordinate values expressed as floating-point
numbers. This fourth function defines a "clipping
window", so that objects inside this rectangle are displayed
within the viewport. Objects outside this rectangle are clipped;
i.e., not displayed. As an alternative, the function gluOrtho2D could be replaced with glOrtho, as
discussed in the section on Viewing Transformations.
DISPLAYING A SCENE USING GLUT
After initializing GLUT,
setting the window parameters (position, size, and background
color), and specifying the coordinate system, we can display a
scene with the following functions
glutDisplayFunc(sceneDescrip);
glutMainLoop ();
The parameter sceneDescrip in the first function is a routine that
describes the primitives and attribute settings for the scene.
Rendering and display of window contents are effective with the
final GLUT function: glutMainLoop.
OUTPUT PRIMITIVES
POINT PLOTTING
The function glVertex () specifies the
coordinates for a point position.
We define world-coordinate
positions with glVertex functions placed between a glBegin/glEnd pair using the primitive type constant:
GL_POINTS. Coordinate positions can be specified in two or three
dimensions. We can also use homogeneous-coordinate
representations (four dimensional). Default values for the z
coordinate and the h parameter in coordinate
specifications are z = 0 and h = 1. We use a suffix
(2, 3, or 4) on the glVertex to indicate the coordinate dimension.
The data type to be used in
specifying a particular cordinate position is also indicated with
a suffix code on the glVertex function. These suffix codes are double
(d), float (f), integer (i), and short (s). Coordinate values can
be explicitly listed, or they can be given in a separate array
designation. For an array specification of a coordinate position,
we append a third suffix code: v (for "vector").
In the following example, three
points are plotted along a two-dimensional straight-line path
with a slope of 2. Coordinates are given as integers.
glBegin (GL_POINTS);
glVertex2i (50, 100);
glVertex2i (75, 150);
glVertex2i (100, 200);
glEnd ();
Alternatively, we could have
used a vector specification for coordinate positions by replacing
each of the statements between the glBegin/glEnd pair with a statement of the form
glVertex2iv (endpointCoords1);
where parameter endpointCoords1 is a pointer to an array of coordinate values.
LINE FUNCTIONS
As with point plotting,
straight line segments are specified with glVertex
functions that are placed within glBegin/glEnd pairs. In this case however, the coordinate
positions are interpreted as line endpoint positions. Straight
line segments are drawn as solid lines, unless other attribute
options are selected. There are three primitive types in OpenGL
that we can use to generate line segments:
GL_LINES |
Generates a series of
unconnected line segments between each successive pair of
specified endpoints. Thus, we obtain one straight line
segment between the first and second coordinate points,
then another line segment between the third and fourth
points, and so forth up to the final pair of endpoint
positions. If the number of specified endpoints is odd,
the last endpoint position is ignored. |
GL_LINE_STRIP |
Generates a
"polyline" of connected line segments between
the first endpoint and the last endpoint. |
GL_LINE_LOOP |
Generates a series of
connected line segments the same as GL_LINE_STRIP, but then adds a final line segment from
the last point back to the first point specified. |
Example:
glBegin (lineMode);
glVertex2i (50,150);
glVertex2i (150, 150);
glVertex2i (150, 50);
glVertex2i (50, 50);
glEnd ();
If parameter lineMode in this example is set to the value GL_LINES, we obtain two unconnected line segments that
are horizontal and parallel. With GL_LINE_STRIP,
we have a connected polyline with three line segments between
position (50, 150) and position (50, 50). And with GL_LINE_LOOP, we draw the four edges of a square, where each
edge is 100 pixels long.
DISPLAYING CURVED LINES
Since curves cannot be
precisely described with linear equations, there are no simple
curve functions, such as those for points and straight lines, in
OpenGL. One way to display a curve is to approximate it with
discrete points or straight-line segments. For example, we could
set up routines to implement midpoint methods for any given
function, although this is generally not straightforward for
complex curves. Another approach is to generate curves using the
spline methods that are available in OpenGL. For quadrics, such
as circles and ellipses, there are routines available in the
OpenGL Utility Library (GLU).
FILL-AREA FUNCTIONS
We display filled polygons with
the same procedures that we used for straight-line drawing,
except that the glVertex function is now used to give the
polygon vertex coordinates. Different shapes are obtained by
specifying different polygon type constants in the glBegin command. By default, polygons are displayed with
a solid fill color. Other attribute options, such as pattern fill
and border display, are also available. There are six polygon
fill primitives available in OpenGL:
GL_POLYGON |
Generates
a single polygon fill area from a list of vertex
coordinate positions. The fill area is inside the
boundary formed by the straight-line edge segments that
connect vertex positions. The specified vertex list must
contain three or more positions for anything to be
displayed, the vertices must form a convex
polygon, and there must be no crossing edges. |
GL_TRIANGLES |
Generates
a set of unconnected triangle fill areas. The first
triangle is formed with the first three vertices
specified, the next triangle is formed from the next
three vertices, and so on. If the number of vertices
specified is not a multiple of 3, the final one or two
vertex positions are not used. |
GL_TRIANGLE_STRIP |
Generates
a set of connected triangles. Each successive triangle
shares an edge with the previously specified triangle.
Thus, the ordering of the vertex list must be set up to
ensure a consistent display. For N specified vertex
positions, we obtain N-2 triangles in the strip. If N is
odd, vertices n, n+1, and n+2 are used to form triangle
n. If n is even, vertices n+1, n, and n+2 are used to
form triangle n, where n = 1, 2, ... , N-2. This is
required so that the triangles can form a consistent set
of facets for a single surface. The vertex list should
contain at least three coordinate positions. |
GL_TRIANGLE_FAN |
Generates
a set of connected triangles that all share a common
vertex. For N specified vertices, we obtain N-2 triangles
in the fan. The first vertex along with vertices n+1 and
n+2 are used to form triangle n, where n = 1, 2, ... ,
N-2. Thus, the first triangle is specified with three
vertices, and each additional vertex defines the next
connecting triangle. |
GL_QUADS |
Generates
a set of unconnected quadrilaterals (four-sided
polygons). This primitive is similar to GL_TRIANGLES. The first polygon is formed with the
first four vertices, the second polygon with the next
four vertices, and so forth. Clearly, the number of
coordinate positions given in the vertex list should be a
multiple of 4. Any additional positions are ignored. |
GL_QUAD_STRIP |
Generates
a series of connected quadrilaterals, similar to the
triangle set formed with GL_TRIANGLE_STRIP. For N specified vertices, we obtain N/2
- 1 polygons in the strip. The nth quadrilateral is
formed with vertices 2n-1, 2n, 2n+2, and 2n+1, where n =
1, 2, ... , N/2 - 1. Thus, the first quadrilateral is
formed with the first four vertices, and each additional
pair of vertices defines the next connecting polygon. |
Each polygon that we specify
has two faces: a back face and a front face. In OpenGL,
attributes can be set for each face separately, and back/front
identification is needed in both two-dimensional and
three-dimensional viewing routines. Therefore, polygon vertices
should be specified in a counterclockwise order as we view the
"outside" face of the polygon. This identifies the
front face for that polygon.
As an example, the following
code section generates a filled square version of the polygon
that was described using line segments (only edges displayed) in
the line-function example of the previous section.
glBegin (GL_POLYGON);
glVertex2i (50, 50);
glVertex2i (150, 50);
glVertex2i (150, 150);
glVertex2i (50, 150);
glEnd ();
When polygons or other objects
are to be specified with a large number of coordinate positions,
we can reduce the number of function calls by setting up arrays
to store the coordinate data. These arrays are referred to as
vertex arrays in OpenGL. Similar arrays can be used for other
types of data as well, such as color values.
IMAGES AND BITMAPS
In addition to straight lines
and polygons, we can use rectangular grid patterns to define
shapes or scenes as a set of two-dimensional color points. The
grid pattern could be a scanned image or it could be a shape we
constructed by hand or with a program. This primitive is referred
to as an image or as pixel data in OpenGL. In some
other packages, the grid of color points is called a cell array.
We display such a defined shape with the function
glDrawPixels (width, height, pixelFormat, dataType, image);
Parameters width and height give the dimensions of the color array image. We use parameter pixelFormat
to specify the format for the color specification. For example,
this parameter could be assigned one of the constants: GL_RGB,
GL_RED, GL_GREEN, GL_BLUE, GL_COLOR_INDEX, etc. And we use
parameter dataType to specify the type of data in the
array. We assign this parameter one of the constants: GL_FLOAT,
GL_INT, GL_BYTE, etc.
When a rectangular gird of
color points is specified, it is placed into the frame buffer so
that the lower left corner of the grid is at the current
position. We set the value of the current position with the
function
glRasterPos () |
Sets the
Cartesian coordinates for the current position. |
Coordinates can two-, three-,
or four-dimensional, and we can specify coordinate values in a
variety of formats. Suffixes for specifying dimension and format
are the same as for the glVertex function. The specified coordinates are
transformed to screen coordinates by the viewing routines.
Two other image functions are
available in OpenGL. We can store a rectangular section of the
frame buffer in a designated array with the function glReadPixels, and we can copy a rectangular section of the
frame buffer to another location within the frame buffer with glCopyPixels.
Another method for defining
shapes using a rectangular grid is with the function
glBitmap (width, height, x0, y0, xOffset, yOffset, image);
Parameters width and
height are the same as in the function glDrawPixels. Parameter image is now a
binary array, so that each pixel position in the grid is displayed at
the same color. When the current position is set, the current color
setting is applied to the bitmap. Coordinate position (x0, y0) defines
the "origin" of the bitmap relative to the lower left corner
of the rectangular grid. Coordinate values for the bitmap origin may
be positive or negative. The bitmap is displayed by positioning the
bitmap origin at the current position within the frame buffer. Values
xOffset and yOffset are used
as coordinate offsets to update the current frame buffer position
after the bitmap is displayed.
CHARACTER GENERATION
Only low-level support is
provided in OpenGL for displaying characters and text. One method
for generating text is to define each character as a bitmap.
Another method for setting up a
text definition is to use a display list, which is simply a set
of OpenGL commands. In this approach, the character codes for a
particular font are used to index a set of bitmaps. To display a
character string, we execute the corresponding display lists.
ATTRIBUTES OF OUTPUT PRIMITIVES
COLOR
We can specify color settings
for primitives using either the RGB mode (or RGBA
mode) or the color-index mode. Once we specify a
particular set of color values, these values apply to all
subsequently defined primitives until the color settings are
changed. A new color then affects only the objects we define
after the color change.
In RGB mode, we specify values
for the red, green, and blue components of a color. We can also
set a fourth color parameter, called the alpha value. The
complete, four-dimensional, color specification is then referred
to as the RGBA color. This fourth color parameter is used to
control color blending for overlapping objects. An important
application of color blending is in the simulation of
transparency effects. For these calculations, the alpha value
corresponds to the transparency coefficient.
To use RGB (or RGBA) mode, we
simply set the current color with the function:
glColor () |
Sets RGB
or RGBA values in the range from 0.0 to 1.0. |
Integer, floating-point, or other
numerical formats can be used to specify the RGB components of a
color. Just as with the glVertex
function, we use suffix codes such as 3, 4, d, f, and i to indicate
color dimension and data format. For example, the following function
specifies RGB color components in floating point and sets the current
color to the highest intensity blue:
glColor3f (0.0, 0.0, 1.0);
The default RGB color is white
(1, 1, 1), and the default alpha value is 1. Optionally, we can
set color values using arrays. In this case, we add a third
suffix, v, to the function, and we set a single
argument as a pointer to an array of color values. Using an
array, we set the color in the above example as
glColor3fv (colorArray);
Another method for setting color
values is to use the color-index mode, which
references color tables. We use this mode when we have limited
storage available. With this mode, the current color is set from
a color table using the function
glIndex (index);
which specifies an index
position within an array of color values. This function also
requires a data-type suffix such as d, f, or i for the index
value. We can set up a color table with the function
glIndexPointer (type, offset, ptr);
where parameter type
gives the data type, parameter offset gives
the spacing between consecutive color values, and parameter ptr
is a pointer to the first element in the color array.
POINT ATTRIBUTES
We can set two attributes for
points: color and size. Color is controlled by the current color
setting, and we set the size for a point with
glPointSize (size); |
Specifies
parameter size as a multiple of the pixel
width. We can specify size as
any positive floating-point value. If the value for size is not an integer, it is rounded to the
nearest integer (assuming antialiasing is disabled). The
default value for point size is 1. |
LINE ATTRIBUTES
Basic attributes for a straight
line segment are line type, line width, and line color. Other
possible line effects, such as pen or brush type, can be
implemented with adaptions of line type and width functions.
A single color for display of a
line segment is determined by the current color settings. Another
possibility for color display of a solid line is to vary the
color along the line path. One way to do this is to assign a
different color to each line endpoint as we define the line,
instead of setting a current color for the line as a whole. To
illustrate this method, the following code segment assigns the
color blue to one endpoint and red to the other endpoint as the
endpoint coordinates are defined. The solid line is then
displayed as a linear interpolation of the colors at the two
endpoints.
glBegin (GL_LINES);
glColor3f (0.0, 0.0, 1.0);
glVertex2i (50,50);
glColor3f (1.0, 0.0, 0.0);
glVertex2i (250,250);
glEnd ();
The default line-type attribute
is solid. Lines can also be displayed as dashed, dotted, or
dash-dotted. And we can vary the length of the dashes and the
spacing between dashes or dots. A particular line type composed
of single-color dots or dashes is specified with the OpenGL
function
glLineStipple (repeatFactor, pattern);
which specifies a pixel pattern
for line display. Parameter pattern gives a 16-bit binary pattern (1 =
pixel on, 0 = pixel off), and integer parameter repeatFactor specifies how many times each bit in the pattern
is to be repeated. The pattern is applied to the pixels along the
line path starting with the low-order bits in the pattern.
As an example of specifying a line
type, suppose parameter pattern is
assigned the hexadecimal representation 0x00FF and the repeat factor
is 1. This would produce dashed lines with 8 pixels in each dash and 8
pixels in each space between the dashes. Also, since low-order bits
are applied first, each line would begin with a dash drawn from the
first endpoint along the line path. This would be followed by equal
length space-dash combinations until the second endpoint position is
reached. With a series of connected line segments, a specified
line-type pattern is not restarted at the beginning of each
segment. It is applied continuously across all the segments, starting
at the first endpoint and ending at the final endpoint for the last
segment in the series.
To apply a specified line type
composed of dases and dots, we must enable it. Otherwise, the
line is displayed with the default pattern: 0xFFFF. Enabling is
accomplished with the function:
glEnable (GL_LINE_STIPPLE);
We turn off a line-type pattern
with glDisable.
Line width is set with the
function
glLineWidth (width);
The default value of parameter width is 1, and floating-point values are rounded to
the nearest integer when antialiasing is not applied. With
antialiasing enabled, fractional width values are possible.
AREA-FILL ATTRIBUTES
For polygons, the basic
attribute is the fill style we chose. Polygons can be filled with
a single color, a specified fill pattern, or in a
"hollow" style by displaying only the edges or the
vertex points. And we can select different attributes for the
front and back faces of a polygon, reverse the definition of
front and back, and eliminate the display of polygons that are
either back facing or front facing.
A fill pattern is applied to a
polygon with the function
glPolygonStipple (fillPattern);
Parameter fillPattern
is a pointer to a 32-bit by 32-bit mask. A value of 1 in the mask
indicates that the corresponding pixel is to be turned on, and a
0 indicates pixel off. The fill pattern is specified in bytes,
using the OpenGL data type Glubyte, and pixel intensity is set according
to the current color setting. We specify the bit pattern with
hexadecimal values, as for example,
GLubyte fillPattern[] = {
0xff, 0x00,0xff, 0x00, ...};
The bits must be specified
starting with the bottom row of the pattern, and continuing up to
the topmost row (32) of the pattern. The pattern is then applied
across the current window, filling in the specified polygon where
the pattern overlaps the polygon interior. Once we set the
current fill pattern with glPolygonStipple, we need to enable the fill routines
before we specify the vertices for the polygons that are to be
filled with the current pattern. We do this with the statement
glEnable (GL_POLYGON_STIPPLE);
Similarly, we turn off pattern
filling with
glDisable (GL_POLYGON_STIPPLE);
Another method for filling
polygons is to use texture patterns, as discussed in the section
on Surface Rendering. Also, the interpolation schemes for surface
shading of three-dimensional objects can be adapted to fill the
interior of two-dimensional polygons. We obtain an interpolation
coloring of a polygon interior just as we did with the line
primitive: A color is assigned to each vertex as we specify the
polygon shape. As an example, the following code segment assigns
a different color to each of the three vertices of a triangle and
displays a triangle interior as a linear interpolation of the
colors from each vertex.
glBegin (GL_TRIANGLES);
glColor3f (0.0, 0.0, 1.0);
glVertex2i (50, 50);
glColor3f (1.0, 0.0, 0.0);
glVertex2i (150, 50);
glColor3f (0.0, 1.0, 0.0);
glVertex2i (75, 150);
glEnd ();
If a single color is set for
the polygon as a whole, the polygon is filled with that one
color.
We can also choose to draw only
polygon edges, thus displaying the polygon in wireframe or
"hollow" form. And we could display a polygon by only
plotting the vertex positions. These options are selected with
function
glPolygonMode (face, displayMode;
We use parameter face
to select one of the two polygon faces by assigning this
parameter one of the following constant values: GL_FRONT,
GL_BACK, or GL_FRONT_AND_BACK. Then, if we want only the polygon
edges displayed for this face, we assign the constant GL_LINE to
parameter displayMode. To plot only the polygon vertex
points, we assign the constant GL_POINTS to parameter displayMode. We can also assign this parameter the value
GL-FILL, which is the default.
We can only apply rendering
routines to convex polygons in OpenGL. For a concave polygon, we
must apply a splitting algorithm to convert the polygon into a
set of convex polygons, typically all triangles. If we then want
to display the split polygon in wireframe form, we need to tell
OpenGL which lines are part of the original polygon boundary. We
do this with the glEdgeFlag function, which we use to indicate
whether or not a vertex is the first endpoint of a boundary edge
of the original polygon. The following function is used between glBegin/glEnd pairs.
glEdgeFlag (GL_FALSE);
This command indicates that the
next vertex does not precede a boundary edge. Also, it applies to
all subsequently specified vertices until the next call to glEdgeFlag is made. The argument GL_TRUE indicates that a
vertex does initialize an edge of the polygon boundary.
The definition of a polygon
"front" face is set with the function
glFrontFace (vertexOrder);
We can choose either a
counterclockwise or a clockwise ordering of the vertices as the
defining property of a front face. This is done by assigning one
of the constant values GL_CCW or GL_CW to parameter vertexOrder . The default ordering is counterclockwise. This
function can be used to swap faces of a polygon for which we have
specified vertices in a clockwise order.
ANTIALIASING
We activate the antialiasing
routines with the function
glEnable (primitiveType);
where parameter primitiveType is assigned one of the values: GL_POINT_SMOOTH,
GL_LINE_SMOOTH, or GL_POLYGON_SMOOTH. For antialiasing color
points and fill patterns, we also need to apply blending
functions.
INQUIRY FUNCTIONS
We can retrieve values for current
attribute settings and for various other parameters using an
appropriate "Get" function such as glGetIntegerv (), glGetFloatv (), glGetPolygonStipple
().
For instance, we can retrieve
the current color settings with
glGetFloatv (GL_CURRENT_COLOR, colorArray);
or we could get the current
position using the constant GL_CURRENT_RASTER_POSITION.
Similarly, we could check the range of point sizes or line widths
that are supported using the constants GL_POINT_SIZE_RANGE and
GL_LINE_WIDTH_RANGE. And we could also check whether certain
routines, such as antialiasing, were enabled or disabled.
GEOMETRIC TRANSFORMATIONS
The basic geometric
transformation functions in OpenGL are
glTranslate (tx, ty, tz); |
Specifies
a translation vector. |
glRotate (theta, vx, vy, vz); |
Specifies
a rotation angle about a rotation-axis vector (vx, vy,
vz), with the axis passing through the coordinate origin.
|
glScale (sx, sy, sz); |
Specifies
multiplicative factors relative to the coordinate origin
for either coordinate scaling or reflection. |
Each of these functions
produces a 4 by 4 transformation matrix that can be applied to
the two-dimensional or three-dimensional vertices of an output
primitive. For two-dimensional applications, we set tz = 0, (vx,
vy, vz) = (0, 0, 1), and sz = 1. Reflection transformations are
performed by setting one or more of sx, sy, and sz to a negative
value. To indicate the numerical format of the values that are to
be assigned to the transformation parameters, we affix a suffix
of f (float) or d (double) to the transformation functions. For
example, we obtain a two-dimensional translation along a
45-degree line in the xy plane with
glTranslatef (25.0, 25.0, 0.0);
Geometric transformation
functions are applied to objects as matrix multiplications. And,
in OpenGL, the jk component of a matrix, represents the element
in the jth column and kth row. As each transformation function is
specified, its matrix representation is pre-multiplied by
the current matrix. After all transformations are
specified, coordinate positions are transformed by the composite
matrix. We can initialize the current matrix to the identity
matrix with
glLoadIdentity (); |
Sets the
current matrix to the 4 by 4 identity matrix I. |
Or we can set the elements ot
the current matrix to some other values:
glLoadMatrix (M); |
Specifies
the current matrix as M, which is a predefined 4 by 4
matrix or a 16-element vector. |
We can also specify any matrix
for concatenation with the current matrix. This is accomplished
with the function
glMultMatrix (M); |
Post-multiplies
the current matrix by matrix M. |
We indicate data type for the
matrices to be loaded or multiplied in the above two commands
with suffix d or f.
Before initializing the current
matrix or specifying transformations, we set the mode for the
matrix operations. This is accomplished with the function
glMatrixMode (GL_MODELVIEW);
Other mode constants are used
to indicate matrix operations for viewing and for texture
mapping. A complete set of geometric transformation statements
might have the form
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();;
glMultMatrixf (M1);
glMultMatrixf (M2);
This set of statements would be
followed by an object definition that would be transformed with
the matrix product M1M2.
INTERACTIVE INPUT USING GLUT FUNCTIONS
glutReshapeFunc (func); |
Specifies
a function that will accept new width and height values
for a window that is to be moved or resized. Also, this
function can be used to reset the size of the display
screen area (viewport). |
glutKeyboardFunc (func); |
Specifies
a function that is to be executed when a particular key
character is selected. This function also can return the
mouse position in window coordinates. |
glutMouseFunc (func); |
Specifies
a function that is to be executed when a mouse button is
pressed or released, and returns the mouse position in
window coordinates. |
glutMotionFunc (func); |
Specifies
a function that is to be executed when a mouse pointer
moves within the window while one or more buttons is
pressed. The mouse position is returned in window
coordinates. |
VIEWING TRANSFORMATIONS
TWO-DIMENSIONAL VIEWING
Once a display
"window" is activated, as discussed in the first
section of this supplement, we need to define a clipping
"window" and the viewport coordinates for the
window-to-viewport transformation. We also need to specify a
transformation type for matrix operations (which is GL_PROJECTION
in this case), and we need to initialize the transformation
matrix.
Viewport parameters are
specified with the function
glViewport (xvmin, yvmin, vpWidth, vpHeight);
where all parameter values are
given in integer, screen coordinates within the display window.
The default position for the lower left corner of the viewport is
(0, 0), and the default size is the width and height of the
display window.
We set the matrix mode and
initialize the transformation matrix to the identity matrix with
the two statements:
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
We can then define a
two-dimensional clipping window with the function
gluOrtho2D (xwmin, xwmax, ywmin, ywmax);
which specifies the min and max
coordinate positions as double-precision numbers. This function
sets up the transfomation matrix for mapping objects within the
clip window to the specified viewport. Another way to set
coordinates for a clipping window is with the function:
glOrtho (xwmin, xwmax, ywmin, ywmax, -1.0, 1.0);
As discussed in the section on
Three-Dimensional Viewing, this function is used to set a
clipping volume (view volume). The last two parameters set the
clipping range for the z direction. Since z = 0 for
two-dimensional applications, no objects will be outside the z
clipping range: -1 to 1.
THREE-DIMENSIONAL VIEWING
We set the mode for
three-dimensional viewing transformations with the same function
that we used for two-dimensional viewing operations:
glMatrixMode (GL_PROJECTION);
And, just as in two-dimensional
applications, we need to initialize the transformation matrix to
the identity matrix.
In OpenGl, we set up a viewing
system with the following three parameters: a view reference
position (also called the viewpoint, or "eye" position)
P0, a "look-at" position Pref,
and the view-up vector V with the function
gluLookAt (x0, y0, z0, xref, yref, zref, Vx, Vy, Vz);
The direction of viewing is
then given by the vector Pref - P0,
from the viewpoint to the look-at point. Default values are the
world-coordinate origin (0, 0, 0) for the viewpoint, the negative
z axis for the viewing direction, and the world-coordinate y
direction for the view-up vector. A viewing matrix is set up for
these parameters and is pre-multiplied by the current matrix.
This function is in the Utility Library because it uses a
combination of rotation and translation routines to produce the
matrix for transforming from world to viewing coordinates.
Since viewport coordinates are
assigned in two-dimensional screen coordinates, we use the same
function for both two-dimensional and three-dimensional viewing.
Thus, we set the position and size of the viewport with glViewport, which was discussed in the last section.
We specify parameters for an
orthographic, parallel projection with
glOrtho (xwmin, xwmax, ywmin, ywmax, dNear, dFar);
which sets the clip-window
coordinates and gives the distances to the near and far clipping
planes from the viewpoint. The clipping plane distances dNear and dFar are positive if the clipping planes are
to be positioned along the direction of view. If the clipping
plane distances are negative, the clipping planes are
"behind" the viewpoint.
A perspective transformation is
specified with the function
glFrustum (xwmin, xwmax, ywmin, ywmax, dNear, dFar);
which has the same parameters
as the orthographic, parallel projection function. For a
perspective projection, the near and far clipping plane distances
must be positive.
An alternative specification
for a perspective transformation is with the function
gluPerspective (fovAngle, aspectRatio, dNear, dFar);
Parameter fovAngle
represents the "camera" field-of-view angle, which is
the angle at the viewpoint that the clipping window subtends. In
other words, the field-of-view angle is a measure of the width of
the clipping window. We can assign to parameter fovAngle any value between 0 and 180o. A large
field-of-view angle simulates a camera with a wide-angle lens.
Parameter aspectRatio is used to specify the width-to-height
ratio of the clipping window. This value should match that of the
viewport. Distances to the near and far clipping planes are
specified with the last two parameters in this function.
As an option in OpenGl, we can
also set up arbitrary clipping planes with the following
functions. Parameters for this function are a clip-plane
identification number and an array name that lists values for the
plane-equation parameters A, B, C, and D:
glClipPlane (id, paramArray);
glEnable (id);
Parameter id can be
assigned values GL_CLIP_PLANE0, GL_CLIP_PLANE1, and so forth up to a facility defined
maximum.
VISIBLE-SURFACE IDENTIFICATION
As a preliminary to viewing
only the visible surfaces in a scene, we can eliminate the
back-facing surfaces with the functions
glEnable (GL_CULL_FACE);
glCullFace (GL_BACK);
There are other options we can
use for culling object surfaces in OpenGL. Arguments for the glCullFace function can also be GL_FRONT or GL_FRONT_AND_BACK.
We apply the depth buffer
method for viewing only visible surfaces by enabling the
depth-testing routines in OpenGL and clearing the depth buffer.
This is accomplished with the following statements:
glEnable (GL_DEPTH_TEST);
glClear (GL_DEPTH_BUFFER_BIT);
We only need to enable depth
testing once in a program, but we need to clear the depth buffer
each time we want to redisplay a scene. Also, we can clear both
the color buffer and the depth buffer at the same time with
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
It is possible in OpenGL to use
the depth test to view more distant objects instead of the
closest objects. In fact, OpenGL provides a variety of options
for the depth test. When we compare a depth value to the current
buffer value for a given pixel position, we can save the depth
value if it is greater than the buffer value, equal to the buffer
value, and so forth. We select an option for depth testing with
the function
glDepthFunction (depthTestOption);
Parameter depthTestOption can be assigned any of the values GL_LESS,
GL_GREATER, GL_EQUAL, GL_LEQUAL, GL_GEQUAL, GL_NOTEQUAL,
GL_ALWAYS, GL_NEVER. The default depth-test option is GL_LESS.
OpenGL provides no functions
for directly testing for wireframe visibility. But we can adapt
the depth-buffer method to view only the visible edges in a
scene. To implement this approach, we can display all surface
edges in a foreground color, and then fill the polygon interiors
with the background color. With depth buffering enabled, only
visible edges will be displayed providing we have only simple
surfaces in the scene. If surface edges overlap the interior
region for some objects, we would need to apply other methods for
viewing only the visible parts of a wireframe display.
ILLUMINATION MODELS AND SURFACE RENDERING
LIGHT SOURCES
To illuminate a scene in
OpenGL, we set up light "sources" that have a variety
of properties, such as position, color, and direction. We set
these light-source properties with
glLight (id, property, propertyValue);
Parameter id is
assigned an OpenGl constant value that names the light source.
Depending on capabilities at a particular facility, we can set
from one to eight different light sources in a scene, using the
id names GL_LIGHT0, GL_LIGHT1, up to GL_LIGHT7. Parameter property is assigned one of the ten property code names
allowed for OpenGL light sources. We set each property value for
a particular light source with a separate call to glLight which specifies the id, the appropriate OpenGL
property name, and the property value. A suffix, f (float) or i
(integer), is used with this function to indicate the data type
for the assigned property value. For position, intensity, and
directional values, parameter propertyValue
is a pointer to an array of values. For the assignment of array
values, we also need to add the suffix v to
function glLight.
We set the position of a source by
assigning parameter property the
constant GL_POSITION and assigning parameter propertyValue an
array name that lists the x, y, z, and h values. For example,
glLightfv (GL_LIGHT1, GL_POSITION, ptCoords);
If the homogeneous parameter h
is not assigned a value of 0, then the coordinate position (x, y,
z) sets the location for a point light source. In OpenGL, this is
called a positional light source. Otherwise, with h = 0,
the light source is considered to be very far away (at
"infinity") so that the rays from the light source are
all parallel. This is called a directional light source in
OpenGL. The direction for the light rays in this case is defined
as the vector from (x, y, z) to the viewing origin. The default
value for the position parameter is (0, 0, 1, 0), which defines a
distant source with ray direction parallel to the negative z
direction. Light-source positions must be set before we specify
the viewing transformation. This ensures that the position of
light sources and the viewpoint are both transformed the same
way.
Three different sets of RGB colors
can be assigned to a light source in OpenGL, instead of a single RGB
light intensity that an actual source would have. In this empirical
scheme, the three color properties provide additional options for
varying the lighting effects in a scene. These properties are called
GL_AMBIENT, GL_DIFFUSE, and GL_SPECULAR, and they are used in surface
rendering calculations to obtain diffuse and specular lighting
effects. The ambient RGB value for a light source contributes to the
background, or ambient, lighting in a scene; the diffuse component of
the source contributes to the diffuse lighting effects; and the
specular component contributes to the specular effects. Default colors
for GL_LIGHT0 are black for the ambient component and white for the
diffuse and specular components. Black is the default color for all
three components of any other light source, such as GL_LIGHT1,
GL_LIGHT2, etc. For realistic lighting effects, the diffuse and
specular components of any light source should be set to the same RGB
values, typically with the ambient component turned off (black). As an
example of setting a color component, the following two statements
assign the color white to the specular property of light source
2.
GLfloat rgbaSpecValues[] = {1.0, 1.0, 1.0, 1.0};
glLightfv (GL_LIGHT2, GL_SPECULAR, rgbaSpecValues);
Another property that we can
set for OpenGL light sources is the spotlight effect. For
nearby ("positional") lights, we can restrict the light
emission to a cone shape by specifying the spotlight direction
(cone axis) and a cone angle. Spotlight direction is given as the
three components (vx, vy, vz) of a vector which defines the cone
axis. This vector value is assigned to the property
GL_SPOT_DIRECTION. The default spotlight direction is parallel to
the negative z axis: (0, 0, -1). Spotlight size is given as the
angular spread of the cone, measured from the cone axis to the
edge of the cone. Cone angle must be either a value in the range
from 0o to 90o or
the value 180o, and a selected angular value is
assigned to the property GL_SPOT_CUTOFF. The default spotlight
angle is 360o, which gives a source that emits light
in all directions. In the following example, a light source is
defined to be a spotlight that points in a direction parallel to
the x axis and has a cone angle of 30o.
GLfloat spotDirVector[] = {1.0, 0.0, 0.0, 1.0};
glLightfv (GL_LIGHT3, GL_SPOT_DIRECTION, spotDirVector);
glLightf (GL_LIGHT3, GL_SPOT_CUTOFF, 30.0);
Nearby, or
"positional", light sources can also be assigned values
for intensity attenuation calculations. Intensity attenuation is
performed in the empirical OpenGL lighting model as an inverse
quadratic function, where distance d is measured from the light
position to a point on an object surface. Each of the three
attenuation coefficients (a0, a1, and a2) are separately assigned
either integer or floating-point values. The corresponding
light-source properties are named: GL_CONSTANT_ATTENUATION,
GL_LINEAR_ATTENUATION, and GL_QUADRATIC_ATTENUATION. Default
values for the attenuation coefficients are a0 = 1, a1 = 0, and
a2 = 0.
GLOBAL LIGHTING PARAMETERS
Another lighting parameter that
can be set in OpenGL is the global level for the ambient, or
background, lighting. (This is in addition to the ambient light
component that can be set for each OpenGL light source.) We can
also specify whether the specular-reflection calculations are to
be performed assuming a "local" viewing position or one
that is infinitely far away, and we can apply surface rendering
to front faces only or to both front and back faces of surfaces.
These global effects are set with the following function, in the
same way that we set properties for light sources.
glLightModel (globalProperty, globalPropertyValue);
Parameter globalProperty takes one of the following OpenGL constant
values: GL_LIGHT_MODEL_AMBIENT, GL_LIGHT_MODEL_LOCAL_VIEWER,
GL_LIGHT_MODEL_TWO_SIDE. The level of the general ambient light
for a scene is assigned as an array of RGBA values. Default for
the ambient light is (0.2, 0.2, 0.2, 1.0). The local-viewing
property can be assigned either the value GL_TRUE or the value
GL_FALSE (or 0, or 0.0). The value GL_FALSE causes the view
direction to be set as parallel to the negative z direction.
Otherwise (GL_TRUE), we obtain "local viewing" with the
view position at the origin of the viewing ("eye")
coordinates. Default value for the local-viewing parameter is
GL_FALSE. And we select two-sided or one-sided lighting with the
values GL_TRUE and GL_FALSE, respectively. The default here is
GL_FALSE (one-sided lighting only). Suffixes for the glLightModel function are again f, i, and v, depending on the
data type for parameter globalPropertyValue.
SURFACE REFLECTION AND EMISSION PROPERTIES
We set the illumination
properties for the front and back faces of a surface with
glMaterial (face, surfaceProperty, surfacePropertyValue);
These properties are set at each
vertex as we specify the vertex coordinates. Suffixes for this
function are f (float), i (integer), and v (vector). All data values
except the specular-reflection exponent are given as
arrays. Reflection coefficients in OpenGL are named GL_AMBIENT,
GL_DIFFUSE, and GL_SPECULAR. Also, since ambient light is diffuse, we
can set both coefficients to the same value with the property
GL_AMBIENT_AND_DIFFUSE. Default values are (0.2, 0.2, 0.2, 1.0) for
the ambient-reflection coefficient, (0.8, 0.8, 0.8, 1.0) for the
diffuse-reflection coefficient, and (0.0, 0.0, 0.0, 1.0) for the
specular-reflection coefficient. The specular-reflection exponent for
highlight effects is called GL_SHININESS, and the default exponent
value is 0. We can set this exponent to any value in the range from 0
to 128.
SURFACE RENDERING
We have two options in OpenGL
for surface rendering: constant-intensity (flat) shading and
Gouraud ("smooth") shading. Once color values have been
assigned to polygon vertices, we select a shading type with
glShadeModel (renderingType);
Parameter renderingType
is assigned either the value GL_FLAT or the value GL_SMOOTH. The
default surface rendering is Gouraud shading
("smooth").
We can also apply texture patterns
in OpenGL to any primitive, such as a set of points, a straight line
segment, or a polygon surface, or to any curved line or curved
surface. Texture patterns can be one dimensional or two dimensional,
and we specify various parameters for a pattern either with
glTexImage1D or with glTexImage2D.
These functions give the size, format, data type, pattern array name,
and other information. Other functions are available for performing
pattern manipulations, such as scaling, copying a pattern from the
frame buffer, and modifying an existing pattern. We apply a pattern
to an object by enabling the texture routines and by specifying
texture coordinates along with the object vertex coordinates. The
texture coordinates determine how a pattern is to be applied to an
object.
Transparency is simulated by
combining color values from different objects using the alpha
component of the color values. The alpha component is assigned a
value between 0 and 1, and it corresponds to a transparency
coefficient in color-blending applications. For the transparency
calculations, we need to specify objects in a scene from back to
front. As each object in turn is processed, we then blend its
surface color with the currently stored raster color. We
accomplish this with the set of commands:
glEnable (GL_BLEND);
glBlendFunc (surfaceParameter, rasterParameter);
The two parameters in this
function provide a number of options for color blending. For the
simulation of transparency, we can set surfaceParameter to the value GL_SRC_ALPHA and rasterParameter to the value GL_ONE_MINUS_SRC_ALPHA. In OpenGL,
the current surface is referred to as the "source" and
the current pixel color stored in the frame buffer is referred to
as the "destination". Thus, these settings for the
blend function arguments indicate that the pixel color
("destination") should be multiplied by the
transparency coefficient (alpha value) of the current surface
("source"), and the surface color should be multiplied
by one minus the transparency coefficient. The result is then
added and normalized to a value in the range from 0 to 1. This
color is then stored as the new pixel color, and the next surface
is processed. We can set a number of other options for the glBlendFunc parameters to provide various color-blending
combinations.
OpenGL provides no built-in
routines for producing shadows in a scene. To determine shadow
regions for a light source, we can set the viewpoint at the
light-source position and determine which surface sections cannot
be "seen" from that position. These surfaces can then
be tagged so that only the global ambient lighting (and possibly
lighting effects from other sources) is applied.
ACTIVATING THE LIGHTING EFFECTS
To apply surface rendering with
selected lighting conditions, we need to "turn on" the
OpenGL lighting effects. Otherwise, objects are simply displayed
using current color settings. We activate lighting effects with
the function
glEnable (GL_LIGHTING);
REFERENCES
OpenGL Programming Guide, Second Edition
Mason Woo, Jackie Neider, and Tom Davis
Addison-Wesley Developers Press, 1997
OpenGL Reference Manual, Second Edition
OpenGL Architecture Review Board Editors: Renate Kempf and Chris Frazier
Addison-Wesley Developers Press, 1997