I know I promised not to be so dull in future, but enough people seem to share my curiosity about what goes on inside DirectX matrices for it to be worth publishing the details of DX's other pre-defined matrix form, the XYZ matrix.
So, if I create rotation matrices for a rotation about X by x radians (and call it Rx), about Y by y, and about Z by z, and multiply them together Rx * Ry * Rz, I wind up with the following:
Cos(y).Cos(z) |
Cos(y).Sin(z) |
-Sin(y) |
Sin(x).Sin(y).Cos(z) + Cos(x).-Sin(z) |
Sin(x).Sin(y).Sin(z) + Cos(x).Cos(z) |
Sin(x).Cos(y) |
Cos(x).Sin(y).Cos(z) + Sin(x).Sin(z) |
Cos(x).Sin(y).Sin(z) + -Sin(x).Cos(z) |
Cos(x).Cos(y) |
....and if, as before, I want to look at a matrix and work out what single set of x, y, z rotations would get me to the same orientation, the code below will do the trick.
Like the roll-pitch-yaw case, the numbers go loopy when the rotation about Y is an odd multiple of ninety degrees, so there's a crude test in there to spot that happening and go to a plan B.
(Same disqualifier too - if you're concerned for numerical stability and being able to guarantee getting the same matrix back that you started with, there is a more reliable route which avoids the setting of the angle about z to being zero ["gimbal lock"] and again I'd point you to The Right Way to Calculate Stuff by Don Hatch).
static public void DecomposeXYZRotationMatrix(Matrix mx, out double rx, out double ry, out double rz){ ry = Math.Asin(-mx.M13); double threshold = 0.001; if(Math.Cos(ry) > threshold) { rx = Math.Atan2(mx.M23, mx.M33); rz = Math.Atan2(mx.M12, mx.M11); } else { rx = Math.Atan2(mx.M21, mx.M22); rz = 0.0; }}
My next blog will be about Managed DirectX and the Effects framework, so if you think that's dull too, apologies!!
|