1.6 XNA MATH VECTORS

来源:互联网 发布:天猫盒子软件 编辑:程序博客网 时间:2024/05/20 23:35

1.6 XNA MATH VECTORS

1.6 XNA 数学库

In Direct3D9 and 10, the D3DX library shipped with a 3D math utility library that includedsupport for vectors among other core 3D math types required for doing 3Dgraphics. The D3DX library for version 11 no longer ships with 3D math code.Instead it ships with the XNA Math library, which is a vector math librarydeveloped separately from Direct3D that takes advantages of special hardwareregisters on Windows and XBox  360. OnWindows, the library uses the SSE2 (Streaming SIMD Extensions  2) instruction set. With  128-bit wide SIMD  (single instruction multiple data) registers,SIMD instructions can operate on four 32-bit floats or ints with oneinstruction. This is very useful for vector calculations; for example, if youlook at vector addition:

在Direct3D 9和10中,D3DX数学库装载了实用3D数学库,其中包含对其他核心3D数学类型的向量支持。而在Direct3D 11不再沿用实用3D数学库,取而代之的XNA 数学库。这是个向量数学库,它独立与Direct3D。它可以利用window和XBOX360平台上的硬件寄存器。在window平台上,使用的是128 位宽的SIMD寄存器,每条SIMD指令可以操作4个32位整型或浮点型数据。这对向量计算是十分有用的。假定有如下向量加法:

u + v = (ux+ vx, uy + vy, uz + vz)

we see thatwe just add corresponding components. By using SIMD, we can do 4D vectoraddition with one SIMD instruction instead of 4 scalar instructions. If we areworking in 3D, we can still use SIMD, but we would just set the 4th componentto 0 and ignore it; likewise for 2D.

可以看到,我们只需要将各个分量相加。通过使用SIMD,我们可以仅使用一条SIMD指令而不是四条标量计算指令来计算4D向量。如果我们要计算3D向量,仍可用SIMD计算,只需将第四个分量设为0即可。2D计算也是类似的。

Our coverageof the XNA Math library is not comprehensive, and we only cover the key partsneeded for this book. For all the details, we recommend the onlinedocumentation [XNAMath2010]. For readers wishing to understand how an SIMDvector library might be developed optimally, and, perhaps, to gain some insightinto why the XNA Math library made some of the design decisions that it did, werecommend the article Designing Fast Cross-Platform SIMD Vector Libraries by[Oliveira2010].

本书并未涉及全部的XNA数学库,我们只是包含了本书所需的关键部分。如果想了解更多,我们推荐网络文档[XNAMath2010],对于想要深入了解XNA数学库的读者,我们推荐文档Designing Fast Cross-PlatformSIMD Vector Libraries by [Oliveira2010].

To use theXNA Math library, you only need to #include <xnamath.h>. There are noadditional library files, as all

the code isimplemented inline in the header file.

要使用XNA数学库,你只需要包含xnamath.h头文件,此外无需添加额外的库文件,所有的代码都在里面。

 

Note:There is nothing that stopsyou from including <d3dx10.h>, linking with d3dx10.lib, and using theD3DX10

Mathfunctions instead of the XNA math library.

                注意:你仍旧可以使用d3dx10.h头文件,通过连接到d3dx10.lib使用D3DX10 Math的函数而不是XNA数学库。

 

1.6.1 Vector Types

1.6.1 向量类型

In XNA Math,the core vector type is XMVECTOR, which maps to SIMD hardware registers. Thisis a 128-bit type that can process four 32-bit floats with a single SIMDinstruction. When SSE2 is available, it is defined like so:

在XNA中,核心的向量类型是XMVECTOR,他被映射到了SIMD硬件寄存器。该寄存器宽128位,当SSE2可用时,它可以通过一条SIMD指令操作4个32位浮点型数据。

typedef __m128  XMVECTOR;                                                                            

 

where __m128is a special SIMD type. When doing calculations, vectors must be of this typeto take advantage of SIMD. As already mentioned, we still use this type for 2Dand 3D vectors to take advantage of SIMD, but we just zero out the unusedcomponents and ignore them.

