多次调用glDrawElements比在GLSL中执行相同的每片段计算更有效吗?

时间:2012-10-29 23:45:27

标签: ios opengl-es glsl

我正在尝试使用GLSL(在iOS中),我编写了一个简单的着色器,它为两个圆圈(centerradiusedgeSmoothing获取颜色值和参数。在整个屏幕上使用单个四边形绘制,着色器使用gl_FragCoord并确定每个点是否在圆圈内部或外部 - 它在圆圈内计算出alpha为1.0,在{{{{{{{{{{ 1}},然后它将镜像风格的钳位应用于alpha(三角波以获得偶数奇数填充规则效果)并设置radius + edgeSmoothing

这样可以正常使用,但我想要5个不同颜色的10个圆圈,所以我为所有着色器制服调用gl_FragColor = mix(vec4(0.0), color, alpha);,并为glUniform调用四个不同时间(使用不同颜色和圆形参数) ),我的混合模式是添加剂,所以不同的颜色加起来很好地给出我想要的图案,完美!

请记住,这是一个实验,所以我试图了解GL和GLSL而不是画圈子。

现在我认为仅仅绘制一次四边形并将所有10个圆的参数传递到统一数组(glDrawElementscenters[10]等)会更有效率,循环遍历它们在GLSL中添加它们在着色器中生成的颜色。所以我编写了这个着色器并重构我的代码以立即传递所有的圆形参数。我得到了正确的结果(输出看起来完全一样)但我的帧速率从15fps下降到大约3fps - 它慢了五倍!!

着色器代码现在有循环,但使用相同的数学计算每对圆的alpha值。为什么这么慢?当然,我做的工作少于填充整个屏幕五次和GL做添加剂混合五次(即读取像素值,混合和写回)?现在我只计算累积的颜色并只填充整个屏幕一次?

任何人都能解释为什么我认为优化会产生相反的效果吗?

更新:将此代码粘贴到ShaderToy,看看我在说什么。

radii[10]

1 个答案:

答案 0 :(得分:2)

增加片段着色器中操作的复杂性会对渲染时间产生非线性影响。即使添加一个简单的分支操作,在某些情况下也可以使着色器速度减慢10倍。

在iOS设备上的片段着色器中,循环特别糟糕,所以我会不惜一切代价避免使用它们。我敢打赌,如果你将这个循环展开到针对你的统一值的一系列检查中,它会表现得更好。

然而,对你的制服进行10次检查,这听起来像涉及步骤或平滑步骤,在应用于帧缓冲区中的每个像素时会非常昂贵。它也相当浪费,因为你屏幕的很大一部分不会被任何特定的圈子覆盖。

无需使用单独的glDrawElements()调用绘制各个圆圈,也可以通过绘制屏幕大小的四边形来绘制。我在this answer内的开源应用程序中描述了一个用于绘制球体冒名顶替者的过程,我可以在最新的iOS设备上以60 FPS在屏幕上绘制数千个圆圈(球体)。为此,我传入一个四边形,每个圆圈足够大,包含该圆圈,不大。这些四边形都是一个阵列,然后立即绘制。每个圆的附加参数作为属性与顶点数据一起传递。例如,我不需要指定半径,因为我在顶点旁边使用从(-1,-1)到(1,1)的冒充者空间坐标,并进行简单的计算以确定一个点是否在圆内。 / p>

如果您只绘制每个圆所需的碎片,而不是更多,您将从管道的碎片处理部分中获取大量负载。您仍然需要启用混合模式,但是四倍大小的减少,以及片段着色器中执行的操作的简化,将导致整体性能更好。