Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quaternion camera. How do I make it rotate correctly?

I have a 3D camera with its current rotation stored as a quaternion, and I'm having trouble rotating it correctly. I want the camera to rotate incrementally around its local axes based on mouse movement each frame (first-person-shooter-style), but the rotation is wrong. It kind of works, but the camera seems to "roll" around its forward axis when it shouldn't.

I update the rotation each frame with this function:

void Camera::rotate(const Quat& q)
{
    // m_rot is the current rotation
    m_rot = m_rot * q;
}

Here's my quaternion multiplication function:

Quat Quat::operator*(const Quat &rhs) const
{
    // quaternion elements in w,x,y,z order
    Vector4d res;

    res[0] = m_q[0]*rhs.m_q[0] - m_q[1]*rhs.m_q[1] -
             m_q[2]*rhs.m_q[2] - m_q[3]*rhs.m_q[3];
    res[1] = m_q[0]*rhs.m_q[1] + m_q[1]*rhs.m_q[0] +
             m_q[2]*rhs.m_q[3] - m_q[3]*rhs.m_q[2];
    res[2] = m_q[0]*rhs.m_q[2] - m_q[1]*rhs.m_q[3] +
             m_q[2]*rhs.m_q[0] + m_q[3]*rhs.m_q[1];
    res[3] = m_q[0]*rhs.m_q[3] + m_q[1]*rhs.m_q[2] -
             m_q[2]*rhs.m_q[1] + m_q[3]*rhs.m_q[0];

    return Quat(res);
}

Am I doing something wrong, or is this some kind of floating-point error thing?

like image 400
KTC Avatar asked Mar 25 '12 02:03

KTC


People also ask

How do you rotate with quaternion?

For rotation quaternions, the inverse equals the conjugate. So for rotation quaternions, q−1 = q* = ( q0, −q1, −q2, −q3 ). Inverting or conjugating a rotation quaternion has the effect of reversing the axis of rotation, which modifies it to rotate in the opposite direction from the original.

How do quaternion rotations work?

Quaternions are an alternate way to describe orientation or rotations in 3D space using an ordered set of four numbers. They have the ability to uniquely describe any three-dimensional rotation about an arbitrary axis and do not suffer from gimbal lock.


1 Answers

Figured out the problem. For a mouse-controled first-person camera like the one I'm going for, I want to rotate around the local x-axis to look up and down, but the global y-axis for looking side to side.

So this is correct for the x-axis:

m_rot = m_rot * q;

But I need to do this for the y-axis:

m_rot = d * m_rot;
like image 187
KTC Avatar answered Oct 23 '22 09:10

KTC