我正在对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
的上述组合没有重现与使用三元运算符的方法相同的结果有什么原因?
答案 0 :(得分:2)
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;
上面的代码将comp设置为v1或v2,具体取决于vTest的当前值。一定要测试这个显式实现与编译器生成的三元impl,以查看哪一个更快。