問題
使用四元數可以解決萬向節鎖的問題,但是我在實際使用中出現問題:我設計了一個程序,顯示一個三維物體,用戶可以輸入繞zyx三個軸進行旋轉的指令,物體進行相應的轉動。
由於用戶輸入的是繞三個軸旋轉的角度,所以很直接的就想到用歐拉角來表示每一個旋轉。但是歐拉角會出現萬向節鎖,所以我使用四元數替代原來的歐拉角,來計算旋轉矩陣。但是奇怪的結果出現了,gimbal lock仍然出現,使用四元數和使用歐拉角,程序的表現一模一樣。
原因
經過一番思考,並參考 Using Quaternions for OpenGL Rotations ,我找到了問題的根源。
正如回答所說:
implement Euler angles with quaternions. That's not helping.
我的程序是這樣計算的:
計算出繞xyz旋轉的歐拉角,轉化為四元數,再轉為旋轉矩陣,傳給shader計算。每一次用戶輸入,都會重新計算繞zyx三個軸旋轉的角度,然后生成新的四元數,再生成新的旋轉矩陣。這樣做在使用歐拉角的時候沒有什么問題(反正會出現Gimbal lock),但是使用四元數的時候還這樣做,就無法避免Gimbal lock樂。因為這樣做,用戶輸入了繞多個軸的旋轉,生成的歐拉角自然是繞多個軸的。參考上一篇博文所述,多次旋轉疊加沒有考慮坐標系的變化,Gimbal lock還是會產生了。
解決辦法是分別計算用戶每一次輸入的旋轉變換矩陣,將每一次的單獨的旋轉變換矩陣點乘原來的旋轉變換矩陣,得到最新的變換矩陣。后續的每一次變換都在這個矩陣的基礎上不斷的乘,也就是說每一次都是在原來的基礎上再加一點點變化,這樣就完美解決了GImbal lock 。
需要說明的是,用四元數生成多個旋轉矩陣,進行相乘,其計算的順序不會對結果有影響,這是四元數和歐拉角之間的顯著區別。也是四元數可以解決問題的關鍵。
他人的解釋如下:
you just have a quaternion which represents the current orientation of the object. When you decide to apply a rotation to it (of some angle by some axis), you construct a quaternion that represents that rotation by an angle around that axis. Then you right-multiply that quaternion with the current orientation quaternion, producing a new current orientation.