我已经做了一些实验,现在可以使用在屏幕上渲染大约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两次(导致要渲染的四边形数量是原来的两倍,但流式传输顶点数据的工作量是原来的一倍(——只比只渲染一次慢得不多。因此,我认为主要的瓶颈是将顶点数据流式传输到顶点缓冲区对象(2GHz的双核60%都在忙!!(。
现在,每个顶点都有3个浮动,再加上纹理坐标的2个浮动。(总共20个字节(。我想我可以将这个数量缩短为3 GL_SHORT加2 GL_SHORT作为纹理坐标。使用转换矩阵(总共5个字节(,但这只会加快4倍。(不知何故,sizeof(GL_SHORT(在我的系统中给出了4,所以我也不确定。(
无论如何,有些游戏甚至已经很老了,但每帧都会在屏幕上渲染远远超过300万个基本体(它们不可避免地必须流式传输这些顶点,因为没有一个GPU可以容纳这么多数据(,并且仍然可以获得超过100帧/秒的帧速率!
我确信,在这个过程中,我仍然遗漏了一些重要的一点,但我就是弄不清它是什么。有什么建议吗?
编辑:这些是松散的四边形,类似于粒子系统中的四边形。(或者更确切地说,因为每个纹理可能最终都有不同的纹理(纹理取自单个纹理的子纹理,因此没有广泛的绑定;((
我确信,我仍然错过了过程中的一些重要点
点应该是我需要画3 MB的三角形吗,而不是如何突破硬件限制
您应确认的限制应为硬件。传输速率、GPU时钟和内存时钟是没有更新硬件就无法覆盖的特性。事实上,你应该尽量有效地利用目前的硬件。
正如我所理解的,在渲染时需要更新顶点缓冲区;因此,您可以映射缓冲区对象、更新数据、取消映射和渲染。我想你会反复做的。在这种情况下,您必须考虑从CPU到GPU的传输速率;你能减少渲染场景所需的数据吗?也许是插值关键顶点位置?
例如,如果我需要渲染一个地形,我可以发送数十亿个三角形来渲染一个完美的地形。但我肯定可以通过使用最重要的一个来达到同样的结果。在不扭曲好结果的情况下使用更少的三角形,使我能够做得越来越多。
在1920x1080,有2 MB的像素。。。我需要使用2MB的三角形来绘制它吗?也许碎片着色器的性能会更好。
有许多技术用于降低处理负载(CPU和GPU上(和传输速率:
- 剔除
- 详细程度
- 实例化渲染
- 关键帧动画
- 骨骼动画
实际上你可以做很多事情(或者做这些事情是为了获得更多的吞吐量(。我只是略读了一些,因为这可以(而且确实(填满一本(或多本(书。
- 画三角形,而不是四边形。最终,四边形将被拆分为三个四边形(图形硬件针对三角形处理进行了优化(
- 当你有这么多三角形组成的大对象时,你会尽可能使用条形和扇形(将要发送的顶点数据量从3N减少到N+2(
- 巧妙地缓存数据(尤其是在渲染大型场景时(至关重要。正如您所观察到的,数据传输是系统中的瓶颈。因此,基本上每个引擎都经过了大量优化,以避免不必要的数据传输。不过,这取决于应用程序。这也是一个可以写很多书的话题
我可以推荐这些书作为主题的条目:
http://www.realtimerendering.com/
http://www.gameenginebook.com/
每个顶点位置都是使用存储在堆上的压缩数据和简单的计算来计算的。
也许顶点或几何体着色器可以代替它?
无论如何,有一些游戏,甚至已经很老了,但每帧都会在屏幕上渲染远远超过300万个基元(它们不可避免地必须流式传输这些顶点,因为没有GPU可以容纳这么多数据(
CCD_ 1,即使是较旧的GPU也能轻松使用。