# The Industry's Foundation for High Performance Graphics

1. ## Matrix composition

Hi,

I've just started getting back into OpenGL and have started to write some matrix functions. I decided to separate out the 4x4 matrix into a 3x3 matrix for rotation and scale and use a 3 vector for the translation. Now, I worked out the proof that I needed to compose this into a 4x4 matrix.

Given that a 4x4 matrix is composed thus:

Code :
```     |M|T|
M1 = -----
|0|1|```
Where M1 is a 3x3 matrix and T is a column vector representing the translation.

This is the formula for multiplying 2 4x4 matrices:

Code :
```    |m0 m4 m8  m12|     |t0 t4 t8  t12|
M = |m1 m5 m9  m13| T = |t1 t5 t9  t13|
|m2 m6 m10 m14|     |t2 t6 t10 t14|
|m3 m7 m11 m15|     |t3 t7 t11 t15|

|(m0t0 + m4t1 + m8t2  + m12t3) (m0t4 + m4t5 + m8t6  + m12t7) (m0t8 + m4t9 + m8t10  + m12t11) (m0t12 + m4t13 + m8t14  + m12t15)|
MT = |(m1t0 + m5t1 + m9t2  + m13t3) (m1t4 + m5t5 + m9t6  + m13t7) (m1t8 + m5t9 + m9t10  + m13t11) (m1t12 + m5t13 + m9t14  + m13t15)|
|(m2t0 + m6t1 + m10t2 + m14t3) (m2t4 + m6t5 + m10t6 + m14t7) (m2t8 + m6t9 + m10t10 + m14t11) (m2t12 + m6t13 + m10t14 + m14t15)|
|(m3t0 + m7t1 + m11t2 + m15t3) (m3t4 + m7t5 + m11t6 + m15t7) (m3t8 + m7t9 + m11t10 + m15t11) (m3t12 + m7t13 + m11t14 + m15t15)|```
So, substituting:

Code :
```Proof 1:

|m0 m4 m8  0|   |1 0 0 t0|
|m1 m5 m9  0| * |0 1 0 t1| =
|m2 m6 m10 0|   |0 0 1 t2|
|0  0  0   1|   |0 0 0 1 |

|(m0(1)  + m4(0)  + m8(0)  + (0)(0)) (m0(0)  + m4(1)  + m8(0)  + (0)(0)) (m0(0)  + m4(0)  + m8(1)  + (0)(0)) (m0t0  + m4t1  + m8t2  + (0)(0))|
|(m1(1)  + m5(0)  + m9(0)  + (0)(0)) (m1(0)  + m5(1)  + m9(0)  + (0)(0)) (m1(0)  + m5(0)  + m9(1)  + (0)(0)) (m1t0  + m5t1  + m9t2  + (0)(0))| =
|(m2(1)  + m6(0)  + m10(0) + (0)(0)) (m2(0)  + m6(1)  + m10(0) + (0)(0)) (m2(0)  + m6(0)  + m10(1) + (0)(0)) (m2t0  + m6t1  + m10t2 + (0)(0))|
|((0)(1) + (0)(0) + (0)(0) + (1)(0)) ((0)(0) + (0)(1) + (0)(0) + (1)(0)) ((0)(0) + (0)(0) + (0)(1) + (1)(0)) ((0)t0 + (0)t1 + (0)t2 + (1)(1))|

|(m0) (m4) (m8 ) (m0t0  + m4t1 + m8t2 )|
|(m1) (m5) (m9 ) (m1t0  + m5t1 + m9t2 )|
|(m2) (m6) (m10) (m2t0  + m6t1 + m10t2)|
|(0 ) (0 ) (0  ) (1                   )|```
And, now if I multiply a 3x3 matrix with a 3 vector:

Code :
```Proof 2:

|m0 m4 m8 |   |t0|
|m1 m5 m9 | * |t1| =
|m2 m6 m10|   |t2|

|m0t0 + m4t1 + m8t2 |
|m1t0 + m5t1 + m9t2 |
|m2t0 + m6t1 + m10t2|```
So, proof 2 is the same as the translation part of the matrix in proof 1, hence to compose a 4x4 matrix from a 3x3 and a vector, the final formula is:

Code :
```     |M|MT|
M2 = ------
|0|1 |```
Now, from my code, this doesn't quite work out. Yet, if I don't multiply the translation by the 3x3 matrix when I compose the 4x4, everything is fine, yet I don't quite understand why this works?

I have seen a post on here that noted that M1 is equal to a rotation followed by a translation, and M2 is the opposite. But, surely if this were correct, M2 would work as expected, yet it doesn't; it's almost as though the triangle I'm rotating is being sheared.

Can somebody shed some light on this problem?

Thanks,
Luke.

2. ## Re: Matrix composition

Be mindfull of the row, column order you're using. Remember, the reverse order law of transposition says that
A^t B^t = (BA)^t, where ^t is transposition.
My hunch is that you're ending up with the transpose, or reverse transpose, of what you want, hence the shearing.

3. ## Re: Matrix composition

