2011-11-28 18 views
2

我正在開發在XNA三維spaceshooter作爲學校項目(基本上在小行星帶3D功率UPS),並已着手實施滾動,俯仰和偏航相對於船的局部軸。 (我要強調的是:旋轉方面不絕對/世界X,Y和Z軸)。可悲的是,我一直在努力與這個在過去的幾個星期。谷歌和我的新石器時代的猴子大腦讓我失望了;也許你們可以幫忙!XNA - 3D關於局部(改變)船軸的旋轉 - 我錯過了什麼?

這裏是我的設置:

通過鍵盤輸入,我有以下變量蓄勢待發:

  • yawRadians,從船的初始 位置
  • pitchRadians存儲目標偏航而去,其存儲所希望的間距從 船舶的初始位置遠離
  • rollRadians,其從船的存儲所需的輥 遠s的初始位置

該船還保持着自己的前,後,右,左,上和下單位矢量,這些矢量用於旋轉和推進。 (不同的鍵將推動船舶向前,後方等。這部分工作很好。)

最終,我生成旋轉矩陣mShipRotation,表示船舶的所有旋轉,它被傳遞給船的繪製方法。

我的問題是與旋轉自己。我試過的不同解決方案有不同的結果。以下是我已經走了這麼遠:

方法1 - 相對於絕對/世界X偏航,俯仰和滾轉,Y和Z軸

起初,我天真地使用嘗試按照我的船的更新方法:

qYawPitchRoll = Quaternion.CreateFromYawPitchRoll(yawRadians, pitchRadians, rollRadians);  

vFront = Vector3.Transform(vOriginalFront, qYawPitchRoll); 
vBack = -1 * vFront; 

vRight = Vector3.Transform(vOriginalRight, qYawPitchRoll); 
vLeft = -1 * vRight; 

vTop = Vector3.Transform(vOriginalTop, qYawPitchRoll); 
vBottom = -1 * vTop; 

mShipRotation = Matrix.CreateFromQuaternion(qYawPitchRoll); 

(vOriginalFront,vOriginalRight和vOriginalTop只儲存船的初始方向)

以上實際工作沒有任何錯誤,除了旋轉總是相對於在x,y和z軸,而不是相對於船的前/後/左/右/上/下的載體。這導致該船並不總是像預期的那樣偏航和俯仰。 (具體來說,如果你已經向上傾斜,那麼偏航就會退化爲滾動,這樣就可以理解,因爲這個解決方案中的偏航只是圍繞着世界軸線旋轉。)

我聽說Quarternion。 CreateFromAxisAngle方法,聽起來很完美。我可以將三個四元數旋轉組合在一起,一個圍繞船的每個局部軸。有什麼可能出錯?

方法二 - 四元數。CreateFromAxisAngle

下面是我在船上的更新方法所使用的第二代碼片段:

qPitch = Quaternion.CreateFromAxisAngle(vRight, pitchRadians); 
qYaw = Quaternion.CreateFromAxisAngle(vTop, yawRadians); 
qRoll = Quaternion.CreateFromAxisAngle(vFront, rollRadians); 
qPitchYawAndRoll = Quaternion.Concatenate(Quaternion.Concatenate(qPitch, qYaw), qRoll); 

vFront = Vector3.Normalize(Vector3.Transform(vOriginalFront, qPitchYawAndRoll)); 
vBack = -1 * vFront; 
vRight = Vector3.Normalize(Vector3.Transform(vOriginalRight, qPitchYawAndRoll)); 
vLeft = -1 * vRight; 

vTop = Vector3.Normalize(Vector3.Transform(vOriginalTop, qPitchYawAndRoll)); 
vBottom = -1 * vTop; 

mShipRotation = Matrix.CreateFromQuaternion(qPitchYawAndRoll); 

上述作品完美,如果我只能做一個旋轉在一個時間(偏航,俯仰或滾動),但如果我同時結合了多個旋轉,船開始瘋狂地旋轉並指向許多不同的方向,變得越來越彎曲,直到它完全消失。

我已經嘗試過上述的變體,我首先將音高應用於所有矢量,然後是偏航,然後是滾動,但沒有運氣。

我也試了一下直接使用矩陣,儘管萬向節鎖定的擔憂:

方法3:矩陣

mShipRotation = Matrix.Identity; 

