我将回答自己的问题,分享我的知识。我们首先注意到不稳定性出现在x
接近于零的情况下。然而,我们也可以将其转换为abs(x) << abs(y)
。因此,我们首先将平面(假设我们在单位圆上)分成两个区域:一个是|x| <= |y|
,另一个是|x| > |y|
,如下所示:
![two regions](https://i.imgur.com/85MbHs4.png)
我们知道,在绿色区域内,atan(x,y)
更加稳定——当x接近于零时,我们得到了与atan(0.0)
非常稳定的结果,而通常的atan(y,x)
在橙色区域更加稳定。您还可以亲自验证以下这个关系:
atan(x,y) = PI/2 - atan(y,x)
对于所有非原点(x,y),该函数都成立,即使在其未定义的情况下,我们也谈论能够返回从-PI到PI整个范围内的角度值的atan(y,x)
,而不是仅返回在-PI/2到PI/2之间的角度值的atan(y_over_x)
。因此,我们健壮的GLSL的atan2()
例程非常简单:
float atan2(in float y, in float x)
{
bool s = (abs(x) > abs(y));
return mix(PI/2.0 - atan(x,y), atan(y,x), s);
}
顺便提一下,数学函数 atan(x)
的恒等式实际上是:
atan(x) + atan(1/x) = sgn(x) * PI/2
这是正确的,因为它的范围是(-π/2, π/2)。
![图表](https://istack.dev59.com/lvnfy.webp)
atan()
函数除了无法处理x = 0的情况之外... -- 这是不正确的:atan(y,x)
被设计用来处理x或y(但不能同时为零)的情况。当y为正时,atan(y,0.)
返回PI/2
,当y为负时,返回-PI/2
。 - Jonathan Lidbeckatan(y,x)
返回“其正切为y / x的角度”。按原样使用,可以看出其规范不能保证在x = 0
时返回可用结果,因为y/0
未定义。这仍然与Web版本一致。 - HuaTham