《dx12 龙书》第一部分学习笔记(二)

1、DirectXMath库的向量运算:
(1)向量类型:
 核心向量类型为XMVECTOR,它将映射到SIMD硬件寄存器。
 typedef __m128 XMVECTOR;
 这里的__m128是一种特殊的SIMD类型。
 XMVECTOR类型的数据需要按16字节对齐,这对与局部变量和全局变量而言都是自动实现的。
 类中的数据成员,建议分别使用XMFLOAT2、XMFLOAT3、XMFLOAT4类型来加以代替。
 为了充分发挥出SIMD技术的高效特性,我们还需要将这些类型的实例转换为XMVECTOR类型。转换的过程可以通过DirectXMath库的加载函数(loading function)实现。相反地,DirectXMath库也提供了用来将XMVECTOR类型转换为XMFLOATn类型的存储函数(storage function)。
 小结:
  a.局部变量或全局变量用XMVECTOR类型。
  b.对于类中的数据成员,使用XMFLOAT2、XMFLOAT3、XMFLOAT4类型。
  c.在运算之前,通过加载函数将XMFLOATn类型转换为XMVECTOR类型。
  d.用XMVECTOR实例来进行运算。
  e.通过存储函数将XMVECTOR类型转换为XMFLOATn类型。
2、加载和存储方法:

#include <iostream>
#include <DirectXMath.h>
#include <DirectXPackedVector.h>

int main()
{
    typedef __m128 XMVECTOR;
    typedef const XMVECTOR FXMVECTOR;

    //通过下列方法将数据从XMFLOATn类型加载到XMVECTOR类型中
    //将数据从XMFLOAT2类型中加载到XMVECTOR类型
    XMVECTOR XM_CALLCONV XMFLoadFloat2(const XMFLOAT2 *pSource);
    //将数据从XMFLOAT3类型中加载到XMVECTOR类型
    XMVECTOR XM_CALLCONV XMFLoadFloat3(const XMFLOAT3 *pSource);
    //将数据从XMFLOAT4类型中加载到XMVECTOR类型
    XMVECTOR XM_CALLCONV XMFLoadFloat4(const XMFLOAT4 *pSource);

    //通过下列方法将数据从XMVECTOR类型加载到XMFLOATn类型中
    //将数据从XMVECTOR类型中加载到XMFLOAT2类型
    void XM_CALLCONV XMStoreFloat2(XMFLOAT2 *pDestination, FXMVECTOR V);
	//将数据从XMVECTOR类型中加载到XMFLOAT3类型
	void XM_CALLCONV XMStoreFloat3(XMFLOAT3 * pDestination, FXMVECTOR V);
	//将数据从XMVECTOR类型中加载到XMFLOAT4类型
	void XM_CALLCONV XMStoreFloat4(XMFLOAT4 * 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);
}

struct XMFLOAT2
{
	float x;
	float y;
	
	XMFLOAT2() {}
	XMFLOAT2(float _x, float _y) : x(_x), y(_y) {}
	explicit XMFLOAT2(_In_reads_(2) const float *pArray) : x(pArray[0]), y(pArray[1]) {}
		
	XMFLOAT2& operator= (const XMFLOAT2& Float2) { x = Float2.x; y = Float2.y; return *this; }
};
 
struct XMFLOAT3
{
	float x;
	float y;
	float z;
	
	XMFLOAT3() {}
	XMFLOAT3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
	explicit XMFLOAT3(_In_reads_(3) const float *pArray) : x(pArray[0]), y(pArray[1]), z(pArray[2]) {}
	
	XMFLOAT3& operator= (const XMFLOAT3& Float3) { x = Float3.x; y = Float3.y; z = Float3.z; return *this; }
};
 
struct XMFLOAT4
{
	float x;
	float y;
	float z;
	float w;
	
	XMFLOAT4() {}
	XMFLOAT4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) {}
	explicit XMFLOAT4(_In_reads_(4) const float *pArray) : x(pArray[0]), y(pArray[1]), z(pArray[2]), w(pArray[3]) {}
	
	XMFLOAT4& operator= (const XMFLOAT4& Float4) { x = Float4.x; y = Float4.y; z = Float4.z; w = Float4.w; return *this; }
};

正常开发中可使用using namespace DirectX;对常量数据类型进行创建

3、参数的传递:
 为了提高效率,可以将XMVECTOR类型的值作为函数的参数,直接传送至SSE/SSE2寄存器里,而不存于栈内。
 以此方式传递的参数取决于用户使用的平台和编译器。因此,为了是代码更具通用性,不受具体平台、编译器的影响,将利用FXMVECTOR、GXMVECTOR、HXMVECTOR、CXMVECTOR类型来传递XMVECTOR类型的参数。
 一定要把调用约定注解XM_CALLCONV加载函数名之前。
 XMVECTOR传递参数规则:
  a.前3个XMVECTOR参数应当用类型FXMVECTOR;
  b.第4个XMVECTOR参数应当用类型GXMVECTOR;
  c.第5、6个XMVECTOR参数应当用类型HXMVECTOR;
  d.其余的XMVECTOR参数应当用类型CXMVECTOR;
此处贴出当前官方文档对应个数:
最新官方个数注意:
 对于构造函数不要使用XM_CALLCONV
 由于__vectorcall的限制,建议不要对 C++ 构造函数使用 GXMVECTOR 或 HXMVECTOR 。 只需对前三个 XMVECTOR 值使用 FXMVECTOR,然后对其余值使用 CXMVECTOR。
在XMVECTOR类型的参数之间,我们也可以掺杂其他非XMVECTOR类型的参数。此时XMVECTOR参数的规则依然适用,在统计XMVECTOR参数个数的时候会忽略其他类型的参数。
传递XMVECTOR参数的规则仅适用于“输入”参数。“输出”的XMVECTOR参数(即XMVECTOR&或XMVECTOR*)则不会占用SSE/SSE2寄存器,所以它们的处理方式与非XMVECTOR类型的参数一样。

猜你喜欢

转载自blog.csdn.net/weixin_47819574/article/details/126727014