-
d3d12龍書閱讀----數(shù)學(xué)基礎(chǔ) 向量代數(shù)、矩陣代數(shù)、變換
- directx 采用左手坐標(biāo)系
- 點積與叉積
-
點積與叉積的正交化
- 使用點積進(jìn)行正交化
- 使用叉積進(jìn)行正交化
- 矩陣與矩陣乘法
- 轉(zhuǎn)置矩陣 單位矩陣 逆矩陣 矩陣行列式
-
變換
- 旋轉(zhuǎn)矩陣
- 坐標(biāo)變換
-
利用DirectXMath庫進(jìn)行向量運算、矩陣運算以及空間變換
- 頭文件與命名空間
- 核心向量類型 XMVECTOR
- FMVECTOR GMVECTOR HMVECTOR CMVECTOR XM_CALLCONV
- XMFLOAT 與 XMVECTOR之間的相互轉(zhuǎn)換
- 向量的初始化
- 向量的運算
- XMMATRIX定義與初始化
- XMMATRIX FXMMATRIX CXMMTRIX
- 矩陣操作的常用函數(shù)
- 空間變換
d3d12龍書閱讀----數(shù)學(xué)基礎(chǔ) 向量代數(shù)、矩陣代數(shù)、變換
directx 采用左手坐標(biāo)系
在directx中,坐標(biāo)系統(tǒng)一采用左手坐標(biāo)系,與opengl采用右手坐標(biāo)系不同
四指向右指向x軸,然后彎曲向y軸,大拇指的方向即z軸正方向
點積與叉積
略
點積與叉積的正交化
規(guī)范正交向量集:對于向量集的每個向量,它與其它向量之前都是互相正交,并且都是單位向量
正交化:將不規(guī)范正交的集合轉(zhuǎn)換為規(guī)范正交的集合
使用點積進(jìn)行正交化
對于二維 兩個向量的正交化來說
將第一個向量作為起始向量,將其標(biāo)準(zhǔn)化為單位向量
然后第二個向量減去在第一個向量上的投影,就只剩下與其正交的那部分,然后再將這部分標(biāo)準(zhǔn)化為單位向量
三維 三個向量
先讓v1與v0正交,然后v2減去在v1與v0方向上的投影,再標(biāo)準(zhǔn)化
更一般的結(jié)論:
使用叉積進(jìn)行正交化
如上圖所示 使用叉積對三個向量進(jìn)行正交化 即 先以其中一個向量v0為基礎(chǔ) 求出它與v1的叉積w2,由于叉積本身的性質(zhì),此時w2已經(jīng)與v0 v1 兩兩正交了,然后再求 w2 與 w0的叉積,就得到了第三個向量
值得注意的是 在進(jìn)行正交化的過程中,我們可以發(fā)現(xiàn)除了我們選為基礎(chǔ)的向量,其余的向量的方向都可能發(fā)生變化,比如在求相機坐標(biāo)系的三個基向量時候,我們不想改變相機觀察向量的方向,此時我們就可以將該向量設(shè)置為起始向量,這樣該向量的方向就不會改變
矩陣與矩陣乘法
directx采用行主序矩陣
在進(jìn)行向量與矩陣的乘法運算時,directx這里采用行向量左乘的形式表達(dá):
最終可以化簡成,向量中每個系數(shù)依次與矩陣的每個行向量進(jìn)行線性組合
轉(zhuǎn)置矩陣 單位矩陣 逆矩陣 矩陣行列式
略
變換
關(guān)于變換的大部分知識games101中已經(jīng)涵蓋 這里就不多贅述
這里主要記錄下旋轉(zhuǎn)矩陣與坐標(biāo)變換
旋轉(zhuǎn)矩陣
這里介紹繞任意軸旋轉(zhuǎn)$\theta $角的公式推導(dǎo):
如上圖所示 黑色的v向量繞著藍(lán)色的k向量旋轉(zhuǎn)$\theta $角,我們可以把v向量分解為垂直于k軸與平行于k軸兩部分,在旋轉(zhuǎn)的過程中,平行于k軸的部分不變,而垂直于k軸的向量發(fā)生改變。
平行于k軸的向量可表示為:
垂直于k軸的向量即可表示為原向量減去平行向量:
垂直向量旋轉(zhuǎn)$\theta $角 如上圖的紅色向量所示 可分解為:
最后的旋轉(zhuǎn)向量 就等于旋轉(zhuǎn)之后的垂直向量 再加上平行向量:
然后將其轉(zhuǎn)換為矩陣形式(這里可以利用叉積的矩陣表示):
坐標(biāo)變換
其實對幾何體進(jìn)行變換與坐標(biāo)變換在數(shù)學(xué)上是等價的:
如上圖所示
一種是從幾何體的平移 旋轉(zhuǎn)的視角來理解(幾何體的坐標(biāo)發(fā)生變化)
一種是從坐標(biāo)系的變換來理解(即基向量的變換,坐標(biāo)不變,坐標(biāo)系變化)
我們可以根據(jù)不同的場景 選擇不同的角度去理解
利用DirectXMath庫進(jìn)行向量運算、矩陣運算以及空間變換
頭文件與命名空間
#include <windows.h> // for XMVerifyCPUSupport
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <iostream>
using namespace std;
using namespace DirectX;
using namespace DirectX::PackedVector;
核心向量類型 XMVECTOR
#if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_)
using XMVECTOR = __m128;
核心向量類型XMVECTOR被定義為_m128這種特殊的SIMD類型,被映射到SIMD寄存器,通過SIMD指令能夠一次處理4個32位的浮點數(shù)
XMVECTOR型的數(shù)據(jù)需要使用16字節(jié)對齊,這對于全局以及局部變量是自動實現(xiàn)的,對于類的數(shù)據(jù)成員,建議使用XMFLOAT2/XMFLOAT3/XMFLOAT4類型的結(jié)構(gòu)體來替代,在實際使用時再將其轉(zhuǎn)換為XMVECTOR類型
XMFLOAT3類型的定義:
// 3D Vector; 32 bit floating point components
struct XMFLOAT3
{
float x;
float y;
float z;
XMFLOAT3() = default;
XMFLOAT3(const XMFLOAT3&) = default;
XMFLOAT3& operator=(const XMFLOAT3&) = default;
XMFLOAT3(XMFLOAT3&&) = default;
XMFLOAT3& operator=(XMFLOAT3&&) = default;
constexpr XMFLOAT3(float _x, float _y, float _z) noexcept : x(_x), y(_y), z(_z) {}
explicit XMFLOAT3(_In_reads_(3) const float* pArray) noexcept : x(pArray[0]), y(pArray[1]), z(pArray[2]) {}
};
FMVECTOR GMVECTOR HMVECTOR CMVECTOR XM_CALLCONV
在進(jìn)行參數(shù)的傳遞時,我們可以直接將XMVECTOR的值作為參數(shù)傳給寄存器,而不是存儲于棧內(nèi),同時為了適應(yīng)不同的平臺與編譯器,定義了FMVECTOR GMVECTOR HMVECTOR CMVECTOR四種類型,可以根據(jù)不同的平臺與編譯器定義為不同的類型。
傳遞規(guī)則如下圖:
書上舉了兩個例子加以說明:
注意:
(1)這里的數(shù)量統(tǒng)計統(tǒng)計的是XMVECTOR類型的參數(shù),而不是其它類型的參數(shù)
(2)定義函數(shù)要加上XM_CALLCONV 注解
對于win32來說:
而XM_CALLCONV 則是定義調(diào)用約定的:
#if _XM_VECTORCALL_
#define XM_CALLCONV __vectorcall
#elif defined(__GNUC__)
#define XM_CALLCONV
#else
#define XM_CALLCONV __fastcall
#endif
(3) 對于構(gòu)造函數(shù), 只要針對前三個 XMVECTOR 值使用 FXMVECTOR,然後針對其餘值使用 CXMVECTOR
(4) 對于輸出參數(shù),一律使用 XMVECTOR* 或 XMVECTOR& ,因為此時它們不使用寄存器,和其它非XMVECTOR類型的參數(shù)一致
其余更為詳細(xì)的說明可查看:https://learn.microsoft.com/zh-tw/windows/win32/dxmath/pg-xnamath-internals
XMFLOAT 與 XMVECTOR之間的相互轉(zhuǎn)換
以float3為例
vector到float3:
inline void XM_CALLCONV XMStoreFloat3
(
XMFLOAT3* pDestination,
FXMVECTOR V
)
ostream& XM_CALLCONV operator << (ostream& os, FXMVECTOR v)
{
XMFLOAT3 dest;
XMStoreFloat3(&dest, v);
os << "(" << dest.x << ", " << dest.y << ", " << dest.z << ")";
return os;
}
float3到vector:
inline XMVECTOR XM_CALLCONV XMLoadFloat3(const XMFLOAT3* pSource)
XMVECTOR test = XMLoadFloat3(&dest);
向量的初始化
我們可以采用多種方法對向量進(jìn)行初始化定義:
// x,y,z,w全部初始化為0
XMVECTOR p = XMVectorZero();
// x,y,z,w全部初始化為1
XMVECTOR q = XMVectorSplatOne();
// 使用四個值來初始化向量
XMVECTOR u = XMVectorSet(1.0f, 2.0f, 3.0f, 0.0f);
// 使用一個值初始化向量的四個值
XMVECTOR v = XMVectorReplicate(-2.0f);
// 使用某個向量的一個方向的值初始化向量的四個值
XMVECTOR w = XMVectorSplatZ(u);
向量的運算
運算符的重載:
// Vector addition: XMVECTOR operator +
XMVECTOR a = u + v;
// Vector subtraction: XMVECTOR operator -
XMVECTOR b = u - v;
// Scalar multiplication: XMVECTOR operator *
XMVECTOR c = 10.0f*u;
向量運算(點積,叉積,單位化等):
//計算向量的長度
XMVECTOR L = XMVector3Length(u);
//求對應(yīng)的單位向量
XMVECTOR d = XMVector3Normalize(u);
//向量之間的點積
XMVECTOR s = XMVector3Dot(u, v);
//向量之間的叉積
XMVECTOR e = XMVector3Cross(u, v);
//求向量w在單位向量n上的投影向量以及垂直向量
XMVECTOR projW;
XMVECTOR perpW;
XMVector3ComponentsFromNormal(&projW, &perpW, w, n);
// 判斷向量之間是否相等
bool equal = XMVector3Equal(projW + perpW, w) != 0;
bool notEqual = XMVector3NotEqual(projW + perpW, w) != 0;
// 計算向量之間的角度
// 計算的是弧度制的數(shù)值結(jié)果
XMVECTOR angleVec = XMVector3AngleBetweenVectors(projW, perpW);
float angleRadians = XMVectorGetX(angleVec);
//轉(zhuǎn)換為角度
float angleDegrees = XMConvertToDegrees(angleRadians);
其它運算:
// 輸出向量v的每個組件的絕對值
cout << "XMVectorAbs(v) = " << XMVectorAbs(v) << endl;
// 輸出向量w的每個組件的余弦值
cout << "XMVectorCos(w) = " << XMVectorCos(w) << endl;
// 輸出向量u的每個組件的自然對數(shù)
cout << "XMVectorLog(u) = " << XMVectorLog(u) << endl;
// 輸出向量p的每個組件的指數(shù)(e的指數(shù))
cout << "XMVectorExp(p) = " << XMVectorExp(p) << endl;
// 輸出向量u和向量p對應(yīng)組件的冪次運算結(jié)果
cout << "XMVectorPow(u, p) = " << XMVectorPow(u, p) << endl;
// 輸出向量u的每個組件的平方根
cout << "XMVectorSqrt(u) = " << XMVectorSqrt(u) << endl;
// 輸出向量u的組件重新排列為(z, z, y, w)的結(jié)果
cout << "XMVectorSwizzle(u, 2, 2, 1, 3) = " << XMVectorSwizzle(u, 2, 2, 1, 3) << endl;
// 輸出向量u的組件重新排列為(z, y, x, w)的結(jié)果
cout << "XMVectorSwizzle(u, 2, 1, 0, 3) = " << XMVectorSwizzle(u, 2, 1, 0, 3) << endl;
// 輸出向量u和向量v對應(yīng)組件的乘積
cout << "XMVectorMultiply(u, v) = " << XMVectorMultiply(u, v) << endl;
// 輸出向量q的每個組件限制在[0, 1]范圍內(nèi)的結(jié)果
cout << "XMVectorSaturate(q) = " << XMVectorSaturate(q) << endl;
// 輸出向量p和向量v對應(yīng)組件的最小值
cout << "XMVectorMin(p, v) = " << XMVectorMin(p, v) << endl;
// 輸出向量p和向量v對應(yīng)組件的最大值
cout << "XMVectorMax(p, v) = " << XMVectorMax(p, v) << endl;
get方法:
注意上述有些向量運算的結(jié)果(比如兩個向量之間的點積等等)應(yīng)該是個標(biāo)量,但是這里仍然使用XMVECTOR來存儲,將標(biāo)量的結(jié)果復(fù)制到XMVECTOR的各個分量之中,這樣做是為了盡可能降低SIMD向量與標(biāo)量的混合運算次數(shù),提高計算效率
XMMATRIX定義與初始化
一般情況下 XMMATRIX是由XMVECTOR數(shù)組構(gòu)成:
XMVECTOR r[4];
初始化:
// 采用四個XMVECTOR初始化
constexpr XMMATRIX(FXMVECTOR R0, FXMVECTOR R1, FXMVECTOR R2, CXMVECTOR R3) noexcept : r{ R0,R1,R2,R3 } {}
// 采用4x4個浮點數(shù)初始化
XMMATRIX(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) noexcept;
// 采用大小為16的浮點數(shù)數(shù)組初始化
explicit XMMATRIX(_In_reads_(16) const float* pArray) noexcept;
除了上述構(gòu)造函數(shù)的方法,我們也可以使用set函數(shù)來初始化:
inline 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
) noexcept
XMMATRIX FXMMATRIX CXMMTRIX
在聲明具有XMMATRIX的參數(shù)時,第一個XMMATRIX參數(shù)應(yīng)當(dāng)為FXMMATRIX,其余應(yīng)為CXMMATRIX
由于一個XMMATRIX矩陣看作四個XMVECTOR參數(shù),所以在fastcall調(diào)用約定下,矩陣類型的數(shù)據(jù)都是通過堆棧加以引用,在vectorcall調(diào)用約定下,F(xiàn)XMMATRIX可以傳至寄存器
注意對于構(gòu)造函數(shù)來說,總是采用CXMMATRIX類型來獲取XMMATRIX參數(shù),不需要使用XM_CALLCONV注解
同時,對于自定義類中的矩陣類型的數(shù)據(jù)成員,建議使用XMFLOAT4X4來存儲類中的矩陣。
XMFLOAT4X4與XMMATRIX之間的相互轉(zhuǎn)換:
矩陣操作的常用函數(shù)
//初始化矩陣
XMMATRIX A(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 2.0f, 0.0f, 0.0f,
0.0f, 0.0f, 4.0f, 0.0f,
1.0f, 2.0f, 3.0f, 1.0f);
//將矩陣初始化為單位陣
XMMATRIX B = XMMatrixIdentity();
// 矩陣乘法
XMMATRIX C = A * B;
//矩陣轉(zhuǎn)置
XMMATRIX D = XMMatrixTranspose(A);
//求矩陣的行列式
XMVECTOR det = XMMatrixDeterminant(A);
//求矩陣的逆
XMMATRIX E = XMMatrixInverse(&det, A);
空間變換
文章來源:http://www.zghlxwxcb.cn/news/detail-825257.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-825257.html
到了這里,關(guān)于d3d12龍書閱讀----數(shù)學(xué)基礎(chǔ) 向量代數(shù)、矩陣代數(shù)、變換的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!