Sign in to follow this  
SaTANO

column vs. rows

Recommended Posts

[font="Times"][size="2"]
I've been wondering which matrix format are you using.

Many applications use row-major matrices but GLSL vertex shader uses column-major matrices (so do I).
When I was writing export plugin for blender I discovered that blender uses row-major matrices (it gives me different results like those in my application but its was not problem at all)
It's not big problem so I can use both because post-multiplying with column-major matrices produces the same result as pre-multiplying with row-major matrices.

Just simplified example:
I want to get local position of object in coordinate system 'A' (A is 4x4 matrix, position of object is represented by vector...). This is simple and easy to imagine way to determine multiplication order
-------------------------------------------------
[b]If I use row vector to represent position:[/b]
[i]localPosition (x,y,z,w)[/i]
[b]to get global position I can use:[/b]
[i]localPosition * A = globalPosition[/i]

so
[b]localPosition = globalPosition*A[sup]-1[/sup][/b]

-------------------------------------------------
[b]If I use column vector to represent position:[/b]
[i]localPosition [/i][i](x; [/i][i]y; [/i][i]z; [/i][i]w)[/i]
[b]to get global position I can use:[/b]
[i]A * localPosition = globalPosition[/i]
[i]
[/i][/size][/font]
[font="Times"][size="2"][u]using transpose:[/u][i] [/i][/size][/font]
[font="Times"][size="3"][size="2"][i][i]localPosition[b][sup]T[/sup][/b] * A[i][b][sup]T[/sup][/b][/i] = globalPosition[i][b][sup]T[/sup][/b][/i][/i][/i][/size][/size][/font]
[font="Times"][size="3"][size="2"][i][i][i][b][sup][size="2"][i]localPosition[b][sup]T[/sup][/b] = globalPosition[i][b][sup]T[/sup][/b][/i][/i][/size][/sup][/b][/i][/i][/i][/size][/size][/font][font="Times"][size="2"][i][i][i][b][sup][size="2"][i]* (A[/i][/size][/sup][/b][/i][/i][/i][/size][/font][font="Times"][size="2"][i][i][i][b][sup][size="2"][i][i][b][sup]-1[/sup][/b][/i][/i][/size][/sup][/b][/i][/i][/i][/size][/font][font="Times"][size="2"][i][i][i][b][sup][size="2"][i])[/i][/size][/sup][/b][/i][/i][/i][/size][/font][font="Times"][size="2"][i][i][i][b][sup][size="2"][i][i][b][sup]T[/sup][/b][/i][/i][/size][/sup][/b][/i][/i][/i][/size][/font]
[font="Times"][size="2"][i][i][b][sup][/sup][/b][/i][/i][size="3"][size="2"][b][i]
[/i][/b][/size][/size]so
[b]localPosition = A[sup]-1[/sup] * globalPosition[font="arial, verdana, tahoma, sans-serif"][size="3"] [/size][/font][/b][/size][/font][font="Times"][size="3"][size="2"][b][i](direct analogy to pre/post multiplying)[/i]
[/b][/size][/size][/font][font="Times"][size="2"]-------------------------------------------------

