DirectX11 With Windows SDK--06 DirectXMath數學庫

前言

xnamath.h本來是位於DirectX SDK的一個數學庫,可是如今Windows SDK包含的數學庫已經拋棄掉原來的xnamath.h,並演變成了如今的DirectXMath.h。其實本質上並無多大區別,只是將原來的xna數學函數移植到了這裏,並多了一層名稱空間DirectXhtml

DirectX11 With Windows SDK完整目錄git

Github項目源碼github

歡迎加入QQ羣: 727623616 能夠一塊兒探討DX11,以及有什麼問題也能夠在這裏彙報。數組

SIMD與SSE2指令集加速

SIMD(單指令多數據)能夠僅使用一條指令就同時完成多個數據的運算或處理。架構

其中Intel處理器支持SSE2(SIMD流擴展2)指令集,提供了128位的寄存器,在硬件層面上能夠作到同時進行4個32位float或者uint的運算,特別適合用於表示4D向量或者4x4的矩陣。而xna數學庫正是利用了SSE2指令集來實現硬件加速,在運算性能上有所提高。ide

默認狀況下,VS的項目會直接支持SSE2指令集。函數

向量和矩陣

向量

在xna數學庫中,用於運算的向量類型爲XMVECTOR,能夠看到:性能

typedef __m128 XMVECTOR;

而__m128是一個共用體:測試

typedef union __declspec(intrin_type) __declspec(align(16)) __m128 {
     float               m128_f32[4];
     unsigned __int64    m128_u64[2];
     __int8              m128_i8[16];
     __int16             m128_i16[8];
     __int32             m128_i32[4];
     __int64             m128_i64[2];
     unsigned __int8     m128_u8[16];
     unsigned __int16    m128_u16[8];
     unsigned __int32    m128_u32[4];
 } __m128;

能夠發現,__m128是一種固有類型,而且在內存上嚴格要求按16字節對齊,即在內存上的地址最後一個十六進制值必須從0開始。除此以外,它還能夠被表示成各類類型。在這裏,內存要求對齊是由於寄存器從內存中讀取或者寫入數據也是直接按對齊的16字節進行的,確保快速讀寫。ui

若是須要存儲向量,則應該用下面的這些類型來進行存儲:

2D向量: XMFLOAT2(經常使用), XMINT2, XMUINT2
3D向量: XMFLOAT3(經常使用), XMINT3, XMUINT3
4D向量: XMFLOAT4(經常使用), XMINT4, XMUINT4

這些類型能夠比較方便進行賦值修改,但不支持運算。

向量的存取

因爲XMFLOAT3等這些用於存儲的類型是不能直接用到指令集加速的。要想進行向量的運算,就須要從用於存儲的變量,經過讀取函數,將數據讀入到XMVECTOR下面這些函數都是用於向量的讀取:

// 2D向量讀取
XMVECTOR XMLoadFloat2(const XMFLOAT2* pSource);
XMVECTOR XMLoadSInt2(const XMINT2* pSource);
XMVECTOR XMLoadUInt2(const XMUINT2* pSource);
// 3D向量讀取
XMVECTOR XMLoadFloat3(const XMFLOAT3* pSource);
XMVECTOR XMLoadSInt3(const XMINT3* pSource);
XMVECTOR XMLoadUInt3(const XMUINT3* pSource);
// 4D向量讀取
XMVECTOR XMLoadFloat4(const XMFLOAT4* pSource);
XMVECTOR XMLoadSInt4(const XMINT4* pSource);
XMVECTOR XMLoadUInt4(const XMUINT4* pSource);

調用了對向量的一些操做、運算函數後,咱們須要使用存儲函數將結果保存起來