__128 是一种特殊的SIMD类型。计算时,向量必须指定为该类型才能利用SIMD来计算。如前所述,我们也可以使用该类型来表示2D和3D向量,只需将无用的分量设为0并忽略它既可。

XMVECTORneeds to be 16-byte aligned, and this is done automatically for local andglobal variables. For class data members, it is recommended to use XMFLOAT2(2D), XMFLOAT3 (3D), and XMFLOAT4 (4D) instead; these structures are definedbelow:

XMVECTOR需要16字节线性的,对于局部和全局变量它将自动完成。对于类的成员变量,建议使用XMFLOAT2(2D)、XMFLOAT3(3D)和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;

However, ifwe use these types directly for calculations, then we will not take advantageof SIMD. In order to use SIMD, we need to convert instances of these types intothe XMVECTOR type. This is done with the XNA Math loading functions.Conversely, XNA Math provides storage functions which are used to convert datafrom XMVECTOR into the XMFLOAT* types described previously.

然而,如果我们直接使用这些类型计算,我们将无法使用SIMD。为了使用SIMD,我们需要将这些类型的实例转换成XMVECTOR类型,此过程可使用XNA库封装的加载函数来完成。XNA数学库提供了内置函数来将XMVECTOR类型转换成之前提到的XMFLOAT* 类型。

Tosummarize,

1. UseXMVECTOR for local or global variables.

2. UseXMFLOAT2, XMFLOAT3, and XMFLOAT4 for class data members.

3. Useloading functions to convert from XMFLOAT* to XMVECTOR before doingcalculations.

4. Docalculations with XMVECTOR instances.

5. Usestorage functions to convert from XMVECTOR to XMFLOAT*.

小结:

1.      局部变量或全局变量可使用XMVECTOR

2.      使用XMFLOAT2, XMFLOAT3, 和 XMFLOAT4作为类的成员变量

3.      计算前,使用加载函数将XMFLOAT*类型转换成为XMVECTOR类型

4.      使用XMVECTOR类型的实例进行计算

5.      使用存储函数将XMVECTOR类型转换成XMFLOAT* 类型

1.6.2 Loading andStorage Methods

We use thefollowing methods to load data from XMFLOAT* into XMVECTOR:

我们使用下列方法将数据从XMFLOAT*类型加载到XMVECTOR类型

//  Loads XMFLOAT2  into  XMVECTOR 加载 XMFLOAT2  到 XMVECTOR

XMVECTOR  XMLoadFloat2(CONST  XMFLOAT2 *pSource);

//  Loads XMFLOAT3  into  XMVECTOR加载 XMFLOAT3  到 XMVECTOR

XMVECTOR  XMLoadFloat3(CONST  XMFLOAT3 *pSource);

//  Loads XMFLOAT4  into  XMVECTOR加载 XMFLOAT4  到 XMVECTOR

XMVECTOR  XMLoadFloat4(CONST  XMFLOAT4 *pSource);

 

NOTE:here are many moreloading methods used to load other data types into an XMVECTOR; the reader canview the XNA Math documentation for the complete list. Following are a few moreexamples:

注意:存在许多加载函数可以将其他数据类型转换到XMVECTOR类型,读者可以自己浏览XNA Math 文档查看完整地函数列表。下面给出少许例子:

//  Loads 3-element  UINT  array into  XMVECTOR 加载三元素无符号整型数组到XMVECTOR

XMVECTOR  XMLoadInt3(CONST  UINT* pSource);

//  Loads XMCOLOR  into  XMVECTOR 加载XMCOLOR到XMVECTOR

XMVECTOR  XMLoadColor(CONST  XMCOLOR *pSource);

//  Loads XMBYTE4  into  XMVECTOR 加载XMBYTE4到XMVECTOR

XMVECTOR  XMLoadByte4(CONST  XMBYTE4 *pSource);

 

We use thefollowing methods to store data from XMVECTOR into XMFLOAT*:

我们使用下列函数将XMVECTOR类型数据存储为XMFLOAT*

//  Loads XMVECTOR  into  XMFLOAT2 加载XMVECTOR到XMFLOAT2

VOID  XMStoreFloat2(XMFLOAT2  *pDestination,  FXMVECTOR V);

