我正在尝试使用 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
所有着色器制服并glDrawElements
分别绘制四边形五次(使用不同的颜色和圆圈参数),并且我的混合模式是相加的,因此不同的颜色相加很好地给出我想要的图案,完美!
请记住,这是一个实验,所以我试图了解 GL 和 GLSL 而不是画圆圈。
现在我认为只绘制一次四边形并将所有 10 个圆的参数传递到统一数组(centers[10]
、radii[10]
等)中,在 GLSL 中循环它们并将它们在着色器中产生的颜色相加会更有效. 所以我编写了这个着色器并重构了我的代码以一次传递所有的圆形参数。我得到了正确的结果(输出看起来完全一样),但我的帧速率从 15fps 下降到大约 3fps - 它慢了五倍!
着色器代码现在有循环,但使用相同的数学计算每对圆的 alpha 值。为什么这么慢?当然,我所做的工作比填充整个屏幕五次而 GL 进行五次加法混合(即读取像素值、混合和写回)要少吗?现在我只是计算累积的颜色并填充整个屏幕一次?
谁能解释为什么我认为的优化会产生相反的效果?
更新:将此代码粘贴到ShaderToy以查看我在说什么。
#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);
}