# D3D12渲染技术之矩阵向量运算

## 向量运算封装

#if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_)
typedef __m128 XMVECTOR;
#elif defined(_XM_ARM_NEON_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_)
typedef float32x4_t XMVECTOR;
#else
typedef __vector4 XMVECTOR;
#endif

D3D12已经为我们定义了向量，该向量是四维的，是四个32位浮点分量在16字节上对齐，考虑了内存占用，代码很严谨。每个接下来做的事情就是赋值，然后我们做运算，看看有没有给向量的赋值函数，我们继续在D3D12中查找，在文件DirectXMathVector.inl中找到了给向量赋值的内联函数：

inline XMVECTOR XM_CALLCONV XMVectorSet
(
float x,
float y,
float z,
float w
)
{
#if defined(_XM_NO_INTRINSICS_)
XMVECTORF32 vResult = { { { x, y, z, w } } };
return vResult.v;
#elif defined(_XM_ARM_NEON_INTRINSICS_)
float32x2_t V0 = vcreate_f32(((uint64_t)*(const uint32_t *)&x) | ((uint64_t)(*(const uint32_t *)&y) << 32));
float32x2_t V1 = vcreate_f32(((uint64_t)*(const uint32_t *)&z) | ((uint64_t)(*(const uint32_t *)&w) << 32));
return vcombine_f32(V0, V1);
#elif defined(_XM_SSE_INTRINSICS_)
return _mm_set_ps( w, z, y, x );
#endif
}

    XMVECTOR n = XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f);
XMVECTOR u = XMVectorSet(1.0f, 2.0f, 3.0f, 0.0f);
XMVECTOR v = XMVectorSet(-2.0f, 1.0f, -3.0f, 0.0f);
XMVECTOR w = XMVectorSet(0.707f, 0.707f, 0.0f, 0.0f);

#ifndef _XM_NO_XMVECTOR_OVERLOADS_
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);
#endif /* !_XM_NO_XMVECTOR_OVERLOADS_ */

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

// ||u||
XMVECTOR L = XMVector3Length(u);

// d = u / ||u||
XMVECTOR d = XMVector3Normalize(u);

// s = u dot v
XMVECTOR s = XMVector3Dot(u, v);

// e = u x v
XMVECTOR e = XMVector3Cross(u, v);

// Find proj_n(w) and perp_n(w)
XMVECTOR projW;
XMVECTOR perpW;
XMVector3ComponentsFromNormal(&projW, &perpW, w, n);

// Does projW + perpW == w?
bool equal = XMVector3Equal(projW + perpW, w) != 0;
bool notEqual = XMVector3NotEqual(projW + perpW, w) != 0;

// The angle between projW and perpW should be 90 degrees.
XMVECTOR angleVec = XMVector3AngleBetweenVectors(projW, perpW);
float angleDegrees = XMConvertToDegrees(angleRadians);

## 矩阵运算

#if ( defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || _XM_VECTORCALL_ ) && !defined(_XM_NO_INTRINSICS_)
typedef const XMMATRIX FXMMATRIX;
#else
typedef const XMMATRIX& FXMMATRIX;
#endif

// Fix-up for (2nd+) XMMATRIX parameters to pass by reference
typedef const XMMATRIX& CXMMATRIX;

#ifdef _XM_NO_INTRINSICS_
struct XMMATRIX
#else
__declspec(align(16)) struct XMMATRIX
#endif
{
#ifdef _XM_NO_INTRINSICS_
union
{
XMVECTOR r[4];
struct
{
float _11, _12, _13, _14;
float _21, _22, _23, _24;
float _31, _32, _33, _34;
float _41, _42, _43, _44;
};
float m[4][4];
};
#else
XMVECTOR r[4];
#endif

XMMATRIX() XM_CTOR_DEFAULT
#if defined(_MSC_VER) && _MSC_VER >= 1900
constexpr XMMATRIX(FXMVECTOR R0, FXMVECTOR R1, FXMVECTOR R2, CXMVECTOR R3) : r{ R0,R1,R2,R3 } {}
#else
XMMATRIX(FXMVECTOR R0, FXMVECTOR R1, FXMVECTOR R2, CXMVECTOR R3) { r[0] = R0; r[1] = R1; r[2] = R2; r[3] = R3; }
#endif
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);

#ifdef _XM_NO_INTRINSICS_
float       operator() (size_t Row, size_t Column) const { return m[Row][Column]; }
float&      operator() (size_t Row, size_t Column) { return m[Row][Column]; }
#endif

XMMATRIX&   operator= (const XMMATRIX& M) { r[0] = M.r[0]; r[1] = M.r[1]; r[2] = M.r[2]; r[3] = M.r[3]; return *this; }

XMMATRIX    operator+ () const { return *this; }
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);
};


inline XMMATRIX XM_CALLCONV XMMatrixIdentity()
{
XMMATRIX M;
M.r[0] = g_XMIdentityR0.v;
M.r[1] = g_XMIdentityR1.v;
M.r[2] = g_XMIdentityR2.v;
M.r[3] = g_XMIdentityR3.v;
return M;
}

    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;

XMMATRIX D = XMMatrixTranspose(A);

XMVECTOR det = XMMatrixDeterminant(A);
XMMATRIX E = XMMatrixInverse(&det, A);

XMMATRIX F = A * E;