首页 > 解决方案 > 如何在openGL中围绕全局轴旋转模型?

问题描述

在 OpenGL 中,我想围绕全局轴旋转模型。

我要旋转的对象如下所示:

class Object {
public:
    inline Object()
        : vao(0),
        positionBuffer(0),
        colorBuffer(0),
        indexBuffer(0),
        elements(0)
    {}

    inline ~Object() { // GL context must exist on destruction
        glDeleteVertexArrays(1, &vao);
        glDeleteBuffers(1, &indexBuffer);
        glDeleteBuffers(1, &colorBuffer);
        glDeleteBuffers(1, &positionBuffer);
    }
    GLuint vao;        // vertex-array-object ID
    GLuint positionBuffer; // ID of vertex-buffer: position
    GLuint colorBuffer;    // ID of vertex-buffer: color
    GLuint indexBuffer;    // ID of index-buffer
    GLuint elements; // Number of Elements
    glm::mat4x4 model; // model matrix
};

启动对象的函数如下所示:

void initObject(Object &obj, vector<glm::vec3> &vertices, vector<glm::vec3> &colors, vector<GLushort> &indices, glm::vec3 offset)
{
    GLuint programId = program.getHandle();
    GLuint pos;

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // Step 0: Create vertex array object.
    glGenVertexArrays(1, &obj.vao);
    glBindVertexArray(obj.vao);

    // Step 1: Create vertex buffer object for position attribute and bind it to the associated "shader attribute".
    glGenBuffers(1, &obj.positionBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, obj.positionBuffer);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);

    // Bind it to position.
    pos = glGetAttribLocation(programId, "position");
    glEnableVertexAttribArray(pos);
    glVertexAttribPointer(pos, 3, GL_FLOAT, GL_FALSE, 0, 0);

    // Step 2: Create vertex buffer object for color attribute and bind it to...
    glGenBuffers(1, &obj.colorBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, obj.colorBuffer);
    glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), colors.data(), GL_STATIC_DRAW);

    // Bind it to color.
    pos = glGetAttribLocation(programId, "color");
    glEnableVertexAttribArray(pos);
    glVertexAttribPointer(pos, 3, GL_FLOAT, GL_FALSE, 0, 0);

    // Step 3: Create vertex buffer object for indices. No binding needed here.
    glGenBuffers(1, &obj.indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, obj.indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLushort), indices.data(), GL_STATIC_DRAW);

    // Unbind vertex array object (back to default).
    glBindVertexArray(0);

    // Modify model matrix.
    obj.model = glm::translate(glm::mat4(1.0f), offset);
}

现在我得到了一个实例,它是作为球体的镶嵌八面体,我想围绕全局轴旋转,特别是 X 轴。该对象的中心位于 (3, 1, 0) 处,因此如果原点位于 (3, 0, 1) 处,则围绕 90 度旋转。

我试图用glm::rotate方法做到这一点:

glm::vec3 axis;
axis = { 1.0, 0.0f, 0.0f };
sphere.model = glm::rotate(sphere.model, glm::radians(90.0f), axis);

但这只会围绕它的本地轴旋转对象。

我尝试的另一个解决方案是这个:

glm::vec3 axis;
axis = glm::inverse(sphere.model) * glm::vec4(1.0, 0.0, 0.0, 0.0f);
sphere.model = glm::rotate(sphere.model, (2.0f*3.1415f)/48.0f, axis);

另一只手的行为就像全局轴位于模型的中心。因此,如果对象的中心等于全局坐标系的原点,则旋转是正确的。

标签: c++openglglm-math

解决方案


retMat = glm::rotate(curMat, ...)计算旋转矩阵并将其与给定curMat矩阵相乘。

返回的矩阵retMat可以与在同一坐标系(又称“空间”)中定义的任何点一起使用,curMat以计算新坐标,再次在同一空间中:newXYZ = retMat * oldXYZ.

给定的旋转轴glm::rotate总是穿过空间的原点。
如果您需要另一条旋转线(不包含原点),那么您必须执行“平移到线上的某个点 ==> 旋转 ==> 向后平移”的顺序

对于你的情况,我猜你的球体是这样定义的,它的中心是 origin 0,0,0。这意味着“模型空间”与“全局空间”相同。因此,您无需在旋转之前平移球体。


旋转对象后,将其平移到您希望的位置。


推荐阅读