//  Loads XMVECTOR  into  XMFLOAT3加载XMVECTOR到XMFLOAT3

VOID  XMStoreFloat3(XMFLOAT3  *pDestination,  FXMVECTOR V);

//  Loads XMVECTOR  into  XMFLOAT4加载XMVECTOR到XMFLOAT4

VOID  XMStoreFloat4(XMFLOAT4  *pDestination,  FXMVECTOR V);

NOTE:There are many more storing methodsused to store XMVECTOR into other data types. Following is a small sampling;the reader can see the XNA Math documentation for the complete list.

注意:存在许多加载函数可以将XMVECTOR类型转换到其他数据类型,读者可以自己浏览XNA Math 文档查看完整地函数列表。下面给出少许例子:

//  Loads XMVECTOR  into  3 element  UINT  array

VOID  XMStoreInt3(UINT*  pDestination, FXMVECTOR  V);

//  Loads XMVECTOR  into  XMCOLOR

VOID  XMStoreColor(XMCOLOR*  pDestination, FXMVECTOR  V);

//  Loads XMVECTOR  into  XMBYTE4

VOID  XMStoreByte4(XMBYTE4  *pDestination,  FXMVECTOR V);

Sometimes wejust want to get or set one component of an XMVECTOR; the following getter andsetter functions facilitate this:

有时我们可能只希望设置或得到XMVECTOR的一个分量,下列的存取方法可以实现它:

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

 

1.6.3 Parameter Passing

To takeadvantage of SIMD, there are some rules for passing parameters to functions oftype XMVECTOR. These rules differ based on the platform; in particular, theydiffer between 32-bit Windows, 64-bit Windows, and XBox 360. To be platformindependent, we use the types CXMVECTOR and FXMVECTOR for passing XMVECTORparameters; these are defined to the right type based on the platform. ForWindows, these are defined as:

为了使用SIMD,我们必须遵循XMVECTOR的函数传递规则,这些规则基于不同的平台有所不同,尤其是在32 位window、64位window以及XBOX360上。为了使平台独立化,我们使用类型CXVECTOR和FXMVECTOR来传递XMVECTOR类型的参数,它们的具体类型定义取决于平台。在window中,其定义如下:

 

//  32-bit Windows

typedef  const XMVECTOR  FXMVECTOR;

typedef  const XMVECTOR&  CXMVECTOR;

//  64-bit Windows

typedef  const XMVECTOR&  FXMVECTOR;

typedef  const XMVECTOR&  CXMVECTOR;

Thedifference is whether we can pass a copy of XMVECTOR directly, or if we mustpass a reference. Now the rule for passing XMVECTOR parameters is as follows:

不同之处在于我们是否可以直接传递一个XMVECTOR的副本,或者我们必须传递一个引用变量。因此XMVECTOR类型的参数传递规则如下:

The first 3XMVECTOR parameters should be of type FXMVECTOR; any additional XMVECTORparameters should be of type CXMVECTOR. Here is an example:

前三个XMVECTOR参数的类型必须为FXMVECTOR;其余的XMVECTOR参数必须指定为CXMVECTOR类型。示例如下:

XMINLINE  XMMATRIX XMMatrixTransformation( FXMVECTOR ScalingOrigin,

FXMVECTOR  ScalingOrientationQuaternion, FXMVECTOR  Scaling,

CXMVECTOR  RotationOrigin,

CXMVECTOR  RotationQuaternion,

CXMVECTOR  Translation);

This  function takes        6  XMVECTOR parameters,  but  following the  parameter  passing rules,  it  uses the FXMVECTOR and CXMVECTOR types. Thefirst three XMVECTOR parameters are of type FXMVECTOR and the additionalXMVECTOR parameters are of type CXMVECTOR. Note that you can have non-XMVECTORparameters between XMVECTOR parameters; the first 3 XMVECTOR parameters arestill typed as XMVECTOR, and additional XMVECTOR parameters are typed asCXMVECTOR:

