当前绑定到OpenGL中GL_ELEMENT_ARRAY_BUFFER
目标的缓冲区是顶点数组对象(此处为VAO)中包含的状态的一部分。根据OpenGL 4.4核心配置文件规范,似乎在没有绑定VAO的情况下尝试更改或访问GL_ELEMENT_ARRAY_BUFFER
是一个错误:
10.4顶点数组对象
...任何命令都会生成
INVALID_OPERATION
错误 没有顶点数组时修改,绘制或查询顶点数组状态 受约束。这发生在初始GL状态,并且可能发生在a BindVertexArray 的结果或 DeleteVertexArrays 的副作用。
这是由OpenGL wiki的Buffer Object页面支持的:
GL_ELEMENT_ARRAY_BUFFER
gl*Draw*Elements*
形式的所有渲染函数都将使用指针 field作为从绑定到此的缓冲区对象的开头偏移的字节 目标。用于索引渲染的索引将从缓冲区中获取 宾语。 请注意,此绑定目标是Vertex Array Objects状态的一部分, 所以在绑定缓冲区之前必须绑定一个VAO 。
现在,如果不是这样的话会很好。这将使得与任何特定VAO分开创建和管理索引缓冲区变得容易。但是,如果仅在没有VAO绑定的情况下将缓冲区绑定到GL_ELEMENT_ARRAY_BUFFER
,则唯一的替代方法是表示索引缓冲区的类在创建/更新/等时绑定虚拟VAO。
Nicol Bolas'出色的OpenGL tutorial说这种用法实际上是有效的:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER)
:在没有VAO限制的情况下调用此方法不会失败。
这似乎与标准和opengl.org wiki相矛盾。是否有标准支持我错过了,或者这只是指兼容性配置文件上下文中不需要使用VAO?
答案 0 :(得分:0)
如果你有AMD或NV GPU,你总是可以使用EXT_direct_state_access
扩展来操作缓冲区对象而不绑定它(这纯粹是一个驱动程序功能,不需要任何特殊类别的硬件)。令人遗憾的是,英特尔,梅萨和苹果公司尽管已有5年的存在,但并未打算实施这一扩展 - 懒惰的懒虫。
查看以下功能,它们将使您所描述的更容易:
glNamedBufferDataEXT (...)
glNamedBufferSubDataEXT (...)
glMapNamedBufferEXT (...)
glUnmapNamedBufferEXT (...)
现在,由于DSA的采用很少,您可能不得不为不支持它的系统编写一些回退代码。您可以通过编写具有相同功能签名的函数来重现DSA的功能,这些函数签名使用虚拟VAO来绑定VBO和IBO,以便在不支持扩展的系统上进行数据操作。您必须在使用之前跟踪VAO的绑定,并在所述函数返回之前将其恢复以消除副作用。
在一个好的引擎中,你应该隐藏VAO绑定状态,而不必从GL查询它。也就是说,不是直接使用glBindVertexArray (...)
,而是实现一个包装该调用的系统,因此始终知道VAO绑定到特定上下文的内容。最后,这会模拟DSA功能,其中驱动程序支持不存在 很多 更高效。如果你尝试这样的事情,你需要知道glDelete (...)
函数隐含地解绑(通过绑定 0 )被删除的对象,如果它被绑定在当前上下文中。
答案 1 :(得分:0)
但是,如果在没有 VAO 绑定时仅将缓冲区绑定到 GL_ELEMENT_ARRAY_BUFFER
是被禁止的,那么唯一的选择是让表示索引缓冲区的类在创建/更新/等时绑定虚拟 VAO。>
对旧问题的新回复,但在不需要 VAO(或干扰当前绑定的 VAO)的情况下使用索引缓冲区的简单方法是将缓冲区绑定到 GL_ELEMENT_ARRAY_BUFFER
以外的目标。< /p>
例如,而不是这个:
glBindVertexArray(vaoID); // ...Do I even have a VAO yet?
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); // <- Alters VAO state!
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, ...);
-- 可以这样写:
glBindBuffer(GL_COPY_WRITE_BUFFER, indexBufferID);
glBufferSubData(GL_COPY_WRITE_BUFFER, ...);
(这里我随意使用了 GL_COPY_WRITE_BUFFER
,它的存在是为了提供一个临时目标,使缓冲区之间的复制更容易,但大多数其他目标也可以。)