Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

Combining quaternions:

Started by CodeReaver Aug 7, 2007 at 1:55 PM 2 replies 2.4k views
Original Post
CodeReaver
CodeReaver
I'm using quaternions to rotate my camera around an object. I want to combine the cameras current rotation with an amount of extra rotation when the mouse moves. Any explanation I can find just says to multiply the quaternion for the current rotation with a quaterion for the angle to rotate it by. However if I try to change the pitch when the camera has already been rotated to the side of my object, I get the effect of the roll changing instead. How can I get the camera to rotate relative to it's current position instead of it's starting position? I want it to behave like I'd multiplied the current rotation matrix by another matrix, except avoiding gimbal lock since I'm using quaternions. Here's the code I'm using:
        public void RotateVertical(float fAngle)
        {
            m_xRotation *= Quaternion.RotationYawPitchRoll(0.0f, fAngle, 0.0f);
        }

        public void RotateHorizontal(float fAngle)
        {
            m_xRotation *= Quaternion.RotationYawPitchRoll(fAngle, 0.0f, 0.0f);
        }
Where m_xRotation is a quaternion that my camera position gets rotated by before being passed into Matrix.LookAtLH. I know this has probably been asked many times before, but the answer is usually "use quaternions" which I already am, "multiply the quaternions" like I am or an explanation of how to convert an Euler to a Quaternion, which the RotationYawPitchRoll method already does.
remigius
remigius
I think the behavior you describe (pitch vs roll) isn't really gimball lock, but rather expected behavior when using rotations based on the coordinate axes (ie yaw, pitch and roll). RotateVertical and RotateHorizontal are ambiguous since in your opinion they should rotate the object around its local (post-rotated) axes, but since you're still using YawPitchRoll they'll be rotated around the absolute coordinate axes. So quaternions aren't going to magically get you out of this one.

The most straightforward way to implement these functions with the behavior you want is probably to find the local axes and apply the rotations around these. It shouldn't really matter whether you use quaternions or matrices for this. So for example (pseudocode, will not compile):

public void RotateVertical(float fAngle){    // our base axis for 'vertical' rotation, when the object isn't rotated    Vector3 baseUp = new Vector3(0, 1, 0);      // find out where this axis is pointing now the object is rotated    Vector3 currentUp = Vector3.Transform(baseUp, m_xRotation);        m_xRotation *= Quaternion.RotationFromAxisAngle(currentUp, fAngle);}


Hope this helps :)
CodeReaver
CodeReaver
So, would currentUp be the same one I pass into Matrix.LookAtLH when I'm creating the matrix or is it a seperate copy? I assume I'd just swap baseUp for a baseRight to make the RotateHorizontal function.
remigius
remigius
Quote:
I assume I'd just swap baseUp for a baseRight to make the RotateHorizontal function.


That depends, but basically yes. This highlights the problem with the function names you picked. Horizontal or vertical rotations don't have a clear meaning, so functions like RotateAroundLocalX, RotateAroundLocalY, RotateAroundLocalZ convey what they do a lot better.


Quote:
So, would currentUp be the same one I pass into Matrix.LookAtLH when I'm creating the matrix or is it a seperate copy?


I'm not sure what you mean by 'a seperate copy', but just sticking it into the regular Matrix.LookAtLH(pos, target, up) most likely won't have the desired effect. These functions work out well to compute a rotation matrix which can be used to construct a world matrix for your object. If you just want to rotate your object, you should probably just use this rotation matrix as your world matrix.

If you're sure you want to rotate the camera around the object, you should take the vector from your target to the camera's base position (baseCamPos - targetPos) and transform that using the rotation matrix. With a bit more work (targetPos - rotatedCamPos, I think), this will give you the new camera position which your can use with Matrix.LookAtLH. Rotating a camera around an object is a bit of an art though. If you're feeling bold, you may want to look into arcballs for the most common way to go about this. There's a sample implementation in the managed DXUT framework that's used for the samples in the DirectX SDK.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.