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\$ Commented 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\$ Commented 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\$ Commented Nov 6, 2023 at 12:56

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.