Move Vectormath main
C++20 game and graphics mathematics
Loading...
Searching...
No Matches
Normal3.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cmath>
4#include <cstdint>
5#include <optional>
6#include <type_traits>
7#include <utility>
8
10#include <mv/math/detail/Normalization.hpp>
11
12namespace mv::math
13{
14 template <typename T>
15 requires std::is_floating_point_v<T>
16 class Plane3;
17
18 enum class RefractionStatus : std::uint8_t
19 {
20 Success,
24 };
25
26 template <typename T>
27 requires std::is_floating_point_v<T>
28 class Normal3;
29
30 template <typename T>
31 requires std::is_floating_point_v<T>
32 [[nodiscard]] Normal3<T> Rotate(const Rotation3<T>&,
33 const Normal3<T>&) noexcept;
34
35 template <typename T>
36 requires std::is_floating_point_v<T>
37 class Normal3
38 {
39 public:
40 using Component = T;
41
42 Normal3() noexcept : Value_(T(1), T(0), T(0))
43 {
44 }
45
46 [[nodiscard]] static std::optional<Normal3> TryFrom(
47 const Vec3<T>& value) noexcept
48 {
49 const auto normalized = detail::TryNormalizeVector(value);
50 if (!normalized)
51 {
52 return std::nullopt;
53 }
54 return Normal3(*normalized, UncheckedTag{});
55 }
56
58 Normal3 fallback) noexcept
59 {
60 const auto result = TryFrom(value);
61 return result ? *result : fallback;
62 }
63
65 const Direction3<T>& direction) noexcept
66 {
67 return Normal3(direction.Vector(), UncheckedTag{});
68 }
69
71 {
72 return Normal3(Vec3<T>(T(1), T(0), T(0)), UncheckedTag{});
73 }
74
76 {
77 return Normal3(Vec3<T>(T(0), T(1), T(0)), UncheckedTag{});
78 }
79
81 {
82 return Normal3(Vec3<T>(T(0), T(0), T(1)), UncheckedTag{});
83 }
84
86 {
87 return Value_;
88 }
89
95
97 {
98 return Normal3(Value_ * T(-1), UncheckedTag{});
99 }
100
101 [[nodiscard]] friend bool operator==(const Normal3& left,
102 const Normal3& right) noexcept
103 {
104 return left.Value_ == right.Value_;
105 }
106
107 private:
108 struct UncheckedTag
109 {
110 };
111
112 explicit Normal3(const Vec3<T>& value, UncheckedTag) noexcept :
113 Value_(value)
114 {
115 }
116
117 Vec3<T> Value_;
118
119 friend class Plane3<T>;
120 friend Normal3<T> Rotate<T>(const Rotation3<T>&,
121 const Normal3<T>&) noexcept;
122 };
123
126
127 template <typename T>
128 requires std::is_floating_point_v<T>
130 {
132 std::optional<Direction3<T>> Direction;
133
134 [[nodiscard]] explicit operator bool() const noexcept
135 {
137 }
138 };
139
142
143 template <typename T>
144 requires std::is_floating_point_v<T>
146 const Normal3<T>& normal) noexcept
147 {
148 return Normal3<T>(Rotate(rotation, normal.Vector()),
149 typename Normal3<T>::UncheckedTag{});
150 }
151
152 template <typename T>
153 requires std::is_floating_point_v<T>
155 const Vec3<T>& value, const Normal3<T>& planeNormal) noexcept
156 {
157 // Vector rejection from a unit normal follows Ericson, Real-Time
158 // Collision Detection (2005), section 5.1.1.
159 return value - planeNormal.Vector() * Dot(value, planeNormal.Vector());
160 }
161
162 template <typename T>
163 requires std::is_floating_point_v<T>
165 const Normal3<T>& normal) noexcept
166 {
167 // Algebra follows GLSL 4.60 section 8.5's reflect operation; the
168 // Normal3 contract supplies GLSL's normalized-normal precondition.
169 return incident -
170 normal.Vector() * (T(2) * Dot(normal.Vector(), incident));
171 }
172
173 template <typename T>
174 requires std::is_floating_point_v<T>
176 const Direction3<T>& incident,
179 {
180 if (!(incidentOverTransmittedIndex > T(0)) ||
181 !std::isfinite(incidentOverTransmittedIndex))
182 {
183 return {RefractionStatus::InvalidIndexRatio, std::nullopt};
184 }
185
186 // Algebra and direction convention follow GLSL 4.60 section 8.5's
187 // refract(I, N, eta), with eta explicitly named n_incident/n_exit.
188 // Unlike GLSL's zero-vector sentinel, Move reports TIR explicitly.
189 const T normalDotIncident =
190 Dot(surfaceNormal.Vector(), incident.Vector());
191 const T discriminant =
194 if (discriminant < T(0))
195 {
196 return {RefractionStatus::TotalInternalReflection, std::nullopt};
197 }
198
199 const Vec3<T> refracted =
201 surfaceNormal.Vector() *
203 std::sqrt(discriminant));
205 if (!direction)
206 {
207 return {RefractionStatus::NumericalFailure, std::nullopt};
208 }
209 return {RefractionStatus::Success, std::move(direction)};
210 }
211} // namespace mv::math
212
213static_assert(sizeof(mv::math::Normal3f) == sizeof(mv::math::Vec3f));
214static_assert(alignof(mv::math::Normal3f) == alignof(mv::math::Vec3f));
215static_assert(std::is_trivially_copyable_v<mv::math::Normal3f>);
216static_assert(std::is_standard_layout_v<mv::math::Normal3f>);
217static_assert(sizeof(mv::math::Normal3d) == sizeof(mv::math::Vec3d));
218static_assert(alignof(mv::math::Normal3d) == alignof(mv::math::Vec3d));
219static_assert(std::is_trivially_copyable_v<mv::math::Normal3d>);
220static_assert(std::is_standard_layout_v<mv::math::Normal3d>);
static std::optional< Direction3 > TryFrom(const Vec3< T > &value) noexcept
static Normal3 FromDirection(const Direction3< T > &direction) noexcept
Definition Normal3.hpp:64
static Normal3 AxisX() noexcept
Definition Normal3.hpp:70
static Normal3 AxisY() noexcept
Definition Normal3.hpp:75
Direction3< T > ToDirection() const noexcept
Definition Normal3.hpp:90
static Normal3 AxisZ() noexcept
Definition Normal3.hpp:80
Normal3() noexcept
Definition Normal3.hpp:42
Normal3 operator-() const noexcept
Definition Normal3.hpp:96
const Vec3< T > & Vector() const noexcept
Definition Normal3.hpp:85
friend bool operator==(const Normal3 &left, const Normal3 &right) noexcept
Definition Normal3.hpp:101
static std::optional< Normal3 > TryFrom(const Vec3< T > &value) noexcept
Definition Normal3.hpp:46
static Normal3 FromOr(const Vec3< T > &value, Normal3 fallback) noexcept
Definition Normal3.hpp:57
constexpr T Dot(const Quat< T > &left, const Quat< T > &right) noexcept
Definition Quat.hpp:102
Vec3< T > ProjectOntoPlane(const Vec3< T > &value, const Normal3< T > &planeNormal) noexcept
Definition Normal3.hpp:154
Normal3< float > Normal3f
Definition Normal3.hpp:124
RefractionStatus
Definition Normal3.hpp:19
Normal3< double > Normal3d
Definition Normal3.hpp:125
Vec3< T > Reflect(const Vec3< T > &incident, const Normal3< T > &normal) noexcept
Definition Normal3.hpp:164
Vec3< T > Rotate(const Rotation3< T > &rotation, const Vec3< T > &vector) noexcept
RefractionResult3< T > Refract(const Direction3< T > &incident, const Normal3< T > &surfaceNormal, T incidentOverTransmittedIndex) noexcept
Definition Normal3.hpp:175
RefractionStatus Status
Definition Normal3.hpp:131
std::optional< Direction3< T > > Direction
Definition Normal3.hpp:132