XNA数学库之向量
1. XNA数学库简介
之所以要使用XNA数学库,是因为XNA数学库为我们提供了SIMD指令优化,使得我们的数学计算更加快速。XNA数学库需要包含d3dx10.h头文件,不需要包含动态链接库,因为实现都是在头文件内联的。
2. 向量类型
如果SSE2(单指令多数据流扩展)是可用的,那么有如下向量定义:
typedef __m128 XMVECTOR;
__m128 是一个特殊的SIMD类型,有助于优化计算。
XMVECTOR 是16位对齐,并且只适用于局部变量和全局变量。对于类的数据成员储存,需要转换到XMFLOAT2 (2D), XMFLOAT3 (3D), and XMFLOAT4 (4D) 这些适用于储存的结构来代替。它们的结构定义如下:
typedef struct _XMFLOAT2 {
FLOAT x;
FLOAT y;
} XMFLOAT2;
typedef struct _XMFLOAT3 {
FLOAT x;
FLOAT y;
FLOAT z;
} XMFLOAT3;
typedef struct _XMFLOAT4 {
FLOAT x;
FLOAT y;
FLOAT z;
FLOAT w;
} XMFLOAT4;
然而储存结构不能使用SIMD指令优化,故如果我们需要用到计算,还是要转换回XMVECTOR。
3. 如何转换到XMVECTOR类型?
使用如下的载入函数可以将XMFLOATxx类型转换为XMVECTOR类型:
// Loads XMFLOAT2 into XMVECTOR
XMVECTOR XMLoadFloat2(CONST XMFLOAT2 *pSource );
// Loads XMFLOAT3 into XMVECTOR
XMVECTOR XMLoadFloat3(CONST XMFLOAT3 *pSource );
// Loads XMFLOAT4 into XMVECTOR
XMVECTOR XMLoadFloat4(CONST XMFLOAT4 *pSource );
当然除了float,其他类型也是可以转换的:
// Loads 3-element UINT array into XMVECTOR
XMVECTOR XMLoadInt3(CONST UINT* pSource );
// Loads XMCOLOR into XMVECTOR
XMVECTOR XMLoadColor(CONST XMCOLOR *pSource );
// Loads XMBYTE4 into XMVECTOR
XMVECTOR XMLoadByte4(CONST XMBYTE4 *pSource );
4. 如何将XMVECTOR转换到用于储存的变量?
使用储存函数:
// Loads XMVECTOR into XMFLOAT2
VOID XMStoreFloat2(XMFLOAT2 *pDestination, FXMVECTOR V);
// Loads XMVECTOR into XMFLOAT3
VOID XMStoreFloat3(XMFLOAT3 *pDestination, FXMVECTOR V);
// Loads XMVECTOR into XMFLOAT4
VOID XMStoreFloat4(XMFLOAT4 *pDestination, FXMVECTOR V);
4. 关于XMVECTOR的set和get函数
FLOAT XMVectorGetX(FXMVECTOR V);
FLOAT XMVectorGetY(FXMVECTOR V);
FLOAT XMVectorGetZ(FXMVECTOR V);
FLOAT XMVectorGetW(FXMVECTOR V);
XMVECTOR XMVectorSetX(FXMVECTOR V, FLOAT x);
XMVECTOR XMVectorSetY(FXMVECTOR V, FLOAT y);
XMVECTOR XMVectorSetZ(FXMVECTOR V, FLOAT z);
XMVECTOR XMVectorSetW(FXMVECTOR V, FLOAT w);
4. XMVECTOR用作函数参数类型吗?
出于平台独立,XMVECTOR作为形参可使用这两个类型:FXMVECTOR和CXMVECTOR,它们的定义为:
// 32-bit Windows
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
// 64-bit Windows
typedef const XMVECTOR& FXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
关于如何使用,需要遵守如下规则:
但凡用到XMVECTOR的地方,前三个XMVECTOR用FXMVECTOR代替,其他XMVECTOR用CXMVECTOR代替:
XMINLINE XMMATRIX XMMatrixTransformation(
FXMVECTOR ScalingOrigin,
FXMVECTOR ScalingOrie ntationQuate rnion,
FXMVECTOR Scaling,
CXMVECTOR RotationOrigin,
CXMVECTOR RotationQuaternion,
CXMVECTOR Translation);
如下的函数也是正确的写法:
XMINLINE XMMATRIX XMMatrixTransformation2D(
FXMVECTOR ScalingOrigin,
FLOAT ScalingOrie ntation,
FXMVECTOR Scaling,
FXMVECTOR RotationOrigin,
FLOAT Rotation,
CXMVECTOR Translation);
5. XMVECTOR用作常量吗?
XMVECTOR作为常量,需要使用XMVECTORF32类型(用于初始化的变量亦是如此)。如:
static const XMVECTORF32 g_vHalfVector = { 0.5f, 0.5f, 0.5f, 0.5f };
static const XMVECTORF32 g_vZe ro = { 0.0f, 0.0f, 0.0f, 0.0f };
XMVECTORF32 vRightTop = {
vViewFrust.RightSlope ,
vViewFrust.TopSlope ,
1.0f,1.0f
};
XMVECTORF32 vLeftBottom = {
vViewFrust.LeftSlope ,
vViewFrust.BottomSlope,
1.0f,1.0f
};
这是XMVECTORF32的定义:
// Conve rsion types for constants
typedef _DECLSPEC_ALIGN_16_struct XMVECTORF32 {
union {
float f[4];
XMVECTOR v;
};
#ifdefine d(__cplus plus )
inline operator XMVECTOR() const { re turn v; }
#if !defined(_XM _NO_INTRINSICS_) && defined(_XM _SSE_INTRINSICS_)
inline operator __m128i() const
{ re turn reinterpret_cast<const __m128i *>(&v)[0]; }
inline operator __m128d() const
{ re turn reinterpret_cast<const __m128d *>(&v)[0]; }
#endif
#endif // __cplusplus
} XMVECTORF32;
对于整形数据,我们使用XMVECTORU32:
static const XMVECTORU32 vGrabY = {
0x00000000,0xFFFFFFFF,0x00000000,0x00000000
};
6. 向量操作的函数有哪些?
XMMATH定义了许多向量操作的函数。但是你可以使用XM_NO_OPERATOR_OVERLOADS来禁用这些重载操作函数,这是出于性能提升的特殊目的。
// Vector ope rators
#if defined(__cplusplus ) && !defined(XM_NO_OPERATOR_OVERLOADS)
XMVECTOR operator+ (FXMVECTOR V);
XMVECTOR operator- (FXMVECTOR V);
XMVECTOR& operator+= (XMVECTOR& V1, FXMVECTOR V2);
XMVECTOR& operator-= (XMVECTOR& V1, FXMVECTOR V2);
XMVECTOR& operator*= (XMVECTOR& V1, FXMVECTOR V2);
XMVECTOR& operator/= (XMVECTOR& V1, FXMVECTOR V2);
XMVECTOR& operator*= (XMVECTOR& V, FLOAT S);
XMVECTOR& operator/= (XMVECTOR& V, FLOAT S);
XMVECTOR operator+ (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR operator- (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR operator* (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR operator/ (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR operator* (FXMVECTOR V, FLOAT S);
XMVECTOR operator* (FLOAT S, FXMVECTOR V);
XMVECTOR operator/ (FXMVECTOR V, FLOAT S);
#endif // __cplus plus && !XM_NO_OPERATOR_OVERLOADS
7. 杂项
π的常量:
#de fine XM_PI
3.141592654f
#de fine XM_2PI
6.283185307f
#de fine XM_1DIVPI
0.318309886f
#de fine XM_1DIV2PI
0.159154943f
#de fine XM _PIDIV2
1.570796327f
#de fine XM _PIDIV4
0.785398163f
角度与弧度之间的转换:
XMFINLINE FLOAT XMConvertToRadians (FLOAT fDegrees)
{
re turn fDegre e s * (XM_PI / 180.0f);
}
XMFINLINE FLOAT XMConvertToDegrees (FLOAT fRadians)
{
re turn fRadians * (180.0f / XM_PI);
}
最小值最大值函数:
XMFINLINE FLOAT XMConvertToRadians (FLOAT fDegrees)
{
re turn fDegre e s * (XM_PI / 180.0f);
}
XMFINLINE FLOAT XMConvertToDegrees (FLOAT fRadians)
{
re turn fRadians * (180.0f / XM_PI);
}
8. 向量setter函数
XMVECTOR XMVectorSplatOne ();
// Returns the vector (1, 1, 1, 1)
XMVECTOR XMVectorSe t(FLOAT x, FLOAT y, FLOAT z, FLOAT w);
// Returns the vector (x, y, z, w)
XMVECTOR XMVe ctorRe plicate (FLOAT s);
// Returns the vector(s, s, s, s)
XMVECTOR XMVectorSplatX(FXMVECTOR V);
// Returns the vector (vx, vx, vx, vx)
XMVECTOR XMVectorSplatY(FXMVECTOR V);
// Returns the ve ctor (vy, vy, vy, vy)
XMVECTOR XMVectorSplatZ(FXMVECTOR V);
// Returns the ve ctor (vz, vz, vz, vz)
9. 向量计算函数
XMVECTOR XMVector3Length(FXMVECTOR V);
// Returns || v ||
//Input v
XMVECTOR XMVector3LengthSq(FXMVECTOR V);
// Returns || v ||2
//Input v
XMVECTOR XMVector3Dot(FXMVECTOR V1, FXMVECTOR V2);
// Returns v1 • v2
//Input v1
//Input v2
XMVECTOR XMVector3Cross(FXMVECTOR V1, FXMVECTOR V2);
// Returns v1 × v2
//Input v1
//Input v2
XMVECTOR XMVector3Normalize (FXMVECTOR V);
// Returns v/|| v ||
//Input v
XMVECTOR XMVector3Orthogonal(FXMVECTOR V);
// Ret urns a vector
orthogonal to v// Inp ut v
XMVECTOR
XMVector3AngleBetweenVectors(FXMVECTOR V1, FXMVECTOR V2);
// Ret urns the angle between
v1and v2
//Input v1
//Input v2
VOID XMVector3ComponentsFromNormal(XMVECTOR* pParallel,
XMVECTOR* pPerpendicular, FXMVECTOR V, FXMVECTOR
Normal);
// Ret urns projn(v)
// Ret urns prepn(v)
//Input v
//Input n
BOOL XMVector3Equal(FXMVECTOR V1, FXMVECTOR V2);
// Returns v1 = v2
//Input v1
//Input v2
BOOL XMVector3NotEqual(FXMVECTOR V1, FXMVECTOR V2);
// Returns v1 ≠ v2
//Input v1
//Input v2
值得注意的是,即使是返回一个标量,为了SIMD优化指令,函数的返回值都是XMVECTORS,该向量的分量值都是相同的标量结果。
10. 浮点数错误
因为浮点数是不精确的,因此进行浮点数比较或把浮点数用作计算幂的指数的时候可能会出现错误。解决方法,定义一个Epsilon误差范围值,误差小于这个范围的数值都可以认为是相等的。XNAMATH也提供一个误差比较函数:
// Returns
// abs(U.x – V.x) <= Epsilon.x &&
// abs(U.y – V.y) <= Epsilon.y &&
// abs(U.z – V.z) <= Epsilon.z
XMFINLINE BOOL XMVector3NearEqual(
FXMVECTOR U,
FXMVECTOR V,
FXMVECTOR Eps ilon);