此函数有6个XMVECTOR类型的参数,但仍遵循参数传递规则,它使用FXMVECTOR 和CXMVECTOR类型。前三个参数的类型为FXMVECTOR其余为CXMVECTOR。注意在任意两个XMVECTOR类型参数之间都可使用非XMVECTOR类型,但前三个XMVECTOR参数的类型必须为FXMVECTOR;其余的XMVECTOR参数必须指定为CXMVECTOR类型。

XMINLINE  XMMATRIX XMMatrixTransformation2D( FXMVECTOR ScalingOrigin,

FLOAT  ScalingOrientation,

FXMVECTOR  Scaling,

FXMVECTOR  RotationOrigin,

FLOAT  Rotation,

CXMVECTOR  Translation);

1.6.4 Constant Vectors

ConstantXMVECTOR instances should use the XMVECTORF32 type. Here are some examples fromthe DirectX SDK’s CascadedShadowMaps11 sample:

静态向量实例必须指定为XMVECTORF32类型,下列有一些来自CascadedShadowMaps1示例的代码示例:

 

static  const XMVECTORF32  g_vHalfVector  =  {  0.5f, 0.5f,  0.5f,  0.5f };

static  const XMVECTORF32  g_vZero  =  {  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

};

 

Essentially,we use XMVECTORF32 whenever we want to use initialization syntax. XMVECTORF32is a  16-byte aligned structure with aXMVECTOR conversion operator; it is defined as follows:

本质上,我们在初始化时使用XMVECTORF32。XMVECTORF32是使用XMVECTOR转换操作符的16字节线性结构体,其定义如下:

//  Conversion types  for  constants 常量类型转换

typedef  _DECLSPEC_ALIGN_16_  struct XMVECTORF32 

{ union  {

float  f[4];

XMVECTOR  v;

};

#if  defined(__cplusplus)

inline  operator XMVECTOR()  const  { return  v;  }

#if  !defined(_XM_NO_INTRINSICS_)  && defined(_XM_SSE_INTRINSICS_)

inline  operator __m128i()  const

 

{  return reinterpret_cast<const __m128i  *>(&v)[0];  }

 inline operator  __m128d()  const

{  return reinterpret_cast<const __m128d  *>(&v)[0];  } #endif

#endif  // __cplusplus

}  XMVECTORF32;

You can alsocreate a constant XMVECTOR of integer data using XMVECTORU32:

你也可以使用XMVECTORU32创建一个XMVECTOR类型的整型数据:

static  const XMVECTORU32  vGrabY  =  {

0x00000000,0xFFFFFFFF,0x00000000,0x00000000

};

1.6.5 OverloadedOperators

1.6.5 重载操作

 

TheXMVECTOR  has  several overloaded  operators  for doing  vector  addition, subtraction, and scalar multiplication. Operator  overloading can  be  disabled by defining XM_NO_OPERATOR_OVERLOADS. The  reason some application would want to disable operator overloading is forperformance, as the function versions can be faster when forming complexexpressions (see [Oliveira2010]). We prefer the more intuitive syntax ofoperator overloading in this book and keep it enabled.

XMVECTOR中有许多加减及标量乘法的重载运算符。重载运算可通过定义XM_NO_OPERATOR_OVERLOADS来禁止,一些程序之所以禁用重载是为了使运算更高效,因为标准运算函数在复杂语句中运行更快。我们更倾向于随心所欲的重载,所以本书中将保持可重载。

//  Vector operators

#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  // __cplusplus  &&  !XM_NO_OPERATOR_OVERLOADS

 

 

 

 

1.6.6 Miscellaneous

 

The XNA Mathlibrary defined the following constants useful for approximating differentexpressions involving π:

XNA数学库定义了下列常量用来近似表示与π有关的参量

#define  XM_PI 3.141592654f

#define  XM_2PI 6.283185307f

#define  XM_1DIVPI 0.318309886f

#define  XM_1DIV2PI 0.159154943f

#define  XM_PIDIV2 1.570796327f

#define  XM_PIDIV4 0.785398163f

In addition,it defines the following inline functions for converting between radians anddegrees:

此外,还定义了下列内联函数用于将弧度和角度进行转换:

XMFINLINE  FLOAT XMConvertToRadians(FLOAT fDegrees)

{

return  fDegrees *  (XM_PI  / 180.0f);

}

