Tag DirectX下的博客主要用于记录DirectX的学习过程,主要参考《DirectX 12 3D 游戏实战开发》。

Vector in DirectX

Shader的编写离不开数学运算,尤其是向量矩阵类型的运算,DirectX为我们准备了一个完备的数学库DirectXMath.h,里面封装了常用的向量矩阵类型,并且重载了许多方法,如点积、叉积、矩阵乘法等。DirectXMath是Windows SDK的一部分,是为D3D打造的3D数学库,采用SIMD指令集加速向量运算,如:单条SIMD加法指令可以直接计算4D向量的加法结果。

变量类型

添加#include <DirectXMath.h>即可使用DirectXMath库,其中的代码都位于namespace DirectX,使用相关数据类型则需添加#include <DirectXPackedVector.h>,其中的代码位于namespace DirectX::PackedVector。在DirectXMath库中的核心类型为XMVECTOR,它需要按16字节对齐,其中向量类型为XMFLOAT2XMFLOAT3XMFLOAT4。而在开启SSE2之后,在x86和x64平台中,XMVECTOR被定义为一个共用体_m128,通过这个类型,SIMD技术才得以实现。

  1. // _m128在xmmintrin.h下被定义
  2. typedef union __declspec(intrin_type) __declspec(align(16)) __m128 {
  3. float m128_f32[4];
  4. unsigned __int64 m128_u64[2];
  5. __int8 m128_i8[16];
  6. __int16 m128_i16[8];
  7. __int32 m128_i32[4];
  8. __int64 m128_i64[2];
  9. unsigned __int8 m128_u8[16];
  10. unsigned __int16 m128_u16[8];
  11. unsigned __int32 m128_u32[4];
  12. } __m128;

Setter函数

DirectXMath库提供了设置XMVECTOR类型中数据的函数。

  1. // return zero vector
  2. XMVECTOR XM_CALLCONV XMVectorZero();
  3. // return unit vector
  4. XMVECTOR XM_CALLCONV XMVectorSplatOne();
  5. // return vector(x, y, z, w)
  6. XMVECTOR XM_CALLCONV XMVectorSet(float x, float y, float z, float w);
  7. // return vector(Value, Value, Value, Value)
  8. XMVECTOR XM_CALLCONV XMVectorReplicate(float Value);
  9. // return vector(V.x, V.x, V.x, V.x)
  10. XMVECTOR XM_CALLCONV XMVectorSplatX(FXMVECTOR V);
  11. // return vector(V.y, V.y, V.y, V.y)
  12. XMVECTOR XM_CALLCONV XMVectorSplatY(FXMVECTOR V);
  13. // return vector(V.z, V.z, V.z, V.z)
  14. XMVECTOR XM_CALLCONV XMVectorSplatZ(FXMVECTOR V);

常向量

XMVECTOR类型的常量应使用XMVECTORF32或者XMVECTORU32类型表示,即使用XMVECTORF32初始化浮点型向量,使用XMVECTORU32初始化整型向量。

加载/存储

为了发挥SIMD特性,在构建向量实例时还应使用库提供的loading function把实例转换为XMVECTOR类型,同时,库还提供了逆向转换的storage function,用于把XMVECTOR转换为XMFLOATn类型。总结就是:变量统一为XMVECTOR类型,类内成员用XMFLOATn类型,运算前转换为XMVECTOR类型,运算后转换回XMFLOATn类型。

  1. // loading function(n为向量维度)
  2. XMVECTOR XM_CALLCONV XMLoadFloatn(const XMFLOATn *pSource);
  3. // storage function(n为向量维度)
  4. void XM_CALLCONV XMStoreFloatn(XMFLOATn *pDestination, FXMVECTOR V);
  5. // 获取or存储XMVECTOR中的某个分量(以x分量为例)
  6. float XM_CALLCONV XMVectorGetX(FXMVECTOR V);
  7. XMVECTOR XM_CALLCONV XMVectorSetX(FXMVECTOR V, float x);

参数传递

