## Matrix conventions / multiplication order

**category:**code [glöplog]

Hi, I read ryg's very nice blog post about matrix conventions over at

http://fgiesen.wordpress.com/2012/02/12/row-major-vs-column-major-row-vectors-vs-column-vectors/

Some of the facts mentioned there include:

- GL fixed function is column-major and uses column vectors multiplied from the right.

- D3D fixed function was row-major and used row vectors multiplied from left.

- Matrix multiplication is not commutative, i.e. A*B != B*A.

My question is:

Doesn't this in fact imply that overloading “operator *” in matrix classes to perform matrix multiplication should be generally avoided? Because I think this way your codebase will “lock in” to a specific multiplication order, as writing A*B has a different meaning in OpenGL vs. D3D.

I am not sure this can be solved by a simple transpose in the rendering backend code: What about matrices that resulted out of complex transformations with many multiplications?

Isn't it better to keep the required multiplication order for the currently active platform in a globally accessible flag that you then passthru to your multiplyMatrix() function (LEFT_MULTIPLY for row vectors to be multiplied from the left (D3D), RIGHT_MULTIPLY for column vectors to be multiplied from the right (GL)), or something like that?

Furthermore, it seems to me that implementing a custom matrix stack (similar to OpenGL) can also help to eliminate the mentioned issues: The order of "push", "pop", "Load/MultMatrix", etc. calls is agnostic of the actual matrix multiplication order (i think), so special case code only has to live inside the "MultMatrix" implementation.

Any thoughts?

http://fgiesen.wordpress.com/2012/02/12/row-major-vs-column-major-row-vectors-vs-column-vectors/

Some of the facts mentioned there include:

- GL fixed function is column-major and uses column vectors multiplied from the right.

- D3D fixed function was row-major and used row vectors multiplied from left.

- Matrix multiplication is not commutative, i.e. A*B != B*A.

My question is:

Doesn't this in fact imply that overloading “operator *” in matrix classes to perform matrix multiplication should be generally avoided? Because I think this way your codebase will “lock in” to a specific multiplication order, as writing A*B has a different meaning in OpenGL vs. D3D.

I am not sure this can be solved by a simple transpose in the rendering backend code: What about matrices that resulted out of complex transformations with many multiplications?

Isn't it better to keep the required multiplication order for the currently active platform in a globally accessible flag that you then passthru to your multiplyMatrix() function (LEFT_MULTIPLY for row vectors to be multiplied from the left (D3D), RIGHT_MULTIPLY for column vectors to be multiplied from the right (GL)), or something like that?

Furthermore, it seems to me that implementing a custom matrix stack (similar to OpenGL) can also help to eliminate the mentioned issues: The order of "push", "pop", "Load/MultMatrix", etc. calls is agnostic of the actual matrix multiplication order (i think), so special case code only has to live inside the "MultMatrix" implementation.

Any thoughts?

generally you pick either system and use that consistently throughout your codebase

then, if somewhere down the line conversion is required (e.g. in a renderer backend), you solve it there in the platform specific implementation

then, if somewhere down the line conversion is required (e.g. in a renderer backend), you solve it there in the platform specific implementation

But then if my codebase computed e.g. M = (((Trans*Rot)*Scale)*Bla1)*... (opengl-compatible order) how would I be able to convert the resulting M that gets passed to my D3D renderer backend?

I.e. how do I yield the required M_d3d = (((...*Bla1)*Scale)*Rot)*Trans) from the given M?

I.e. how do I yield the required M_d3d = (((...*Bla1)*Scale)*Rot)*Trans) from the given M?

argh, M_d3d = ...*(Bla1*(Scale*(Rot*Trans))) I mean

i'm bad at programming, but isn't it by transposing the result matrix?

If I am not mistaken, to convert between an openGL and a D3D matrix, you need to transpose it, i.e. Rot_GL = transpose(Rot_D3D).

Now you are lucky that

transpose(A) * transpose(B) = transpose(B * A)

So if you do M_d3d = transpose(M_GL) you will get the same as transposing the individual matrices and multiplying them in the reverse order.

Or in other words: What nystep said.

Now you are lucky that

