Search code examples
c++glm-math

Rotating a shape to anywhere between 1 and 2 radians resets its rotation


I'm currently using GLM to transform shapes in OpenGL. However, when the rotation of the shape is between 1 and 2 radians, the values of the matrix that represent rotation are set back to how they would be in an identity matrix. I'm outputting the model matrix to the console currently which helped find out the exact moment it turned back to 0 radians of rotation. Here is that:

1 Sorry if it's hard to understand, I've tried to annotate it because of how annoying it is to look at otherwise. Here's a link directly to the image if it is needed.

The first value on each line in the console is the rotation as a single value, in radians. Then, the model matrix of the shape is output.

Uploading a video of it is annoying to do but I'm sure you can visualise it - it's just a shape rotating normally for a while until that rotation hits one radian, at which point it gets reset to normal rotation. Then, when it reaches two radians, it goes back to normal as if there was never a problem.

Here's the code related to shape transformation:

// NOTE: the variables 'active_translation, active_rotation, and active_scaling' are the values the user gives to translate, rotate, and scale the shape
// In this case, 'active_rotation' is equal to ~0.02 (1 degree in radians) every frame

void defshape::apply_transformations() {
    // Create an identity matrix to store the applied transformations
    glm::mat4 applied_transformation = glm::mat4(1.0f);

    // Add the active translation to the stored transformations variable
    applied_transformation = glm::translate(applied_transformation, active_translation);

    // Apply the rotation to the mat4. For the sake of this example, I've only showed the Z axis line to simplify it as it's the only one being affected.
    applied_transformation = glm::rotate(applied_transformation, active_rotation.z, glm::vec3(0, 0, 1));

    // Add the active scale to the stored transformations variable
    applied_transformation = glm::scale(applied_transformation, active_scaling);

    // Apply these changes to the renderer by setting its model matrix and then updating it
    renderer_handle->model_matrix = applied_transformation;
    renderer_handle->update_renderer();

    // Reset the translation of the model matrix back to 0
    // This step ensures that the object rotates around its local origin, rather than the world space origin
    applied_transformation = glm::translate(applied_transformation, glm::vec3(0.0f));

    // Then apply this change to the renderer's model matrix
    renderer_handle->model_matrix = applied_transformation;
    renderer_handle->update_renderer();
}

Could this be related to GLM, or is there something wrong with my code?


Solution

  • Solved - the issue was related to a block of code specific to my project, which was likely why it is so unique.


    Specifically, I made a mistake related to what axes to affect when rotating via glm. The way I coded it the first time was as follows:

    // Variable to store the affected rotation axes
    glm::vec3 _active_rotation_axes = glm::vec3(0, 0, 0);
    
    // Get the affected axes for rotation
    // 'active_rotation' stores the rotation values for each axis
    _active_rotation_axes.x = (active_rotation.x != 0) ? 1 : 0;
    _active_rotation_axes.y = (active_rotation.y != 0) ? 1 : 0;
    _active_rotation_axes.z = (active_rotation.z != 0) ? 1 : 0;
    
    // Keep in mind the above code is partly pseudocode, as I have simplified it heavily and typed it directly into the answer.
    

    The variable _active_rotation_axes was then used as such:

    if (_active_rotation_axes.x != 0) applied_transformation = glm::rotate(applied_transformation, active_rotation.x, glm::vec3(_active_rotation_axes.x, 0, 0));
    if (_active_rotation_axes.y != 0) applied_transformation = glm::rotate(applied_transformation, active_rotation.y, glm::vec3(0, _active_rotation_axes.y, 0));
    if (_active_rotation_axes.z != 0) applied_transformation = glm::rotate(applied_transformation, active_rotation.z, glm::vec3(0, 0, _active_rotation_axes.z));
    

    This caused the issue I was experiencing, although I still don't know exactly why.

    Regardless, all I had to do in the end was remove the first code block, and change the second code block to the following, which checks active_rotation directly instead of the now non-existent variable _active_rotation_axes:

    if (active_rotation.x != 0) applied_transformation = glm::rotate(applied_transformation, active_rotation.x, glm::vec3(1, 0, 0));
    if (active_rotation.y != 0) applied_transformation = glm::rotate(applied_transformation, active_rotation.y, glm::vec3(0, 1, 0));
    if (active_rotation.z != 0) applied_transformation = glm::rotate(applied_transformation, active_rotation.z, glm::vec3(0, 0, 1));
    

    Really, I should have done it this way from the start as it is significantly more efficient and simple.