mShipRotation *= Matrix.CreateFromAxisAngle(vRight, pitchRadians); 
mShipRotation *= Matrix.CreateFromAxisAngle(vFront, rollRadians); 
mShipRotation *= Matrix.CreateFromAxisAngle(vTop, yawRadians); 

vFront = Vector3.Normalize(Vector3.Transform(vOriginalFront, mShipRotation)); 
vBack = -1 * vFront; 

vRight = Vector3.Normalize(Vector3.Transform(vOriginalRight, mShipRotation)); 
vLeft = -1 * vRight; 

vTop = Vector3.Normalize(Vector3.Transform(vOriginalTop, mShipRotation)); 
vBottom = -1 * vTop; 

沒有運氣;我得到了同樣的行爲。一次旋轉一圈即可,但繞多個軸旋轉會導致相同的離心旋轉行爲。經過一些精彩的調試(讀作:將變量盲目地輸出到控制檯)之後,我注意到Front/Right/Top矢量隨着時間的推移慢慢變得不那麼正交。我基本上在每一步中都添加了標準化,並嘗試計算基於叉積的新矢量,以確保它們始終保持垂直於彼此,但即使如此,它們也不是完全正交的。我猜這是由於浮點數學不是非常精確。

請注意,我每次更新方法都會重新生成mShipRotation矩陣,因此它不能直接累積漂移或不準確性。我認爲應用多個Quarternion旋轉可能會累積錯誤(因爲我可以做一次旋轉就好),但我嘗試修復它並沒有奏效。

簡而言之:

  • 我可以俯仰/翻滾/偏航相對於世界軸x,y和z只是 細。這不僅僅是球員預期會發生的事情,因爲 滾動/俯仰/偏航與船舶無關,而是與 世界相關。
  • 我可以在船的局部座標軸(前/後/上/下/左/右)上滾動,俯仰或偏航,但一次只能有一個。他們的任何組合將導致船舶螺旋和迅速變形。

我試過四元數和矩陣。我已經嘗試過在各種論壇中找到的建議,但最終還是沒有找到可行的解決方案。通常人們推薦使用Quaternion.CreateFromYawPitchRoll,並沒有真正意識到其意圖是讓一艘船圍繞自己的(不斷變化的)軸旋轉,而不是(固定的)世界軸。

任何想法?考慮到您對船舶的前部,右側和頂部矢量進行滾動,俯仰和偏航的情況,您將如何着手創建旋轉矩陣?

+0

一位智者曾經說過,一張圖片講千言萬語 – annonymously

回答

2

您似乎在您的方法中將您的整個角度(yawRadians,pitchRadians,rollRadians)應用於您的本地軸2 & 3.這些值與世界軸結合,在本地空間中沒有意義。你的問題的根源是想掛在3個角度。

在本地空間中,使用一個角度量,它是要在幀之間旋轉的量。如果自上一幀以來您只投射了0.002f弧度,那麼當您圍繞vRight軸旋轉時,將會使用這個值。

這將與您的整體角度值(yawRadians,pitchRadians,& rollRadians)一起使用並使其無效,但大多數堅持使用3D編程的人很快就會放棄角度方法來存儲方向。

只需將您的矩陣或四元數一點一點地圍繞您的本地軸旋轉一圈,並將方向存儲在該結構(四元數或矩陣)中而不是三個角度。

當你像這樣旋轉一個關於局部座標軸的矩陣時,不用擔心萬向節鎖定。您必須在兩幀之間進行90度旋轉才能將其帶入畫面。

如果您想避免錯誤累積,請使用quat來存儲方向並將其每個幀規格化。然後,你發送的效果矩陣將從四捨五入的每一幀進行,並且是正常的。即使您沒有使用quat並將您的方向存儲在矩陣中,也需要數小時或數天來積累足夠的錯誤以便在視覺上引人注目。

此博客可以幫助:http://stevehazen.wordpress.com/2010/02/15/matrix-basics-how-to-step-away-from-storing-an-orientation-as-3-angles/

+0

非常感謝,這工作!我讀過你的博客文章(和其他類似的文章),關於從三個角度存儲方向,但重要性直到現在才真正點擊我。我認爲我很難理解增量旋轉的替代方案,而不是通過絕對的存儲角度進行旋轉,而這顯然無法可靠地工作。 – Manath