XMFINLINE  FLOAT XMConvertToDegrees(FLOAT fRadians)

{

return  fRadians *  (180.0f  / XM_PI);

}

It alsodefines min/max macros:

 

#define  XMMin(a, b)  (((a)  < (b))  ?  (a) :  (b))

#define  XMMax(a, b)  (((a)  > (b))  ?  (a) :  (b))

1.6.7 Setter Functions

1.6.7 设置函数

XNA Mathprovides the following functions to set the contents of an XMVECTOR:

XNA数学库提供了下列函数来设置XMVECTOR的内容:

XMVECTOR  XMVectorZero();  // Returns  the  zero vector  0 返回参数全零的向量

XMVECTOR  XMVectorSplatOne();  // Returns  the  vector (1,  1,  1,  1)

XMVECTOR  XMVectorSet( //  Returns  the vector  (x,  y, z,  w)

FLOAT  x, FLOAT  y,  FLOAT z,  FLOAT  w);

XMVECTOR  XMVectorReplicate(  // Returns  the  vector (s,  s,  s,  s)FLOAT  s);

XMVECTOR  XMVectorSplatX(  // Returns  the  vector (vx,  vx,  vx,  vx)

FXMVECTOR  V);

XMVECTOR  XMVectorSplatY(  // Returns  the  vector (vy,  vy,  vy, vy)

FXMVECTOR  V);

XMVECTOR  XMVectorSplatZ(  // Returns  the  vector (vz,  vz,  vz, vz)

FXMVECTOR  V);

Thefollowing program illustrates most of these functions:

下列的程序示例演示了如何使用他们:

#include  <windows.h>  // for  FLOAT  definition #include  <xnamath.h>

#include  <iostream>

using  namespace std;

//  Overload the  "<<"  operators so  that  we can  use  cout  to//  output  XMVECTOR objects.

ostream&  operator<<(ostream&  os, FXMVECTOR  v)

{

XMFLOAT3  dest;

XMStoreFloat3(&dest,  v);

os  << "("  <<  dest.x <<  ",  " <<  dest.y  << ",  "  << dest.z  <<  ")"; return  os;

}

int  main()

{

cout.setf(ios_base::boolalpha);

//  Check support  for  SSE2 (Pentium4,  AMD  K8, and  above). if(  !XMVerifyCPUSupport()  )

{

cout  << "xna  math  not supported"  <<  endl; return 0;

}

XMVECTOR  p =  XMVectorZero();

XMVECTOR  q =  XMVectorSplatOne();

XMVECTOR  u =  XMVectorSet(1.0f,  2.0f, 3.0f,  0.0f);

XMVECTOR  v =  XMVectorReplicate(-2.0f);

XMVECTOR  w =  XMVectorSplatZ(u);

cout  << "p  =  " <<  p  << endl;

cout  << "q  =  " <<  q  << endl;

cout  << "u  =  " <<  u  << endl;

cout  << "v  =  " <<  v  << endl;

cout  << "w  =  " <<  w  << endl;

return  0;

}

1.6.8 Vector Functions

XNA Mathprovides the following functions to do various vector operations. We illustratewith the 3D versions, but there are analogous versions for 2D and 4D; the 2Dand 4D versions have the same names as the 3D versions, with the exception of a2 and 4 substituted for the 3, respectively.

XNA数学库提供了下列函数用于各种向量操作。此示例使用3D版本(即三维空间版本),但是其中仍有2D和4D的类型版本。2D和4D版本的函数名与3D相同,只不过把函数名中3换成2或4即可。

 

XMVECTOR  XMVector3Length(  // Returns  ||  v  ||

FXMVECTOR  V); //  Input  v

XMVECTOR  XMVector3LengthSq(  // Returns  ||  v  ||

2FXMVECTOR  V);  // Input  v

XMVECTOR  XMVector3Dot( //  Returns  v1  •  v2

FXMVECTOR  V1, //  Input  v1

FXMVECTOR  V2);  //  Input v2

XMVECTOR  XMVector3Cross(  // Returns  v1  ×  v2

FXMVECTOR  V1, //  Input  v1

FXMVECTOR  V2); //  Input  v2

XMVECTOR  XMVector3Normalize(  // Returns  v/||  v  ||

FXMVECTOR  V); //  Input  v

XMVECTOR  XMVector3Orthogonal(  // Returns  a  vector orthogonal  to  v

FXMVECTOR  V); //  Input  v

XMVECTOR XMVector3AngleBetweenVectors(  // Returns  the  angle between  v1  and  v2

FXMVECTOR  V1, //  Input  v1

FXMVECTOR  V2); //  Input  v2

VOID  XMVector3ComponentsFromNormal(

XMVECTOR*  pParallel, //  Returns  projn(v)

XMVECTOR*  pPerpendicular,  // Returns  prepn(v)

FXMVECTOR  V, //  Input  v

FXMVECTOR  Normal); //  Input  n

BOOL  XMVector3Equal(  // Returns  v1  =  v2

FXMVECTOR  V1, //  Input  v1

FXMVECTOR  V2);  //  Input v2

BOOL  XMVector3NotEqual(  // Returns  v1  ≠  v2

 FXMVECTOR V1,  //  Input v1

FXMVECTOR  V2); //  Input  v2

Note:Observe that thesefunctions return XMVECTORS even for operations that mathematically return ascalar (for example,  the  dot product  k  = v1 •  v2).  The scalar result  is replicated  in  each component  of  the XMVECTOR. For example, for the dotproduct, the returned vector would be (v1 • v2, v1 • v2, v1 • v2, v1 • v2). One reason forthis is to minimize mixing of scalar and SIMD vector operations; it is moreefficient to keep everything SIMD until you are done with your calculations.

注意:观察到这些函数均返回XMVECTORS,即使是返回一个标量(例如,点积k = v1  •  v2)。标量结果是把XMVECTOR的每个分量复制为相同量。例如,对于点积而言,结果向量应为v1 • v2, v1 • v2, v1 • v2, v1 • v2)。这样做的原因是避免将标量运算和SIMD的向量运算混淆。在你计算时,保持使用SIMD是非常必要的。

