日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

转-D3D中的四元数

發布時間:2025/6/15 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 转-D3D中的四元数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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)?//?創建用于旋轉的四元數q,?v必須為單位向量??
  • {??
  • ????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中的四元数的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。