【DirectX 12 GJ的龙书学习笔记 二】向量

“For the things of this world cannot be made known without a knowledge of mathematics.”

Roger Bacon, Opus Majus part 4 Distinctia Prima cap 1, 1267.


现在我们来到了PART I数学基础的学习。

数学的重要性无需多言。由于书中讲述的数学内容仅是为后续内容服务的,并不全面,所以从学习数学的角度讲,书中推荐了两本专讲数学的书籍:

Lengyel, Eric, Mathematics for 3D Game Programming and Computer Graphics. Charles River Media, Inc., 2002.

https://book.douban.com/subject/6675562/

Verth, James M. van, and Lars M. Bishop. Essential Mathematics for Games & Interactive Applications: A Programmer’s Guide. Morgan Kaufmann Publishers (www.mkp.com), 2004.

https://book.douban.com/subject/26635117/


Part I的第一章是向量代数。向量在计算机图形学、碰撞检测和物理模拟中起着至关重要的作用,所以这一章一定要熟练掌握啊。

有关向量基本内容如坐标系,加减,数乘,点乘,叉乘,长度,单位化,投影,正交化等不再多说,我们直接看DirectX数学库中的向量。

从Windows8开始,DirectX math就成为了Windows SDK的一部分。它使用SSE2 (Streaming SIMD Extensions 2)指令集。通过使用128位宽的SIMD(single instruction multiple data)寄存器,SIMD指令可以一条指令操作四个32位的浮点数或int数。于是我们可以通过一条SIMD指令操作4D向量加法,或是忽略多余位的3D,2D向量加法。

要使用DirectX数学库,需要包含DirectXMath.h(名称空间DirectX),一些附加的数据类型需要包含DirectXPackedVector.h(名称空间DirectX::PackedVector)。对于x86平台需要启用SSE2(Project Properties > Configuration Properties > C/C++ > Code Generation > Enable Enhanced Instruction Set),对于所有平台都要启用快速浮点模型 /fp:fast (Project Properties > Configuration Properties > C/C++ > Code Generation > Floating Point Model)。

在DirectX数学库中,核心数据类型是XMVECTOR,它对应SIMD硬件寄存器。此外还有XMFLOAT2,XMFLOAT3,XMFLOAT4作为2D,3D,4D向量。以XMFLOAT3为例,其结构定义:

struct XMFLOAT3
{
    float x;
    float y;
    float z;
    XMFLOAT3() {}
    XMFLOAT3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
    explicit XMFLOAT3(_In_reads_(3) const float *pArray)
    :
    x(pArray[0]), y(pArray[1]), z(pArray[2]) {}
    XMFLOAT3& operator= (const XMFLOAT3& Float3)
    { x = Float3.x; y = Float3.y; z = Float3.z; return *this; }
};

对于它们的使用,我们有以下准则:

1.对于局部或全局变量,使用XMVECTOR;

2.对于类数据成员使用XMFLOAT2, XMFLOAT3, 和XMFLOAT4;

3.在做计算之前,使用加载函数将XMFLOATn转换为XMVECTOR;

4.使用储存函数将XMVECTOR转换为XMFLOATn。

其中加载函数如下:

// Loads XMFLOAT2 into XMVECTOR
XMVECTOR XM_CALLCONV XMLoadFloat2(const XMFLOAT2 *pSource);
// Loads XMFLOAT3 into XMVECTOR
XMVECTOR XM_CALLCONV XMLoadFloat3(const XMFLOAT3 *pSource);
// Loads XMFLOAT4 into XMVECTOR
XMVECTOR XM_CALLCONV XMLoadFloat4(const XMFLOAT4 *pSource);

储存函数如下:

// Loads XMVECTOR into XMFLOAT2
void XM_CALLCONV XMStoreFloat2(XMFLOAT2 *pDestination, FXMVECTOR V);
// Loads XMVECTOR into XMFLOAT3
void XM_CALLCONV XMStoreFloat3(XMFLOAT3 *pDestination, FXMVECTOR V);
// Loads XMVECTOR into XMFLOAT4
void XM_CALLCONV XMStoreFloat4(XMFLOAT4 *pDestination, FXMVECTOR V);

下列函数用于get或set XMVECTOR的某一位:

