首先,VAO只“记住”最后一个顶点属性绑定(和索引缓冲区的VBO绑定(如果有的话))。因此它不会记住在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
因此,你可以使用单个VAO和一个或多个VBO来绘制交错的顶点数组,使用glDrawElements
方法。回答你问题的第二部分,你可以为网格的不同部分有不同的VAO和VBO(这样绘制独立的部分很容易),或者将所有内容融合到一个VAO VBO对中(这样就不需要经常调用glBind*()
),然后使用多个glDraw*()
调用来绘制网格的各个部分(如上面的代码所示 - 想象一下第一个glDrawElements()
绘制船体,第二个绘制炮塔,你只需要在调用之间更新一些矩阵统一变量)。
由于着色器可以在uniforms中包含多个modelview矩阵,您还可以将mesh id编码为另一个顶点属性,并让顶点着色器根据该属性选择要使用的矩阵来转换顶点。这个想法也可以扩展到每个单个顶点使用多个矩阵,其中为每个矩阵分配一些权重。当动画有机物对象(例如玩家角色)时,这是常用的技术(请搜索“skinning”)。
至于uniform buffer objects,唯一的优势就是可以将大量数据打包到它们中,并且它们可以轻松共享于支持的所有着色器(只需将UBO绑定到任何能够使用它的着色器即可)。除非你要使用具有数千个矩阵的对象,否则使用它们没有实际优势。
此外,我从记忆中编写了上面的源代码。如果有错误/问题,请告诉我...
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); // 这是VAO保存的状态
- tauran