Add more Quaternion methods for SimpleMath (#116)

This commit is contained in:
Chuck Walbourn 2022-01-19 21:58:21 -08:00 коммит произвёл GitHub
Родитель 0a267e7afe
Коммит 5013cab0b8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 137 добавлений и 4 удалений

Просмотреть файл

@ -713,6 +713,9 @@ namespace DirectX
float Dot(const Quaternion& Q) const noexcept;
void RotateTowards(const Quaternion& target, float maxAngle) noexcept;
void __cdecl RotateTowards(const Quaternion& target, float maxAngle, Quaternion& result) const noexcept;
// Computes rotation about y-axis (y), then x-axis (x), then z-axis (z)
Vector3 ToEuler() const noexcept;
@ -736,6 +739,14 @@ namespace DirectX
static void Concatenate(const Quaternion& q1, const Quaternion& q2, Quaternion& result) noexcept;
static Quaternion Concatenate(const Quaternion& q1, const Quaternion& q2) noexcept;
static void __cdecl FromToRotation(const Vector3& fromDir, const Vector3& toDir, Quaternion& result) noexcept;
static Quaternion FromToRotation(const Vector3& fromDir, const Vector3& toDir) noexcept;
static void __cdecl LookRotation(const Vector3& forward, const Vector3& up, Quaternion& result) noexcept;
static Quaternion LookRotation(const Vector3& forward, const Vector3& up) noexcept;
static float Angle(const Quaternion& q1, const Quaternion& q2) noexcept;
// Constants
static const Quaternion Identity;
};
@ -762,11 +773,11 @@ namespace DirectX
Color(const XMFLOAT4& c) noexcept { this->x = c.x; this->y = c.y; this->z = c.z; this->w = c.w; }
explicit Color(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; this->z = F.f[2]; this->w = F.f[3]; }
// BGRA Direct3D 9 D3DCOLOR packed color
explicit Color(const DirectX::PackedVector::XMCOLOR& Packed) noexcept;
// BGRA Direct3D 9 D3DCOLOR packed color
// RGBA XNA Game Studio packed color
explicit Color(const DirectX::PackedVector::XMUBYTEN4& Packed) noexcept;
// RGBA XNA Game Studio packed color
Color(const Color&) = default;
Color& operator=(const Color&) = default;

Просмотреть файл

