1
\$\begingroup\$

Let's assume we have 4x4 3D transformation matrix, that is the result of scale, rotation, and translation transforms. How to set its scale to (1,1,1) in the fastest way? Assume also that the matrix is represented by float[16] array.

By fastest way I mean, the most performance accurate way, that will be low CPU cost.

\$\endgroup\$
  • \$\begingroup\$ Is the scale known, or do we need to compute it? Is the scale guaranteed to be uniform, or could there be a non-uniform scale applied? \$\endgroup\$ – DMGregory Apr 11 '16 at 13:56
  • \$\begingroup\$ Scale is composed in the matrix (float[16]) that we have. Scale can be various (uniform, non uniform, but different from 1,1,1). \$\endgroup\$ – komorra Apr 11 '16 at 14:05
  • 1
    \$\begingroup\$ which other transformations can be in the matrix? only rotation and translation or is shear allowed? \$\endgroup\$ – ratchet freak Apr 11 '16 at 14:53
2
\$\begingroup\$

Assuming your matrix multiplication follows the convention...

M * v = (T * R * S) * v

(where M is your composed matrix, T is a Translation matrix, R rotation, S scale, and v is a vector you want to transform using the matrix)

...then you can normalize the first three columns of the matrix to get just the T * R part.

If you use the opposite matrix multiplication convention (v * M) then you'd normalize the first three rows instead. Either way, you only want to modify the 3x3 block of entries in the top-left of the matrix, ignoring the last row & column (which contain translation information and the homogeneous unit)

If you want to eke out every last CPU cycle, you can play with SIMD instructions to do the three vector normalizations with one multiply & square root, but this is likely to only be noticeable if you're processing big batches of these matrices in a very friendly data layout.

\$\endgroup\$
  • \$\begingroup\$ I agree with DMGregory - sadly there are no great tricks here. However, if you know that an object has a constant scale, you can calculate the magnitude of the scale once, and store it as 1/scale, allowing you to apply it to subsequent transforms for that object - for example, I do this when I take a scaled model and need to rotate and translate a physics mesh that doesn't support scale - each time the matrix changes I can use my stored values to remove the scale cheaply (cheaper-ly?) but that assumes scale is not changing. \$\endgroup\$ – Steven Apr 12 '16 at 4:02
0
\$\begingroup\$

There's a trick you can use to numerically remove (or rather reduce as much as you want) any scaling from the upper 3x3 sub-matrix, assuming it's not singular. Let's call that 3x3 sub-matrix M. You can take the transpose of the inverse of M, and average it with M. That will be the new M for the next loop.

while (...) {       
   N = (transpose(inv(M)) + M)/2
   if M is almost like N then stop
   M <-- N
}

You can set a max number of loops, and stop earlier if M is close enough to N

\$\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.