3D Math Keynote 2

3D Math Keynote 2算法

一、方向(diretion),指的是前方朝向。方位(orientation),指的是head、pitch、roll。ide

    

二、歐拉角的缺點:spa

  1)給定方位的表達式不唯一。code

    例如,pitch 135 = heading180 + pitch 45 + bank 180。blog

    經過將 heading、bank 限制在 +180~-180度,pitch限制在+90~-90度便可解決不唯一的問題。數學

  2)兩個角度間插值很是困難。it

三、複數的共軛io

  

  複數的模。event

    

四、複數集存在於一個2D平面上,能夠認爲這個平面有2個軸:實軸、虛軸。class

    

  四元數有3個虛部,i、j、k。

    

  繞向量 n 旋轉 0 度的四元數:

    

  q與-q表明的實際角位移是相同的,將0 加上360度,不會改變q的角位移,但q的四個份量都變負了。因此任意角位移有2種四元數的表示法。

   四元數也有模。

    

五、四元數的共軛:

    

  四元數的逆:

    

  當 |q| 爲1時,四元數的共軛,就是四元數的逆。

  單位四元數:[1, 0]

  四元數逆意味着向相反的方向旋轉相同的角度。

六、四元數乘法。

  

  四元數乘法知足結合律,不知足交換律。

  四元數叉乘的模等於模的積:

  

  

  四元數逆的性質:

  

七、四元數旋轉公式:

  

  下例,先執行a旋轉,再執行b旋轉:

    

八、四元數點乘。結果是一個標量。

  

九、四元數的對數。引入變量 alpha = 0/2

  

  指數公式爲:

    

9.一、四元數求冪。咱們看看它的數學定義。
  

  結合9中的公式,上式能夠推導爲 exp(t[0 alpha*n]),也就是 q^t次方,實際上是 alpha 乘以了t。因此q^t其實是 [cos(t*alpha) n.sin(t*alpha)]。

 

  下述代碼使用上述原理,計算四元數 q 的 t 次方的值。原理是讓角度 alpha * t。

  

  上面的 if 是用於避免單位四元數[1 0]的狀況,單位四元數放大 t 倍,仍是單位四元數。

十、slerp 避免了歐拉角插值的全部問題。四元數插值的理論:

  

  

  旋轉插值圖解:

    

  

  由類似三角形原理,能夠求出 k0、k1。

  

    

  因此 V(t) 能夠表示爲:

    

  擴展到四元數即爲:

    

  slerp 的完整代碼以下:

    

    

  上述實現用了一個書上未證實的公式,四元數的點乘等於夾角的 cos。

    

十一、squard 是四元數的樣條插值。須要引入控制點:

  

  能夠看到,Si的計算須要引用 qi-一、qi、qi+1。因此在計算轉變時,實際須要四個 q點。

  

  樣條插值軌跡爲:

  

十二、從歐拉角到矩陣。

  從慣性座標系到物體座標系很是容易,將3個軸軸的旋轉矩陣相乘便可。
  

  而從物體座標系到慣性座標系,取上面矩陣的轉置矩陣便可。

  

  

1三、從矩陣到歐拉角

  

  

  上面求解出了 pitch,也就推出了 cosp 的值。從而根據 m1三、m33 能夠推出 sinh、cosh 的的值,而後使用 atan2 便可計算出 h。

    

  用一樣的方式,能夠用m2一、m22解得 bank。

    

  若 cosp 爲0,則可推出 p 是+/- 90,b 爲0。從而可使用下面的值化簡公式:

      

  經過 m十一、m31 可計算出h。

1四、實現從矩陣解出歐拉角的算法。

// 設矩陣保存在下面這些變量中
float m11, m12, m13;
float m21,m22,m23;
float m31,m32,m33;

// 以弧度形式計算歐拉角並存在如下變量中
float h,p,b;

// 從m23計算pitch, 當心 asin() 的域錯誤,因浮點計算咱們容許必定的偏差
float sp = -m23;
if (sp <= -1.0f){
    p = -1.570796f; // -pi/2
}else if (sp >= 1.0){
    p = 1.570796; // pi/2
} else {
    p = asign(sp);
}

// 檢查萬象鎖的狀況,容許一些偏差
if (sp > 0.9999f){
    // 向正上或正下看
    // 將 bank 置零,賦值給 heading
    b = 0.0f;
    h = atan2(-m32, m11);
} else {
    // 經過 m12 和 m33 計算heading
    h = atan2(m12, m33);
    b = atan2(m21, m22);
}
View Code

