DirectXMath) (入门

DirectXMath 库为单精度浮点向量( (2D、3D 和 4D) 或矩阵 (3×和 4×4) )实现算术和线性代数运算的最佳可移植接口。 库对整数向量运算的一些有限支持。 图形程序在呈现和动画中广泛使用这些操作。 不支持双精度向量 (包括长、短或字节) ,仅支持有限的整数向量运算。

该库在各种 Windows 平台上可用。 由于库提供的功能以前不可用,因此此版本取代了以下库:

  • Xboxmath.h 标头提供的 Xbox 数学库
  • D3DX 9 DLL 提供的 D3DX 9 库
  • 通过 D3DX 10 DLL 提供的 D3DX 10 数学库
  • 由 DirectX SDK 和 Xbox 360 XDK 中的 xnamath.h 标头提供的 XNA 数学库

这些部分概述了入门的基础知识。

下载

DirectXMath 库包含在 Windows SDK 中。 或者,可以从 GitHub/Microsoft/DirectXMath 下载它。 此网站还包含相关示例项目。

Run-Time系统要求

DirectXMath 库在矢量操作可用时使用专用处理器指令。 为了避免程序生成“未知指令异常”错误,在使用 DirectXMath 库之前,检查通过调用 XMVerifyCPUSupport 来获得处理器支持。

以下是基本的 DirectXMath 库运行时支持要求:

  • Windows (x86/x64) 平台上的默认编译需要 SSE/SSE2 指令支持。
  • Windows RT平台上的默认符合性需要 ARM-NEON 指令支持。
  • 使用 定义的_XM_NO_INTRINSICS_ 编译只需要标准浮点操作支持。

注意

调用 XMVerifyCPUSupport 时,请先包括 <windows.h> ,然后再包括 <DirectXMath.h>。 这是库中唯一需要 windows.h <> 中任何内容的函数,因此<无需在每个使用 <DirectXMath.h> 的模块中包含 windows.h>。

 

设计概述

DirectXMath 库主要支持 C++ 编程语言。 库是使用头文件中的内联例程 DirectXMath*.inl、DirectXPackedVector.inl 和 DirectXCollision.inl 实现的。 此实现使用高性能编译器内部函数。

DirectXMath 库提供:

  • 使用 SSE/SSE2 内部函数的实现。
  • 没有内部函数的实现。
  • 使用 ARM-NEON 内部函数的实现。

由于库是使用头文件传递的,因此请使用源代码来自定义和优化自己的应用。

矩阵约定

DirectXMath 使用行主矩阵、行向量和预乘法。 手动性取决于使用哪个函数版本 (RH 与 LH) ,否则该函数适用于左手视图坐标或右手视图坐标。

为了参考,Direct3D 历来使用左手坐标系、行主矩阵、行向量和预乘法。 新式 Direct3D 对左坐标和右手坐标没有很强的要求,通常 HLSL 着色器默认使用列主矩阵。 有关详细信息,请参阅 HLSL 矩阵排序

基本用法

若要使用 DirectXMath 库函数,请包括 DirectXMath.h、DirectXPackedVector.h、DirectXColors.h 和/或 DirectXCollision.h 标头。 标头位于适用于 Windows 应用商店应用的 Windows 软件开发工具包中。

类型使用指南

XMVECTORXMMATRIX 类型是 DirectXMath 库的工作马。 每个操作都会使用或生成这些类型的数据。 使用它们是使用库的关键。 但是,由于 DirectXMath 使用 SIMD 指令集,因此这些数据类型受到许多限制。 如果要充分利用 DirectXMath 函数,请务必了解这些限制。

应将 XMVECTOR 视为 SIMD 硬件寄存器的代理,将 XMMATRIX 视为四个 SIMD 硬件寄存器的逻辑分组的代理。 这些类型经过批注,以指示它们需要 16 字节对齐才能正常工作。 当它们用作局部变量时,编译器会自动将它们正确放置在堆栈上,或者在用作全局变量时将它们放置在数据段中。 使用适当的约定,还可以将其作为参数安全传递给函数 (请参阅 调用约定 了解详细信息) 。

但是,堆中的分配更为复杂。 因此,每当使用 XMVECTORXMMATRIX 作为要从堆分配的类或结构的成员时,都需要小心。 在 Windows x64 上,所有堆分配都是 16 字节对齐的,但对于 Windows x86,它们只有 8 字节对齐。 可以通过 16 字节对齐方式从堆分配结构, (请参阅正确 对齐分配) 。 对于 C++ 程序,可以使用运算符 new/delete/new[]/delete[] 重载 (全局或特定于类的) ,以根据需要强制实施最佳对齐。

注意

作为通过重载 new/delete 直接在 C++ 类中强制对齐的替代方法,可以使用 pImpl 成语。 如果确保 Impl 类通过 内部_aligned_malloc 对齐,则可以在内部实现中自由使用对齐的类型。 当“public”类是Windows 运行时 ref 类或旨在与 std::shared_ptr<> 一起使用时,这是一个不错的选择,否则可能会中断谨慎对齐。

 

但是,通常更容易、更紧凑地避免直接在类或结构中使用 XMVECTORXMMATRIX 。 请改用 XMFLOAT3XMFLOAT4XMFLOAT4X3XMFLOAT4X4 等作为结构的成员。 此外,还可以使用 矢量加载矢量存储 函数将数据有效地移动到 XMVECTORXMMATRIX 局部变量中,执行计算并存储结果。 还有 (XMVector3TransformStreamXMVector4TransformStream 等) 流式处理函数,可对这些数据类型的数组高效运行。

创建向量

常量矢量

许多操作需要在向量计算中使用常量,并且有多种方法可以加载具有所需值的 XMVECTOR

  • 如果将标量常量加载到 XMVECTOR 的所有元素中,请使用 XMVectorReplicateXMVectorReplicateInt

    XMVECTOR vFive = XMVectorReplicate( 5.f );
    
  • 如果使用具有不同固定值的矢量常量作为 XMVECTOR,请使用 XMVECTORF32XMVECTORU32XMVECTORI32XMVECTORU8 结构。 然后,可以直接在传递 XMVECTOR 值的任何位置引用这些值。

    static const XMVECTORF32 vFactors = { 1.0f, 2.0f, 3.0f, 4.0f };
    

    注意

    请勿将初始值设定项列表直接用于 XMVECTOR (即 XMVECTOR v = { 1.0f, 2.0f, 3.0f, 4.0f }) 。 此类代码效率低下,无法在 DirectXMath 支持的所有平台上移植。

     

  • DirectXMath 包括许多可在代码 (g_XMOne、g_XMOne3、g_XMTwo、g_XMOneHalf、g_XMHalfPi、g_XMPi等) 中使用的预定义全局常量。 在 DirectXMath.h 标头中搜索 XMGLOBALCONST 值。

  • 有一组常见 RGB 颜色的向量常量 (红、绿、蓝、黄等) 。 有关这些向量常量的详细信息,请参阅 DirectXColors.h 和 DirectX::Colors 命名空间。

变量中的向量

矢量中的向量

  • 如果从另一个向量创建向量,且特定组件设置为变量,则可以考虑使用 向量访问器函数

    XMVECTOR v2 = XMVectorSetW( v1, fw );
    
  • 如果从复制了单个组件的另一个矢量创建矢量,请使用 XMVectorSplatXXMVectorSplatYXMVectorSplatZXMVectorSplatW

    XMVECTOR vz = XMVectorSplatZ( v );
    
  • 如果从另一个矢量或具有重新排序的组件对创建矢量,请参阅 XMVectorSwizzleXMVectorPermute

    XMVECTOR v2 = XMVectorSwizzle<XM_SWIZZLE_Z, XM_SWIZZLE_Y, XM_SWIZZLE_W, XM_SWIZZLE_X>( v1 );
    
    XMVECTOR v3 = XMVectorPermute<XM_PERMUTE_0W, XM_PERMUTE_1X, XM_PERMUTE_0X, XM_PERMUTE_1Z>( v1, v2 );
    

内存中的矢量

从向量中提取组件

将数据加载到 SIMD 寄存器并在提取结果之前完全处理时,SIMD 处理效率最高。 标量和矢量形式之间的转换效率低下,因此建议仅在需要时进行转换。 出于此原因,DirectXMath 库中生成标量值的函数以向量形式返回,其中标量结果在生成的向量 (即 XMVector2DotXMVector3Length 等) 。 但是,如果需要标量值,下面是一些有关如何操作的选项:

  • 如果计算单个标量答案,则适合使用 矢量访问器函数

    float f = XMVectorGetX( v );
    
  • 如果需要提取矢量的多个分量,请考虑将矢量存储在内存结构中并读回。 例如:

    XMFLOAT4A t;
    XMStoreFloat4A( &t, v );
    // t.x, t.y, t.z, and t.w can be individually accessed now
    
  • 最有效的矢量处理形式是使用内存到内存流式处理,其中输入数据从内存加载 (使用 矢量加载函数) 加载,以 SIMD 形式完全处理,然后使用 矢量存储函数) 写入内存 (。

DirectXMath 编程指南