PDA

View Full Version : While matrices are in Row-major or column-major, I'm in confunsion-major!



Keithster
11-22-2015, 08:27 PM
I'm deeply confused about this whole row-major vs column-major business.

I asked the question on SO but I would love to hear answers from the opengl community as well. httpee://stackoverflow.com/questions/33862730/row-major-vs-column-major-confusion (sorry it didn't let me post the link so I had to modify it hence the 'pee')

I hope you can see how lost I am, I'm just mixing up a bunch of stuff but I can't seem to figure out what is it I'm mixing.

Take a translation matrix for example (the picture on my SO link edit), does row-major mean that we store the transformation vector in the last row? and column-major means we store it in the last column? or the opposite?

I'm gonna try and answer my own question: let's try to translate a vector with our row-major and column-major matrices:

First the translation values are stored in the last column (the way I have them stored in 'My Matrix' in the picture in SO link)

|1, 0, 0, x| |3| |3 + x|
|0, 1, 0, y| |5| |5 + y|
|0, 0, 1, z| |0| |0 + z|
|0, 0, 0, 1| |1| |1|

OK that makes sense to me. We got our translated vector!

Now let's try the other matrix, the way glm has it, where the values are stored in the last row:

|1, 0, 0, 0| |3| |3|
|0, 1, 0, 0| |5| |5|
|0, 0, 1, 0| |0| |0|
|x, y, z, 1| |1| |3x + 5y + 0 + 1|

That doesn't make sense, we didn't get the translated vector.

Let's try multiplying the vector from the left, transposed:


.....................|1, 0, 0, 0| |3 + x|
.....................|0, 1, 0, 0| |5 + y|
|3, 5, 0, 1|....|0, 0, 1, 0| |0 + z|
.....................|x, y, z, 1| |1|

We got our translated vector again!

But that doesn't really clear up the confusion. What did that result teach us? Well I've been reading and it seems that when you have a column-major matrix, you multiply the vector from the right. i.e. M x V which is what we did in the first example with my matrix, so does that mean that my matrix is in column-major? and glm's is in row major? but If that's really the case, then why is it that in glm, we always multiply the vector last, we never do V x M, so... there goes my theory :\

I hope you get the picture, and how much confused I am.

Any help is GREATLY appreciated!

Keithster
11-22-2015, 08:51 PM
Another thing we could do to make the glm transformation work when we do M x V is to multiply the columns not the rows of the matrix with the vector, but that goes against we're taught in linear algebra class (which is to multiply rows from the first matrix with columns from the second)... i.e.

|1, 0, 0, 0|....|3|...|1*3 + 0*5 + 0*0 + x*1|.... | 3 + x|
|0, 1, 0, 0|....|5|...|etc|................................. ... | 5 + y|
|0, 0, 1, 0|....|0|...|etc|................................. ... | 0 + z|
|x, y, z, 1|.....|1|...|1|.................................. .... | 1|

But looking at glm's code, that's not what happens. They use an array of vectors instead of a float array to represent a matrix. I initially thought that each vector represented a column, but when debugging I saw that each vector was actually a row. And in their multiplication code, they multiply the vectors in that array which means they're multiplying rows and not columns, i.e. not doing what I just mentioned. Unless I'm wrong about this and those vectors actually represent columns even though they look like they're laid out horizontally in the debugger... Attaching the picture I linked in my SO question (for some reason it won't let me attach it): httpee://i.imgur.com/fFdBhFd.png

Alfonse Reinheart
11-22-2015, 09:34 PM
I think this answer on gamedev.stackexchange (http://gamedev.stackexchange.com/a/18929) is pretty thorough examination of the issue.

For your specific issues with GLM:


Now let's try the other matrix, the way glm has it, where the values are stored in the last row:

No, GLM is column major. Always has been.


Unless I'm wrong about this and those vectors actually represent columns even though they look like they're laid out horizontally in the debugger...

You are misinterpreting what you're seeing.

A GLM 4x4 matrix is an array of 4 vec4s. Each vec4 represents a column of the matrix. So naturally, the final column should contain the translation. As it does in your example.

Keithster
11-22-2015, 10:03 PM
I did read some of those answers in that link, but I stopped cause the more I read the more I got confused :D

So you're saying, it's a visual misinterpretation? So even though they're laid out horizontally, they're actually columns?

So this:

|1, 0, 0, 0|
|0, 1, 0, 0|
|0, 0, 1, 0|
|x, y, z, 1|

is actually this?

|1, 0, 0, x|
|0, 1, 0, y|
|0, 0, 1, z|
|0, 0, 0, 1|

Mat[0] == [1, 0, 0, 0]
Mat[1] == [0, 1, 0, 0]
Mat[2] == [0, 0, 1, 0]
Mat[3] == [x, y, z, 1]

Is that what you're saying?

GClements
11-23-2015, 03:31 AM
So you're saying, it's a visual misinterpretation? So even though they're laid out horizontally, they're actually columns?

"Row-major" means that the outermost array dimension is the row. "Column-major" means that the outermost array dimension is the column.

Given a matrix


[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]

row-major order is


float m[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

or


float m[4][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}};

while column-major order is


float m[16] = {0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15};

or


float m[4][4] = {{0,4,8,12},{1,5,9,13},{2,6,10,14},{3,7,11,15}};

OpenGL's default order is column-major. The legacy matrix functions glLoadMatrix() and glMultMatrix() expect the matrix in column-major order. OpenGL 1.3 added glLoadTransposeMatrix() and glMultTransposeMatrix() which accept a matrix in row-major order. Matrices in GLSL are column-major unless explicitly qualified as row-major. GLM stores matrices in column-major order.

Note that row-major versus column-major is purely about memory layout on computers. It has nothing to do with the mathematics of matrices.

In terms of the mathematics, an important point is that (A.B)T=BT.AT. For a matrix multiplication, transposing the matrices and reversing their order will produce the same result, only transposed. A multiplication with a matrix on the left and a column-vector on the right yields a column vector. Changing the multiplication so that the matrix is transposed and on the right and the vector is a row vector on the left yields the same result but as a row vector.

Mathematical and OpenGL conventions are to represent vectors as column vectors. For some reason, DirectX uses row vectors, so any articles which are written with DirectX in mind will have their matrices transposed (i.e. the translation component will be in the bottom row rather than the right-hand column, any projective component will be in the right-hand column rather than in the bottom row), and multiplications will have a row vector on the left rather than a column vector on the right.

Passing a row-major matrix where a column-major matrix is expected will effectively transpose the matrix, but row-major versus column-major is a computing concept, transposition is a mathematical concept.