在模型矩阵上链接旋转

Chaining rotation on model matrix

我有一个小的 opengl 世界,我尝试用模型矩阵制作一个小立方体并围绕原点轴旋转它。我几乎把所有事情都做对了,但我的问题是,每当我尝试链接旋转时,即(一次在 x 轴上旋转,然后在不重置矩阵的情况下在 y 轴上旋转)我没有得到我想要的。我希望立方体在固定轴上旋转,但立方体在其自己的轴上旋转。我的意思是说我想使用原点的轴旋转但模型使用它自己的轴旋转,轴保持在原点但它有点随模型旋转。我以为我的相机在移动而不是模型,但是当我尝试使用多个盒子时它证明我的相机在它自己的位置上。我不知道如何进行正确的旋转。这是我所做的代码(一些代码来自 learnopengl.com):


x_Camera camera;

class XYZ_line
{
public:
    glm::vec3 xCol, yCol, zCol;
    std::vector<glm::vec3>m_Vertices;
    unsigned int VBO, VAO;
    GAME::Shader shader;
    glm::mat4 model;
    inline void Init()
    {
        model = glm::mat4(1.0f);
        shader.Init(GAME::CubeVsShader, GAME::CubeFsShader);
        shader.Bind();
        xCol = glm::vec3(1.0f, 0.0f, 0.0f);
        yCol = glm::vec3(0.0f, 1.0f, 0.0f);
        zCol = glm::vec3(0.0f, 0.0f, 1.0f);

        float x1 = 0.0f, x2 = 800.0f;
        m_Vertices.push_back(glm::vec3(x1, 0.0f, 0.0f)); m_Vertices.push_back(xCol);
        m_Vertices.push_back(glm::vec3(x2, 0.0f, 0.0f)); m_Vertices.push_back(xCol);
        m_Vertices.push_back(glm::vec3(0.0f, x1, 0.0f)); m_Vertices.push_back(yCol);
        m_Vertices.push_back(glm::vec3(0.0f, x2, 0.0f)); m_Vertices.push_back(yCol);
        m_Vertices.push_back(glm::vec3(0.0f, 0.0f, x1)); m_Vertices.push_back(zCol);
        m_Vertices.push_back(glm::vec3(0.0f, 0.0f, x2)); m_Vertices.push_back(zCol);

        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBindVertexArray(VAO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * m_Vertices.size(), &m_Vertices[0], GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, 0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float) * 3));

    }

    void SetMatrices(glm::mat4& v, glm::mat4& p)
    {
        shader.Bind();
        glBindVertexArray(VAO);
        shader.SetUniformMat4fv("projection", 1, GL_FALSE, p);
        shader.SetUniformMat4fv("view", 1, GL_FALSE, v);
        shader.SetUniformMat4fv("model", 1, GL_FALSE, model);
    }

    void Draw()
    {
        shader.Bind();
        glBindVertexArray(VAO);
        glDrawArrays(GL_LINES, 0, m_Vertices.size() / 2);
    }
};

void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
void processInput(GLFWwindow* window);


float deltaTime = 0.0f;
float lastFrame = 0.0f;
glm::mat4 projection;
glm::mat4 view;

Cube cube;
const glm::vec3 fCol = glm::vec3(1.0f, 1.0f, 1.0f);//white
const glm::vec3 bCol = glm::vec3(1.0f, 0.6f, 0.0f);//orange
const glm::vec3 rCol = glm::vec3(1.0f, 0.0f, 0.0f);//red
const glm::vec3 lCol = glm::vec3(1.0f, 1.0f, 0.0f);//yellow
const glm::vec3 uCol = glm::vec3(0.0f, 0.0f, 1.0f);//blue
const glm::vec3 dCol = glm::vec3(0.0f, 1.0f, 0.0f);//green