@ -3115,6 +3115,11 @@ inline float Quaternion::Dot(const Quaternion& q) const noexcept
return XMVectorGetX(XMQuaternionDot(q1, q2));
}
inline void Quaternion::RotateTowards(const Quaternion& target, float maxAngle) noexcept
{
RotateTowards(target, maxAngle, *this);
}
inline Vector3 Quaternion::ToEuler() const noexcept
{
float xx = x * x;
@ -3273,6 +3278,34 @@ inline Quaternion Quaternion::Concatenate(const Quaternion& q1, const Quaternion
return result;
}
inline Quaternion Quaternion::FromToRotation(const Vector3& fromDir, const Vector3& toDir) noexcept
{
Quaternion result;
FromToRotation(fromDir, toDir, result);
return result;
}
inline Quaternion Quaternion::LookRotation(const Vector3& forward, const Vector3& up) noexcept
{
Quaternion result;
LookRotation(forward, up, result);
return result;
}
inline float Quaternion::Angle(const Quaternion& q1, const Quaternion& q2) noexcept
{
using namespace DirectX;
XMVECTOR Q0 = XMLoadFloat4(&q1);
XMVECTOR Q1 = XMLoadFloat4(&q2);
// We can use the conjugate here instead of inverse assuming q1 & q2 are normalized.
XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(Q0), Q1);
float rs = XMVectorGetW(R);
R = XMVector3Length(R);
return 2.f * atan2f(XMVectorGetX(R), rs);
}
/****************************************************************************
*

Просмотреть файл

@ -54,8 +54,97 @@ namespace DirectX
}
}
using namespace DirectX;
using namespace DirectX::SimpleMath;
/****************************************************************************
*
* Quaternion
*
****************************************************************************/
void Quaternion::RotateTowards(const Quaternion& target, float maxAngle, Quaternion& result) const noexcept
{
XMVECTOR T = XMLoadFloat4(this);
// We can use the conjugate here instead of inverse assuming q1 & q2 are normalized.
XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(T), target);
float rs = XMVectorGetW(R);
XMVECTOR L = XMVector3Length(R);
float angle = 2.f * atan2f(XMVectorGetX(L), rs);
if (angle > maxAngle)
{
XMVECTOR delta = XMQuaternionRotationAxis(R, maxAngle);
XMVECTOR Q = XMQuaternionMultiply(delta, T);
XMStoreFloat4(&result, Q);
}
else
{
// Don't overshoot.
result = target;
}
}
void Quaternion::FromToRotation(const Vector3& fromDir, const Vector3& toDir, Quaternion& result) noexcept
{
// Melax, "The Shortest Arc Quaternion", Game Programming Gems, Charles River Media (2000).
XMVECTOR F = XMVector3Normalize(fromDir);
XMVECTOR T = XMVector3Normalize(toDir);
float dot = XMVectorGetX(XMVector3Dot(F, T));
if (dot >= 1.f)
{
result = Identity;
}
else if (dot <= -1.f)
{
XMVECTOR axis = XMVector3Cross(F, Vector3::Right);
if (XMVector3NearEqual(XMVector3LengthSq(axis), g_XMZero, g_XMEpsilon))
{
axis = XMVector3Cross(F, Vector3::Up);
}
XMVECTOR Q = XMQuaternionRotationAxis(axis, XM_PI);
XMStoreFloat4(&result, Q);
}
else
{
XMVECTOR C = XMVector3Cross(F, T);
XMStoreFloat4(&result, C);
float s = sqrtf((1.f + dot) * 2.f);
result.x /= s;
result.y /= s;
result.z /= s;
result.w = s * 0.5f;
}
}
void Quaternion::LookRotation(const Vector3& forward, const Vector3& up, Quaternion& result) noexcept
{
Quaternion q1;
FromToRotation(Vector3::Forward, forward, q1);
XMVECTOR C = XMVector3Cross(forward, up);
if (XMVector3NearEqual(XMVector3LengthSq(C), g_XMZero, g_XMEpsilon))
{
// forward and up are co-linear
result = q1;
return;
}
XMVECTOR U = XMQuaternionMultiply(q1, Vector3::Up);
Quaternion q2;
FromToRotation(U, up, q2);
XMStoreFloat4(&result, XMQuaternionMultiply(q2, q1));
}
/****************************************************************************
*
* Viewport
*
@ -82,7 +171,7 @@ static_assert(offsetof(DirectX::SimpleMath::Viewport, maxDepth) == offsetof(D3D1
#endif
#if defined(__dxgi1_2_h__) || defined(__d3d11_x_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)
RECT DirectX::SimpleMath::Viewport::ComputeDisplayArea(DXGI_SCALING scaling, UINT backBufferWidth, UINT backBufferHeight, int outputWidth, int outputHeight) noexcept
RECT Viewport::ComputeDisplayArea(DXGI_SCALING scaling, UINT backBufferWidth, UINT backBufferHeight, int outputWidth, int outputHeight) noexcept
{
RECT rct = {};
@ -143,7 +232,7 @@ RECT DirectX::SimpleMath::Viewport::ComputeDisplayArea(DXGI_SCALING scaling, UIN
}
#endif
RECT DirectX::SimpleMath::Viewport::ComputeTitleSafeArea(UINT backBufferWidth, UINT backBufferHeight) noexcept
RECT Viewport::ComputeTitleSafeArea(UINT backBufferWidth, UINT backBufferHeight) noexcept
{
float safew = (float(backBufferWidth) + 19.f) / 20.f;
float safeh = (float(backBufferHeight) + 19.f) / 20.f;