0
votes

Description: In my program I do have an object and when clicked on it 3 rotation axis will be drawn. By clicking on one of the axis and moving mouse around it is possible to rotate an object.

Problem: object is always rotating around local and not world axis which leads to undesired behaviour. To resolve the problem I tried this however it did not work either.

Code: When I am loading the object I rotate it such that it will face the camera.

    m_phantomRotationMatrix = glm::rotate(m_phantomRotationMatrix, -90 * glm::pi<float>() / 180.0f, glm::vec3(1.0f, 0.0f, 0.0f));
    m_phantomRotationMatrix = glm::rotate(m_phantomRotationMatrix, 90 * glm::pi<float>() / 180.0f, glm::vec3(0.0f, 0.0f, 1.0f));

Then in an event handler for mouse movement I am performing further rotations if mouse is moved

        case 5: // X rotation axis
        {
            GLfloat xCurrentPosition = wxGetMousePosition().x;
            GLfloat yCurrentPosition = wxGetMousePosition().y;

            m_phantomRotationMatrix = glm::rotate(m_phantomRotationMatrix, (xCurrentPosition - m_xLastPosition) * glm::pi<float>() / 180.0f, glm::vec3(1.0f, 0.0f, 0.0f));

            m_xLastPosition = xCurrentPosition;
            m_yLastPosition = yCurrentPosition;
            break;
        }
        case 6: // Y rotation axis
        {
            GLfloat xCurrentPosition = wxGetMousePosition().x;
            GLfloat yCurrentPosition = wxGetMousePosition().y;

            m_phantomRotationMatrix = glm::rotate(m_phantomRotationMatrix, (yCurrentPosition - m_yLastPosition) * glm::pi<float>() / 180.0f, glm::vec3(0.0f, 1.0f, 0.0f));

            m_xLastPosition = xCurrentPosition;
            m_yLastPosition = yCurrentPosition;
            break;
        }
        case 7: // Z rotation axis
        {
            GLfloat xCurrentPosition = wxGetMousePosition().x;
            GLfloat yCurrentPosition = wxGetMousePosition().y;

            m_phantomRotationMatrix = glm::rotate(m_phantomRotationMatrix, (xCurrentPosition - m_xLastPosition) * glm::pi<float>() / 180.0f, glm::vec3(0.0f, 0.0f, 1.0f));

            m_xLastPosition = xCurrentPosition;
            m_yLastPosition = yCurrentPosition;
            break;
        }

main loop

void MyGLCanvas::draw(wxDC& dc)
{
    wxGLCanvas::SetCurrent(*m_glContext);
    glEnable(GL_MULTISAMPLE);
    glViewport(0, 0, m_windowWidth, m_windowHeight);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_STENCIL_TEST);
    glClearDepth(1.0f);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glDepthFunc(GL_LEQUAL);

    m_rotationAngleAroundPhantom++;
    glm::mat4 phantomModel, view, projection;
    phantomModel = glm::translate(phantomModel, m_phantomPosition);
    view = m_fpsCamera->getViewMatrix();
    projection = m_fpsCamera->getProjectionMatrix(m_windowWidth, m_windowHeight);
    m_color = glm::vec4(0.310f, 0.747f, 0.185f, 1.0f);
    glm::vec3 lightPos = glm::vec3(0.0f, 1.0f, 0.0f);
    glm::vec3 lightColor = glm::vec3(1.0f, 1.0f, 1.0f);

    ShaderProgram shaderProgram;
    shaderProgram.loadShaders("Shaders/phantom.vert", "Shaders/phantom.frag");

    glClearStencil(0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    shaderProgram.use();
    shaderProgram.setUniform("phantomRotationMatrix", m_phantomRotationMatrix);
    shaderProgram.setUniform("model", phantomModel);
    shaderProgram.setUniform("view", view);
    shaderProgram.setUniform("projection", projection);
    shaderProgram.setUniform("color", m_color);
    shaderProgram.setUniform("lightColor", lightColor);
    shaderProgram.setUniform("lightPos", m_fpsCamera->getPosition());
    shaderProgram.setUniform("cameraPos", m_fpsCamera->getPosition());

    glStencilMask(0xFF); // Write to stencil buffer
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
    glStencilFunc(GL_ALWAYS, 0, 0xFF);  // Set any stencil to 0

    glStencilFunc(GL_ALWAYS, 1, 0xFF); // Set any stencil to object ID
    m_pantomMesh->draw();
    glStencilFunc(GL_ALWAYS, 0, 0xFF);  // Set any stencil to 0
    shaderProgram.deleteProgram();

    if (phantomIsSelected && leftMouseClicked)
    {
        drawMovementAxes(phantomModel, view, projection);
    }

    if (phantomIsSelected && rightMouseClicked)
    {
        drawRotationAxes(phantomModel, view, projection);
    }

    glFlush();
    wxGLCanvas::SwapBuffers();
}

Vertex shader

#version 330 core

layout (location = 0) in vec3 pos;
layout (location = 1) in vec3 normal;
out vec4 vert_color;
out vec3 Normal;
out vec3 FragPos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 phantomRotationMatrix;
uniform vec4 color;

void main()
{
    vert_color = color;
    gl_Position = projection * view * model * phantomRotationMatrix * vec4(pos.x, pos.y, pos.z, 1.0);
    FragPos = vec3(model * phantomRotationMatrix * vec4(pos, 1.0));
    Normal = vec3(transpose(inverse(phantomRotationMatrix)) * vec4(normal, 0.0));
}
1

1 Answers

3
votes

You have your model view matrix (actually, it's in your shader) but you can compute it exactly the same in your CPU. You just need to multiply the invert of your rotation matrix with the model matrix to get the rotation in object space and then multiply/apply it to your object.

If I understand your code correctly, you are more or less doing this:

   World = View * Model * RotationMatrix * Object

Then, RotationMatrix applies to Object. If I understand your need, you want:

   World = View * WorldRotationMatrix * Model * Object

Then you just need to solve the matrix equation so that Model * RotationMatrix2 = WorldRotationMatrix * Model.

Thus, if A * B = T, A-1*A * B = A-1*T => B = A-1 * T

RotationMatrix2 = Model-1 * WorldRotationMatrix * Model

In my notation above, -1 stands for invert of the matrix.

Please have a look here