2
\$\begingroup\$

It is possible to calculate the translation, rotation and scale that were used to build a matrix?

I mean if I have a matrix M can I calculate the rotation, scale, and translation it represents?

Of course I could save each component in the matrix individually, but can I recover this information from just the matrix data?

\$\endgroup\$
  • \$\begingroup\$ Are you asking how, given a 4x4 matrix known to contain translation, rotation and scale information, you can extract that information? \$\endgroup\$ – Josh Mar 1 '16 at 21:16
  • \$\begingroup\$ The XMMatrixDecompose method can recover the elements, but they will not exactly match your original inputs to say XMMatrixTransformation because there are many ways to achieve the same rotation. \$\endgroup\$ – Chuck Walbourn Sep 28 '16 at 16:00
4
\$\begingroup\$

Assuming the following matrix multiplication convention, where M is the matrix you want to decompose, and the p variables represent points as column vectors with a w coordinate of 1...

p_transformed = M * p_local

    ┌                    ┐
M = | m00  m01  m02  m03 |  assumed to be decomposible into
    | m10  m11  m12  m13 |  M = T * R * S
    | m20  m21  m22  m23 |  such that that...
    |   0    0    0    1 |
    └                    ┘

p_transformed = T * R * S * p_local

    ┌             ┐
T = | 1  0  0  tx |  Translation by (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 |
    └               ┘

R = Rotation matrix (orthonormal)

Then it is possible to compute a choice of translation T, rotation R, and scale S with the same combined result as M.

But there is no guarantee that these will be the same values originally used to create M, as we'll see below.

You also may lose precision due to rounding errors along the way, so you should avoid repeated round-trip conversions between M and T R S, such as when laying out objects in a level editor, saving and loading as you go.

This also goes for updating the transform of a dynamic object at runtime. Being able to rebuild the matrix from raw translation, rotation, and scale values will help you avoid harmful rounding errors.

So, it will almost certainly be worth keeping the extra memory to store your original transformation parameters, both for consistency from a user's perspective, and for accuracy/stability.

That said, if it's something you're using in a read-only manner, or you need to reconstruct transformation parameters from baked data which only contains combined matrices, you can do it like this...


First, extracting the translation component is direct & unambiguous:

tx = m03   ty = m13   tz = m23

The scale can be computed as the length of the basis vectors multiplied by M:

sx = || M * (1, 0, 0, 0) ||  (and similarly for sy, sz)
   = || (m00, m10, m20) ||
   = sqrt(m00 * m00 + m10 * m10 + m20 * m20)

If your scales can be negative then you have an added complication to solve. A reflection in any one axis is identical to a reflection in a different axis combined with a suitable rotation, and a reflection in two axes is equivalent to a pure rotation.

So, you'll need to pick a convention for resolving this. One is to detect whether there is a net reflection (ie. a reflection along 1 or 3 axes) and decide by fiat that it should be a reflection along the x axis:

if (dot(
       cross((m00, m10, m20), (m01, m11, m21)),
       (m02, m12, m22)
   ) < 0)
then
   sx *= -1

(if sx or any other scale is zero then you're dealing with a planar, line, or point projection, so we can express it as a rotation without reflection)

With S in hand we can divide it out to reconstruct an appropriate R:

    ┌                           ┐
R = | m00/sx  m01/sy  m03/sz  0 |
    | m10/sx  m11/sy  m13/sz  0 |
    | m20/sx  m21/sy  m23/sz  0 |
    |   0        0       0    1 |
    └                           ┘

Note that if one of sx, sy, or sz is zero, you'll want to replace the corresponding column with the cross product of the other two to avoid a divide by zero error.

If two axes have zero scale, you can pick two arbitrary unit vectors mutually orthogonal with the remaining axis. If all three axes have zero scale, you can let R = Identity since a point is a point regardless of rotation.

By construction R should be an orthonormal rotation matrix, but in practice numerical errors can cause it to deviate, so including an error-correction step where you orthonormalize it is probably a sensible precaution.

You can use the usual methods to convert that rotation matrix into an equivalent unit quaternion or Euler angle triplet if needed, so I won't elaborate on that here.

\$\endgroup\$
  • \$\begingroup\$ I test this method and the result was very different from the original values. So I decided to save the original transformation. \$\endgroup\$ – amit Mar 5 '16 at 21:17
0
\$\begingroup\$

You can multiply translation, rotation, and scale matrices to get one, final movement matrix.

If you are asking how to extract the values from one final product of several translation, rotation, and scale matrices, then no. It is like trying to find the chosen divisor of a number, say 16. It can be 4, 2, 8, etc.

There is no method to do this (get IDENTICAL translations, rotations, and scales to your original values) unless you have previous matrices, in which case you can divide (for the 16 example: say that you know one of the divisors is 8. Then, you can divide by 8 to get 2 -> this logic is a little different for matrices).

If you are asking how to get translation rotation and scale values from one matrix dedicated to one of those things, then that is easy. It depends if you are using column major or row major order. For that, use this helpful link: http://www.codinglabs.net/article_world_view_projection_matrix.aspx

Transformation:

TransformxAxis.x TransformyAxis.x TransformzAxis.x Translation.x
TranformxAxis.y  TransformyAxis.y TransformzAxis.y Translation.y
TransformxAxis.z TransformyAxis.z TransformzAxis.z Translation.z
0                0                0                1

*depends if you are in 3D or 2D

Translation:

1 0 0 Translation.x
0 1 0 Translation.y
0 0 1 Translation.z
0 0 0 1

Scale:

Scale.x 0 0 0
0 Scale.y 0 0
0 0 Scale.z 0 
0 0 0       1

Check the link for all of them-> Under "Transformation matrix"

\$\endgroup\$
  • \$\begingroup\$ Hit and run down voting, are we? \$\endgroup\$ – Java Man Tea Man Mar 2 '16 at 3:41
  • 1
    \$\begingroup\$ I'd speculate the downvotes are because of the lack of formatting around the matrices (I'll edit to fix that), and because of the somewhat misleading claim that there is "no method" to decompose a matrix M = T*R*S back into a translation, rotation, and scale. As the other answer shows, there is such a method, if we accept the caveat that the rotation & scale extracted may not be identical to the original input values, just equivalent in net effect. \$\endgroup\$ – DMGregory Mar 2 '16 at 3:57
  • \$\begingroup\$ @DMGregory Wow, thank you. And yes, I agree with the identical and equivalent part-- I was trying to convey that and will edit my answer accordingly. Thanks again \$\endgroup\$ – Java Man Tea Man Mar 2 '16 at 20:13

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.