1五、從四元數轉換到矩陣。

  繞任意軸的旋轉矩陣:

    

  繞任意軸旋轉的四元數:

  

  咱們須要把每個m推導成爲 w,x,y,z 的形式,以m11爲例。

  

  使用 cos 倍角公式:

    

  最後展開化簡可得:

    

  其餘m求法的就不舉例了,是相似的方法。下面是最終答案,從四元數構造出的完整旋轉矩陣:

    

  

1六、從矩陣轉換到四元數。

  從直接利用公式 10.23,首先檢查對角線元素。

    

  能夠用有相似的方法求得其餘三個元素:

    

  由於平方根的結果老是正。另外一個技術是檢查對稱位置上的元素和。

    

  首先用第一種方法計算出 w,x,y,z 其中一個的值,而後再用第二種方法,得出另外三個數值的值,便可避免全部元素均爲正的問題。
    

  下面是算法實現:

// 輸入矩陣
float m11, m12, m13;
float m21, m22, m23;
float m31, m32, m33;

// 輸出四元數
float w, x, y, z;

// 探測 w, x, y, z 中的最大絕對值
float fourWSquaredMinus1 = m11 + m22 +m33;
float fourXSquaredMinus1 = m11 - m22 - m33;
float fourYSquaredMinus1 = m22-m11-m33;
float fourZSquaredMinus1 = m33 - m11 -m33;

int biggestIndex = 0;
float fourBiggestSquaredMinus1 = fourWSquaredMinus1;

if (fourXSquaredMinus1 > fourBiggestSquaredMinus1){
    fourBiggestSquaredMinus1 = fourXSquaredMinus1;
    biggestIndex = 1;
}

if (fourYSquaredMinus1 > fourBiggestSquaredMinus1){
    fourBiggestSquaredMinus1 = fourYSquaredMinus1;
    biggestIndex = 2;
}

if (fourZSquaredMinus1 > fourBiggestSquaredMinus1){
    fourBiggestSquaredMinus1 = fourZSquaredMinus1;
    biggestIndex = 3;
}

// 計算平方根和除法
float biggestVal = sqrt(fourBiggestSquaredMinus1 + 1.0f) * 0.5f;
float mult = 0.25f / biggestVal;

// 計算四元數的值 
switch(biggestIndex){
case 0:
    w = biggestVal;
    x = (m23-m32)*mult;
    y = (m31-m13)*mult;
    z = (m12 - m21) * mult;
    break;
case 1:
    x = biggestVal;
    w = (m23-m32)*mult;
    y = (m12+m21)*mult;
    z = (m31+m12)*mult;
    break;
case 2:
    y = biggestVal;
    w = (m31 - m13) * mult;
    x = (m12 + m21) * mult;
    z = (m23 + m32) * mult;
    break;
case 3:
    z = biggestVal;
    w = (m12 - m21) * mult;
    x = (m31 + m13) * mult;
    y = (m23 + m32) * mult;
    break;
}
View Code

 

1七、從歐拉角轉換到四元數。

  先將三個軸的旋轉分別轉換爲四元數,再將這三個四元數鏈接成一個四元數。下面是分別旋轉的四元數:

    

  將其鏈接起來便可獲得結果。

    

1八、從四元轉換到歐拉角

  咱們已經知道從四元數到矩陣,也知道從矩陣到歐拉角。下面是從矩陣求歐拉角:

  

  再下面是四元數求矩陣:

  

  將圖一中的 m 所有替換爲 wxyz,便可得四元數到歐拉角的推導公式。

  

// 使用全局變量保存輸入輸出
float w,x,y,z;
float h,p,b;

// 計算 si(pitch)
float sp = -2.0f * (y*z + w*x);

// 檢查萬向鎖,容許有必定偏差
if (fabs(sp)>0.9999f){
    // 向正上或正下看
    p = 1.570796f * sp;
    // 計算 heading, bank 置零
    h = atan2(-x*z - w*y, 0.5f - y*y - z*z);
    b = 0.0f;
}else{
    // 計算角度
    p = asin(sp);
    h = atan2(x*z - w*y, 0.5f - x*x - y*y);
    b = atan2(x*y - w*z, 0.5f - x*x, -z*z);
}
View Code

 

1九、

20、

相關文章
相關標籤/搜索