我正在使用OpenGL(通过OpenTK和C#)编写一个小图形引擎。
为了定义顶点属性,我有一个Vertex声明类,其中包含映射到glEnableVertex AttribArray/glVertex AttribPoenter调用的Vertex Element结构数组。
此外,为了支持多个顶点流,我有一个特殊的结构来保存顶点缓冲区、顶点声明、顶点偏移和实例频率(如XNA的Vertex BufferBind结构)。
目前,每当调用绘图调用时,我都会遍历所有设置的顶点流并绑定它们的顶点缓冲区,应用顶点声明,禁用未使用的顶点属性并绘制图元。
我想使用VAO来缓存glEnableVertex AttribArray调用到它们中,并且每当应用顶点流时,绑定VAO并更改其数组缓冲区绑定。
这是VAOs的正确用法吗?
这是VAOs的正确用法吗?
否1.
glVertexAttribPointer
使用在调用函数时绑定到 GL_ARRAY_BUFFER
的缓冲区对象。所以你不能这样做:
glVertexAttribPointer(...);
glBindBuffer(GL_ARRAY_BUFFER, bufferObject);
glDrawArrays(...);
这不会使用bufferObject
;它将使用最初调用glVertexAttribPointer
时绑定到GL_ARRAY_BUFFER
的任何内容。
VAOs捕捉这种状态。因此,对于每个顶点属性,VAO将存储调用时绑定到< code>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是如何进行顶点属性绑定的。”如果您碰巧使用了提供此扩展的实现,您可以有效地执行您所说的操作,因为属性格式与缓冲区对象的存储无关。此外,glVertex AttribPoenter
的扭曲逻辑已经消失。
通常,我们在OpenGL世界中解决这个问题的方法是将尽可能多的东西放在同一个缓冲区对象中。否则,只需为每个对象使用一个VAO。