萬向節鎖的一種解決辦法(非尤拉限角)
看到網上有個flash遊戲,控制一個方盒子在地板上移動,我便想寫一個3D版的,但是發現讓方盒子向任意方向翻滾存在萬向節鎖問題。
有關萬向節鎖,網上有一段視訊:優酷地址
簡單來說,萬向節鎖就是:一個3D物體存在3個座標軸,物體發生旋轉的時候,是圍繞三個座標軸發生的。在XNA中,一個3D模型的旋轉是通過旋轉變換矩陣完成的,請看下面的程式碼:
effect.Alpha = alpha;
effect.EnableDefaultLighting();
effect.World = Matrix.CreateRotationX(rotation.X) *
Matrix.CreateRotationY(rotation.Y) *
Matrix.CreateRotationZ(rotation.Z)
Matrix.CreateScale(scale) *
Matrix.CreateTranslation(position);
effect.View = camera.View;
effect.Projection = camera.Projection;
上面這段程式碼中劃線部分既是使3D模型發生旋轉的程式碼。但是大家知道,矩陣乘法是不遵守交換律的,也就是說A*B!=B*A,這使得XYZ三個座標軸上的旋轉有了層級關係。按照上面這段程式碼給出的順序,X軸是父層級,Y軸是X軸的子層級,Z軸是Y軸的子層級。
所謂層級,也就是說,如果3D模型圍繞X軸發生旋轉,那麼同時也將改變Y軸和Z軸的朝向,但是當模型圍繞Z軸轉動的時候,X軸的方向卻是不變的。這樣便形成了萬向節鎖。萬向節鎖發生的時候,會有兩個座標軸重合。
舉個例子,比如在初始狀態下,XYZ三個軸相互垂直,然後我們讓物體圍繞Y軸發生轉動,這樣一來,X軸沒有發生變化,但是Z軸隨著物體轉向了X軸,並在合適時候會與X軸重合。重合之後會發生什麼呢?那便是我們失去了一個座標軸。原因很簡單,因為此時X軸和Z軸重合了嘛,無論你是圍繞X軸轉動,還是為繞Z軸轉動,最終效果都是一樣的。
建議大家看一看本文開頭連線的優酷上那段視訊。在那段視訊中,解說採用了一種叫尤拉限角的方法解決萬向節鎖問題。這個方法簡單說就是給旋轉加上一個限制,不讓3D物體發生任意角度的完全自由的旋轉,從而避免萬向節鎖的發生。
但是對於我們的遊戲,需要物體發生可能產生萬向節鎖的旋轉,怎麼辦呢?
我嘗試讓物體在發生旋轉併產生萬向節鎖之後,再自己轉回來。
簡單說,對於一個在座標軸方向上均勻對稱的物體(比如球和立方體)來說,當我們站在一個固定角度上看他的時候,它的座標軸朝向無關緊要,因為我們說了,它是個在座標軸方向上對稱的物體,那麼我們為什麼不可以在程式碼裡把旋轉的暈頭轉向的這個3D物體在擺正了呢?反正玩家看不出來嘛!
那麼對於非對稱的物體呢?
我們只需要多做幾個模型,適應這種非對稱狀況就好了。
但是這個辦法和尤拉限角方法一樣,不是萬能的,對於各向異性的物體,比如一個人物,比如一朵花,特別是會動的東西(帶動畫的模型),幾乎不起作用了。
下面給出我做完的兩個小遊戲,一個是仿照網上的立方體在地板上滾動,滾過去地板就消失那個做的,另一個是仿照網上的長方體在地板上滾動,最後到達目的地做的。兩個遊戲都是用上下左右鍵控制就ok了,空格鍵可以重置。希望大家指教~~~