EBGeometry
Compact, header-only C++ library for fast evaluation of signed distance functions
Loading...
Searching...
No Matches
EBGeometry_SmoothRayForms.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Robert Marskar <robert.marskar@sintef.no>
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
22#ifndef EBGEOMETRY_SMOOTHRAYFORMS_HPP
23#define EBGEOMETRY_SMOOTHRAYFORMS_HPP
24
25// Std includes
26#include <cmath>
27#include <cstdint>
28#include <type_traits>
29#include <utility>
30
31// Our includes
33#include "EBGeometry_Fused.hpp"
34#include "EBGeometry_Math.hpp"
36#include "EBGeometry_Ray.hpp"
38
39namespace EBGeometry {
40
41namespace RayDetail {
42
52template <class T>
53[[nodiscard]] EBGEOMETRY_HOST_DEVICE
54inline T
55blendDepth(const T a_smooth, const bool a_exponential) noexcept
56{
57 return a_exponential ? a_smooth * T(0.6931471805599453) : T(0.25) * a_smooth;
58}
59
66template <class S>
68{
73
77 static constexpr DistanceQuality distanceQuality = distanceQualityOf<S>;
78
83
89 [[nodiscard]] EBGEOMETRY_HOST_DEVICE
90 inline T
91 signedDistance(const Vec3T<T>& a_point) const noexcept
92 {
93 return m_shape.signedDistance(a_point);
94 }
95
100 [[nodiscard]] EBGEOMETRY_HOST_DEVICE
102 computeBoundingVolume() const noexcept
103 {
104 return m_shape.computeBoundingVolume();
105 }
106};
107
112template <class S>
113struct IsComposition<MarchedView<S>> : std::bool_constant<CalledOutOfLine<S>>
114{
115};
116
129template <class T, class... Cs>
131{
136
140 static constexpr DistanceQuality distanceQuality = distanceQualityOf<Node>;
141
146
151
157 [[nodiscard]] EBGEOMETRY_HOST_DEVICE
158 inline T
159 signedDistance(const Vec3T<T>& a_point) const noexcept
160 {
161 return this->value(a_point, std::index_sequence_for<Cs...>{});
162 }
163
168 [[nodiscard]] EBGEOMETRY_HOST_DEVICE
170 computeBoundingVolume() const noexcept
171 {
172 return m_box;
173 }
174
175private:
182 template <size_t... Is>
183 [[nodiscard]] EBGEOMETRY_HOST_DEVICE
184 inline T
185 value(const Vec3T<T>& a_point, std::index_sequence<Is...>) const noexcept
186 {
187 const T smooth = m_node.layout().m_op.m_smooth;
188
189 CSGOps::Pair<T> pair = CSGOps::pairInit<T>(false);
190
191 (CSGOps::pairInsert(pair, RayDetail::fusedOperand<Is>(m_node).signedDistance(a_point), false), ...);
192
193 const T blended = CSGOps::pairBlend(pair, smooth, false, false);
194
195 return Math::max(blended, pair.m_second - (smooth + RayDetail::blendDepth(smooth, false)));
196 }
197};
198
204template <class T, class... Cs>
205struct IsComposition<BlendZoneView<T, Cs...>> : std::true_type
206{
207};
208
222template <class T, class Op, class... Cs, size_t... Is>
224inline void
226 const T a_grow,
228 bool& a_any,
229 std::index_sequence<Is...>) noexcept
230{
231 const BoundingVolumes::AABBT<T> boxes[] = {RayDetail::fusedOperand<Is>(a_node).computeBoundingVolume()...};
232 const Vec3T<T> grow = a_grow * Vec3T<T>::ones();
233
234 for (size_t i = 0; i < sizeof...(Is); i++) {
235 for (size_t j = i + 1; j < sizeof...(Is); j++) {
236 const Vec3T<T> lo = max(boxes[i].getLowCorner(), boxes[j].getLowCorner()) - grow;
237 const Vec3T<T> hi = min(boxes[i].getHighCorner(), boxes[j].getHighCorner()) + grow;
238
239 if (lo[0] <= hi[0] && lo[1] <= hi[1] && lo[2] <= hi[2]) {
240 a_box = a_any ? BoundingVolumes::AABBT<T>(min(a_box.getLowCorner(), lo), max(a_box.getHighCorner(), hi))
242 a_any = true;
243 }
244 }
245 }
246}
247
248} // namespace RayDetail
249
264template <class T, bool IsUnion, class... Cs>
265struct RayForm<Fused::Node<Fused::SmoothCombineOp<T, IsUnion>, Cs...>>
266{
271
281 [[nodiscard]] EBGEOMETRY_HOST_DEVICE
282 static inline HitT<T>
283 firstHit(const Node& a_shape, const RayT<T>& a_ray, T a_tMin, T a_tMax, const RayOptions<T>& a_options) noexcept
284 {
285 const auto trace =
286 [&a_shape, &a_ray, &a_options](const T a_t0, const T a_t1, const bool a_all, RaySpansT<T>& a_spans) noexcept {
287 spans(a_shape, a_ray, a_t0, a_t1, a_options, !a_all, a_spans);
288 };
289
290 // A marched crossing's normal is the gradient there; marching again around it would find no better one.
291 const auto resolve = [&a_shape, &a_ray, &a_options](const T a_t, const uint32_t) noexcept {
292 const auto box = a_shape.computeBoundingVolume();
293 const T h = a_options.m_tolerance * RayDetail::scaleOf(box.getLowCorner(), box.getHighCorner(), a_options);
294
295 HitT<T> hit;
296
297 hit.m_normal = RayDetail::gradientNormal(RayDetail::MarchedView<Node>{a_shape}, a_ray.at(a_t), h);
298
299 return hit;
300 };
301
302 HitT<T> hit = RayDetail::traceSpans(trace, resolve, a_ray, a_tMin, a_tMax);
303
304 hit.m_primitive = 0U;
305
306 return hit;
307 }
308
319 [[nodiscard]] EBGEOMETRY_HOST_DEVICE
320 static inline CrossingT<T>
321 firstCrossing(const Node& a_shape, const RayT<T>& a_ray, T a_tMin, T a_tMax, const RayOptions<T>& a_options) noexcept
322 {
323 const auto trace =
324 [&a_shape, &a_ray, &a_options](const T a_t0, const T a_t1, const bool a_all, RaySpansT<T>& a_spans) noexcept {
325 spans(a_shape, a_ray, a_t0, a_t1, a_options, !a_all, a_spans);
326 };
327
328 return RayDetail::traceCrossing(trace, a_ray, a_tMin, a_tMax);
329 }
330
343 static inline void
344 spans(const Node& a_shape,
345 const RayT<T>& a_ray,
346 T a_tMin,
347 T a_tMax,
348 const RayOptions<T>& a_options,
349 bool a_firstOnly,
350 RaySpansT<T>& a_spans) noexcept
351 {
352 RaySpansT<T> scratch;
353 RaySpansT<T> operand;
354
355 if constexpr (IsUnion) {
356 const Fused::SmoothCombineOp<T, IsUnion>& op = a_shape.layout().m_op;
357
358 if (op.m_exponential) {
359 // An exponential blend differs from the plain union everywhere, if only slightly: marched whole.
360 RayDetail::shapeSpans(
361 RayDetail::MarchedView<Node>{a_shape}, a_ray, a_tMin, a_tMax, a_options, a_firstOnly, a_spans);
362 }
363 else {
364 // The plain union, exact, united with where the smooth union is inside and may differ from it, marched
365 // up to what the plain union is known up to (see RayDetail::BlendZoneView).
366 RayDetail::fusedOperandSpans<0>(a_shape, a_ray, a_tMin, a_tMax, a_options, a_firstOnly, a_spans);
367
368 if (a_firstOnly) {
369 RayDetail::keepFirst(a_spans);
370 }
371
372 RayDetail::fusedUnite<1>(a_shape, a_ray, a_tMin, a_options, a_firstOnly, a_spans, operand);
373
374 // The blend zone view, marched where two operands' boxes grown by w overlap, up to what the plain union is
375 // known up to (see RayDetail::BlendZoneView).
376 const T level = op.m_smooth + RayDetail::blendDepth(op.m_smooth, false);
377
379
380 bool any = false;
381
382 RayDetail::pairOverlaps(a_shape, level, zone, any, std::index_sequence_for<Cs...>{});
383
384 // With no overlap, the smooth union is the plain union.
385 if (any) {
386 RayDetail::shapeSpans(RayDetail::BlendZoneView<T, Cs...>{a_shape, zone},
387 a_ray,
388 a_tMin,
389 a_spans.m_horizon,
390 a_options,
391 a_firstOnly,
392 operand);
393 RayDetail::uniteInto(a_spans, operand);
394
395 if (a_firstOnly) {
396 RayDetail::keepFirst(a_spans);
397 }
398 }
399 }
400 }
401 else {
402 // Marched within the plain intersection, as a fused intersection traces it: the traced operands first, the
403 // marched ones only within them. All its spans: where the smooth intersection is outside in one, it may be
404 // inside in the next.
405 constexpr size_t first = RayDetail::FirstTraced<T, Cs...>::value;
406
407 RaySpansT<T> bracket;
408
409 RayDetail::fusedOperandSpans<first>(a_shape, a_ray, a_tMin, a_tMax, a_options, false, bracket);
410 RayDetail::fusedIntersect<0, false, first>(a_shape, a_ray, a_tMin, a_options, false, bracket, operand, scratch);
411 RayDetail::fusedIntersect<0, true, first>(a_shape, a_ray, a_tMin, a_options, false, bracket, operand, scratch);
412 RayDetail::spansWithin(
413 RayDetail::MarchedView<Node>{a_shape}, a_ray, bracket, a_options, a_firstOnly, scratch, a_spans);
414 }
415
416 RayDetail::nameLeaf(0U, a_spans);
417 }
418};
419
420} // namespace EBGeometry
421
422#endif
The ray forms (see RayForm) of compositions: the fused union, intersection, difference,...
Fused CSG: the operations of the expression builder (EBGeometry_Expr.hpp) as types,...
#define EBGEOMETRY_HOST_DEVICE
Mark a function as callable from both host and device code (no-op on host compilers).
Definition EBGeometry_GPU.hpp:80
Scalar helpers and numeric limits that compile for both host and device.
Ray forms of offsets and annuli: the level sets of their operands' values.
The span arithmetic that traces a composition along a ray: each operand's spans (where the ray is ins...
Ray queries on any shape: where a ray, or the segment between two points, first crosses its surface (...
T blendDepth(const T a_smooth, const bool a_exponential) noexcept
How far a smooth union's blend can deepen its operands' minimum: s/4 for the polynomial blend,...
Definition EBGeometry_SmoothRayForms.hpp:55
void pairOverlaps(const Fused::Node< Op, Cs... > &a_node, const T a_grow, BoundingVolumes::AABBT< T > &a_box, bool &a_any, std::index_sequence< Is... >) noexcept
Where two of a fused node's operands' boxes, grown by a_grow, overlap: the box of each pair's overlap...
Definition EBGeometry_SmoothRayForms.hpp:225
Axis-aligned bounding box (AABB) enclosing a set of 3D points.
Definition EBGeometry_BoundingVolumes.hpp:37
const Layout & layout() const noexcept
The node's layout.
Definition EBGeometry_Fused.hpp:383
Three-dimensional vector class with arithmetic operators.
Definition EBGeometry_Vec.hpp:258
static constexpr Vec3T< T > ones() noexcept
Return a vector with x = y = z = 1.
T pairBlend(const Pair< T > &a_pair, const T a_smooth, const bool a_largest, const bool a_exponential) noexcept
The smooth minimum (or maximum) of a pair's two values.
Definition EBGeometry_CSGOps.hpp:603
void pairInsert(Pair< T > &a_pair, const T a_value, const bool a_largest) noexcept
Insert a value into a pair of extreme values.
Definition EBGeometry_CSGOps.hpp:547
constexpr T max(const T &a_a, const T &a_b) noexcept
The larger of two values.
Definition EBGeometry_Math.hpp:61
Namespace containing all of EBGeometry's functionality.
Definition EBGeometry_Affine.hpp:26
Vec2T< T > min(const Vec2T< T > &u, const Vec2T< T > &v) noexcept
Component-wise minimum of two vectors.
typename ExprDetail::ShapeInfo< S >::precision ShapePrecision
The precision of a shape type: T for a shape whose box type is AABBT<T>.
Definition EBGeometry_Expr.hpp:167
DistanceQuality
How far the value of a signed distance function can be trusted, from strongest to weakest.
Definition EBGeometry_DistanceQuality.hpp:25
Vec2T< T > max(const Vec2T< T > &u, const Vec2T< T > &v) noexcept
Component-wise maximum of two vectors.
The two most extreme values seen so far, for an n-ary smooth union or intersection.
Definition EBGeometry_CSGOps.hpp:496
V m_second
The next.
Definition EBGeometry_CSGOps.hpp:505
Where a ray first crosses a surface, without the normal or the primitive there: what firstCrossing() ...
Definition EBGeometry_Ray.hpp:156
Smooth union or intersection: a smooth minimum (maximum) of the two smallest (largest) values.
Definition EBGeometry_Fused.hpp:570
bool m_exponential
Whether the blend is exponential (BlendKind::Exponential) rather than polynomial.
Definition EBGeometry_Fused.hpp:579
T m_smooth
Smoothing length.
Definition EBGeometry_Fused.hpp:574
Where a ray first crosses a surface.
Definition EBGeometry_Ray.hpp:97
Vec3T< T > m_normal
The outward unit normal at the crossing: from the shape's ray form, or the normalized gradient of its...
Definition EBGeometry_Ray.hpp:125
uint32_t m_primitive
The finest element the shape can name at the crossing: the face of a mesh SDF, the deciding leaf of a...
Definition EBGeometry_Ray.hpp:119
A fused smooth union restricted to where it can differ from the plain union of its operands: the valu...
Definition EBGeometry_SmoothRayForms.hpp:131
BoundingVolumes::AABBT< T > m_box
Where two operands' boxes, grown by w, overlap: the blend zone lies within it.
Definition EBGeometry_SmoothRayForms.hpp:150
Node m_node
The smooth union.
Definition EBGeometry_SmoothRayForms.hpp:145
T signedDistance(const Vec3T< T > &a_point) const noexcept
The value.
Definition EBGeometry_SmoothRayForms.hpp:159
BoundingVolumes::AABBT< T > computeBoundingVolume() const noexcept
The blend zone's box.
Definition EBGeometry_SmoothRayForms.hpp:170
static constexpr DistanceQuality distanceQuality
The quality of its value: a bound at best.
Definition EBGeometry_SmoothRayForms.hpp:140
The first of a fused node's operands an intersection does not march, which it traces first: 0 if it m...
Definition EBGeometry_CSGRayForms.hpp:225
A shape seen only through its value, with no ray form: what a smooth operation is marched as where it...
Definition EBGeometry_SmoothRayForms.hpp:68
T signedDistance(const Vec3T< T > &a_point) const noexcept
The shape's value.
Definition EBGeometry_SmoothRayForms.hpp:91
BoundingVolumes::AABBT< T > computeBoundingVolume() const noexcept
The shape's box.
Definition EBGeometry_SmoothRayForms.hpp:102
static constexpr DistanceQuality distanceQuality
The quality of its value: the shape's.
Definition EBGeometry_SmoothRayForms.hpp:77
S m_shape
The shape.
Definition EBGeometry_SmoothRayForms.hpp:82
ShapePrecision< S > T
Floating-point precision.
Definition EBGeometry_SmoothRayForms.hpp:72
static void spans(const Node &a_shape, const RayT< T > &a_ray, T a_tMin, T a_tMax, const RayOptions< T > &a_options, bool a_firstOnly, RaySpansT< T > &a_spans) noexcept
Where a ray is inside over an interval: the plain operation traced, and the smooth one marched where ...
Definition EBGeometry_SmoothRayForms.hpp:344
static HitT< T > firstHit(const Node &a_shape, const RayT< T > &a_ray, T a_tMin, T a_tMax, const RayOptions< T > &a_options) noexcept
The first crossing along a ray.
Definition EBGeometry_SmoothRayForms.hpp:283
static CrossingT< T > firstCrossing(const Node &a_shape, const RayT< T > &a_ray, T a_tMin, T a_tMax, const RayOptions< T > &a_options) noexcept
The first crossing of the node along a ray, without the normal or primitive there: the trace of first...
Definition EBGeometry_SmoothRayForms.hpp:321
How to ray trace a shape directly, instead of marching its signed distance.
Definition EBGeometry_Ray.hpp:400
How a query marches, where a shape has no ray form.
Definition EBGeometry_Ray.hpp:202
Where a ray is inside an object over an interval [t0, t1]: its spans, in order, each from where it en...
Definition EBGeometry_Ray.hpp:295
A ray: the points origin + t * direction.
Definition EBGeometry_Ray.hpp:55