我试图在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。这个想法是在第一次绘制像素之后。然后在模板缓冲区中将其更改为非零。然后不应该再次绘制该像素,从而减少透支量。然而,事实证明这并不比仅使用模板缓冲区或深度缓冲区绘制所有内容更快。
人们发现写作的最快方式是做我想做的事情吗?
答案 0 :(得分:3)
根本问题在于你填充限制,这是GPU无法遮盖你要求它在你期望的时间内绘制的所有片段。你深度缓冲技巧无效的原因是处理中最耗时的部分是对片段进行着色(通过自己的片段着色器或通过固定功能着色引擎),这会发生在深度测试之前。使用模板也会出现同样的问题;在模板印刷之前对像素进行着色。
有一些事情可能有所帮助,但它们取决于您的硬件:
使用片段着色器立即检查texel的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测试,但是不可能说在片段着色完成之前是否会应用测试。)