【发布时间】:2017-02-15 00:03:31
【问题描述】:
我有 38 个具有不同着色器的粒子系统,每个粒子系统可以在世界上不同的地方(发射器)渲染多达 200 次。 每帧我唯一需要更新(上传到 GPU)的是发射器位置(可能还有某些系统中的其他一些属性), 当且仅当任何粒子系统处于活动状态且在视锥中可见。
我是否应该像这样分配和更新所有内容: - 为每个可以处理多达 200 个发射器的粒子系统分配一个 VBO。使用 glBufferSubData() 为每个粒子系统每帧更新 0 到 200 个发射器。 为每个粒子系统执行一次绘制调用。
在最坏的情况下,我们需要执行 38 次 glBufferSubData() 调用!
或者,我应该这样做(共享 VBO): -分配一个非常大的 VBO,最多可以处理 38(粒子系统)* 200(每个粒子系统的发射器)。使用单个更新所有粒子系统 调用 glBufferSubData()。在这种情况下,我们需要对每个粒子系统的所有发射器进行分组, 因为每个绘制调用都必须知道每个粒子系统及其发射器的起始偏移量。 为每个粒子系统执行一次绘制调用。
我们只需要调用一次 glBufferSubData() !
案例 nr 2 显然是赢家,但我有一些疑问。我们知道 38 个粒子系统共享一个 VBO, 但是如何停止 GPU 流水线呢? 当且仅当所有 38 个粒子系统都完成渲染时,图形驱动程序才能执行 VBO 更新,即不从 VBO 读取任何数据。
我发现了这一点:考虑使用多个缓冲区对象以避免在数据存储更新期间停止渲染管道。如果管道中的任何渲染引用了由 glBufferSubData 更新的缓冲区对象中的数据,尤其是来自正在更新的特定区域的数据,则该渲染必须从管道中排出,然后才能更新数据存储。
这里:https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferSubData.xhtml
对于案例 nr 2,我应该使用双倍甚至三倍缓冲吗?
【问题讨论】:
-
38*200 = 7600 个职位不算什么。 GPU 应该在短暂的闪烁中渲染它们。为什么要打扰?
-
每个发射器位置代表 GPU 上的 150-300 个粒子。最大的问题是,应该如何处理 CPU-GPU 传输,而不是 GPU 计算/渲染部分。
-
好的。 200万不算小,但也不算大。对其进行基准测试。如果两种方式都很慢(第一种方式,绘制一半,上传并绘制其余部分)您最好阅读第 28 章异步...openglinsights.com
-
感谢 Ripi2,一篇非常好的文章!我的解决方案:使用 Round Robin 分配三重缓冲,并在每帧调用一次 glBufferSubData()(如果在我们的截锥体中可见任何粒子系统)。 glMapBufferRange() 可以比 glBufferSubData() 更快,但是即使我们根据 AZDO(接近零驱动程序开销)指定 GL_MAP_UNSYNCHRONIZED_BIT,多线程驱动程序也可以强制同步。持久映射流需要 OpenGL 4.4...