4
\$\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\$
2
  • \$\begingroup\$ Are you asking how, given a 4x4 matrix known to contain translation, rotation and scale information, you can extract that information? \$\endgroup\$
    – user1430
    Mar 1, 2016 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\$ Sep 28, 2016 at 16:00

2 Answers 2

6
\$\begingroup\$

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

$$\begin{array}{lc} \vec p_{transformed} = M \times \vec p_{local} & M=\begin{bmatrix} m_{00} & m_{01} & m_{02} & m_{03} \\ m_{10} & m_{11} & m_{12} & m_{13} \\ m_{20} & m_{21} & m_{22} & m_{23} \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \\ & \text{where $M$ is assumed to be}\\ & \text{decomposible into: }\\ \vec p_{transformed} = T \times R \times S \times \vec p_{local} &M = T \times R \times S\\ \end{array}$$

Here the component matrices are:

  • Translation by a vector \$\vec t = (t_x, t_y, t_z)\$: $$T=\begin{bmatrix} 1 & 0 & 0 & t_x \\ 0 & 1 & 0 & t_y \\ 0 & 0 & 1 & t_z \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}$$

  • Rotation by an orthonormal rotation matrix \$R\$ (with determinant 1), and...

  • Axis-aligned scale by \$(s_x, s_y, s_z)\$: $$S=\begin{bmatrix} s_x & 0 & 0 & 0 \\ 0 & s_y & 0 & 0 \\ 0 & 0 & s_z & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}$$

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, the translation vector is the image of the origin position vector after transformation:

$$\vec t = M \times \begin{bmatrix}0\\ 0\\ 0\\ 1\end{bmatrix}$$

Which we can look at as simply extracting the last column of the matrix. In pseudo-code:

Vector3 translation = Vector3(matrix[0, 3], matrix[1, 3], matrix[2, 3])

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

$$s_x = \Vert M \times \begin{bmatrix}1\\0\\0\\0\end{bmatrix} \Vert, \quad s_y = \Vert M \times \begin{bmatrix}0\\1\\0\\0\end{bmatrix} \Vert, \quad s_z = \Vert M \times \begin{bmatrix}0\\0\\1\\0\end{bmatrix} \Vert$$

Which is just the length of each of the first three columns interpreted as vectors. In pseudo-code:

Vector3 scale;
for(int i = 0; i < 3; i++) {
    scale[i] = sqrt(
                 matrix[i, 0] * matrix[i, 0]
               + matrix[i, 1] * matrix[i, 1]
               + matrix[i, 2] * matrix[i, 2]);
}

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) using the determinant/triple-scalar product and decide by fiat that it should be represented by a reflection along the x axis:

if dot(
       cross( Vector3(matrix[0,0], matrix[1,0], matrix[2,0]), 
              Vector3(matrix[0,1], matrix[1,1], matrix[2,1])), 
       Vector3(matrix[0,2], matrix[1,2], matrix[2,2]) 
   ) < 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=\begin{bmatrix} \frac{m_{00}}{s_x} & \frac{m_{01}}{s_y} & \frac{m_{03}}{s_z} & 0 \\ \frac{m_{10}}{s_x} & \frac{m_{11}}{s_y} & \frac{m_{13}}{s_z} & 0 \\ \frac{m_{20}}{s_x} & \frac{m_{21}}{s_y} & \frac{m_{23}}{s_z} & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}$$

Note that if one of \$s_x\$, \$s_y\$, or \$s_z\$ 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 the rotation matrix be the identity matrix, \$R = I\$, 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\$
1
  • \$\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, 2016 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\$
3
  • \$\begingroup\$ Hit and run down voting, are we? \$\endgroup\$ Mar 2, 2016 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, 2016 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\$ Mar 2, 2016 at 20:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .