106

I'm getting thoroughly confused over matrix definitions. I have a matrix class, which holds a float[16] which I assumed is row-major, based on the following observations:

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

matrixA and matrixB both have the same linear layout in memory (i.e. all numbers are in order). According to http://en.wikipedia.org/wiki/Row-major_order this indicates a row-major layout.

matrixA[0] == matrixB[0][0]; matrixA[3] == matrixB[0][3]; matrixA[4] == matrixB[1][0]; matrixA[7] == matrixB[1][3]; 

Therefore, matrixB[0] = row 0, matrixB[1] = row 1, etc. Again, this indicates row-major layout.

My problem / confusion comes when I create a translation matrix which looks like:

1, 0, 0, transX 0, 1, 0, transY 0, 0, 1, transZ 0, 0, 0, 1 

Which is laid out in memory as, { 1, 0, 0, transX, 0, 1, 0, transY, 0, 0, 1, transZ, 0, 0, 0, 1 }.

Then when I call glUniformMatrix4fv, I need to set the transpose flag to GL_FALSE, indicating that it's column-major, else transforms such as translate / scale etc don't get applied correctly:

If transpose is GL_FALSE, each matrix is assumed to be supplied in column major order. If transpose is GL_TRUE, each matrix is assumed to be supplied in row major order.

Why does my matrix, which appears to be row-major, need to be passed to OpenGL as column-major?

4
  • How do you determine that you "need to set the transpose flag to GL_FALSE?" How are you using the uniform? Commented Jul 18, 2013 at 8:13
  • @Angew I need to set the transpose flag to GL_FALSE, else translations / scales etc don't work, they apply transposed transforms to the view. Commented Jul 18, 2013 at 8:23
  • 1
    I've elaborated on the subject a bit more here. "Matrices are not transforms" : bit.ly/1cPINCm . Commented Aug 18, 2013 at 6:45
  • There is an excellent article on this on Scratchapixel: scratchapixel.com/lessons/3d-basic-lessons/lesson-4-geometry/…. Commented Jul 10, 2014 at 22:09

6 Answers 6

97

matrix notation used in opengl documentation does not describe in-memory layout for OpenGL matrices

If think it'll be easier if you drop/forget about the entire "row/column-major" thing. That's because in addition to row/column major, the programmer can also decide how he would want to lay out the matrix in the memory (whether adjacent elements form rows or columns), in addition to the notation, which adds to confusion.

OpenGL matrices have same memory layout as directx matrices.

x.x x.y x.z 0 y.x y.y y.z 0 z.x z.y z.z 0 p.x p.y p.z 1 

or

{ x.x x.y x.z 0 y.x y.y y.z 0 z.x z.y z.z 0 p.x p.y p.z 1 } 
  • x, y, z are 3-component vectors describing the matrix coordinate system (local coordinate system within relative to the global coordinate system).

  • p is a 3-component vector describing the origin of matrix coordinate system.

Which means that the translation matrix should be laid out in memory like this:

{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 }. 

Leave it at that, and the rest should be easy.

---citation from old opengl faq--


9.005 Are OpenGL matrices column-major or row-major?

For programming purposes, OpenGL matrices are 16-value arrays with base vectors laid out contiguously in memory. The translation components occupy the 13th, 14th, and 15th elements of the 16-element matrix, where indices are numbered from 1 to 16 as described in section 2.11.2 of the OpenGL 2.1 Specification.

Column-major versus row-major is purely a notational convention. Note that post-multiplying with column-major matrices produces the same result as pre-multiplying with row-major matrices. The OpenGL Specification and the OpenGL Reference Manual both use column-major notation. You can use any notation, as long as it's clearly stated.

Sadly, the use of column-major format in the spec and blue book has resulted in endless confusion in the OpenGL programming community. Column-major notation suggests that matrices are not laid out in memory as a programmer would expect.


I'm going to update this 9 years old answer.

A mathematical matrix is defined as m x n matrix. Where m is a number of rows and n is number of columns. For the sake of completeness, rows are horizontals, columns are vertical. When denoting a matrix element in mathematical notation Mij, the first element (i) is a row index, the second one (j) is a column index. When two matrices are multiplied, i.e. A(m x n) * B(m1 x n1), the resulting matrix has number of rows from the first argument(A), and number of columns of the second(B), and number of columns of the first argument (A) must match number of rows of the second (B). so n == m1. Clear so far, yes?