transpose(A) * transpose(B) = transpose(B * A)

So if you do M_d3d = transpose(M_GL) you will get the same as transposing the individual matrices and multiplying them in the reverse order.

Or in other words: What nystep said.

basically if you change from row to column major you transpose the matrices if my undercaffeinated brain gets that right.

then this rule applies: (ab)^t = (b^t)(a^t). so you can simply implement your own stuff and then transpose if needed afterwards, for instance in the specific shader or in memory, whatever you prefer.

then this rule applies: (ab)^t = (b^t)(a^t). so you can simply implement your own stuff and then transpose if needed afterwards, for instance in the specific shader or in memory, whatever you prefer.

chock: i only had to think longer :D

GL and D3D matrices have the same _memory layout_, no need to transpose them!

Quoting from ryg's article:

Quoting from ryg's article:

**Quote:**

If you look at an individual matrix (say translation by (tx, ty, tz)), the D3D and GL versions look exactly the same in memory. However, they do not behave the same way: in OpenGL, the matrix that represents “first A then B” is B*A; in D3D, it is A*B.

indeed, a transpose will do the trick (*). unless you're working with third party libraries that also use an order different than yours you'll generally only have this going on in the platform renderer.

(* - another issue to look out for is projection matrices when using a different handed graphics api)

(* - another issue to look out for is projection matrices when using a different handed graphics api)

i'd advise adhering to b*a btw, since everyone does that.

so the transpose reverses the previous concatenation order?

because i state again: there is no difference in memory layout, so no transposing required regarding layout

because i state again: there is no difference in memory layout, so no transposing required regarding layout

**Quote:**

generally you pick either system and use that consistently throughout your codebase

No no no, that's all wrong. Generally you make a mess out of it and then throw random transposes and inverses around until it seems to work and finally throw the result onto maintenance programmer.

:D

spike:

When memory layout is identical (i.e. row-major as Ryg describes it) it becomes a matter of interpretation (or implementation if you will).

Simply put:

- GL and D3D implement the matrix mul. the other way around, so wherever this is of concern, correct it (GLSL, fixed pipe stuff). In practice you'll find that you often create full transform matrices yourself and upload them to shader constants: so then nothing's different really.

- Projection is obviously different for each, but that's sorta besides the point here.

- Pick one way of doing things in your own code, and stick with it. Adjust in places where needed, and at the last moment (platform dep. code). Or go with what 216 just said, since that is usually what happens and allows for hours of fun!

Matrix transpose has a few uses (e.g. transpose 3x3 part to invert rotate/scale). It's also used to convert the memory layout.

Also: (AB)t == BtAt

So that does not mean that (AB)t == BA

