GL_ARB_vertex_attrib_binding 和索引绘图
Posted
技术标签:
【中文标题】GL_ARB_vertex_attrib_binding 和索引绘图【英文标题】:GL_ARB_vertex_attrib_binding and indexed drawing 【发布时间】:2015-12-26 20:07:11 【问题描述】:我正在尝试在 OpenGL 中渲染一个类似 Minecraft 的世界。世界被分割成块(每个块包含 N^3 个块),这些块在每一帧都被渲染。
目前我每块使用一个 VAO。我一直觉得这有点奇怪,因为每个块都使用相同的顶点格式 - 为什么我不能使用单个 VAO,然后通过更改索引和顶点缓冲区绑定来绘制每个块?
最近我遇到了核心 4.3 中的 GL_ARB_vertex_attrib_binding 扩展,它似乎解决了这个问题 - VAO 和 VBO 绑定现在可以分开了。但是没有提到索引缓冲区绑定,它仍然是 VAO 状态的一部分,使得扩展对索引渲染毫无用处。我唯一能想到的就是在渲染时为每个块和顶点缓冲区绑定更改更新绑定索引缓冲区的内容,但这没有什么意义。
我的问题是,我是否理解扩展程序的正确功能?如果我这样做了,是否可以使用另一种方法来避免每块 VAO,而无需将每块索引缓冲区合并到一个大 IBO(因为它会使块流管理不必要地复杂化)?
【问题讨论】:
【参考方案1】:你已经......部分误解了顶点属性绑定的目的。
是的,它在vertex format 和buffer bindings 之间创建separation。但是,这种分离仅在 API 级别。也就是说,您有诸如设置格式的 glVertexAttribFormat 和设置缓冲区的 glBindVertexBuffer 之类的函数。
但所有这些功能仍然会修改 VAO 状态。
但是,没有必要仅仅因为您正在更改 VAO 内 VAO 的状态而更改 VAO。顶点属性绑定存在的原因是因为改变顶点格式状态是昂贵的。而改变缓冲区绑定状态不是(或至少,它不是 as 昂贵的)。所以拨打glBindVertexBuffer
比拨打glVertexAttribFormat
便宜。
这就是该功能存在的原因:这样您就不会为了执行便宜的操作而拨打昂贵的电话。
所以你想做的很好;您可以只绑定 VAO,然后根据需要进行 glBindVertexBuffer
和 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER)
调用。是的,这些会修改 VAO 中的状态,但那又如何呢?只要不触碰VAO中的顶点格式就可以了。
话虽如此,如果您的目标是性能,那么您可能不应该更改每个块的缓冲区绑定状态。将所有块(或至少一大组)放入同一缓冲区的不同区域。块组的所有索引同样应该存在于单个缓冲区中。索引应该相对于该块数据的开头,因此您应该能够使用 16 位 GLshort 索引。
当需要渲染特定块时,使用BaseVertex-based rendering 来选择要渲染的单个块。 base_vertex
用于提供索引的偏移量。这个偏移量应该基于块的最大大小。
这样,要使用一组块进行渲染,您可以最大限度地减少您执行的缓冲区绑定操作的数量。因此可以最大限度地减少绘图调用之间的状态更改次数。
【讨论】:
原来我很困惑 - 我认为由于 IBO 绑定是 VAO 状态的一部分(为什么?),它被“锁定”并且无法更改。在您的帮助和阅读其他答案的情况下,我终于了解了 VAO、VBO 和 IBO 之间的关系,现在我的单 VAO 实现可以正常工作。非常详细的答案,非常感谢(也提供性能提示)!以上是关于GL_ARB_vertex_attrib_binding 和索引绘图的主要内容,如果未能解决你的问题,请参考以下文章