## Troubleshooting TransformationsIt's pretty easy to get a camera pointed in the right direction, but in computer graphics, you have to specify position and direction with coordinates and angles. As we can attest, it's all too easy to achieve the well-known black-screen effect. Although any number of things can go wrong, often you get this effect - which results in absolutely nothing being drawn in the window you open on the screen - from incorrectly aiming the "camera" and taking a picture with the model behind you. A similar problem arises if you don't choose a field of view that's wide enough to view your objects but narrow enough so they appear reasonably large. If you find yourself exerting great programming effort only to create a black window, try these diagnostic steps. - Check the obvious possibilities. Make sure your system is plugged in. Make sure you're drawing your objects with a color that's different from the color with which you're clearing the screen. Make sure that whatever states you're using (such as lighting, texturing, alpha blending, logical operations, or antialiasing) are correctly turned on or off, as desired.
- Remember that with the projection commands, the near and far coordinates
measure distance from the viewpoint and that (by default) you're looking down
the negative
`z`axis. Thus, if the near value is 1.0 and the far 3.0, objects must have`z`coordinates between -1.0 and -3.0 in order to be visible. To ensure that you haven't clipped everything out of your scene, temporarily set the near and far clipping planes to some absurdly inclusive values, such as 0.001 and 1000000.0. This alters appearance for operations such as depth-buffering and fog, but it might uncover inadvertently clipped objects. - Determine where the viewpoint is, in which direction you're looking, and where your objects are. It might help to create a real three-dimensional space - using your hands, for instance - to figure these things out.
- Make sure you know where you're rotating about. You might be rotating about some arbitrary location unless you translated back to the origin first. It's OK to rotate about any point unless you're expecting to rotate about the origin.
- Check your aim. Use
**gluLookAt()**to aim the viewing volume at your objects. Or draw your objects at or near the origin, and use**glTranslate*()**as a viewing transformation to move the camera far enough in the`z`direction only so that the objects fall within the viewing volume. Once you've managed to make your objects visible, try to change the viewing volume incrementally to achieve the exact result you want, as described next.
Even after you've aimed the camera in the correct direction and you can see
your objects, they might appear too small or too large. If you're using
#define PI 3.1415926535 double calculateAngle(double size, double distance) { double radtheta, degtheta; radtheta = 2.0 * atan2 (size/2.0, distance); degtheta = (180.0 * radtheta) / PI; return (degtheta); } Of course, typically you don't know the exact size of an object, and the distance
can only be determined between the viewpoint and a single point in your scene.
To obtain a fairly good approximate value, find the bounding box for your scene
by determining the maximum and minimum For example, suppose all the coordinates in your object satisfy the equations
-1 ≤ If the viewpoint is at (8, 9, 10), the distance between it and the center is The tangent of the half angle is 5.477 divided by 12.570, which equals 0.4357, so the half angle is 23.54 degrees. Remember that the field-of-view angle affects the optimal position for the viewpoint, if you're trying to achieve a realistic image. For example, if your calculations indicate that you need a 179-degree field of view, the viewpoint must be a fraction of an inch from the screen to achieve realism. If your calculated field of view is too large, you might need to move the viewpoint farther away from the object. ## Manipulating the Matrix StacksThe modelview and projection matrices you've been creating, loading, and multiplying have only been the visible tips of their respective icebergs. Each of these matrices is actually the topmost member of a stack of matrices (see Figure 3-20).
A stack of matrices is useful for constructing hierarchical models, in which
complicated objects are constructed from simpler ones. For example, suppose
you're drawing an automobile that has four wheels, each of which is attached
to the car with five bolts. You have a single routine to draw a wheel and another
to draw a bolt, since all the wheels and all the bolts look the same. These
routines draw a wheel or a bolt in some convenient position and orientation,
say centered at the origin with its axis coincident with the Suppose for a minute that all you have to do is draw the car body and the wheels. The English description of what you want to do might be something like this: - Draw the car body. Remember where you are, and translate to the right front wheel. Draw the wheel and throw away the last translation so your current position is back at the origin of the car body. Remember where you are, and translate to the left front wheel....
Similarly, for each wheel, you want to draw the wheel, remember where you are, and successively translate to each of the positions that bolts are drawn, throwing away the transformations after each bolt is drawn. Since the transformations are stored as matrices, a matrix stack provides an
ideal mechanism for doing this sort of successive remembering, translating,
and throwing away. All the matrix operations that have been described so far
(
Example 3-4 draws an automobile, assuming the existence of routines that draw the car body, a wheel, and a bolt.
draw_wheel_and_bolts() { long i; draw_wheel(); for(i=0;i<5;i++){ glPushMatrix(); glRotatef(72.0*i,0.0,0.0,1.0); glTranslatef(3.0,0.0,0.0); draw_bolt(); glPopMatrix(); } } draw_body_and_wheel_and_bolts() { draw_car_body(); glPushMatrix(); glTranslatef(40,0,30); /*move to first wheel position*/ draw_wheel_and_bolts(); glPopMatrix(); glPushMatrix(); glTranslatef(40,0,-30); /*move to 2nd wheel position*/ draw_wheel_and_bolts(); glPopMatrix(); … /*draw last two wheels similarly*/ } This code assumes the wheel and bolt axes are coincident with the A stack is more efficient than an individual matrix, especially if the stack
is implemented in hardware. When you push a matrix, you don't need to copy the
current data back to the main process, and the hardware may be able to copy
more than one element of the matrix at a time. Sometimes you might want to keep
an identity matrix at the bottom of the stack so that you don't need to call
## The Modelview Matrix StackAs you've seen earlier in "Viewing and Modeling Transformations," the modelview
matrix contains the cumulative product of multiplying viewing and modeling transformation
matrices. Each viewing or modeling transformation creates a new matrix that
multiplies the current modelview matrix; the result, which becomes the new current
matrix, represents the composite transformation. The modelview matrix stack
contains at least thirty-two 4 × 4 matrices; initially, the topmost matrix
is the identity matrix. Some implementations of OpenGL may support more than
thirty-two matrices on the stack. To find the maximum allowable number of matrices,
you can use the query command ## The Projection Matrix StackThe projection matrix contains a matrix for the projection transformation,
which describes the viewing volume. Generally, you don't want to compose projection
matrices, so you issue One use for a second matrix in the stack would be an application that needs to display a help window with text in it, in addition to its normal window showing a three-dimensional scene. Since text is most easily positioned with an orthographic projection, you could change temporarily to an orthographic projection, display the help, and then return to your previous projection: glMatrixMode(GL_PROJECTION); glPushMatrix(); /*save the current projection*/ glLoadIdentity(); glOrtho(…); /*set up for displaying help*/ display_the_help(); glPopMatrix(); Note that you'd probably have to also change the modelview matrix appropriately.
If you know enough mathematics, you can create custom projection matrices that perform arbitrary projective transformations. For example, the OpenGL and its Utility Library have no built-in mechanism for two-point perspective. If you were trying to emulate the drawings in drafting texts, you might need such a projection matrix. |