Robust atan(y,x) on GLSL for converting XY coordinate to angle

后端 未结 5 706
花落未央
花落未央 2021-02-02 16:34

In GLSL (specifically 3.00 that I\'m using), there are two versions of atan(): atan(y_over_x) can only return angles between -PI/2, PI/2, while

5条回答
  •  佛祖请我去吃肉
    2021-02-02 17:10

    I'm going to answer my own question to share my knowledge. We first notice that the instability happens when x is near zero. However, we can also translate that as abs(x) << abs(y). So first we divide the plane (assuming we are on a unit circle) into two regions: one where |x| <= |y| and another where |x| > |y|, as shown below:

    two regions

    We know that atan(x,y) is much more stable in the green region -- when x is close to zero we simply have something close to atan(0.0) which is very stable numerically, while the usual atan(y,x) is more stable in the orange region. You can also convince yourself that this relationship:

    atan(x,y) = PI/2 - atan(y,x)
    

    holds for all non-origin (x,y), where it is undefined, and we are talking about atan(y,x) that is able to return angle value in the entire range of -PI,PI, not atan(y_over_x) which only returns angle between -PI/2, PI/2. Therefore, our robust atan2() routine for GLSL is quite simple:

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

    As a side note, the identity for mathematical function atan(x) is actually:

    atan(x) + atan(1/x) = sgn(x) * PI/2
    

    which is true because its range is (-PI/2, PI/2).

    graph

提交回复
热议问题