The  following demo  program  shows how  to  use most  of  these functions,  as  well as  some of the overloadedoperators:

下列示例演示了如何使用这些函数,其中也包含了许多重载操作

 

#include  <windows.h>  // for  FLOAT  definition #include  <xnamath.h>

#include  <iostream> 
using  namespace  std;

//  Overload the  "<<"  operators so  that  we can  use  cout to //  output  XMVECTOR objects.

ostream&  operator<<(ostream&  os,  FXMVECTOR  v) 
{

XMFLOAT3  dest;

XMStoreFloat3(&dest,  v);

os  << "("  <<  dest.x <<  ",  " <<  dest.y  << ",  "  << dest.z  <<  ")";

return  os;

}

int  main() 
{

cout.setf(ios_base::boolalpha);

//  Check support  for  SSE2 (Pentium4,  AMD  K8, and  above). if(  !XMVerifyCPUSupport()  )

{

cout  << "xna  math  not supported"  <<  endl; return 0;

}

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); //  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  angleRadians =  XMVectorGetX(angleVec);

float  angleDegrees = XMConvertToDegrees(angleRadians);

cout  << "u  =  " <<  u  << endl;

cout  << "v  =  " <<  v  << endl;

cout  << "w  =  " <<  w  << endl;

cout  << "n  =  " <<  n  << endl;

cout  << "a  =  u +  v  = "  <<  a <<  endl;

cout  << "b  =  u -  v  = "  <<  b <<  endl;

cout  << "c  =  10  *  u =  "  << c  <<  endl;

cout  << "d  =  u /  ||u||  = "  <<  d <<  endl;

cout  << "e  =  u x  v  = "  <<  e <<  endl;

cout  << "L  =  ||u|| =  "  << L  <<  endl;

cout  << "s  =  u.v  =  " <<  s  << endl;

cout  << "projW  =  " <<  projW  << endl;

cout  << "perpW  =  " <<  perpW  << endl;

cout  << "projW  +  perpW ==  w  = "  <<  equal <<  endl;

cout  << "projW  +  perpW !=  w  = "  <<  notEqual <<  endl; cout  << "angle  =  " <<  angleDegrees  << endl;

