您最好在 RAM 中自己的副本中更新频繁变化的颜色信息,并在一次操作中将数据交给 GL,每帧一次,最好在帧结束时,就在交换缓冲区之前(这意味着您需要做它曾经在第一帧中脱节)。
glBufferSubData
可以比它更快,glBufferData
因为它不会重新分配服务器上的内存,并且因为它可能传输更少的数据。但是,在您的情况下,它可能会更慢,因为它需要与仍在绘制的数据同步。此外,由于数据可能在任何随机位置发生变化,因此仅上传子范围的收益不会很大,并且每帧上传一次整个缓冲区在带宽方面应该没有问题。
最好的策略是glDraw(Elements|Arrays|Whatever)
跟注,然后是glBufferData(...NULL)
。这告诉OpenGL你不再关心缓冲区,它可以在绘制完成后立即丢弃内容(当你现在映射这个缓冲区或复制到它时,OpenGL会偷偷使用一个新的缓冲区而不告诉你. 这样,您可以在旧缓冲区尚未完成绘制时处理新缓冲区,这避免了停顿)。
现在你运行你的物理模拟,并以任何你想要的方式修改你的颜色数据。完成后,可以使用glMapBuffer
、memcpy
、 和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.