(转)【D3D11游戏编程】学习笔记二:XNAMath之XMVECTOR

(注:【D3D11游戏编程】学习笔记系列由CSDN作者BonChoix所写,转载请注明出处:http://blog.csdn.net/BonChoix,谢谢~)

一、XNA Math简介

在D3D10及之前的版本中,3D数学库是伴随在D3DX库中的。在D3D11版中,3D数学库被单独隔离出来,为XNA Math库,功能和之前基本一样,但是建立在SIMD指令上,以更好地利用Windows及XBox360上特殊的硬件寄存器(128位,可以同时操作4个32位数)。

二、向量类型

在XNA数学库中,核心的向量类型为XMVECTOR,它正好映射为SIMD硬件上的128位寄存器,以利用一个指令同时操作4个32位的数。当SEE2指令集可用时,可以定义为:

[cpp] view plain copy

  1. typedef __m128 XMVECTOR;

在操作向量时,XMVECTOR除了用于4维向量外,还可以用于操作2维、三维向量,以于多出的几维默认为0,不关心即可。

此外要注意的是,XMVECTOR在内存中是16位对齐的,当作为局部或全局变量使用时,由硬件自动实现对齐。对于类中的成员变量,则推荐使用XMFLOAT2(2D), XMFLOAT3(3D), XMFLOAT4(4D)来代替XMVECTOR,定义分别如下:

[cpp] view plain copy

  1. typedef struct _XMFLOAT2
  2. {
  3. FLOAT x;
  4. FLOAT y;
  5. } XMFLOAT2;
  6. typedef struct _XMFLOAT3
  7. {
  8. FLOAT x;
  9. FLOAT y;
  10. FLOAT z;
  11. } XMFLOAT3;
  12. typedef struct _XMFLOAT4
  13. {
  14. FLOAT x;
  15. FLOAT y;
  16. FLOAT z;
  17. FLOAT w;
  18. } XMFLOAT4;

但是,如果直接使用XMFLOAT2、XMFLOAT3等这些类型进行计算,是不会利用到SIMD指令的加速效果的,因此在计算前要把这些向量转换为XMVECTOR,然后再进行各种向量运算。这几种类型与XMVECTOR之间的相互转换函数主要分为Store和Load两种,Store型用来把一个XMVECTOR存储到指定的XMFLOATx中,Load型用来从一个XMFLOATx读取内容到XMVECTOR中。总结下这段话内容,即:

1. 在局部、全局变量中使用XMVECTOR类型;

2. 在类中定义向量成员时,使用类型XMFLOAT2,XMFLOAT3,XMFLOAT4;

3. 对类中的向量进行运算时,用Load型函数把相应向量读取到XMVECTOR中,再进行运算;

4. 运算完后把相应的结果XMVECTOR通过Store型函数存储到相应的XMFLOATx向量中。

三、 Load型和Store型函数

Load型函数用来从一个XMFLOATx向量中读取内容到XMVECTOR中。如下几种:

[cpp] view plain copy

  1. XMVECTOR XMLoadFloat2(CONST XMFLOAT2 *pSource);     //从XMFLOAT2中读取内容到一个XMVECTOR中
  2. XMVECTOR XMLoadFloat3(CONST XMFLOAT3 *pSource);     //从XMFLOAT3中读取内容到一个XMVECTOR中
  3. XMVECTOR XMLoadFloat4(CONST XMFLOAT4 *pSource);     //从XMFLOAT4中读取内容到一个XMVECTOR中

此外除了XMFLOATx类型,还可以Load到其他类型的向量数据中,如:

[cpp] view plain copy

  1. XMVECTOR XMLoadInt2(CONST UINT *pSource);       //从二维UINT向量中读取内容到一个XMVECTOR向量中
  2. XMVECTOR XMLoadColor(CONST XMCOLOR *pSource);       //从XMCOLOR中读取内容到一个XMVECTOR中
  3. XMVECTOR XMLoadByte4(CONST XMBYTE4 *pSource);       //从XMBYTE4中读取内容到一个XMVECTOR中

Store型函数用来把一个XMVECTOR存储到一个XMFLOATx向量中。如下几种:

[cpp] view plain copy

  1. void XMStoreFloat2(XMFLOAT2 *pDest, FXMVECTOR V);   //把XMVECTOR存储到一个XMFLOAT2向量中
  2. void XMStoreFloat3(XMFLOAT3 *pDest, FXMVECTOR V);   //把XMVECTOR存储到一个XMFLOAT3向量中
  3. void XMStoreFloat4(XMFLOAT4 *pDest, FXMVECTOR V);   //把XMVECTOR存储到一个XMFLOAT4向量中

同理,除了XMFLOATx类型,还可以把XMVECTOR存储到其他类型向量中,如:

[cpp] view plain copy

  1. void XMStoreInt3(UINT *pDest, FXMVECTOR V);     //把XMVECTOR存储到一个二维UINT向量中
  2. void XMStoreColor(XMCOLOR *pDest, FXMVECTOR V);     //把XMVECTOR存储到一个XMCOLOR向量中
  3. void XMStoreByte4(XMBYTE4 *pDest, FXMVECTOR V);     //把XMVECTOR存储到一个XMBYTE4向量中

由于XMVECTOR映射为一个特殊的SIMD寄存器,而不是一个struct,因此我们不能直接操作其x,y,z,w维数据,因此提供了以下几个Set和Get函数:

[cpp] view plain copy

  1. FLOAT XMVectorGetX(FXMVECTOR V);    //得到XMVECTOR的X维数据
  2. FLOAT XMVectorGetY(FXMVECTOR V);    //得到XMVECTOR的Y维数据
  3. FLOAT XMVectorGetZ(FXMVECTOR V);    //得到XMVECTOR的Z维数据
  4. FLOAT XMVectorGetW(FXMVECTOR V);    //得到XMVECTOR的W维数据
  5. XMVECTOR XMVectorSetX(FXMVECTOR V, FLOAT x);    //设置一个XMVECTOR的X维数据,并返回新XMVECTOR
  6. XMVECTOR XMVectorSetY(FXMVECTOR V, FLOAT y);    //设置一个XMVECTOR的Y维数据,并返回新XMVECTOR
  7. XMVECTOR XMVectorSetZ(FXMVECTOR V, FLOAT z);    //设置一个XMVECTOR的Z维数据,并返回新XMVECTOR
  8. XMVECTOR XMVectorSetW(FXMVECTOR V, FLOAT w);    //设置一个XMVECTOR的W维数据,并返回新XMVECTOR

你可能注意到,在上面所有的函数中,有好多FXMVECTOR类型的参数,而不是XMVECTOR类型。别急,这正是我们下一步要说的。

四、 XMVECTOR类型参数传递规定

为了更好地利用SIMD,当XMVECTOR作为函数参数类型时,有特殊的规定。这些规则与平台相关,比如在32位和64位的Windows及XBox360下规则就不一样。为了在写代码时与平台无关,XNA Math专门针对函数参数类型定义了这两个类型:CXMVECTOR和FXMVECTOR。在不同的平台下这两个类型有着相应的不同的定义,对于程序员在写代码时则无需考虑这些,只要服从相应的规则即可。规则如下:

在一个函数中,前三个使用到XMVECTOR类型的参数,必须为FXMVECTOR;之后所有其他的XMVECTOR类型参数要为CXMVECTOR。

[cpp] view plain copy

  1. XMINLINE XMMATRIX XMMatrixTransformation(
  2. FXMVECTOR ScalingOrigin,                    //第1个XMVECTOR类型参数
  3. FXMVECTOR ScalingOrientationQuaternion,             //第2个XMVECTOR类型参数
  4. FXMVECTOR Scaling,                      //第3个XMVECTOR类型参数
  5. CXMVECTOR RotationOrigin,                   //第4个开始,后面的全部为CXMVECTOR类型
  6. CXMVECTOR RotationQuaternion,
  7. CXMVECTOR Translation);

当然,各参数之间也可以夹杂其他非XMVECTOR类型的参数,但只要是前三个类型为XMVECTOR的参数使用FXMVECTOR,后面所有类型为XMVECTOR的参数使用CXMVECTOR即可。例如:

[cpp] view plain copy

  1. XMINLINE XMMATRIX XMMatrixTransformation2D(
  2. FXMVECTOR ScalingOrigin,                    //第1个XMVECTOR类型参数
  3. FLOAT     ScalingOrientation,
  4. FXMVECTOR Scaling,                      //第2个XMVECTOR类型参数
  5. FXMVECTOR RotationOrigin,                   //第3个XMVECTOR类型参数
  6. FLOAT     Rotation,
  7. CXMVECTOR Translation);                     //第4个,必须使用CXMVECTOR

是不是感觉这规则有点奇怪?反正我感觉很奇怪,不过无所谓,其实也很简单,我们平时操作XMVECTOR类型进行运算时不用关心这个,仅仅是在定义函数时,如果参数类型为XMVECTOR,才需要考虑这个规则。

五、 常量向量

当用到常量型的XMVECTOR时,应该使用XMVECTORF32类型,尤其是当使用初始化式时。例如:

[cpp] view plain copy

  1. const XMVECTORF32 g_Zero = {0.f,0.f,0.f,0.f};
  2. static const XMVECTORF32 g_tmp = {x,y,z,w};

XMVECTORF32是16字节对齐的数据结构,可以转换为XMVECTOR类型。定义如下:

[cpp] view plain copy

  1. typedef _DECLSPEC_ALIGN_16_ struct XMVECTORF32
  2. {
  3. union
  4. {
  5. float v[4];
  6. XMVECTOR v;
  7. };
  8. //如果是在C++环境下,则还有其他成员函数
  9. //比如重载()操作符,转换为XMVECTOR类型
  10. };

因此,如果想事先定义一些常量型的XMVECTOR,则可以用const XMVECTORF32类型来定义,在程序中用到XMVECTOR类型时,再利用类型转换(static_cast)转换为XMVECTOR类型即可。比如我们可能想事先定义好各种常见的颜色,像白色可以这样定义:const XMFLOAT32 White = {1.f, 1.f, 1.f, 1.f};

六、 针对XMVECTOR类型重载的操作符

在C++环境下,针对各种常见的向量操作,对XMVECTOR重载了相应的操作符。比如:向量加减+、-、+=、-=,向量与数字相乘:*、/、*=、/=,向量点积:*,*=等。

七、 一些Setter函数

[cpp] view plain copy

  1. XMVECTOR XMVectorZero();        //[0,0,0,0]
  2. XMVECTOR XMVectorSplatOne();    //[1.f, 1.f, 1.f, 1.f]
  3. XVMECTOR 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);   //[v.x, v.x, v.x, v.x]
  6. XMVECTOR XMVectorSplatY(FXMVECTOR v);   //[v.y, v.y, v.y, v.y]
  7. XMVECTOR XMVectorSplatZ(FXMVECTOR v);   //[v.y, v.y, v.y, v.y]