为了进一步提高效率,DirectX还允许把XMVECTOR类型的值作为函数参数直接送入SSE寄存器中,但是通过这种方法传递的参数有数量限制,数量的限制也因平台而异。为了让代码更具通用性,DirectX为我们提供了一种约定注解XM_CALLCONV。这个注解添加在有XMVECTOR类型参与的函数定义之前,编译器会根据平台转化为特定的调用约定。调用约定则会把特定数量的XMVECTOR类型直接送往寄存器。

  1. // 在32位的Windows系统上,XM_CALLCONV转化为__fastcall调用约定
  2. // 把前三个XMVECTOR类型直接传入寄存器时,将会出现如下类型定义
  3. typedef const XMVECTOR FXMVECTOR;
  4. typedef const XMVECTOR& GXMVECTOR;
  5. typedef const XMVECTOR& HXMVECTOR;
  6. typedef const XMVECTOR& CXMVECTOR;

DirectX给我们的建议是,在同一个函数调用中,前三个XMVECTOR参数应使用类型FXMVECTOR,第四个XMVECTOR参数应使用GXMVECTOR,第5、6个XMVECTOR应使用HXMVECTOR,其余的使用CXMVECTOR。而在定义构造函数时,规则又有所不同。定义构造函数时,前三个XMVECTOR类型应使用FXMVECTOR类型,其余的使用CXMVECTOR,而且不要对构造函数使用XM_CALLCONV注解。而在参数输出时并不会输出到SSE寄存器内,故处理方式和普通类型一致。在DirectXMath库某些函数的定义中就可以体会到XMVECTOR的参数传递法则。

  1. // DirectXMath库中的XMMatrixTransformation函数
  2. inline XMMATRIX XM_CALLCONV XMMatrixTransformation(
  3. FXMVECTOR ScalingOrigin,
  4. FXMVECTOR ScalingOrientationQuaternion,
  5. FXMVECTOR Scaling,
  6. GXMVECTOR RotationOrigin,
  7. HXMVECTOR RotationQuaternion,
  8. HXMVECTOR Translation);

运算符重载

XMVECTOR类型提供了有关向量间运算、向量与标量运算的运算符重载。

  1. XMVECTOR XM_CALLCONV operator+ (FXMVECTOR V);
  2. XMVECTOR XM_CALLCONV operator- (FXMVECTOR V);
  3. XMVECTOR& XM_CALLCONV operator+= (XMVECTOR& V1, FXMVECTOR V2);
  4. XMVECTOR& XM_CALLCONV operator-= (XMVECTOR& V1, FXMVECTOR V2);
  5. XMVECTOR& XM_CALLCONV operator*= (XMVECTOR& V1, FXMVECTOR V2);
  6. XMVECTOR& XM_CALLCONV operator/= (XMVECTOR& V1, FXMVECTOR V2);
  7. XMVECTOR& operator*= (XMVECTOR& V, float S);
  8. XMVECTOR& operator/= (XMVECTOR& V, float S);
  9. XMVECTOR XM_CALLCONV operator+ (FXMVECTOR V1, FXMVECTOR V2);
  10. XMVECTOR XM_CALLCONV operator- (FXMVECTOR V1, FXMVECTOR V2);
  11. XMVECTOR XM_CALLCONV operator* (FXMVECTOR V1, FXMVECTOR V2);
  12. XMVECTOR XM_CALLCONV operator/ (FXMVECTOR V1, FXMVECTOR V2);
  13. XMVECTOR XM_CALLCONV operator* (FXMVECTOR V, float S);
  14. XMVECTOR XM_CALLCONV operator* (float S, FXMVECTOR V);
  15. XMVECTOR XM_CALLCONV operator/ (FXMVECTOR V, float S);

向量函数