Be mindfull of the row, column order you're using. Remember, the reverse order law of transposition says that
A^t B^t = (BA)^t, where ^t is transposition.
My hunch is that you're ending up with the transpose, or reverse transpose, of what you want, hence the shearing.
Yes, but the numbering I've used in the examples, is the correct order for OpenGL, i.e. m0->m15 is an array like:

Code :
`GLfloat mtx[16];`
Luke.

4. ## Re: Matrix composition

Here's the code (in Ada) that I'm using:

Code :
```  procedure Compose(Result : out Object; Left : in Vector3.Object; Right : in Matrix3x3.Object) is

MT : Vector3.Object;

begin

Matrix3x3.Mul(MT, Right, Left);

Result(0)  := Right(0);
Result(1)  := Right(1);
Result(2)  := Right(2);
Result(3)  := 0.0;
Result(4)  := Right(3);
Result(5)  := Right(4);
Result(6)  := Right(5);
Result(7)  := 0.0;
Result(8)  := Right(6);
Result(9)  := Right(7);
Result(10) := Right(8);
Result(11) := 0.0;
Result(12) := MT.X;
Result(13) := MT.Y;
Result(14) := MT.Z;
Result(15) := 1.0;

end Compose;```
Now, if I don't multiply the matrix and translation together and just pass T insteasd of MT into the translation column, it works fine.

I just don't understand why the code I would've expected to work (going by the proofs), doesn't.

Thanks,
Luke.

5. ## Re: Matrix composition

Have you tried a reverse transpose? I'm not sure about your code, but I am sure that matrix multiplication with gl works correctly. There is a disturbing trend with some in the graphics community to bend the universe around the gl. Do your math the way its done in nearly every text, then do a transpose before you send it to gl. This might save you alot of headache.

6. ## Re: Matrix composition

I don't think there is something wrong with your calculations. Your Proof 1 shows what happens if you call first glRotate and then glTranslate, meaning you first Translate and then Rotate. Remember if you want to transform objects you have to reverse the operations.

Another way to look at it would be to transform not the objects but the local coordinate frame...

7. ## Re: Matrix composition

Originally posted by Overmind:
I don't think there is something wrong with your calculations. Your Proof 1 shows what happens if you call first glRotate and then glTranslate, meaning you first Translate and then Rotate.
Yes, but this isn't what is happening when I use that version of the Compose function. I would expect to see the object rotate around *me*, current'y I'm seeing nothing at all

Luke.

8. ## Re: Matrix composition

Let's back up a tad and make sure we're on the same page. When you call MultMatrix(), you are concatenating a matrix with the current gl matrix:
M = I,
M = M * YourMatrix,
M = M * YourMatrix2,
...
Or, in general,
M' = I * M1 * M2 * ... * Mn.
When you transforma a point with this matrix, you have:
P' = ( I * M1 * (M2 * ... * (Mn * P))).
As you can see, the transformations will be applied in the reverse order. If you understand this, you should be good to go.

9. ## Re: Matrix composition

Originally posted by Portal:
Let's back up a tad and make sure we're on the same page. When you call MultMatrix(), you are concatenating a matrix with the current gl matrix:
M = I,
M = M * YourMatrix,
M = M * YourMatrix2,
...
Or, in general,
M' = I * M1 * M2 * ... * Mn.
When you transforma a point with this matrix, you have:
P' = ( I * M1 * (M2 * ... * (Mn * P))).
As you can see, the transformations will be applied in the reverse order. If you understand this, you should be good to go.
Yes, I understand all of this, but that isn't the problem.

Here's my Draw function that is called on every frame:

Code :
```procedure Draw is

RX : Matrix3x3.Object;
RY : Matrix3x3.Object;

begin

MeshData.TM.Translation := (Z => Zoom, others => 0.0);

Matrix3x3.Mul(MeshData.TM.Matrix, RY, RX);

Renderer.Clear;

Renderer.SetMatrix(MeshData.TM.Matrix, MeshData.TM.Translation);
Renderer.DrawMesh(MeshData);

Renderer.SwapBuffers;

end Draw;```
Now the SetMatrix call does the following:

Code :
```procedure SetMatrix(Matrix : in Matrix3x3.Object; Translation : in Vector3.Object := (others => 0.0)) is

TM : Matrix4x4.Object;

begin

Matrix4x4.Compose(TM, Translation, Matrix);

end SetMatrix;```
Where that Compose function is the one I posted earlier.

Something is going wrong when I use this Compose function. When I use the oher Compose function which doesn't multipy the matrix3x3 and the Vector3 I can see the object and rotate it in the manner I expect. I expect from what I've read about this Compose is that the operations should occur in the opposite order so I should have the object rotating about me, but that isn't happening. If I remove the translation completely, I can see the object but it is distorted.

Luke.

10. ## Re: Matrix composition

Remember when you load the matrix to do a transpose, assuming your matrices are row major.
glLoadMatrixf( MyRowMajorMatrix.transpose() ), or something to that effect.

edit:
By the way, the Compose() function looks a little odd, why is the "Left" matrix ignored in the result?

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•