# Replicating deprecated matrix stack

This topic is 2799 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi, I'm writing a small app at the moment to demo some shader techniques, I was originally using the matrix stack and using the built-in uniforms in the shader code, however I want to switch to sending the model and view matrices separately to the shader. I'm using the glut teapot as one of the models, and looking at the glut source code, the following transformations are applied to the matrix stack before drawing:

 glPushMatrix(); glRotated( 270.0, 1.0, 0.0, 0.0 ); glScaled( 0.5 * scale, 0.5 * scale, 0.5 * scale ); glTranslated( 0.0, 0.0, -1.5 ); glPopMatrix(); 

So the matrix stack has the following matrices multiplied together:
camera transform
rotate around y-axis
translate along z-axis
glutteapot base transforms (as above)

How can I replicate this without using the stack? I have a matrix/vector library (SVL) that can generate rotation/translation/scale matrices.

##### Share on other sites
I've just finished a rewrite of my engine to address this. I created my own Matrix code, you'll find it very helpful to learn this because its one of the most important parts of any 3D app. Another option is to read the OpenGL Super Bible and look at his code to see how it can be done. I personally don’t use a stack system but prefer the scene hierarchy itself to store Matrix data. My code needs optimizing still :-)

 class lsMatrix4x4 { public: lsMatrix4x4(); lsMatrix4x4(const float mat4[16]); lsMatrix4x4(const lsQuaternion &q, float x=0, float y=0, float z=0); virtual ~lsMatrix4x4(); lsVector3 Rotate(const lsVector3 &v); void Set(const lsQuaternion &q, float x=0, float y=0, float z=0); void LoadIdentity(); // Transformations void RotateMatrix( float angle, float x, float y, float z ); void TranslateMatrix( float x, float y, float z ); void ScaleMatrix( float x, float y, float z ); // Utilities void PerspectiveProjection( float fovy, float aspect_ratio, float near_plane, float far_plane ); void OrthographicProjection( float xMin, float xMax, float yMin, float yMax, float zMin, float zMax ); float Cotangent(float angle); void LookAt( const lsVector3& eyePosition, const lsVector3& lookAt, const lsVector3& upVector ); lsMatrix4x4& operator=(const lsMatrix4x4& m); lsMatrix4x4& operator*=( const lsMatrix4x4& B ); lsMatrix4x4 operator*( const lsMatrix4x4& B ); lsVector3 operator*(const lsVector3 &v); // Debug void debug( const string& str ); // Data float matrix[16]; }; 

Here's my Matrix class: functions

 #include <string.h> #include "lsMatrix4x4.h" #include "lsVector3.h" #include "lsQuaternion.h" #include "lsMath.h" lsMatrix4x4::lsMatrix4x4() { // identity matrix[ 0]=1; matrix[ 1]=0; matrix[ 2]=0; matrix[ 3]=0; matrix[ 4]=0; matrix[ 5]=1; matrix[ 6]=0; matrix[ 7]=0; matrix[ 8]=0; matrix[ 9]=0; matrix[10]=1; matrix[11]=0; matrix[12]=0; matrix[13]=0; matrix[14]=0; matrix[15]=1; } lsMatrix4x4::lsMatrix4x4(const float mat4[16]) { memcpy( matrix, mat4, sizeof(float)*16 ); } lsMatrix4x4::lsMatrix4x4(const lsQuaternion& q, float x, float y, float z) { Set(q,x,y,z); } lsMatrix4x4::~lsMatrix4x4() { } void lsMatrix4x4::LoadIdentity() { // identity matrix[ 0]=1; matrix[ 1]=0; matrix[ 2]=0; matrix[ 3]=0; matrix[ 4]=0; matrix[ 5]=1; matrix[ 6]=0; matrix[ 7]=0; matrix[ 8]=0; matrix[ 9]=0; matrix[10]=1; matrix[11]=0; matrix[12]=0; matrix[13]=0; matrix[14]=0; matrix[15]=1; } lsVector3 lsMatrix4x4::Rotate(const lsVector3& v) { lsVector3 ret; ret.x = matrix[ 0]*v.x + matrix[ 1]*v.y + matrix[ 2]*v.z; ret.y = matrix[ 4]*v.x + matrix[ 5]*v.y + matrix[ 6]*v.z; ret.z = matrix[ 8]*v.x + matrix[ 9]*v.y + matrix[10]*v.z; return ret; } void lsMatrix4x4::Set( const lsQuaternion& q, float x, float y, float z) { float x2 = q.x + q.x; float y2 = q.y + q.y; float z2 = q.z + q.z; float wx = q.w*x2; float wy = q.w*y2; float wz = q.w*z2; float xx = q.x*x2; float xy = q.x*y2; float xz = q.x*z2; float yy = q.y*y2; float yz = q.y*z2; float zz = q.z*z2; matrix[ 0] = 1 - (yy + zz); matrix[ 1] = xy - wz; matrix[ 2] = xz + wy; matrix[ 3] = x; matrix[ 4] = xy + wz; matrix[ 5] = 1 - (xx + zz); matrix[ 6] = yz - wx; matrix[ 7] = y; matrix[ 8] = xz - wy; matrix[ 9] = yz + wx; matrix[10]= 1 - (xx + yy); matrix[11]= z; matrix[12] = 0; matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; } lsMatrix4x4& lsMatrix4x4::operator=( const lsMatrix4x4& m ) { // Same object? if (this == &m) { cout << "lsMatrix4x4::operator= ERROR: Same object" << endl; return *this; } // Copy matrix[ 0] = m.matrix[ 0]; matrix[ 1] = m.matrix[ 1]; matrix[ 2] = m.matrix[ 2]; matrix[ 3] = m.matrix[ 3]; matrix[ 4] = m.matrix[ 4]; matrix[ 5] = m.matrix[ 5]; matrix[ 6] = m.matrix[ 6]; matrix[ 7] = m.matrix[ 7]; matrix[ 8] = m.matrix[ 8]; matrix[ 9] = m.matrix[ 9]; matrix[10] = m.matrix[10]; matrix[11] = m.matrix[11]; matrix[12] = m.matrix[12]; matrix[13] = m.matrix[13]; matrix[14] = m.matrix[14]; matrix[15] = m.matrix[15]; return *this; } lsMatrix4x4& lsMatrix4x4::operator*=( const lsMatrix4x4& B ) { lsMatrix4x4 ret; lsMatrix4x4 A = *this; for( int i = 0; i < 4; i++ ) { float ai0 = A.matrix[0*4+i], ai1 = A.matrix[1*4+i], ai2 = A.matrix[2*4+i], ai3 = A.matrix[3*4+i]; ret.matrix[0*4+i] = ai0 * B.matrix[ 0] + ai1 * B.matrix[ 1] + ai2 * B.matrix[ 2] + ai3 * B.matrix[ 3]; ret.matrix[1*4+i] = ai0 * B.matrix[ 4] + ai1 * B.matrix[ 5] + ai2 * B.matrix[ 6] + ai3 * B.matrix[ 7]; ret.matrix[2*4+i] = ai0 * B.matrix[ 8] + ai1 * B.matrix[ 9] + ai2 * B.matrix[10] + ai3 * B.matrix[11]; ret.matrix[3*4+i] = ai0 * B.matrix[12] + ai1 * B.matrix[13] + ai2 * B.matrix[14] + ai3 * B.matrix[15]; } *this = ret; return *this; } /* * for (int i = 0; i < 4; i++) { * float ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3); * P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0); * P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1); * P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2); * P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3); * } * */ lsMatrix4x4 lsMatrix4x4::operator*( const lsMatrix4x4& B ) { lsMatrix4x4 ret; lsMatrix4x4 A = *this; for( int i = 0; i < 4; i++ ) { float ai0 = A.matrix[0*4+i], ai1 = A.matrix[1*4+i], ai2 = A.matrix[2*4+i], ai3 = A.matrix[3*4+i]; ret.matrix[0*4+i] = ai0 * B.matrix[ 0] + ai1 * B.matrix[ 1] + ai2 * B.matrix[ 2] + ai3 * B.matrix[ 3]; ret.matrix[1*4+i] = ai0 * B.matrix[ 4] + ai1 * B.matrix[ 5] + ai2 * B.matrix[ 6] + ai3 * B.matrix[ 7]; ret.matrix[2*4+i] = ai0 * B.matrix[ 8] + ai1 * B.matrix[ 9] + ai2 * B.matrix[10] + ai3 * B.matrix[11]; ret.matrix[3*4+i] = ai0 * B.matrix[12] + ai1 * B.matrix[13] + ai2 * B.matrix[14] + ai3 * B.matrix[15]; } return ret; } lsVector3 lsMatrix4x4::operator*(const lsVector3& v) { lsVector3 ret; ret.x = matrix[ 0]*v.x + matrix[ 1]*v.y + matrix[ 2]*v.z + matrix[ 3]; ret.y = matrix[ 4]*v.x + matrix[ 5]*v.y + matrix[ 6]*v.z + matrix[ 7]; ret.z = matrix[ 8]*v.x + matrix[ 9]*v.y + matrix[10]*v.z + matrix[11]; return ret; } //! Rotate transform /*! * Build a rotation matrix. * \n\n * angle is given in degrees and rotates CCW.\n * x,y,z is the vector to rotate around. * * */ void lsMatrix4x4::RotateMatrix( float angle, float x, float y, float z ) { lsMatrix4x4 rot; float s, c; float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c; angle = angle*(ANG2RAD); s = sin(angle); c = cos(angle); xx = x * x; yy = y * y; zz = z * z; xy = x * y; yz = y * z; zx = z * x; xs = x * s; ys = y * s; zs = z * s; one_c = 1.0 - c; rot.matrix[ 0] = (one_c * xx) + c; rot.matrix[ 4] = (one_c * xy) - zs; rot.matrix[ 8] = (one_c * zx) + ys; rot.matrix[12] = 0.0; rot.matrix[ 1] = (one_c * xy) + zs; rot.matrix[ 5] = (one_c * yy) + c; rot.matrix[ 9] = (one_c * yz) - xs; rot.matrix[13] = 0.0; rot.matrix[ 2] = (one_c * zx) - ys; rot.matrix[ 6] = (one_c * yz) + xs; rot.matrix[10] = (one_c * zz) + c; rot.matrix[14] = 0.0; rot.matrix[ 3] = 0.0; rot.matrix[ 7] = 0.0; rot.matrix[11] = 0.0; rot.matrix[15] = 1.0; *this *= rot; } void lsMatrix4x4::TranslateMatrix(float x, float y, float z) { lsMatrix4x4 trans; trans.matrix[12] = x; trans.matrix[13] = y; trans.matrix[14] = z; *this = trans; } void lsMatrix4x4::ScaleMatrix(float x, float y, float z) { lsMatrix4x4 mat; mat.matrix[ 0] = x; mat.matrix[ 5] = y; mat.matrix[10] = z; *this = mat; } void lsMatrix4x4::PerspectiveProjection(float fovy, float aspect_ratio, float near_plane, float far_plane) { matrix[15] = 0; float y_scale = Cotangent((fovy*ANG2RAD) / 2 ); float x_scale = y_scale / aspect_ratio; float frustum_length = far_plane - near_plane; matrix[ 0] = x_scale; matrix[ 5] = y_scale; matrix[10] = -((far_plane + near_plane) / frustum_length); matrix[11] = -1; matrix[14] = -((2 * near_plane * far_plane) / frustum_length ); } void lsMatrix4x4::OrthographicProjection( float xMin, float xMax, float yMin, float yMax, float zMin, float zMax ) { LoadIdentity(); matrix[0] = 2.0 / (xMax - xMin); matrix[5] = 2.0 / (yMax - yMin); matrix[10] = -2.0 / (zMax - zMin); matrix[12] = -((xMax + xMin)/(xMax - xMin)); matrix[13] = -((yMax + yMin)/(yMax - yMin)); matrix[14] = -((zMax + zMin)/(zMax - zMin)); matrix[15] = 1.0; } float lsMatrix4x4::Cotangent(float angle) { return (float)(1.0 / tan(angle)); } //! ViewMatrix /*! * Build a view matrix from the given values. * */ void lsMatrix4x4::LookAt( const lsVector3& eyePosition, const lsVector3& lookAt, const lsVector3& upVector ) { lsMath math; lsVector3 e, l, u; lsVector3 forward, side, up; lsMatrix4x4 rotmat, transmat; e = eyePosition; l = lookAt; u = upVector; // make sure up is normalized up = upVector; up.normalize(); // up.debug( "up: " ); // forward vector forward = l - e; forward.normalize(); // forward.debug( "forward: " ); // side vector side = math.Cross( forward, up ); side.normalize(); // side.debug( "side: " ); rotmat.matrix[0] = side.x; rotmat.matrix[4] = side.y; rotmat.matrix[8] = side.z; rotmat.matrix[1] = up.x; rotmat.matrix[5] = up.y; rotmat.matrix[9] = up.z; rotmat.matrix[2] = -forward.x; rotmat.matrix[6] = -forward.y; rotmat.matrix[10] = -forward.z; transmat.TranslateMatrix( -e.x, -e.y, -e.z ); *this *= rotmat * transmat; } void lsMatrix4x4::debug( const string& str ) { cout << "Matrix : " << str << endl; int k; for( int i=0; i<4; i++ ) { for( int j=0; j<13; j+=4 ) { k = j+i; // cout << " m[" << k << "] = " << mat[k]; cout << "[ " << matrix[k] << " ] "; } cout << endl; } } 

And to use this I just call the next bit of code during my Move phase.

 transmat.TranslateMatrix( position.x, position.y, position.z ); rotmat.RotateMatrix( rotation.x, 1, 0, 0 ); rotmat.RotateMatrix( rotation.y, 0, 1, 0 ); rotmat.RotateMatrix( rotation.z, 0, 0, 1 ); scalemat.ScaleMatrix( scale.x, scale.y, scale.z ); if( parent_node ) ModelMatrix = parent_node->getModelMatrix(); else ModelMatrix.LoadIdentity(); ModelMatrix *= transmat * rotmat * scalemat; 

##### Share on other sites
Hi, maybe I should clarify a bit, I know how to generate and multiply transformation matrices together, the problem I am having is that I want to use matrices computed in the app to position an object in exactly the same way as I have done using glScale/glRotate/glTranslate. My problem is that I can't figure out the correct order. Using SVL, the matrix code I have tried looks like this:

 //base transform as defined in glut_teapot.c teapotBaseTransform = HTrans4(Vec3(0, 0, -1.5)) * HScale4(Vec3(0.5, 0.5, 0.5)) * HRot4(Vec3(1, 0, 0), 1.5 * M_PI); //this is updated every frame to rotate the object worldTransform = HTrans4(Vec3(-2, 0, 0)) * HRot4(Vec3(0, 1, 0), rotAngle / (180.0f / M_PI)); //multiply both together to get the total matrix transform for the teapot teapotTransform = teapotBaseTransform * worldTransform; 

##### Share on other sites
Make sure that your matrices elements are in the same order as that produced by GL. You can compute the matrices with GL and then download them with glGetFloatv. That's what I did for my lib.

##### Share on other sites
Yes, I did the same.. Use the old GL functions just to view whats happening then match it to the LIB your using. You may just have the Matrix Multiply in the wrong order. But I really Really recommend you make your own Matrix stack. You say you already know how, but your still using a lib to do it?

##### Share on other sites
OpenGL used column vectors, and matrix multiplication "on the stack" was done right sided (i.e. on the more local side). Hence, using the OP's example

 glRotated( 270.0, 1.0, 0.0, 0.0 ); glScaled( 0.5 * scale, 0.5 * scale, 0.5 * scale ); glTranslated( 0.0, 0.0, -1.5 ); 

means that the new matrix M[sub]i+1[/sub] is computed as
M[sub]i+1[/sub] := M[sub]i[/sub] * R * S * T
where M[sub]i[/sub] was the matrix previously on the stack (probably the VIEW matrix) and R, S, and T mean the rotation, scaling, and translation, resp. Notice please that the order of commands from top to bottom corresponds to the order of matrices from left to right in the formula.

glPushMatrix / glPopMatrix does nothing more than to store / restore the current matrix for further use. Because this is implemented as a stack, the stack-typical operations "push" and "pop" are used. Push simply creates a copy of the current top matrix as new top matrix, while pop removes the current top matrix, making the new lower matrix the new top one. The other routines (like glLoadIdentity, glMultMatrix, glRotated, ...) just replace the top matrix with the new one.

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 15
• 11
• 9
• 11
• 15