1
\$\begingroup\$

I'm trying to get my camera implemented with a glm::quat used to store the rotation.

However, whenever I do circles with the mouse, the camera rotates along the axis I am viewing (i.e. I think it's called the target axis). For example, if I rotated the mouse in a clockwise fashion, the camera rotates clockwise around the axis.

I initialize my quaternion like so:

void Camera::initialize()
{
    orientationQuaternion_ = glm::quat();
    orientationQuaternion_ = glm::normalize(orientationQuaternion_);
}

I rotate like so:

void Camera::rotate(const glm::detail::float32& degrees, const glm::vec3& axis)
{
    orientationQuaternion_ = orientationQuaternion_ * glm::normalize(glm::angleAxis(degrees, axis));
}

and I set the viewMatrix like so:

void Camera::render()
{
    glm::quat temp = glm::conjugate(orientationQuaternion_);

    viewMatrix_ = glm::mat4_cast(temp);
    viewMatrix_ = glm::translate(viewMatrix_, glm::vec3(-pos_.x, -pos_.y, -pos_.z));
}

The only axis' I actually try to rotate are the X and Y axis (i.e. (1,0,0) and (0,1,0)).

Here is a video of what is going on: Camera weird rotation

Anyone have any idea why I see my camera rotating around the target axis?

EDIT

I added some debug output for the values that are getting calculated.

First entry is the initialized quaternion, calculated with

std::cout << "quat initialized: " << glm::to_string(glm::eulerAngles(orientationQuaternion_)) << std::endl;

Then I output (in the rotate method) the before and after quaternion, and also the rotation. I output them with:

void Camera::rotate(const glm::detail::float32& degrees, const glm::vec3& axis)
{
    std::cout << "orientation before: " << glm::to_string( glm::eulerAngles(orientationQuaternion_) ) << std::endl;

    orientationQuaternion_ = glm::normalize(orientationQuaternion_) * glm::normalize(glm::angleAxis(degrees, glm::normalize(axis)));
    orientationQuaternion_ = glm::normalize(orientationQuaternion_);

    std::cout << "rotation: " << glm::to_string( glm::eulerAngles(glm::angleAxis(degrees, axis)) ) << std::endl;
    std::cout << "orientation after: " << glm::to_string( glm::eulerAngles(orientationQuaternion_) ) << std::endl;
}

Here's the output data:

quat initialized: fvec3(0.000000, -0.000000, 0.000000)

orientation before: fvec3(0.000000, -0.000000, 0.000000)
rotation: fvec3(-0.363636, -0.000000, 0.000000)
orientation after: fvec3(-0.363636, 0.000000, 0.000000)

orientation before: fvec3(-0.363636, 0.000000, 0.000000)
rotation: fvec3(0.000000, -0.545454, 0.000000)
orientation after: fvec3(-0.363653, -0.545444, 0.003462)

orientation before: fvec3(-0.363653, -0.545444, 0.003462)
rotation: fvec3(-4.909091, -0.000000, 0.000000)
orientation after: fvec3(-5.272744, -0.545443, 0.003462)

orientation before: fvec3(-5.272744, -0.545443, 0.003462)
rotation: fvec3(0.000000, 5.272728, 0.000000)
orientation after: fvec3(-5.290381, 4.704929, -0.482044)

orientation before: fvec3(-5.290381, 4.704929, -0.482044)
rotation: fvec3(13.272726, -0.000000, 0.000000)
orientation after: fvec3(7.982345, 4.704931, -0.482044)

orientation before: fvec3(7.982345, 4.704931, -0.482044)
rotation: fvec3(0.000000, 6.909091, 0.000000)
orientation after: fvec3(8.120677, 11.546086, 0.494900)

orientation before: fvec3(8.120677, 11.546086, 0.494900)
rotation: fvec3(7.636363, -0.000000, 0.000000)
orientation after: fvec3(15.757041, 11.546085, 0.494900)

orientation before: fvec3(15.757041, 11.546085, 0.494900)
rotation: fvec3(0.000000, 10.181817, 0.000000)
orientation after: fvec3(16.596092, 21.327044, 3.448837)

orientation before: fvec3(16.596092, 21.327044, 3.448837)
rotation: fvec3(6.181818, -0.000000, 0.000000)
orientation after: fvec3(22.777910, 21.327044, 3.448836)

orientation before: fvec3(22.777910, 21.327044, 3.448836)
rotation: fvec3(0.000000, 12.000000, 0.000000)
orientation after: fvec3(25.255577, 32.297348, 8.913291)

orientation before: fvec3(25.255577, 32.297348, 8.913291)
rotation: fvec3(3.636364, -0.000000, 0.000000)
orientation after: fvec3(28.891941, 32.297352, 8.913290)

orientation before: fvec3(28.891941, 32.297352, 8.913290)
rotation: fvec3(0.000000, 12.727273, 0.000000)
orientation after: fvec3(34.057663, 43.175217, 17.306284)

orientation before: fvec3(34.057663, 43.175217, 17.306284)
rotation: fvec3(0.363636, -0.000000, 0.000000)
orientation after: fvec3(34.421299, 43.175220, 17.306288)

orientation before: fvec3(34.421299, 43.175220, 17.306288)
rotation: fvec3(0.000000, 5.636363, 0.000000)
orientation after: fvec3(37.799271, 47.732010, 22.041012)

orientation before: fvec3(37.799271, 47.732010, 22.041012)
rotation: fvec3(-0.909091, -0.000000, 0.000000)
orientation after: fvec3(36.890179, 47.732010, 22.041016)

orientation before: fvec3(36.890179, 47.732010, 22.041016)
rotation: fvec3(0.000000, 12.545454, 0.000000)
orientation after: fvec3(47.936203, 57.054291, 35.913132)

orientation before: fvec3(47.936203, 57.054291, 35.913132)
rotation: fvec3(-10.727273, -0.000000, 0.000000)
orientation after: fvec3(37.208916, 57.054287, 35.913124)

orientation before: fvec3(37.208916, 57.054287, 35.913124)
rotation: fvec3(0.000000, 2.000000, 0.000000)
orientation after: fvec3(39.175983, 58.626469, 38.236393)

orientation before: fvec3(39.175983, 58.626469, 38.236393)
rotation: fvec3(-4.909091, -0.000000, 0.000000)
orientation after: fvec3(34.266888, 58.626469, 38.236393)

orientation before: fvec3(34.266888, 58.626469, 38.236393)
rotation: fvec3(0.000000, 1.272727, 0.000000)
orientation after: fvec3(35.485283, 59.670666, 39.655521)

orientation before: fvec3(35.485283, 59.670666, 39.655521)
rotation: fvec3(-10.181816, -0.000000, 0.000000)
orientation after: fvec3(25.303461, 59.670673, 39.655521)

It almost looks like a rounding error? I'm not sure. I tried normalizing the quaternion during and after the calculation, but it didn't help...

EDIT - Solution

Changed the rotate(..) method to this:

void Camera::rotate(const glm::detail::float32& degrees, const glm::vec3& axis)
{
    if ( axis == glm::vec3(0.0f, 1.0f, 0.0f) )
        orientationQuaternion_ =  glm::normalize(glm::angleAxis(degrees, axis)) * orientationQuaternion_;
    else
        orientationQuaternion_ = orientationQuaternion_ * glm::normalize(glm::angleAxis(degrees, axis));
}

Still have some work to do here, but it seems to fix the problem from before.

\$\endgroup\$
  • 3
    \$\begingroup\$ Which basis are you using for your rotations? Are you rotating around the world's X axis or the camera's? Your camera (and every object with a transform) has its own local space axes, which will usually not be the same as the world axes. You usually want to rotate a camera horizontally around "world up" and vertically around "camera right". \$\endgroup\$ – Sean Middleditch Nov 6 '13 at 1:10
  • \$\begingroup\$ can you elaborate why are you taking the conjugate ? I wonder if you want inverse instead as conjugate != inverse. \$\endgroup\$ – concept3d Nov 6 '13 at 7:04
  • \$\begingroup\$ @concept3d The OP's probably using unit quats (otherwise it doesn't make sense to talk about rotations in the first place). \$\endgroup\$ – teodron Nov 6 '13 at 8:33
  • \$\begingroup\$ @Jarett: if you want your camera gizmo to behave as a rolling sphere, you should probably use this update equation for your orientation: orientationQuaternion_ = glm::normalize(glm::angleAxis(degrees, axis)) * orientationQuaternion_; \$\endgroup\$ – teodron Nov 6 '13 at 8:35
  • 1
    \$\begingroup\$ @concept3d for unit quaternions the conjugate is the same as the multiplicative inverse. The code is trying to create th view matrix by taking the inverse of the camera world matrix. Depending on your matrix multiplication order, swap the orientaion*transformation operands. \$\endgroup\$ – Maik Semder Nov 6 '13 at 8:40
2
\$\begingroup\$

Your camera (and every object with a transform) has its own local space axes, which will usually not be the same as the world axes. Transforming around the world-space axis will give a different result than transforming around a local-space axis. Cameras typically need to work with both.

You usually want to rotate a camera horizontally around "world up" and vertically around "camera right" in my experience.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.