Now, regarding in-memory layout. You can store matrix two ways. Row-major and column-major. Row-major means that effectively you have rows laid out one after another, linearly. So, elements go from left to right, row after row. Kinda like english text. Column-major means that effectively you have columns laid out one after another, linearly. So elements start at top left, and go from top to bottom.

Example:

//matrix |a11 a12 a13| |a21 a22 a23| |a31 a32 a33| //row-major [a11 a12 a13 a21 a22 a23 a31 a32 a33] //column-major [a11 a21 a31 a12 a22 a32 a13 a23 a33] 

Now, here's the fun part!

There are two ways to store 3d transformation in a matrix. As I mentioned before, a matrix in 3d essentially stores coordinate system basis vectors and position. So, you can store those vectors in rows or in columns of a matrix. When they're stored as columns, you multiply a matrix with a column vector. Like this.

//convention #1 |vx.x vy.x vz.x pos.x| |p.x| |res.x| |vx.y vy.y vz.y pos.y| |p.y| |res.y| |vx.z vy.z vz.z pos.z| x |p.z| = |res.z| | 0 0 0 1| | 1| |res.w| 

However, you can also store those vectors as rows, and then you'll be multiplying a row vector with a matrix:

//convention #2 (uncommon) | vx.x vx.y vx.z 0| | vy.x vy.y vy.z 0| |p.x p.y p.z 1| x | vz.x vz.y vz.z 0| = |res.x res.y res.z res.w| |pos.x pos.y pos.z 1| 

So. Convention #1 often appears in mathematical texts. Convention #2 appeared in DirectX sdk at some point. Both are valid.

And in regards of the question, if you're using convention #1, then your matrices are column-major. And if you're using convention #2, then they're row major. However, memory layout is the same in both cases

[vx.x vx.y vx.z 0 vy.x vy.y vy.z 0 vz.x vz.y vz.z 0 pos.x pos.y pos.z 1] 

Which is why I said it is easier to memorize which element is which, 9 years ago.

Sign up to request clarification or add additional context in comments.

15 Comments

