我来自这个问题:
我使用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中包含一个带有可移动部件的完整模型吗?
答案 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
(顺便说一句:抱歉提出一个老话题,我只是觉得这对其他人有用,这个帖子肯定是!(这让我想起了,谢谢!!))