[DirectX 12 GJ Dragon Book Learning Notes II] Vector

Keywords: Windows Programming Unity SDK

"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.

Now we have come to the study of PART I Mathematics Foundation.

There is no need to say much about the importance of mathematics. Since the mathematical content described in the book is only for the follow-up content, it is not comprehensive, so from the point of view of learning mathematics, the book recommends two books specializing in mathematics:

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/

The first chapter of Part I is vector algebra. Vectors play an important role in computer graphics, collision detection and physical simulation, so this chapter must be skilled.

 

 

The basic contents of vectors, such as coordinate system, addition and subtraction, multiplication, dot multiplication, cross multiplication, length, unity, projection, orthogonalization, etc. are not mentioned any more. Let's look directly at the vectors in DirectX mathematical library.

DirectX math has been part of Windows SDK since Windows 8. It uses SSE2 (Streaming SIMD Extensions 2) instruction set. By using a 128-bit wide SIMD (single instruction multiple data) register, a SIMD instruction can operate on four 32-bit floating-point numbers or ints in one instruction. So we can use a SIMD instruction to manipulate 4D vector addition, or ignore the redundant bit of 3D, 2D vector addition.

To use DirectX math libraries, you need to include DirectXMath.h (namespace DirectX), and some additional data types need to include DirectXPackedVector.h (namespace DirectX::PackedVector). SSE2 (Project Properties > Configuration Properties > C/C++ > Code Generation > Enable Enhanced Instruction Set) needs to be enabled for x86 platforms, and fast floating-point model / fp:fast (Project Properties > Configuration Properties > C/C++ > Code Generation > Floating Point Model) needs to be enabled for all platforms.

In DirectX mathematical library, the core data type is XMVECTOR, which corresponds to the SIMD hardware register. In addition, XMFLOAT2, XMFLOAT3 and XMFLOAT4 are used as 2D, 3D and 4D vectors. Taking XMFLOAT3 as an example, its structure definition is as follows:

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; }
};

For their use, we have the following criteria:

1. For local or global variables, use XMVECTOR;

2. Use XMFLOAT2, XMFLOAT3, and XMFLOAT4 for class data members.

3. Before calculating, XMFLOATn is converted to XMVECTOR using load function.

4. Use storage functions to convert XMVECTOR to XMFLOATn.

The loading function is as follows:

// 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);

The storage functions are as follows:

// 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);

 

The following functions are used for one bit of get or 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. Use type XMVECTORF32 or XMVECTORU32 when using constant vectors

XMVECTOR overloads many operators:

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 Mathematics Library also defines common constants, such as:

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;

Conversion function of radian and angle:

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

Maximum and minimum function:

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; }

Commonly used set-value functions:

// 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);

Commonly used mathematical operations:

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

There are also ways of sacrificing precision for speed:

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

Because of the accuracy of floating-point arithmetic, it is not possible to judge equality by==, but by using 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);

 

Above, we learned how to use vectors in the DirectX math library.

The next step is the matrix!

Posted by xAtlas on Thu, 09 May 2019 05:57:40 -0700