八、 向量操作函数

[cpp] view plain copy

  1. XMVECTOR XMVector3Length(FXMVECTOR v);     //长度L,结果为[L,L,L,L],效率起见,全部为XMVECTOR类型,我们只取一个维即可。
  2. XMVECTOR XMVector3LengthSq(FXMVECTOR v);   //长度L平方根,结果存放同上。其他任何返回scalar数的同理
  3. XMVECTOR XMVector3Dot(FXMVECTOR v1, FXMVECTOR v2);  //点积dot,[dot, dot, dot, dot]
  4. XMVECTOR XMVector3Cross(FXMVECTOR v1, FXMVECTOR v2);    //叉乘
  5. XMVECTOR XMVector3Normalize(FXMVECTOR v);       //归一化
  6. XMVECTOR XMVector3Orthogonal(FXMVECTOR v);      //返回一个垂直的向量
  7. XMVECTOR XMVector3AngleBetweenVectors(FXMVECTOR v1, FXMVECTOR v2);  //返回两向量间角度angle,[angle, angle, angle, angle]

学习XNA Math库的最好方法就是参考SDK,在安装好最新DirectX SDK后都会有个文档《DirectX Documentation for C++》,里面有XNA Math详细介绍,遇到不懂的函数可以直接在上面查找。以上只是对XMVECTOR的一些基本介绍,其他所有的XNA Math函数、类型都可以参考SDK。