int main()
{
    GLFWwindow* window;
    if (!glfwInit())
    {
        return -1;
    }
    window = glfwCreateWindow(800, 800, "TEST", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    if (glewInit() != GLEW_OK)
    {
        glfwTerminate();
        return -1;
    }
    glfwSetKeyCallback(window, KeyCallback);

    camera.Init(glm::vec3(0.0f, 0.0f, 10.0f));
    XYZ_line xyzLine1;
    xyzLine1.Init();

    float bSize = 1.0f;
    float x1 = -1.6f, x2 = -0.5f, x3 = 0.6f;
    float z1 = 1.6f, z2 = 0.5f, z3 = -0.6f;

    cube.Init(glm::vec3(x1, x3, z1), bSize);
    cube.m_Color_L = lCol; cube.m_Color_R = rCol; cube.m_Color_F = fCol;
    cube.m_Color_B = bCol; cube.m_Color_U = uCol; cube.m_Color_D = dCol;
    cube.SetVertexData();

    glEnable(GL_DEPTH_TEST);
    while (!glfwWindowShouldClose(window))
    {
        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;
        processInput(window);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glClearColor(0.8f, 0.8f, 0.8f, 1.0f);

        view = camera.GetViewMatrix();
        projection = glm::perspective(glm::radians(camera.Zoom), 1.0f, 0.1f, 10000.0f);

        xyzLine1.model = cube.model;
        xyzLine1.SetMatrices(view, projection);
        xyzLine1.Draw();


        cube.SetMatrices(view, projection);
        cube.Draw();

        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    glfwTerminate();
    return 0;
}
void processInput(GLFWwindow* window)
{
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
    {
        camera.ProcessKeyboard(Camera_Movement::FORWARD, deltaTime);
    }
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
    {
        camera.ProcessKeyboard(Camera_Movement::BACKWARD, deltaTime);
    }
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
    {
        camera.ProcessKeyboard(Camera_Movement::LEFT, deltaTime);
    }
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
    {
        camera.ProcessKeyboard(Camera_Movement::RIGHT, deltaTime);
    }
    if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
    {
        camera.ProcessKeyboard(Camera_Movement::UP, deltaTime);
    }
    if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
    {
        camera.ProcessKeyboard(Camera_Movement::DOWN, deltaTime);
    }

}
void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    {
        glfwSetWindowShouldClose(window, true);
    }
    if (glfwGetKey(window, GLFW_KEY_X) == GLFW_PRESS)
    {
        cube.RotateX();
    }
    if (glfwGetKey(window, GLFW_KEY_Y) == GLFW_PRESS)
    {
        cube.RotateY();
    }
    if (glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS)
    {
        cube.RotateZ();
    }
}

和我的 Cube class:

    class Cube
    {
    public:
        glm::vec3 t1, t2, t3, t4;
        glm::vec3 b1, b2, b3, b4;
        glm::vec3 m_Color_L, m_Color_R, m_Color_U, m_Color_D, m_Color_F, m_Color_B;

        glm::mat4 model;
        float m_CubeSize;
        float rot_angle_X = 0.0f;
        float rot_angle_Y = 0.0f;
        float rot_angle_Z = 0.0f;

        Cube();

        void Init(glm::vec3 _from, float CubeSize);

        Cube(const Cube& e);
        Cube& operator=(const Cube& e);
        Cube(Cube&& e)noexcept;
        Cube& operator=(Cube&& e)noexcept;
        Cube* operator-> () { return this; }

        operator Cube* () { return this; }
        Cube* Clone() { return new Cube(*this); }

        void SetVertexData();
        unsigned int GetVertexDataSize() { return vertices.size(); }
        void Reset();
        glm::vec3 GetCenter();
    private:
        glm::vec3 m_Min, m_Max, m_Cpt;
        std::vector<glm::vec3>vertices;
        void SetEdgeVertices(glm::vec3 _from, float size);
    public:
        Shader cShader;
        unsigned int cubeVBO, cubeVAO;

        void RotateX();
        void RotateY();
        void RotateZ();

        void Draw();
        glm::vec3 GetPosition() { return model[3]; }
        void SetMatrices(glm::mat4& v, glm::mat4& p);

    private:
    };
    const std::string CubeVsShader =
    {
        "#version 330 core\n"
        "layout(location=0) in vec4 pos;\n"
        "layout(location=1) in vec4 col;\n"
        "\n"
        "uniform mat4 model;\n"
        "uniform mat4 view;\n"
        "uniform mat4 projection;\n"
        "\n"
        "out vec4 color;\n"
        "void main(){\n"
        "gl_Position=projection*view*model*pos;\n"
        "color=col;\n"
        "}\n"
        "\n"
    };
    const std::string CubeFsShader =
    {
        "#version 330 core\n"
        "out vec4 FragColor;\n"
        "\n"
        "in vec4 color;\n"
        "void main(){\n"
        "FragColor=color;\n"
        "}\n"
        "\n"
    };

    Cube::Cube()
        :t1(glm::vec3()), t2(glm::vec3()), t3(glm::vec3()), t4(glm::vec3()),
        b1(glm::vec3()), b2(glm::vec3()), b3(glm::vec3()), b4(glm::vec3()), m_CubeSize(0.0f)
    {

    }

    void Cube::Init(glm::vec3 _from, float CubeSize)
    {
        SetEdgeVertices(_from, CubeSize);
        model = glm::mat4(1.0f);
        cShader.Init(CubeVsShader, CubeFsShader);
        cShader.Bind();
        glGenVertexArrays(1, &cubeVAO);
        glGenBuffers(1, &cubeVBO);
        glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
        glBindVertexArray(cubeVAO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * 48, 0, GL_DYNAMIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, 0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float) * 3));
    }

    Cube::Cube(const Cube& e)
    {
        t1 = e.t1; t2 = e.t2; t3 = e.t3; t4 = e.t4;
        b1 = e.b1; b2 = e.b2; b3 = e.b3; b4 = e.b4;

        m_CubeSize = e.m_CubeSize;
        m_Color_L = e.m_Color_L;
        m_Color_R = e.m_Color_R;
        m_Color_U = e.m_Color_U;
        m_Color_D = e.m_Color_D;
        m_Color_F = e.m_Color_F;
        m_Color_B = e.m_Color_B;
        cShader = e.cShader;
        cubeVBO = e.cubeVBO;
        cubeVAO = e.cubeVAO;
        rot_angle_X = e.rot_angle_X;
        rot_angle_Y = e.rot_angle_Y;
        rot_angle_Z = e.rot_angle_Z;
        model = e.model;
        AddToVector(vertices, e.vertices);
        m_Min = e.m_Min;
        m_Max = e.m_Max;
        m_Cpt = e.m_Cpt;
    }
    Cube& Cube::operator=(const Cube& e)
    {
        t1 = e.t1; t2 = e.t2; t3 = e.t3; t4 = e.t4;
        b1 = e.b1; b2 = e.b2; b3 = e.b3; b4 = e.b4;

        m_CubeSize = e.m_CubeSize;
        m_Color_B = e.m_Color_B;
        m_Color_F = e.m_Color_F;
        m_Color_L = e.m_Color_L;
        m_Color_R = e.m_Color_R;
        m_Color_U = e.m_Color_U;
        m_Color_D = e.m_Color_D;
        cShader = e.cShader;
        cubeVBO = e.cubeVBO;
        cubeVAO = e.cubeVAO;
        model = e.model;
        rot_angle_X = e.rot_angle_X;
        rot_angle_Y = e.rot_angle_Y;
        rot_angle_Z = e.rot_angle_Z;
        AddToVector(vertices, e.vertices);
        m_Min = e.m_Min;
        m_Max = e.m_Max;
        m_Cpt = e.m_Cpt;
        return *this;
    }
    Cube::Cube(Cube&& e) noexcept
    {
        t1 = std::move(e.t1); t2 = std::move(e.t2); t3 = std::move(e.t3); t4 = std::move(e.t4);
        b1 = std::move(e.b1); b2 = std::move(e.b2); b3 = std::move(e.b3); b4 = std::move(e.b4);

        m_CubeSize = std::move(e.m_CubeSize);
        m_Color_B = std::move(e.m_Color_B);
        m_Color_F = std::move(e.m_Color_F);
        m_Color_L = std::move(e.m_Color_L);
        m_Color_R = std::move(e.m_Color_R);
        m_Color_U = std::move(e.m_Color_U);
        m_Color_D = std::move(e.m_Color_D);
        cShader = std::move(e.cShader);
        cubeVBO = std::move(e.cubeVBO);
        cubeVAO = std::move(e.cubeVAO);
        model = std::move(e.model);
        rot_angle_X = std::move(e.rot_angle_X);
        rot_angle_Y = std::move(e.rot_angle_Y);
        rot_angle_Z = std::move(e.rot_angle_Z);
        AddToVector(vertices, std::move(e.vertices));
        m_Min = std::move(e.m_Min);
        m_Max = std::move(e.m_Max);
        m_Cpt = std::move(e.m_Cpt);
    }
    Cube& Cube::operator=(Cube&& e) noexcept
    {
        t1 = std::move(e.t1); t2 = std::move(e.t2); t3 = std::move(e.t3); t4 = std::move(e.t4);
        b1 = std::move(e.b1); b2 = std::move(e.b2); b3 = std::move(e.b3); b4 = std::move(e.b4);

        m_CubeSize = std::move(e.m_CubeSize);
        m_Color_B = std::move(e.m_Color_B);
        m_Color_F = std::move(e.m_Color_F);
        m_Color_L = std::move(e.m_Color_L);
        m_Color_R = std::move(e.m_Color_R);
        m_Color_U = std::move(e.m_Color_U);
        m_Color_D = std::move(e.m_Color_D);
        cShader = std::move(e.cShader);
        cubeVBO = std::move(e.cubeVBO);
        cubeVAO = std::move(e.cubeVAO);
        model = std::move(e.model);
        rot_angle_X = std::move(e.rot_angle_X);
        rot_angle_Y = std::move(e.rot_angle_Y);
        rot_angle_Z = std::move(e.rot_angle_Z);
        m_Min = std::move(e.m_Min);
        m_Max = std::move(e.m_Max);
        m_Cpt = std::move(e.m_Cpt);
        AddToVector(vertices, std::move(e.vertices));
        return *this;
    }

    void Cube::SetVertexData()
    {
        ResetVectors(&vertices);

        vertices.push_back(b1); vertices.push_back(m_Color_D); vertices.push_back(b2); vertices.push_back(m_Color_D);
        vertices.push_back(b3); vertices.push_back(m_Color_D); vertices.push_back(b4); vertices.push_back(m_Color_D);
        vertices.push_back(t1); vertices.push_back(m_Color_U); vertices.push_back(t2); vertices.push_back(m_Color_U);
        vertices.push_back(t3); vertices.push_back(m_Color_U); vertices.push_back(t4); vertices.push_back(m_Color_U);
        vertices.push_back(b1); vertices.push_back(m_Color_L); vertices.push_back(b2); vertices.push_back(m_Color_L);
        vertices.push_back(t2); vertices.push_back(m_Color_L); vertices.push_back(t1); vertices.push_back(m_Color_L);
        vertices.push_back(b4); vertices.push_back(m_Color_R); vertices.push_back(b3); vertices.push_back(m_Color_R);
        vertices.push_back(t3); vertices.push_back(m_Color_R); vertices.push_back(t4); vertices.push_back(m_Color_R);
        vertices.push_back(b2); vertices.push_back(m_Color_B); vertices.push_back(b3); vertices.push_back(m_Color_B);
        vertices.push_back(t3); vertices.push_back(m_Color_B); vertices.push_back(t2); vertices.push_back(m_Color_B);
        vertices.push_back(b1); vertices.push_back(m_Color_F); vertices.push_back(b4); vertices.push_back(m_Color_F);
        vertices.push_back(t4); vertices.push_back(m_Color_F); vertices.push_back(t1); vertices.push_back(m_Color_F);

        cShader.Bind();
        glBindVertexArray(cubeVAO);
        glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec3) * vertices.size(), &vertices[0]);
    }
    void Cube::Reset()
    {
        b1 = b2 = b3 = b4 = t1 = t2 = t3 = t4 = glm::vec3(0.0f);
        m_Color_B = m_Color_F = m_Color_U = glm::vec3(0.0f);
        m_Color_D = m_Color_L = m_Color_R = glm::vec3(0.0f);
        m_CubeSize = 0.0f;
        this->cubeVBO = 0;
        ResetVectors(&this->vertices);
        this->cShader.Reset();
    }
    glm::vec3 Cube::GetCenter()
    {
        return m_Cpt;
    }
    void Cube::SetEdgeVertices(glm::vec3 _from, float size)
    {
        glm::vec3 _min(_from), _max;
        _max.x = _min.x + size; _max.y = _min.y + size; _max.z = _min.z - size;

        this->m_Min = _min; this->m_Max = _max;

        this->m_Cpt = (_max + _min) / glm::vec3(2.0f);

        this->b1 = glm::vec3(_min.x, _min.y, _min.z); this->b2 = glm::vec3(_min.x, _min.y, _max.z);
        this->b3 = glm::vec3(_max.x, _min.y, _max.z); this->b4 = glm::vec3(_max.x, _min.y, _min.z);
        this->t1 = glm::vec3(_min.x, _max.y, _min.z); this->t2 = glm::vec3(_min.x, _max.y, _max.z);
        this->t3 = glm::vec3(_max.x, _max.y, _max.z); this->t4 = glm::vec3(_max.x, _max.y, _min.z);

        this->m_CubeSize = size;

    }

    void Rotate(glm::mat4& mat, float ang_x, float ang_y, float ang_z)
    {
        glm::mat4 transformX = glm::mat4(1.0f);
        glm::mat4 transformY = glm::mat4(1.0f);
        glm::mat4 transformZ = glm::mat4(1.0f);
        transformX = glm::rotate(transformX, glm::radians(ang_x), glm::vec3(1.0f, 0.0f, 0.0f));
        transformY = glm::rotate(transformY, glm::radians(ang_y), glm::vec3(0.0f, 1.0f, 0.0f));
        transformZ = glm::rotate(transformZ, glm::radians(ang_z), glm::vec3(0.0f, 0.0f, 1.0f));

        mat = transformX * transformY * transformZ;
    }
    void Cube::RotateX()
    {
        model = glm::mat4(1.0f);
        rot_angle_X += 90.0f;
        if (rot_angle_X >= 360.0f)
        {
            rot_angle_X = 0.0f;
        }
        Rotate(model, rot_angle_X, rot_angle_Y, rot_angle_Z);
    }
    void Cube::RotateY()
    {
        model = glm::mat4(1.0f);
        rot_angle_Y += 90.0f;
        if (rot_angle_Y >= 360.0f)
        {
            rot_angle_Y = 0.0f;
        }
        Rotate(model, rot_angle_X, rot_angle_Y, rot_angle_Z);
    }
    void Cube::RotateZ()
    {
        model = glm::mat4(1.0f);
        rot_angle_Z += 90.0f;
        if (rot_angle_Z >= 360.0f)
        {
            rot_angle_Z = 0.0f;
        }
        Rotate(model, rot_angle_X, rot_angle_Y, rot_angle_Z);
    }
    void Cube::Draw()
    {
        cShader.Bind();
        glBindVertexArray(cubeVAO);
        glDrawArrays(GL_QUADS, 0, vertices.size() / 2);
    }
    void Cube::SetMatrices(glm::mat4& v, glm::mat4& p)
    {
        cShader.Bind();
        glBindVertexArray(cubeVAO);
        cShader.SetUniformMat4fv("model", 1, GL_FALSE, model);
        cShader.SetUniformMat4fv("view", 1, GL_FALSE, v);
        cShader.SetUniformMat4fv("projection", 1, GL_FALSE, p);
    }

