*sigh* Matrix problems

Started by
14 comments, last by Ali_B 18 years, 9 months ago
What I'm trying to do is create a matrix class which mimics OpenGL's matrix implementation. This is a real bugger, since every article I have found explains things differently and, for the most part, badly. What I want is to: 1. Be able to concatenate transformations like in OpenGL, ie. be able to multiply my one matrix by another 2. Implement rotations by creating a rotation matrix, then multiplying the currewnt matrix by that rotation matrix This is what I have so far:

// These functions are members of class Matrix4x4

             void multiplyBy(const Matrix4x4 &mat) {
                  float newData[16];

                  newData[0]  = data[0] * mat.data[0]  +  data[1] * mat.data[4]  +  data[2] * mat.data[8]  +  data[3] * mat.data[12];
                  newData[1]  = data[0] * mat.data[1]  +  data[1] * mat.data[5]  +  data[2] * mat.data[6]  +  data[3] * mat.data[13];
                  newData[2]  = data[0] * mat.data[2]  +  data[1] * mat.data[6]  +  data[2] * mat.data[10]  +  data[3] * mat.data[14];                  
                  newData[3]  = data[0] * mat.data[3]  +  data[1] * mat.data[7]  +  data[2] * mat.data[11]  +  data[3] * mat.data[15];

                  newData[4]  = data[4] * mat.data[0]  +  data[5] * mat.data[4]  +  data[6] * mat.data[8]  +  data[7] * mat.data[12];
                  newData[5]  = data[4] * mat.data[1]  +  data[5] * mat.data[5]  +  data[6] * mat.data[6]  +  data[7] * mat.data[13];
                  newData[6]  = data[4] * mat.data[2]  +  data[5] * mat.data[6]  +  data[6] * mat.data[10]  +  data[7] * mat.data[14];                  
                  newData[7]  = data[4] * mat.data[3]  +  data[5] * mat.data[7]  +  data[6] * mat.data[11]  +  data[7] * mat.data[15];

                  newData[8]  = data[8] * mat.data[0]  +  data[9] * mat.data[4]  +  data[10] * mat.data[8]  +  data[11] * mat.data[12];
                  newData[9]  = data[8] * mat.data[1]  +  data[9] * mat.data[5]  +  data[10] * mat.data[6]  +  data[11] * mat.data[13];
                  newData[10] = data[8] * mat.data[2]  +  data[9] * mat.data[6]  +  data[10] * mat.data[10]  +  data[11] * mat.data[14];                  
                  newData[11] = data[8] * mat.data[3]  +  data[9] * mat.data[7]  +  data[10] * mat.data[11]  +  data[11] * mat.data[15];

                  newData[12] = data[12] * mat.data[0]  +  data[13] * mat.data[4]  +  data[14] * mat.data[8]  +  data[15] * mat.data[12];
                  newData[13] = data[12] * mat.data[1]  +  data[13] * mat.data[5]  +  data[14] * mat.data[6]  +  data[15] * mat.data[13];
                  newData[14] = data[12] * mat.data[2]  +  data[13] * mat.data[6]  +  data[14] * mat.data[10]  +  data[15] * mat.data[14];                  
                  newData[15] = data[12] * mat.data[3]  +  data[13] * mat.data[7]  +  data[14] * mat.data[11]  +  data[15] * mat.data[15];

                  // copy new information into current matrix
                  for(int count=0; count<16; ++count)
                      data[count] = newData[count];
                  }



             void rotatef(float angle, float x, float y, float z) {
                  // ..convert angle to radians..
                  angle *= 0.0174532925;

                  Matrix4x4 temp;

                  // Rotate around X axis
                  if(x > 0.0) {
                     temp.data[5]  =  cos( angle );
                     temp.data[6]  = -sin( angle );
                     temp.data[9]  =  sin( angle );
                     temp.data[10] =  cos( angle );                                                               
                     }

                  // Rotate around Y axis
                  if(y > 0.0) {
                     temp.data[0]  =  cos( angle );
                     temp.data[2]  =  sin( angle );
                     temp.data[8]  = -sin( angle );
                     temp.data[10] =  cos( angle );                                                               
                     }

                  // Rotate around Z axis
                  if(z > 0.0) {
                     temp.data[0]  =  cos( angle );
                     temp.data[1]  = -sin( angle );
                     temp.data[4]  =  sin( angle );
                     temp.data[5]  =  cos( angle );                                                               
                     }

                     multiplyBy(temp);
                  }



This doesn't work properly, however. I basically create the matrix, load it to identity, and then call rotatef on that matrix. I then load the matrix with glLoadMatrixf. This seems to produce the opposite effect of calling glRotatef with the same values. Using glLoadTransposeMatrixf, however, seems to work. This tells me that my matrices aren't entirely broken, just muddled up- and I have no idea why. Big rates to anyone who can help me!
the rug - funpowered.com
Advertisement
based on what you said at the end (as i cant be bothered to check your maths, heh) you are performing a row major operation when you should be treating the matrix as column major to get the right effect.

Thus, glLoadTransposeMatrixf works as it transposes the matrix from row major to column major.
potential insight:

remember that ogl uses column major whereas many tutorials present the row major form of matrix mulitplies in referene to rotations,scale and translates. so for instance the translation vector is in the fourth column, not the fourth row.

this would explain why the transpose resolves the issue, too.
Well, I'm in a bit of a pickle now, since it turns out glLoadTransposeMatrixf only worked for the simplest of rotations. So I'm starting to think the problem is something else (orinigating somewhere between my keyboard and my chair, most likely...)

I hate to just ask for code, but I think its the only way I'm going to understand this. If anyone has any OpenGL matrix code for multiplying matrices, I'd love to see it.