return  0;

}


Figure 1.19. Output for the above program.

NOTE:The XNA Math library alsoincludes some estimation methods, which are less accurate but faster tocompute. If you are willing to sacrifice some accuracy for speed, then use the estimatemethods. Here are two examples of estimate functions:

注意:XNA数学库也包含了许多近似计算函数,它们不太精确但计算速度快。如果你想牺牲精度而追求速度的话,你可以考虑使用近似计算。下面有2个近似计算函数的示例:

XMFINLINE  XMVECTOR XMVector3LengthEst(  //  Returns estimated  ||  v  ||

FXMVECTOR  V); //  Input  v

XMFINLINE  XMVECTOR XMVector3NormalizeEst(  //  Returns estimated  v/||  v  ||

FXMVECTOR  V); //  Input  v

1.6.9 Floating-PointError

1.6.9 浮点错误

Whileon the subject of working with vectors on a computer, we should be aware of thefollowing. When comparing

floating-pointnumbers, care must be taken due to floating-point imprecision. Two floating-pointnumbers that we expect to be equal may differ slightly. For example,mathematically, we’d expect a normalized vector to have a length of one, but ina computer program, the length will only be approximately one. Moreover, mathematically,1p = 1 for any real number p, but when we only have a numerical approximationfor , we see that the approximation raised to the th power increases the error;thus, numerical error also accumulates. The following short program illustratesthese ideas:

当在计算机中涉及到向量时,我们必须有下列意识。当比较两个浮点数时,一定要考虑浮点数的精度问题。两个我认为相等的浮点数可能略有不同。比如,在数学中,我们希望正规化一个向量使他长度为1,但在计算机程序中,这个长度只能是一个近似值。另外,在实际数学中,1的任意次方为1,但在计算机中我们只能得到一个近似值,这样就会导致计算错误,下列的简单代码演示了这种情况:

#include  <windows.h>  // for  FLOAT  definition

#include  <xnamath.h>

#include  <iostream>

using  namespace std;

int  main()

{

cout.precision(8);

//  Check support  for  SSE2 (Pentium4,  AMD  K8, and  above).

if(  !XMVerifyCPUSupport()  )

{

cout  << "xna  math  not supported"  <<  endl;

return  0;

}

XMVECTOR  u =  XMVectorSet(1.0f,  1.0f, 1.0f,  0.0f);

 XMVECTOR n  =  XMVector3Normalize(u);

float  LU = XMVectorGetX(XMVector3Length(n));

//  Mathematically,  the length  should  be 1.  Is  it numerically?

cout  << LU  <<  endl;

if(  LU ==  1.0f  )

cout  << "Length  1"  << endl;

else

cout  << "Length  not  1" <<  endl;

//  Raising 1  to  any power  should  still be  1.  Is  it?float  powLU  = powf(LU,  1.0e6f);

cout  << "LU^(10^6)  =  " <<  powLU  << endl;

}

Tocompensate for floating-point imprecision, we test if two floating-pointnumbers are approximately equal. We do

thisby defining an Epsilon constant, which is a very small value we use as a  “buffer.” We say two values are

approximatelyequal if their distance is less than Epsilon. In other words, Epsilon gives ussome tolerance for

floating-pointimprecision. The following function illustrates how Epsilon can be used to testif two floating-point values are equal:

为了弥补浮点数不精确的问题,我们检测两个数是否近似相等。我们定义一个Epsilon常量,他的值非常小。当两个浮点数间的差值小于这个值时,我们认为这两个浮点数相等。换句话说,Epsilon允许一定的误差。下列函数示例用于测试两个浮点数是否近似相等:

const  float Epsilon  =  0.001f;

bool  Equals(float lhs,  float  rhs)

{

//  Is the  distance  between lhs  and  rhs less  than  EPSILON?

return  fabs(lhs -  rhs)  < Epsilon  ?  true :  false;

}

TheXNA Math library provides the XMVector3NearEqual function when testing theequality of vectors with an allowed tolerance Epsilon parameter:

XNA数学库提供了XMVector3NearEqual函数,用于测试两个向量在允许容差Epsilon内是否相等。

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

1.7 SUMMARY 

0 0