// 2D向量存儲
void XMStoreFloat2(XMFLOAT2* pDestination, FXMVECTOR V);
void XMStoreSInt2(XMINT2* pDestination, FXMVECTOR V);
void XMStoreUInt2(XMUINT2* pDestination, FXMVECTOR V);
// 3D向量存儲
void XMStoreFloat3(XMFLOAT3* pDestination, FXMVECTOR V);
void XMStoreSInt3(XMINT3* pDestination, FXMVECTOR V);
void XMStoreUInt3(XMUINT3* pDestination, FXMVECTOR V);
// 4D向量存儲
void XMStoreFloat4(XMFLOAT4* pDestination, FXMVECTOR V);
void XMStoreSInt4(XMINT4* pDestination, FXMVECTOR V);
void XMStoreUInt4(XMUINT4* pDestination, FXMVECTOR V);

向量間的運算

在轉成了XMVECTOR後,就可使用xna的數學庫函數了。首先是向量重載的一些運算符:

// 單目運算符
XMVECTOR XM_CALLCONV operator+ (FXMVECTOR V);
XMVECTOR XM_CALLCONV operator- (FXMVECTOR V);
// 向量的份量運算並賦值
XMVECTOR& XM_CALLCONV operator+= (XMVECTOR& V1, FXMVECTOR V2);
XMVECTOR& XM_CALLCONV operator-= (XMVECTOR& V1, FXMVECTOR V2);
XMVECTOR& XM_CALLCONV operator*= (XMVECTOR& V1, FXMVECTOR V2);
XMVECTOR& XM_CALLCONV operator/= (XMVECTOR& V1, FXMVECTOR V2);
// 向量與標量的乘除
XMVECTOR& XM_CALLCONV operator*= (XMVECTOR& V, float S);
XMVECTOR& XM_CALLCONV operator/= (XMVECTOR& V, float S);
// 向量的份量運算
XMVECTOR XM_CALLCONV operator+ (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR XM_CALLCONV operator- (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR XM_CALLCONV operator* (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR XM_CALLCONV operator/ (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR XM_CALLCONV operator* (FXMVECTOR V, float S);
XMVECTOR XM_CALLCONV operator* (float S, FXMVECTOR V);
XMVECTOR XM_CALLCONV operator/ (FXMVECTOR V, float S);

注意到這裏有FXMVECTOR,能夠查看具體的含義:

// Fix-up for (1st-3rd) XMVECTOR parameters that are pass-in-register for x86, ARM, ARM64, and vector call; by reference otherwise
#if ( defined(_M_IX86) || defined(_M_ARM) || defined(_M_ARM64) || _XM_VECTORCALL_ ) && !defined(_XM_NO_INTRINSICS_)
typedef const XMVECTOR FXMVECTOR;
#else
typedef const XMVECTOR& FXMVECTOR;
#endif

// Fix-up for (4th) XMVECTOR parameter to pass in-register for ARM, ARM64, and x64 vector call; by reference otherwise
#if ( defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || (_XM_VECTORCALL_ && !defined(_M_IX86) ) ) && !defined(_XM_NO_INTRINSICS_)
typedef const XMVECTOR GXMVECTOR;
#else
typedef const XMVECTOR& GXMVECTOR;
#endif

// Fix-up for (5th & 6th) XMVECTOR parameter to pass in-register for ARM64 and vector call; by reference otherwise
#if ( defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || _XM_VECTORCALL_ ) && !defined(_XM_NO_INTRINSICS_)
typedef const XMVECTOR HXMVECTOR;
#else
typedef const XMVECTOR& HXMVECTOR;
#endif

// Fix-up for (7th+) XMVECTOR parameters to pass by reference
typedef const XMVECTOR& CXMVECTOR;

在龍書裏面僅提到了FXMVECTORCXMVECTOR兩種變體,但如今竟然又多出了GXMVECTORHXMVECTOR兩種變體。。。

通過一番分析,其實是不一樣平臺架構的寄存器數目是不同的,若是沒有被解釋成引用類型,則是按值直接傳遞給寄存器,提高傳輸速度;若是被解釋成引用類型的話,則其實是須要經過地址間接的傳遞到寄存器上。

對於x86平臺,或使用__fastcall約定,最多支持3個寄存器

對於ARM平臺,最多支持4個寄存器

對於ARM64或平臺,或使用__vectorcall約定,最多支持6個寄存器

通過測試,本人的電腦在Win32模式下使用了__fastcall約定,能夠支持3個寄存器,在x64模式下則使用了__vectorcall約定,支持6個寄存器。

所以,對於自定義函數,若是須要傳入XMVECTOR的話,前3個向量須要使用FXMVECTOR,第4個向量須要使用GXMVECTOR,第5-6個須要使用HXMVECTOR,從第7個開始則使用CXMVECTOR。 能夠說仍是很是奇葩的約定了。

而若是要傳入XMMATRIX的話,第1個矩陣須要使用FXMMATRIX,其他矩陣須要使用CXMMATRIX

除此以外上面的函數還使用了XM_CALLCONV宏,觀察該宏的定義:

#if _XM_VECTORCALL_
#define XM_CALLCONV __vectorcall
#else
#define XM_CALLCONV __fastcall

對於x86/Win32平臺,使用的是__fastcall,而x64平臺則使用的是__vectorcall。它們的目的都是爲了能把儘量多的變量直接傳入寄存器,只不過__vectorcall可以比__fastcall傳入更多的變量到寄存器上。

所以,對於自定義函數,只要是使用了XMVECTOR或者XMMATRIX做爲形參,則必須在函數名前加上XM_CALLCONV,不然在x86模式可能會出現下述錯誤:
formal parameter with requested alignment of 16 won't be aligned

接下來列出一些可能比較經常使用的向量相關函數:

// 用於獲取向量的函數
XMVECTOR XM_CALLCONV XMVectorZero();    // 返回向量(0.0f, 0.0f, 0.0f, 0.0f)
XMVECTOR XM_CALLCONV XMVectorSet(float x, float y, float z, float w);   // 返回向量(x, y, z, w)
XMVECTOR XM_CALLCONV XMVectorReplicate(float Value);    // 返回向量(Value, Value, Value, Value)
XMVECTOR XM_CALLCONV XMVectorSplatX(FXMVECTOR V);       // 返回向量(V.x, V.x, V.x, V.x)
XMVECTOR XM_CALLCONV XMVectorSplatY(FXMVECTOR V);       // 返回向量(V.y, V.y, V.y, V.y)
XMVECTOR XM_CALLCONV XMVectorSplatZ(FXMVECTOR V);       // 返回向量(V.z, V.z, V.z, V.z)
XMVECTOR XM_CALLCONV XMVectorSplatW(FXMVECTOR V);       // 返回向量(V.w, V.w, V.w, V.w)
XMVECTOR XM_CALLCONV XMVectorTrueInt();                 // 返回128位全1的向量
XMVECTOR XM_CALLCONV XMVectorFalseInt();                // 返回128位全0的向量

// 用於獲取向量份量的函數
float XM_CALLCONV XMVectorGetX(FXMVECTOR V);    // 獲取份量V.x
float XM_CALLCONV XMVectorGetY(FXMVECTOR V);    // 獲取份量V.y
float XM_CALLCONV XMVectorGetZ(FXMVECTOR V);    // 獲取份量V.z
float XM_CALLCONV XMVectorGetW(FXMVECTOR V);    // 獲取份量V.w

// 用於設置向量份量的函數
XMVECTOR XM_CALLCONV XMVectorSetX(FXMVECTOR V, float x);    // 返回向量(x, V.y, V.z, V.w)
XMVECTOR XM_CALLCONV XMVectorSetY(FXMVECTOR V, float y);    // 返回向量(V.x, y, V.z, V.w)
XMVECTOR XM_CALLCONV XMVectorSetZ(FXMVECTOR V, float z);    // 返回向量(V.x, V.y, z, V.w)
XMVECTOR XM_CALLCONV XMVectorSetW(FXMVECTOR V, float w);    // 返回向量(V.x, V.y, V.z, w)
XMVECTOR XM_CALLCONV XMVectorSwizzle(FXMVECTOR V, uint32_t E0, uint32_t E1, uint32_t E2, uint32_t E3);  // 返回向量(V[E0], V[E1], V[E2], V[E3])

// 用於向量比較的函數
// 下面這些函數若爲真,返回128位全1,不然返回128位全0
XMVECTOR XM_CALLCONV XMVectorEqual(FXMVECTOR V1, FXMVECTOR V2);         // 對比兩個向量128位是否都相同
XMVECTOR XM_CALLCONV XMVectorNotEqual(FXMVECTOR V1, FXMVECTOR V2);      // 對比兩個向量128位是否存在不一樣
XMVECTOR XM_CALLCONV XMVectorGreater(FXMVECTOR V1, FXMVECTOR V2);       // 對比V1四個份量是否都比V2的大
XMVECTOR XM_CALLCONV XMVectorGreaterOrEqual(FXMVECTOR V1, FXMVECTOR V2);// 對比V1四個份量是否都比V2的大或相等
XMVECTOR XM_CALLCONV XMVectorLess(FXMVECTOR V1, FXMVECTOR V2);          // 對比V1四個份量是否都比V2的小
XMVECTOR XM_CALLCONV XMVectorLessOrEqual(FXMVECTOR V1, FXMVECTOR V2);   // 對比V1四個份量是否都比V2的小或相等

// 用於向量份量操做的函數
XMVECTOR XM_CALLCONV XMVectorMin(FXMVECTOR V1, FXMVECTOR V2);   // 返回向量的每個份量對應V1和V2份量的最小值
XMVECTOR XM_CALLCONV XMVectorMax(FXMVECTOR V1, FXMVECTOR V2);   // 返回向量的每個份量對應V1和V2份量的最大值
XMVECTOR XM_CALLCONV XMVectorRound(FXMVECTOR V);                // 對每一個份量四捨五入
XMVECTOR XM_CALLCONV XMVectorFloor(FXMVECTOR V);                // 對每一個份量向下取整
XMVECTOR XM_CALLCONV XMVectorCeiling(FXMVECTOR V);              // 對每一個份量向上取整
XMVECTOR XM_CALLCONV XMVectorClamp(FXMVECTOR V, FXMVECTOR Min, FXMVECTOR Max);  // 對每一個份量限定在[Min, Max]範圍
XMVECTOR XM_CALLCONV XMVectorSaturate(FXMVECTOR V);             // 對每一個份量限定在[0.0f, 1.0f]範圍
XMVECTOR XM_CALLCONV XMVectorReciprocal(FXMVECTOR V);               // 返回(1/V.x, 1/V.y, 1/V.z, 1/V.w)

// 2D向量的函數
XMVECTOR XM_CALLCONV XMVector2Dot(FXMVECTOR V1, FXMVECTOR V2);      // 每一個份量都是V1.x * V2.x + V1.y * V2.y
XMVECTOR XM_CALLCONV XMVector2Cross(FXMVECTOR V1, FXMVECTOR V2);    // 每一個份量都是V1.x * V2.y - V2.x * V1.y
XMVECTOR XM_CALLCONV XMVector2LengthSq(FXMVECTOR V);                // 每一個份量都是V.x * V.x + V.y * V.y
XMVECTOR XM_CALLCONV XMVector2Length(FXMVECTOR V);                  // 每一個份量都是sqrt(V.x * V.x + V.y * V.y)
XMVECTOR XM_CALLCONV XMVector2Normalize(FXMVECTOR V);               // 標準化2D向量(單位向量化)
XMVECTOR XM_CALLCONV XMVector2Reflect(FXMVECTOR Incident, FXMVECTOR Normal);    // 鏡面反射向量
XMVECTOR XM_CALLCONV XMVector2LinePointDistance(FXMVECTOR LinePoint1, FXMVECTOR LinePoint2, FXMVECTOR Point);   // 每一個份量都是點到直線的距離

// 3D向量的函數
XMVECTOR XM_CALLCONV XMVector3Dot(FXMVECTOR V1, FXMVECTOR V2);      // 每一個份量都是V1.x * V2.x + V1.y * V2.y + V1.z * V2.z
XMVECTOR XM_CALLCONV XMVector3Cross(FXMVECTOR V1, FXMVECTOR V2);    // 返回(V1.y * V2.z - V1.z * V2.y, V1.z * V2.x - V1.x * V2.z, V1.x * V2.y - V1.y * V2.x, 0.0f)
XMVECTOR XM_CALLCONV XMVector3LengthSq(FXMVECTOR V);                // 每一個份量都是V.x * V.x + V.y * V.y + V.z * V.z
XMVECTOR XM_CALLCONV XMVector3Length(FXMVECTOR V);                  // 每一個份量都是sqrt(V.x * V.x + V.y * V.y + V.z * V.z)
XMVECTOR XM_CALLCONV XMVector3Normalize(FXMVECTOR V);               // 標準化3D向量(單位向量化)
XMVECTOR XM_CALLCONV XMVector3Reflect(FXMVECTOR Incident, FXMVECTOR Normal);    // 鏡面反射向量
XMVECTOR XM_CALLCONV XMVector3LinePointDistance(FXMVECTOR LinePoint1, FXMVECTOR LinePoint2, FXMVECTOR Point);   // 每一個份量都是點到直線的距離

// 4D向量的函數
XMVECTOR XM_CALLCONV XMVector4Dot(FXMVECTOR V1, FXMVECTOR V2);      // 每一個份量都是V1.x * V2.x + V1.y * V2.y + V1.z * V2.z + V1.w * V2.w
XMVECTOR XM_CALLCONV XMVector4LengthSq(FXMVECTOR V);                // 每一個份量都是V.x * V.x + V.y * V.y + V.z * V.z + V.w * V.w
XMVECTOR XM_CALLCONV XMVector4Length(FXMVECTOR V);                  // 每一個份量都是sqrt(V.x * V.x + V.y * V.y + V.z * V.z + V.w * V.w)
XMVECTOR XM_CALLCONV XMVector4Normalize(FXMVECTOR V);               // 標準化4D向量(單位向量化)
XMVECTOR XM_CALLCONV XMVector4Reflect(FXMVECTOR Incident, FXMVECTOR Normal);    // 鏡面反射向量

矩陣

在xna數學庫中,用於運算的矩陣類型爲XMMATRIX,實際上裏面是由4個XMVECTOR的數組構成的結構體。

若是須要存儲矩陣,則可使用下面這些類型:

XMFLOAT3X3
XMFLOAT4X3
XMFLOAT4X4

矩陣的存取

要想進行矩陣的運算,就須要從用於存儲的變量,經過讀取函數,將數據讀入到XMMATRIX。下面這些函數都是用於矩陣的讀取:

XMMATRIX XM_CALLCONV XMLoadFloat3x3(const XMFLOAT3X3* pSource);
XMMATRIX XM_CALLCONV XMLoadFloat4x3(const XMFLOAT4X3* pSource);
XMMATRIX XM_CALLCONV XMLoadFloat4x4(const XMFLOAT4X4* pSource);

若是須要存儲運算獲得的矩陣,則可使用下面的函數:

void XM_CALLCONV XMStoreFloat3x3(XMFLOAT3X3* pDestination, FXMMATRIX M);
void XM_CALLCONV XMStoreFloat4x3(XMFLOAT4X3* pDestination, FXMMATRIX M);
void XM_CALLCONV XMStoreFloat4x4(XMFLOAT4X4* pDestination, FXMMATRIX M);

矩陣間的運算

在轉成了XMMATRIX後,就可使用xna的數學庫函數了。首先是矩陣重載的一些運算符,這些都是矩陣類內定義的函數:

// 賦值
XMMATRIX& operator= (const XMMATRIX& M);
// 單目符號運算符
XMMATRIX operator+ () const;
XMMATRIX operator- () const;
// 運算並賦值
XMMATRIX& XM_CALLCONV operator+= (FXMMATRIX M);
XMMATRIX& XM_CALLCONV operator-= (FXMMATRIX M);
XMMATRIX& XM_CALLCONV operator*= (FXMMATRIX M);
XMMATRIX& operator*= (float S);
XMMATRIX& operator/= (float S);
// 矩陣運算,注意矩陣與矩陣的乘法不是各份量相乘的
XMMATRIX XM_CALLCONV operator+ (FXMMATRIX M) const;
XMMATRIX XM_CALLCONV operator- (FXMMATRIX M) const;
XMMATRIX XM_CALLCONV operator* (FXMMATRIX M) const;
XMMATRIX operator* (float S) const;
XMMATRIX operator/ (float S) const;

friend XMMATRIX XM_CALLCONV operator* (float S, FXMMATRIX M);

而後是一些經常使用的矩陣函數:

bool XM_CALLCONV XMMatrixIsNaN(FXMMATRIX M);            // 矩陣的每一個份量都不是一個數(NaN)
bool XM_CALLCONV XMMatrixIsInfinite(FXMMATRIX M);       // 矩陣的每一個份量都是無窮大
bool XM_CALLCONV XMMatrixIsIdentity(FXMMATRIX M);       // 矩陣是否爲單位向量

XMMATRIX XM_CALLCONV XMMatrixMultiply(FXMMATRIX M1, CXMMATRIX M2);              // 矩陣乘法
XMMATRIX XM_CALLCONV XMMatrixMultiplyTranspose(FXMMATRIX M1, CXMMATRIX M2);     // 矩陣乘法後轉置
XMMATRIX XM_CALLCONV XMMatrixTranspose(FXMMATRIX M);                            // 矩陣轉置
XMMATRIX XM_CALLCONV XMMatrixInverse(_Out_opt_ XMVECTOR* pDeterminant, _In_ FXMMATRIX M);   // 矩陣求逆,可選輸出行列式
XMVECTOR XM_CALLCONV XMMatrixDeterminant(FXMMATRIX M);                          // 矩陣求行列式,每一個份量都是

// 將矩陣的縮放、旋轉、平移份量拆出來,其中旋轉份量是四元數
bool XM_CALLCONV XMMatrixDecompose(_Out_ XMVECTOR *outScale, _Out_ XMVECTOR *outRotQuat, _Out_ XMVECTOR *outTrans, _In_ FXMMATRIX M);   

XMMATRIX XM_CALLCONV XMMatrixIdentity();        // 獲取單位向量
XMMATRIX XM_CALLCONV XMMatrixSet(float m00, float m01, float m02, float m03,    // 設置每一個份量並獲取一個矩陣
    float m10, float m11, float m12, float m13,
    float m20, float m21, float m22, float m23,
    float m30, float m31, float m32, float m33);
XMMATRIX XM_CALLCONV XMMatrixTranslation(float OffsetX, float OffsetY, float OffsetZ);  // 平移矩陣
XMMATRIX XM_CALLCONV XMMatrixTranslationFromVector(FXMVECTOR Offset);                   // 使用向量來獲取平移矩陣
XMMATRIX XM_CALLCONV XMMatrixScaling(float ScaleX, float ScaleY, float ScaleZ);         // 縮放矩陣
XMMATRIX XM_CALLCONV XMMatrixScalingFromVector(FXMVECTOR Scale);                        // 使用向量來獲取縮放矩陣
XMMATRIX XM_CALLCONV XMMatrixRotationX(float Angle);                                    // 繞X軸旋轉(弧度,從X軸正方向朝原點看順時針)矩陣                            
XMMATRIX XM_CALLCONV XMMatrixRotationY(float Angle);                                    // 繞Y軸旋轉(弧度,從Y軸正方向朝原點看順時針)矩陣
XMMATRIX XM_CALLCONV XMMatrixRotationZ(float Angle);                                    // 繞Z軸旋轉(弧度,從Z軸正方向朝原點看順時針)矩陣
XMMATRIX XM_CALLCONV XMMatrixRotationRollPitchYaw(float Pitch, float Yaw, float Roll);  // 按照先繞Z軸,而後X軸,最後Y軸的順序獲得旋轉矩陣(弧度,逆時針)
XMMATRIX XM_CALLCONV XMMatrixRotationRollPitchYawFromVector(FXMVECTOR Angles);          // 使用向量來獲取旋轉矩陣(弧度,逆時針)
XMMATRIX XM_CALLCONV XMMatrixRotationNormal(FXMVECTOR NormalAxis, float Angle);         // 繞通過標準化的向量軸旋轉(弧度,逆時針)矩陣
XMMATRIX XM_CALLCONV XMMatrixRotationAxis(FXMVECTOR Axis, float Angle);                 // 繞向量軸旋轉(弧度,逆時針)矩陣,若軸已經標準化,應該用上面的函數
XMMATRIX XM_CALLCONV XMMatrixRotationQuaternion(FXMVECTOR Quaternion);                  // 用旋轉四元數構造旋轉矩陣
XMMATRIX XM_CALLCONV XMMatrixReflect(FXMVECTOR ReflectionPlane);                        // 平面反射矩陣
XMMATRIX XM_CALLCONV XMMatrixShadow(FXMVECTOR ShadowPlane, FXMVECTOR LightPosition);    // 陰影矩陣

XMMATRIX XM_CALLCONV XMMatrixLookAtLH(FXMVECTOR EyePosition, FXMVECTOR FocusPosition, FXMVECTOR UpDirection);   // 觀察矩陣
XMMATRIX XM_CALLCONV XMMatrixPerspectiveFovLH(float FovAngleY, float AspectRatio, float NearZ, float FarZ);     // 透視投影矩陣

向量與矩陣的運算

接下來是經常使用的向量與矩陣的運算:

// 2D向量與矩陣的函數
XMVECTOR XM_CALLCONV XMVector2Transform(FXMVECTOR V, FXMMATRIX M);  // 2D向量與矩陣相乘
XMVECTOR XM_CALLCONV XMVector2TransformCoord(FXMVECTOR V, FXMMATRIX M);     // 假定要變換的是2D座標點,矩陣相乘後對每一個份量除以w,使得最後w份量爲1.0f
XMVECTOR XM_CALLCONV XMVector2TransformNormal(FXMVECTOR V, FXMMATRIX M);    // 假定要變換的是2D向量,則平移變換無效,最後獲得的向量w份量爲0.0f

// 3D向量與矩陣的函數
XMVECTOR XM_CALLCONV XMVector3Transform(FXMVECTOR V, FXMMATRIX M);  // 3D向量與矩陣相乘
XMVECTOR XM_CALLCONV XMVector3TransformCoord(FXMVECTOR V, FXMMATRIX M);     // 假定要變換的是3D座標點,矩陣相乘後對每一個份量除以w,使得最後w份量爲1.0f
XMVECTOR XM_CALLCONV XMVector3TransformNormal(FXMVECTOR V, FXMMATRIX M);    // 假定要變換的是3D向量,則平移變換無效,最後獲得的向量w份量爲0.0f
XMVECTOR XM_CALLCONV XMVector3Project(FXMVECTOR V, float ViewportX, float ViewportY, float ViewportWidth, float ViewportHeight, float ViewportMinZ, float ViewportMaxZ,
    FXMMATRIX Projection, CXMMATRIX View, CXMMATRIX World);     // 通過四大變換後,得到最終在屏幕上的像素位置和深度構成的向量,即(x, y, depth, 0.0f)
XMVECTOR XM_CALLCONV XMVector3Unproject(FXMVECTOR V, float ViewportX, float ViewportY, float ViewportWidth, float ViewportHeight, float ViewportMinZ, float ViewportMaxZ,
    FXMMATRIX Projection, CXMMATRIX View, CXMMATRIX World);     // 從屏幕像素位置和深度構成的向量(x, y, depth, 0.0f)開始,進行逆變換,獲得在世界的位置

// 4D向量與矩陣的函數
XMVECTOR XM_CALLCONV XMVector4Transform(FXMVECTOR V, FXMMATRIX M);  // 4D向量與矩陣相乘

雜項

DirectXMath.h還定義了一些經常使用的XM_CONST常量表達式,其中XM_CONST的宏定義以下:

#define XM_CONST constexpr

XM_CONST定義的比較常常用到的常量有:

XM_CONST float XM_PI        = 3.141592654f;
XM_CONST float XM_2PI       = 6.283185307f;
XM_CONST float XM_1DIVPI    = 0.318309886f;
XM_CONST float XM_1DIV2PI   = 0.159154943f;
XM_CONST float XM_PIDIV2    = 1.570796327f;
XM_CONST float XM_PIDIV4    = 0.785398163f;

因爲通常狀況下XMVECTOR的產生要麼是來自讀取函數,要麼是來自XMVectorSet函數,而某些固定的向量若是常用Setter來獲取,會產生大量重複的內存讀取操做。所以在DirectXMath.h中還定義了一些有用的常向量來避免重複的讀取,這些向量的類型都爲XMVECTORF32

XMGLOBALCONST XMVECTORF32 g_XMIdentityR0            = { { { 1.0f, 0.0f, 0.0f, 0.0f } } };
XMGLOBALCONST XMVECTORF32 g_XMIdentityR1            = { { { 0.0f, 1.0f, 0.0f, 0.0f } } };
XMGLOBALCONST XMVECTORF32 g_XMIdentityR2            = { { { 0.0f, 0.0f, 1.0f, 0.0f } } };
XMGLOBALCONST XMVECTORF32 g_XMIdentityR3            = { { { 0.0f, 0.0f, 0.0f, 1.0f } } };
XMGLOBALCONST XMVECTORF32 g_XMNegIdentityR0         = { { { -1.0f, 0.0f, 0.0f, 0.0f } } };
XMGLOBALCONST XMVECTORF32 g_XMNegIdentityR1         = { { { 0.0f, -1.0f, 0.0f, 0.0f } } };
XMGLOBALCONST XMVECTORF32 g_XMNegIdentityR2         = { { { 0.0f, 0.0f, -1.0f, 0.0f } } };
XMGLOBALCONST XMVECTORF32 g_XMNegIdentityR3         = { { { 0.0f, 0.0f, 0.0f, -1.0f } } };
XMGLOBALCONST XMVECTORF32 g_XMOne                   = { { { 1.0f, 1.0f, 1.0f, 1.0f } } };
XMGLOBALCONST XMVECTORF32 g_XMZero                  = { { { 0.0f, 0.0f, 0.0f, 0.0f } } };
XMGLOBALCONST XMVECTORF32 g_XMNegativeOne           = { { { -1.0f, -1.0f, -1.0f, -1.0f } } };
XMGLOBALCONST XMVECTORF32 g_XMOneHalf               = { { { 0.5f, 0.5f, 0.5f, 0.5f } } };
XMGLOBALCONST XMVECTORF32 g_XMNegativeOneHalf       = { { { -0.5f, -0.5f, -0.5f, -0.5f } } };
XMGLOBALCONST XMVECTORF32 g_XMNegativeTwoPi         = { { { -XM_2PI, -XM_2PI, -XM_2PI, -XM_2PI } } };
XMGLOBALCONST XMVECTORF32 g_XMNegativePi            = { { { -XM_PI, -XM_PI, -XM_PI, -XM_PI } } };
XMGLOBALCONST XMVECTORF32 g_XMHalfPi                = { { { XM_PIDIV2, XM_PIDIV2, XM_PIDIV2, XM_PIDIV2 } } };
XMGLOBALCONST XMVECTORF32 g_XMPi                    = { { { XM_PI, XM_PI, XM_PI, XM_PI } } };
XMGLOBALCONST XMVECTORF32 g_XMReciprocalPi          = { { { XM_1DIVPI, XM_1DIVPI, XM_1DIVPI, XM_1DIVPI } } };
XMGLOBALCONST XMVECTORF32 g_XMTwoPi                 = { { { XM_2PI, XM_2PI, XM_2PI, XM_2PI } } };
XMGLOBALCONST XMVECTORF32 g_XMReciprocalTwoPi       = { { { XM_1DIV2PI, XM_1DIV2PI, XM_1DIV2PI, XM_1DIV2PI } } };

經過調用共用體成員v就能夠獲取XMVECTOR,如g_XMOne.v

DirectX11 With Windows SDK完整目錄

Github項目源碼

歡迎加入QQ羣: 727623616 能夠一塊兒探討DX11,以及有什麼問題也能夠在這裏彙報。

相關文章
相關標籤/搜索