Affine Decomposition
All that's left to do is to implement the actual AffineDecompose
function. This page is mostly just a code-dump of how to put everything together. Let's start with the structures and function signatures of what we have already written. The only decomposition method that isn't needed here is QRDecompositon
, because it is only used as a helper function for SpectralDecompositon
.
struct FactorTranslationResult { Matrix T; // Translation Matrix X; // Linear transformation } struct PolarDecompResult { Matrix Q; // Q is a rotation, or the negative of a rotation Matrix S; // Scale and skew matrix } struct FactorRotationResult { Matrix F; // Positive or negative identity (flip if negative) Matrix R; // Rotation matrix } struct SpectralDecompositionResult { Matrix U; // Each basis vector is an eigenvector Matrix K; // Contains eigenvalues on main diagonal Matrix Ut; // Transpose of U } struct SpectralAdjustmentResult { Matrix U; // Each basis vector is an eigenvector Matrix K; // Contains eigenvalues on main diagonal Matrix Ut; // Transpose of U } FactorTranslationResult FactorTranslation(Matrix M); PolarDecompResult PolarDecomposition(Matrix X); FactorRotationResult FactorRotation(Matrix Q); SpectralDecompositionResult SpectralDecomposition(Matrix S); SpectralAdjustmentResult SpectralDecompositonAdjustment(SpectralDecompositionResult input)
Having already written all of the above functions, implementing AffineDecomposition
becomes a matter of calling the helper functions in the appropriate order, like so:
struct AffineDecompositionResult { Matrix T; // Holds translation of the matrix Matrix F; // Flip data (positive or negative identity) Matrix R; // Holds rotation of the matrix Matrix U; // Holds eigenvectors of the matrix Matrix K; // Holds eigenvalues (scale) of the matrix Matrix Ut;// Transpose of U } AffineDecompositionResult AffineDecomposition(Matrix M) { FactorTranslationResult factorTranslation = FactorTranslation(M); PolarDecompResult polarDecomposition = PolarDecomposition(factorTranslation.X); FactorRotationResult factorRotation = FactorRotation(polarDecomposition.Q); SpectralDecompositionResult spectralDecomp = SpectralDecomposition(factorRotation.R); SpectralAdjustmentResult spectralAdjustment = SpectralDecompositonAdjustment(spectralDecomp); AffineDecompositionResult result; result.T = factorTranslation.T; result.F = factorRotation.F; result.R = factorRotation.R; result.U = spectralAdjustment.U; result.K = spectralAdjustment.K; result.Ut = spectralAdjustment.Ut; return result; }
We might want to re-format the output to match shoemake's reference code a bit more. For the most part this is just a matter of converting some matrices to quaternions, like so:
struct ShoemakeResult { Vector3 T; // Translation float F; // Sign of determinant Quaternion R; // Rotation (q in shoemake's code) Quaternion U; //Stretch matrix Vector3 K; // Scale info } ShoemakeResult ConvertResultToShoemakeFormat(AffineDecompositionResult affine) { ShoemakeResult result; result.T = Vector3(affine.T[12], affine.T[13], affine.T[14]); result.F = affine.F[0]; result.R = ToQuaternion(affine.R); result.U = ToQuaternion(affine.U); result.K = Vector3(affine.K[0], affine.K[5], affine.K[10]); return result; }