關於3D物體的轉動似乎有可能會用到四元數
在這邊先自己記錄一下。
人類最初用9個值的矩陣(Matrix),來表示一個三維物體的旋轉位置。它的缺陷是數據大,和無法自動在兩個角度間產生過度的角度。
由於矩陣描述角度過於抽象,人類又發明了3個值的優拉角(Euler)。可優拉角是個很不負責任的傢伙,旋轉圈數和旋轉順序完全不做區分。三維動畫師最厭惡的情況之一『萬向鎖(Gimbal Lock)』就是這個傢伙的問題。按不同軸以優拉角旋轉幾次後,出現x,y,z三個軸完全變成同向的情況,也就是說,優拉角很容易出現旋轉到最後只剩一個方向可以旋轉的情況,這就是恐怖的『萬向鎖』。
後來,聰明的愛爾蘭數學家發明了我們今天要研究的四元數(Quaternion),這就是迄今為止描述三維空間旋轉相對完美的方案。
四元數和矩陣一樣,不滿足乘法交換率,也就是說,A*B不等於B*A。四元數之所以可以明確地表述三維旋轉,是因為他實際上是一種『四維』的算法。這裡的『四維』是數學上的使用,不需要去想像什麼是四維的世界=_=,只是多一條軸,多一個參數而已。
我們主要介紹PV3d裡Quaternion常用的幾個方法和其用法,不會涉及過深的數學知識,所以不用擔心。Quaternion類位置在org-papervision-core-math包裡。
//構造四元數需要4個值(人家名字就叫4元嘛=_=),x,y,z是個三維向量,表示『任意軸』,w是個標量,表示旋轉度數。這就是幾乎完美的角度旋轉。
四元數之所以不是『絕對完美』,是因為插值的時候過渡速率不恆定,且很難解決。不過這比起『恐怖萬向鎖』已經是很小的問題。
public function Quaternion( x:Number = 0, y:Number = 0, z:Number = 0, w:Number = 1 )
//下面兩個個分別是『從優拉角換算出四元數』和『從矩陣換算出四元數』。這是兩個非常常用的方法,只要已知一個物體的優拉角或矩陣,即可生成對應的四元數。
Pv3d裡任何DisplayObject3D的tranform這個屬性就是變換他的矩陣,由這個矩陣就能得到目前旋轉的四元數。(我們研究所的Flab攝像機旋轉就用到了這些方法)
public static function createFromEuler( ax:Number, ay:Number, az:Number, useDegrees:Boolean = false )
public static function createFromMatrix( matrix:Matrix3D )
//和上面的剛好反向,分別是『得到已知四元數的優拉角』和『得到已知四元數的矩陣』
public function toEuler()
public function get matrix()
//插值是四元數最重要的用處之一,slerp方法的參數中,qa為開始的旋轉位置的四元數,qb為結束的旋轉位置四元數,apha可以看成一個插值的位置的比例,數值在0-1之間。
public static function slerp( qa:Quaternion, qb:Quaternion, alpha:Number )
完美旋轉的思路是這樣的:
我們必須要首先知道我們的開始位置和結束位置,結束位置很多情況用一個DisplayObject3D虛擬,我們可以用它的.tranform(是個矩陣值),變換成一個四元數
知道兩頭的四元數,我們只需要每禎增加alpha值(從0-1),即可在這兩個四元數之間插入任意多的過渡幀的四元數。
然後將每禎的這個四元數反向為矩陣,在通過矩陣相乘目前物體的位置,即可得到物體每禎的新位置。
下面這些都是四元數的基本運算(一般使用沒必要掌握),維基詞典可以瞭解『四元數』更專業的解釋。
維基詞典-四元數(會打開新窗口)
//求模,四元數到原點的距離,簡單的說就是長度
public function get modulo()
//共軌
public static function conjugate( a:Quaternion )
//點乘
public static function dot( a:Quaternion, b:Quaternion )
//叉稱
public static function multiply( a:Quaternion, b:Quaternion )
//求差
public static function sub(a:Quaternion, b:Quaternion)
//求和
public static function add(a:Quaternion, b:Quaternion)
引用:
閃客居 - 幾乎完美的四元數旋轉
延伸閱讀
維基百科 - 四元數
沒有留言:
張貼留言