18. OpenGL Popping and Pushing Matrices (Version 2.0)
Introduction
In OpenGL, transformations such as rotations, translations, and color changes can accumulate, affecting all subsequent objects. This behavior occurs because OpenGL operates as a state machine, where each transformation modifies the current state and remains active until explicitly changed.
This tutorial explores how to control transformations using matrix stacks, specifically with glPushMatrix()
and glPopMatrix()
. These commands allow you to isolate transformations for individual objects, making it possible to manipulate them independently within the same scene.
Understanding Matrix Stacks
OpenGL uses matrix stacks to manage transformations. Each stack operates like a stack of plates:
– glPushMatrix(): Saves the current transformation state onto the stack.
– glPopMatrix(): Restores the last saved transformation state, discarding any changes made since the corresponding glPushMatrix()
.
Why Use Matrix Stacks?
Matrix stacks are essential for scenarios where you want to:
– Apply transformations to one object without affecting others.
– Temporarily modify the transformation state for a specific task, then revert to the previous state.
Here’s an example:
glPushMatrix(); // Save the current state glTranslatef(1.0, 0.0, 0.0); // Apply translation glRotatef(45.0, 0.0, 1.0, 0.0); // Apply rotation glutWireCube(1.0); // Draw a cube glPopMatrix(); // Revert to the previous state
In this example, the translation and rotation only affect the cube drawn between the glPushMatrix()
and glPopMatrix()
calls.
Attributes and Matrix Stacks
Beyond transformations, OpenGL provides glPushAttrib()
and glPopAttrib()
to save and restore specific attributes, such as lighting and colors. These commands allow finer control over the rendering state:
glPushAttrib(GL_LIGHTING_BIT); // Save the lighting attributes glEnable(GL_LIGHTING); // Enable lighting glPopAttrib(); // Restore the previous lighting state
Tutorial Code
Below is a complete example demonstrating how to use glPushMatrix()
and glPopMatrix()
to control transformations for two independently rotating cubes:
// Include necessary libraries #include <GL/gl.h> #include <GL/glut.h> GLfloat angle = 0.0; // Rotation angle for the first cube GLfloat tangle = 0.0; // Rotation angle for the second cube // Draw the first cube void cube(void) { glPushMatrix(); // Save the current state glTranslatef(1.0, 0.0, 0.0); // Move the cube to the right glRotatef(angle, 1.0, 0.0, 0.0); // Rotate around the X-axis glRotatef(angle, 0.0, 1.0, 0.0); // Rotate around the Y-axis glRotatef(angle, 0.0, 0.0, 1.0); // Rotate around the Z-axis glColor3f(1.0, 0.0, 0.0); // Set the cube's color to red glutWireCube(2.0); // Draw the cube glPopMatrix(); // Restore the previous state } // Draw the second cube void cube2(void) { glPushMatrix(); // Save the current state glTranslatef(-1.0, 0.0, 0.0); // Move the cube to the left glRotatef(tangle, 1.0, 0.0, 0.0); // Rotate around the X-axis glRotatef(tangle, 0.0, 1.0, 0.0); // Rotate around the Y-axis glRotatef(tangle, 0.0, 0.0, 1.0); // Rotate around the Z-axis glColor3f(0.0, 1.0, 0.0); // Set the cube's color to green glutWireCube(2.0); // Draw the cube glPopMatrix(); // Restore the previous state } // Display callback void display(void) { glClearColor(0.0, 0.0, 0.0, 1.0); // Set the background color to black glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer glLoadIdentity(); gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); // Position the camera cube(); // Draw the first cube cube2(); // Draw the second cube glutSwapBuffers(); angle += 1.0; // Increment the first cube's angle tangle += 2.0; // Increment the second cube's angle } // Reshape callback void reshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, (GLfloat)w / (GLfloat)h, 1.0, 100.0); glMatrixMode(GL_MODELVIEW); } // Main function int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE); glutInitWindowSize(500, 500); glutCreateWindow("Push and Pop Matrix Example"); glutDisplayFunc(display); glutIdleFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; }
If you have any questions or run into issues, feel free to email me at swiftless@gmail.com. Happy coding!
Hi
I am currently studying openGL etc and there is a certain method to work out the CTM…i was hoping maybe someone knows how to do this method. I understand the individual Matrix for each (Translate, Scale and Rotate) but there is a certain easier method used when you put them all together to obtain your new point. I would appreciate the help!
Thanks
Very, very big fan of your tutorials Swiftless.
Thank you again. They are terrific.
-kropcke
I get how to use them, but about how they work: Does it add and subtract the matrices, or does it store on Push, and reset to identity, then transform to stored position / orientation? And can you have nested Push/Pops? ex:
push()
translate
push()
draw
pop()
pop()
push()
rotate
push()
draw
pop()
push()
draw
pop()
pop()
Hi Theo,
The way matrices work in OpenGL, are based on a Stack setup.
You start off with a matrix on the stack called the “Transformation Matrix” (there are also ones for textures and the projection), every time you do a call to glTranslate or glRotate, this changes the “Transformation Matrix”. If you call glPushMatrix, it takes an exact duplicate of the current “Transformation Matrix” and puts this on the top of the stack and this becomes the current matrix for all further glTranslate or glRotate calls. You can nest as many of these as you like within each other. Then once you call glPopMatrix, it pops the current “Transformation Matrix” off the stack and forgets it, and the previous “Transformation Matrix” becomes the current.
I hope this helps a little.
Cheers,
Swiftless
Thank you very much, Swiftless. This is the best explanation of the OpenGL Transformation Matrix Stack I have found.
=| thanks for trying to explain, but im still lost. Don’t feel bad, 4 people ahve tried to explain it to me… I am still clueless… you should be on ##opengl on freenode
Is this article not done yet? I don’t see anything.
It should be up now sorry, I have had a few posts suddenly stop showing, but I think I have fixed them all now.
Cheers,
Swiftless