最后,附加作者Luna的源代码,通过示例来熟悉XMVECTOR的用法。

XMVectorGetSampleCode();

时间: 2024-08-18 08:53:34

(转)【D3D11游戏编程】学习笔记二:XNAMath之XMVECTOR的相关文章

DirectX 11游戏编程学习笔记之7: 第6章Drawing in Direct3D(在Direct3D中绘制)(重点回顾+勘误)

        本文由哈利_蜘蛛侠原创,转载请注明出处!有问题欢迎联系[email protected]         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候,会使用章节号而非页码.同样的情况适合于"龙书"第二版. 上一期的地址: DX 11游戏编程学习笔记之6 这一章应该是本书最长的一章了,可能也是最难的一章,所以大家一定要好好消化,仔细学习!这一章大致相当于"龙书"第二版的第7章和第8章,还添加了一些别的东西. 由于这一

DirectX 11游戏编程学习笔记之1: 开场白

本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系[email protected] ? ? ? ? ? 这是我之前的博客系列"DirectX9.0c游戏开发手记之'龙书'第二版学习笔记"的平行版,也可以说是续集. 说是平行版,由于这两个博客系列由于某种显而易见的原因.内容是非常平行的:而之所以说是续集,是由于前面那个系列可能就此坑掉了-- ? ? ? ? 前面那个系列是关于"龙书"第二版的学习笔记的.而这一系列是关于"龙书"第四版的.&qu

