This intuition comes from the fact that one usually builds a transformation in mathmetical order
But there is no such thing as a mathematical order. Consider the following: v
is an n-dimensional vector and M
a n x n square matrix. Now the question is: which is the correct multiplication order? And that depends on your convention again. In most classic math textbook, vectors are defined as column vectors. And then: M * v
is the only valid multiplication order, while v * M
is simply not a valid operation mathematically.
If v
is a column vector, then it's transpose v^T
is a row vector and then v^T * M
is the only valid multiplication order. However, to achieve the same result as before, say x = M * v
, you have to also transpose M
: x^T = v^T * M^T
.
If M
is the product of two matrices A
and B
, what we get here due to the non-commutative way of matrix multiplication is this:
x = M * v
x = A * B * v
x = A * (B * v)
or, we could say:
y = B * v
x = A * y
so clearly, B
is applied first.
In the transposed convention with row matrices, we need to follow (A * B)^T = B^T * A^T
and get
x^T = v^T * M^T
x^T = v^T * B^T * A^T
x^T = (v^T * B^T) * A^T
So B^T
again is applied first.
Actually, when you consider the multiplication order, the matrix which is written closest to the vector is generally the one applied first.
I don't believe this has anything to do with column major/row major convention and notation as some threads suggest.
You are right, it has absolutely nothing to do with that. The storage order can be arbitrary and does not change the meaning of the matrices and operations. The confusion often comes from the fact that interpreting a matrix which is stored column-major as a matrix stored row-major (or vice-versa) will just have the effect of transposing the matrix.
Also, GLSL and HLSL and many math libraries do not use explicit column or row vectors, but use it as it fits. E.g., in GLSL you can write:
vec4 v;
mat4 M;
vec4 a = M * v; // v is treated as column vector here
vec4 b = v * M; // v is treated as row vector now
// NOTE: a and b are NOT equal here, they would be if b = v * transpose(M), so by swapping the multiplication order, you get the effect of transposing the matrix
Is there a historical reason for this?
OpenGL follows classical math conventions at many points (i.e. the window space origin is bottom-left and not top-left as most window systems do work), the old fixed function view space convention was to use a right-handed coordinate system (z
pointing out of the screen towards the viewer, so the camera looking towards -z
), and the OpenGL spec uses column vectors to this day. This means that the vertex transform has to be M * v
and the "reverse" order of the transformations applies.
This means, in legacy GL, the following sequence:
glLoadIdentity(); // M = I
glRotate(...); // M = M * R = R
glTranslate(...); // M = M * T = R * T
will first translate the object, and then rotate it.
GLM was designed to follow the OpenGL conventions by default, and the function glm::mat4 glm::translate(glm::mat4 const& m, glm::vec3 const& translation);
is explicitely emulating the old fixed-function GL behavior.
It just seems a bit backwards to me and I would probably rewrite the functions unless there's a good enough reason for it.
Do as you wish. You could set up fnctions which instead of psot-multiply do a pre-multiplication. Or you could set up all transformation matrices as transposed, and post-multiply in the order you consider "intuitive". But note that for someone following either classical math conventions, or typical GL conventions, the "backwards" notation is the "intuitive" one.