This is same with matrices multiplication when converting from global to local space(A and B are 4x4 matrices). It is bit harder to imagine but same as first example.[/size][/font]
[font="Times"][size="3"][size="2"][font="arial, verdana, tahoma, sans-serif"][size="3"]
[font="Times"][size="3"][size="2"][size="2"][b]row-major:[/b][/size][/size][/size][/font]
[font="Times"][size="3"][size="2"][size="2"][b]to get global coordinate system [/b][/size][/size][/size][/font]
[font="Times"][size="3"][size="2"][size="2"][i][font="arial, verdana, tahoma, sans-serif"][size="2"][font="Times"][size="2"][size="2"][size="2"][size="2"][i][i][font="arial, verdana, tahoma, sans-serif"][size="2"][font="Times"][size="2"][size="2"][i][i]localB * [/i][/i][/size][/size][/font][/size][/font][/i]globalA[/i][/size][/size][/size][/size][/font][font="Times"][size="2"][size="2"][i][i] [/i][/i][/size][/size][/font][font="Times"][size="2"][size="2"][i][i]=globalB[/i][/i][/size][/size][/font][/size][/font][/i][/size][/size][/size][/font]
[font="Times"][size="3"][size="2"][size="2"][b][i][font="arial, verdana, tahoma, sans-serif"] [/font][/i][i]
[/i][/b][/size][/size][/size][/font][font="Times"][size="2"]so[/size][/font][/size][/font][/size][/size][/font]
[font="Times"][size="3"][size="2"][b][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][i]localB[/i][/i][/size][/size][/b][/size][/size][/size][/size][/i][/size][/size][/font][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][i]=globalB*globalA[b][sup]-1[/sup][/b][/i][/i][/size][/size][/b][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/b][/size][/size][/font]
[font="Times"][size="3"][size="2"]------------------------------------------------------------------------[/size][/size][/font]
[font="Times"][size="3"][size="2"][b]column-major:[/b][/size][/size][/font]
[font="Times"][size="3"][size="2"][b]to get global coordinate system[/b][/size][/size][/font]
[font="Times"][size="3"][size="2"][b][i][font="arial, verdana, tahoma, sans-serif"][size="2"][font="Times"][size="2"][size="2"][size="2"][size="2"][i]globalA*[/i][/size][/size][/size][/size][/font][font="Times"][size="2"][size="2"][i][i] localB[/i][/i][/size][/size][/font][font="Times"][size="2"][size="2"][i][i]=globalB[/i][/i][/size][/size][/font][/size][/font][/i]
[/b][/size][/size][/font]
[font="Times"][size="2"][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][u]fo example using invert[/u][b]: [/b][/i][/size][/size][/font][/size][/font][/size][/font]
[size="2"][font="Times"][size="2"][size="2"][size="2"][size="2"][i]globalA*[/i][/size][/size][/size][/size][/font][font="Times"][size="2"][size="2"][i][i] localB[/i][/i][/size][/size][/font][font="Times"][size="2"][size="2"][i][i]*globalB[b][sup]-1[/sup][/b][/i][/i][/size][/size][/font][font="Times"][size="2"][size="2"][i][i]=globalB[/i][/i][/size][/size][/font][font="Times"][size="2"][size="2"][i][i]*globalB[b][sup]-1[/sup][/b][/i][/i][/size][/size][/font][/size]
[font="Times"][size="2"][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][i]globalA=(localB*globalB[b][sup]-1[/sup][/b])[/i][b][sup][i]-1[/i][/sup][/b][/i][/size][/size][/font]
[font="Times"][size="3"][size="2"][b][i][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][i]globalA[/i][/i][/size][/size][/b][/size][/size][/size][/size][/i][/size][/size][/font][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][b][sup][i]-1[/i][/sup][/b][/i][/size][/size][/b][/size][/size][/size][/size][/size][/size][/i][/size][/size][/font][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][i]=localB*globalB[b][sup]-1[/sup][/b][/i][/i][/size][/size][/b][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/i][/b][/size][/size][/font][/size][/font][/size][/font]
[font="Times"][size="2"][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="3"][size="2"][b][i][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][i][b][sup]
[/sup][/b][/i][/i][/size][/size][/b][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/i][/b][/size][/size][/font][/size][/font][/size][/font][font="Times"][size="2"][i][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][size="2"][size="2"][i][i][sup][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][size="2"][size="2"][i][i]so[/i][/i][/size][/size][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/sup][/i][/i][/size][/size][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/i][/size][/font]
[font="Times"][size="2"][b][i][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][i][b][sup][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][i]localB=[/i][/i][/size][/size][/b][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/sup][/b][/i][/i][/size][/size][/b][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/i][/b][/size][/font][font="Times"][size="2"][size="2"][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="3"][size="2"][size="2"][b][i][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][i][b][sup][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][i]globalA[/i][/i][/size][/size][/b][/size][/size][/size][/size][/i][/size][/size][/font][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][b][sup][i]-1[/i][/sup][/b][/i][/size][/size][/b][/size][/size][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/sup][/b][/i][/i][/size][/size][/b][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/i][/b][/size][/size][/size][/font][/size][/font][/size][/size][/font][font="Times"][size="2"][b][i][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][i][b][sup][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][b][size="2"][size="2"][i][i]*globalB[/i][/i][/size][/size][/b][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/sup][/b][/i][/i][/size][/size][/b][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/i][/b][/size][/font]
[font="Times"][size="2"][i][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][size="2"][size="2"][i][i][sup][font="arial, verdana, tahoma, sans-serif"][size="3"][font="Times"][size="2"][size="2"][i][size="3"][size="2"][size="2"][size="2"][size="2"][size="2"][i][i]------------------------------------------------------------------------[/i][/i][/size][/size][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/sup][/i][/i][/size][/size][/size][/size][/size][/size][/i][/size][/size][/font][/size][/font][/i][/size][/font]
[font="Times"][size="2"][font="arial, verdana, tahoma, sans-serif"] [/font][/size][/font]
[font="Times"][size="2"]
What am I trying to point out is which vector format (matrix format) is correct, if there is any standard/convention...

Thans for your opinions[/size][/font]

Share this post


Link to post
Share on other sites
There is no correct format, both forms are used extensively.

DirectX like row major.
OpenGL likes column major.

Use whatever 'major' prevents you from having to do the most trasposes.
(and be consistent! pick one)

Share this post


Link to post
Share on other sites
DirectX does not "like row major" any more -- you can use either, and in fact, column major is now the default.

In HLSL you can use the [font="Courier New"]row_major[/font] and [font="Courier New"]column_major[/font] keywords to specify the internal storage format for a matrix variable. If you don't specify one, then the default is column major (just like GLSL).

When writing matrix/vector math using SIMD instructions ([i]on the CPU, or the GPU via GLSL/HLSL[/i]), the math will be exactly the same, but the amount of instructions required to perform the math will be different depending on whether you're using row-major or column-major. Depending on the kinds of operations you're performing, one storage format will be more optimal than the other.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this