iOS 上的片段着色器行为
Fragment shader behavior on iOS
我正在为 iOS 应用对片段着色器进行一些基本优化。我想将几种颜色中的一种分配给 gl_FragColor
。我的第一次尝试使用了三元运算符。这会在模拟器和 iPhone 5C:
上正确显示内容
lowp float maxC = max(color.r, max(color.g, color.b);
lowp float minC = min(color.r, min(color.g, color.b);
gl_FragColor.rgb = (maxC > 1.0 ? result0 : (minC < 0.0 ? result1 : result2));
我尝试用 mix
和 step
的组合替换三元运算符,看看我是否可以用更少的分支复制上述逻辑。不幸的是,这在模拟器中有效,但在 iOS 设备上无效:
lowp float step0 = step(0.0, minC);
lowp float step1 = step(1.001, maxC);
lowp vec3 mix0 = mix(result1, result2, step0);
gl_FragColor.rgb = mix(mix0, result0, step1);
具体来说,一些在模拟器中正确绘制的屏幕白色区域在设备上被错误地绘制为黑色区域。其他一切看起来都很好。
上述 step
和 mix
的组合无法重现与使用三元运算符的方法相同的结果的某些原因是什么?
OpenGL 着色器中浮点运算的具体细节可能难以理解。可能发生的情况是三元运算符被 GLSL 编译器优化为乘以零运算。查看 avoiding-shader-conditionals 了解有关如何将条件折叠成乘法或其他简单操作的信息。最有用的效用函数是:
float when_eq(float x, float y) {
return 1.0 - abs(sign(x - y));
}
一个使用示例是:
float comp = 0.0;
comp += when_eq(vTest, 0.0) * v1;
comp += when_eq(vTest, 1.0) * v2;
上面的代码将根据 vTest 的当前值将 comp 设置为 v1 或 v2。请务必测试此显式实现与编译器生成的三元实现,以查看哪个更快。
我正在为 iOS 应用对片段着色器进行一些基本优化。我想将几种颜色中的一种分配给 gl_FragColor
。我的第一次尝试使用了三元运算符。这会在模拟器和 iPhone 5C:
lowp float maxC = max(color.r, max(color.g, color.b);
lowp float minC = min(color.r, min(color.g, color.b);
gl_FragColor.rgb = (maxC > 1.0 ? result0 : (minC < 0.0 ? result1 : result2));
我尝试用 mix
和 step
的组合替换三元运算符,看看我是否可以用更少的分支复制上述逻辑。不幸的是,这在模拟器中有效,但在 iOS 设备上无效:
lowp float step0 = step(0.0, minC);
lowp float step1 = step(1.001, maxC);
lowp vec3 mix0 = mix(result1, result2, step0);
gl_FragColor.rgb = mix(mix0, result0, step1);
具体来说,一些在模拟器中正确绘制的屏幕白色区域在设备上被错误地绘制为黑色区域。其他一切看起来都很好。
上述 step
和 mix
的组合无法重现与使用三元运算符的方法相同的结果的某些原因是什么?
OpenGL 着色器中浮点运算的具体细节可能难以理解。可能发生的情况是三元运算符被 GLSL 编译器优化为乘以零运算。查看 avoiding-shader-conditionals 了解有关如何将条件折叠成乘法或其他简单操作的信息。最有用的效用函数是:
float when_eq(float x, float y) {
return 1.0 - abs(sign(x - y));
}
一个使用示例是:
float comp = 0.0;
comp += when_eq(vTest, 0.0) * v1;
comp += when_eq(vTest, 1.0) * v2;
上面的代码将根据 vTest 的当前值将 comp 设置为 v1 或 v2。请务必测试此显式实现与编译器生成的三元实现,以查看哪个更快。