Skip to content

Commit

Permalink
fix mixed-precision quaternion math
Browse files Browse the repository at this point in the history
We follow the same rules as C++, e.g. float * double -> double
  • Loading branch information
pixelflinger committed Oct 16, 2023
1 parent 7c6103a commit 14263ef
Showing 1 changed file with 33 additions and 24 deletions.
57 changes: 33 additions & 24 deletions libs/math/include/math/TQuatHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,17 @@ class TQuatProductOperators {

/* compound assignment products by a scalar
*/
constexpr QUATERNION<T>& operator*=(T v) {
template<typename U>
constexpr QUATERNION<T>& operator*=(U v) {
QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
lhs[i] *= v;
}
return lhs;
}

constexpr QUATERNION<T>& operator/=(T v) {
template<typename U>
constexpr QUATERNION<T>& operator/=(U v) {
QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
lhs[i] /= v;
Expand All @@ -85,28 +87,29 @@ class TQuatProductOperators {
/* The operators below handle operation between quaternions of the same size
* but of a different element type.
*/
template<typename RT>
friend inline
constexpr QUATERNION<T> MATH_PURE operator*(const QUATERNION<T>& q, const QUATERNION<RT>& r) {
template<typename U>
friend inline constexpr
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator*(
const QUATERNION<T>& q, const QUATERNION<U>& r) {
// could be written as:
// return QUATERNION<T>(
// q.w*r.w - dot(q.xyz, r.xyz),
// q.w*r.xyz + r.w*q.xyz + cross(q.xyz, r.xyz));

return QUATERNION<T>(
return {
q.w * r.w - q.x * r.x - q.y * r.y - q.z * r.z,
q.w * r.x + q.x * r.w + q.y * r.z - q.z * r.y,
q.w * r.y - q.x * r.z + q.y * r.w + q.z * r.x,
q.w * r.z + q.x * r.y - q.y * r.x + q.z * r.w);
q.w * r.z + q.x * r.y - q.y * r.x + q.z * r.w
};
}

template<typename RT>
friend inline
constexpr TVec3<T> MATH_PURE operator*(const QUATERNION<T>& q, const TVec3<RT>& v) {
template<typename U>
friend inline constexpr
TVec3<arithmetic_result_t<T, U>> MATH_PURE operator*(const QUATERNION<T>& q, const TVec3<U>& v) {
// note: if q is known to be a unit quaternion, then this simplifies to:
// TVec3<T> t = 2 * cross(q.xyz, v)
// return v + (q.w * t) + cross(q.xyz, t)
return imaginary(q * QUATERNION<T>(v, 0) * inverse(q));
return imaginary(q * QUATERNION<U>(v, 0) * inverse(q));
}


Expand All @@ -122,20 +125,23 @@ class TQuatProductOperators {
* q.w*r.z + q.x*r.y - q.y*r.x + q.z*r.w);
*
*/
friend inline
constexpr QUATERNION<T> MATH_PURE operator*(QUATERNION<T> q, T scalar) {
template<typename U>
friend inline constexpr
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator*(QUATERNION<T> q, U scalar) {
// don't pass q by reference because we need a copy anyway
return q *= scalar;
}

friend inline
constexpr QUATERNION<T> MATH_PURE operator*(T scalar, QUATERNION<T> q) {
template<typename U>
friend inline constexpr
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator*(T scalar, QUATERNION<U> q) {
// don't pass q by reference because we need a copy anyway
return q *= scalar;
}

friend inline
constexpr QUATERNION<T> MATH_PURE operator/(QUATERNION<T> q, T scalar) {
template<typename U>
friend inline constexpr
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator/(QUATERNION<T> q, U scalar) {
// don't pass q by reference because we need a copy anyway
return q /= scalar;
}
Expand All @@ -160,9 +166,10 @@ class TQuatFunctions {
* (the first one, BASE<T> being known).
*/

template<typename RT>
friend inline
constexpr T MATH_PURE dot(const QUATERNION<T>& p, const QUATERNION<RT>& q) {
template<typename U>
friend inline constexpr
arithmetic_result_t<T, U> MATH_PURE dot(
const QUATERNION<T>& p, const QUATERNION<U>& q) {
return p.x * q.x +
p.y * q.y +
p.z * q.z +
Expand Down Expand Up @@ -196,7 +203,7 @@ class TQuatFunctions {

friend inline
constexpr QUATERNION<T> MATH_PURE inverse(const QUATERNION<T>& q) {
return conj(q) * (1 / dot(q, q));
return conj(q) * (T(1) / dot(q, q));
}

friend inline
Expand All @@ -214,8 +221,10 @@ class TQuatFunctions {
return QUATERNION<T>(q.xyz, 0);
}

friend inline
constexpr QUATERNION<T> MATH_PURE cross(const QUATERNION<T>& p, const QUATERNION<T>& q) {
template<typename U>
friend inline constexpr
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE cross(
const QUATERNION<T>& p, const QUATERNION<U>& q) {
return unreal(p * q);
}

Expand Down

0 comments on commit 14263ef

Please sign in to comment.