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数学库中表示4x4矩阵,我们使用XMMATRIX类,它被这样定义:

 1 union
 2 {    
 3     XMVECTOR r[4];
 4 struct
 5 {
 6     FLOAT _11, _12, _13, _14;
 7     FLOAT _21, _22, _23, _24;
 8     FLOAT _31, _32, _33, _34;
 9     FLOAT _41, _42, _43, _44;
10 };
11     FLOAT m[4][4];
12 };

 

正如上面定义的,XMMATRIX被用4个使用SIMD的XMVECTOR实例表示。
除了使用各种各样的构造函数,XMMATRIX还可以通过XMMatrixSet函数创建:

1 XMMATRIX XMMatrixSet(
2 FLOAT m00,FLOAT m01,FLOAT m02,FLOAT m03,
3 FLOAT m10,FLOAt m11,FLOAT m12,FLOAT m13,
4 FLOAt m20,FLOAt m21,FLOAT m22,FLOAT m23,
5 FLOAT m30,FLOAT m31,FLOAT m32,FLOAT m33);

正如前面讲过的,我们在类数据成员的表示中,通常被推荐使用XMFLOAT2,XMFLOAT3,XMFLOAT4,同样,在表示类数据成员时,我们被推荐使用XMFLOAT4x4类型存储矩阵。


XNA数学库中包括下面与矩阵有关的函数:

1 XMMATRIX XMMatrixIdentitu();    // 返回单位矩阵 I
2 Bool XMMatrixIsIdentity(CXMMATRIX M);    // 如果M为单位矩阵,返回true
3 XMMATRIX XMMatrixMultiply(CXMMATRIX A,CXMMATRIX B);    // 返回 矩阵A,B的乘积
4 XMMATRIX XMMatrixTranspose(CXMMATRIX M);    // 返回矩阵M的转置矩阵
5 XMVECTOR XMMatrixDeterminant(CXMMATRIX M);    // 返回向量(det M,det M,det M,det M)
6 XMMATRIX XMMatrixInverse(XMVECTOR* pDeterminant,CXMMATRIX M);    // 返回矩阵M的逆矩阵

XMMATRIX参数的类型应该为CXMAATRIX,这将保证XMMATRIX参数在Windows和Xbox平台上被正确传递。

 

XNA中的变换函数:

 1 XMMATRIX XMMatrixScaling(
 2 FLOAT ScaleX,
 3 FLOAT ScaleY,
 4 FLOAT ScaleZ); // 缩放函数
 5 XMMATRIX XMMatrixScalingFromVector(
 6 FXMVECTOR Scale); // //Constructs a scaling matrix from components in vector
 7 XMMATRIX XMMatrixRotationX(
 8 FLOAT Angle); // 绕X轴旋转
 9 XMMATRIX XMMatrixRotationY(
10 FLOAT Angle); // 绕Y轴旋转
11 XMMATRIX XMMatrixRotationZ(
12 FLOAT Angle); // 绕Z轴旋转
13 XMMATRIX XMMatrixRotationAxis(
14 FXMVECTOR Axis,
15 FLOAT Angle); // 绕任意轴n旋转
16 XMMATRIX XMMatrixTranslation(
17 FLOAT OffsetX,
18 FLOAT OffsetY,
19 FLOAT OffsetZ); // 平移矩阵
20 XMMATRIX XMMatrixTranslationFromVector(
21 FXMVECTOR Offset); // Constructs a translation matrix from components in a vector
22 XMVECTOR XMVector3Transform(
23 FXMVECTOR V,
24 CXMMATRIX M); //计算向量V和矩阵M的积
25 XMVECTOR XMVector3TransformCoord(
26 FXMVECTOR V,
27 CXMMATRIX M); //Computes the vector-matrix product vM where vw = 1 for transforming points
28 XMVECTOR XMVector3TransformNormal(
29 FXMVECTOR V,
30 CXMMATRIX M); //Computes the vector-matrix product vM where vw = 0 for transforming vectors

 

注意:最后两个函数XMVector3TransformCoord()和XMVector3TransformNormal(),你不需要明确地指定vw=1 或者 vw =0,因为函数会自动完成。

posted @ 2016-05-17 22:10  朴者  阅读(984)  评论(0编辑  收藏  举报