1
\$\begingroup\$

I'm having a couple of problems while rotating an object every frame with GLM.

First problem
I'm trying to rotate the object with a small increase using quaternion multiplication.

glm::quat deltaQuat = glm::qua(0.001f, glm::vec3(0.0f, 1.0f, 0.0f));
object.SetWorldRotation(object.GetWorldRotation() * deltaQuat);

The result of this code is that the rotation switches back and forward with its inverse each frame, plus the small delta.

Flickering Rotation

Full framerate video here, and the logs I get:

Object world rotation: quat(1.000000, {0.000000, 0.000000, 0.000000})  
Object world rotation: quat(0.001000, {0.000000, 1.000000, 0.000000})   
Object world rotation: quat(-0.999999, {0.000000, 0.002000, 0.000000})  
Object world rotation: quat(-0.003000, {0.000000, -0.999997, 0.000000})  
Object world rotation: quat(0.999994, {0.000000, -0.004000, 0.000000})  
Object world rotation: quat(0.005000, {0.000000, 0.999990, 0.000000})  
Object world rotation: quat(-0.999985, {0.000000, 0.006000, 0.000000})  
Object world rotation: quat(-0.007000, {0.000000, -0.999979, 0.000000})  
Object world rotation: quat(0.999972, {0.000000, -0.008000, 0.000000})  
Object world rotation: quat(0.009000, {0.000000, 0.999964, 0.000000})  
Object world rotation: quat(-0.999955, {0.000000, 0.010000, 0.000000})   
Object world rotation: quat(-0.011000, {0.000000, -0.999945, 0.000000})  
Object world rotation: quat(0.999934, {0.000000, -0.012000, 0.000000})  
Object world rotation: quat(0.013000, {0.000000, 0.999922, 0.000000})   
Object world rotation: quat(-0.999909, {0.000000, 0.014000, 0.000000})  
Object world rotation: quat(-0.015000, {0.000000, -0.999895, 0.000000})  
Object world rotation: quat(0.999880, {0.000000, -0.015999, 0.000000})  
Object world rotation: quat(0.016999, {0.000000, 0.999864, 0.000000})   
Object world rotation: quat(-0.999847, {0.000000, 0.017999, 0.000000})  
Object world rotation: quat(-0.018999, {0.000000, -0.999829, 0.000000})  
Object world rotation: quat(0.999810, {0.000000, -0.019999, 0.000000})   

Second problem
Similarly to the first one, I'm trying to rotate the object with a small increase, this time using euler angles.

object.SetWorldEulerRotation(object.GetWorldEulerRotation() + glm::vec3(0.0f, 0.1f, 0.0f));

// where:

void SetWorldEulerRotation(glm::vec3 const& eulerRotation)
{
    SetWorldRotation(glm::quat(eulerRotation));
}

// and

glm::vec3 GetWorldEulerRotation() const
{
    return glm::eulerAngles(m_rotation); // m_rotation is a world quaternion
}

The result of this code is that the object's rotation does not go beyond 180º in either direction. It jitters between a little over that rotation and a little under it.

Rotate and Hesitate

Video here, and the logs I get:

Object world rotation: quat(0.707403, {0.000000, 0.706810, 0.000000})
Object world rotation: quat(0.703863, {-0.000000, 0.710336, -0.000000})
Object world rotation: quat(0.707403, {0.000000, 0.706810, 0.000000})
Object world rotation: quat(0.703863, {-0.000000, 0.710336, -0.000000})
Object world rotation: quat(0.707403, {0.000000, 0.706810, 0.000000})
Object world rotation: quat(0.703863, {-0.000000, 0.710336, -0.000000})
Object world rotation: quat(0.707403, {0.000000, 0.706810, 0.000000})
Object world rotation: quat(0.703863, {-0.000000, 0.710336, -0.000000})
Object world rotation: quat(0.707403, {0.000000, 0.706810, 0.000000})
Object world rotation: quat(0.703863, {-0.000000, 0.710336, -0.000000})
Object world rotation: quat(0.707403, {0.000000, 0.706810, 0.000000})
Object world rotation: quat(0.703863, {-0.000000, 0.710336, -0.000000})
Object world rotation: quat(0.707403, {0.000000, 0.706810, 0.000000})
Object world rotation: quat(0.703863, {-0.000000, 0.710336, -0.000000})
Object world rotation: quat(0.707403, {0.000000, 0.706810, 0.000000})
Object world rotation: quat(0.703863, {-0.000000, 0.710336, -0.000000})
Object world rotation: quat(0.707403, {0.000000, 0.706810, 0.000000})
Object world rotation: quat(0.703863, {-0.000000, 0.710336, -0.000000})
Object world rotation: quat(0.707403, {0.000000, 0.706810, 0.000000})
Object world rotation: quat(0.703863, {-0.000000, 0.710336, -0.000000})