DirectXMath库提供了封装好的函数执行向量运算,下面给出其中部分的3D向量版本,对应的有2D和4D版本,函数名形式相同。每个函数的命名都已经很好地体现了函数的功能。可以注意到,即使运算在数学上的计算结果是标量,例如点积,对应函数的返回类型仍然是XMVECTOR,而这个结果标量会被复制到各个分量中。这么做的原因之一是尽量减少SIMD向量和标量的混合运算,提高效率。DirectXMath库还提供了一些性能开销交稿的函数的估算版本,这些函数精度低,速度快。

  1. XMVECTOR XM_CALLCONV XMVector3Length(FXMVECTOR V); // 计算V的模长
  2. XMVECTOR XM_CALLCONV XMVector3LengthSq(FXMVECTOR V); // 计算V模长的平方
  3. XMVECTOR XM_CALLCONV XMVector3Dot(FXMVECTOR V1, FXMVECTOR V2); // 点积
  4. XMVECTOR XM_CALLCONV XMVector3Cross(FXMVECTOR V1, FXMVECTOR V2); // 叉积
  5. XMVECTOR XM_CALLCONV XMVector3Normalize(FXMVECTOR V); // 规范化
  6. XMVECTOR XM_CALLCONV XMVector3Orthogonal(FXMVECTOR V); // 返回一个与V正交的向量
  7. XMVECTOR XM_CALLCONV XMVector3AngleBetweenVectors(FXMVECTOR V1, FXMVECTOR V2); // 计算向量间的夹角
  8. // 计算V关于Normal的平行分量和正交分量,输入的Normal必须是已经normalize的
  9. // pParallel存储平行分量,pPerpendicular存储正交分量
  10. void XM_CALLCONV XMVector3ComponentsFromNormal(
  11. XMVECTOR* pParallel,
  12. XMVECTOR* pPerpendicular,
  13. FXMVECTOR V,
  14. FXMVECTOR Normal
  15. );
  16. bool XM_CALLCONV XMVector3Equal(FXMVECTOR V1, FXMVECTOR V2); // 判断V1和V2是否相同
  17. bool XM_CALLCONV XMVector3NotEqual(FXMVECTOR V1, FXMVECTOR V2); // 判断V1和V2是否不同
  18. // 判断V1和V2是否近似相等,容差值为Epsilon,这是为了弥补浮点误差
  19. XMFINLINE bool XM_CALLCONV XMVector3NearEquals(FXMVECTOR V1, FXMVECTOR V2, FXMVECTOR Epsilon);
  20. XMVECTOR XM_CALLCONV XMVector3LengthEst(FXMVECTOR V); // 估算V的模长
  21. XMVECTOR XM_CALLCONV XMVector3NormalizeEst(FXMVECTOR V); // 估算V的规范化向量

杂项

DirectXMath库也提供了一些数学常量的近似值,以及弧度角度转化、比较值的函数。

  1. const float XM_PI = 3.141592654f;
  2. const float XM_2PI = 6.283185307f;
  3. const float XM_1DIVPI = 0.318309886f;
  4. const float XM_1DIV2PI = 0.159154943f;
  5. const float XM_PIDIV2 = 1.570796327f;
  6. const float XM_PIDIV4 = 0.785398163f;
  7. inline float XMConvertToRadians(float fDegrees)
  8. { return fDegrees * (XM_PI / 180.0f); }
  9. inline float XMConvertToDegrees(float fRadians)
  10. { return fRadians * (180.0f / XM_PI); }
  11. template<class T> inline T XMMin(T a, T b) { return (a < b) ? a : b; }
  12. template<class T> inline T XMMax(T a, T b) { return (a > b) ? a : b; }