How do you mean the same memory layout? Given the example in my original post, it indicates the memory layout of my matrix is row-major (as that's how C lays out the memory in two-dimensional arrays). So why do I need to set the flag to tell OpenGL I'm using column-major, when the memory layout doesn't match?
@MarkIngram: row/column is notation thing used ONLY in documentation. In both D3DMatrix AND OpenGL matrix translation elements occupy same position in memory - elements with index/offset 12, 13, 14 (or 13th, 14th and 15th elements of 16 element array).
Column- and row-major are about how the matrix is laid out in memory. See. eg. the book Golub - Matrix Computations, or the Wiki article on row-major. The OpenGL FAQ is wrong, or ambiguous. It is a separate question whether you treat vectors as row- or column-vectors, which also determines whether you should keep your basis vectors in columns or rows. (Sometimes the term row-major is used to refer to this, adding to the confusion.) GLSL's matrix data type is column-major, and the convention is to treat vectors as column vectors. In memory the D3D and OpenGL convention ends up being the same.
Could you please add an explanation on what you believe column-/row-major actually means? I don't understand the "forget about..." remark, at all. According to Wikipedia, these terms define the memory layout, which is the most important part here. Why would I want to forget that?
I'm still perplexed by existence of this answer. Reading inbetween the lines, you could delete whole answer, replace it with "Column major by default, row major if you set transpose flag when uploading your matrix." and it would say everything we ever wanted to know without needless oversimplification that avoids answering the actual question. This also means that by default you left-multiply your vectors by transform matrix (mat * vec). Leaving this here because I know that I'll forget this, look for it again and find this nonsensical answer and be more confused than I was again...
|
86

To summarize the answers by SigTerm and dsharlet: The usual way to transform a vector in GLSL is to right-multiply the transformation matrix by the vector:

mat4 T; vec4 v; vec4 v_transformed; v_transformed = T*v; 

In order for that to work, OpenGL expects the memory layout of T to be, as described by SigTerm,

{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 } 

which is also called 'column major'. In your shader code (as indicated by your comments), however, you left-multiplied the transformation matrix by the vector:

v_transformed = v*T; 

which only yields the correct result if T is transposed, i.e. has the layout

{ 1, 0, 0, transX, 0, 1, 0, transY, 0, 0, 1, transZ, 0, 0, 0, 1 } 

(i.e. 'row major'). Since you already provided the correct layout to your shader, namely row major, it was not necessary to set the transpose flag of glUniform4v.

7 Comments

best answer in my opinion. It is perfect example for graphic's students. In math one of the vector is horizontal while the other is vertical (else product is undefined). I know when programming we forget about most math formalisms XD
why not forget about this formalism as well? It would make much more sense from a programming perspective.
**{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 } ** is column major ? That is confuse again
@LiuHao But it's true, IF you intend to compute your transformed vector as Tv. Then (1,0,0,0), (0,1,0,0), (0,0,1,0), (transX, transY, transZ,1) are the columns of T, which makes the layout column major. IF you intend to use the vT convention with the same data array in memory, you must flag it as row major, because in this case, the rows of T must be (1,0,0,0), (0,1,0,0), (0,0,1,0), (transX, transY, transZ,1) in order to work.
@Roberto You are confusing left and right multiply. These refer to the point/vector not the matrix. So if the point/vector is on the right of the multiplication that is a right or (post) multiply, If it is on the left of the multiplication it is a left (pre) multiply.
|
18

You are dealing with two separate issues.

First, your examples are dealing with the memory layout. Your [4][4] array is row major because you've used the convention established by C multi-dimensional arrays to match your linear array.

The second issue is a matter of convention for how you interpret matrices in your program. glUniformMatrix4fv is used to set a shader parameter. Whether your transform is computed for a row vector or column vector transform is a matter of how you use the matrix in your shader code. Because you say you need to use column vectors, I assume your shader code is using the matrix A and a column vector x to compute x' = A x.

I would argue that the documentation of glUniformMatrix is confusing. The description of the transpose parameter is a really roundabout way of just saying that the matrix is transposed or it isn't. OpenGL itself is just transporting that data to your shader, whether you want to transpose it or not is a matter of convention you should establish for your program.

This link has some good further discussion: http://steve.hollasch.net/cgindex/math/matrix/column-vec.html

6 Comments

I don't do anything fancy with matrices in my shader. It looks like this: gl_Position = vec4(v_xy, 0.0, 1.0) * v_ViewMatrix * v_ProjectionMatrix;
What does it tell me (i.e. what is the convention, and how does it show me)? :)
@MarkIngram it tells you that you are interpreting your positions as row vectors. When you want to transform a vector x by a matrix A, you compute x'^T = x^T A. This is not the standard in general mathematics, but common in computer graphics (unfortunately, it leads to much confusion).
So I should switch the order of multiplication? Rather than vector x model x view x projection;, do projection x view x model x vector;?
@MarkIngram I know I'm late, but yes, if you're multiplying column-major matrices with column vectors, then you must invert the order. In this case, the correct order would be: xformedVertex = projMat * viewMat * modelMat * vertex; and you read it right-to-left.
|
3

I think that the existing answers here are very unhelpful, and I can see from the comments that people are left feeling confused after reading them, so here is another way of looking at this situation.

As a programmer, if I want to store an array in memory, I cannot store a rectangular grid of numbers, because computer memory doesn't work like that, I have to store the numbers in a linear sequence.

Lets say I have a 2x2 matrix and I initialize it in my code like this:

const matrix = [a, b, c, d]; 

I can successfully use this matrix in other parts of my code provided I know what each of the array elements represents.

The OpenGL specification defines what each index position represents, and this is all you need to know to construct an array and pass it to OpenGL and have it do what you expect.

The row or column major issue only comes into play when I want to write my matrix in a document that describes my code, because mathematicians write matrixes as rectangular grids of numbers. However this is just a convention, a way of writing things down, and has no impact on the code I write or the arrangement of numbers in memory on my computer. You could easily re-write these mathematics papers using some other notation, and it would work just as well.

For the array above, I have two options for writing this array in my documentation as a rectangular grid:

|a b| OR |a c| |c d| |b d| 

Whichever way I choose to write my documentation, this will have no impact on my code or the order of the numbers in memory on my computer, it's just documentation.

In order for people reading my documentation to know the order that I stored the values in the linear array in my program, I can specify that this is a column major or row major representation of the array as a matrix. If it is in column major order then I should traverse the columns to get the linear arrangement of numbers. If this is a row major representation then I should traverse the rows to get the linear arrangement of numbers.

In general, writing documentation in row major order makes life easier for programmers, because if I want to translate this matrix

|a b c| |d e f| |g h i| 

into code, I can write it like this:

const matrix = [ a, b, c d, e, f g, h, i ]; 

6 Comments

|a b c| |d e f| |g h i| is not a column major, according en.wikipedia.org/wiki/Row-_and_column-major_order
Oops, pretty big blunder when trying to make things clearer. Corrected now.
As author of one of the very unhelpful answers, I would like to point out that the original poster DID understand the distinction between row major and column major layout correctly. Still, they did not arrive at the expected result, because they chose the wrong multiplication order in their shader code (i.e. vM instead of Mv). Dealing with these two separate issues (layout + multiplication order) makes the answers confusing, but ignoring the multiplication order issue is, in my opinion, even less helpful.
I guess different people find different things helpful/unhelpful. Luckily we have several explanations now from different viewpoints, so there is something for everyone.
this answer puts things in a weird order. since this is math, the matrix exists first (a 2-dimensional thing), and then someone has to put the elements into some linear order in memory. this answer pretends like things in memory came first, and matrices are just an arbitrary notation for things in memory, which is nonsense. the math isn't arbitrary, the implementations are. -- however, I do find helpful that this is the first answer to write down a matrix plainly. the others just confuse this and stick to only code, which doesn't help, because code is an implementation of matrices.
|
0

For example:

GLM stores matrix values as m[4][4]. But it treats matrices as if they have a column major order. Even though for 2 dimensional array m[x][y] in C x represents a row and y represents a column, which means that matrix represented by this array has in fact row major order. The trick is to treat m[x][y] as if x represents a column and y represents a row. It is like you transposing the matrix without performing any additional operations to achieve that.

Comments

0

I will also add my two cents to this, since a lot of the answers contain confusing or simply wrong information or do not go into detail on where the confusion is coming from.

Looking at memory

Let's start by ignoring row-major and column-major (and any mentions of rows/columns in the docs) and we will focus on how the GPU interprets a mat4 when it comes to multiplication by default in GLSL. We will use standard mathematical conventions.

First, in memory, the 16 entries of the matrix are layed out linearly:

[x0 x1 x2 x3 y0 y1 y2 y3 z0 z1 z2 z3 w0 w1 w2 w3]

Conceptually, this is an array of vec4 i.e.

[[x0 x1 x2 x3][y0 y1 y2 y3][z0 z1 z2 z3][w0 w1 w2 w3]]

We know that this is the case if we read the respective sections about memory layout, alignment etc.. This means that if we index the matrix, we get as a result these vectors, i.e.

m[0]=[x0 x1 x2 x3]

The GLSL 4.6 documentation states in chapter 5.10.:

vec3 v, u;
mat3 m;
u = v * m;

will be equivalent to

u.x = dot(v, m[0]); // m[0] is the left column of m
u.y = dot(v, m[1]); // dot(a,b) is the inner (dot) product of a and b
u.z = dot(v, m[2]);

(left-multiply)

and

u = m * v;

is equivalent to

u.x = m[0].x * v.x + m[1].x * v.y + m[2].x * v.z;
u.y = m[0].y * v.x + m[1].y * v.y + m[2].y * v.z;
u.z = m[0].z * v.x + m[1].z * v.y + m[2].z * v.z;

The only possible conclusion from this is that in typical mathematical notation, the matrix looks like this:

x0 y0 z0 w0 x1 y1 z1 w1 x2 y2 z2 w2 x3 y3 z3 w3 

With standard matrix multiplication ("row by column"). Of course, the documentation constantly mentions that the matrix is indeed stored column-by-column and that m[i] accesses the columns of a matrix, so we can conclude that the OpenGL docs follow standard mathematical notation even if we mistrust them.

