typedef Vector3 Point;
// 向量类的实现
template<typename T>
struct Vector3
{
// 向量类的构造函数
Vector3<T>() :x(0), y(0), z(0) {}
Vector3<T>(T _x, T _y, T _z) : x(_x), y(_y), z(_z) {}
// 向量和常数的乘除法:向量的每个分量和常数相乘除。
Vector3<T> operator*(const T value)const
{
return Vector3<T>(this->x * value, this->y * value, this->z * value);
}
Vector3<T> operator/(const T value)const
{
return Vector3<T>(this->x / value, this->y / value, this->z / value);
}
// 向量间加减法:向量的每个分量彼此相加减。
Vector3<T> operator+(const Vector3<T>& vect)const
{
return Vector3<T>(this->x + vect.x, this->y + vect.y, this->z + vect.z);
}
Vector3<T> operator-(const Vector3<T>& vect)const
{
return Vector3<T>(this->x - vect.x, this->y - vect.y, this->z - vect.z);
}
// 向量间点乘:向量的每个分量相乘再相加。
T Dot(const Vector3<T>& vect)const
{
return (this->x * vect.x + this->y * vect.y + this->z * vect.z);
}
// 向量间叉乘:根据叉乘公式。
T Cross(const Vector3<T>& vect)const
{
return (
this->y * vect.z - this->z * vect.y,
this->z * vect.x - this->x * vect.z,
this->x * vect.y - this->y * vect.x);
}
// 向量的长度:向量各分量平方再开根。
T getLength()const
{
return sqrt(this->x * this->x + this->y * this->y + this->z * this.z);
}
// 向量的单位向量:向量各分量除以向量的长度。
Vector3<T> getNormalizeVect()const
{
T length = getLength();
return (*this) / T;
}
// 向量的正交化:向量自身减去在对方上的投影。
void orthogonal(Vector3<T> vect)const
{
*this = (*this) - (*this).Cross(vect) * vect / vect.getLength() / vect.getLength();
// 设有向量A和B,其长度分别为||A||和||B||,其对应单位向量为nA和nB,它们间夹角为ct
// A点乘B = ||A|| * ||B|| * cos(ct)
// A在B上的投影 = ||A|| * nB * cos(ct)
// = ||A|| * B / ||B|| * cos(ct)
// = A点乘B * B / ||B|| / ||B||
}
union
{
T data[3];
T x, y, z;
};
};
SIMD寄存器位数 | 对应变量类型 |
---|---|
128 | __m128 |
256 | __m256 |
512 | __m512 |
using XMVECTOR = __m128;
struct XMFLOAT3
{
float x;
float y;
float z;
XMFLOAT3() = default;
XMFLOAT3(const XMFLOAT3&) = default;
XMFLOAT3& operator=(const XMFLOAT3&) = default;
XMFLOAT3(XMFLOAT3&&) = default;
XMFLOAT3& operator=(XMFLOAT3&&) = default;
constexpr XMFLOAT3(float _x, float _y, float _z) noexcept : x(_x), y(_y), z(_z) {}
explicit XMFLOAT3(_In_reads_(3) const float* pArray) noexcept : x(pArray[0]), y(pArray[1]), z(pArray[2]) {}
};
#define _CRT_SECURE_NO_WARNINGS // 重定向输入输出(否则默认是没有控制台窗口,你也就看不到输出了,此宏必须写在头文件引用之前!)
#include // Windows API编程所需头文件
#include // DirectXMath库
#include
// Windows API编程的main函数为WinMain,照着写就是了
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
PSTR cmdLine, int showCmd)
{
// 这三行代码启动一个控制台,让你的cou和cin绑定控制台
AllocConsole();
freopen("CONOUT$", "w", stdout);
freopen("CONIN$", "r", stdin);
// 定义一个XMVECTOR实例试试
DirectX::XMVECTOR xmvector;
// 由于XMVECTOR即__m128为128位寄存器,所以可以按照不同方式解析数据
// .m128_f32表示将其解析为:存储32位浮点数的数组,然后按照[index]的形式索引即可得到分量xyzw
for (int i = 0; i < 4; i++)
std::cout << xmvector.m128_f32[i] << std::endl;
// 分别定义XMFLAOTn类型
DirectX::XMFLOAT2 xmfloat2;
DirectX::XMFLOAT4 xmflaot4 = DirectX::XMFLOAT4();
xmfloat2.x = 1;
std::cout << xmfloat2.x << std::endl;
std::cout << xmflaot4.x << " " << xmflaot4.y << " " << xmflaot4.z << " " << xmflaot4.w;
while (1); // 阻止程序终止导致控制台关闭无法看到输出信息
return 0;
}
inline XMVECTOR XM_CALLCONV XMLoadFloat2(const XMFLOAT2* pSource) noexcept
{
assert(pSource);
#if defined(_XM_NO_INTRINSICS_)
XMVECTOR V;
V.vector4_f32[0] = pSource->x;
V.vector4_f32[1] = pSource->y;
V.vector4_f32[2] = 0.f;
V.vector4_f32[3] = 0.f;
return V;
#elif defined(_XM_ARM_NEON_INTRINSICS_)
float32x2_t x = vld1_f32(reinterpret_cast<const float*>(pSource));
float32x2_t zero = vdup_n_f32(0);
return vcombine_f32(x, zero);
#elif defined(_XM_SSE_INTRINSICS_)
return _mm_castpd_ps(_mm_load_sd(reinterpret_cast<const double*>(pSource)));
#endif
}
可以看到将XMFLOATn转换为XMVECTOR的函数很简单,名为:XMLoadFloatn,参数传入XMFLOATn实例的地址即可。细看函数内部,是通过使用 _mm_castpd_ps 函数实现的类型转换,这函数是SIMD提供的函数。可知DirectXMath不过也只是对SIMD库进行了再一次封装而已。
实例代码:
#define _CRT_SECURE_NO_WARNINGS // 重定向输入输出(否则默认是没有控制台窗口,你也就看不到输出了,此宏必须写在头文件引用之前!)
#include // Windows API编程所需头文件
#include // DirectXMath库
#include
// Windows API编程的main函数为WinMain,照着写就是了
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
PSTR cmdLine, int showCmd)
{
// 这三行代码启动一个控制台,让你的cou和cin绑定控制台
AllocConsole();
freopen("CONOUT$", "w", stdout);
freopen("CONIN$", "r", stdin);
using namespace DirectX;
XMVECTOR xmvector;
XMFLOAT2 xmfloat2;
XMFLOAT3 xmfloat3;
XMFLOAT4 xmfloat4;
// 将XMFLOATn转换为XMVECTOR
xmvector = XMLoadFloat2(&xmfloat2);
xmvector = XMLoadFloat3(&xmfloat3);
xmvector = XMLoadFloat4(&xmfloat4);
while (1); // 阻止程序终止导致控制台关闭无法看到输出信息
return 0;
}
inline void XM_CALLCONV XMStoreFloat2
(
XMFLOAT2* pDestination,
FXMVECTOR V
) noexcept
{
assert(pDestination);
#if defined(_XM_NO_INTRINSICS_)
pDestination->x = V.vector4_f32[0];
pDestination->y = V.vector4_f32[1];
#elif defined(_XM_ARM_NEON_INTRINSICS_)
float32x2_t VL = vget_low_f32(V);
vst1_f32(reinterpret_cast<float*>(pDestination), VL);
#elif defined(_XM_SSE_INTRINSICS_)
_mm_store_sd(reinterpret_cast<double*>(pDestination), _mm_castps_pd(V));
#endif
}
typedef const XMVECTOR FXMVECTOR;
#define _CRT_SECURE_NO_WARNINGS // 重定向输入输出(否则默认是没有控制台窗口,你也就看不到输出了,此宏必须写在头文件引用之前!)
#include // Windows API编程所需头文件
#include // DirectXMath库
#include
// Windows API编程的main函数为WinMain,照着写就是了
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
PSTR cmdLine, int showCmd)
{
// 这三行代码启动一个控制台,让你的cou和cin绑定控制台
AllocConsole();
freopen("CONOUT$", "w", stdout);
freopen("CONIN$", "r", stdin);
using namespace DirectX;
XMVECTOR xmvector = XMVECTOR(); // 试试不显示初始化XMVECTOR会怎么样
XMFLOAT2 xmfloat2 = XMFLOAT2(1,2);
XMFLOAT3 xmfloat3;
XMFLOAT4 xmfloat4;
XMStoreFloat2(&xmfloat2, xmvector);
std::cout << xmvector.m128_f32[0] << " " << xmvector.m128_f32[1];
XMStoreFloat3(&xmfloat3, xmvector);
XMStoreFloat4(&xmfloat4, xmvector);
while (1); // 阻止程序终止导致控制台关闭无法看到输出信息
return 0;
}
inline float XM_CALLCONV XMVectorGetX(FXMVECTOR V) noexcept
{
#if defined(_XM_NO_INTRINSICS_)
return V.vector4_f32[0];
#elif defined(_XM_ARM_NEON_INTRINSICS_)
return vgetq_lane_f32(V, 0);
#elif defined(_XM_SSE_INTRINSICS_)
return _mm_cvtss_f32(V);
#endif
}
inline XMVECTOR XM_CALLCONV XMVectorSetX(FXMVECTOR V, float x) noexcept
{
#if defined(_XM_NO_INTRINSICS_)
XMVECTORF32 U = { { {
x,
V.vector4_f32[1],
V.vector4_f32[2],
V.vector4_f32[3]
} } };
return U.v;
#elif defined(_XM_ARM_NEON_INTRINSICS_)
return vsetq_lane_f32(x, V, 0);
#elif defined(_XM_SSE_INTRINSICS_)
XMVECTOR vResult = _mm_set_ss(x);
vResult = _mm_move_ss(V, vResult);
return vResult;
#endif
}
#define _CRT_SECURE_NO_WARNINGS // 重定向输入输出(否则默认是没有控制台窗口,你也就看不到输出了,此宏必须写在头文件引用之前!)
#include // Windows API编程所需头文件
#include // DirectXMath库
#include
// Windows API编程的main函数为WinMain,照着写就是了
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
PSTR cmdLine, int showCmd)
{
// 这三行代码启动一个控制台,让你的cou和cin绑定控制台
AllocConsole();
freopen("CONOUT$", "w", stdout);
freopen("CONIN$", "r", stdin);
using namespace DirectX;
// 获取XMVECTOR的分量
XMVECTOR xmvector1 = XMVECTOR();
std::cout << XMVectorGetX(xmvector1) <<" "
<< XMVectorGetY(xmvector1) <<" "
<< XMVectorGetZ(xmvector1) << std::endl;
// 设置XMVECTOR的分量
XMVECTOR xmvector2 = XMVectorSetX(xmvector1, 1);
std::cout << XMVectorGetX(xmvector2) << std::endl;
while (1); // 阻止程序终止导致控制台关闭无法看到输出信息
return 0;
}
ResType XM_CALLCONV 函数名 (参数列表...)
{
函数体
}