Search code examples
c++opengl3dquaternionsglm-math

Problem rotating with quaternions in OpenGL (GLM/C++)


I'm programming a game engine for educational purposes and I'm a bit stucked with rotations. The thing is that I have in the UI 3 squares to represent an object's orientation in Euler Angles, and from there I can change the values.

To change them, I call:

void TransformComponent::SetOrientation(glm::vec3 eulerAxAngles)
{
    glm::vec3 euler_inRadians = glm::radians(eulerAxAngles);

    glm::quat newRot;
    double cy = cos(euler_inRadians.y * 0.5);
    double sy = sin(euler_inRadians.y * 0.5);
    double cp = cos(euler_inRadians.x * 0.5);
    double sp = sin(euler_inRadians.x * 0.5);
    double cr = cos(euler_inRadians.z * 0.5);
    double sr = sin(euler_inRadians.z * 0.5);
    newRot.w = cy * cp * cr + sy * sp * sr;
    newRot.x = cy * cp * sr - sy * sp * cr;
    newRot.y = sy * cp * sr + cy * sp * cr;
    newRot.z = sy * cp * cr - cy * sp * sr;

    m_Orientation = newRot * m_Orientation;
    UpdateTransform();
}

m_Orientation is a quaternion storing the object's current orientation.I know all that conversion from eulers to quaternion could be handled by glm but I changed to this to debug what was happening...

Then, UpdateTransform() does the next:

void TransformComponent::UpdateTransform()
{
    m_TransformationMatrix = glm::translate(glm::mat4(1.0f), m_Translation) *
        glm::scale(glm::mat4(1.0f), m_Scale) * glm::mat4_cast(m_Orientation);


    //Set euler angles
    m_Rotation_InEulerAngles = glm::eulerAngles(m_Orientation);
}

And m_Rotation_InEulerAngles is the vec3 that can be seen from the UI to change the angles of the object's orientation.

The problem is that when I try to modify one of the 3 euler angles, the 3 are modified, I mean, if I modify the Roll angle (around Z axis), it modifies also Pitch and Yaw (not with the Z value, it's like it sets another orientation to the object).

In this gif is shown how the translation/scaling are well performed but rotation (here is seen in radians by now), is not well performed, it changes the whole orientation, not just the one in the axis I want:

https://gfycat.com/plushhonestargentineruddyduck

Does somebody sees what I'm I doing wrong?


Solution

  • Changing, or setting orientation, is not the same as rotating:

    To set your orientation, you want to do it like this:

    void setOrientation(glm::vec3 eular)
    {
        m_Orientation = glm::quat(eular); // very simple
    }
    
    void setRotation(glm::vec3 eular)
    {
        m_Rotation = glm::quat(eular); // very simple
    }
    

    To rotate, we want to integrate the rotation quaternion, using SLERP:

    void update(float deltaTimeS)
    {
        glm::quat ident(1.0f);
        glm::quat rotation = glm::mix(ident, m_Rotation, deltaTimeS);
        m_Orientation = rotation * m_Orientation;
    }
    

    And to get your rotation matrix:

    void setTransform()
    {
        m_RotationMatrix = glm::gtx::quaternion::toMat4(quaternion);
    }
    

    See here for more information on quaternion rotations.