一般來說,我們解決向量旋轉問題一般要么是用旋轉矩陣,要么是用四元數。但很早以前我從網上找了一種比較另類的函數,當時也沒有深究。最近又把這個函數拿出看看,仔細一琢磨,發現真的很另類。這里分享一下,就當是擴展一下思維。這個旋轉方法據說叫Rodrigues旋轉公式。
這個方法的公式是這樣的,P'=P·cosθ + (A×P)sinθ +A(A·P)(1 - cosθ)。這種公式任誰第一眼看到都會摸不着頭腦,我們首先來將公式換一個寫法:
圖1
這個公式中|A|=1。為什么這樣變換呢?因為P'正好是三個向量相加,后面會詳細分析的,我們先將假設P'=u1+u2+u3。接下來我們分析每一項具體是什么。如圖2所示,P繞A軸旋轉θ角,其中θ角如圖位置。φ角是向量P和軸A之間的夾角。u1是向量P在A軸的投影,u2是向量(P'-u1)在向量(P-u1)的投影,u3是從u2末端到P'的向量,垂直於u2。
圖2
u1的公式如下:
圖3
其中|A|=1,u2的公式如下:
圖4
其中|P-u1|=|P'-u1|,u3的公式如下:
圖5
其中公式已經很清楚的闡述了推理過程,下面貼出實現的函數代碼。
void rotateWithAxis(CVector3& rotate, CVector3& axis, GLdouble angle, CVector3& direct) { /* P繞A軸旋轉角度θ,得到新的向量P',則: P'=P * cosθ + (A×P)sinθ +A(A·P)(1 - cosθ) 其中A為單位向量,旋轉角度θ為"逆時針方向"旋轉的角度。 rotate 表示的是向量P axis 表示的是軸A angle 表示的是角度θ direct 表示的是向量P' A×P=(ay * pz- az * py, ax * pz- az * px , ax * py- ay * px) A·P = ax * px + ay * py + az * pz */ #define PI 3.1415926535898 #define Cos cos(anglePI) #define Sin sin(anglePI) GLdouble anglePI = angle/180 * PI; CVector3 cross; GLdouble s; axis.Normal(); cross = CVector3::Cross(rotate, axis); s = rotate[0]*axis[0] + rotate[1]*axis[1] + rotate[2]*axis[2]; direct.SetVector3(rotate[0]*Cos + cross[0]*Sin + axis[0]*s*(1-Cos), rotate[1]*Cos + cross[1]*Sin + axis[1]*s*(1-Cos), rotate[2]*Cos + cross[2]*Sin + axis[2]*s*(1-Cos)); }