方向向量轉四元數

之前寫過一篇方向向量轉歐拉角的,相對來說歐拉角還是有一些限制,現在研究下方向向量轉四元數公式。

該四元數能夠使方向向量從Z軸(0,0,1)旋轉至(X,Y,Z)。四元數可以理解爲繞某軸(x,y,z)旋轉角度w,記爲(cos(w/2),sin(w/2)x,sin(w/2)y,sin(w/2)z)。

需要注意的是,對於四元數來說,如果對應的四個值都互爲相反數,可以理解爲這兩個四元數對應的旋轉相同。比方說,四元數(a,b,c,d)和四元數(-a,-b,-c,-d)對應的旋轉是相同的。

使用unity函數進行轉換的代碼如下


    public Quaternion CalQuaternion(Vector3 dir)
    {
        Quaternion cal = new Quaternion();
        Vector3 euler = Quaternion.LookRotation(dir).eulerAngles;

        //歐拉角Y: cosY = z/sqrt(x^2+z^2)
        float CosY = dir.z / Mathf.Sqrt(dir.x * dir.x + dir.z * dir.z); 
        float CosYDiv2 = Mathf.Sqrt((CosY + 1) / 2);
        if (dir.x < 0) CosYDiv2 = -CosYDiv2; 

        float SinYDiv2 = Mathf.Sqrt((1-CosY) / 2);

        //歐拉角X: cosX = sqrt((x^2+z^2)/(x^2+y^2+z^2)
        float CosX = Mathf.Sqrt((dir.x * dir.x + dir.z * dir.z) / (dir.x * dir.x + dir.y * dir.y + dir.z * dir.z));
        if (dir.z < 0) CosX = -CosX;
        float CosXDiv2 = Mathf.Sqrt((CosX + 1) / 2);
        if (dir.y > 0) CosXDiv2 = -CosXDiv2;
        float SinXDiv2 = Mathf.Sqrt((1 - CosX) / 2);

        //四元數w = cos(x/2)cos(y/2)
        cal.w = CosXDiv2 * CosYDiv2;
        //四元數x = sin(x/2)cos(y/2)
        cal.x = SinXDiv2 * CosYDiv2;
        //四元數y = cos(x/2)sin(y/2)
        cal.y = CosXDiv2 * SinYDiv2;
        //四元數z = sin(x/2)sin(y/2)
        cal.z = -SinXDiv2 * SinYDiv2;


        CalCosX = CosX;
        CalCosY = CosY;
        RightCosX = Mathf.Cos(Mathf.Deg2Rad * (Quaternion.LookRotation(dir).eulerAngles.x));
        RightCosY = Mathf.Cos(Mathf.Deg2Rad * (Quaternion.LookRotation(dir).eulerAngles.y));
        RightEulers = Quaternion.LookRotation(dir).eulerAngles;

        return cal;
    }

實際還是使用歐拉角轉四元數的方式進行的換算,旋轉次序還是z,x,y。同時還用到了三角函數轉半三角函數的公式。

需要注意的是,由於之前提到的原因,得到的四元數和unity自帶的Quaternion.LookRotation(dir)可能是相反的,實際代表的是一種旋轉。在計算中需要注意得到的三角函數的正負。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章