Is there something I'm misunderstanding about quaternions/Euler angles, rotations in general or the GLM library?

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Your Euler angle example is running afoul of the same issue I explain in the context of Unity here - Euler angles have to have wrap-around points somewhere, so there's no guarantee the triplet you get back from a quaternion is the same one you gave it - somewhere in the 3 DOF domain it has to add a 360 degree rotation or two 180 degree flips to keep the angles in the defined output range, which can mean suddenly "increase y angle" can have the opposite meaning you expect. \$\endgroup\$
    – DMGregory
    Commented Apr 10, 2022 at 23:09
  • 1
    \$\begingroup\$ For the first problem, I'm having a devil of a time finding documentation for how glm::qua(float s, glm::vec3 v) interprets its arguments. It looks from your code like you're expecting s to be an angle and v to be a unit vector representing a rotation axis. But from the logs, it looks like we're seeing s as the real (w) component of the quaternion and v as the imaginary triplet. Do you get anything more sensible if you try something like glm::qua(glm::cos(angle/2), glm::vec3(0, glm::sin(angle/2), 0))? \$\endgroup\$
    – DMGregory
    Commented Apr 10, 2022 at 23:21
  • \$\begingroup\$ @DMGregory You're right! I assumed the API worked differently. That constructor is for setting the x,y,z,w values of the quaternion. Switching to glm::quat deltaQuat = glm::quat(glm::vec3(0.0f, 0.001f, 0.0f)); solves the first problem. \$\endgroup\$ Commented Apr 11, 2022 at 0:50
  • 1
    \$\begingroup\$ Want to post your solution as an Answer below? If you're waiting on a solution to the second problem, just store your own angle triplet rather than converting from quaternions to Euler angles to try to recover them. That way you have full visibility and control over where and how you wrap them. \$\endgroup\$
    – DMGregory
    Commented Apr 11, 2022 at 1:45
  • \$\begingroup\$ I shouldn't try to "solve" the second problem. As you explained, it's doing something that shouldn't be done when (only) using quaternion internally. \$\endgroup\$ Commented Apr 11, 2022 at 3:17

1 Answer 1

0
\$\begingroup\$

As discussed in the comments (special thanks to @DMGregory):

Problem 1:
The GLM API is a bit misleading and the constructor I was using actually sets the quaternion's x,y,z,w values instead of it being an "angle along this vector"-constructor.
Using the euler angles constructor works: glm::quat deltaQuat = glm::quat(glm::vec3(0.0f, 0.001f, 0.0f));.

Problem 2:
I've fallen to a common trap by rotating in euler angles when internally using quaternions. Basically, there are no guarantees in the continuity of the euler angles you get when converting from a quaternion. So adding a euler angle rotation on top of those will likely result in this type of behaviour. More info in this question.
I'd suggest simply sticking to quaternions for incremental rotations or, as Gregory said, you can store the euler angles internally as well instead of converting them from the quaternion.

\$\endgroup\$
1
  • \$\begingroup\$ Don't forget to mark this answer as "Accepted" it it worked for you. \$\endgroup\$
    – DMGregory
    Commented May 11, 2022 at 23:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .