Monday, January 15, 2018

transformation - Do matrix manipulations for 3D graphics ever produce singular matrices?


A singular matrix is a matrix that cannot be inverted. The vecmath library, for example, throws a SingularMatrixException if you try to invert a singular matrix.


I think I understand what singular matrices are. But there are plenty of matrix operations that I don't understand, so I'm not sure what might produce one. Are singular matrices ever produced accidentally when manipulating 3D graphics transforms, the way gimbal lock can be? If so, are there any strategies for avoiding singular matrices, and/or what can you do about them if you encounter one?



Answer



The simplest way this can happen is if you shrink an object until its local scale in one or more axes is 0 (flattening it to a plane, line, or point). You can avoid this by disallowing scales below a certain magnitude on any axis.


(If your system allows hierarchical nesting of transforms, you'll also have to watch out that no chain of parented matrices result in a scale below this threshold, even if each scale individually checks out. It won't reach zero, but it might get close enough to make your matrix inversion code behave badly)


The subtler way this can happen is through rounding errors.



A common first attempt at an object renderer or scene graph will store object transforms as a matrix, and perform each change by overwriting the matrix with its concatenation by some incremental transformation (eg. rotating n degrees per frame). In psuedocode:


Rotate(object, angle, axis)
{
object.matrix = CreateRotationMatrix(angle, axis) * object.matrix;
}

Because the matrix is used in the calculation of its own successor, any errors in the current matrix propagate into the next, accumulating and snowballing over time. This can cause the scale or orthogonality of the matrix to become distorted (the object can squash, stretch, or shear unintentionally).


In extreme cases the scale can get rounded to 0 along one axis, or one axis can become coplanar with the other two, resulting in a singular matrix.


There are two main ways to keep these rounding errors from accumulating:





  1. Store the transformation in terms of its constituent parts (translation vector, rotation quaternion or angles, local scale triple). When any aspect changes, the matrix is recomputed from scratch using these validated inputs. This guarantees it is orthogonal and (if you disallow near-0 values in your scale triplet) invertible, and prevents repeated changes to one parameter (eg. rotation) from causing drift in another (eg. scale). This also lets you distinguish rotation by 180 degrees from reflection along two axes, in case that's useful for your transform UI. ;)




  2. Apply error correction after each step to prevent runaway error accumulation. To correct for wandering axes, orthogonalize the resulting matrix. To correct scale errors you'll still need a reference uniform scale value or local scale triplet stored separately, so you can scale each column/row (depending on your multiplication convention) to the right length.




Both of these assume you never want to deliberately introduce shear into your transformation matrices, though you could store additional shear information to maintain a non-orthogonal matrix.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...