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

时间:2015-03-31 12:47:37

标签: ios iphone glsl

考虑以下片段着色器。当我在模拟器或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;
}

更新:情节变粗。

如果我按以下方式更改着色器,则错误消失,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;
}

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

如果我这样计算,它在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);

如果我这样做,它就有效:

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);

2 个答案:

答案 0 :(得分:1)

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

您的if (x == x)子句似乎可以被编译器消除,但由于它是一个fp值,它实际上是对NaN的测试。

即。比较任何与NaN相等的东西总是假的,即使你把这个值与自己相比也是如此。

看起来这个测试阻止编译器传播你的常量值,如果你要求汇编输出汇编,这应该是显而易见的。

答案 1 :(得分:0)

我还在iOS13上尝试使用atan的错误 我用这种方法来计算两点之间的角度

float getAngle(vec2 point, vec2 center) {
  float y = point.y - center.y;
  float x = point.x - center.x;
  return atan(y, x);
}

每当我用相同的点值调用此方法时,它就会出错。

vec2 p1 = vec2(40.0, 30.0);
vec2 p2 = vec2(40.0, 30.0);
float angle = getAngle(p1, p2);

似乎要调用atan(0.0,0.0)错误

我能够在iOS上实现此功能的方法是更改​​这样的方法

float getAngle(vec2 point, vec2 center) {
  float y = point.y - center.y;
  float x = point.x + 0.000000001 - center.x;
  return atan(y, x);
}

相加0.000000001可确保两点相减不等于0。