Removing the roll from a quaternion:

Started by
12 comments, last by Einstone 16 years, 5 months ago
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.
Advertisement
I built a quat with arbitrary yaw, pitch, roll values. Then I used your method to calculate the yaw, pitch, roll from the quat. They don't come back to the original values. That means the method is wrong. I don't think converting a quat to yaw, pitch, roll angles is a easy and simple thing. If you do want to do that, it is better to convert the quat to a matrix then extract the angles from the matrix.
By the way, if you want to align your camera Y axis to the world's Y axis(I just guess that, because you didn't said the y axis is the one in world space),
I would sugguest you to build a new matrix. the new matrix z axis remain the same as the camera's z axis, by crosing world's y axis with camera's z axis, you get the x axis, then get the y axis by crossing the camera's z axis with the new x axis. I hope that would be the new camera matrix you want.
Use the quat to rotate the (1,0,0) vector, use that vector along with the up-vector to produce a new rotation matrix, then convert that matrix to a new quat.
Won't I get gimbol lock if I use matrices? Currently I'm calculating all my rotations using quats and only converting to a matrix in my update function right before I render.
Gimbal lock is issue related to Euler angles, not to Matrices nor quaternions. In other words - its more of a problem with construction of rotation rather than representation.
The way I do it is to create a lookat style view matrix and then convert that back into a quaternion. For more details see here.
http://www.dhpoware.com
So, are quaternions just compressed matrices? If so, I might be better off scrapping the rotation quats and just sticking with a matrix.

Also, if any use of eulers to compute a quat or a matrix will cause gimbal lock, does that mean using the RotationYawPitchRoll and RotationAxis methods will cause it as well? How would I get around that? Any angle I try to use to rotate my original matrix or quaternion would be a euler.
Although quaternion is another form of matirx, but since you want the aligning in y axix and there is no y axis information can be accessed directly in a quaternion, it may be better to do it in matrix way.
And what about those rotation functions (RotationYawPitchRoll and RotationAxis) I mentioned? Can those cause gimbol lock due to them accepting eulers as their arguments? I'm not sure if I mentioned, but even though I want the ability to remove the roll, I still want to be able to change it sometimes.
If you try to extract the yaw/pitch/roll angle values from a matrix, a gimbal lock can happen. For example, get two books, place them so they have the same orientation. Get the first book, rotate it clockwise 90 degrees around an axis pointing upward (yaw). Now rotate the book clockwise by 90 degrees around an axis pointing forward(pitch). Now rotate the book counterclockwise 90 degrees around an axis pointing upward (roll). Now the book's matrix's yaw = 90, pitch = 90, roll = -90. But if you just rotate the second book clockwise by 90 degrees around an axis point rightward (pitch), the second book's orientation is the same as the first book, this time the result matrix's yaw = 0, pitch = 90, roll = 0. As you can see, when you try to get the yaw/pitch/roll angle values from the result matrix, you have two sets of answers, which one would you choose? In the case you posted here, you can choose to remove the roll of -90 degrees or the roll of 0 degrees and the results are obviously different.

This topic is closed to new replies.

Advertisement