2013-01-19 103 views
2

因此,我在OpenGL場景中爲我的3D對象實現旋轉,到目前爲止基本旋轉本身(使用四元數)工作正常。我也大多解決了「查看」問題,這樣我就可以使任何3D對象,包括相機在內,精確無誤地面對3D空間中的任何點。當只需要X-Y旋轉時,3D對象正在沿着所有三個軸旋轉

然而,指揮的對象時面對一個給定的點,這將經常沿其局部Z軸滾動;看到這張圖片,小船正在看紅色,綠色和藍色線條交匯點。你可以看到它看起來不像人們所期望的那樣,例如,沿着它的Y軸旋轉面對綠線,然後沿着它的X軸向下傾斜以面對三條線的交匯點。

enter image description here

我並不想這樣。我寧願直視那一點,但順時針傾斜一點(從正面看),使它的翼尖處於相同的Y水平。由於面向某一點的整個點是局部Z軸穿過該點,所以不應該如何繞物體的本地Z軸旋轉物體,但結果的旋轉始終傾斜,儘管偏斜似乎取決於物體的相對位置及其焦點。

在任何情況下,這裏是我的LookAt()代碼,我想要修改這些代碼,以便我可以更好地控制最終的Z軸旋轉。

void Thing::LookAt(sf::Vector3<float> Target) 
{ 
    ///Derived from pseudocode found here: 
    ///http://stackoverflow.com/questions/13014973/quaternion-rotate-to 
    //Reset the rotation to default 
    m_Orientation = Quaternion(); 

    //Get the normalized vector from the camera position to Target 
    sf::Vector3<double> VectorTo(Target.x - m_Position.x, 
           Target.y - m_Position.y, 
           Target.z - m_Position.z); 
    //Get the length of VectorTo 
    double VectorLength = sqrt(VectorTo.x*VectorTo.x + 
           VectorTo.y*VectorTo.y + 
           VectorTo.z*VectorTo.z); 
    //Normalize VectorTo 
    VectorTo.x /= VectorLength; 
    VectorTo.y /= VectorLength; 
    VectorTo.z /= VectorLength; 

    //Straight-ahead vector 
    sf::Vector3<double> LocalVector = m_Orientation.MultVect(sf::Vector3<double>(0, 0, -1)); 

    //Get the cross product as the axis of rotation 
    sf::Vector3<double> Axis(VectorTo.y*LocalVector.z - VectorTo.z*LocalVector.y, 
          VectorTo.z*LocalVector.x - VectorTo.x*LocalVector.z, 
          VectorTo.x*LocalVector.y - VectorTo.y*LocalVector.x); 
    //Normalize the axis 
    //Get the length of VectorTo 
    double AxisLength = sqrt(Axis.x*Axis.x + 
          Axis.y*Axis.y + 
          Axis.z*Axis.z); 
    //Normalize VectorTo 
    Axis.x /= AxisLength; 
    Axis.y /= AxisLength; 
    Axis.z /= AxisLength; 

    //Get the dot product to find the angle 
    double DotProduct = (VectorTo.x*LocalVector.x + 
         VectorTo.y*LocalVector.y + 
         VectorTo.z*LocalVector.z); 
    double Angle = acos(DotProduct); 

    //Determine whether or not the angle is positive 
    //Get the cross product of the axis and the local vector 
    sf::Vector3<double> ThirdVect(Axis.y*LocalVector.z - Axis.z*LocalVector.y, 
            Axis.z*LocalVector.x - Axis.x*LocalVector.z, 
            Axis.x*LocalVector.y - Axis.y*LocalVector.x); 
    //If the dot product of that and the local vector is negative, so is the angle 
    if (ThirdVect.x*VectorTo.x + ThirdVect.y*VectorTo.y + ThirdVect.z*VectorTo.z < 0) 
    { 
     Angle = -Angle; 
    } 

    //Finally, create a quaternion 
    //Quaternion AxisAngle; 
    m_Orientation.FromAxisAngle(Angle, Axis.x, Axis.y, Axis.z); 
    m_Orientation.RotationMatrix(m_RotationMatrix); 
} 

我的問題是,我不知道如何獲得對圍繞Z軸的最終旋轉的控制。請注意,當我從m_Orientation四元數中提取一個Z角時,它告訴我上圖所示的船繞其Z軸旋轉0弧度。我嘗試手動將Z分量設置爲0並重新正常化四元數,但是(顯然我猜)沒有工作。目前,可以很好地計算船舶旋轉「頂部向上」所需的特定Z分量,即,使得其兩個翼尖處於相同的Y水平上並且其Y軸陡峭儘可能,但我想更清楚地知道如何操作最終的Z軸旋轉。任何想法或資源?

回答

2

如果您關於任意軸執行一次旋轉,那麼很自然會得到這個結果。你有沒有想到這個轉變?

但是,有一種更簡單的方法來構造旋轉矩陣。你只需要找到軸被映射到的向量。

所以例如如果模型指向-z,則z軸(正向)映射到z = VectorToz = -VectorTo。爲了保持向上的方向,你需要定義它。比方說up = (0, 1, 0)。然後將x軸映射到x = z x up的叉積。最後你需要重新計算向上矢量以保持與y = x x z的純旋轉。 (中間的x指定了叉積運算符)。

已經計算出這些向量,你現在可以構建變換矩陣如下(歸一化向量):

/x.x y.x z.x 0 \ 
    | x.y y.y z.y 0 | 
T = | x.z y.z z.z 0 | 
    \ 0 0 0 1/

根據您的API,你可能需要轉這個矩陣。

如果您需要四元數,您可以使用像this one這樣的方法。

+0

謝謝!儘管最終的結果是船舶顛倒倒退,但這種方式大多可行。我發現我需要使向上的向量爲'(0,-1,0)',並且X軸向量爲'-VectorTo',以便船舶正確定位。這可能意味着我在代碼中犯了一個錯誤,我確信我會找到它。另一個說明,這是否意味着沒有簡單的方法直接與四元數做到這一點? IIRC Unity引擎的四元數可以佔用一個向量(http://docs.unity3d.com/Documentation/ScriptReference/Quaternion.LookRotation.html),它們也可以在引擎蓋下使用矩陣嗎? – GarrickW

+0

這聽起來像你真的需要轉置矩陣。但是,如果你有一個工作解決方案,沒關係。可能有一種方法可以直接計算四元數。但是,我不能說如何。 –