这是正确使用VAO的方式吗?
不是。glVertexAttribPointer使用绑定到GL_ARRAY_BUFFER的缓冲对象,在函数调用时会使用它。因此你不能这样做:
glVertexAttribPointer(...);
glBindBuffer(GL_ARRAY_BUFFER, bufferObject);
glDrawArrays(...);
这将不使用bufferObject;它将使用在glVertexAttribPointer最初调用时绑定到GL_ARRAY_BUFFER的任何内容。
VAO捕获此状态。因此,对于每个顶点属性,VAO将存储在调用时绑定到GL_ARRAY_BUFFER的任何缓冲区对象。这使您可以执行以下操作:
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, buffer1);
glVertexAttribPointer(0, ...);
glVertexAttribPointer(1, ...);
glBindBuffer(GL_ARRAY_BUFFER, buffer2);
glVertexAttribPointer(2, ...);
属性0和1将来自于
buffer1
,属性2将来自于
buffer2
。现在VAO捕获了所有状态。要进行渲染,只需执行以下操作:
glBindVertexArray(VAO);
glDraw*();
简而言之,如果您想要改变OpenGL中属性存储的位置,您必须同时改变它的格式。即使是相同的格式,您也必须再次调用glVertexAttribPointer。
1: 这个讨论假设您没有使用新的ARB_vertex_attrib_binding。或者,它被称为"正如Direct3D如何绑定顶点属性"。如果您正在使用提供此扩展的实现,您可以有效地完成您所说的事情,因为属性格式不与缓冲对象的存储绑定。此外,glVertexAttribPointer的复杂逻辑已经消失了。
一般来说,在OpenGL世界中解决这个问题的方法是尽可能将许多东西放在同一个缓冲对象中。如果失败,只需为每个对象使用一个VAO。
glEnableVertexAttribArray
调用说“否”。链接问题“When to callglVertexAttribPointer
?”的答案表明,这正是VAO的作用,也是现在推荐的方法。 - xealits