【问题标题】:performance - drawing many 2d circles in opengl性能 - 在 opengl 中绘制许多 2d 圆圈
【发布时间】:2013-02-04 10:28:59
【问题描述】:

我正在尝试在 opengl 中为我的 2d 游戏绘制大量 2d 圆圈。它们的大小相同,质地相同。许多精灵重叠。最快的方法是什么?

an example of the kind of effect I'm making http://img805.imageshack.us/img805/6379/circles.png

(需要注意的是,黑边只是由于圆圈的扩大爆炸造成的。截屏后不久就被填充了。

目前我正在使用一对带纹理的三角形来制作每个圆圈。我在纹理边缘周围有透明度,以使其看起来像一个圆圈。事实证明,为此使用混合非常慢(并且 z 剔除是不可能的,因为它们被渲染为深度缓冲区的正方形)。相反,我没有使用混合,而是让我的片段着色器丢弃任何 alpha 为 0 的片段。这可行,但是这意味着早期 z 是不可能的(因为片段被丢弃)。

速度受到大量透支和 GPU 填充率的限制。圆圈的绘制顺序并不重要(只要它不会在产生闪烁的帧之间发生变化),所以我一直在努力确保屏幕上的每个像素只能写入一次。

我尝试使用深度缓冲区。在每一帧开始时,它被清除为 1.0f。然后,当绘制一个圆圈时,它会将深度缓冲区的那部分更改为 0.0f。当通常在那里绘制另一个圆时,它不是因为新圆的 z 也为 0.0f。这不小于深度缓冲区中当前存在的 0.0f,因此它不会被绘制。这有效,并且应该减少必须绘制的像素数量。然而;奇怪的是它并没有更快。我已经问过一个关于这种行为的问题 (opengl depth buffer slow when points have same depth),建议是使用相等的 z 值时 z 剔除没有被加速。

相反,我必须将我所有的圈子从 0 向上分开的虚假 z 值。然后,当我使用 glDrawArrays 和默认值 GL_LESS 进行渲染时,由于 z 剔除,我们正确地获得了速度提升(尽管早期 z 是不可能的,因为碎片被丢弃以使圆圈成为可能)。然而,这并不理想,因为我不得不为 2d 游戏添加大量与 z 相关的代码,而这根本不需要它(如果可能的话,不传递 z 值会更快)。然而,这是我目前找到的最快的方法。

最后我尝试了使用模板缓冲区,这里我使用了

glStencilFunc(GL_EQUAL, 0, 1);
glStencilOp(GL_KEEP, GL_INCR, GL_INCR);

模板缓冲区每帧重置为 0。这个想法是在一个像素被绘制到第一次之后。然后在模板缓冲区中将其更改为非零。然后不应再次绘制该像素,从而减少透支量。然而,事实证明,这并不比仅在没有模板缓冲区或深度缓冲区的情况下绘制所有内容快。

人们发现写我正在尝试的最快方法是什么?

【问题讨论】:

  • 你是单批画的吗?
  • 是的,只有一个 glDrawArrays(GL_TRIANGLES, 0, 100001*(2*3));每帧绘制所有这些。
  • hmm 我预计会有相当好的结果 - 窗口越小越快?
  • 是的。它要快得多。

标签: performance opengl gpu geometry particles


【解决方案1】:

根本问题是您填充受限,这是 GPU 无法在您期望的时间内对您要求它绘制的所有片段进行着色。您使用深度缓冲技巧无效的原因是处理中最耗时的部分是对片段进行着色(通过您自己的片段着色器或通过固定功能着色引擎),这会发生 在深度测试之前。使用模板也会出现同样的问题;对像素进行着色是在模板制作之前进行的。

有一些事情可能会有所帮助,但它们取决于您的硬件:

  • 使用深度缓冲从前到后渲染您的精灵。现代 GPU 通常会尝试确定一组片段是否可见,然后再将它们发送出去进行着色。粗略地说,检查深度缓冲区(或它的表示)以查看即将被着色的片段是否可见,如果不可见,则在该点终止处理。这应该有助于减少需要写入帧缓冲区的像素数量。
  • 使用片段着色器立即检查纹素的 alpha 值,并在任何其他处理之前丢弃片段,如下所示:

    varying vec2 texCoord;
    uniform sampler2D tex;
    
    void main()
    {
        vec4 texel = texture( tex, texCoord );
    
        if ( texel.a < 0.01 ) discard;
    
        // rest of your color computations
    }
    

(你也可以在固定功能片段处理中使用alpha测试,但无法说是否会在片段着色完成之前应用测试)。

【讨论】:

  • 我可能不清楚。如果我在 z 轴上给每个圆一个不同的值,它实际上比不使用深度缓冲快两倍多(在我的测试中)。然而,对于圆圈使用相同的 z 值进行深度缓冲并不比完全不进行 z 缓冲快得多。 (看起来它应该也可以工作?)这可能是因为你的第一点。 (这很有趣,因为这听起来像早期的 z?我认为如果你在片段着色器中丢弃是不可能的?)我的片段着色器就是这样。谢谢你的回复。
  • @Ellipsis 使用深度缓冲没有意义:至少您可以将一堆读取-修改-写入周期保存到颜色和深度缓冲区,所以我对此并不感到惊讶。至于使用相同的z值,我不知道。可能存在用于小于深度测试的快速模式,或者相等模式产生与非深度测试基本相同的结果。最后,如果您使用此技巧,有些架构会禁用 early-z,但这并不是所有 GPU 的普遍特征 - 这是一个实现问题,您只能通过测试才能发现。而且,不客气。
猜你喜欢
  • 2013-04-17
  • 1970-01-01
  • 1970-01-01
  • 2014-04-11
  • 2012-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多