DX12龙书 02 - DirectXMath 库中与向量有关的类和函数
0x00 需要用到的头文件
#include <DirectXMath>
#include <DirectXPackedVector.h>
using namespace DirectX;
using namespace DirectX::PackedVector;
0x01 针对不同平台的设置
针对 x86 平台:
需要启用 SSE2 指令集(Project Properties(工程属性) -> Configuration Properties(配置属性) -> C/C++ -> Code Generation(代码生成) -> Enable Enhanced Instruction Set(启用增强指令集)。
针对所有平台:
应当启用快速浮点模型 /fp:fast (Project Properties(工程属性) -> Configuration Properties(配置属性) -> C/C++ -> Code Generation(代码生成) -> Floating Point Model(浮点模型)。
针对 x64 平台:
不必开启 SSE2 指令集,因为所有的 x64 CPU 对此均有支持。
0x02 充分利用 SIMD 技术
什么是 SIMD ?
SIMD 全称 Single Instruction Multiple Data,单指令多数据流,能够复制多个操作数,并把它们打包在大型寄存器的一组指令集,可一次性获得所有操作数进行运算。
在 DirectXMath 中,核心向量类型是 XMVECTOR,它将被映射到 SIMD 硬件寄存器。在计算向量的过程中,必须通过此类型才可以充分地利用 SIMD 技术。
XMVECTOR 类型的数据需要按 16 字节对齐,这对局部变量和全局变量都是自动实现的。至于类中的数据成员,建议分别使用 XMFLOAT2、XMFLOAT3 和 XMFLOAT4 类型来加以代替。
总结:
- 局部变量或全局变量用 XMVECTOR 类型。
- 对于类中的数据成员,使用 XMFLOAT2、XMFLOAT3 和 XMFLOAT4 类型。
- 在运算之前,通过加载函数将 XMFLOATn 类型转换为 XMVECTOR 类型。
- 用 XMVECTOR 实例来进行运算。
- 通过存储函数将 XMVECTOR 类型转换为 XMFLOATn 类型。
0x03 加载和存储方法
使用下面的方法将数据从 XMFLOATn 类型加载到 XMVECTOR 类型:
XMVECTOR XM_CALLCONV XMLoadFloatn(const XMFLOATn *pSource);
使用下面的方法将数据从 XMVECTOR 类型存储到 XMFLOATn 类型:
void XM_CALLCONV XMStoreFloatn(XMFLOATn *pDestination, FXMVECTOR V);
如果只希望从 XMVECTOR 中得到一个向量的分量或将一个向量的分量转换为 XMVECTOR 类型,可以使用下面的方法:
float XM_CALLCONV XMVectorGetX(FXMVECTOR V);
float XM_CALLCONV XMVectorGetY(FXMVECTOR V);
float XM_CALLCONV XMVectorGetZ(FXMVECTOR V);
float XM_CALLCONV XMVectorGetW(FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVectorSetX(FXMVECTOR V, float x);
XMVECTOR XM_CALLCONV XMVectorSetY(FXMVECTOR V, float y);
XMVECTOR XM_CALLCONV XMVectorSetZ(FXMVECTOR V, float z);
XMVECTOR XM_CALLCONV XMVectorSetW(FXMVECTOR V, float w);
0x04 参数的传递
为了提高效率,可以将 XMVECTOR 类型的值作为函数的参数,直接传送至 SSE/SSE2 寄存器里,而不存于栈(stack)内。
这里有几个使用 XMVECTOR 参数的规则:
- 将约定注解 XM_CALLCONV 加在函数名前;
- 前 3 个 XMVECTOR 参数应当用类型 FXMVECTOR;
- 第 4 个 XMVECTOR 参数应当用类型 GXMVECTOR;
- 第 5、6 个 XMVECTOR 参数应当用类型 HXMVECTOR;
- 其余的 XMVECTOR 参数应当用类型 CXMVECTOR。
构造函数注意事项:
在编写构造函数时,前 3 个 XMVECTOR 参数用 FXMVECTOR 类型,其余 XMVECTOR 参数则用 CXMVECTOR 类型。
0x05 常向量
XMVECTOR 类型的常量实例应当用 XMVECTORF32 类型来表示。在初始化的时候就要使用 XMVECTORF32 类型。
static const XMVECTORF32 g_vHalfVector = {0.5f, 0.5f, 0.5f, 0.5f};
XMVECTORF32 是一种按 16 字节对齐的结构体,数学库中还提供了将它转换至 XMVECTOR 类型的运算符。其定义如下:
__declspec(align(16)) struct XMVECTORF32
{
union
{
float f[4];
XMVECTOR v;
};
inline operator XMVECTOR() const { return v; }
inline operator const float*() const { return f; }
#if !defined(_XM_NO_INTRINSICS_) && defined(_XM_SSE_INTRINSICS_)
inline operator __m128i() const { return _mm_castps_si128(v); }
inline operator __m128d() const { return _mm_castps_pd(v); }
#endif
};
另外,也可以通过 XMVECTORU32 类型来创建由整型数据构成的 XMVECTOR 常向量:
static const XMVECTORU32 vGrabY = {0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000};
0x06 向量函数
DirectXMath 库除了提供常见的向量加减法和标量运算的运算符重载之外,还提供了一些函数来执行各种向量运算。
值得注意的是,即使在数学上计算的结构是标量,比如点积,但这些函数所返回的类型依旧是 XMVECTOR,得到的标量结果则被复制到 XMVECTOR 中的各个分量之中。这样做的原因之一是:将标量和 SIMD 向量的混合运算次数降到最低,全程使用 SIMD 技术,以提升计算效率。
DirectXMath 库也提供一些估算方法,精度低但速度快。如:
// 返回估算值 ||V||
XMVECTOR XM_CALLCONV XMVector2LengthEst(FXMVECTOR V);
0x07 浮点数误差
在比较浮点数时,一定要注意浮点数存在的误差。我们认为相等的两个浮点数可能会存在细微的差别。为了弥补浮点数精确性上的不足,我们通过比较两个浮点数是否近似相等来加以解决。在比较时,需要定义一个非常小的常量 Epsilon。如果两个数相差小于 Epsilon,就说这两个数是近似相等的。
对此, DirectXMath 库提供了 XMVector3NearEqual 函数,用于以 Epsilon 作为容差,测试比较的向量是否相等:
// return
// abs(V1.x - V2.x) <= Epsilon.x &&
// abs(V1.y - V2.y) <= Epsilon.y &&
// abs(V1.z - V2.z) <= Epsilon.z
bool XM_CALLCONV XMVector3NearEqual(FXMVECTOR V1, FXMVECTOR V2, FXMVECTOR Epsilon);
DX12龙书 02 - DirectXMath 库中与向量有关的类和函数的更多相关文章
- DX12龙书 01 - 向量在几何学和数学中的表示以及运算定义
0x00 向量 向量 ( vector ) 是一种兼具大小 ( magnitude ) 和方向的量. 0x01 几何表示 几何方法中用一条有向线段来表示一个向量,其中,线段长度代表向量的模,箭头的指向 ...
- DX12龙书第6章习题
1. { { , DXGI_FORMAT_R32G32B32_FLOAT, , , D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, }, { , DXGI_FO ...
- 线程高级应用-心得8-java5线程并发库中同步集合Collections工具类的应用及案例分析
1. HashSet与HashMap的联系与区别? 区别:前者是单列后者是双列,就是hashmap有键有值,hashset只有键: 联系:HashSet的底层就是HashMap,可以参考HashSe ...
- DX12龙书 00 - 环境配置:通过 Visual Studio 2019 运行示例项目
0x00 安装 Visual Studio 2019 安装 Visual Studio 2019 以及相关组件. 注:安装组件时带的 Windows 10 SDK 可以在 Individual com ...
- 排序方法之标准库中的快排 qsort ()函数
C标准库qsort()函数的用法(快排) 使用快速排序例程进行排序 头文件:stdlib.h 用 法: void qsort(void *base, int nelem, int width, i ...
- 标准模板库中的向量(vector)
//C++数据结构与算法(第4版) Adam Drozdek 著 徐丹 吴伟敏<<清华大学出版社>> 头文件:#include<vector> 向量是最简单的S ...
- 龙书(Dragon book) +鲸书(Whale book)+虎书(Tiger book)
1.龙书(Dragon book)书名是Compilers: Principles,Techniques,and Tools作者是:Alfred V.Aho,Ravi Sethi,Jeffrey D. ...
- 正则表达式引擎的构建——基于编译原理DFA(龙书第三章)——3 计算4个函数
整个引擎代码在github上,地址为:https://github.com/sun2043430/RegularExpression_Engine.git nullable, firstpos, la ...
- 编译原理 #03# 龙书中缀转后缀JS实现版
// 来自龙书第2章2.5小节-简单表达式的翻译器 笔记 既然是语法制导翻译(Syntax-directed translation),那么最重要的东西当然是描述该语言语法的文法,以下为中缀表达式文法 ...
随机推荐
- File类与IO流
一.File类与IO流 数组.集合等内容都是把数据放在内存里面,一旦关机或者断电,数据就会立刻从内存里面消失.而IO主要讲文件的传输(输入和输出),把内存里面的数据持久化到硬盘上,如.txt .avi ...
- oracle创建/删除 用户,表空间-九五小庞
以下红色标示的都是可以修改的字段 可以按照如下顺序来创建表空间,创建用户,以及删除表空间,删除用户 查看oracle数据库已有的表空间路径 select name from v$datafile; 1 ...
- SQL连接(内连接、外连接、交叉连接)
SQL连接(内连接.外连接.交叉连接) 假设现在有两个表:table1 , table2 table1: table2 : id ...
- C004:要求用户输入一个美元数量,然后显示出增加5%税率后的相应金额
程序: #include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { float amount; do{ printf(&q ...
- [bash] 获取linux主机名,检视内中是否有特定字符串
代码: #!/bin/bash hostname=$(hostname) #调用hostname命令获取主机名放入变量hostname中 #echo $hostname if [ `echo ${ho ...
- leetcode刷题-55跳跃游戏
题目 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 判断你是否能够到达最后一个位置. 思路 贪心算法:记录每一个位置能够跳跃到的最远距离,如果 ...
- boostrap栅格系统自适应的布局
1.栅格系统 Bootstrap是基于移动优先的原则开发的,使用了一系列的媒体查询(media queries)方法,为我们的布局和界面创建自适应的的分界点.这些分界点主要是基于视口宽度的最小值, ...
- 为什么互联网巨头们纷纷使用Git而放弃SVN?(内含Git核心命令与原理总结)
写在前面 最近发现很多小伙伴对于工作中的一些基本工具的使用还不是很了解,比如:Git这个分布式的代码管理仓库,很多小伙伴就不是很了解,或者说不是很熟悉.甚至有些小伙伴都没听说过Git,就只会用个SVN ...
- Django 仿ajax传递数据(Django十)
之前用form表单传递数据,没有遇到任何问题 具体见:https://blog.csdn.net/qq_38175040/article/details/104867747 然后现在我想用ajax传递 ...
- 浅谈Charles —— 青花瓷
Charles -- 青花瓷 网络抓包工具 可以拦截 iPhone/Android 手机中 App 的非加密网络请求数据 使用 手机&电脑在同一个局域网 确保电脑能够通过路由器访问互联网 电脑 ...