2012-10-22 140 views
4

我在世界空間中的一些物體,讓我們在(0,0,0)說,並希望將其旋轉至面(10,10,10)。四元數 - 旋轉到

我該如何使用四元數來做到這一點?

+1

你問關於四元數旋轉背後的數學或如何實現它?如果你明白四元數是如何工作的,用C++實現它非常簡單,取決於這是否是一次性事情,可以用幾行mathy代碼完成。如果你不明白四元數,這是錯誤的地方 –

+0

@ AK4749 - 嗨,我在問這個幕後的數學問題。有兩個Vector3,其中(1)是對象的位置,(2)是我希望此對象旋轉到的位置 - 我如何計算將代表此旋轉的四元數? – PeeS

+0

四元數在矩陣和矢量之間進行插值很好。您需要至少兩組兩個向量(位置+方向)來構建兩個矩陣(即位置+旋轉)。然後將這些矩陣轉換爲四元數,插入它們並將其轉換回矩陣。 –

回答

7

這個問題沒有引起太大的意義。你說你想要一個對象「面對」一個特定的點,但是這不能提供足夠的信息。

首先,什麼意思這個方向?在OpenGL中,這意味着本地參考座標系中的座標軸與某個外部座標系中的指定方向對齊。爲了使這種對齊發生,我們需要知道對象的相關軸當前「面對」的方向。

然而,這仍然無法定義一個唯一的變革。即使你知道什麼方向,使-z軸點,對象是仍然可以自由地旋轉各地該軸。這就是爲什麼功能gluLookAt()要求您提供'at'方向'向上'的方向。

接下來我們需要知道的是最終結果需要的格式是什麼?對象的方向通常以四元數格式存儲。但是,如果要以圖形方式旋轉對象,則可能需要旋轉矩陣。

因此,讓一些假設。我會假設你的物體以世界點c爲中心,並且具有默認對齊。即對象的Xÿ,並ž軸與世界Xÿ,並ž軸對準。這意味着對象相對於世界的方向可以表示爲單位矩陣或身份四元數:(使用四元數慣例,其中w第一)。

如果您希望將調整對象的-z軸與點p最短旋轉:= [p.x p.y p.z],那麼你將φ圍繞軸線一個旋轉。現在我們會找到這些值。首先,我們發現軸線一個通過歸一化矢量PC然後取跨產品與單位長度-z載體中,然後再歸一化:

一個 =歸一化(交叉積(- z,標準化(pc)));

通過取它們的點積的反餘弦發現這兩個單位矢量之間的最短角:

φ= ACOS(dotProduct(-z,正常化(對-C)));

不幸的是,這是由兩個向量形成的角度的絕對值的度量。我們需要弄清楚在a附近旋轉時它是正面還是負面。必須有一種更優雅的方式,但首先想到的方法是找到第三個軸,垂直於a-z,然後從它的點積乘以我們的目標軸。可見:

b =交叉積(一個-z);

如果(dotProduct(b,正常化(對-C))< 0)φ=-φ;

一旦我們有了我們的軸和角度,把它變成一個四元數是容易的:

q = [cos(φ/ 2)SIN(φ/ 2)一個];

這個新的四元數表示對象的新方向。可以將其轉換爲用於渲染目的的矩陣,或者可以使用它來直接旋轉對象的頂點,如果需要,可以使用四元數乘法的規則。

+0

非常感謝您的一個很好的解釋 – PeeS

0

您可能需要使用球面線性插值(球面線性插值)。關於如何做到這一點在C++

0

計算表示兩個矢量之間的旋轉可以在OGRE源代碼中找到用於Ogre::Vector3 class四元數的一個例子參考看到此article

1

爲了迴應您的澄清並回答這個問題,我無恥地複製了一個非常有趣且整潔的算法,用於查找兩個向量之間的四元數,看起來像我以前從here以前從未見過的。在數學上,它似乎是有效的,因爲你的問題是關於它背後的數學,我相信你可以將這個僞代碼轉換成C++。

quaternion q; 
vector3 c = cross(v1,v2); 
q.v = c; 
if (vectors are known to be unit length) { 
    q.w = 1 + dot(v1,v2); 
} else { 
    q.w = sqrt(v1.length_squared() * v2.length_squared()) + dot(v1,v2); 
} 
q.normalize(); 
return q; 

讓我知道你是否需要幫助澄清僞代碼的任何位。應該是直截了當的。

dot(a,b) = a1*b1 + a2*b2 + ... + an*bn 

cross(a,b) = well, the cross product. it's annoying to type out and 
can be found anywhere. 
+1

謝謝你的解釋。我的問題已經解決,感謝您的描述和JCooper的。 – PeeS