2013-01-10 62 views
19

我正在写一个使用OpenGL(通过OpenTK与C#)的小图形引擎。OpenGL,VAOs和多个缓冲区

要定义顶点属性,我有一个VertexDeclaration类,其中有一个VertexElement结构数组,映射到glEnableVertexAttribArray/glVertexAttribPointer调用。另外,为了支持多个顶点流,我有一个特殊的结构,它包含一个顶点缓冲区,顶点声明,顶点偏移量和实例频率(如XNA的VertexBufferBinding结构)。

目前,只要调用绘图电话,我遍历所有的顶点集流和 结合其顶点缓冲区,应用顶点声明,禁用不用的顶点属性和绘制图元。

我想使用VAO将glEnableVertexAttribArray调用缓存到它们中,每当应用顶点流时,绑定VAO并更改其数组缓冲区绑定。

这是VAO的正确用法吗?

回答

34

这是VAO的正确用法吗?

否。

glVertexAttribPointeruses the buffer object that was bound to GL_ARRAY_BUFFERat the moment the function was called。所以,你不能做到这一点:

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

:此讨论假定您使用新ARB_vertex_attrib_binding。或者,正如其他人所知,“Exactly how Direct3D does vertex attribute binding.”如果您恰好使用提供此扩展的实现,则可以有效地执行您正在讨论的内容,因为属性格式不与缓冲对象的存储绑定。另外,glVertexAttribPointer的折磨逻辑消失了。

一般来说,我们在OpenGL世界中解决这个问题的方法是将尽可能多的东西放在同一个缓冲区对象中。如果不这样做,只需为每个对象使用一个VAO。

+0

感谢这个伟大的答案。那么'glBufferData'步骤在哪里起作用?在使用'glVertexAttribPointer'之前,你不必先缓冲数据吗?对不起,我对OpenGL很陌生 –