我想不通我哪里做错了。任何想法或帮助将不胜感激!!!

矩阵乘法不是commutative。变薄意味着 rotateX(a) * rotateY(b) * rotateX(c) rotateX(a+c) * rotateY(b) 不同

不加角度,而是将新的旋转矩阵乘以当前模型矩阵:

class Cube
{
public:
    glm::mat4 model = glm::mat4(1.0f);

    // [...]
}

void Rotate(glm::mat4& mat, float ang_x, float ang_y, float ang_z)
{
    glm::mat4 transformX = glm::rotate(glm::mat4(1.0f), glm::radians(ang_x), glm::vec3(1.0f, 0.0f, 0.0f));
    glm::mat4 transformY = glm::rotate(glm::mat4(1.0f), glm::radians(ang_y), glm::vec3(0.0f, 1.0f, 0.0f));
    glm::mat4 transformZ = glm::rotate(glm::mat4(1.0f), glm::radians(ang_z), glm::vec3(0.0f, 0.0f, 1.0f));

    mat = transformX * transformY * transformZ * mat;
}

void Cube::RotateX()
{
    Rotate(model, 90.0f, 0.0f, 0.0f);
}

void Cube::RotateY()
{
    Rotate(model, 0.0f, 90.0f, 0.0f);
}

void Cube::RotateZ()
{
    Rotate(model, 0.0f, 0.0f, 90.0f);
}