6
\$\begingroup\$

I have a transformation matrix that rotates and scales. Is there any easy way to disassemble it into the original rotation and scaling matrices?

For instance:

M = R * S;
// I need f and h such that
R = f(M); S = h(M);
\$\endgroup\$
  • \$\begingroup\$ It's not that simple. It's like saying "I have the number 4, I need to split it into the two numbers which, when added together, will give me 4, what are the two numbers?" \$\endgroup\$ – Maximus Minimus May 5 '14 at 17:18
  • 3
    \$\begingroup\$ @JimmyShelter It's not quite that bad. Rotation and scale are fundamentally different geometric operations, so they actually can be unambiguously separated even when combined in the same matrix. \$\endgroup\$ – Nathan Reed May 5 '14 at 20:32
11
\$\begingroup\$

As long as you're doing only uniform scaling, this is easy; you can simply extract each row (or column; it doesn't matter), of the 3x3 matrix. The scale factor will be the length of the row vector. If you normalize each row vector and construct a new matrix from the normalized rows, that will be the rotation part. (If you have a 4x4 matrix, you just do this to the upper-left 3x3 part.)

This can be done because uniform scaling commutes with rotation, and therefore the two can be cleanly separated. In fact, a matrix constructed from any sequence of rotations and uniform scales can be broken down into a single rotation and a single scale.

If you have nonuniform scaling, but it's done along the axes before any rotations are applied in the transformation chain, you can also extract that with the same technique as above; you just get the three axial scale factors from the lengths of each of the three rows or columns (depending which convention you use; here, it does matter).

The general case of an arbitrary combination of nonuniform scales and rotations can't be decomposed into a single rotation and a single scale, since nonuniform scaling doesn't commute with rotation in general. However, using singular value decomposition, a general linear transformation can be decomposed as a rotation, a nonuniform scale, and another rotation.

\$\endgroup\$
  • \$\begingroup\$ What is the definition of uniform scaling and how do I differentiate it from the alternative (nonuniform)? \$\endgroup\$ – wolfdawn May 6 '14 at 8:16
  • 2
    \$\begingroup\$ Uniform scaling is just using the same scale factor for all three axes. \$\endgroup\$ – GuyRT May 6 '14 at 8:51
  • \$\begingroup\$ @GuyRT So I don't understand what's wrong with multiplying the Matrix by e1, e2, e3 and checking their lengths? Wouldn't the scaling matrix be determined by the lengths of Me1, Me2 and M*e3? I am not sure why none-uniform is problematic. \$\endgroup\$ – wolfdawn May 7 '14 at 17:11
  • \$\begingroup\$ Yes, you can extract nonuniform scaling factors from a matrix. A problem arises (as noted in the answer) if a non uniform scale is applied after a rotation (imagine rotating a square by 45 degrees, then scaling in one direction only - you no longer have a square). The resulting transformation cannot be decomposed into just a scale and rotation. There may be a shear involved too, and I don't think you can unambiguously separate the shear from the rotation. \$\endgroup\$ – GuyRT May 7 '14 at 21:24
  • 1
    \$\begingroup\$ @NightElfik True! That can be detected by looking at the matrix determinant, which will be negative if there's a reflection in it. Then you negate one of the three axis scales (pick one arbitrarily) and proceed as before. There's ambiguity about which axis is reflected because, for instance, a reflection along X is equivalent to reflecting along Y and then rotating 180° about Z, etc. \$\endgroup\$ – Nathan Reed Jan 6 '18 at 21:30
2
\$\begingroup\$

You can apply the transformation matrix to a point and calculate the orientation and the scale from it. This of course only works if there are no other transformations than that.

Vec2 scale;
Angle rotation;

Vec2 point(0, 1);
point = matrix.apply(point);
scale.Y = point.length();
rotation = AngleBetween(point,   Vec2(0, 1));

Vec2 pointX(1, 0);
pointX = matrix.apply(pointX);
scale.X = pointX.length();

Though, it would be better if you just store the parameters alongside with the transformation and just read out that information when needed.

\$\endgroup\$
0
\$\begingroup\$

This is what I did. Please comment and vote if it's correct?

I had a 3d transform matrix that both scales and rotates a vector:

I took the vectors : \$(1, 0, 0); (0, 1, 0); (0, 0, 1)\$ (let's call them x1, y1, z1) and I multiplied the matrix by those vectors. I then intuitively checked their lengths much like API-Beast suggested.

So I figured the scaling Matrix is:

$$ \begin{pmatrix} Tx1.length & 0 & 0 \\ 0 & Ty1.length & 0 \\ 0 & 0 & Tz1.length \\ \end{pmatrix} $$

I then inverted this matrix (easily)

$$ \begin{pmatrix} \dfrac 1 {Tx1.length} & 0 & 0 \\ 0 & \dfrac 1 {Ty1.length} & 0 \\ 0 & 0 & \dfrac 1 {Tz1.length} \\ \end{pmatrix} $$

And if \$T = RS\$ then \$T(S^-1) = RS(S^-1) = R\$.

\$\endgroup\$
  • \$\begingroup\$ You usually apply the scaling first, not the rotation. For matrices order of operation matters. You would need the inverse of the rotation matrix not the scaling matrix. \$\endgroup\$ – API-Beast May 6 '14 at 12:29
  • \$\begingroup\$ What does the "T" here represent? \$\endgroup\$ – doppelgreener Jan 11 at 16:32

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.