XNA数学库
Posted 廉江宏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XNA数学库相关的知识,希望对你有一定的参考价值。
XNA Math Vectors
在direct3D 9 和10中,包含3D数学库的D3DX库支持向量和其他核心类型的计算。在direct11中,D3DX库不在包含3D数学库,取而代之的是XNA数学库。XNA利用的是特殊的硬件寄存器。在windows环境中,XNA
数学库使用SSE2(Streaming SIMD Extension 2)指令集。它使用128-bits大小的SIMD(single instruction multiple data)寄存器,可以用一个指令操作4个32-bits浮点型数据或整型数据。
例如:u + v = (ux + vx, uy + vy, uz + vz)
我们用3个加法指令将每个分量加起来。但通过使用SIMD,我们可以只用一个SIMD指令做4D向量加法,而不是用4个标量指令。如果你操作3D向量,我们仍然可以使用SIMD,
我们只需将向量的第四个分量置为0并且忽略它。在2D中类似。
为了使用XNA数学库,我们只需添加头文件#include<xnamath.h> 。当然,你也可以通过包含头文件#include<d3dx10.h>,并且链接静态库d3dx10.lib使用D3DX10数学库。
在XNA数学库中,关键的向量类型是XMVECTOR. 它是一个128-bits类型,可以被单个SIMD指令处理。
它被这样定义:
1 typedef __m128 XMVECTOR;
这里,__m128是一个特殊的SIMD类型。对于类数据成员,最好使用XMFLOAT2,XMFLOAT3,XMFLAOT4。它们被如下定义:
1 typedef struct _XMFLOAT4 2 { 3 FLOAT x; 4 FLOAT y; 5 FLOAT z; 6 FLOAT w; 7 }XMFLOAT4;
然而,如果我们直接使用这些类型进行计算,将不能利用SIMD硬件。我们需要将这些类型的实例转化为XMFLOAT类型。这些是XNA载入函数(loading functions)的工作。相反地,XNA还提供存储函数(storage functions)将
XMVECTOR转化为XMFLOAT*类型。
Loading 和 Storage 函数
Loading函数:
1 XMVECTOR XMLoadFloat2(CONST XMFLOAT2 *pSource); // 将XMFLOAT2转化为XMVECTOR类型 2 XMVECTOR XMLoadFloat3(CONST XMFLOAT3 *pSource); // 将XMFLOAT3转化为XMVECTOR类型 3 XMVECTOR XMLoadFloat4(CONST XMFLOAT4 *pSource); // 将XMFLOAT4转化为XMVECTOR类型
还有很多方法将其他类型转化为XMVECTOR类型,下面是一些例子:
1 XMVECTOR XMLoadInt3(CONST UINT* pSource); // Loads 3-element UINT array into XMVECTOR 2 XMVECTOR XMLoadColor(CONST XMCOLOR *pSource); // Loads XMCOLOR into XMVECTOR 3 XMVECTOR XMLoadByte4(CONST XMBYTE4 *pSource); // Loads XMBYTE4 into XMVECTOR
Storage函数:
1 VOID XMStoreFloat2(XMFLOAT2 *pDestination,FXMVECTOR V); // 将XMVECTOR转化为XMFLOAT2类型
还有很多方法将XMVECTOR转化为其他类型,下面是一些例子:
1 VOID XMStoreInt3(UINT* pDestination, FXMVECTOR V); 2 VOID XMStoreColor(XMCOLOR* pDestination, FXMVECTOR V); 3 VOID XMStoreByte4(XMBYTE4 *pDestination, FXMVECTOR V);
有时,我们只想获取或者设置XMVECTOR的一个分量,可以使用下面的函数完成:
1 FLOAT XMVectorGetX(FXMVECTOR V); 2 XMVECTOR XMVectorSetX(FXMVECTOR V,Float x);
传递参数的规则
为了利用SIMD,将参数传递给XMVECTOR类型的函数有一些规则需要遵守,这些规则根据平台的不同而不同。尤其是32-bit Windows、64-bit Windows和XBOX 360. 为了独立于平台,
我们使用类型CXMVECTOR和FXMVECTOR传递XMVECTOR的参数。对于Windows,它们被定义如下:
1 // 32-bit Windows 2 typedef const XMVECTOR FXMVECTOR; 3 typedef const XMVECTOR& CXMVECTOR; 4 // 64-bit Windows 5 typedef const XMVECTOR& FXMVECTOR; 6 typedef const XMVECTOR& CXMVECTOR;
它们的不同点是,我们可以直接传递XMVECTOR的副本还是我们必须传递一个引用。现在,传递XMVECTOR参数的规则如下:
前三个XMVECTOR参数应该是FXMVECTOR类型,后面的为CXMVECTOR类型。
1 XMINLINE XMMATRIX XMMatrixTransformation( 2 FXMVECTOR ScalingOrigin, 3 FXMVECTOR ScalingOrientationQuaternion, 4 FXMVECTOR Scaling, 5 CXMVECTOR RotationOrigin, 6 CXMVECTOR RotationQuaternion, 7 CXMVECTOR Translation);
注意,你可以拥有非XMVECTOR类型的参数,前面的规则仍然有效:
1 XMINLINE XMMATRIX XMMatrixTransformation2D( 2 FXMVECTOR ScalingOrigin, 3 FLOAT ScalingOrientation, // FLOAT类型 4 FXMVECTOR Scaling, 5 FXMVECTOR RotationOrigin, 6 FLOAT Rotation, // FLOAT类型 7 CXMVECTOR Translation);
对于常量XMVECTOR实例,我们应该使用XMVECTORF32类型存储浮点型向量。这儿有一些例子:
1 static const XMVECTORF32 g_vZero = { 0.0f, 0.0f, 0.0f, 0.0f }; 2 3 XMVECTORF32 vRightTop = { 4 vViewFrust.RightSlope, 5 vViewFrust.TopSlope, 6 1.0f,1.0f 7 };
使用XMVECTORU32存储整型向量:
1 static const XMVECTORU32 vGrabY = { 2 0x00000000,0xFFFFFFFF,0x00000000,0x00000000 3 };
XNA数学库定义了一些与PI有关的常量:
1 #defineXM_PI 3.141592654f 2 #defineXM_2PI 6.283185307f 3 #defineXM_1DIVPI 0.318309886f // 1/PI 4 #defineXM_1DIV2PI 0.159154943f // 1/2PI 5 #defineXM_PIDIV2 1.570796327f // PI/2 6 #defineXM_PIDIV4 0.785398163f // PI/4
它还定义了如下内联函数用来在角度和弧度之间进行转换:
1 XMFINLINE FLOAT XMConvertToRadians(FLOAT fDegrees) 2 { 3 return fDegrees*(XM_PI/180.0f); 4 } 5 6 XMFINLINE FLOAT XMConvertToDegrees(FLOAT fRadians) 7 { 8 return fRadians*(180.0f/XM_PI); 9 }
它也定义了最大最小宏:
1 #define XMMin(a,b) (((a) < (b)) ? (a) : (b)) 2 #define XMMax(a, b) (((a) > (b)) ? (a) : (b))
XNA数学库提供了下列函数来设置XMVECTOR的内容:
1 XMVECTOR XMVectorZero(); // 返回0向量(0,0,0,0) 2 XMVECTOR XMVectorSplatOne(); // 返回向量(1, 1, 1, 1) 3 XMVECTOR XMVectorSet(FLOAT x, FLOAT y, FLOAT z,FLOAT w); // 返回向量(x, y, z, w) 4 XMVECTOR XMVectorReplicate(FLOAT s); // 返回向量(s, s, s, s) 5 XMVECTOR XMVectorSplatX(FXMVECTOR V);// 返回向量(vx, vx, vx,vx) 6 XMVECTOR XMVectorSplatY(FXMVECTOR V);// 返回向量(vy, vy, vy,vy) 7 XMVECTOR XMVectorSplatZ(FXMVECTOR V);// 返回向量(vz, vz, vz,vz)
一些向量计算的函数:(下面为3D的例子,2D,4D同理,只需将函数名中的3替换为2、4)
1 XMVECTOR XMVector3Length(FXMVECTOR V); // Returns || v || 2 XMVECTOR XMVector3LengthSq(FXMVECTOR V); // Returns || v ||的二次方 3 XMVECTOR XMVector3Dot(FXMVECTOR V1, FXMVECTOR V2); // Returns v1 • v2 4 XMVECTOR XMVector3Cross(FXMVECTOR V1, FXMVECTOR V2); //Returns v1 × v2 5 XMVECTOR XMVector3Normalize(FXMVECTOR V); // Returns v/|| v || 6 XMVECTOR XMVector3Orthogonal(FXMVECTOR V); // Returns a vector orthogonal to v 7 XMVector3AngleBetweenVectors(FXMVECTOR V1, FXMVECTOR V2); // Returns the angle between v1 and v2 8 VOID XMVector3ComponentsFromNormal(XMVECTOR* pParallel,XMVECTOR* pPerpendicular, FXMVECTOR V, FXMVECTORNormal); // Returns projn(v)// Returns prepn(v) 9 BOOL XMVector3Equal(FXMVECTOR V1, FXMVECTOR V2); // Returns v1 = v2 10 BOOL XMVector3NotEqual(FXMVECTOR V1, FXMVECTOR V2); // Returns v1 ≠ v2
还有一些估算方法,如果你不在乎精确度,而在乎速度,可以使用如下函数:
MFINLINE XMVECTOR XMVector3LengthEst(XMVECTOR V); // Returns estimated || v ||
MFINLINE XMVECTOR XMVector3NormalizeEst(XMVECTOR V); // Returns estimated v/|| v ||
众所周知,浮点数的操作结果是不精确的。
可以定义一个阙值来解决:
1 const float Epsilon = 0.001f; 2 bool Equals(float lhs, float rhs) 3 { 4 return fabs(lhs - rhs) < Epsilon ? true : false; 5 }
在XNA数学库中有类似的函数:XMVector3NearEqual()
1 // Returns 2 // abs(U.x – V.x) <= Epsilon.x && 3 // abs(U.y – V.y) <= Epsilon.y && 4 // abs(U.z – V.z) <= Epsilon.z 5 XMFINLINE BOOL XMVector3NearEqual( 6 FXMVECTOR U, 7 FXMVECTOR V, 8 FXMVECTOR Epsilon);
以上是关于XNA数学库的主要内容,如果未能解决你的问题,请参考以下文章