I needed a way of lining my camera back up with the Y axis (ie stripping out the roll) when changing between two different modes and the only way I could find was to convert the quat to a yaw, pitch and roll and back to a quat with just the pitch and yaw. I found these two formulas:
//tan(yaw) = 2*(q0*q3 - q1*q2) / (q0*q0 + q1*q1 - q2*q2 - q3*q3)
//sin(pitch) = 2*(q0*q2 + q1*q3)
//tan(roll) = 2*(q0*q1 - q2*q3) / (q0*q0 - q1*q1 - q2*q2 + q3*q3)
//dx = 2.0 * (x * z - w * y);
//dy = 2.0 * (y * z + w * x);
//dz = 1.0 - 2.0 * (x * x + y * y);
There wasn't an explanation of what dx, dy and dz were in that second one. They said it was equivilant to the first in the discussion and that it worked when they tried it.
However they don't seem to work properly. Calling this function just seems to alternate between two or three different positions. Am I doing this right?
public void RemoveRoll()
{
float fQ0 = m_xRotation.X;
float fQ1 = m_xRotation.Y;
float fQ2 = m_xRotation.Z;
float fQ3 = m_xRotation.W;
float fYaw = (float)Math.Atan((double)(2.0f*(fQ0*fQ3-fQ1*fQ2)/(fQ0*fQ0+fQ1*fQ1-fQ2*fQ2-fQ3*fQ3)));
float fPitch = (float)Math.Asin((double)(2.0f*(fQ0*fQ2+fQ1*fQ3)));
float fRoll = (float)Math.Atan((double)(2.0f*(fQ0*fQ1-fQ2*fQ3)/(fQ0*fQ0-fQ1*fQ1-fQ2*fQ2+fQ3*fQ3)));
m_xRotation = Quaternion.RotationYawPitchRoll(fYaw, fPitch, 0.0f);
m_xRotation.Normalize();
}
I tried making fQ0 = W, fQ1 = X, fQ2 = Y and fQ3 = Z in case that was what was wrong, but I still get the same problem.