Thanks a lot to the previous posters (Ali_B gets an A for effort [wink])
the rug - funpowered.com
for the operation:
ret = mat * v

	ret[0] = (mat[0]*v[0]) + (mat[4]*v[1]) + (mat[8]*v[2]) + (mat[12]*v[3]);	ret[4] = (mat[0]*v[4]) + (mat[4]*v[5]) + (mat[8]*v[6]) + (mat[12]*v[7]);	ret[8] = (mat[0]*v[8]) + (mat[4]*v[9]) + (mat[8]*v[10])+ (mat[12]*v[11]);	ret[12]= (mat[0]*v[12])+ (mat[4]*v[13])+ (mat[8]*v[14])+ (mat[12]*v[15]);	ret[1] = (mat[1]*v[0]) + (mat[5]*v[1]) + (mat[9]*v[2]) + (mat[13]*v[3]);	ret[5] = (mat[1]*v[4]) + (mat[5]*v[5]) + (mat[9]*v[6]) + (mat[13]*v[7]);	ret[9] = (mat[1]*v[8]) + (mat[5]*v[9]) + (mat[9]*v[10])+ (mat[13]*v[11]);	ret[13]= (mat[1]*v[12])+ (mat[5]*v[13])+ (mat[9]*v[14])+ (mat[13]*v[15]);	ret[2] = (mat[2]*v[0]) + (mat[6]*v[1]) + (mat[10]*v[2]) + (mat[14]*v[3]);	ret[6] = (mat[2]*v[4]) + (mat[6]*v[5]) + (mat[10]*v[6]) + (mat[14]*v[7]);	ret[10]= (mat[2]*v[8]) + (mat[6]*v[9]) + (mat[10]*v[10])+ (mat[14]*v[11]);	ret[14]= (mat[2]*v[12])+ (mat[6]*v[13])+ (mat[10]*v[14])+ (mat[14]*v[15]);	ret[3] = (mat[3]*v[0]) + (mat[7]*v[1]) + (mat[11]*v[2]) + (mat[15]*v[3]);	ret[7] = (mat[3]*v[4]) + (mat[7]*v[5]) + (mat[11]*v[6]) + (mat[15]*v[7]);	ret[11]= (mat[3]*v[8]) + (mat[7]*v[9]) + (mat[11]*v[10])+ (mat[15]*v[11]);	ret[15]= (mat[3]*v[12])+ (mat[7]*v[13])+ (mat[11]*v[14])+ (mat[15]*v[15]);


This is my operator * code and I use my matrix class with opengl (including glmultmatrixf). So if this doesnt work for you then your problem is elsewhere.

About rotation, when you create temp, does the constructor initialize it to the identity?
Thankyou, that is awesome!

Yes, it was my numbers that were jiggered. Ah well, I should pay more attention. Just so you know the_phantom, I did rate you up again, but it made absolutely no difference [grin]

Ahhh, GameDev. Is there anything it can't do?
the rug - funpowered.com
float mtx[16];/*IN OpenGL:|Rx  0   0   Tx||0   Ry  0   Ty||0   0   Rz  Tz||0   0   0   1 |therefore:|0   1   2   3 ||4   5   6   7 ||8   9   10  11||12  13  14  15|and thusly:mtx[0]  == Rxmtx[5]  == Rymtx[10] == RztehTranslate3f = mtx[3], mtx[7], mtx[11]*/


Now when you do rotations with matrices you perform them in some developer defined order, right? let's pretend you multiply matrices A by B by C in Dx/row major/LHSsystems. Notice that the ANS matrix will be also be in Dx/Row Major/LHS form.

ANS = A * B * C

However to accomplish the same results when the matrices are in OGL/column major/RHS systems would be to multiply them in reverse order, which results in the ANS matrix to be in the OGL/Column Major/RHS form.

ANS = C * B * A


consider the following example:

let A and b be LHS matrices where
A =
|1 2|
|3 4|
B=
|5 6|
|7 8|
ANS = A * B =
|(1*5 + 2*7) (1*6 + 2*8)|
|(3*5 + 4*7) (3*6 + 4*8)|
=
|19 22|
|43 42|

now let's try it in RHS where A and B are
A =
|1 3|
|2 4|
B=
|5 7|
|6 8|
ANS = B * A =
|(5*1 + 7*2) (5*3 + 7*4)|
|(6*1 + 8*2) (6*3 + 8*4)|
=
|19 43|
|22 42|
= transpose of ANS in the LHS system


now why all this info .. perhaps you have the order matrix mulitplies backwards (for the rotations, translations and projections) in your code, and you mulitply method is actually a-ok? after all, in general matrix mulitplicaiton is not commutative. just another possibility for you to consider.
Maybe I'm being an ass, but it seems that OpenGL can do these things for you and possibly be more efficent(not to insult anybody).

// R = M * V

float* multMatrix(const float M[16], const float V[16]) // you guys seem to like those letters
{
float R[16]; // result

glMatrixMode (GL_MODELVIEW); // you can use any matrix, but we need to choose one
glPushMatrix ();
glLoadMatrixf(M); // GL_MATRIX = M
glMultMatrixf(V); // GL_MATRIX = M * V
glGetFloatv (GL_MODELVIEW_MATRIX, R); // R = GL_MATRIX -> R = M * V
glPopMatrix();

return R;
}

// optional matrix:
// glMatrixMode can have GL_MODELVIEW, GL_PROJECTION or GL_TEXTURE
// thus glGetFloatv must have GL_MODELVIEW_MATRIX, GL_PROJECTION_MATRIX or GL_TEXTURE_MATRIX respectivly


this way you can also preform OpenGL operations and output the matrix to see the resulting matrix, just trying to help
glLoadTransposeMatrixf is it extension or what i can't find it in the blue book??

This topic is closed to new replies.

Advertisement