Thus, GLSL treats every single matrix as a column-major matrix by default. As far as I am aware, HLSL uses row-major by default. New versions of GLSL support layout-qualifiers, allowing you to explicitly specify a matrix as row-major, which will cause it to be interpreted accordingly.

Concrete example: Translation matrix

Now to the example using a translation matrix. Mathematically it looks like this:

1 0 0 Tx 0 1 0 Ty 0 0 1 Tz 0 0 0 1 

Which means that if you want to perform a translation using a 4x4 matrix in a GLSL shader the matrix has to have the layout

[1 0 0 0 0 1 0 0 0 0 1 0 Tx Ty Tz 1]

I think so far, this is pretty obvious. We understand how everything works now in the column-major world.

In column-major we usually see M * v whereas row-major often uses v * M.

GLSL implicitly treats v as a row-vector in the second case and we've previously established that the result consists of the dot-product with the columns of M. This means that M has to be transposed for this calculation to be correct which is probably obvious to anyone familiar with matrix multiplication. Note that "reading" a row-major matrix as column-major (and vice-versa) IS a transposition, because what you treat as columns are actually the rows.

Thus, as far as OpenGL is concerned, if you have row-major matrices client-side, you can

  • Transpose them before upload and use M * v (i.e. via transpose argument of glUniformMatrix)

  • Transpose them in shader as transpose(M) * v

  • Mark them using layout(row_major) and use M * v

  • Upload them as-is and use v * M (and reverse multiplication order of matrices in the shader). It'll be read column-major, which transposes it and makes this calculation correct.

The case in the question

OP was using row-major matrices client-side and was confused about why the transpose argument needed to be false for the transformations to work correctly. Assuming that OP stated the memory layout faithfully, my conclusion is that OP used v * M in the shader, which would make this correct. Alternatively it is quite possible that OP was just confused about the layout in the library.

Nowadays, the docs for the transpose argument read

Specifies whether to transpose the matrix as the values are loaded into the uniform variable. Must be GL_FALSE.

Which makes no statements about row-major or column-major. This is most likely due to the addition of layout(row_major), where the old definition as stated in the old post by OP would make no sense anymore.

Why everyone is confused

In the "row-major" world (i.e. HLSL), people have become used to the convention of using v * M instead of M * v. If the shader would read the row-major matrix as column-major, the fourth bullet point from above would apply and everything would be fine.

However, HLSL assumes row-major layout by default. If we want to be calculating v * M using row-major matrices that are also read row-major in the shader then this can only work if M is already transposed.

For this reason, you'll see a translation-matrix on the client-side defined as:

1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, Tx, Ty, Tz, 1 Linear: [1 0 0 0 0 1 0 0 0 0 1 0 Tx Ty Tz 1] 

Thus the matrix has the same linear layout as a column-major translation matrix, because in row-major, this is a transposed translation matrix (the translation bit is in the last row).

And that is why this topic is so confusing. For some reason, some people thought this would be a good convention to have, where you are basically hiding the fact that behind all of those variable names for your fancy transformation matrices, you actually have a transposed matrix. That is of course also why in this type of "framework", matrix multiplication has to be in the reverse order in shader AND client-side.

TL;DR

  • What matters is how the linear memory is interpreted. GLSL default is column-major, HLSL default is row-major. Modern shader languages let you specify it.

  • If the client-side layout does not match what the shader thinks the layout is, your matrix will behave as a transposed matrix

  • If you have client-side row-major matrices in GLSL, your options are

    • Transpose them before upload and use M * v (i.e. via transpose argument of glUniformMatrix)

    • Transpose them manually in shader as transpose(M) * v

    • Mark them using layout(row_major) and use M * v

    • Upload them as-is and use v * M (and reverse multiplication order of matrices in the shader). It'll be read column-major, which transposes it and makes this calculation correct.

  • In HLSL, people for some reason like to use v * M with row-major matrices on client-side and shader-side, which means that these people have to create all their matrices in transposed form implicitly. They have to reverse multiplication order due to this. Another consequence is that these row-major matrices have the same memory layout as a non-transposed column-major matrix, which is why some people made that claim in their answers.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.