OpenGL - 在加快 QUADS 渲染的道路上更进一步
Posted
技术标签:
【中文标题】OpenGL - 在加快 QUADS 渲染的道路上更进一步【英文标题】:OpenGL - One Step Further On The Way To Faster QUADS Rendering 【发布时间】:2011-10-19 17:50:11 【问题描述】:我已经做了一些试验,现在可以使用
将大约 300 万个 GL_QUADS 渲染到屏幕上glDrawArrays(GL_QUADS, 0, nVertexCount);
我还使用多重缓冲,循环遍历 18 个顶点缓冲对象,每个对象有 100 万个顶点。每个顶点位置都是使用存储在堆上的压缩数据和简单的计算来计算的。我用
ptr = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
和
glUnmapBuffer(GL_ARRAY_BUFFER);
每帧将每个顶点写入缓冲区对象。当缓冲区对象已满时,我取消映射它,调用 glDrawArrays,绑定并映射下一个 VBO 以流式传输更多顶点数据。当所有 18 个都用完后,我在逻辑上绑定第一个并重新开始。
根据我的经验,使用 VBO 的映射几乎是使用堆数组处理顶点数据的两倍。我怎么知道?因为,由于我渲染了 300 万个 GL_QUADS,帧率明显低于 30 fps。我可以用肉眼观察 VBO 的帧速率是如何翻倍的。
我还观察到,在每个填充的顶点缓冲区对象上连续调用 glDrawArrays 两次(导致要渲染的四边形数量增加一倍,但是一旦努力流式传输顶点数据) - 只比渲染慢一点只有一次。因此,我认为主要瓶颈是将顶点数据流式传输到顶点缓冲区对象(2 GHz 双核有 60% 忙于它!)。
现在每个顶点需要 3 个浮点数加上 2 个浮点数用于纹理坐标。 (总共 20 个字节)。我想我可以将这个数量缩短到 3 GL_SHORT 加上 2 GL_SHORT 以获得纹理坐标。使用翻译矩阵(总共 5 个字节),但这只会加速 4 倍。 (不知何故 sizeof(GL_SHORT) 在我的系统上给出了 4,所以我也不确定。)
无论如何,那里有一些游戏,它们甚至已经很老了,但每帧在屏幕上渲染远远超过 300 万个图元(而且它们不可避免地必须流式传输这些顶点,因为没有 GPU 可以容纳如此大量数据)并且仍然获得超过 100 fps 的不错的帧速率!
我敢肯定,我在这个过程中仍然遗漏了一些重要的点,但我就是不知道它是什么。有什么建议吗?
编辑: 这些是松散的四边形,就像在粒子系统中一样。 (或者更确切地说,因为每个可能最终都有不同的纹理(纹理取自单个的子纹理,因此没有广泛的绑定;)))
【问题讨论】:
这些是松散的四边形(每个四边形的顶点独立于其他四边形,例如在粒子系统中)还是由四边形组成的网格? 顺便说一句:"...已经很老了,但渲染的次数远远超过 300 万..."。我真的会怀疑。世界由超过 300 万个三角形组成的事实并不意味着它们每帧都被渲染。想想视锥体剔除、门户剔除、PVS……,这些游戏肯定会应用一些技术。但这并不意味着它对您的情况有所帮助,只是为了澄清您不能仅在场景复杂性和性能之间进行如此简单的比较。 @Nicol Bolas:四边形松散。请参阅我的编辑。在 Christian Rau:我有一个截锥体剔除——但使用它比简单地写入 20 个字节消耗更多的 CPU。就我而言,我正在尝试绘制超过 300 万个四边形。如果稍后有效地剔除 4000 万中的 15 个,那就太好了,但我仍然需要渲染超过 300 万... @Fejwin 如今,在过度批处理和实例化渲染的时代,诸如截锥剔除之类的 CPU 绑定技术并不总能提供预期的性能提升(就像在你的情况下看起来一样) .这就是为什么你不能与其他应用程序进行如此简单的比较,这些应用程序的构建考虑了完全不同的优化目标,不管它们每帧渲染超过 300 万个三角形的假设可能是错误的,无论如何。 @ChristianRau 他们渲染的图元少于 3 百万?老实说,我不知道确切的平均值是多少。也许你可以给我一个提示?基本上我知道我的方法没有优化。有什么建议我可以做什么? 【参考方案1】:我确定,我在这个过程中仍然遗漏了一些重要的点
该点应该是我需要绘制 3 MB 的三角形吗?,而不是 我怎样才能打破硬件限制?
你应该承认的限制应该是硬件。传输速率、GPU 时钟和内存时钟是在没有更新硬件的情况下无法覆盖的特性。确实,您应该尝试有效地利用当前的硬件。
据我了解,您需要在渲染时更新顶点缓冲区;所以你映射缓冲区对象,更新数据,取消映射和渲染。我想你会重复。在这种情况下,您必须考虑从 CPU 到 GPU 的传输速率;你能减少渲染场景所需的数据吗?也许插值关键顶点位置?
例如,如果我需要渲染一个地形,我可以发送数十亿个三角形来渲染一个完美的地形。但可以肯定的是,我只使用最重要的一个就可以达到相同的结果。使用更少的三角形而不扭曲好的结果,让我能够做更多的事情。
在 1920x1080 有 2 MB 的像素...我需要使用 2 MB 的三角形来绘制它吗?也许片段着色器会表现得更好。
有许多技术可用于降低处理负载(CPU 和 GPU 上)和传输速率:
剔除 详细程度 实例化渲染 关键帧动画 骨骼动画【讨论】:
刚才我意识到你是完全正确的!我将所有顶点放入 VBO 并在不更新的情况下渲染它们 - 结果仍然非常滞后。因此,这是一个硬件限制! =) 我现在将专注于从四边形到三角形,因为这些并没有被弃用,希望能稍微提高性能。从现在开始,我将把我所有的顶点都存储在一个 VBO 中,而不会进行过多的更新,因为 GPU 无论如何都无法释放其所有内存延迟。我今天学到了!非常感谢你! =)【参考方案2】:实际上您可以做很多事情(或者为了提高吞吐量)。 我只是略读一些,因为这可以(并且确实)填满一本书(或更多)。
-
绘制三角形,而不是四边形。最终,无论如何,四边形将被拆分为三边形(图形硬件已针对三角形处理进行了优化)。
当您有由这么多三角形组成的大对象时,您将尽可能使用条形和扇形(将要发送的顶点数据量从 3N 减少到 N+2)。
巧妙地缓存数据(尤其是在渲染大型场景时)至关重要。正如您所观察到的,数据传输是系统中的瓶颈。因此,基本上每个引擎都经过大量优化以避免不必要的数据传输。不过,这取决于应用程序。这也是一个可以写很多书的话题(并且已经写过)。
我可以推荐这些书作为主题的入口:
http://www.realtimerendering.com/
http://www.gameenginebook.com/
【讨论】:
谢谢,我去看看这些! “画三角形,而不是四边形”为什么?那将是非常低效的不是吗?四边形共享其最后 2 个顶点。就像三角形条一样。只为下一个三元组使用一个顶点。我不认为他们会愚蠢地为每个三角形欺骗最后两个顶点,浪费大量的 gpu 内存,好像索引会更快。我知道事实上,更多的内存会使它变慢。例如,单一的 int 颜色,与 3 个浮动 rgb 的颜色。如果opengl 对给定的顶点数据进行任何自动优化,他们肯定会将浮点数转换为字节。他们没有。 而原因是因为您定义了如何使用您上传的vbo内存。 vbo indexing 的全部原因是在使用三角形时节省顶点内存。 quads 似乎只是自动实现它。【参考方案3】:每个顶点位置都是使用存储在堆上的压缩数据和简单的计算来计算的。
也许顶点或几何着色器可以代替它?
无论如何,那里有一些游戏,它们甚至已经很老了,但每帧在屏幕上渲染远远超过 300 万个图元(而且它们不可避免地必须流式传输这些顶点,因为没有 GPU 可以容纳如此大量数据)
3000000 * 20 bytes = 60 megabytes
甚至更旧的 GPU 都可以轻松访问。
【讨论】:
这些只是简单的添加和存储操作,对于最多 240 字节的顶点数据,可能需要 30 字节。我的带有 300 万个顶点的示例肯定相当小。如果你拿3000万,3年前任何显卡都处理不了。 @Fejwin:你忘了,你在屏幕上看到的大部分都是重复使用的数据。例如,您可以只拥有少量的人物角色模型,但通过更改纹理和调整一些蒙皮矩阵,可以使它们具有非常独特的外观。 3 年前,内存大于 512MB 的显卡也很常见。例如,我仍在工作和开发具有 768MB RAM 的 GeForce8800GTX,这是我在 2006 年 11 月购买的,即大约 5 年前。在此之前,我有一个 256MB 内存的 GeForce7800,在此之前我也有一个 256MB 的 Radeon9800,也是 2003 年购买的。 @datenwolf:看来我正在尝试在 2008 年的显卡上进行开发,它落后于您 2006 年的显卡! =) (不应该对板载 GPU 上的笔记本电脑有太多期望)。我觉得你们是对的!我可以在 GPU 上存储所有需要的数据。因为,即使这样,GPU 也无法以良好的性能一次性渲染所有内容,因此这是硬件限制。以上是关于OpenGL - 在加快 QUADS 渲染的道路上更进一步的主要内容,如果未能解决你的问题,请参考以下文章
OpenGL 在 GL_QUADS 之上绘制 GL_LINES