You may be wondering about now why we had to bother with all this matrix stuff in the first place. Can’t we just call these transformation functions to move our objects around and be done with it? Do we really need to know that it is the Modelview matrix that is being modified?
The answer is yes and no, but only if you are drawing a single object in your scene. This is because the effects of these functions are cumulative. Each time you call one, the appropriate matrix is constructed and multiplied by the current Modelview matrix. The new matrix then becomes the current Modelview matrix, which is then multiplied by the next transformation, and so on.
Suppose you want to draw two spheres—one 10 units up the positive y-axis, and one 10 units out the positive x-axis, as shown in Figure 7-13. You might be tempted to write code that looks something like this:
// Go 10 units up the y-axis glTranslatef(0.0f, 10.0f, 0.0f); // Draw the first sphere auxSolidSphere(1.0f); // Go 10 units out the x-axis glTranslatef(10.0f, 0.0f, 0.0f); // Draw the second sphere auxSolidSphere(1.0f);
Consider, however, that each call to glTranslate is cumulative on the Modelview matrix, so the second call would translate 10 units in the positive x direction from the previous translation in the y direction. This would yield the results shown in Figure 7-14.
You could make an extra call to glTranslate to back down the y-axis 10 units in the negative direction, but this would make some complex scenes very difficult to code and debug. A simpler method would be to reset the Modelview matrix to a known state—in this case, centered at the origin of our eye coordinate system.
This is done by loading the Modelview matrix with the Identity matrix. The Identity matrix specifies that no transformation is to occur, in effect saying that all the coordinates you specify when drawing are in eye coordinates. An Identity matrix contains all 0’s with the exception of a diagonal row of ones. When this matrix is multiplied by any vertex matrix, the result is that the vertex matrix is unchanged. Figure 7-15 shows this equation.
As we’ve already stated, the details of performing matrix multiplication are outside the scope of this book. For now, just remember this: Loading the Identity matrix means that no transformations are performed on the vertices. In essence, you are resetting the Modelview matrix back to the origin.
The following two lines load the identity matrix into the Modelview matrix:
The first line specifies that the current operating matrix is the Modelview matrix. Once you set the current operating matrix (the matrix that your matrix functions are affecting), it remains the active matrix until you change it. The second line loads the current matrix (in this case, the Modelview matrix) with the identity matrix.
Now the following code will produce results as shown in Figure 7-13:
// Set current matrix to Modelview and reset glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Go 10 units up the y-axis glTranslatef(0.0f, 10.0f, 0.0f); // Draw the first sphere auxSolidSphere(1.0f); // Reset Modelview matrix again glLoadIdentity(); // Go 10 units out the x-axis glTranslatef(10.0f, 0.0f, 0.0f); // Draw the second sphere auxSolidSphere(1.0f);
It is not always desirable to reset the Modelview matrix to Identity before placing every object. Often you will want to save the current transformation state and then restore it after some objects have been placed. This is most convenient when you have initially transformed the Modelview matrix as your viewing transformation (and thus are no longer located at the origin).
To facilitate this, OpenGL maintains a matrix stack for both the Modelview and Projection matrices. A matrix stack works just like an ordinary program stack. You can push the current matrix onto the stack to save it, then make your changes to the current matrix. Popping the matrix off the stack then restores it. Figure 7-16 shows the stack principle in action.
The stack depth can reach a maximum value that can be retrieved with a call to either
If you exceed the stack depth, you’ll get a GL_STACK_OVERFLOW; if you try to pop a matrix value off the stack when there is none, you will generate a GL_STACK_UNDERFLOW. The stack depth is implementation dependent. For the Microsoft software implementation these values are 32 for the Modelview and 2 for the Projection stack.