4 GLU
4.010 What is GLU? How is it different from
OpenGL?
If you think of OpenGL as a low-level 3D
graphics library, think of GLU as adding some higher-level
functionality not provided by OpenGL. Some of GLU's features
include:
- Scaling of 2D images and creation of
mipmap pyramids
- Transformation of object coordinates into
device coordinates and vice versa
- Support for NURBS surfaces
- Support for tessellation of concave or bow
tie polygonal primitives
- Specialty transformation matrices for
creating perspective and orthographic projections,
positioning a camera, and selection/picking
- Rendering of disk, cylinder, and sphere
primitives
- Interpreting OpenGL error values as ASCII
text
The best source of information on GLU is
the OpenGL red and blue books and the
GLU specification, which you can obtain from the OpenGL org Web page.
4.020 How does GLU render sphere, cylinder, and
disk primitives?
There is nothing special about how GLU
generates these primitives. You can easily write routines
that do what GLU does. You can also download the Mesa source, which contains a GLU distribution, and see what
these routines are doing.
The GLU routines approximate the specified
primitive using normal OpenGL primitives, such as quad strips
and triangle fans. The surface is approximated according to
user parameters. The vertices are generated using calls to
the sinf() and cosf() math library functions.
4.030 How does gluPickMatrix() work?
It simply translates and scales so that the
specified pick region fills the viewport. When specified on
the projection matrix stack, prior to multiplying on a normal
projection matrix (such as gluPerspective(), glFrustum(),
glOrtho(), or gluOrtho2D()), the result is that the view
volume is constrained to the pick region. This way only
primitives that intersect the pick region will fall into the
view volume. When glRenderMode() is set to GL_SELECT, these
primitives will be returned.
4.040 How do I use GLU tessellation routines?
GLU provides tessellation routines to let
you render concave polygons, self-intersecting polygons, and
polygons with holes. The tessellation routines break these
complex primitives up into (possibly groups of) simpler,
convex primitives that can be rendered by the OpenGL API.
This is done by providing the data of the simpler primitives
to your application from callback routines that your
application must provide. Your app can then send the data to
OpenGL using normal API calls.
An example program is available in the GLUT
distribution under progs/redbook/tess.c. (Download the GLUT distribution).
The usual steps for using tessellation
routines are:
1. Allocate a new GLU tessellation object:
GLUtesselator *tess = gluNewTess();
2. Assign callbacks for use with this
tessellation object:
gluTessCallback (tess, GLU_TESS_BEGIN, tcbBegin);
gluTessCallback (tess, GLU_TESS_VERTEX, tcbVertex);
gluTessCallback (tess, GLU_TESS_END, tcbEnd);
2a. If your primitive is self-intersecting,
you must also specify a callback to create new vertices:
gluTessCallback (tess, GLU_TESS_COMBINE, tcbCombine);
3. Send the complex primitive data to GLU:
// Assumes:
// GLdouble data[numVerts][3];
// …and assumes the array has been filled with 3D vertex data.
gluTessBeginPolygon (tess, NULL);
gluTessBeginContour (tess);
for (i=0; i<sizeof(data)/(sizeof(GLdouble)*3);i++)
gluTessVertex (tess, data[i], data[i]);
gluTessEndContour (tess);
gluEndPolygon (tess);
4. In your callback routines, make the
appropriate OpenGL calls:
void tcbBegin (GLenum prim);
{
glBegin (prim);
}
void tcbVertex (void *data)
{
glVertex3dv ((GLdouble *)data);
}
void tcbEnd ();
{
glEnd ();
}
void tcbCombine (GLdouble c[3], void *d[4], GLfloat w[4], void **out)
{
GLdouble *nv = (GLdouble *) malloc(sizeof(GLdouble)*3);
nv[0] = c[0];
nv[1] = c[1];
nv[2] = c[2];
*out = nv;
}
The above list of steps and code segments
is a bare-bones example and is not intended to demonstrate
the full capabilities of the tessellation routines. By
providing application-specific data as parameters to
gluTessBeginPolygon() and gluTessVertex() and handling the
data in the appropriate callback routines, your application
can color and texture map these primitives as it would a
normal OpenGL primitive.
4.050 Why aren't my tessellation callback
routines called?
Normally your tessellation callback
routines are executed when you call gluEndPolygon(). If they
are not being called, an error has occurred. Typically this
is caused when you haven't defined a GLU_TESS_COMBINE*
callback for a self-intersecting primitive.
You might try defining a callback for GLU_TESS_ERROR
to see if it's called.
4.060 How do I use GLU NURBS routines?
The GLU NURBS interface converts the B-Spline
basis control points into Bezier basis equivalents and calls
directly to the OpenGL Evaluator routines to render the
surface.
An example program is available in the GLUT
distribution under progs/redbook/surface.c. (Download the GLUT distribution).
4.070 How do I use gluProject() and gluUnProject()?
Both routines take a ModelView matrix,
Projection matrix, and OpenGL Viewport as parameters.
gluProject() also takes an XYZ-object space
coordinate. It returns the transformed XYZ window (or device)
coordinate equivalent.
gluUnProject() does the opposite. It takes
an XYZ window coordinate and returns the back-transformed XYZ
object coordinate equivalent.
The concept of window space Z is often
confusing. It's the depth buffer value expressed as a
GLdouble in the range 0.0 to 1.0. Assuming a default
glDepthRange(), a window coordinate with a Z value of 0.0
corresponds to an eye coordinate located on the zNear clipping
plane. Similarly, a window space Z value of 1.0 corresponds
to an eye space coordinate located on the zFar plane.
You can obtain any window space Z value by reading the depth
buffer with glReadPixels().
|