Matrix Decomposition - Polar Decomposition

Started by
4 comments, last by Dirk Gregorius 12 years, 7 months ago
I have read this topic: http://www.gamedev.net/topic/375401-matrix-decomposition-non-uniform-scaling/ and used GPU Gems IV matrix decomposition.

I am usign matrix DX layout (left-handed, row vectors), so I transform it for GPU Gems layout (right handed, column vectors)

For conversion from LH -> RH, I multiply Z values (eg. 3rd col) in 3x3 submatrix by -1


LH To RH Matrix
Transpose Matrix

AffineParts parts
decomp_affine(Matrix, &parts)



Decomposition works for Translation (of course, its logic), scale seemsed to be correct to. But quaternion is wrong. XYZW parts have correct number values ins abs(X), but order and sign is wrong

For example:

Quaternion qt = :Quaternion(-0.75f, 0.2f, -0.1f, 1.0f);
qt.Normalize(); //(-0.59, 0.15, -0.078, 0.78)

world = Matrix4x4::Scaling(1, 2, 3) * Matrix4x4::RotationQuaternion(qt) * Matrix4x4::Translation(0, 0, -64);

Decompose()

and now quternion has values (-0.15, -0.59, 0.78, 0.078)



What am I doing wrong ?
Advertisement
Good morning :)

I implemented this algorithm myself yesterday. The polar decomposition doesn't care about handness. But if you are using row vectors like DirectX you want to decompose M = S * Q though (not M = Q * S). Another thing to watch out for is "negative" scale. If one or three elements of your scale vector are negative the rotation matrix contains a reflection (the determinant is negative). You need to factor further Q = (-I) * Q' and the negative identity matrix goes into S. In a real implementation you would use a matrix with say a11 = -1, a22 = a33 = 1. You only need to negate one row and one column. If two elements are negative this is basically a rotation and the decomposition will give you positive scales and a different rotation matrix. It basically moves the rotation into Q.

The algorithm for the polar decomposition is very easy. Essentially (without acceleration) it is a simple fixpoint iteration:

Mat3 X1 = M;
for ( say 32 iterations )
..Mat3 X2 = 0.5 * ( X1 + X1^-T); // Just add the matrix and its inverse transpose
..X1 = X2;

Q = X1;
S = M * Q^T

Here are two very good papers about the topic which I used as reference myself:
http://www.cs.wisc.edu/graphics/Courses/838-s2002/Papers/polar-decomp.pdf
http://eprints.ma.man.ac.uk/694/01/covered/MIMS_ep2007_9.pdf

I recommend to implement the algorithm yourself as in the second paper *with* the acceleration. It is working great for me and you usually have a result after 3-5 iterations. Your function for the decomposition should also return the determinant which you need for the inversion anyway. Then a user can decide if he wants to factor Q further.


HTH,
-Dirk
Thanks fo reply.. but implementation of function decomp_affine is taken from GPU Gems IV, so I think that should be correct. Output numbers seems correct to.. I just dont understand, why are they in incorrect order.
Do you have a link to the code or can you paste it here? I thought you were referening to K. Shoemakes implementation.
You don't need to transpose the input matrix, use S = M * QT.

If you use the Shoemake code the affine parts also contain the determinant f which give you the handness of the rotation
I used this code:
http://users.soe.ucsc.edu/~pang/160/f98/Gems/GemsIV/polar_decomp/Decompose.c
http://users.soe.ucsc.edu/~pang/160/f98/Gems/GemsIV/polar_decomp/Decompose.h

I transpose matrix because DX has row vectors, but Shoemaker expect column vectors.
We use row vectors as well and I don't transpose. The reason is that the polar decomposition is coordinate independent (see paper).

This topic is closed to new replies.

Advertisement