Ogre中的四元數Quaternion與旋轉

來源:互聯網
上載者:User

想象一個物體在3D空間中移動的過程,該物體必然會涉及到旋轉。例如一個怪物,他的運動方向會改變,要改變其方向只需要對其進行旋轉即可。

旋轉的方式大致分為三種:Euler旋轉,矩陣旋轉,以及四元數旋轉。

這裡稍微記錄下我目前對於四元數旋轉的理解。對於四元數方面的數學,以及其原理,這裡不關心,只需要學會如何使用即可。

無論是哪一種旋轉,物體與該物體的局部座標系之間的相對位置,相對方位都是不會改變的。因此,在進行兩個局部旋轉(即相對於局部座標系)時,要注意結果可能不是你預期的。

對於Euler旋轉,OGRE中為SceneNode提供了yaw, pitch, roll之類的介面。這些介面預設都是參照局部座標系旋轉,可以通過第二個參數來指定,例如 yaw( Degree( 90 ), SceneNode::TS_WORLD );

OGRE中的Quaternion類用於四元數處理。該類(也可以說是四元數本身)有四個成員:x,y,z,w。這四個數分別代表什嗎?

在OGRE論壇上我找到了一些可以讓人很容易理解的資訊:

Quaternions can seem pretty daunting because of the use of 'imaginary' numbers. It's much easier to understand if you just ignore this concept completely. The basic formula for creating a quaternion from angle/axis is:

Q = cos (angle/2) + i (x * sin(a/2)) + j (y * sin(a/2)) + k(z * sin(a/2))

or

Code:

Q.w = cos (angle / 2)

Q.x = axis.x * sin (angle / 2)

Q.y = axis.y * sin (angle / 2)

Q.z = axis.z * sin (angle / 2)

稍微忽略下那些複數之類的概念,使用角度/軸的方式建立四元數的公式為:

Q = cos (angle/2) + i (x * sin(a/2)) + j (y * sin(a/2)) + k(z * sin(a/2))

對應的代碼為:

Q.w = cos (angle / 2)

Q.x = axis.x * sin (angle / 2)

Q.y = axis.y * sin (angle / 2)

Q.z = axis.z * sin (angle / 2)

再看一下OGRE中關於Quaternion的一個構造四元數的函數原始碼:

void Quaternion::FromAngleAxis (const Radian& rfAngle,

const Vector3& rkAxis)

{

// assert: axis[] is unit length

//

// The quaternion representing the rotation is

// q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)

Radian fHalfAngle ( 0.5*rfAngle );

Real fSin = Math::Sin(fHalfAngle);

w = Math::Cos(fHalfAngle);

x = fSin*rkAxis.x;

y = fSin*rkAxis.y;

z = fSin*rkAxis.z;

}

雖然可以說四元數中的w代表旋轉量,x, y, z代表對應軸,但是這也不全正確。因為我們看到,對於真正的旋轉量啊之類的資料,是需要進行有些公式變換後,才得到w, x, y, z 的。

但是,即使如此,我們還是可以這樣簡單地構造一個四元數用於旋轉:

Quaternion q( Degree( -90 ), Vector3::UNIT_X );

該建構函式第一個參數指定旋轉角度,第二個參數指定旋轉軸(可能不是),上面的代碼就表示,饒著X軸(正X方向),旋轉-90度。將該四元數用於一個Scene Node旋轉:

sceneNode->rotate( q );

即可實現該node饒X軸旋轉-90度的效果。

再看一下OGRE tutorial中的一段代碼:

Vector3 src = mNode->getOrientation() * Vector3::UNIT_X;

Ogre::Quaternion quat = src.getRotationTo(mDirection);

mNode->rotate(quat);

SceneNode的getOrientation獲得該node的方位,用一個四元數來表示。什麼是方位?這裡我也不清楚,但是對於一個四元數,它這裡表示的是一種旋轉位移,位移於初始朝向。

OGRE論壇上有這麼一段話:

The reason there's no other way to convert a quaternion to a vector is because a quaternion is relative. It has no direction.

With a direction (like a vector) you could say "face north east".

But with a quaternion, you say "face 45 degrees clockwise from whatever direction you are already facing" (very simplified example). Without knowing which way the object is already facing, a quaternion is virtually meaningless with respect to orientation. So we just default it to some initial direction, like Unit Z, and make all orientations relative to that.

然後,getOrientation() * Vector3::UINT_X又會得到什嗎?我可以告訴你,第一句代碼整體的作用就是擷取該物體當前面向的方向。關於四元數與向量相乘,:

可以進一步看出,四元數表示了一個旋轉位移,它與一個向量相乘後就獲得了另一個向量。該結果向量代表了這個旋轉位移所確定的方向。

那麼第一句代碼中為什麼要乘上UNIT_X呢?因為這裡所代表的物體的初始朝向就是正X方向。

第二句話由向量構造一個四元數,它表示,從當前的朝向,旋轉到目的朝向所需要的一個四元數。第三句話就直接使用該四元數來旋轉該node。但是有時候似乎旋轉不正確(在我的實驗中,我使用的模型其初始朝向是負Y方向,在初始化時我又將其饒著X軸旋轉了負90度,後來旋轉時就不正確了),這可以通過rotate( q, SceneNode::TS_WORLD)來矯正。(所以估計是之前旋轉導致的錯誤)(有時候我在想,為什麼對於所有物體的旋轉之類的變換,都不直接參照於全局座標系?因為我們最終看到的就是在全局座標系中。)

注意,當旋轉角度是180度時,這裡就會出現錯誤,為了防止這種錯誤,可以這樣做:

Vector3 src = mNode->getOrientation() * Vector3::UNIT_X;

if ((1.0f + src.dotProduct(mDirection)) < 0.0001f)

{

mNode->yaw(Degree(180));

}

else

{

Ogre::Quaternion quat = src.getRotationTo(mDirection);

mNode->rotate(quat);

} // else

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.