Quaternion Camera Rotation

Started by
6 comments, last by Zakwayda 14 years, 2 months ago
Basic quaternion camera question. Using Cpp / DirectX9 and attempting a 6DOF camera. Each time I move the mouse in large circles the camera rolls, even though the mouse movement is set to only effect yaw/pitching. Im not worried about moving the camera at this stage. I've seen this question before with no answer, so does this mean im doing something fundamentally wrong? Heres the now exteremly stripped down source.


//rotate function.
void cameraQuat::rotate( float yawDegrees, float pitchDegrees, float rollDegrees)
{
    float heading = D3DXToRadian(yawDegrees);
    float pitch = D3DXToRadian(pitchDegrees);
    float roll = D3DXToRadian(rollDegrees);


    D3DXQUATERNION rot;
    //calculate quaternion rotation
    D3DXQuaternionRotationYawPitchRoll(&rot, heading, pitch, roll);
    //apply rotation to our orientation quaternion
    D3DXQuaternionMultiply(&m_orientationQuat, &m_orientationQuat, &rot);
}



void cameraQuat::updateViewMatrix()
{
    // Reconstruct the view matrix.
    D3DXQuaternionNormalize(&m_orientationQuat, &m_orientationQuat);
    D3DXMatrixRotationQuaternion(&m_viewMatrix, &m_orientationQuat);

    D3DXMatrixInverse(&m_viewMatrix, NULL, &m_viewMatrix);
}


I've tried this multiple different ways including separately by pitch,yaw and roll but I get the same result. I need to some how make sure the axis are orthogonal in the quaternion?
-RJ
Advertisement
If the effect is what I think it is, then yes it's doing exactly what you're asking it to. I can't explain it properly because I'm no math or graphics expert, but it's something like: you're multiplying a quat with another quat, but because it's a 6DOF camera, it treats your current rotation as the axis to rotate around, which gives you what you're asking for, 6DOF. I'm getting the feeling 6DOF is not actually what you want. I find that I need to keep euler angles, clamp or wrap them to -360 : 360. I find wrapping seems to avoid gimbal lock, but your camera will be upside down at one stage if you go all the way. I'm pretty sure the same thing happens if you do it with matrices too.
Are your angles the change in the angles (which they should be)?

You might add D3DXQuaternionNormalize(..) around your multiplication. I couldn't find any docs that say that D3DXQuatYawPitchRoll returns a normalized quat, so it might not hurt to normalize that before the multiplication.

Also, there are no "axes" in a quaternion. A quaternion represents a rotation about a vector.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Quote:Original post by Buckeye
Are your angles the change in the angles (which they should be)?

You might add D3DXQuaternionNormalize(..) around your multiplication. I couldn't find any docs that say that D3DXQuatYawPitchRoll returns a normalized quat, so it might not hurt to normalize that before the multiplication.

Also, there are no "axes" in a quaternion. A quaternion represents a rotation about a vector.


An axis is a vector, therefore it is also a rotation around an axis.
As mentioned previously, the behavior you describe is the expected behavior for 6DOF motion; that is, accumulated local yaw and pitch will usually result in a perceived local roll. If this isn't the behavior you're after, then it may not actually be 6DOF motion that you're wanting. (As a side note, some games that have incorporated 6DOF motion have included an 'auto-leveling' feature to counteract this effect.)

Also, I'm not entirely sure that you're performing your quaternion multiplication in the right order (although that may not have anything to do with the problem you're describing).
Track your rotation angles internally, on rotate calls dont build the quaternion and combine with the old, simply sum the angles and clamp to 360.
Then in update build pitch yaw and roll quaternions

pitch.FromAxisAngle(vec3(1, 0, 0), pitchAngleSum);
yaw.FromAxisAngle(vec3(0, 1, 0), yawAngleSum);

quaternion tmp = yaw * pitch;

zaxis = tmp * vec3(0, 0, 1);
roll.FromAxisAngle(zaxis, rollAngleSum);

quaternion current = roll * tmp; // store this calc on update only

build your view matrix from "current"
Thanks for the quick replies.
The angle passed is indeed the change coming from mouse movement.
I've also tried normalising at various stages and it doesnt make much of a difference.

Im looking to build a camera class capable of switching between a spectator mode (unrestricted?) 3rd person/chase and 1st person.
I assumed that once i got a fully functioning 6dof camera, the rest could be done from just restricting certain axis rotations and setting positions?

jyk -> do you have any info on how to implement an auto-leveling function? I have thrown together a lookat that converts the oreintation quaterion to matrix and takes out the look. Then calcs the other axis from that and builds a view matrix. This sort of works but im not sure its the right way of doing it.

Havent tried NumberXaero's suggestion yet, once i get my head around it i'll give it a whirl.
-RJ
Quote:Im looking to build a camera class capable of switching between a spectator mode (unrestricted?) 3rd person/chase and 1st person.
I assumed that once i got a fully functioning 6dof camera, the rest could be done from just restricting certain axis rotations and setting positions?
That's probably not the way I'd do it, just because the requirements of the types of cameras you mention are different enough (IMO) that trying to implement them all in terms of 6DOF motion seems a bit artificial. It might work fine though (I've never tried doing it that way myself).
Quote:do you have any info on how to implement an auto-leveling function? I have thrown together a lookat that converts the oreintation quaterion to matrix and takes out the look. Then calcs the other axis from that and builds a view matrix. This sort of works but im not sure its the right way of doing it.
The way I would do it is to compute an axis-angle rotation that will align the up vector of your object with the world up vector, and then apply it to your object's orientation. You can probably find info on how to do this in the forum archives if you search for e.g. 'align with terrain', 'align with up', or 'align with axis' (there have been quite a few threads on the topic).

This topic is closed to new replies.

Advertisement