Move Vectormath main
C++20 game and graphics mathematics
Loading...
Searching...
No Matches
LinearQueries.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cmath>
4#include <limits>
5#include <optional>
6#include <type_traits>
7
12
13namespace mv::math
14{
15 enum class BackFaceMode
16 {
17 Include,
18 Cull
19 };
20
21 template <typename T>
22 requires std::is_floating_point_v<T>
24 {
26 T ParallelTolerance = std::numeric_limits<T>::epsilon() * T(8);
27 };
28
31
32 namespace detail
33 {
34 template <typename T>
40
41 // Standard plane-equation solve; cross-checked against GLM
42 // intersectRayPlane (MIT). Move accepts t=0 and rejects non-finite
43 // hits.
44 template <typename T>
45 [[nodiscard]] inline std::optional<RayPlaneSolution<T>>
47 const Plane3<T>& plane,
48 T parallelTolerance) noexcept
49 {
50 const T tolerance = std::abs(parallelTolerance);
51 if (!std::isfinite(tolerance))
52 {
53 return std::nullopt;
54 }
55
56 const T denominator =
57 Dot(plane.Normal().Vector(), ray.Direction().Vector());
58 if (!std::isfinite(denominator) ||
59 std::abs(denominator) <= tolerance)
60 {
61 return std::nullopt;
62 }
63
64 const T distance =
65 -plane.SignedDistance(ray.Origin()) / denominator;
66 if (!(distance >= T(0)) || !std::isfinite(distance))
67 {
68 return std::nullopt;
69 }
71 }
72
73 template <typename T>
81
82 // Moller-Trumbore ray/triangle test (JGT 1997,
83 // doi:10.1080/10867651.1997.10487468); Move adds explicit culling,
84 // finite-construction, tolerance, and boundary policy.
85 template <typename T>
86 [[nodiscard]] inline std::optional<RayTriangleSolution<T>>
90 {
91 const T tolerance = std::abs(options.ParallelTolerance);
92 if (!std::isfinite(tolerance))
93 {
94 return std::nullopt;
95 }
96
97 const Vec3<T> edge01 = triangle.Edge01();
98 const Vec3<T> edge02 = triangle.Edge02();
100 Cross(ray.Direction().Vector(), edge02);
102 if (!std::isfinite(determinant))
103 {
104 return std::nullopt;
105 }
106
107 if (options.BackFaces == BackFaceMode::Cull)
108 {
109 if (!(determinant > tolerance))
110 {
111 return std::nullopt;
112 }
113 }
114 else if (std::abs(determinant) <= tolerance)
115 {
116 return std::nullopt;
117 }
118
120 const Vec3<T> fromFirst = ray.Origin() - triangle.First();
121 const T secondWeight =
123 if (!(secondWeight >= T(0) && secondWeight <= T(1)))
124 {
125 return std::nullopt;
126 }
127
129 const T thirdWeight =
130 Dot(ray.Direction().Vector(), fromFirstCrossEdge01) *
132 if (!(thirdWeight >= T(0) && secondWeight + thirdWeight <= T(1)))
133 {
134 return std::nullopt;
135 }
136
137 const T distance =
139 if (!(distance >= T(0)) || !std::isfinite(distance))
140 {
141 return std::nullopt;
142 }
143
146 }
147 } // namespace detail
148
149 template <typename T>
150 [[nodiscard]] inline std::optional<RayPlaneHit3<T>> Intersect(
151 const Ray3<T>& ray,
152 const Plane3<T>& plane,
153 T parallelTolerance = std::numeric_limits<T>::epsilon() * T(8)) noexcept
154 {
155 const auto solution =
157 if (!solution)
158 {
159 return std::nullopt;
160 }
161 return RayPlaneHit3<T>{
162 solution->Distance, ray.PointAt(solution->Distance), plane.Normal(),
163 solution->Denominator < T(0) ? FaceOrientation::Front
165 }
166
167 template <typename T>
168 [[nodiscard]] inline bool Intersects(
169 const Ray3<T>& ray,
170 const Plane3<T>& plane,
171 T parallelTolerance = std::numeric_limits<T>::epsilon() * T(8)) noexcept
172 {
174 .has_value();
175 }
176
177 template <typename T>
178 [[nodiscard]] inline std::optional<RayTriangleHit3<T>> Intersect(
179 const Ray3<T>& ray,
180 const Triangle3<T>& triangle,
181 RayTriangleOptions<T> options = {}) noexcept
182 {
183 const auto solution =
184 detail::TryIntersectRayTriangle(ray, triangle, options);
185 if (!solution)
186 {
187 return std::nullopt;
188 }
189
190 const auto normal = triangle.TryNormal();
191 if (!normal)
192 {
193 return std::nullopt;
194 }
195
196 return RayTriangleHit3<T>{
197 solution->Distance, ray.PointAt(solution->Distance), *normal,
198 Vec3<T>(T(1) - solution->SecondWeight - solution->ThirdWeight,
199 solution->SecondWeight, solution->ThirdWeight),
200 solution->Determinant > T(0) ? FaceOrientation::Front
202 }
203
204 template <typename T>
205 [[nodiscard]] inline bool Intersects(
206 const Ray3<T>& ray,
207 const Triangle3<T>& triangle,
208 RayTriangleOptions<T> options = {}) noexcept
209 {
210 return detail::TryIntersectRayTriangle(ray, triangle, options)
211 .has_value();
212 }
213} // namespace mv::math
std::optional< RayPlaneSolution< T > > TryIntersectRayPlane(const Ray3< T > &ray, const Plane3< T > &plane, T parallelTolerance) noexcept
std::optional< RayTriangleSolution< T > > TryIntersectRayTriangle(const Ray3< T > &ray, const Triangle3< T > &triangle, RayTriangleOptions< T > options) noexcept
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
Vec3< T > Cross(const Vec3< T > &left, const Vec3< T > &right) noexcept
Definition Vec3.hpp:367
std::optional< RaySphereHit3< T > > Intersect(const Ray3< T > &ray, const Sphere3< T > &sphere) noexcept