在 GLSL(特别是我正在使用的 3.00)中,有两个版本的
atan()
:atan(y_over_x)
只能返回-PI/2、PI/2之间的角度,而atan(y/x)
可以考虑所有 4 个象限,因此角度范围涵盖了从 -PI、PI 的所有内容,很像 C++ 中的 atan2()
。
我想使用第二个 atan
将 XY 坐标转换为角度。
但是,GLSL 中的atan()
除了在x = 0
时不能处理之外,还不是很稳定。尤其是在 x
接近于零的情况下,除法可能会溢出,从而导致相反的角度(您会得到接近 -PI/2 的值,而您假设会得到大约 PI/2)。
我们可以在 GLSL atan(y,x)
之上构建什么好的、简单的实现以使其更健壮?
最佳答案
我将回答我自己的问题以分享我的知识。我们首先注意到不稳定性发生在 x
时。接近于零。但是,我们也可以将其翻译为 abs(x) << abs(y)
.所以首先我们将平面(假设我们在一个单位圆上)分成两个区域:一个是 |x| <= |y|
还有一个 |x| > |y|
,如下图:
我们知道 atan(x,y)
在绿色区域更加稳定——当 x 接近于零时,我们只是有一个接近 atan(0.0) 的值,它在数值上非常稳定,而通常的 atan(y,x)
在橙色区域更稳定。你也可以说服自己这种关系:
atan(x,y) = PI/2 - atan(y,x)
适用于所有未定义的非原点 (x,y),我们正在谈论 atan(y,x)
能够返回-PI,PI整个范围内的角度值,而不是atan(y_over_x)
它只返回 -PI/2、PI/2 之间的角度。因此,我们强大的 atan2()
GLSL 的例程非常简单:
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
这是真的,因为它的范围是 (-PI/2, PI/2)。
关于c++ - GLSL 上的强大 atan(y,x) 用于将 XY 坐标转换为角度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26070410/