OpenGL GLSL中atan(y/x)和atan2(y,x)有什么区别?

3

我在理解glsl中atan函数的结果方面遇到了一些问题,文档也不是很充分。

例如,我需要将一个顶点转换为球坐标系,转换球坐标系的半径,然后将其转换回笛卡尔坐标系。我正在对半径为2并且以0为中心的icosphere的顶点使用以下变换。

vec3 to_sphere(vec3 P)
{
    float r = sqrt(P.x*P.x + P.y*P.y + P.z*P.z);
    float theta = atan(P.y,(P.x+1E-18));
    float phi= acos(P.z/r); // in [0,pi]
    return vec3(r,theta, phi);
}

vec3 to_cart(vec3 P)
{
    float r = P.x;
    float theta = P.y;
    float phi = P.z;
    return r * vec3(cos(phi)*sin(theta),sin(phi)*sin(theta),cos(theta);
}

void main()
{
    vec4 V = gl_Vertex.xyz;
    vec3 S = to_sphere(V.xyz);
    S.x += S.y;
    V.xyz = to_cartesian(S);

    gl_Position = gl_ModelViewProjectionMatrix * V;
}

如果我使用atan(y/x)atan2(y,x),结果会不同。 我添加了小的1E-18常量以避免极点。

为什么会这样呢?我猜想atan(y/x)atan2(y,x)返回的值有不同的范围。 特别是在此实现中,我认为theta应该在[0-Pi]范围内,而Phi则在[0,2Pi]范围内。

我对吗?是否有更精确的球坐标转换实现?

1个回答

8

atan2 函数可以正确处理所有四个象限的情况,并且可以处理 x==0 的情况。

atan2(-1,-1) 正确返回 -3/4*PI,而 atan(-1/-1) 则返回 1/4*PI


那我应该坚持使用atan2进行正确的球面坐标转换吗? - linello
@linello 是的,你应该这样做。如果你没有坐标,atan才有用,即使如此也应该小心使用。 - Arpegius
令人惊讶的是,https://www.opengl.org/sdk/docs/man/html/atan.xhtml 实际上对于 atan(y,x) 表示:“如果 x 为零,则结果未定义。” 如果这是真的,那么 atan(y,x) 几乎没有用处。这似乎很可能是文档错误。 - david van brink
4
《GLSLang规范文档》第8.1节(PDF链接)表示:“如果x和y都是0,则结果未定义”,这使得它可以完全有用。 - ratchet freak
1
呼!秩序恢复了。 - david van brink
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接