0
\$\begingroup\$

Let's say we have a 4-by-4 matrix A which represents some transformation.

We can use this matrix to transform a vector in two ways.

  • Ax by assuming x is a 4-by-1 column vector.
  • xA by assuming x is a 1-by-4 row vector.

Up until yesterday, I have not seen this xA variant and I thought it was unnecessary. Then I came about this.

This function takes just the projection matrix, computes the inverse projection matrix and then does this xA variant (not Ax) to transform (or unproject) a bunch of coordinates.

At first, I wasn't looking and did Ax which came out nonsensical and now I'm trying to understand why.

I've noticed that Ax == xAT but when I look at the way the matrix multiplication is carried out. The components that make up the result are very different depending on whether I use Ax or xA (as it should be, matrix multiplication is not commutative).

The analytic solution for Ax (3-by-3 matrix and row vector)

{x,y,z}.{{a,b,c},{d,e,f},{g,h,i}} == {ax+dy+gz,bx+ey+hz,cx+fy+iz}

The analytic solution for xA (3-by-3 matrix and column vector)

{{a,b,c},{d,e,f},{g,h,i}}.{{x},{y},{z}} == {{ax+by+cz},{dx+ey+fz},{gx+hy+iz}}

I use Mathematica to test these things. On a hunch I tried the analyitic solution for xA with the elements of A transposed manually and of course, I get.

{{a,d,g},{b,e,h},{c,f,i}}.{{x},{y},{z}} == {{ax+dy+gz},{bx+ey+hz},{cx+fy+iz}}

Which is equivalent to Ax except we now have a column vector not a row vector. I'm assuming all of this is purely conventional (and depends on whether I'm assuming row- or column-major matrix layout). It looks like I might have answered the question my self but if I'm wrong about anything here please correct me.

\$\endgroup\$
  • 2
    \$\begingroup\$ As you said, it is purely conventional. Some people prefer rows, other columns, it also depends on which library you use, but it does not change anything \$\endgroup\$ – realUser404 Nov 25 '16 at 12:30
  • 1
    \$\begingroup\$ I can only recommend the excellent "Game Engine Architecture" by Jason Gregory, it explains very well all you need to know, including 3D Math \$\endgroup\$ – realUser404 Nov 25 '16 at 12:37
  • 1
    \$\begingroup\$ Yes, almost all linear algebra uses the row major convention since matrices are operators and operators are usually applied in a left-to-right fashion; this is because operators, just like functions, act on certain quantities. It feels natural to say "apply this operator to that object" not vice-versa "on this object apply that operator". Both sentences are correct in both natural and mathematical language. But in the mathematical language, one has to switch the major axis (column or row) for both operand and operator (i.e. vector and matrix) and then switch their order of appearance. \$\endgroup\$ – teodron Nov 25 '16 at 13:32
  • 1
    \$\begingroup\$ Row-major vs column-major is the one of main differences between OpenGL and DirectX. It seems OpenGL uses column-major, while DirectX uses row-major. It's pure conventional, but it starts to matter in what order to perform matrix vs vector multiplication in shader. In GLSL shader if use OpenGL based math library you would use "Ax" convention, but if you use DirectX based math library for your OpenGL app, you would need to use "xA convention". Also this makes difference in what order you need to multiply your matrices. \$\endgroup\$ – Dmitry Tolmachov Nov 25 '16 at 16:00
  • 1
    \$\begingroup\$ In OpenGL based math libraries it's mat4.mult(ProjectionMatrix, mat4.mult(ViewMatrix ,ModelMatrix)), while in DirectX based math libraries it's mat4.mult(mat4.mult(ModelMatrix,ViewMatrix),ProjectionMatrix) \$\endgroup\$ – Dmitry Tolmachov Nov 25 '16 at 16:02
1
\$\begingroup\$

I think the answer I was looking for was laid out in @DmitryTolmachov's comment.

Row-major vs column-major is the one of main differences between OpenGL and DirectX. It seems OpenGL uses column-major, while DirectX uses row-major. It's pure conventional, but it starts to matter in what order to perform matrix vs vector multiplication in shader. In GLSL shader if use OpenGL based math library you would use "Ax" convention, but if you use DirectX based math library for your OpenGL app, you would need to use "xA convention". Also this makes difference in what order you need to multiply your matrices.

We can turn row-major into column-major by transposing the matrix. In my particular case I have been using row-major for my 4-by-4 matrix. I then transpose these matrices when I send them to OpenGL (I use OpenGL).

Since I'm using a row-major convention for my matrix math library, transforming a vector must be implemented as xA. If I use a column-major convention I implement vector transform as Ax.

It doesn't matter which you use but you cannot mix them (that would be undefined behavior) and the end result must be compatible (with regards to their respective shader language) with the 3D API we're using, be it DirectX or OpenGL or something else.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.