【DX12】DirectX Math库 Vector和Matrix类型 XMVECTOR、XMMATRIX
DirectX Math Library 是一个3D数学库,包含在Windows SDK中。该库使用了SSE2(Streaming SIMD Extensions 2)指令集。使用128位宽的SIMD(Single Instruction Multiple Data)寄存器,因此做向量计算会更快。
注:在X86平台下,需要在VS中手动设置,启用SSE2(Enable Enhanced Instruction Set)。在任何平台下,都要手动启用fast floating point model。在project prote具体方法请查阅资料。
1 Vector
1.1 XMVECTOR
DirectX Math Library库中核心的Vector类型:XMVECTOR。是对SIMD硬件寄存器的映射。在当前CPU上SSE2指令集可用时,它是这样定义的:
typedef _m128 XMVECTOR;
_m128是由Microsoft提供的基本数据类型,用于与SSE、SSE2内部指令一起使用的。在16字节边界上自动对齐。ARM处理器不支持该类型。
虽然这是一个128位宽的寄存器,能存储一个四维的Vector,但当我们使用二维或三维的Vector运算时,为了效率,仍然会去使用XMVECTOR类型。
XMVECTOR的数据不能直接访问。可以转换成XMFLOAT类型(转换方法见下文),也可通过特定的接口get或set其某个分量:
// XM_CALLCONV 的作用之后会解释
// 为什么这个地方是FXMVECTOR,多了个‘F’,之后会解释
float XM_CALLCONV XMVectorGetX(FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVectorSetX(FXMVECTOR V, float x);
XMVECTOR重载了加减乘除等运算符,可以方便的进行运算。
1.2 XMVECTORF32
XMVECTOR的常量实例,应定义为XMVECTORF32。
例如:
static const XMVECTORF32 g_vHalfVector = {0.5f ,0.5f, 0.5f, 0.5f};
XMVECTORF32可以转换为四维float数组,或者XMVECTOR。
1.3 XMFLOATn
上文提到,XMVECTOR需要16位对齐,当定义为局部或者全局变量时,这个对齐操作是自动的。当定义为类的成员变量时,推荐使用XMFLOAT2、XMFLOAT3、XMFLOAT4来代替。这些类型的数据结构,实际只是封装了几个普通的float变量。
XMVECTOR与XMFLOATn之间可以相互转换。当要进行计算操作时,建议将XMFLOATn转换为XMVECTOR。XMFLOATn到XMVECTOR的转换,需要通过DirectX Math loading functions来完成。
XMVECTOR到XMFLOATn的转换,需要通过DirectX Math storage functions来完成。
转换函数的申明如下:
// 加载XMFLOAT2到XMVECTOR
XMVECTOR XM_CALLCONV XMLoadFloat2(cosnt XMFLOAT2 *pSource);// 存储XMVECTOR到XMFLOAT2
void XM_CALLCONV XMStoreFloat2(XMFLOAT2 *pDestination, FXMVECTOR V);
1.4 参数传递
由于XMVECTOR的数据存储在寄存器,而不在堆栈上,因此参数传递时会有些特殊。基本的想法是,能用寄存器传递的就用寄存器传递,不能的就用栈。具体可以通过寄存器传递的参数数量,根据平台和编译器而定。
为此,增加了几种用于参数传递的数据类型,FXMVECTOR、GXMVECTOR、HXMVECTOR、CXMVECTOR。基本的使用规则是:
- 前三个XMVECTOR参数使用FXMVECTOR
- 第四个XMVECTOR参数使用GXMVECTOR
- 第五六个XMVECTOR参数使用HXMVECTOR
- 其他使用CXMVECTOR
而宏XM_CALLCONV,就是用于告诉编译器该函数调用时,有这种特别的参数传递规则。
所以会看到这样的定义:
void XM_CALLCONV XMStoreFloat2(XMFLOAT2 *pDestination, FXMVECTOR V);
但是,这些规则在构造函数中并不适用。在构造函数中:
- 前三个XMVECTOR参数使用FXMVECTOR
- 其他使用CXMVECTOR
- 不要使用XM_CALLCONV
另外,这些规则只是针对于XMVECTOR类型本身。而对于复合类型,XMVECTOR&、XMVECTOR*并不会使用寄存器传递,和普通参数同等看待。
有了上面的基础可以看两个例子。有助于理解。
#include <windows.h> // 为了使用函数XMVerifyCPUSupport,检查是否支持SSE2
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <iostream>
using namespace std;
using namespace DirectX;
using namespace DirectX::PackedVector;
// 重载 "<<" 运算符,用于输出XMVECTOR类型的对象
ostream& XM_CALLCONV operator<<(ostream& os, FXMVECTOR v)
{// XMVECTOR数据不能直接访问,因此要进行转换!XMFLOAT3 dest;XMStoreFloat3(&dest, v);os << "(" << dest.x << ", " << dest.y << ", " << dest.z << ")";return os;
}
int main()
{// 检查是否支持SSE2 (Pentium4, AMD K8, and above).if (!XMVerifyCPUSupport()){cout << "directx math not supported" << endl;return 0;}// 一些常用的获取XMVECTOR对象的函数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;system("pause");return 0;
}
/*
output:
p = (0, 0, 0)
q = (1, 1, 1)
u = (1, 2, 3)
v = (-2, -2, -2)
w = (3, 3, 3)
*/
第二个例子中将使用一些常用的Vector运算。
注意,即使运算结果为标量,返回值仍然是XMVECTOR,因为运算都是通过SIMD进行的。这也有利于继续使用这个标量进行Vector运算。
#include <windows.h> // 为了使用函数XMVerifyCPUSupport,检查是否支持SSE2
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <iostream>
using namespace std;
using namespace DirectX;
using namespace DirectX::PackedVector;
// 重载 "<<" 运算符,用于输出XMVECTOR类型的对象
ostream& XM_CALLCONV operator << (ostream& os, FXMVECTOR v)
{// XMVECTOR数据不能直接访问,因此要进行转换!XMFLOAT3 dest;XMStoreFloat3(&dest, v);os << "(" << dest.x << ", " << dest.y << ", " << dest.z << ")";return os;
}
int main()
{cout.setf(ios_base::boolalpha);// 检查是否支持SSE2 (Pentium4, AMD K8, and above).if (!XMVerifyCPUSupport()){cout << "directx 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 vXMVECTOR s = XMVector3Dot(u, v);// e = u x vXMVECTOR e = XMVector3Cross(u, v);// 计算w平行于n、垂直于n的两个分量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;// projW 和 perpW 成90度.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;system("pause");return 0;
}
/*
output:
u = (1, 2, 3)
v = (-2, 1, -3)
w = (0.707, 0.707, 0)
n = (1, 0, 0)
a = u + v = (-1, 3, 0)
b = u - v = (3, 1, 6)
c = 10 * u = (10, 20, 30)
d = u / ||u|| = (0.267261, 0.534522, 0.801784)
e = u x v = (-9, -3, 5)
L = ||u|| = (3.74166, 3.74166, 3.74166)
s = u.v = (-9, -9, -9)
projW = (0.707, 0, 0)
perpW = (0, 0.707, 0)
projW + perpW == w = true
projW + perpW != w = false
angle = 90
*/
Matrix
XMMATRIX类型用于存储矩阵,有了上面的基础,也就比较简单了。
XMMATRIX实际是存储了4个XMVECTOR。也有对应的非寄存器类型XMFLOAT4X4,有16个float组成。有相互转换的函数。
在函数的参数传递中,第一个XMMATRIX类型要用FXMMATRIX,其他用CXMMATRIX。
看一个例子
#include <windows.h>
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <iostream>
using namespace std;
using namespace DirectX;
using namespace DirectX::PackedVector;
ostream& XM_CALLCONV operator << (ostream& os, FXMVECTOR v)
{XMFLOAT4 dest;XMStoreFloat4(&dest, v);os << "(" << dest.x << ", " << dest.y << ", " << dest.z << ", " << dest.w << ")";return os;
}
ostream& XM_CALLCONV operator << (ostream& os, FXMMATRIX m)
{for (int i = 0; i < 4; ++i){os << XMVectorGetX(m.r[i]) << "\t";os << XMVectorGetY(m.r[i]) << "\t";os << XMVectorGetZ(m.r[i]) << "\t";os << XMVectorGetW(m.r[i]);os << endl;}return os;
}
int main()
{if (!XMVerifyCPUSupport()){cout << "directx math not supported" << endl;return 0;}XMMATRIX A(1.0f, 0.0f, 0.0f, 0.0f,0.0f, 2.0f, 0.0f, 0.0f,0.0f, 0.0f, 4.0f, 0.0f,1.0f, 2.0f, 3.0f, 1.0f);XMMATRIX B = XMMatrixIdentity();XMMATRIX C = A * B;XMMATRIX D = XMMatrixTranspose(A);XMVECTOR det = XMMatrixDeterminant(A);XMMATRIX E = XMMatrixInverse(&det, A);XMMATRIX F = A * E;cout << "A = " << endl << A << endl;cout << "B = " << endl << B << endl;cout << "C = A*B = " << endl << C << endl;cout << "D = transpose(A) = " << endl << D << endl;cout << "det = determinant(A) = " << det << endl << endl;cout << "E = inverse(A) = " << endl << E << endl;cout << "F = A*E = " << endl << F << endl;return 0;
}
reference:
Introdunction to 3D Game Programming with DirectX 12
【DX12】DirectX Math库 Vector和Matrix类型 XMVECTOR、XMMATRIX相关推荐
- Python库之math库
math库的学习 math库的简介 4个数学常数 44个函数 16个数值表示函数 函数简介 部分实例 8个幂对数函数 函数简介 部分实例 16个三角对数函数 函数简介 4个高等特殊函数 函数简介 ma ...
- python中math库_Python库详解之math库
1 首先我们看下定义的Number-theoretic and representation functions. 1:ceil(x):功能:返回一个浮点数据,该数据向上取整. 2:copysign( ...
- python中求和公式是什么函数_Python的math库中,用于求和的函数是( )。
[单选题]确定兴利库容 V 兴 ,已知某水库为一回运用水库,其一次蓄水量为 V 1 =300 万 m 3 ,一次供水量为 V 2 =150 万 m 3 . [ ]. [单选题]hAB大于0说明B点的高 ...
- C++标准库vector及迭代器
vector是同一种对象的集合,每个对象都有一个对应的整数索引值.和string对象一样,标准库将负责管理与存储元素相关的类存.引入头文件 #include<vector> 1.vecto ...
- python math库 sqrt eval_Python 在线基础课程
注释的两种方法: 单行注释以#开头 #Here are the comments 多行注释以'''开头和结尾 赋值操作 可以多赋值 比如交换x,y的值 x,y=y,x 输入函数 Input()函 ...
- python怎么导入math库_Python math数学库的用法
对于基本的加.减.乘.除等运算,不用引入任何库就可以完成.但是如果要进行求正弦值.求平方根等运算,便需要使用数学库 math. math 库通过下面语句引入: import math 该库包含常用的常 ...
- math库是python语言的数学模块吗_math库是python语言的数学模块。
[单选题]for i in range(10): ...... 中 ,i的循环终值是 (). [简答题]人生观的主要内容 [填空题]下面程序的运行结果是( ). b, c=2, 4 def g_fun ...
- python math库常用函数_Python math库常用函数
math库常用函数及举例: 注意:使用math库前,用import导入该库 >>> import math 取大于等于x的最小的整数值,如果x是一个整数,则返回x >>& ...
- 【 MATLAB 】norm ( Vector and matrix norms )(向量范数以及矩阵范数)
norm Vector and matrix norms Syntax n = norm(v) n = norm(v,p) n = norm(X) n = norm(X,p) n = norm(X,' ...
- c++ 使用 math库笔记
目录 win10系统 cmakelist.txt linux gcc方式 c++使用pi win10系统 这个头文件在visual studio的 sdk中 引用方法: #include<mat ...
最新文章
- 第十五届全国大学生智能汽车竞赛人工智能创意赛
- Python包的相对导入时出现问题解决
- sublime 正则搜索日语字符
- Nginx 运维之域名验证
- linux c mysql 增删改查_Linux C语言连接MySQL 增删改查操作
- tflite C++ API 部署分类模型
- Codeforces Round #161 (Div. 2) B. Squares
- 根据osdid 查询磁盘是ssd盘还是sas盘
- 第四章 consul cluster
- 如果在安卓后台杀死程序怎么进行保存
- 「leetcode」203.移除链表元素:听说用虚拟头节点会方便很多?
- 锐起无盘系统菜鸟教程
- 解决sese9 安装时多个屏幕
- Sniffer的使用
- 华为云学院-人人学loT学习笔记- 第三章 窄带无线,宽带互联
- 服务器u单核性能排行,CPU单核性能排行(2017年10月更新).doc
- 电话程控交换机安装注意
- opencore黑苹果教程
- 09、IO流—File类与IO流
- PHP判断来访是搜索引擎蜘蛛还是普通用户的代码小结