1
votes

I have a 4x4 matrix with translation, rotation, and scaling components, but no shear or other transformations. How do I find its inverse? I'm using the Eigen library in c++.

1

1 Answers

3
votes

This is tricky to get right, since the operations need to be performed in the correct order:

template<class Derived>
Matrix4f AffineInverse(const Eigen::MatrixBase<Derived>& mat)
{
    Matrix3f RotSclInv = (
        mat.block<3, 3>(0, 0).array().rowwise()
        / mat.block<3, 3>(0, 0).colwise().squaredNorm().array() //scaling
        ).transpose(); //rotation
    return (Matrix4f(4,4) << RotSclInv
        , -RotSclInv * mat.block<3, 1>(0, 3) //translation
        , 0, 0, 0, 1).finished();
}

As this answer states, the inverse of the top left 3x3 block can be calculated separately:

inv ([ A b ]) = [inv(A)  -inv(A)*b]
    ([ 0 1 ])   [  0          1   ]

The key insight for the top left block is that the scaling and rotation is equal to a orthogonal (rotation) matrix Q times a diagonal (scaling) matrix D: Q*D. To invert it, do some linear algebra:

  inv(Q*D)
= transp(transp(inv(Q*D)))
= transp(inv(transp(Q*D)))
= transp(inv(transp(D)*transp(Q)))

(see this proof), and since D is diagonal and Q is orthogonal,

= transp(inv(D*inv(Q)))
= transp(Q*inv(D))).

Q*inv(D) is easy to find: Since in Q*D each column is a column of Q (which is a unit vector) times an entry of D (which is a scalar), it is enough to divide each column by the square of its norm. This is what the first three lines of the function do.

Written out fully in linear algebra form:

inv ([ Q*D b ]) = [transp(Q*inv(D))  -transp(Q*inv(D))*b]
    ([ 0   1 ])   [       0                 1           ]