1
\$\begingroup\$

I have been following some tutorial's on how Matrix maths works, with adding, dividing, scaling, etc, but I am struggling to understand how the 4x4 matrix represents an object's position in space.

There are 16 elements in the array but to my knowledge you only need to use 7 of them? (I am most likely, horribly wrong but please correct me) and they are; x, y, z, scale, pitch, roll and yaw.

Furthermore what is the significance of a column major matrix over a row major one or vice versa? Is it just down to the framework you are using that determines which one you use? (i.e OpenGL or DirectX) and what is the difference between them? is it just the order the elements appear in?

\$\endgroup\$
3
\$\begingroup\$

A matrix is just a big grid of numbers with rules that define how we can multiply it with other grids or lists of numbers.

In games, we want to construct a matrix so that, when multiplied with a list of numbers representing a source position (say, the position of a vertex in a mesh) we get a list of numbers representing a destination position (say, the position of that vertex in the game world, after applying the transformations of all its parent objects, or the position of the vertex projected on the screen by our camera)

Because of how matrix multiplication is defined, we can either do:

Matrix * ColumnVector = RowVector

or

RowVector * Matrix = ColumnVector

I'm most familiar with the first convention, so that's what I'll use for the examples below. If your environment uses the opposite convention, just transpose all of the examples below (turn each column into a row)

p_destination = M * p_source
           ┌    ┐
Where      | px |
p_source = | py |  Is the source position we want to transform.
           | pz |  The "w" corrdinate of 1 means we're using homogeneous coordinates
           |  1 |  to apply translation (setting this to 0 will only rotate/scale/skew,
           └    ┘  which is desireable when transforming directions like surface normals)

A typical object transform in games (not including camera projection) will look like this:

    ┌                    ┐
M = | m00  m01  m02  m03 | = T * R * S 
    | m10  m11  m12  m13 |   ie. 
    | m20  m21  m22  m23 |    p_destination = M * p_source
    |   0    0    0    1 |    p_destination = T * R * S * p_source
    └                    ┘

Since we rarely deliberately introduce skew in object transformations, this matrix is generally the product of three distinct transformations, we could look at as being three distinct matrices:

    ┌             ┐
T = | 1  0  0  tx |  Translation by the vector (tx, ty, tz)
    | 0  1  0  ty |
    | 0  0  1  tz |
    | 0  0  0   1 |
    └             ┘

    ┌               ┐
S = | sx   0   0  0 |  Axis-aligned scale by (sx, sy, sz)
    |  0  sy   0  0 |
    |  0   0  sz  0 |
    |  0   0   0  1 |
    └               ┘

    ┌               ┐  (Given a left-handed, y-up coordinate system)
R = | rx  ux  fx  0 |  Rotation so that:
    | ry  uy  fy  0 |   local x axis points to r = (rx, ry, rz) "right"
    | rz  uz  fz  0 |   local y axis points to u = (ux, uy, uz) "up"
    |  0   0   0  1 |   local z axis points to f = (fx, fy, fz) "forward"
    └               ┘  Where r, u, f are all perpendicular unit vectors (a basis)

  We can compute the r, u, f vectors using pitch, roll, and yaw angles.
  These angles are just a compact way to represent an orientation, called "Euler Angles;"
  we generally unpack them to a matrix or quaternion when transforming a lot of vectors
  because the less-compact representations are more efficient to use in bulk calculations,
  and can avoid snares like "gimbal lock" that creep in when modifying Euler angles.

Bringing it all together, by multiplying these three transformations:

    ┌                            ┐
M = | sx*rx   sy*ux   sz*fx   tx | 
    | sx*ry   sy*uy   sz*fy   ty |
    | sx*rz   sy*uz   sz*fz   tz |
    |   0       0       0      1 |
    └                            ┘

Using the conventions above, you can see vectors we care about often occur as columns in the matrix (eg. translation in the 4th column, direction vectors in the first three columns of the rotation matrix). So, if we use a column-major matrix representation (where consecutive elements in a column are consecutive in storage order), this makes it convenient to set or read columns of the matrix (eg. T[3] = (tx, ty, tz, 1) to set the 4th column of a translation matrix). A row-major representation would store consecutive elements in a row consecutively.

So, row-major vs column-major is just about using the data representation that's most convenient for the matrix multiplication conventions used by your engine or programming environment.

\$\endgroup\$
  • \$\begingroup\$ Thank you for the brilliant reply, it definitely has cleared some things up for me \$\endgroup\$ – 0xen Jun 29 '16 at 14:47
  • 1
    \$\begingroup\$ ...plus homogeneous coordinates for the last elements if I am not mistaken \$\endgroup\$ – wondra Jun 29 '16 at 20:04
  • \$\begingroup\$ @wondra I'm not sure if I understand your comment. I describe homogeneous coordinates briefly when defining p_source - was there something you wanted to elaborate on here? \$\endgroup\$ – DMGregory Jun 29 '16 at 20:40
  • \$\begingroup\$ Turns out I just did not see them, (they were not present in summary matrix) \$\endgroup\$ – wondra Jun 29 '16 at 21:20
  • \$\begingroup\$ Still not sure what you mean - there's a [0, 0, 0, 1] in the final row of all of these matrices. (Fun fact for 0xen: many game vector math libraries will store matrices as 3x4, omitting this last row since it's so predictable, and just "pretend" it's there for purposes of transformation calculations) \$\endgroup\$ – DMGregory Jun 29 '16 at 21:36

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.