iPhone 6 Plus上的GLSL atan给出了错误的结果

Sep*_*ppo 5 iphone glsl ios

请考虑以下片段着色器.当我在模拟器或iPhone 5(8.3)上运行时,它会显示预期的颜色(红色).如果我在iPhone 6 Plus(8.2)上运行它会转到第二个if子句(绿色),这显然是错误的,因为正确的计算结果应该在1.22左右.如果我直接将atan参数作为编译时常量提供,则计算有效.

我已经尝试了最新的Xcode 6.2和最新的6.3 Beta.

void main()
{
    highp float y = 0.57;
    highp float x = 0.21;

    highp float a = atan(y, x); 
    // works if changed to atan(0.57, 0.21);
    // does not work if changed to atan(y / x);

    if (a > 1.2 && a < 1.25)
    {
        // Should always come here
        // Works on Simulator, iPhone 5
        gl_FragColor = vec4(1, 0, 0, 1);
    }
    else if (a > 1.5 && a < 1.55)
    {
        // Comes here on iPhone 6 Plus
        gl_FragColor = vec4(0, 1, 0, 1);
    }

    return;
}
Run Code Online (Sandbox Code Playgroud)

更新:情节变粗.

如果我以下列方式更改着色器,则错误消失并且atan返回正确的值.似乎无论我对x和y放置什么都必须是编译时间常量.这解决了我的生产代码中的问题以及根本没有编译时常量的问题.BTW同样的问题影响acos和asin.

highp float y = texCoord.x;
highp float x = texCoord.x;

if (x == x) // Removing this line makes error return
{
    x = 0.21;
}

if (y == y) // Removing this line makes error return
{
    y = 0.57;
}
Run Code Online (Sandbox Code Playgroud)

另一个例子.这就是我实际使用它的方式.

如果我这样计算,它在iPhone 6上失败了:

float y = sin(lon2 - lon1) * cos(lat2);
float x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon2 - lon1);

float bearing = atan(y, x) + 2.0 * pi;

return mod(bearing, 2.0 * pi);
Run Code Online (Sandbox Code Playgroud)

如果我这样做,它的工作原理:

float y = texCoord.y;
float x = texCoord.x;

if (y == y)
{
    y = sin(lon2 - lon1) * cos(lat2);
}

if (x == x)
{
    x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon2 - lon1);
}

float bearing = atan(y, x) + 2.0 * pi;

return mod(bearing, 2.0 * pi);
Run Code Online (Sandbox Code Playgroud)

小智 1

这看起来像是编译时常量传播错误。

您的if (x == x)子句看起来可以被编译器消除,但由于它是一个 fp 值,因此它实际上是对NaN.

即,将任何内容与 NaN 进行比较总是错误的,即使您将值与其自身进行比较也是如此。

看起来这个测试正在阻止编译器传播您的常量值,如果您要求从编译中获得汇编程序输出,这应该是显而易见的。