如何在openGL中绕全局轴旋转模型?

问题描述 投票:0回答:3

在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),因此,绕90度旋转应该使原点位于(3,0,1)。

我尝试使用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++ opengl glm-math
3个回答
0
投票

我会向@genpfault表示敬意。听起来像glm :: rotate的实现是:[https://github.com/g-truc/glm/blob/1498e094b95d1d89164c6442c632d775a2a1bab5/glm/ext/matrix_transform.inl

因此它不触碰平移,它仅改变矩阵的旋转部分,就像设置物体一样。为了执行动画或组合不同的转换,您需要使用另一个API。


0
投票

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

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

赋予glm::rotate的旋转轴始终穿过该空间的原点。 如果您需要另一条旋转线(不包含原点),则必须执行序列“转换到直线上的某个点==>旋转==>向后平移”

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

旋转对象后,将其平移到所需的位置。


0
投票

在模型+视图+投影(MVP)矩阵(或四元数)运算中,您正在混合模型和视图矩阵。您需要将模型从单位矩阵旋转到所需的RPY矩阵。然后,将对象移动和/或旋转到XYZ空间中所需的位置。最后,您可以根据需要应用正交投影或透视投影。

© www.soinside.com 2019 - 2024. All rights reserved.