JPL Spatial
Sound spatialization and propagation library
Loading...
Searching...
No Matches
MinimalBasis.h
Go to the documentation of this file.
1//
2// ██╗██████╗ ██╗ ██╗██████╗ ███████╗
3// ██║██╔══██╗ ██║ ██║██╔══██╗██╔════╝ ** JPLSpatial **
4// ██║██████╔╝ ██║ ██║██████╔╝███████╗
5// ██ ██║██╔═══╝ ██║ ██║██╔══██╗╚════██║ https://github.com/Jaytheway/JPLSpatial
6// ╚█████╔╝██║ ███████╗██║██████╔╝███████║
7// ╚════╝ ╚═╝ ╚══════╝╚═╝╚═════╝ ╚══════╝
8//
9// Copyright 2024 Jaroslav Pevno, JPLSpatial is offered under the terms of the ISC license:
10//
11// Permission to use, copy, modify, and/or distribute this software for any purpose with or
12// without fee is hereby granted, provided that the above copyright notice and this permission
13// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
14// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
16// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
17// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#pragma once
21
22#include "JPLSpatial/Core.h"
27
28#include <cmath>
29
30namespace JPL
31{
33 template<CVec3 Vec3>
34 struct Basis
35 {
37
38 Vec3 X, Y, Z;
39
40 [[nodiscard]] static const Basis& Identity() noexcept
41 {
42 static constexpr Basis sIdentity(
43 Vec3{ Float(1), Float(0), Float(0) },
44 Vec3{ Float(0), Float(1), Float(0) },
45 Vec3{ Float(0), Float(0), Float(1) }
46 );
47 return sIdentity;
48 }
49
52 [[nodiscard]] JPL_INLINE static Basis FromForward(const Vec3& forward) noexcept
53 {
54 Basis basis{ .Z = forward };
55 Math::CreateOrthonormalBasis(forward, basis.X, basis.Y);
56 return basis;
57 }
58
60 [[nodiscard]] inline static Basis FromUpAndForward(const Vec3& up, const Vec3& forward) noexcept
61 {
62 Vec3 Y = up;
63 const Vec3 Z = forward;
64 if (Math::IsNearlyEqual(Math::Abs<Float>(DotProduct(Y, Z)), Float(1.0)))
65 Y = (Math::Abs(GetZ(Z)) < Float(0.999) ? Vec3(0, 0, 1) : Vec3(1, 0, 0));
66
67 const Vec3 X = Normalized(CrossProduct(Y, Z));
68 Y = CrossProduct(Z, X);
69
70 return Basis{ X, Y, Z };
71 }
72
78 [[nodiscard]] inline static Basis Rotation(const Vec3& axis, Float angleRad) noexcept
79 {
80 const auto [s, c] = Math::SinCos(angleRad);
81 const Float t = Float(1) - c;
82
83 const Vec3 taxyz = t * axis;
84 const Vec3 sAxis = s * axis;
85
86 // Outer-product columns: (a ⊗ a) columns are ax*a, ay*a, az*a
87 const Vec3 t_ax_a = axis * taxyz.X;
88 const Vec3 t_ay_a = axis * taxyz.Y;
89 const Vec3 t_az_a = axis * taxyz.Z;
90
91 return Basis{
92 .X = t_ax_a + Vec3{ c, sAxis.Z, -sAxis.Y },
93 .Y = t_ay_a + Vec3{ -sAxis.Z, c, sAxis.X },
94 .Z = t_az_a + Vec3{ sAxis.Y, -sAxis.X, c }
95 };
96 }
97
99 [[nodiscard]] JPL_INLINE Vec3 InverseTransform(const Vec3& pWorld) const noexcept
100 {
101 return Vec3{
102 DotProduct(pWorld, X), // component along local X
103 DotProduct(pWorld, Y), // along local Y
104 DotProduct(pWorld, Z) // along local Z
105 };
106 }
107
109 [[nodiscard]] JPL_INLINE Vec3 Transform(const Vec3& vector) const noexcept
110 {
111 // 3 FMAs, or 9 mul + 6 add
112 return GetX(vector) * X + GetY(vector) * Y + GetZ(vector) * Z;
113 }
114
117 JPL_INLINE void Transform(simd& inOutX, simd& inOutY, simd& inOutZ) const noexcept
118 {
119 // Take a copy of the original input values
120 // because we modify them as we compute next component
121 const simd inX = inOutX;
122 const simd inY = inOutY;
123 const simd inZ = inOutZ;
124
125 inOutX = Math::FMA(simd(GetX(X)), inX, Math::FMA(simd(GetX(Y)), inY, simd(GetX(Z)) * inZ));
126 inOutY = Math::FMA(simd(GetY(X)), inX, Math::FMA(simd(GetY(Y)), inY, simd(GetY(Z)) * inZ));
127 inOutZ = Math::FMA(simd(GetZ(X)), inX, Math::FMA(simd(GetZ(Y)), inY, simd(GetZ(Z)) * inZ));
128 }
129
131 [[nodiscard]] JPL_INLINE Basis Transform(const Basis& otherBasis) const noexcept
132 {
133 return Basis{ // R * R_other
134 .X = Transform(otherBasis.X),
135 .Y = Transform(otherBasis.Y),
136 .Z = Transform(otherBasis.Z)
137 };
138 }
139
141 [[nodiscard]] JPL_INLINE Basis InverseTransform(const Basis& otherBasis) const noexcept
142 {
143 return Basis{ // RT * R_other
144 .X = InverseTransform(otherBasis.X),
145 .Y = InverseTransform(otherBasis.Y),
146 .Z = InverseTransform(otherBasis.Z)
147 };
148 }
149
150 };
151
152 namespace Math
153 {
156 template<CVec3 Vec3>
157 [[nodiscard]] JPL_INLINE static Basis<Vec3> MakeBasis(const Vec3& forward) noexcept
158 {
159 return Basis<Vec3>::MakeFrom(forward);
160 }
161
164 template<CVec3 Vec3>
165 [[nodiscard]] JPL_INLINE static Basis<Vec3> MakeBasis(const Vec3& forward, const Vec3& up) noexcept
166 {
167 return Basis<Vec3>::FromUpAndForward(up, forward);
168 }
169 }
170} // namespace JPL
std::remove_cvref_t< decltype(GetX(std::declval< Vec3 >()))> FloatOf
Definition Vec3Math.h:36
void CreateOrthonormalBasis(const Vec3 &normal, Vec3 &tangent, Vec3 &bitangent) noexcept
Definition Vec3Math.h:84
JPL_INLINE constexpr T FMA(T a, T b, T c) noexcept
Inlined fuse multiply-add. Compiler in some circumstances is more eager to optimize this than std::fm...
Definition Math.h:186
JPL_INLINE constexpr bool IsNearlyEqual(T a, T b, T tolerance=JPL_FLOAT_EPS_V< T >) noexcept
Definition Math.h:152
JPL_INLINE constexpr auto Abs(const T &value) noexcept
Standard abs is not constexpr in C++20.
Definition Math.h:87
JPL_INLINE std::pair< T, T > SinCos(T value) noexcept
Definition Math.h:164
Definition AcousticMaterial.h:36
JPL_INLINE auto GetX(const Vec3Type &v) noexcept
Definition Vec3Traits.h:35
JPL_INLINE auto GetZ(const Vec3Type &v) noexcept
Definition Vec3Traits.h:37
JPL_INLINE auto GetY(const Vec3Type &v) noexcept
Definition Vec3Traits.h:36
Orthonormal basis (column-major)
Definition MinimalBasis.h:35
JPL_INLINE Vec3 InverseTransform(const Vec3 &pWorld) const noexcept
Apply rotation world -> local.
Definition MinimalBasis.h:99
JPL_INLINE Vec3 Transform(const Vec3 &vector) const noexcept
Apply rotation local -> world.
Definition MinimalBasis.h:109
Vec3 X
Definition MinimalBasis.h:38
static const Basis & Identity() noexcept
Definition MinimalBasis.h:40
Vec3 Z
Definition MinimalBasis.h:38
Internal::FloatOf< Vec3 > Float
Definition MinimalBasis.h:36
Vec3 Y
Definition MinimalBasis.h:38
JPL_INLINE void Transform(simd &inOutX, simd &inOutY, simd &inOutZ) const noexcept
Definition MinimalBasis.h:117
static Basis Rotation(const Vec3 &axis, Float angleRad) noexcept
Definition MinimalBasis.h:78
JPL_INLINE Basis Transform(const Basis &otherBasis) const noexcept
Compose orientations: apply 'this' basis mapping to the other's axes.
Definition MinimalBasis.h:131
JPL_INLINE Basis InverseTransform(const Basis &otherBasis) const noexcept
Re-express 'other' in 'this' local frame.
Definition MinimalBasis.h:141
static Basis FromUpAndForward(const Vec3 &up, const Vec3 &forward) noexcept
Creates a basis from the given up and forward normalized unit vectors.
Definition MinimalBasis.h:60
static JPL_INLINE Basis FromForward(const Vec3 &forward) noexcept
Definition MinimalBasis.h:52
Minimal 4-wide 32-bit float vector implementation for SIMD.
Definition SIMD.h:60