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。基本的使用规则是:

  1. 前三个XMVECTOR参数使用FXMVECTOR
  2. 第四个XMVECTOR参数使用GXMVECTOR
  3. 第五六个XMVECTOR参数使用HXMVECTOR
  4. 其他使用CXMVECTOR

而宏XM_CALLCONV,就是用于告诉编译器该函数调用时,有这种特别的参数传递规则。

所以会看到这样的定义:

void XM_CALLCONV XMStoreFloat2(XMFLOAT2 *pDestination, FXMVECTOR V); 

但是,这些规则在构造函数中并不适用。在构造函数中:

  1. 前三个XMVECTOR参数使用FXMVECTOR
  2. 其他使用CXMVECTOR
  3. 不要使用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相关推荐

  1. Python库之math库

    math库的学习 math库的简介 4个数学常数 44个函数 16个数值表示函数 函数简介 部分实例 8个幂对数函数 函数简介 部分实例 16个三角对数函数 函数简介 4个高等特殊函数 函数简介 ma ...

  2. python中math库_Python库详解之math库

    1 首先我们看下定义的Number-theoretic and representation functions. 1:ceil(x):功能:返回一个浮点数据,该数据向上取整. 2:copysign( ...

  3. python中求和公式是什么函数_Python的math库中,用于求和的函数是( )。

    [单选题]确定兴利库容 V 兴 ,已知某水库为一回运用水库,其一次蓄水量为 V 1 =300 万 m 3 ,一次供水量为 V 2 =150 万 m 3 . [ ]. [单选题]hAB大于0说明B点的高 ...

  4. C++标准库vector及迭代器

    vector是同一种对象的集合,每个对象都有一个对应的整数索引值.和string对象一样,标准库将负责管理与存储元素相关的类存.引入头文件 #include<vector> 1.vecto ...

  5. python math库 sqrt eval_Python 在线基础课程

    注释的两种方法: 单行注释以#开头 #Here are the comments 多行注释以'''开头和结尾 赋值操作 可以多赋值 比如交换x,y的值 x,y=y,x 输入函数 Input()函 ...

  6. python怎么导入math库_Python math数学库的用法

    对于基本的加.减.乘.除等运算,不用引入任何库就可以完成.但是如果要进行求正弦值.求平方根等运算,便需要使用数学库 math. math 库通过下面语句引入: import math 该库包含常用的常 ...

  7. math库是python语言的数学模块吗_math库是python语言的数学模块。

    [单选题]for i in range(10): ...... 中 ,i的循环终值是 (). [简答题]人生观的主要内容 [填空题]下面程序的运行结果是( ). b, c=2, 4 def g_fun ...

  8. python math库常用函数_Python math库常用函数

    math库常用函数及举例: 注意:使用math库前,用import导入该库 >>> import math 取大于等于x的最小的整数值,如果x是一个整数,则返回x >>& ...

  9. 【 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,' ...

  10. c++ 使用 math库笔记

    目录 win10系统 cmakelist.txt linux gcc方式 c++使用pi win10系统 这个头文件在visual studio的 sdk中 引用方法: #include<mat ...

最新文章

  1. 第十五届全国大学生智能汽车竞赛人工智能创意赛
  2. Python包的相对导入时出现问题解决
  3. sublime 正则搜索日语字符
  4. Nginx 运维之域名验证
  5. linux c mysql 增删改查_Linux C语言连接MySQL 增删改查操作
  6. tflite C++ API 部署分类模型
  7. Codeforces Round #161 (Div. 2) B. Squares
  8. 根据osdid 查询磁盘是ssd盘还是sas盘
  9. 第四章 consul cluster
  10. 如果在安卓后台杀死程序怎么进行保存
  11. 「leetcode」203.移除链表元素:听说用虚拟头节点会方便很多?
  12. 锐起无盘系统菜鸟教程
  13. 解决sese9 安装时多个屏幕
  14. Sniffer的使用
  15. 华为云学院-人人学loT学习笔记- 第三章 窄带无线,宽带互联
  16. 服务器u单核性能排行,CPU单核性能排行(2017年10月更新).doc
  17. 电话程控交换机安装注意
  18. opencore黑苹果教程
  19. 09、IO流—File类与IO流
  20. PHP判断来访是搜索引擎蜘蛛还是普通用户的代码小结

热门文章

  1. 系统管理、系统安全命令
  2. 饱食沪深港澳22日-港:星级传统韩菜-梨花园~110207
  3. mysql 复制frm_如何通过直接复制frm文件以实现恢复/复制innodb数据表
  4. LeetCode:三数之和
  5. 间断点怎么求?——6个例子来详细解析较难的间断点的求法
  6. ubuntu 16.04安装网易云音乐,没声音?
  7. java基础,进阶(二)
  8. shio世硕AI智慧指读学习机加入智能教育硬件新战场【无标题】
  9. 安卓权限工具类(二)
  10. mac 查看端口使用情况