VAO / VBO的OpenGL结构用于带有运动部件的模型?

时间:2012-01-14 13:42:57

标签: opengl vbo

我来自这个问题:

opengl vbo advice

我使用OpenGL 3.3并且不会使用已弃用的功能。我使用Assimp导入我的搅拌机模型。但我有点困惑的是,我应该根据VAO和VBO将它们拆分多少。

首先是一个小问题。我使用glDrawElements,这意味着我不能交错我的顶点属性,或者VAO可以使用glVertexAttribPointer和glDrawElements偏移来计算我的顶点位置在哪里?

主要问题我想,归结为我如何构建我的VAO / VBO用于具有多个运动部件和多个网格的模型。一部分。

assimp中的每个节点都可以包含多个网格,其中每个网格都有纹理,顶点,法线,材质等.assimp中的节点包含转换。说我有一艘装有大炮炮塔的船。我希望能够在炮塔上进行掠夺。这是否意味着我将使船舶节点与包含其属性(或多个VBO等)的每个网格的VBO分离。 我想这就像

draw(ship);    //call to draw ship VAO
pushMatrix(turretMatrix)  //updating uniform modelview matrix for the shader
draw(turret);  //call to draw turret VAO

我还没有完全理解UBO(统一缓冲区对象),但似乎我可以传递多个制服,这会帮助我在一个VAO中包含一个带有可移动部件的完整模型吗?

2 个答案:

答案 0 :(得分:13)

首先,关闭VAO只会“记住”最后一个顶点属性绑定(以及索引缓冲区的VBO绑定(GL_ELEMENT_ARRAY_BUFFER_BINDING),如果有的话)。因此它不记得glDrawElements()中的偏移量,您需要在使用VAO时稍后调用它。它也不会阻止您使用交错的顶点数组。让我试着解释一下:

int vbo[3];
glGenBuffers(3, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, data0, size0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, data1, size1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, data2, size2);
// create some buffers and fill them with data

int vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// create a VAO

{
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO
    glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * sizeof(float), NULL); // this is VAO saved state
    glEnableVertexAttribArray(0); // this is VAO saved state
    // sets up one vertex attrib array from vbo[0] (say positions)

    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); // not saved in VAO
    glVertexAttribPointer(1, 3, GL_FLOAT, false, 5 * sizeof(float), NULL); // this is VAO saved state
    glVertexAttribPointer(2, 2, GL_FLOAT, false, 5 * sizeof(float), (const void*)(2 * sizeof(float))); // this is VAO saved state
    glEnableVertexAttribArray(1); // this is VAO saved state
    glEnableVertexAttribArray(2); // this is VAO saved state
    // sets up two more VAAs from vbo[1] (say normals interleaved with texcoords)

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]); // this is VAO saved state
    // uses the third buffer as the source for indices
}
// set up state that VAO "remembers"

glBindVertexArray(0); // bind different vaos, etc ...

稍后......

glBindVertexArray(vao); // bind our VAO (so we have VAAs 0, 1 and 2 as well as index buffer)
glDrawElements(GL_TRIANGLE_STRIP, 57, GL_UNSIGNED_INT, NULL);
glDrawElements(GL_TRIANGLE_STRIP, 23, GL_UNSIGNED_INT, (const void*)(57 * sizeof(unsigned int)));
// draws two parts of the mesh as triangle strips

所以你看到......你可以使用glDrawElements使用单个VAO和一个或多个VBO绘制交错的顶点数组。

要回答你问题的第二部分,要么可以为网格的不同部分设置不同的VAO和VBO(这样可以很容易地绘制单独的部分),或者你可以将所有部分融合到一个VAO VBO中(所以你不需要)经常调用glBind*()并使用多个glDraw*()调用来绘制网格的各个部分(如上面的代码所示 - 想象第一个glDrawElements()绘制船只,第二个绘制炮塔,你只是在调用之间更新一些矩阵统一。)

因为着色器可以在制服中包含多个模型视图矩阵,所以您还可以将网格id编码为另一个顶点属性,并让顶点着色器根据此属性选择用于变换顶点的矩阵。这个想法也可以扩展到每个单个顶点使用多个矩阵,并为每个矩阵分配一些权重。这通常用于动画有机物体(如玩家角色)(查找“蒙皮”)。

随着统一缓冲区对象的进行,唯一的优势是您可以将大量数据打包到它们中,并且可以在着色器之间轻松共享(只需将UBO绑定到任何能够使用它的着色器)。使用它们对你没有什么好处,除非你想拥有1000个矩阵的对象。

另外,我从内存中写了上面的源代码。如果有一些错误/问题,请告诉我......

答案 1 :(得分:0)

@theswine

在VAO初始化期间不对此进行绑定会导致程序崩溃,但在绑定VAO后绑定它会导致程序正常运行。你确定这个没有保存在VAO中吗?

glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO

(顺便说一句:抱歉提出一个老话题,我只是觉得这对其他人有用,这个帖子肯定是!(这让我想起了,谢谢!!))