http://blog.csdn.net/cppyin/article/details/6177742
?
在3D程序中,通常用quaternion來計算3D物體的旋轉角度,與Matrix相比,quaternion更加高效,占用的儲存空間更小,此外也更便于插值。在數學上,quaternion表示復數w+xi+yj+zk,其中i,j,k都是虛數單位:
i*i = j*j = k*k= -1
i*j = k, j*i = -k
可以把quaternion看做一個標量和一個3D向量的組合。實部w表示標量,虛部表示向量標記為V,或三個單獨的分量(x,y,z)。所以quaternion可以記為[ w,?V]或[ w,(x,y,x)]。對quaternion最大的誤解在于認為w表示旋轉角度,V表示旋轉軸。正確的理解應該是w與旋轉角度有關,v與旋轉軸有關。例如,要表示以向量N為軸,軸旋α度,相對的quaternion應該是:
q = [ cos(α/ 2) , sin(α/ 2)?N]
? =[ cos(α/ 2) , ( sina(α/ 2)?Nx, sin(α/ 2)Ny, sin(α/ 2)Nz ) ]
為了計算方便,一般要求N為單位矢量。對quaternion來說使用四個值就能記錄旋轉,而不是Matrix所需的十六個值。為什么用quaternion來計算旋轉很方便呢?先說過quaternion是一個復數,如果你還記得一點點復數的知識,那么應該知道復數乘法(叉乘)的幾何意義實際上就是對復數進行旋轉。對最簡單的復數p= x + yi來說,和另一個復數q = ( conα,sinα)相乘,則表示把p沿逆時針方向旋轉α:
p’ = pq
當然,x+yi的形式只能表示2D變換,對3D變換來說就需要使用?quaternion了,而且計算也要復雜一點。為了對3D空間中的一個點p(x,y,z)進行旋轉,需要先把它轉換為quaternion形式p = [0, ( x, y, z)],接下來前面討論的內容,定義q = cos(α/ 2) , sin(α/ 2)?N為旋轉quaternion,這里N為單位矢量長度的旋轉軸,α為旋轉角度。那么旋轉之后的點p’則為:
???????p’ = qpq-1
?
1. 數學分析
1) 四元數是什么東西?
這個東西算盤、矩陣、復數是一類東西,即數學工具,數學家們創造了這個東西來解決一些數學問題。其實四元數是一種超復數,他不是只有一個虛數的復數,而是有三個虛數的復數。我們先回顧一下復數吧。
?
2) 虛數的來源
實數集中沒有-1的平方根,因為沒有哪個實數的平方等于-1,所以數學家們就創造它——虛數i,并且定義了i * i = -1。
所以我們可以計算sqrt(-4)了,sqrt(-4) = 2*i
?
3) 復數
定義:一個實數與一個虛數的和。 z = a + bi。
a叫實部,b叫虛部。
其中(a,b)為復平面上的點。這也是為什么3D圖形運算能和四元數掛上關系了。
運算法則:
z1 = a + b*i
z2 = c + d*i
?
與標量相乘 k*z1 = k*a + K*b*i
復數相加 z1 + z2 = a + c + (b + d) * i
復數相乘 z1 * z2 = (a + b * i) * (c + d * i) = a * c + a * d * i + c * b * i - b * d = a*c - b*d + (a*d+b*c) * i
復數相除 z1 / z2 = (a + b*i) / (c + d*i)
z1的共軛z1* = a - b*i,作用是z×z*為實數
所以復數相除 z1 / z2 = (a + b*i)*(c - d*i) / (c2+d2) = ... = (a*c + b*d)/(a2+b2) + (b*c-a*d)*i)/(a2+b2)
z1的倒數 1/z = 1 / (a+b*i),同樣可以轉化為:a/(a2+b2) + b*i/(a2+b2)
z1的范數 |z| = sqrt(a2+b2) = sqrt(z×z*)
?
4) 超復數
q = q0?+ q1*i + q2*j + q3*k
上面就是四元數的表示,其中q0為實部,而虛部<q1,q2,q3>正好組成了3D復平面中的向量。
簡寫就是q = q0?+ qv,其中qv是向量<q1, q2?,q3>。
超復數的運算法則與復數相同,這里就不再重復了,但要特別說明四元數的倒數q-1。
q×q-1?= 1
兩邊同時乘以q*:
q×q-1×q* = q*
因為:q×q* = |q|2
所以q-1=q* / |q|2
可以注意到,如果q是一個單位四元數的話,那么q的倒數就等于q的共軛。
這個特性非常重要,因為在四元數旋轉中要使用。
?
5) 四元數旋轉
對于一個3D向量<x, y, z>,我們把他表現為四元數形式,則是:vq= <0, x, y, z>。
以及給定一個表示旋轉軸和旋轉角度的單位四元數q,那么向量vq繞指定軸旋轉指定角度的結果四元數vq'滿足如下:
右手坐標系:
? 順時針旋轉:vq' = q*×vq×q
? 逆時針旋轉:vq' = q×vq×q*
左手坐標系:
? 順時針旋轉:vq' = q×vq×q*
? 逆時針旋轉:vq' = q*×vq×q
其中,對于那個用于存儲旋轉軸和旋轉角度的單位四元數q,他與旋轉軸v = <x0, y0, z0>和角度theta關系如下:
q = Cos(theta/2) + Sin(theta/2) ×?v
?
?
?
2. 代碼實現
1) 四元數結構體定義
?
[cpp]?view plaincopy
typedef?struct?QUAT_TYPE???{??????union??????{??????????double?M[4];??????????struct??????????{??????????????double?w,?x,?y,?z;??????????};??????????struct??????????{??????????????double?q0;??????????????VECTOR3D?qv;??????????};??????};??}?QUAT,?*QUAT_PTR;?? ?
?
?
2) 四元數常用操作函數實現
?
[cpp]?view plaincopy
void?_CPPYIN_Math::QuatCreate(QUAT_PTR?q,?VECTOR3D_PTR?v,?double?theta)???{??????double?theta_div_2?=?(0.5)*theta;??????double?sin_theta?=?sin(theta_div_2);????????q->x?=?sin_theta?*?v->x;??????q->y?=?sin_theta?*?v->y;??????q->z?=?sin_theta?*?v->z;??????q->w?=?cos(?theta_div_2?);??}????void?_CPPYIN_Math::QuatGetVectorAndTheta(QUAT_PTR?q,?VECTOR3D_PTR?v,?double?*theta)??{??????*theta?=?acos(q->w);??????double?sin_theta_inv?=?1.0/sin(*theta);????????v->x?=?q->x?*?sin_theta_inv;??????v->y?=?q->y?*?sin_theta_inv;??????v->z?=?q->z?*?sin_theta_inv;????????*theta?*=?2;??}????void?_CPPYIN_Math::QuatAdd(QUAT_PTR?q1,?QUAT_PTR?q2,?QUAT_PTR?qsum)??{??????qsum->x?=?q1->x?+?q2->x;??????qsum->y?=?q1->y?+?q2->y;??????qsum->z?=?q1->z?+?q2->z;??????qsum->w?=?q1->w?+?q2->w;??}????void?_CPPYIN_Math::QuatSub(QUAT_PTR?q1,?QUAT_PTR?q2,?QUAT_PTR?qdiff)??{??????qdiff->x?=?q1->x?-?q2->x;??????qdiff->y?=?q1->y?-?q2->y;??????qdiff->z?=?q1->z?-?q2->z;??????qdiff->w?=?q1->w?-?q2->w;??}????void?_CPPYIN_Math::QuatConjugate(QUAT_PTR?q,?QUAT_PTR?qconj)???{??????qconj->x?=?-q->x;??????qconj->y?=?-q->y;??????qconj->z?=?-q->z;??????qconj->w?=?q->w;??}????void?_CPPYIN_Math::QuatScale(QUAT_PTR?q,?double?scale,?QUAT_PTR?qs)??{??????qs->x?=?scale?*?q->x;??????qs->y?=?scale?*?q->y;??????qs->z?=?scale?*?q->z;??????qs->w?=?scale?*?q->w;??}????double?_CPPYIN_Math::QuatNorm(QUAT_PTR?q)??{??????return?sqrt(q->w?*?q->w?+?q->x?*?q->x?+?q->y?*?q->y?+?q->z?*?q->z);??}????double?_CPPYIN_Math::QuatNorm2(QUAT_PTR?q)??{??????return?q->w?*?q->w?+?q->x?*?q->x?+?q->y?*?q->y?+?q->z?*?q->z;??}????void?_CPPYIN_Math::QuatNormalize(QUAT_PTR?q,?QUAT_PTR?qn)??{??????double?qlength_inv?=?1.0/(sqrt(q->w*q->w?+?q->x*q->x?+?q->y*q->y?+?q->z*q->z));????????qn->w?=?q->w?*?qlength_inv;??????qn->x?=?q->x?*?qlength_inv;??????qn->y?=?q->y?*?qlength_inv;??????qn->z?=?q->z?*?qlength_inv;??}????void?_CPPYIN_Math::QuatUnitInverse(QUAT_PTR?q,?QUAT_PTR?qi)???{??????qi->w?=??q->w;??????qi->x?=?-q->x;??????qi->y?=?-q->y;??????qi->z?=?-q->z;??}????void?_CPPYIN_Math::QuatInverse(QUAT_PTR?q,?QUAT_PTR?qi)???{??????double?norm2_inv?=?1.0?/?(q->w?*?q->w?+?q->x?*?q->x?+?q->y?*?q->y?+?q->z?*?q->z);????????qi->w?=??q->w?*?norm2_inv;??????qi->x?=?-q->x?*?norm2_inv;??????qi->y?=?-q->y?*?norm2_inv;??????qi->z?=?-q->z?*?norm2_inv;??}????void?_CPPYIN_Math::QuatMul(QUAT_PTR?q1,?QUAT_PTR?q2,?QUAT_PTR?qprod)??{??????double?prd_0?=?(q1->z?-?q1->y)?*?(q2->y?-?q2->z);??????double?prd_1?=?(q1->w?+?q1->x)?*?(q2->w?+?q2->x);??????double?prd_2?=?(q1->w?-?q1->x)?*?(q2->y?+?q2->z);??????double?prd_3?=?(q1->y?+?q1->z)?*?(q2->w?-?q2->x);??????double?prd_4?=?(q1->z?-?q1->x)?*?(q2->x?-?q2->y);??????double?prd_5?=?(q1->z?+?q1->x)?*?(q2->x?+?q2->y);??????double?prd_6?=?(q1->w?+?q1->y)?*?(q2->w?-?q2->z);??????double?prd_7?=?(q1->w?-?q1->y)?*?(q2->w?+?q2->z);??????double?prd_8?=?prd_5?+?prd_6?+?prd_7;??????double?prd_9?=?0.5?*?(prd_4?+?prd_8);????????qprod->w?=?prd_0?+?prd_9?-?prd_5;??????qprod->x?=?prd_1?+?prd_9?-?prd_8;??????qprod->y?=?prd_2?+?prd_9?-?prd_7;??????qprod->z?=?prd_3?+?prd_9?-?prd_6;??}????void?_CPPYIN_Math::QuatMul3(QUAT_PTR?q1,?QUAT_PTR?q2,?QUAT_PTR?q3,?QUAT_PTR?qprod)???{??????QUAT?qtmp;??????QuatMul(q1,?q2,?&qtmp);??????QuatMul(&qtmp,?q3,?qprod);??} ?
總結
以上是生活随笔為你收集整理的转-D3D中的四元数的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。