Move Vectormath main
C++20 game and graphics mathematics
Loading...
Searching...
No Matches
ObbQueries.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <cmath>
5#include <cstddef>
6#include <limits>
7#include <optional>
8#include <type_traits>
9
14
15namespace mv::math
16{
17 template <typename T>
18 [[nodiscard]] inline std::optional<RayObbHit3<T>> Intersect(
19 const Ray3<T>& ray, const Obb3<T>& box) noexcept
20 {
21 const Rotation3<T> inverse = box.Orientation().Inverse();
22 const auto localDirection =
23 Direction3<T>::TryFrom(Rotate(inverse, ray.Direction().Vector()));
24 const auto localRay =
27 inverse, ray.Origin() - box.Center())),
29 : std::nullopt;
31 Point3<T>::Origin(), box.HalfExtents());
32 if (!localRay || !localBox)
33 {
34 return std::nullopt;
35 }
36
37 const auto localHit = Intersect(*localRay, *localBox);
38 if (!localHit)
39 {
40 return std::nullopt;
41 }
42 std::optional<Normal3<T>> entryNormal;
43 if (localHit->EntryNormal)
44 {
45 entryNormal = Rotate(box.Orientation(), *localHit->EntryNormal);
46 }
47 return RayObbHit3<T>{localHit->EntryDistance, localHit->ExitDistance,
48 localHit->StartsInside, entryNormal,
49 Rotate(box.Orientation(), localHit->ExitNormal)};
50 }
51
52 template <typename T>
53 [[nodiscard]] inline bool Intersects(const Ray3<T>& ray,
54 const Obb3<T>& box) noexcept
55 {
56 return Intersect(ray, box).has_value();
57 }
58
59 template <typename T>
60 [[nodiscard]] inline bool Intersects(const Sphere3<T>& sphere,
61 const Obb3<T>& box) noexcept
62 {
63 const Vec3<T> difference =
64 sphere.Center() - box.ClosestPoint(sphere.Center());
65 return LengthSquared(difference) <= sphere.Radius() * sphere.Radius();
66 }
67
68 template <typename T>
69 [[nodiscard]] inline bool Intersects(const Obb3<T>& box,
70 const Sphere3<T>& sphere) noexcept
71 {
72 return Intersects(sphere, box);
73 }
74
75 // Full 15-axis OBB separating-axis test from Ericson, Real-Time Collision
76 // Detection (2005), section 4.4.1. The epsilon makes nearly parallel axes
77 // conservative, avoiding culling false negatives at the cost of possible
78 // touching/near-touching false positives.
79 template <typename T>
80 [[nodiscard]] inline bool Intersects(const Obb3<T>& first,
81 const Obb3<T>& second) noexcept
82 {
83 const std::array<Vec3<T>, 3> a = {first.AxisX().Vector(),
84 first.AxisY().Vector(),
85 first.AxisZ().Vector()};
86 const std::array<Vec3<T>, 3> b = {second.AxisX().Vector(),
87 second.AxisY().Vector(),
88 second.AxisZ().Vector()};
89 const std::array<T, 3> ae = {first.HalfExtents().X(),
90 first.HalfExtents().Y(),
91 first.HalfExtents().Z()};
92 const std::array<T, 3> be = {second.HalfExtents().X(),
93 second.HalfExtents().Y(),
94 second.HalfExtents().Z()};
95 T rotation[3][3]{};
96 T absoluteRotation[3][3]{};
97 const T epsilon = std::numeric_limits<T>::epsilon() * T(8);
98 for (std::size_t i = 0U; i < 3U; ++i)
99 {
100 for (std::size_t j = 0U; j < 3U; ++j)
101 {
102 rotation[i][j] = Dot(a[i], b[j]);
103 absoluteRotation[i][j] = std::abs(rotation[i][j]) + epsilon;
104 }
105 }
106
107 const Vec3<T> centerDifference = second.Center() - first.Center();
108 const std::array<T, 3> translation = {Dot(centerDifference, a[0]),
110 Dot(centerDifference, a[2])};
111 for (std::size_t i = 0U; i < 3U; ++i)
112 {
113 const T secondRadius = be[0] * absoluteRotation[i][0] +
114 be[1] * absoluteRotation[i][1] +
115 be[2] * absoluteRotation[i][2];
116 if (std::abs(translation[i]) > ae[i] + secondRadius)
117 {
118 return false;
119 }
120 }
121 for (std::size_t j = 0U; j < 3U; ++j)
122 {
123 const T projection = std::abs(translation[0] * rotation[0][j] +
124 translation[1] * rotation[1][j] +
125 translation[2] * rotation[2][j]);
126 const T firstRadius = ae[0] * absoluteRotation[0][j] +
127 ae[1] * absoluteRotation[1][j] +
128 ae[2] * absoluteRotation[2][j];
129 if (projection > firstRadius + be[j])
130 {
131 return false;
132 }
133 }
134 for (std::size_t i = 0U; i < 3U; ++i)
135 {
136 const std::size_t i1 = (i + 1U) % 3U;
137 const std::size_t i2 = (i + 2U) % 3U;
138 for (std::size_t j = 0U; j < 3U; ++j)
139 {
140 const std::size_t j1 = (j + 1U) % 3U;
141 const std::size_t j2 = (j + 2U) % 3U;
142 const T projection =
143 std::abs(translation[i2] * rotation[i1][j] -
144 translation[i1] * rotation[i2][j]);
145 const T firstRadius = ae[i1] * absoluteRotation[i2][j] +
147 const T secondRadius = be[j1] * absoluteRotation[i][j2] +
150 {
151 return false;
152 }
153 }
154 }
155 return true;
156 }
157
158 template <typename T>
159 [[nodiscard]] inline bool Intersects(const Aabb3<T>& first,
160 const Obb3<T>& second) noexcept
161 {
162 const auto center = first.TryCenter();
163 const auto halfExtents = first.TryHalfExtents();
164 if (!center || !halfExtents)
165 {
166 return false;
167 }
170 return firstObb && Intersects(*firstObb, second);
171 }
172
173 template <typename T>
174 [[nodiscard]] inline bool Intersects(const Obb3<T>& first,
175 const Aabb3<T>& second) noexcept
176 {
177 return Intersects(second, first);
178 }
179} // namespace mv::math
static std::optional< Aabb3 > TryFromCenterHalfExtents(const Point3< T > &center, const Vec3< T > &halfExtents) noexcept
Definition Aabb3.hpp:48
static std::optional< Direction3 > TryFrom(const Vec3< T > &value) noexcept
static std::optional< Obb3 > TryFromCenterHalfExtents(const Point3< T > &center, const Vec3< T > &halfExtents, const Rotation3< T > &orientation=Rotation3< T >::Identity()) noexcept
Definition Obb3.hpp:27
static std::optional< Ray3 > TryFromOriginDirection(const Point3< T > &origin, const Direction3< T > &direction) noexcept
Definition Ray3.hpp:23
constexpr T Dot(const Quat< T > &left, const Quat< T > &right) noexcept
Definition Quat.hpp:102
bool Intersects(const Ray3< T > &ray, const Sphere3< T > &sphere) noexcept
constexpr T LengthSquared(const Quat< T > &value) noexcept
Definition Quat.hpp:110
std::optional< RaySphereHit3< T > > Intersect(const Ray3< T > &ray, const Sphere3< T > &sphere) noexcept
Vec3< T > Rotate(const Rotation3< T > &rotation, const Vec3< T > &vector) noexcept