3

我正在开发一个基于瓷砖的物理游戏,例如 Falling Sand Game。我目前对顶点使用静态 VBO,对与每种块类型关联的颜色使用动态 VBO。在这种类型的游戏中,颜色 VBO 中的数据变化非常频繁。(曾经块更改)目前我正在为每个块更改调用 glBufferSubDataARB。我发现这行得通,但它不能很好地适应分辨率。(随着分辨率的每次增加,速度会慢得多)我希望我能获得两倍的当前可播放分辨率。(256x256)

我应该非常频繁地调用 BufferSubData 还是一帧调用一次 BufferData?我应该放弃 VBO 并使用顶点数组吗?

对不支持 VBO 的视频卡可以做什么?

(注:每块大于一个像素)

4

2 回答 2

5

首先,您应该停止使用这两个功能。自 2002 年左右以来,缓冲区对象一直是 OpenGL 的核心功能;没有理由使用它们的扩展形式。您应该使用 glBufferData 和 glBufferSubData,而不是 ARB 版本。

其次,如果你想要高性能的缓冲区对象流,可以在 OpenGL wiki 上找到提示。但总的来说,在同一内存上每帧多次调用 glBufferSubData 并没有帮助。映射缓冲区并直接修改它可能会更好。

对于你的最后一个问题,我想说的是:你为什么要关心?如前所述,缓冲区对象是旧的。这就像问你应该为只支持 D3D 5.0 的硬件做什么。

忽略它; 没有人会关心。

于 2011-10-25T20:49:02.987 回答
3

您最好在 RAM 中自己的副本中更新频繁变化的颜色信息,并在一次操作中将数据交给 GL,每帧一次,最好在帧结束时,就在交换缓冲区之前(这意味着您需要做它曾经在第一帧中脱节)。

glBufferSubData 可以比它更快,glBufferData因为它不会重新分配服务器上的内存,并且因为它可能传输更少的数据。但是,在您的情况下,它可能会更慢,因为它需要与仍在绘制的数据同步。此外,由于数据可能在任何随机位置发生变化,因此仅上传子范围的收益不会很大,并且每帧上传一次整个缓冲区在带宽方面应该没有问题。

最好的策略是glDraw(Elements|Arrays|Whatever)跟注,然后是glBufferData(...NULL)。这告诉OpenGL你不再关心缓冲区,它可以在绘制完成后立即丢弃内容(当你现在映射这个缓冲区或复制到它时,OpenGL会偷偷使用一个新的缓冲区而不告诉你. 这样,您可以在旧缓冲区尚未完成绘制时处理新缓冲区,这避免了停顿)。

现在你运行你的物理模拟,并以任何你想要的方式修改你的颜色数据。完成后,可以使用glMapBuffermemcpy、 和glUnmapBuffer,或者简单地使用glBufferData(映射有时会更好,但在这种情况下,它应该几乎没有区别或没有区别)。这是您将在下一帧中绘制的数据。最后,交换缓冲区。

这样,当卡仍在处理最后一次绘制调用时,驱动程序就有时间进行传输。此外,如果启用了 vsync 并且您的应用程序阻塞等待 vsync,则该时间可供驱动程序用于数据传输。因此,您实际上可以保证无论何时进行绘图调用(下一帧),数据都已准备好。

关于不支持 VBO 的卡,这实际上并不存在(嗯,确实存在,但不是真的)。VBO 更像是一种编程模型,而不是硬件功能。如果您使用普通的普通顶点数组,驱动程序最终仍然必须以某种方式将数据块传输到卡。唯一的区别是拥有一个顶点数组,但驱动程序拥有一个 VBO。
这意味着在 VBO 的情况下,司机不需要问你什么时候做什么。对于顶点数组,它只能依赖于数据在您调用的确切时间有效glDrawElements。在 VBO 的情况下,它总是知道数据是有效的,因为您只能通过驱动程序控制的接口对其进行修改。这意味着它可以更优化地管理内存和传输,并且可以更好地绘制管道。

There do of course exist implementations that don't support VBOs, but those would need to be truly old (like 10+ years old) drivers. It's not something to worry about, realistically.

于 2011-10-26T11:27:19.970 回答