0
\$\begingroup\$

Given a single affine transformation in 3D (i.e., TRS transforms) that is represented by a translation vector (t), quaternion (r) and scaling vector (s).

Is there some way of efficiently computing the inverse transform, while maintaining the same representation?

I initially thought that this was a simple as inverting each component, but a simple test with the resulting 4x4 matrices for these transforms clearly shows that this is incorrect. E.g., the transform:

A  := ({t=(10, 1, 0), r=(0.97, 0.26, 0, 0), s=(5, 5, 5)}
B  := inv(A)       // {t=(-10, -1, 0), r=(0.97, -0.26, 0, 0), s=(0.2, 0.2, 0.2)}
ma := A.to_mat4()  // { { 5 0 0 10 } { 0 4.3 -2.5 1 } { 0 2.5 4.3 0 } { 0 0 0 1 } }
mb := B.to_mat4()  // { { 0.2 0 0 -10 } { 0 0.17 0.1 -1 } { 0 -0.1 0.17 -0 } { 0 0 0 1 } }
i  := ma * mb      // { { 1 0 0 -40 } { 0 1 0 -3.33013 } { 0 0 1 -2.5 } { 0 0 0 1 } }
                   // Clearly not the identity matrix

Is this actually possible to do in some way? If not, are there some circumstances under which this can be done?

\$\endgroup\$
2
  • 1
    \$\begingroup\$ remember the matrix inversion rule: inv(A*B) = inv(B)*inv(A) \$\endgroup\$ Nov 3, 2023 at 15:25
  • \$\begingroup\$ How does that apply to this case? I'm not actually inverting any matrices, in fact, that's what I'm trying to avoid \$\endgroup\$
    – Xaldew
    Nov 3, 2023 at 15:57

1 Answer 1

2
\$\begingroup\$

when you have the transform split into components you apply them one at a time to an object:

o1 = object.scale(trs.scale);
o2 = o1.rotate(trs.quaternion);
o3 = o2.translate(trs.translate);

Or in other' words the final equivalent transformation matrix for this order is M = Trans*Rot*Scale

However the inversion rule requires that you swap the operands of the multiply when you invert it

inv(M) = inv(Trans*Rot*Scale) = inv(Scale)*inv(Rot)*inv(Trans)

Which is the wrong order

Uniform scale and rotate will be commutative with each other so that is not an issue.

In the end you need to find a translation such that T_result*inv(Rot)*inv(Scale) == inv(Scale)*inv(Rot)*inv(Trans)

Some basic matrix multiplications on both sides gives me:

T_result*inv(Rot)*inv(Scale)*Scale  == inv(Scale)*inv(Rot)*inv(Trans)*Scale
T_result*inv(Rot)*Rot               == inv(Scale)*inv(Rot)*inv(Trans)*Scale*Rot
T_result                            == inv(Scale)*inv(Rot)*inv(Trans)*Scale*Rot
\$\endgroup\$
1
  • \$\begingroup\$ Thanks! This mostly solved my issues, however I should note that the T_result matrix wouldn't actually be a pure translation if handled in this way, and hence the transform can't be represented the same way as the input (t=vec3, r=quat, s=vec3). In the end, it seems simpler to add a boolean to this representation to flip the multiplication order when necessary, or as I did, simply having a separate function to generate the inverse (.to_inv_mat4()). \$\endgroup\$
    – Xaldew
    Nov 6, 2023 at 12:56

This site is temporarily in read-only mode and not accepting new answers.

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