Move Vectormath main
C++20 game and graphics mathematics
Loading...
Searching...
No Matches
Vec3.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cassert>
5#include <cmath>
6#include <cstddef>
7#include <cstdint>
8#include <type_traits>
9
10#include <mv/math/Vec2.hpp>
11#include <mv/math/detail/VectorOps.hpp>
12
13namespace mv::math
14{
15 template <typename T>
16 requires std::is_floating_point_v<T>
17 class Mat3;
18
19 template <typename T>
20 requires std::is_arithmetic_v<T>
21 class Vec3;
22
23 template <typename T>
24 requires std::is_arithmetic_v<T>
25 [[nodiscard]] T Dot(const Vec3<T>& left, const Vec3<T>& right) noexcept;
26
27 template <typename T>
28 requires std::is_arithmetic_v<T>
29 [[nodiscard]] Vec3<T> Cross(const Vec3<T>& left,
30 const Vec3<T>& right) noexcept;
31
32 template <typename T>
33 requires std::is_arithmetic_v<T>
34 [[nodiscard]] Vec3<T> Min(const Vec3<T>& left,
35 const Vec3<T>& right) noexcept;
36
37 template <typename T>
38 requires std::is_arithmetic_v<T>
39 [[nodiscard]] Vec3<T> Max(const Vec3<T>& left,
40 const Vec3<T>& right) noexcept;
41
42 template <typename T>
43 requires std::is_arithmetic_v<T>
44 class alignas(sizeof(T) * 4U) Vec3
45 {
46 private:
47 using Ops = detail::SelectedVectorOps<T>;
48
49 public:
50 using Component = T;
51
52 Vec3() noexcept : Native_(Ops::Load4(Zero_))
53 {
54 }
55
56 Vec3(T x, T y, T z) noexcept
57 {
58 const T values[3] = {x, y, z};
59 Native_ = Ops::Load3(values);
60 }
61
62 template <typename U>
63 requires(std::is_arithmetic_v<U> && !std::is_same_v<T, U>)
64 explicit Vec3(const Vec3<U>& other) noexcept :
65 Vec3(static_cast<T>(other.X()),
66 static_cast<T>(other.Y()),
67 static_cast<T>(other.Z()))
68 {
69 }
70
71 template <typename U>
72 requires std::is_arithmetic_v<U>
73 explicit Vec3(const Vec2<U>& xy, T z = T(0)) noexcept :
74 Vec3(static_cast<T>(xy.X()), static_cast<T>(xy.Y()), z)
75 {
76 }
77
79 {
80 return Vec3(T(0), T(0), T(0));
81 }
82
84 {
85 return Vec3(T(1), T(1), T(1));
86 }
87
88 [[nodiscard]] static Vec3 Filled(T value) noexcept
89 {
90 return Vec3(value, value, value);
91 }
92
94 {
95 return Vec3(T(1), T(0), T(0));
96 }
97
99 {
100 return Vec3(T(0), T(1), T(0));
101 }
102
104 {
105 return Vec3(T(0), T(0), T(1));
106 }
107
109 {
110 return Ops::GetX(Native_);
111 }
112
114 {
115 return Ops::GetY(Native_);
116 }
117
119 {
120 return Ops::GetZ(Native_);
121 }
122
123 [[nodiscard]] T operator[](std::size_t index) const noexcept
124 {
125 assert(index < 3U);
126 switch (index)
127 {
128 case 0U:
129 return X();
130 case 1U:
131 return Y();
132 default:
133 return Z();
134 }
135 }
136
137 template <std::size_t Index>
139 {
140 static_assert(Index < 3U);
141 if constexpr (Index == 0U)
142 {
143 return X();
144 }
145 else if constexpr (Index == 1U)
146 {
147 return Y();
148 }
149 else
150 {
151 return Z();
152 }
153 }
154
156 {
157 return Vec2<T>(X(), Y());
158 }
159
161 {
162 return Vec2<T>(X(), Z());
163 }
164
166 {
167 return Vec2<T>(Y(), Z());
168 }
169
170 void SetX(T value) noexcept
171 {
172 Native_ = Ops::SetX(Native_, value);
173 }
174
175 void SetY(T value) noexcept
176 {
177 Native_ = Ops::SetY(Native_, value);
178 }
179
180 void SetZ(T value) noexcept
181 {
182 Native_ = Ops::SetZ(Native_, value);
183 }
184
185 [[nodiscard]] bool SetComponent(std::size_t index, T value) noexcept
186 {
187 switch (index)
188 {
189 case 0U:
190 SetX(value);
191 return true;
192 case 1U:
193 SetY(value);
194 return true;
195 case 2U:
196 SetZ(value);
197 return true;
198 default:
199 return false;
200 }
201 }
202
203 template <std::size_t Index>
204 void Set(T value) noexcept
205 {
206 static_assert(Index < 3U);
207 if constexpr (Index == 0U)
208 {
209 SetX(value);
210 }
211 else if constexpr (Index == 1U)
212 {
213 SetY(value);
214 }
215 else
216 {
217 SetZ(value);
218 }
219 }
220
221 [[nodiscard]] Vec3 operator+(const Vec3& other) const noexcept
222 {
223 return Vec3(Ops::Add(Native_, other.Native_));
224 }
225
226 [[nodiscard]] Vec3 operator-(const Vec3& other) const noexcept
227 {
228 return Vec3(Ops::Subtract(Native_, other.Native_));
229 }
230
231 [[nodiscard]] Vec3 operator*(const Vec3& other) const noexcept
232 {
233 return Vec3(Ops::Multiply(Native_, other.Native_));
234 }
235
236 [[nodiscard]] Vec3 operator*(T scalar) const noexcept
237 {
238 return Vec3(Ops::Multiply(Native_, scalar));
239 }
240
241 [[nodiscard]] Vec3 operator/(const Vec3& other) const noexcept
242 {
243 return Vec3(Ops::Divide3(Native_, other.Native_));
244 }
245
246 [[nodiscard]] Vec3 operator+(T scalar) const noexcept
247 {
248 return Vec3(Ops::Add(Native_, scalar));
249 }
250
251 [[nodiscard]] Vec3 operator-(T scalar) const noexcept
252 {
253 return Vec3(Ops::Subtract(Native_, scalar));
254 }
255
256 [[nodiscard]] Vec3 operator/(T scalar) const noexcept
257 {
258 return Vec3(Ops::Divide(Native_, scalar));
259 }
260
262 {
263 return Vec3(Ops::Negate(Native_));
264 }
265
266 Vec3& operator+=(const Vec3& other) noexcept
267 {
268 Native_ = Ops::Add(Native_, other.Native_);
269 return *this;
270 }
271
272 Vec3& operator-=(const Vec3& other) noexcept
273 {
274 Native_ = Ops::Subtract(Native_, other.Native_);
275 return *this;
276 }
277
278 Vec3& operator*=(const Vec3& other) noexcept
279 {
280 Native_ = Ops::Multiply(Native_, other.Native_);
281 return *this;
282 }
283
284 Vec3& operator/=(const Vec3& other) noexcept
285 {
286 Native_ = Ops::Divide3(Native_, other.Native_);
287 return *this;
288 }
289
291 {
292 Native_ = Ops::Add(Native_, scalar);
293 return *this;
294 }
295
297 {
298 Native_ = Ops::Subtract(Native_, scalar);
299 return *this;
300 }
301
303 {
304 Native_ = Ops::Multiply(Native_, scalar);
305 return *this;
306 }
307
309 {
310 Native_ = Ops::Divide(Native_, scalar);
311 return *this;
312 }
313
315 const Vec3& vector) noexcept
316 {
317 return vector * scalar;
318 }
319
320 [[nodiscard]] friend bool operator==(const Vec3& left,
321 const Vec3& right) noexcept
322 {
323 return left.X() == right.X() && left.Y() == right.Y() &&
324 left.Z() == right.Z();
325 }
326
327 private:
328 explicit Vec3(typename Ops::Native native) noexcept : Native_(native)
329 {
330 }
331
332 inline static constexpr T Zero_[4] = {T(0), T(0), T(0), T(0)};
333 typename Ops::Native Native_;
334
335 friend T Dot<T>(const Vec3&, const Vec3&) noexcept;
336 friend Vec3 Cross<T>(const Vec3&, const Vec3&) noexcept;
337 friend Vec3 Min<T>(const Vec3&, const Vec3&) noexcept;
338 friend Vec3 Max<T>(const Vec3&, const Vec3&) noexcept;
339 template <typename U>
340 requires std::is_floating_point_v<U>
341 friend class Mat3;
342 };
343
354 using Vec3i = Vec3i32;
355 using Vec3u = Vec3u32;
356
357 template <typename T>
358 requires std::is_arithmetic_v<T>
359 [[nodiscard]] T Dot(const Vec3<T>& left, const Vec3<T>& right) noexcept
360 {
361 using Ops = detail::SelectedVectorOps<T>;
362 return Ops::Dot3(left.Native_, right.Native_);
363 }
364
365 template <typename T>
366 requires std::is_arithmetic_v<T>
368 const Vec3<T>& right) noexcept
369 {
370 using Ops = detail::SelectedVectorOps<T>;
371 return Vec3<T>(Ops::Cross3(left.Native_, right.Native_));
372 }
373
374 template <typename T>
375 [[nodiscard]] T LengthSquared(const Vec3<T>& value) noexcept
376 {
377 return Dot(value, value);
378 }
379
380 template <typename T>
381 requires std::is_floating_point_v<T>
383 const Vec3<T>& left,
384 const Vec3<T>& right,
386 {
387 return IsNearlyEqual(left.X(), right.X(), tolerance) &&
388 IsNearlyEqual(left.Y(), right.Y(), tolerance) &&
390 }
391
392 template <typename T>
393 requires std::is_floating_point_v<T>
395 const Vec3<T>& value,
396 T absoluteTolerance = Tolerance<T>::Default().Absolute) noexcept
397 {
398 return IsNearlyZero(value.X(), absoluteTolerance) &&
401 }
402
403 template <typename T>
404 requires std::is_floating_point_v<T>
405 [[nodiscard]] T Length(const Vec3<T>& value) noexcept
406 {
407 // Semantics follow GLSL 4.60 section 8.5's length operation.
408 return std::sqrt(LengthSquared(value));
409 }
410
411 template <typename T>
413 const Vec3<T>& right) noexcept
414 {
415 return LengthSquared(left - right);
416 }
417
418 template <typename T>
419 requires std::is_floating_point_v<T>
420 [[nodiscard]] T Distance(const Vec3<T>& left, const Vec3<T>& right) noexcept
421 {
422 // Semantics follow GLSL 4.60 section 8.5's distance operation.
423 return Length(left - right);
424 }
425
426 template <typename T>
427 requires std::is_arithmetic_v<T>
429 const Vec3<T>& right) noexcept
430 {
431 using Ops = detail::SelectedVectorOps<T>;
432 return Vec3<T>(Ops::Min(left.Native_, right.Native_));
433 }
434
435 template <typename T>
436 requires std::is_arithmetic_v<T>
438 const Vec3<T>& right) noexcept
439 {
440 using Ops = detail::SelectedVectorOps<T>;
441 return Vec3<T>(Ops::Max(left.Native_, right.Native_));
442 }
443
444 template <typename T>
446 const Vec3<T>& minimum,
447 const Vec3<T>& maximum) noexcept
448 {
449 // Component semantics follow GLSL 4.60 section 8.3's clamp operation.
450 return Min(Max(value, minimum), maximum);
451 }
452
453 template <typename T>
455 T minimum,
456 T maximum) noexcept
457 {
459 }
460
461 template <typename T>
462 requires(std::is_signed_v<T> || std::is_floating_point_v<T>)
463 [[nodiscard]] Vec3<T> Abs(const Vec3<T>& value) noexcept
464 {
465 return Vec3<T>(static_cast<T>(std::abs(value.X())),
466 static_cast<T>(std::abs(value.Y())),
467 static_cast<T>(std::abs(value.Z())));
468 }
469
470 template <typename T>
471 requires(std::is_signed_v<T> || std::is_floating_point_v<T>)
472 [[nodiscard]] Vec3<T> Sign(const Vec3<T>& value) noexcept
473 {
474 // Component semantics follow GLSL 4.60 section 8.3's sign operation.
475 const auto sign = [](T component)
476 {
477 return static_cast<T>((T(0) < component) - (component < T(0)));
478 };
479 return Vec3<T>(sign(value.X()), sign(value.Y()), sign(value.Z()));
480 }
481
482 template <typename T>
483 requires std::is_floating_point_v<T>
485 const Vec3<T>& to,
486 T amount) noexcept
487 {
488 // Algebra follows GLSL 4.60 section 8.3's mix operation.
489 return from + (to - from) * amount;
490 }
491
492 template <typename T>
493 requires std::is_floating_point_v<T>
495 const Vec3<T>& to,
496 T amount) noexcept
497 {
498 return LerpUnclamped(from, to, std::clamp(amount, T(0), T(1)));
499 }
500} // namespace mv::math
501
502static_assert(sizeof(mv::math::Vec3f) == 16);
503static_assert(alignof(mv::math::Vec3f) == 16);
504static_assert(std::is_trivially_copyable_v<mv::math::Vec3f>);
505static_assert(std::is_standard_layout_v<mv::math::Vec3f>);
Vec3 operator/(const Vec3 &other) const noexcept
Definition Vec3.hpp:241
Vec2< T > YZ() const noexcept
Definition Vec3.hpp:165
void SetX(T value) noexcept
Definition Vec3.hpp:170
Vec3 operator*(T scalar) const noexcept
Definition Vec3.hpp:236
static Vec3 Filled(T value) noexcept
Definition Vec3.hpp:88
Vec2< T > XY() const noexcept
Definition Vec3.hpp:155
Vec3 operator*(const Vec3 &other) const noexcept
Definition Vec3.hpp:231
Vec3 operator-(const Vec3 &other) const noexcept
Definition Vec3.hpp:226
Vec3 & operator/=(const Vec3 &other) noexcept
Definition Vec3.hpp:284
T Y() const noexcept
Definition Vec3.hpp:113
static Vec3 AxisY() noexcept
Definition Vec3.hpp:98
Vec3(const Vec2< U > &xy, T z=T(0)) noexcept
Definition Vec3.hpp:73
Vec3 operator+(T scalar) const noexcept
Definition Vec3.hpp:246
static Vec3 One() noexcept
Definition Vec3.hpp:83
T Z() const noexcept
Definition Vec3.hpp:118
static Vec3 AxisZ() noexcept
Definition Vec3.hpp:103
Vec3 & operator-=(T scalar) noexcept
Definition Vec3.hpp:296
Vec3 & operator-=(const Vec3 &other) noexcept
Definition Vec3.hpp:272
bool SetComponent(std::size_t index, T value) noexcept
Definition Vec3.hpp:185
Vec3(T x, T y, T z) noexcept
Definition Vec3.hpp:56
Vec3 operator-(T scalar) const noexcept
Definition Vec3.hpp:251
Vec3 & operator*=(const Vec3 &other) noexcept
Definition Vec3.hpp:278
Vec2< T > XZ() const noexcept
Definition Vec3.hpp:160
friend Vec3 operator*(T scalar, const Vec3 &vector) noexcept
Definition Vec3.hpp:314
T X() const noexcept
Definition Vec3.hpp:108
void SetY(T value) noexcept
Definition Vec3.hpp:175
T operator[](std::size_t index) const noexcept
Definition Vec3.hpp:123
Vec3 & operator+=(T scalar) noexcept
Definition Vec3.hpp:290
void SetZ(T value) noexcept
Definition Vec3.hpp:180
Vec3(const Vec3< U > &other) noexcept
Definition Vec3.hpp:64
Vec3 operator/(T scalar) const noexcept
Definition Vec3.hpp:256
Vec3 & operator/=(T scalar) noexcept
Definition Vec3.hpp:308
friend bool operator==(const Vec3 &left, const Vec3 &right) noexcept
Definition Vec3.hpp:320
Vec3() noexcept
Definition Vec3.hpp:52
void Set(T value) noexcept
Definition Vec3.hpp:204
static Vec3 Zero() noexcept
Definition Vec3.hpp:78
static Vec3 AxisX() noexcept
Definition Vec3.hpp:93
Vec3 & operator+=(const Vec3 &other) noexcept
Definition Vec3.hpp:266
T Get() const noexcept
Definition Vec3.hpp:138
Vec3 operator-() const noexcept
Definition Vec3.hpp:261
Vec3 & operator*=(T scalar) noexcept
Definition Vec3.hpp:302
Vec3 operator+(const Vec3 &other) const noexcept
Definition Vec3.hpp:221
Vec2< T > Sign(const Vec2< T > &value) noexcept
Definition Vec2.hpp:349
constexpr T Dot(const Quat< T > &left, const Quat< T > &right) noexcept
Definition Quat.hpp:102
Vec2< T > LerpUnclamped(const Vec2< T > &from, const Vec2< T > &to, T amount) noexcept
Definition Vec2.hpp:361
Vec3< T > Cross(const Vec3< T > &left, const Vec3< T > &right) noexcept
Definition Vec3.hpp:367
T Distance(const Point3< T > &point, const Line3< T > &line) noexcept
bool IsNearlyEqual(const Quat< T > &left, const Quat< T > &right, Tolerance< T > tolerance=Tolerance< T >::Default()) noexcept
Definition Quat.hpp:176
constexpr T LengthSquared(const Quat< T > &value) noexcept
Definition Quat.hpp:110
Vec2< T > Min(const Vec2< T > &left, const Vec2< T > &right) noexcept
Definition Vec2.hpp:307
Vec3< std::int32_t > Vec3i32
Definition Vec3.hpp:350
Vec2< T > Clamp(const Vec2< T > &value, const Vec2< T > &minimum, const Vec2< T > &maximum) noexcept
Definition Vec2.hpp:323
T Length(const Quat< T > &value) noexcept
Definition Quat.hpp:116
Vec3< float > Vec3f
Definition Vec3.hpp:344
constexpr bool IsNearlyZero(T value, T absoluteTolerance=Tolerance< T >::Default().Absolute) noexcept
Definition Tolerance.hpp:54
Vec2< T > Max(const Vec2< T > &left, const Vec2< T > &right) noexcept
Definition Vec2.hpp:315
Vec3< std::uint32_t > Vec3u32
Definition Vec3.hpp:351
Vec2< T > Lerp(const Vec2< T > &from, const Vec2< T > &to, T amount) noexcept
Definition Vec2.hpp:371
Vec2< T > Abs(const Vec2< T > &value) noexcept
Definition Vec2.hpp:341
T DistanceSquared(const Point3< T > &point, const Line3< T > &line) noexcept