Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/111.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在GLSL中对每个片段执行相同的计算时,对GLDrawerElements的多次调用是否比执行相同的计算更有效?_Ios_Opengl Es_Glsl - Fatal编程技术网

Ios 在GLSL中对每个片段执行相同的计算时,对GLDrawerElements的多次调用是否比执行相同的计算更有效?

Ios 在GLSL中对每个片段执行相同的计算时,对GLDrawerElements的多次调用是否比执行相同的计算更有效?,ios,opengl-es,glsl,Ios,Opengl Es,Glsl,我正在试验GLSL(在iOS中),我编写了一个简单的着色器,它为两个圆(center,radius,和edgeSmoothing)获取颜色值和参数。它在整个屏幕上使用单个四边形绘制,着色器使用gl_FragCoord并确定每个点是在圆内还是在圆外-它计算圆内的alpha为1.0,平滑着色到圆外的0.0radius+edgeSmoothing,然后对alpha应用镜像样式夹(三角波以获得奇偶填充规则效果)并设置gl_FragColor=mix(vec4(0.0),color,alpha); 这很好

我正在试验GLSL(在iOS中),我编写了一个简单的着色器,它为两个圆(
center
radius
,和
edgeSmoothing
)获取颜色值和参数。它在整个屏幕上使用单个四边形绘制,着色器使用
gl_FragCoord
并确定每个点是在圆内还是在圆外-它计算圆内的alpha为1.0,平滑着色到圆外的0.0
radius+edgeSmoothing
,然后对alpha应用镜像样式夹(三角波以获得奇偶填充规则效果)并设置
gl_FragColor=mix(vec4(0.0),color,alpha);

这很好,但是我想要5种不同颜色的10个圆,所以我调用
glUniform
来获得所有着色器制服和
gldrawerelements
来分别绘制五次四边形(使用不同的颜色和圆参数),我的混合模式是加法模式,因此不同的颜色可以很好地叠加,以提供我想要的图案,完美

记住,这是一个实验,所以我试图学习GL和GLSL,而不是画圆圈

现在,我认为只绘制一次四边形并将所有10个圆的参数传递到统一的数组(
中心[10]
半径[10]
,等等)会更有效,在GLSL中循环通过它们,并将它们在着色器中产生的颜色相加。因此,我编写此着色器并重构代码,以便一次传入所有圆参数。我得到了正确的结果(输出看起来完全相同),但我的帧速率从15fps下降到3fps左右-速度慢了五倍

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

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

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

#ifdef GL_ES
precision highp float;
#endif

uniform float time;

void main(void)
{
    float r, d2, a0, a1, a2;
    vec2 pos, mid, offset;
    vec4 bg, fg;

    bg = vec4(.20, .20, .40, 1.0);
    fg = vec4(.90, .50, .10, 1.0);
    mid = vec2(256.0, 192.0);

    // Circle 0
    pos = gl_FragCoord.xy - mid;
    d2 = dot(pos, pos);
    r = 160.0;
    a0 = smoothstep(r * r, (r + 1.0) * (r + 1.0), d2);

    // Circle 1
    offset = vec2(110.0 * sin(iGlobalTime*0.8), 110.0 * cos(iGlobalTime));
    pos = gl_FragCoord.xy - mid + offset;
    d2 = dot(pos, pos);
    r = 80.0;
    a1 = smoothstep(r * r, (r + 1.0) * (r + 1.0), d2);

    // Circle 2
    offset = vec2(100.0 * sin(iGlobalTime*1.1), -100.0 * cos(iGlobalTime*0.7));
    pos = gl_FragCoord.xy - mid + offset;
    d2 = dot(pos, pos);
    r = 80.0;
    a2 = smoothstep(r * r, (r + 1.0) * (r + 1.0), d2);

    // Calculate the final alpha
    float a = a0 + a1 + a2;
    a = abs(mod(a, 2.0) - 1.0);

    gl_FragColor = mix(bg, fg, a);
}

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

在iOS设备上的片段着色器中,循环尤其可怕,因此我会不惜一切代价避免它们。我打赌,如果将该循环展开为一系列针对统一值的检查,它的性能会更好

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

无需使用单独的
gldrawerelements()
调用或通过绘制屏幕大小的四边形来绘制各个圆。我描述了一个在我的开源应用程序中绘制球体冒名顶替者的过程,在这个过程中,我可以绘制数千个圆(球体)在最新的iOS设备上以60 FPS的速度在屏幕上显示。为此,我为每个圆传入一个四元组,这个四元组足够大,可以包含该圆,但不能大于该圆。这些四元组都聚集在一个数组中,并一次绘制。每个圆的附加参数作为顶点数据旁边的属性传入。例如,我不需要指定半径因为我在顶点旁边使用(-1,-1)到(1,1)的视点替用特效子空间坐标,并进行简单的计算以确定点是否在圆内


如果您只绘制每个圆所需的片段,而不绘制更多的片段,您将减轻管道中片段处理部分的大量负担。您仍然需要启用混合模式,但四元体大小的减小,以及片段着色器中执行的操作的简化,将带来更好的性能ce总的来说。

如果没有看到你的着色器,我会说你这里有动态分支问题,因此无法利用完整的GPU管道。试着手动展开循环,看看它是否解决了问题。感谢这个答案-这篇文章和进一步的阅读确实帮助我更多地理解了GLSL,以及分支和循环如何杀死t并行化。我很想这样做,但我不认为GL混合可以达到我想要的奇偶效果(请参阅我更新中的着色器代码),因为一切都被钳制得太早了。有没有办法让附加效果超过1.0,然后使用我自己的钳制规则(
a=abs(mod(a,2.0)-1.0)
)?@jhabbott-您仍然可以进行加法混合,每一次圆的输出值按您使用的圆数的倒数(本例中为1/10)进行缩放。然后,您可以将模数作为第二次传递应用,从第一次传递中获取输入,并按圈数将其放大。这样会丢失一点动态范围(基于所涉及的圈数),但它仍然会很快。我也想到了,但你没有在片段着色器中读取目标缓冲区数据,因此我如何才能访问以前写入的数据?@jhabbott-你应该首先对所有圆进行加法混合,并让你渲染的FBO由纹理支持。对于第二个pass,您可以从该纹理加载,并对其中的颜色执行模运算。或者,您可以使用新的iOS 6.0帧缓冲区加载操作来更快地读取以前输出的颜色。啊,我没有想到使用单独的纹理作为临时存储,谢谢:)