Game Physics Cookbook
上QQ阅读APP看书,第一时间看更新

Matrix inverse

The inverse of matrix M is denoted as Matrix inverse. Multiplying a matrix by its inverse will result in the identity matrix. Not every matrix has an inverse. Only matrices with a non-zero determinant have an inverse. Finding the inverse of a matrix is one of the more expensive operations we are going to perform. However, not every matrix has an inverse! Only square matrices with a non-zero determinant have an inverse.

To find the inverse of a matrix, first find the inverse of its determinantMatrix inverse. If this scalar is zero, the matrix has no inverse. If it's non-zero, perform a component wise scalar multiplication of the inverse determinant and the adjugate of the matrix:

Matrix inverse

Getting ready

Having already implemented both the Determinant and Adjugate functions, all we have to do is make sure the matrix actually has an inverse. We do this by checking the determinant against 0, using the CMP macro we copied over from vectors.cpp. If the determinant is 0, we just return the identity matrix. Doing so prevents us from triggering a possible divide by 0 exception.

How to do it…

Follow these steps to implement a function which returns the inverse of two, three and four dimensional square matrices:

  1. Add the declaration for the inverse functions to matrices.h:
    mat2 Inverse(const mat2& mat);
    mat3 Inverse(const mat3& mat);
    mat4 Inverse(const mat4& mat);
  2. Implement these functions in matrices.cpp:
    mat2 Inverse(const mat2& mat) {
        float det = Determinant(mat);
        if (CMP(det, 0.0f)) { return mat2(); }
        return Adjugate(mat) * (1.0f / det);
    }
    mat3 Inverse(const mat3& mat) {
        float det = Determinant(mat);
        if (CMP(det, 0.0f)) { return mat3(); }
        return Adjugate(mat) * (1.0f / det);
    }
    mat4 Inverse(const mat4& mat) {
        float det = Determinant(mat);
        if (CMP(det, 0.0f)) { return mat4(); }
        return Adjugate(mat) * (1.0f / det);
    }

How it works…

Finding the inverse of a matrix comes down to two functions we have already implemented; Determinant and Adjugate. The reason only matrices with a non-zero determinant have an inverse is this part of the inverse equation: How it works…. If the determinant of the matrix were 0, we would have a divide by 0 to deal with. Because division by 0 is undefined, so is the inverse of any matrix that has a determinant of 0.

There's more…

Loops in code are expensive! To a much lesser extent, so are function calls. Our matrix inverse function heavily relies on both! Inverting a 4 X 4 matrix is such a common operation; you should really consider expanding this function. You've already seen an expanded function, the determinant of a 2 X 2 matrix.

Expanding the inverse

Expanding a function is just a fancy way of saying we're planning to unroll all loops and write out every operation the computer has to do in a linear fashion. For the 2 X 2 matrix, the expanded code looks like this:

mat2 Inverse(const mat2& mat) {
    float det = mat._11 * mat._22 - mat._12 * mat._21;
    if (CMP(det, 0.0f)) { 
        return mat2(); 
    }
    mat2 result;
    float i_det = 1.0f / det;     //To avoid excessive division
    result._11 =  mat._22 * i_det;//Do reciprocal multiplication
    result._12 = -mat._12 * i_det;
    result._21 = -mat._21 * i_det;
    result._22 =  mat._11 * i_det;
    return result;
}

Expanding 4 X 4 matrix multiplication would take almost two pages of text; instead of including it here, I've gone ahead and included it in the downloadable code for this book.