【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指令集可用時,可以定義爲:

typedef __m128 XMVECTOR;


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

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

typedef struct _XMFLOAT2
{
    FLOAT x;
    FLOAT y;
} XMFLOAT2;

typedef struct _XMFLOAT3
{
    FLOAT x;
    FLOAT y;
    FLOAT z;
} XMFLOAT3;

typedef struct _XMFLOAT4
{
    FLOAT x;
    FLOAT y;
    FLOAT z;
    FLOAT w;
} 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中。如下幾種:

XMVECTOR XMLoadFloat2(CONST XMFLOAT2 *pSource);		//從XMFLOAT2中讀取內容到一個XMVECTOR中
XMVECTOR XMLoadFloat3(CONST XMFLOAT3 *pSource);		//從XMFLOAT3中讀取內容到一個XMVECTOR中
XMVECTOR XMLoadFloat4(CONST XMFLOAT4 *pSource);		//從XMFLOAT4中讀取內容到一個XMVECTOR中

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

XMVECTOR XMLoadInt2(CONST UINT *pSource);		//從二維UINT向量中讀取內容到一個XMVECTOR向量中
XMVECTOR XMLoadColor(CONST XMCOLOR *pSource);		//從XMCOLOR中讀取內容到一個XMVECTOR中
XMVECTOR XMLoadByte4(CONST XMBYTE4 *pSource);		//從XMBYTE4中讀取內容到一個XMVECTOR中

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

void XMStoreFloat2(XMFLOAT2 *pDest, FXMVECTOR V);	//把XMVECTOR存儲到一個XMFLOAT2向量中
void XMStoreFloat3(XMFLOAT3 *pDest, FXMVECTOR V);	//把XMVECTOR存儲到一個XMFLOAT3向量中
void XMStoreFloat4(XMFLOAT4 *pDest, FXMVECTOR V);	//把XMVECTOR存儲到一個XMFLOAT4向量中

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

void XMStoreInt3(UINT *pDest, FXMVECTOR V);		//把XMVECTOR存儲到一個二維UINT向量中	
void XMStoreColor(XMCOLOR *pDest, FXMVECTOR V);		//把XMVECTOR存儲到一個XMCOLOR向量中
void XMStoreByte4(XMBYTE4 *pDest, FXMVECTOR V);		//把XMVECTOR存儲到一個XMBYTE4向量中

 

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

FLOAT XMVectorGetX(FXMVECTOR V);	//得到XMVECTOR的X維數據
FLOAT XMVectorGetY(FXMVECTOR V);	//得到XMVECTOR的Y維數據
FLOAT XMVectorGetZ(FXMVECTOR V);	//得到XMVECTOR的Z維數據
FLOAT XMVectorGetW(FXMVECTOR V);	//得到XMVECTOR的W維數據

XMVECTOR XMVectorSetX(FXMVECTOR V, FLOAT x);	//設置一個XMVECTOR的X維數據,並返回新XMVECTOR
XMVECTOR XMVectorSetY(FXMVECTOR V, FLOAT y);	//設置一個XMVECTOR的Y維數據,並返回新XMVECTOR
XMVECTOR XMVectorSetZ(FXMVECTOR V, FLOAT z);	//設置一個XMVECTOR的Z維數據,並返回新XMVECTOR
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。

XMINLINE XMMATRIX XMMatrixTransformation(
		FXMVECTOR ScalingOrigin,					//第1個XMVECTOR類型參數
		FXMVECTOR ScalingOrientationQuaternion,				//第2個XMVECTOR類型參數
		FXMVECTOR Scaling,						//第3個XMVECTOR類型參數
		CXMVECTOR RotationOrigin,					//第4個開始,後面的全部爲CXMVECTOR類型
		CXMVECTOR RotationQuaternion,
		CXMVECTOR Translation);	

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

XMINLINE XMMATRIX XMMatrixTransformation2D(
		FXMVECTOR ScalingOrigin,					//第1個XMVECTOR類型參數
		FLOAT	  ScalingOrientation,
		FXMVECTOR Scaling,						//第2個XMVECTOR類型參數
		FXMVECTOR RotationOrigin,					//第3個XMVECTOR類型參數
		FLOAT	  Rotation,
		CXMVECTOR Translation);						//第4個,必須使用CXMVECTOR

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

        五、 常量向量

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

const XMVECTORF32 g_Zero = {0.f,0.f,0.f,0.f};
static const XMVECTORF32 g_tmp = {x,y,z,w};

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

typedef _DECLSPEC_ALIGN_16_ struct XMVECTORF32
{
	union
	{
		float v[4];
		XMVECTOR v;
	};
	
	//如果是在C++環境下,則還有其他成員函數
	//比如重載()操作符,轉換爲XMVECTOR類型
};

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

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

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

       七、 一些Setter函數

XMVECTOR XMVectorZero();		//[0,0,0,0]
XMVECTOR XMVectorSplatOne();	//[1.f, 1.f, 1.f, 1.f]
XVMECTOR XMVectorSet(FLOAT x, FLOAT y, FLOAT z, FLOAT w);	//[x,y,z,w]
XMVECTOR XMVectorReplicate(FLOAT s);	//[s, s, s, s]
XMVECTOR XMVectorSplatX(FXMVECTOR v);	//[v.x, v.x, v.x, v.x]
XMVECTOR XMVectorSplatY(FXMVECTOR v);	//[v.y, v.y, v.y, v.y]
XMVECTOR XMVectorSplatZ(FXMVECTOR v);	//[v.y, v.y, v.y, v.y]

       八、 向量操作函數

XMVECTOR XMVector3Length(FXMVECTOR v);	   //長度L,結果爲[L,L,L,L],效率起見,全部爲XMVECTOR類型,我們只取一個維即可。
XMVECTOR XMVector3LengthSq(FXMVECTOR v);   //長度L平方根,結果存放同上。其他任何返回scalar數的同理
XMVECTOR XMVector3Dot(FXMVECTOR v1, FXMVECTOR v2);	//點積dot,[dot, dot, dot, dot]
XMVECTOR XMVector3Cross(FXMVECTOR v1, FXMVECTOR v2);	//叉乘
XMVECTOR XMVector3Normalize(FXMVECTOR v);		//歸一化
XMVECTOR XMVector3Orthogonal(FXMVECTOR v);		//返回一個垂直的向量
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();
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章