(afair, i haven't done much geometry/graphics stuff the past 2 years)

spike:

When memory layout is identical (i.e. row-major as Ryg describes it) it becomes a matter of interpretation (or implementation if you will).

Simply put:

- GL and D3D implement the matrix mul. the other way around, so wherever this is of concern, correct it (GLSL, fixed pipe stuff). In practice you'll find that you often create full transform matrices yourself and upload them to shader constants: so then nothing's different really.

- Projection is obviously different for each, but that's sorta besides the point here.

- Pick one way of doing things in your own code, and stick with it. Adjust in places where needed, and at the last moment (platform dep. code). Or go with what 216 just said, since that is usually what happens and allows for hours of fun!

Matrix transpose has a few uses (e.g. transpose 3x3 part to invert rotate/scale). It's also used to convert the memory layout.

Also: (AB)t == BtAt

So that does not mean that (AB)t == BA

(afair, i haven't done much geometry/graphics stuff the past 2 years)

**Quote:**

Also: (AB)t == BtAt

So that does not mean that (AB)t == BA

(afair, i haven't done much geometry/graphics stuff the past 2 years)

but you are still right.

for the matrix mul row vs col major and memory layout means that they just switch the inner and outer loops of the multiplication? man, weirdos...

ok, i think i figured it out:

we want to build a transformation matrix that uniformly scales by 2 first an then translates by (5,5,5):

OGL: M_gl = T*S

|1 0 0 5| |2 0 0 0|

|0 1 0 5| |0 2 0 0| =

|0 0 1 5| |0 0 2 0|

|0 0 0 1| |0 0 0 1|

|2 0 0 5|

|0 2 0 5|

|0 0 2 5|

|0 0 0 1|

in memory (column major storage): {{2,0,0,0},{0,2,0,0},{0,0,2,0},{5,5,5,1}}

D3D: M_d3d = S*T

|2 0 0 0| |1 0 0 0|

|0 2 0 0| |0 1 0 0| =

|0 0 2 0| |0 0 1 0|

|0 0 0 1| |5 5 5 1|

|2 0 0 0|

|0 2 0 0|

|0 0 2 0|

|5 5 5 1|

in memory (row major storage): {{2,0,0,0},{0,2,0,0},{0,0,2,0},{5,5,5,1}}

So the answer indeed is to stick with one of the two multiplication order conventions and the resulting matrix then can be used with either D3D or GL (*) -

(* with the exception of projection matrices as plek points out (because D3D uses a [0..1] clipping range for z, while GL uses [-1..1]). and i also think view/lookat matrices are API/handedness dependend..)

we want to build a transformation matrix that uniformly scales by 2 first an then translates by (5,5,5):

OGL: M_gl = T*S

|1 0 0 5| |2 0 0 0|

|0 1 0 5| |0 2 0 0| =

|0 0 1 5| |0 0 2 0|

|0 0 0 1| |0 0 0 1|

|2 0 0 5|

|0 2 0 5|

|0 0 2 5|

|0 0 0 1|

in memory (column major storage): {{2,0,0,0},{0,2,0,0},{0,0,2,0},{5,5,5,1}}

D3D: M_d3d = S*T

|2 0 0 0| |1 0 0 0|

|0 2 0 0| |0 1 0 0| =

|0 0 2 0| |0 0 1 0|

|0 0 0 1| |5 5 5 1|

|2 0 0 0|

|0 2 0 0|

|0 0 2 0|

|5 5 5 1|

in memory (row major storage): {{2,0,0,0},{0,2,0,0},{0,0,2,0},{5,5,5,1}}

So the answer indeed is to stick with one of the two multiplication order conventions and the resulting matrix then can be used with either D3D or GL (*) -

**i.e. no transposing is needed**!(* with the exception of projection matrices as plek points out (because D3D uses a [0..1] clipping range for z, while GL uses [-1..1]). and i also think view/lookat matrices are API/handedness dependend..)

You're right, when you only scale, you don't need to transpose.. :) (runs to optimize his engine code once again!)

so you're saying i picked a bad case to prove that transposing is not needed... uff, ok, i'll double check..

**Quote:**

No no no, that's all wrong. Generally you make a mess out of it and then throw random transposes and inverses around until it seems to work and finally throw the result onto maintenance programmer.

Or you can use a library like glm and stop wasting time with that... unless you're making an intro, of course.

flure: i want to see you taking the projection matrix from glm and stick it straight inside D3D and it works fine.. :)

awful example spike. what's that matrix doing? isn't the 5,5,5 setup to modify the w component? kinda unimportant. you coulda based it on translation. and there is that for soft simd implementations the column major layout is probably the better choice for d3d. and mangle the shaders to do the math that way. there's more differences between gl and d3d so the render back end gotta solve the matrix orientation magic anyway.

also: stop overthinking this

just beware you're not writing kludgy logic everywhere (the endless transposing/inverting 216 mentioned) and you'll be fine

research as needed

just beware you're not writing kludgy logic everywhere (the endless transposing/inverting 216 mentioned) and you'll be fine

research as needed

plek: you're probably right regarding overthinking. but on the other hand i'd like to really understand what's going on. after all ryg wrote the article, because people don't know what they are doing and there is a lot of confusing/wrong info on the web.

logged out: the 5,5,5 _is_ a translation. talking about confused people..

logged out: the 5,5,5 _is_ a translation. talking about confused people..

i just read that article and not only is it spot on, it also answers all questions that were asked here ;)

@spike really? mmh. *shrugs* yeah. anyway... it's confusing. double standards suck major ass. :D