DirectX:Vector的更多相关文章

  1. 初入水:vector

    ---恢复内容开始---Vector 是一个类模板.不是一种数据类型. Vector<int>是一种数据类型 类的作用,是一种顺序容器,支持随机访问,可动态分配空间(扩充:销毁旧内存,更新 ...

  2. 顺序容器:vector,deque,list

    1.顺序容器:vector,deque,list 容器类共享公共接口,只要学会其中一种类型就能运用另一种类型.每种容器提供一组不同的时间和功能这种方案,通常不需要修改代码,秩序改变类型声明,每一种容器 ...

  3. JAVA中的数据结构——集合类(线性表:Vector、Stack、LinkedList、set接口;键值对:Hashtable、Map接口<HashMap类、TreeMap类>)

    Java的集合可以分为两种,第一种是以数组为代表的线性表,基类是Collection:第二种是以Hashtable为代表的键值对. ... 线性表,基类是Collection: 数组类: person ...

  4. C++学习笔记:Vector容器

    vector v:初始化一个0大小的向量 vector v(10):初始化一个10个大小的向量 push_back:增加一个元素 pop:删除一个元素,不返回 front:返回第一个元素 back:返 ...

  5. JAVA提高十八:Vector&Stack深入分析

    前面我们已经接触过几种数据结构了,有数组.链表.Hash表.红黑树(二叉查询树),今天再来看另外一种数据结构:栈. 什么是栈呢,我们先看一个例子:栈就相当于一个很窄的木桶,我们往木桶里放东西,往外拿东 ...

  6. Java集合类源码解析:Vector

    [学习笔记]转载 Java集合类源码解析:Vector   引言 之前的文章我们学习了一个集合类 ArrayList,今天讲它的一个兄弟 Vector.为什么说是它兄弟呢?因为从容器的构造来说,Vec ...

  7. C++:vector的用法详解

    原文地址:http://blog.csdn.net/hancunai0017/article/details/7032383 vector(向量): C++中的一种数据结构,确切的说是一个类.它相当于 ...

  8. Effective STL 学习笔记 Item 16:vector, string & C API

    有时需要支持 C 的接口,但这并不复杂. 对于 vector 来讲, \(v[0]\) 的地址 \(\&v[0]\) 即可作为数组指针传递给 C API: 1: // Legacy C API ...

  9. Java集合(3):Vector && Stack

    一.Vector介绍 Vector可以实现可增长的动态对象数组.与数组一样,它包含可以使用整数索引进行访问的组件.不过,Vector的大小是可以增加或者减小的,以便适应创建Vector后进行添加或者删 ...

随机推荐

  1. C# - VS2019WinFrm桌面应用程序FtpClient实现

    前言 本篇主要记录:VS2019 WinFrm桌面应用程序实现简单的FtpClient,包含Ftp文件查看.上传和下载等功能. 准备工作 搭建WinFrm前台界面 添加必要的控件,这里主要应用到Gro ...

  2. Pytest 测试框架

    一 . Pytest 简介 Pytest是python的一种单元测试框架. 1. pytest 特点 入门简单,文档丰富 支持单元测试,功能测试 支持参数化,重复执行,部分执行,测试跳过 兼容其他测试 ...

  3. JavaScript AJAX PHP

    AJAX PHP示例 AJAX用于创建更多交互式应用程序. 以下示例演示了当用户在输入字段中键入字符时,网页如何与Web服务器通信: <!DOCTYPE html> <html> ...

  4. centos下非yum方式安装docker环境

    1.下载docker源码包 docker官网地址: https://download.docker.com/linux/static/stable/ 选择.tgz的包下载,例如:https://dow ...

  5. React + Ts 实现三子棋小游戏

    在这里阅读效果更佳 还记得当年和同桌在草稿纸上下三子棋的时光吗 今天我们就用代码来重温一下年少(假设你有react基础,没有也行,只要你会三大框架的任意一种,上手react不难) 游戏规则 双方各执一 ...

  6. ucoreOS_lab3 实验报告

    所有的实验报告将会在 Github 同步更新,更多内容请移步至Github:https://github.com/AngelKitty/review_the_national_post-graduat ...

  7. java8新特性—四大内置核心接口

    java8新特性-四大内置核心接口 四大内置核心接口 //消费型接口 Consumer<T>:: vode accept(T t); //供给型接口 Supplier<T>:: ...

  8. 每天一套题打卡|河南省第七届ACM/ICPC

    A 海岛争霸 题目:Q次询问,他想知道从岛屿A 到岛屿B 有没有行驶航线,若有的话,所经过的航线,危险程度最小可能是多少. 多源点最短路,用floyd 在松弛更新:g[i][k] < g[i][ ...

  9. flask如何返回真正意义上的json字符串?以及中文如何正常显示?

    flask中,不能直接return字典,需要把字典转换为json字符串方式有三种:1. return str(字典)2.return json.dumps(字典)3.return jsonify(字典 ...

  10. 【使用篇二】SpringBoot文件上传(5)

    一.单个文件上传 1. 在static目录下创建upload.html <!DOCTYPE html> <html> <head> <meta charset ...