The Matrix Stack

Up until now, we have used matrices like this with OpenGL ES:

gl.glMatrixMode(GL10.GL_PR0JECTI0N); gl.glLoadIdentity(); gl.gl0rthof(-1, 1, -1, 1, -10, 10);

The first statement sets the currently active matrix. All subsequent matrix operations will be executed on that matrix. In this case, we set the active matrix to an identity matrix and then multiply it by an orthographic projection matrix. We did something similar with the model-view matrix:

gl.glMatrixMode(GL10.GL_M0DELVIEW); gl.glLoadIdentity(); gl.glTranslatef(0, 0, -10); gl.glRotate(45, 0, 1, 0);

This snippet manipulates the model-view matrix. It first loads an identity matrix to clear whatever was in the model-view matrix before that call. Next it multiplies the matrix with a translation matrix and a rotation matrix. This order of multiplication is important, as it defines in what order these transformations get applied to the vertices of our meshes. The last transformation we specify will be the first to be applied to the vertices. In the preceding case, we first rotate each vertex by 45 degrees around the y-axis. Then we move each vertex by -10 units along the z-axis.

In both cases all the transformations are encoded in a single matrix, in either the OpenGL ES projection or model-view matrix. But it turns out that for each matrix type, there's actually a stack of matrices at our disposal.

For now we're only using a single slot in this stack: the top of the stack (TOS). The TOS of a matrix stack is the one actually used by OpenGL ES to transform our vertices, be it with the projection or model-view matrix. Any matrix below the TOS on the stack just sits there idly, waiting to become the new TOS. So how can we manipulate this stack?

OpenGL ES has two methods we can use to push and pop the current TOS:

GL10.glPushMatrix(); GL10.glPopMatrix();

Like glTranslatef() and consorts, these methods always work on the currently active matrix stack that we set via glMatrixMode().

The glPushMatrix() method takes the current TOS, makes a copy of it, and pushes it on the stack. The glPopMatrix() method takes the current TOS and pops it from the stack so that the element below it becomes the new TOS. Let's work through a little example:

gl.glMatrixMode(GL10.GL_M0DELVIEW);

gl.glLoadIdentity();

gl.glTranslate(0,0,-10);

Up until this point, there has only been a single matrix on the model-view matrix stack. Let's "save" this matrix:

gl.glPushMatrix();

Now we've made a copy of the current TOS and pushed down the old TOS. We have two matrices on the stack now, each encoding a translation on the z-axis by -10 units.

Since matrix operations always work on the TOS, we now have a scaling operation, a rotation, and a translation encoded in the top matrix. The matrix we pushed still only contains a translation. When we now render a mesh given in model space, like our cube, it will first be scaled on the y-axis, then rotated around the y-axis, and then translated by -10 units on the z-axis. Let's pop the TOS:

gl.glPopMatrix();

This will remove the TOS and make the matrix below it the new TOS. In our example, that's the original translation matrix. After this call there's only one matrix on the stack again—the one we initialized in the beginning of the example. If we render an object now, it will only be translated by -10 units on the z-axis. The matrix containing the scaling, rotation, and translation is gone due to us popping it from the stack. Figure 1013 shows what happens to the matrix stack when we execute the preceding code.

Figure 10-13. Manipulating the matrix stack

So what's this good for? The first thing we can use it for is to remember transformations that should be applied to all the objects in our world. Say we want all objects in our world to be offset by 10 units on each axis. We could do the following:

gl.glMatrixMode(GL10.GL_M0DELVIEW); gl.glLoadIdentity(); gl.glTranslatef(10, 10, 10); for( MyObject obj: myObjects) { gl.glPushMatrix();

gl.glTranslatef(obj.x, obj.y, obj.z); gl.glRotatef(obj.angle, 0, 1, 0);

// render model of object given in model space, e.g., the cube gl.glPopMatrix();

We will use this pattern later on when we discuss how to create a camera system in 3D. The camera position and orientation is usually encoded as a matrix. We will load this camera matrix, which will transform all objects in such a way that we see them from the camera's point of view. There's something even better we can use the matrix stack for, though.

0 0

Post a comment