(轉)【D3D11游戲編程】學習筆記二:XNAMath之XMVECTOR


   (注:【D3D11游戲編程】學習筆記系列由CSDN作者BonChoix所寫,轉載請注明出處:http://blog.csdn.net/BonChoix,謝謝~)

 

       一、XNA Math簡介

       在D3D10及之前的版本中,3D數學庫是伴隨在D3DX庫中的。在D3D11版中,3D數學庫被單獨隔離出來,為XNA Math庫,功能和之前基本一樣,但是建立在SIMD指令上,以更好地利用Windows及XBox360上特殊的硬件寄存器(128位,可以同時操作4個32位數)。

       二、向量類型

       在XNA數學庫中,核心的向量類型為XMVECTOR,它正好映射為SIMD硬件上的128位寄存器,以利用一個指令同時操作4個32位的數。當SEE2指令集可用時,可以定義為:

[cpp]  view plain copy
  1. typedef __m128 XMVECTOR;  


在操作向量時,XMVECTOR除了用於4維向量外,還可以用於操作2維、三維向量,以於多出的幾維默認為0,不關心即可。

       此外要注意的是,XMVECTOR在內存中是16位對齊的,當作為局部或全局變量使用時,由硬件自動實現對齊。對於類中的成員變量,則推薦使用XMFLOAT2(2D), XMFLOAT3(3D), XMFLOAT4(4D)來代替XMVECTOR,定義分別如下:

[cpp]  view plain copy
  1. typedef struct _XMFLOAT2  
  2. {  
  3.     FLOAT x;  
  4.     FLOAT y;  
  5. } XMFLOAT2;  
  6.   
  7. typedef struct _XMFLOAT3  
  8. {  
  9.     FLOAT x;  
  10.     FLOAT y;  
  11.     FLOAT z;  
  12. } XMFLOAT3;  
  13.   
  14. typedef struct _XMFLOAT4  
  15. {  
  16.     FLOAT x;  
  17.     FLOAT y;  
  18.     FLOAT z;  
  19.     FLOAT w;  
  20. } XMFLOAT4;  


       但是,如果直接使用XMFLOAT2、XMFLOAT3等這些類型進行計算,是不會利用到SIMD指令的加速效果的,因此在計算前要把這些向量轉換為XMVECTOR,然后再進行各種向量運算。這幾種類型與XMVECTOR之間的相互轉換函數主要分為Store和Load兩種,Store型用來把一個XMVECTOR存儲到指定的XMFLOATx中,Load型用來從一個XMFLOATx讀取內容到XMVECTOR中。總結下這段話內容,即:

1. 在局部、全局變量中使用XMVECTOR類型;

2. 在類中定義向量成員時,使用類型XMFLOAT2,XMFLOAT3,XMFLOAT4;

3. 對類中的向量進行運算時,用Load型函數把相應向量讀取到XMVECTOR中,再進行運算;

4. 運算完后把相應的結果XMVECTOR通過Store型函數存儲到相應的XMFLOATx向量中。

       三、 Load型和Store型函數

       Load型函數用來從一個XMFLOATx向量中讀取內容到XMVECTOR中。如下幾種:

[cpp]  view plain copy
  1. XMVECTOR XMLoadFloat2(CONST XMFLOAT2 *pSource);     //從XMFLOAT2中讀取內容到一個XMVECTOR中  
  2. XMVECTOR XMLoadFloat3(CONST XMFLOAT3 *pSource);     //從XMFLOAT3中讀取內容到一個XMVECTOR中  
  3. XMVECTOR XMLoadFloat4(CONST XMFLOAT4 *pSource);     //從XMFLOAT4中讀取內容到一個XMVECTOR中  

       此外除了XMFLOATx類型,還可以Load到其他類型的向量數據中,如:

[cpp]  view plain copy
  1. XMVECTOR XMLoadInt2(CONST UINT *pSource);       //從二維UINT向量中讀取內容到一個XMVECTOR向量中  
  2. XMVECTOR XMLoadColor(CONST XMCOLOR *pSource);       //從XMCOLOR中讀取內容到一個XMVECTOR中  
  3. XMVECTOR XMLoadByte4(CONST XMBYTE4 *pSource);       //從XMBYTE4中讀取內容到一個XMVECTOR中  

       Store型函數用來把一個XMVECTOR存儲到一個XMFLOATx向量中。如下幾種:

[cpp]  view plain copy
  1. void XMStoreFloat2(XMFLOAT2 *pDest, FXMVECTOR V);   //把XMVECTOR存儲到一個XMFLOAT2向量中  
  2. void XMStoreFloat3(XMFLOAT3 *pDest, FXMVECTOR V);   //把XMVECTOR存儲到一個XMFLOAT3向量中  
  3. void XMStoreFloat4(XMFLOAT4 *pDest, FXMVECTOR V);   //把XMVECTOR存儲到一個XMFLOAT4向量中  

       同理,除了XMFLOATx類型,還可以把XMVECTOR存儲到其他類型向量中,如:

[cpp]  view plain copy
  1. void XMStoreInt3(UINT *pDest, FXMVECTOR V);     //把XMVECTOR存儲到一個二維UINT向量中     
  2. void XMStoreColor(XMCOLOR *pDest, FXMVECTOR V);     //把XMVECTOR存儲到一個XMCOLOR向量中  
  3. void XMStoreByte4(XMBYTE4 *pDest, FXMVECTOR V);     //把XMVECTOR存儲到一個XMBYTE4向量中  

 

       由於XMVECTOR映射為一個特殊的SIMD寄存器,而不是一個struct,因此我們不能直接操作其x,y,z,w維數據,因此提供了以下幾個Set和Get函數:

[cpp]  view plain copy
  1. FLOAT XMVectorGetX(FXMVECTOR V);    //得到XMVECTOR的X維數據  
  2. FLOAT XMVectorGetY(FXMVECTOR V);    //得到XMVECTOR的Y維數據  
  3. FLOAT XMVectorGetZ(FXMVECTOR V);    //得到XMVECTOR的Z維數據  
  4. FLOAT XMVectorGetW(FXMVECTOR V);    //得到XMVECTOR的W維數據  
  5.   
  6. XMVECTOR XMVectorSetX(FXMVECTOR V, FLOAT x);    //設置一個XMVECTOR的X維數據,並返回新XMVECTOR  
  7. XMVECTOR XMVectorSetY(FXMVECTOR V, FLOAT y);    //設置一個XMVECTOR的Y維數據,並返回新XMVECTOR  
  8. XMVECTOR XMVectorSetZ(FXMVECTOR V, FLOAT z);    //設置一個XMVECTOR的Z維數據,並返回新XMVECTOR  
  9. XMVECTOR XMVectorSetW(FXMVECTOR V, FLOAT w);    //設置一個XMVECTOR的W維數據,並返回新XMVECTOR  

       你可能注意到,在上面所有的函數中,有好多FXMVECTOR類型的參數,而不是XMVECTOR類型。別急,這正是我們下一步要說的。
      

       四、 XMVECTOR類型參數傳遞規定

       為了更好地利用SIMD,當XMVECTOR作為函數參數類型時,有特殊的規定。這些規則與平台相關,比如在32位和64位的Windows及XBox360下規則就不一樣。為了在寫代碼時與平台無關,XNA Math專門針對函數參數類型定義了這兩個類型:CXMVECTOR和FXMVECTOR。在不同的平台下這兩個類型有着相應的不同的定義,對於程序員在寫代碼時則無需考慮這些,只要服從相應的規則即可。規則如下:

       在一個函數中,前三個使用到XMVECTOR類型的參數,必須為FXMVECTOR;之后所有其他的XMVECTOR類型參數要為CXMVECTOR。

[cpp]  view plain copy
  1. XMINLINE XMMATRIX XMMatrixTransformation(  
  2.         FXMVECTOR ScalingOrigin,                    //第1個XMVECTOR類型參數  
  3.         FXMVECTOR ScalingOrientationQuaternion,             //第2個XMVECTOR類型參數  
  4.         FXMVECTOR Scaling,                      //第3個XMVECTOR類型參數  
  5.         CXMVECTOR RotationOrigin,                   //第4個開始,后面的全部為CXMVECTOR類型  
  6.         CXMVECTOR RotationQuaternion,  
  7.         CXMVECTOR Translation);   

當然,各參數之間也可以夾雜其他非XMVECTOR類型的參數,但只要是前三個類型為XMVECTOR的參數使用FXMVECTOR,后面所有類型為XMVECTOR的參數使用CXMVECTOR即可。例如:

[cpp]  view plain copy
  1. XMINLINE XMMATRIX XMMatrixTransformation2D(  
  2.         FXMVECTOR ScalingOrigin,                    //第1個XMVECTOR類型參數  
  3.         FLOAT     ScalingOrientation,  
  4.         FXMVECTOR Scaling,                      //第2個XMVECTOR類型參數  
  5.         FXMVECTOR RotationOrigin,                   //第3個XMVECTOR類型參數  
  6.         FLOAT     Rotation,  
  7.         CXMVECTOR Translation);                     //第4個,必須使用CXMVECTOR  

是不是感覺這規則有點奇怪?反正我感覺很奇怪,不過無所謂,其實也很簡單,我們平時操作XMVECTOR類型進行運算時不用關心這個,僅僅是在定義函數時,如果參數類型為XMVECTOR,才需要考慮這個規則。     

        五、 常量向量

       當用到常量型的XMVECTOR時,應該使用XMVECTORF32類型,尤其是當使用初始化式時。例如:

[cpp]  view plain copy
  1. const XMVECTORF32 g_Zero = {0.f,0.f,0.f,0.f};  
  2. static const XMVECTORF32 g_tmp = {x,y,z,w};  

       XMVECTORF32是16字節對齊的數據結構,可以轉換為XMVECTOR類型。定義如下:

[cpp]  view plain copy
  1. typedef _DECLSPEC_ALIGN_16_ struct XMVECTORF32  
  2. {  
  3.     union  
  4.     {  
  5.         float v[4];  
  6.         XMVECTOR v;  
  7.     };  
  8.       
  9.     //如果是在C++環境下,則還有其他成員函數  
  10.     //比如重載()操作符,轉換為XMVECTOR類型  
  11. };  

因此,如果想事先定義一些常量型的XMVECTOR,則可以用const XMVECTORF32類型來定義,在程序中用到XMVECTOR類型時,再利用類型轉換(static_cast)轉換為XMVECTOR類型即可。比如我們可能想事先定義好各種常見的顏色,像白色可以這樣定義:const XMFLOAT32 White = {1.f, 1.f, 1.f, 1.f};

       六、 針對XMVECTOR類型重載的操作符

       在C++環境下,針對各種常見的向量操作,對XMVECTOR重載了相應的操作符。比如:向量加減+、-、+=、-=,向量與數字相乘:*、/、*=、/=,向量點積:*,*=等。

       七、 一些Setter函數

[cpp]  view plain copy
  1. XMVECTOR XMVectorZero();        //[0,0,0,0]  
  2. XMVECTOR XMVectorSplatOne();    //[1.f, 1.f, 1.f, 1.f]  
  3. XVMECTOR XMVectorSet(FLOAT x, FLOAT y, FLOAT z, FLOAT w);   //[x,y,z,w]  
  4. XMVECTOR XMVectorReplicate(FLOAT s);    //[s, s, s, s]  
  5. XMVECTOR XMVectorSplatX(FXMVECTOR v);   //[v.x, v.x, v.x, v.x]  
  6. XMVECTOR XMVectorSplatY(FXMVECTOR v);   //[v.y, v.y, v.y, v.y]  
  7. XMVECTOR XMVectorSplatZ(FXMVECTOR v);   //[v.y, v.y, v.y, v.y]  

       八、 向量操作函數

[cpp]  view plain copy
  1. XMVECTOR XMVector3Length(FXMVECTOR v);     //長度L,結果為[L,L,L,L],效率起見,全部為XMVECTOR類型,我們只取一個維即可。  
  2. XMVECTOR XMVector3LengthSq(FXMVECTOR v);   //長度L平方根,結果存放同上。其他任何返回scalar數的同理  
  3. XMVECTOR XMVector3Dot(FXMVECTOR v1, FXMVECTOR v2);  //點積dot,[dot, dot, dot, dot]  
  4. XMVECTOR XMVector3Cross(FXMVECTOR v1, FXMVECTOR v2);    //叉乘  
  5. XMVECTOR XMVector3Normalize(FXMVECTOR v);       //歸一化  
  6. XMVECTOR XMVector3Orthogonal(FXMVECTOR v);      //返回一個垂直的向量  
  7. XMVECTOR XMVector3AngleBetweenVectors(FXMVECTOR v1, FXMVECTOR v2);  //返回兩向量間角度angle,[angle, angle, angle, angle]  

 

       學習XNA Math庫的最好方法就是參考SDK,在安裝好最新DirectX SDK后都會有個文檔《DirectX Documentation for C++》,里面有XNA Math詳細介紹,遇到不懂的函數可以直接在上面查找。以上只是對XMVECTOR的一些基本介紹,其他所有的XNA Math函數、類型都可以參考SDK。

       最后,附加作者Luna的源代碼,通過示例來熟悉XMVECTOR的用法。

       XMVectorGetSampleCode();


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM