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