Skip to content

Commit

Permalink
Actually use quaternions for CSolidObject::UpdateDirVectors() and CSo…
Browse files Browse the repository at this point in the history
…lidObject::SetHeadingFromDirection()
  • Loading branch information
lhog committed Feb 9, 2025
1 parent 1d05355 commit ee8fa9b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 28 deletions.
38 changes: 11 additions & 27 deletions rts/Sim/Objects/SolidObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Sim/MoveTypes/MoveDefHandler.h"
#include "Game/GameHelper.h"
#include "System/SpringMath.h"
#include "System/Quaternion.h"

#include "System/Misc/TracyDefs.h"

Expand Down Expand Up @@ -380,14 +381,11 @@ void CSolidObject::SetHeadingFromDirection() {
// undo UpdateDirVectors transformation

// construct quaternion to describe rotation from uDir to UpVector
float4 quat{ -updir.z, 0.0f, updir.x, 1.0f + updir.y }; // same angle as in UpdateDirVectors, but inverted axis
float qN = quat.SqLength() + quat.w * quat.w;
quat *= math::isqrt(qN);
CQuaternion quat(-updir.z, 0.0f, updir.x, 1.0f + updir.y); // same angle as in UpdateDirVectors, but inverted axis
quat.ANormalize();

const float3 fDir =
2.0f * quat.dot(frontdir) * static_cast<float3>(quat) +
(quat.w * quat.w - quat.dot(quat)) * frontdir +
2.0f * quat.w * quat.cross(frontdir);
const float3 fDir = quat * frontdir;
assert(epscmp(fDir.y, 0.0f, float3::cmp_eps()));

heading = GetHeadingFromVector(fDir.x, fDir.z);
}
Expand All @@ -408,27 +406,13 @@ void CSolidObject::UpdateDirVectors(const float3& uDir)
const float3 rDir = float3{ -fDir.z, 0.0f, fDir.x };

// construct quaternion to describe rotation from UpVector to uDir
// can use CQuaternion::MakeFrom(const float3& v1, const float3& v2);
// but simplified given UpVector is trivial
CQuaternion quat(uDir.z, 0.0f, -uDir.x, 1.0f + uDir.y);
quat.ANormalize();

// https://raw.org/proof/quaternion-from-two-vectors/
// const float dp = UpVector.dot(uDir);
// const float3 axis = UpVector.cross(uDir);
// float4 quat { axis, 1.0f + dp };

// same as above, but simplified given UpVector is trivial
float4 quat{ uDir.z, 0.0f, -uDir.x, 1.0f + uDir.y };
float qN = quat.SqLength() + quat.w * quat.w;
quat *= math::isqrt(qN);

frontdir =
2.0f * quat.dot(fDir) * static_cast<float3>(quat) +
(quat.w * quat.w - quat.dot(quat)) * fDir +
2.0f * quat.w * quat.cross(fDir);

rightdir =
2.0f * quat.dot(rDir) * static_cast<float3>(quat) +
(quat.w * quat.w - quat.dot(quat)) * rDir +
2.0f * quat.w * quat.cross(rDir);

frontdir = quat * fDir;
rightdir = quat * rDir;
updir = uDir;
}

Expand Down
28 changes: 27 additions & 1 deletion rts/System/Quaternion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,18 @@ CQuaternion& CQuaternion::Normalize()
if unlikely(sqn < float3::nrm_eps())
return *this;

*this *= InvSqrt(sqn);
*this /= math::sqrt(sqn);

return *this;
}

CQuaternion& CQuaternion::ANormalize()
{
const float sqn = SqNorm();
if unlikely(sqn < float3::nrm_eps())
return *this;

*this *= math::isqrt(sqn);

return *this;
}
Expand Down Expand Up @@ -387,6 +398,21 @@ CQuaternion& CQuaternion::operator*=(float f)
return *this;
}

CQuaternion& CQuaternion::operator/=(float f)
{
if unlikely(epscmp(f, 0.0f, float3::cmp_eps()))
return *this;

f = 1.0f / f;

x *= f;
y *= f;
z *= f;
r *= f;

return *this;
}

float CQuaternion::SqNorm() const {
return (x * x + y * y + z * z + r * r);
}
Expand Down
9 changes: 9 additions & 0 deletions rts/System/Quaternion.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class alignas(16) CQuaternion
public:
bool Normalized() const;
CQuaternion& Normalize();
CQuaternion& ANormalize();
constexpr CQuaternion& Conjugate() { x = -x; y = -y; z = -z; return *this; }
CQuaternion Inverse() const;
CQuaternion& InverseInPlace();
Expand Down Expand Up @@ -94,8 +95,16 @@ class alignas(16) CQuaternion
return CQuaternion(x - rhs.x, y - rhs.y, z - rhs.z, r - rhs.r);
}

float3 operator*(const float3& arg) const {
return Rotate(arg);
}
float4 operator*(const float4& arg) const {
return Rotate(arg);
}

CQuaternion operator*(const CQuaternion& rhs) const;
CQuaternion& operator*=(float f);
CQuaternion& operator/=(float f);

bool operator==(const CQuaternion& rhs) const { return equals(rhs); } //aproximate
bool operator!=(const CQuaternion& rhs) const { return !equals(rhs); } //aproximate
Expand Down

0 comments on commit ee8fa9b

Please sign in to comment.