opengl,转换球形坐标从笛卡尔坐标

时间:2017-06-11 12:04:06

标签: opengl

我试图从笛卡尔坐标系中的一个点找到球面坐标中的角度theta和phi。

我找到答案,这不正确。但我无法弄清楚发生了什么。 请帮帮我。

这是我的代码:

Vector4 g_eye(8.0f, 8.0f, 8.0f);

Vector4 g_lookat(0.0f, 0.0f, 0.0f);

Vector4 g_up(0.0f, -1.0f, 0.0f);

struct spherical_sys
{

    spherical_sys(Vector4& p)
    {
        _dirty = 1;
       _pos = p;
       _pos.w = 0.0f;
       get_spherical(_pos, _theta, _phi, _r);
    }

    float getTheta()
    {
       return _theta;
    }

    float getPhi()
    {
       return _phi;
    }

    void setTheta(float t)
    {
       _theta = t;
       _dirty = 1;
    }

    void setPhi(float t)
    {
       _phi = t;
       _dirty = 1;
    }

    Vector4 get_pos()
    {
       if (_dirty)
       {
           float sin_phi, cos_phi;
           float sin_theta, cos_theta;
           FastMath::SinCos(_phi, sin_phi, cos_phi);
           FastMath::SinCos(_theta, sin_theta, cos_theta);

           _pos.w = 0.0f;
           _pos[0] = _r* cos_phi * cos_theta;
           _pos[1] = _r* sin_phi;
           _pos[2] = _r* cos_phi * sin_theta;
           _dirty = 0;
       }
       return _pos;
   }
private:
   void get_spherical(Vector4& dir, float& theta, float& phi, float& r)
   {
       r = dir.Length();
       dir.Normalize();
       phi = FastMath::ACos(Vector3Dotf(dir, Vector4(0.0f, 1.0f, 0.0f, 0.0f)));
       Vector4 v = Vector3CrossProduct(Vector4(0.0f, 1.0f, 0.0f, 0.0f), dir);
       if (v.x < 0.0f)
       {
           phi *= -1;
           phi = phi + MATH_PI * 0.5f;
       }
       else
       {
           phi = phi - MATH_PI * 0.5f;
       }
        theta = FastMath::ACos(Vector3Dotf(dir, Vector4(1.0f, 0.0f, 0.0f, 0.0f)));
        v = Vector3CrossProduct(Vector4(1.0f, 0.0f, 0.0f, 0.0f), dir);
       if (v.y < 0.0f)
       {
           theta *= -1;
       }
    }
    float _phi;
    float _theta;
    float _r;
    Vector4 _pos;
    int _dirty;
};
spherical_sys _teye(g_eye);
spherical_sys _tup(g_up);

_teye.get_pos()的答案.x,_teye.get_pos()。y,_ teye.get_pos()。z为6.531521,-7.998896,-9.238880。

显然,出了点问题。

1 个答案:

答案 0 :(得分:2)

看起来像几个问题。我不会评论你的代码结构,只是转换....

供参考,以下是Cartesian-Spherical conversions的等式。

您从Spherical转换为笛卡儿的行为不正确。它看起来既倒退也错......以下是正确的公式(请参阅下面关于交换y / z的说明)

       _pos[0] = _r* sin_theta * cos_phi;
       _pos[1] = _r* sin_theta * sin_phi;
       _pos[2] = _r* cos_theta;

等式中的Dot积无效,结果只是向量的y分量:

phi = FastMath::ACos(dir.y);

另一个问题是你似乎已经交换了Y轴和Z轴。只要你保持一致,这很好。即使使用此交换,您从球形到笛卡尔的转换仍然不正确。让我们保持古典。

phi = FastMath::ACos(dir.z);

接下来,您使用交叉产品来帮助修复acos功能的范围。这是一个聪明的&#39;诀窍,直到你compute the product by hand并且看到你实际上只是检查Z坐标。

cross( (0,1,0), (x,y,z) ) => (z,0,-x)

接下来,我们将检查theta计算:

theta = FastMath::ACos(Vector3Dotf(dir, Vector4(1.0f, 0.0f, 0.0f, 0.0f)));

再一次,Dot prodcut是无用的,你只是抓住了x

theta = FastMath::ACos(dir.x);

简化后,您可以看到缺少组件并且使用了错误的trig功能。使用ArcTan和 ArcCos。

theta = ATan2(dir.y, dir.x);

再次,看起来您正在使用交叉产品来修复范围。然而,手动计算产品:

cross ( (1,0,0) , (x,y,z) ) => (0,-z,y)

所以你再次只是检查dir.z组件的符号,不需要额外的计算。

我的建议是先使用经典方程来回转换。不要担心修复范围,以后可以在代码工作时执行此操作。

一旦有效,请修复范围。范围正确后,担心交换Z轴和Y轴(或不要)。

如果您不确定Dot产品或Cross产品的作用,请手动完成。忽略这些函数的几何重要性,您会发现它们正在浪费计算并且通常会使代码复杂化。

祝你好运!