float XM_CALLCONV XMVectorGetX(FXMVECTOR V);
float XM_CALLCONV XMVectorGetY(FXMVECTOR V);
float XM_CALLCONV XMVectorGetZ(FXMVECTOR V);
float XM_CALLCONV XMVectorGetW(FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVectorSetX(FXMVECTOR V, float x);
XMVECTOR XM_CALLCONV XMVectorSetY(FXMVECTOR V, float y);
XMVECTOR XM_CALLCONV XMVectorSetZ(FXMVECTOR V, float z);
XMVECTOR XM_CALLCONV XMVectorSetW(FXMVECTOR V, float w);

P.S.使用常向量时应该使用类型XMVECTORF32或XMVECTORU32

XMVECTOR重载了许多运算符:

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& operator*= (XMVECTOR& V, float S);
XMVECTOR& 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);

DirectX数学库也定义了常见常量,如:

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

弧度与角度的转换函数:

inline float XMConvertToRadians(float fDegrees)
{ return fDegrees * (XM_PI / 180.0f); }
inline float XMConvertToDegrees(float fRadians)
{ return fRadians * (180.0f / XM_PI); }

最大最小值函数:

template<class T> inline T XMMin(T a, T b) { return (a < b) ? a : b; }
template<class T> inline T XMMax(T a, T b) { return (a > b) ? a : b; }

常用的设值函数:

// Returns the zero vector 0
XMVECTOR XM_CALLCONV XMVectorZero();
// Returns the vector (1, 1, 1, 1)
XMVECTOR XM_CALLCONV XMVectorSplatOne();
// Returns the vector (x, y, z, w)
XMVECTOR XM_CALLCONV XMVectorSet(float x, float y,
float z, float w);
// Returns the vector (s, s, s, s)
XMVECTOR XM_CALLCONV XMVectorReplicate(float Value);
// Returns the vector (vx, vx, vx, vx)
XMVECTOR XM_CALLCONV XMVectorSplatX(FXMVECTOR V);
// Returns the vector (vy, vy, vy, vy)
XMVECTOR XM_CALLCONV XMVectorSplatY(FXMVECTOR V);
// Returns the vector (vz, vz, vz, vz)
XMVECTOR XM_CALLCONV XMVectorSplatZ(FXMVECTOR V);

常用的数学操作:

XMVECTOR XM_CALLCONV XMVector3Length( // Returns ||v||
FXMVECTOR V); // Input v
XMVECTOR XM_CALLCONV XMVector3LengthSq( // Returns ||v||^2
FXMVECTOR V); // Input v
XMVECTOR XM_CALLCONV XMVector3Dot( // Returns v1·v2
FXMVECTOR V1, // Input v1
FXMVECTOR V2); // Input v2
XMVECTOR XM_CALLCONV XMVector3Cross( // Returns v1 × v2
FXMVECTOR V1, // Input v1
FXMVECTOR V2); // Input v2
XMVECTOR XM_CALLCONV XMVector3Normalize( // Returns v/||v||
FXMVECTOR V); // Input v
XMVECTOR XM_CALLCONV XMVector3Orthogonal( // Returns a vector orthogonal to v
FXMVECTOR V); // Input v
XMVECTOR XM_CALLCONV XMVector3AngleBetweenVectors( // Returns the angle between v1 and v2
FXMVECTOR V1, // Input v1
FXMVECTOR V2); // Input v2
void XM_CALLCONV XMVector3ComponentsFromNormal(
XMVECTOR* pParallel, // Returns projn(v)
XMVECTOR* pPerpendicular, // Returns perpn(v)
FXMVECTOR V, // Input v
FXMVECTOR Normal); // Input n
bool XM_CALLCONV XMVector3Equal( // Returns v1 = v2
FXMVECTOR V1, // Input v1
FXMVECTOR V2); // Input v2
bool XM_CALLCONV XMVector3NotEqual( // Returns v1 ≠ v2
FXMVECTOR V1, // Input v1
FXMVECTOR V2); // Input v2

还有一些牺牲精度换取速度的方法:

XMVECTOR XM_CALLCONV XMVector3LengthEst( // Returns estimated ||v||
FXMVECTOR V); // Input v
XMVECTOR XM_CALLCONV XMVector3NormalizeEst( // Returns estimated v/||v||
FXMVECTOR V); // Input v

由于浮点数运算的精度问题,判断相等不能用==,可以用XMVector3NearEqual:

// Returns
// abs(U.x – V.x) <= Epsilon.x &&
// abs(U.y – V.y) <= Epsilon.y &&
// abs(U.z – V.z) <= Epsilon.z
XMFINLINE bool XM_CALLCONV XMVector3NearEqual(
FXMVECTOR U,
FXMVECTOR V,
FXMVECTOR Epsilon);

以上,我们学习了DirectX数学库中向量的使用。

下一步,就是矩阵了!

猜你喜欢

转载自blog.csdn.net/zgjstudy/article/details/89291865