0
votes

I've been dabbling in OpenGL and DirectX for the past while, and I've noticed that all transformations are done by doing matrix by matrix and matrix by vector multiplication. I think we can all admit that especially matrix by matrix multiplication is not intuitive, and when I learned that matrix by matrix multiplication involved 64 multiplications and 48 additions, I wasn't so hard on myself for not understanding them well.

Anyway, I know that matrix and vector multiplication on modern systems is done with SIMD or SSE instructions, reducing the number of operations (or calculations), but many calculations I've seen programmers make seem unnecessary.

For example if you have a vertex you want to transform, lets just say we want to rotate 45 degrees and then translate (5, 5, 5) locally, the typical way I've seen is the following:

1: Get the identity matrix.

2: Multiply the identity matrix by the rotation matrix.

3: Multiply the resulting matrix by the translation matrix (order matters).

4: Multiply the resulting matrix by the point/vector you want to transform.

If I wanted to translate an object in a certain direction, instead of multiplying its matrix by

{ 1  0  0  translationX }
{ 0  1  0  translationY }
{ 0  0  1  translationZ }
{ 0  0  0      1        }

...couldn't I just add the translations to the appropriate matrix indices, ie., matrix[3][0] += translationX;

The difference is 3 additions instead of 64 multiplications and 48 additions.

Likewise, say I wanted to translate locally, and not in world space, say for example down an object's right vector, then I could multiply the translation vector by the upperleft part of the object's world or model matrix, getting the object's local right vector? That would only be 3x3 matrix times a vector?

So yeah, I've been thinking about this for a while, and I was just wondering if these big matrix by matrix multiplications are entirely unnecessary, at least for some things. Also, I'm aware that scaling adds some complexities, and haven't got my head around the concept of matrices that well yet.

2
You can certainly optimize special cases, but the specific order of concatenation matters. For simple "rotate & translate" only transformations, it's often best just use a quaternion and a translation rather than maintain a matrix, but it depends on how general you want your system to be. In practice what matters is not how expensive it is to compute the matrix as much as how many vertices will you be transforming by that matrix. For 'real-world' models, the vertex transformation cost usually dominates. - Chuck Walbourn
if you consider matrices not intuitive see my attempt to explain them for rookies in: Understanding 4x4 homogenous transform matrices may be that will help a bit - Spektre

2 Answers

3
votes

think we can all admit that especially matrix by matrix multiplication is not intuitive

I completely disagree. First and foremost, when thinking about linear transformations it doesn't make sense to think of matrices to be "2D arrays of numbers". The proper way to think of matrices is as operators in a very general way.

Anyway, I know that matrix and vector multiplication on modern systems is done with SIMD or SSE instructions, reducing the number of operations (or calculations), but many calculations I've seen programmers make seem unnecessary.

The rules of matrix multiplication and their necessity are fully determined by the rules of linear algebra. You start out with certain elementary rules how transformations of vectors from one space to another shall behave and from there the rules of matrix multiplication rise.

Important is, that when chaining up a series of transformations the end result can be coalesced into one single matrix. That's the beauty of these things. No matter how convoluted and complex your transformation setup is, one single matrix does the job. Matrices give you the oppertunity for precomputation!

...couldn't I just add the translations to the appropriate matrix indices, ie., matrix[3][0] += translationX;

Not in general. Only if the upper left part is a identity transformation. The moment that part is non-identity, the translation gets modified by that as well.

I suggest you write out per hand the result

M = rot((0,0,1), 90°) · translate(1, 2, 3)

hint

                    |  0 -1  0  0 |
rot((0,0,1), 90°) = |  1  0  0  0 |
                    |  0  0  1  0 |
                    |  0  0  0  1 |

So yeah, I've been thinking about this for a while, and I was just wondering if these big matrix by matrix multiplications are entirely unnecessary, at least for some things.

The funny thing is, that once you hit a certain depth of transformation levels matrices quickly win out over chaining individual base vector operations.

But here's the thing: Don't think of matrices as 2D arrays of numbers. That's just a way to write down linear transformations.

1
votes
  • It is a premature optimization. Small matrix multiplication (i.e. for 2d or 3d graphics) are cheap enough in most cases for us not to think about it.

  • No, matrices are not the only way to represent transformations. Another really nice representation, alas less popular, is with quaternion for rotation + vector for translation. It does not include some of the transformations possible with a 3x4 (or 4x4) matrix, but they are more compact, more numerically stable, easier to interpolate and sometimes cheaper to work with. I'm surprised that you call matrices 'unintuitive', but if so quaternions might be even harder to grasp.

  • The point of those transformation representations (matrices or quaternions) is that they can be composed. What happens IRL is that you compute some transformation as a composition of multiple transformations and then apply that to every vertex of a model, say. Consider a case that a viewer from a flying helicopter looks at a tank with a rotating turret. To render the turret you have to apply at least three rotations and translations to transform the vertices from the model-space of the turret to the viewer coordinates. Doing it by applying each of the transformations individually is costly, compared to precomputing the whole chain into one matrix and then applying that to each vertex at a mere cost of 9 additions and 9 multiplications per vertex (this is the cost of a non-projective matrix-vector multiplication).