DirectX游戏编程学习(二)文本显示与基本图元绘制

一.文本显示 在游戏开发中,在游戏界面上现实一些文字信息是很常见的一件事,要学习DX游戏开发,显然了解DX文本如何显示是必不可少的.字符包含诸多的属性,比如颜色,大小,是否加粗,斜体,等等.我们通过DX提供的LPD3DFONT对象来指定这些字体属性,然后再进行渲染. 采用WIN32程序框架实现文本绘制的具体流程如下: 二.基本图元的绘制 无论再复杂的物体,它归根结底都是由基本图元构成的.在CG(Computer graphics)领域,人们普遍使用一组或者多组包围物体表面的多边形近似的表示真实的

DirectX 11游戏编程学习笔记2: 文章1章Vector Algebra(向量代数)

本文由哈里_蜘蛛侠原创,转载请注明出处.有问题欢迎联系[email protected]         注:我给的电子版是700多页.而实体书是800多页,所以我在提到相关概念的时候.会使用章节号而非页码. 相同的情况适合于"龙书"第二版. 我们这一期正式開始学习DX 11编程了! 前三章组成了本书的第一部分.叫做"Mathematical Prerequisites".学好这一部分是继续前进的前提条件.这一部分的导言前面引用了一句名言,这让我颇为意外.这让我想起

FFmpeg编程学习笔记二:音频重采样

ffmpeg实现音频重采样的核心函数swr_convert功能非常强大,可是ffmpeg文档对它的注释太过简单,在应用中往往会出这样那样的问题,其实在读取数据->重采样->编码数据的循环中在第一次执行swr_convert后还应用swr_convert再作个缓存检测看看是否还有数据,如果有就要把它写到FIFO中去,留在下次再使用,这点在转码和由低向高转换采样率时特别重要. 下面一段简单的代码,摘自我自已写的测试程序. const int frame_size = FFMIN(fifo_size

linux sheel编程学习笔记(二) --- grep命令

Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户. grep的工作方式是这样的,它在一个或多个文件中搜索字符串模板.如果模板包括空格,则必须被引用,模板后的所有字符串被看作文件名.搜索的结果被送到标准输出,不影响原文件内容. grep可用于shell脚本,因为grep通过返回一个状态值来说明搜索的状态,如果模板搜索成

(转)【D3D11游戏编程】学习笔记二十三:Cube Mapping进阶之动态环境图

(注:[D3D11游戏编程]学习笔记系列由CSDN作者BonChoix所写,转载请注明出处:http://blog.csdn.net/BonChoix,谢谢~) 在前面两篇介绍Cube Mapping的文章中,我们所使用到的Cube Map都是事先制作好的,这样的一个好处就是运行时效率很高,适合于大多数情形.但如果对于即时动态变化的场景来说,依靠静态图来实现反射效果就不再适用了.因为在不同时刻,一个物体周围的场景是不断变化的,想要把这些变化在物表的反射中体现出来,就需要一张动态的环境图. 1.C

(转)【D3D11游戏编程】学习笔记二十一:Cube Mapping及其应用之一:天空盒的实现

(注:[D3D11游戏编程]学习笔记系列由CSDN作者BonChoix所写,转载请注明出处:http://blog.csdn.net/BonChoix,谢谢~) 这一节讨论有关纹理映射的进阶内容:Cube Mapping. 1. 简介 单从名字上,就大概可以看出点端倪了,翻译成中文为立方体映射,因此肯定跟立方体有关系.确实,Cube Mapping就是使用六张正方形的图片来进行纹理映射的.这六张图片分别对应了一个立方体中的六个面.由于这个立方体是轴对齐的,因此每个面可以用坐标系中的六个轴方向来惟

(转)【D3D11游戏编程】学习笔记二十四:切线空间(Tangent Space)

(注:[D3D11游戏编程]学习笔记系列由CSDN作者BonChoix所写,转载请注明出处:http://blog.csdn.net/BonChoix,谢谢~) 切换空间,同局部空间.世界空间等一样,是3D图形学中众多的坐标系之一.切换空间最重要的用途之一,即法线映射(Normal Mapping).关于法线映射的细节,将在下一篇文章中详细介绍.但在学习法线映射之前,深刻地理解切换空间非常重要.因此借这一篇文章来学习下它,以为后面学习法线映射.视差映射(Parallax Mapping).Dis