0
\$\begingroup\$

Given two affine transformations in 3D (i.e., TRS transforms) called T0 and T1, each represented by a translation vector (t), quaternion (r) and scaling vector (s).

Now, say that I want to compute the composed transform, i.e., creating the single transform that corresponds to T1(T0(*)).

One (naive) way is to simply setup the 3x4 matrix corresponding to this transform, extract the translation vector and combined scaling/rotation matrix and then use polar decomposition to split that matrix into the scaling vector and quaternion. This decomposition however is rather costly computation-wise, is it possible to compute the new scaling vector and quaternion without this operation?

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Unfortunately this is not possible to do in the most general case. That's because the set of TRS transformations is not closed under composition. Applying one {Translation, Rotation, axis-aligned Scale} transformation followed by another may result in a transformation this is not itself expressible as a single {Translation, Rotation, axis-aligned Scale} trio.

The problem cases arise whenever these two criteria are both met:

  • the first/inner transformation has a rotation that's not expressible as a series of 90° rotations about the coordinate axes

  • AND the second/outer transformation has a non-uniform scale

This combination results in a net scale that is diagonal to the object's local coordinate axes, so it can't be expressed with a single axis-aligned scale vector.

It can still be expressed as a matrix, since matrix transformations are more general than TRS transformations (able to include shears). The set of matrix transformations is closed under composition (matrix multiplication).

This is the reason why in Unity's transformation API, there are properties for "local" position, rotation, and scale, but for "global" there's only position and rotation. The global scale property is called lossyScale to communicate that it can no longer be guaranteed to fully represent the scaling applied when multiple transformations are stacked.

If you can guarantee that the later transform(s) will only ever apply uniform scale, then you can compose the transformations like so:

$$ \begin{align} \bf T_0: & \vec t_0 \quad & \bf T_1: &\vec t_1\\ &\bf r_0 & & \bf r_1\\ & \vec s_0 & & \vec s_1 = \begin{bmatrix}u\\u\\u\end{bmatrix} \end{align} $$

$$ \begin{align} \bf T_c &= \bf T_1 \circ \bf T_0\\ \vec t_c &= \vec t_1 + u\left(\bf r_1 \circ \vec t_0 \right) \\ \bf r_c &= \bf r_1 \circ \bf r_0\\ \vec s_c &= u \vec s_0 \end{align} $$

This special case (non-uniform scales only at the leaf level) is one we often want to enforce in game object transformation hierarchies for other reasons anyway (eg. skeletal animations or physics), so you may find it's not too onerous to stick to this subset and benefit from easy TRS composition producing TRS outputs.

\$\endgroup\$

You must log in to answer this question.

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