17#ifndef EBGEOMETRY_TREEBVH_HPP
18#define EBGEOMETRY_TREEBVH_HPP
69 for (
const auto& p : a_leafPrims) {
86template <
class List,
size_t K>
91 for (
size_t k = 0; k < K; k++) {
93 "%s: the partitioner returned an empty partition (%zu of %zu, from %zu primitives). A leaf "
94 "must hold at least one primitive; a partitioner must return %zu non-empty partitions.",
117appendAliased(std::vector<P>& a_dst,
const std::shared_ptr<std::vector<P>>& a_block)
120 a_dst = std::move(*a_block);
123 a_dst.insert(a_dst.end(), std::make_move_iterator(a_block->begin()), std::make_move_iterator(a_block->end()));
139 switch (a_construction) {
144 "%s: ConstructionOptions::maxLeafSize must be positive for a top-down construction",
153 a_options.targetLeafSize > 0,
154 "%s: ConstructionOptions::targetLeafSize must be positive for a space-filling-curve construction",
175template <
class X,
size_t K>
177 static_assert(K >= 2,
"EqualCounts<X, K>: branching factor K must be at least 2");
181 const int length = a_primitives.size() / K;
182 int remain = a_primitives.size() % K;
189 for (
size_t k = 0; k < K; k++) {
195 chunks[k] = std::vector<X>(std::make_move_iterator(a_primitives.begin() + begin),
196 std::make_move_iterator(a_primitives.begin() + end));
213template <
class T,
class P,
class BV,
size_t K>
220 for (
const auto& pbv : a_primsAndBVs) {
221 lo =
min(lo, pbv.first->getCentroid());
222 hi =
max(hi, pbv.first->getCentroid());
225 const size_t splitDir = (hi - lo).maxDir(
true);
228 std::sort(a_primsAndBVs.begin(),
231 return pbv1.first->getCentroid(splitDir) < pbv2.first->getCentroid(splitDir);
234 return BVH::EqualCounts<PrimAndBV<P, BV>, K>(std::move(a_primsAndBVs));
246template <
class T,
class P,
class BV,
size_t K>
253 for (
const auto& pbv : a_primsAndBVs) {
254 lo =
min(lo, pbv.second.getCentroid());
255 hi =
max(hi, pbv.second.getCentroid());
258 const size_t splitDir = (hi - lo).maxDir(
true);
261 std::sort(a_primsAndBVs.begin(),
264 return pbv1.second.getCentroid()[splitDir] < pbv2.second.getCentroid()[splitDir];
267 return BVH::EqualCounts<PrimAndBV<P, BV>, K>(std::move(a_primsAndBVs));
288template <
class T,
class P,
class BV>
291 const size_t a_begin,
293 const bool a_longestAxisOnly =
false) noexcept
295 static_assert(std::is_same_v<BV, EBGeometry::BoundingVolumes::AABBT<T>>,
"SAH2WaySplit requires BV == AABBT<T>");
299 constexpr int BINS = 32;
301 const size_t N = a_end - a_begin;
307 for (
size_t i = a_begin; i < a_end; i++) {
308 const auto& c = a_list[i].second.getCentroid();
323 T leftArea[BINS - 1];
324 int leftCnt[BINS - 1];
326 const int firstAxis = a_longestAxisOnly ? (chi - clo).maxDir(
true) : 0;
327 const int lastAxis = a_longestAxisOnly ? firstAxis : 2;
329 for (
int axis = firstAxis; axis <= lastAxis; axis++) {
330 const T lo = clo[axis];
331 const T hi = chi[axis];
332 const T ext = hi - lo;
335 const T scale = T(BINS) / ext;
337 if (!(ext > T(0)) || !std::isfinite(scale)) {
341 for (
int b = 0; b < BINS; b++) {
347 for (
size_t i = a_begin; i < a_end; i++) {
349 const T x = (a_list[i].second.getCentroid()[axis] - lo) * scale;
350 const int b = (x > T(0)) ? ((x < T(BINS - 1)) ?
static_cast<int>(x) : BINS - 1) : 0;
351 binLo[b] =
min(binLo[b], a_list[i].second.getLowCorner());
352 binHi[b] =
max(binHi[b], a_list[i].second.getHighCorner());
353 binCnt[b] = binCnt[b] + 1;
361 for (
int b = 0; b < BINS - 1; b++) {
363 rlo =
min(rlo, binLo[b]);
364 rhi =
max(rhi, binHi[b]);
367 rcnt = rcnt + binCnt[b];
368 leftArea[b] = (rcnt > 0) ? BV(rlo, rhi).getArea() : T(0);
377 for (
int b = BINS - 1; b >= 1; b--) {
379 rrlo =
min(rrlo, binLo[b]);
380 rrhi =
max(rrhi, binHi[b]);
385 if (leftCnt[b - 1] > 0 && rrcnt > 0) {
386 const T cost = leftArea[b - 1] * T(leftCnt[b - 1]) + BV(rrlo, rrhi).getArea() * T(rrcnt);
388 if (cost < bestCost) {
391 bestPlane = lo + T(b) / scale;
399 return a_begin + N / 2;
402 auto mid = std::partition(
403 a_list.begin() + a_begin, a_list.begin() + a_end, [bestAxis, bestPlane](
const PrimAndBV<P, BV>& pbv)
noexcept {
404 return pbv.second.getCentroid()[bestAxis] < bestPlane;
407 const size_t splitIdx =
static_cast<size_t>(std::distance(a_list.begin(), mid));
410 return (splitIdx == a_begin || splitIdx == a_end) ? a_begin + N / 2 : splitIdx;
427template <
class T,
class P,
class BV>
430 const size_t a_begin,
433 std::vector<std::pair<size_t, size_t>>& a_groups,
434 const bool a_longestAxisOnly =
false)
436 static_assert(std::is_same_v<BV, EBGeometry::BoundingVolumes::AABBT<T>>,
"SAHKWaySplit requires BV == AABBT<T>");
438 if (a_K <= 1 || a_begin >= a_end) {
439 a_groups.emplace_back(a_begin, a_end);
444 const size_t K1 = a_K / 2;
445 const size_t K2 = a_K - K1;
452 const size_t rawMid = SAH2WaySplit<T, P, BV>(a_list, a_begin, a_end, a_longestAxisOnly);
455 SAHKWaySplit<T, P, BV>(a_list, a_begin, mid, K1, a_groups, a_longestAxisOnly);
456 SAHKWaySplit<T, P, BV>(a_list, mid, a_end, K2, a_groups, a_longestAxisOnly);
487template <
class T,
class P,
class BV,
size_t K,
bool LongestAxisOnly = false>
493 std::vector<std::pair<size_t, size_t>> groups;
496 SAHKWaySplit<T, P, BV>(a_primsAndBVs, 0, a_primsAndBVs.size(), K, groups, LongestAxisOnly);
499 for (
size_t k = 0; k < K; k++) {
500 const auto [b, e] = groups[k];
502 std::make_move_iterator(a_primsAndBVs.begin() + e));
523template <
class T,
class P,
class BV>
529 const size_t N = a_end - a_begin;
534 for (
size_t i = a_begin; i < a_end; i++) {
535 const auto& c = a_list[i].second.getCentroid();
541 const size_t splitDir = (hi - lo).maxDir(
true);
542 const T midpoint = T(0.5) * (lo[splitDir] + hi[splitDir]);
544 auto mid = std::partition(
545 a_list.begin() + a_begin, a_list.begin() + a_end, [splitDir, midpoint](
const PrimAndBV<P, BV>& pbv)
noexcept {
546 return pbv.second.getCentroid()[splitDir] < midpoint;
549 const size_t splitIdx =
static_cast<size_t>(std::distance(a_list.begin(), mid));
554 return (splitIdx == a_begin || splitIdx == a_end) ? a_begin + N / 2 : splitIdx;
572template <
class T,
class P,
class BV>
575 const size_t a_begin,
578 std::vector<std::pair<size_t, size_t>>& a_groups)
580 if (a_K <= 1 || a_begin >= a_end) {
581 a_groups.emplace_back(a_begin, a_end);
586 const size_t K1 = a_K / 2;
587 const size_t K2 = a_K - K1;
592 const size_t rawMid = Midpoint2WaySplit<T, P, BV>(a_list, a_begin, a_end);
595 MidpointKWaySplit<T, P, BV>(a_list, a_begin, mid, K1, a_groups);
596 MidpointKWaySplit<T, P, BV>(a_list, mid, a_end, K2, a_groups);
620template <
class T,
class P,
class BV,
size_t K>
628 std::vector<std::pair<size_t, size_t>> groups;
631 MidpointKWaySplit<T, P, BV>(a_primsAndBVs, 0, a_primsAndBVs.size(), K, groups);
634 for (
size_t k = 0; k < K; k++) {
635 const auto [b, e] = groups[k];
637 std::make_move_iterator(a_primsAndBVs.begin() + e));
652template <
class T,
class P,
class BV,
size_t K>
677template <
class T,
class P,
class BV,
size_t K>
680 static_assert(std::is_floating_point_v<T>,
"TreeBVH: T must be a floating-point type");
681 static_assert(K >= 2,
"TreeBVH: branching factor K must be at least 2");
774 operator=(
TreeBVH&& a_other) noexcept = default;
800 template <typename S>
808 [[nodiscard]] inline
bool
815 [[nodiscard]] inline
bool
822 [[nodiscard]] inline const BV&
838 [[nodiscard]] inline const std::vector<BV>&
847 [[nodiscard]] inline T
855 [[nodiscard]] inline const
Array<std::shared_ptr<
TreeBVH<T, P, BV, K>>, K>&
870 [[nodiscard]] inline std::shared_ptr<
TreeBVH<T, P, BV, K>>
903 template <class NodeKey>
933 template <class BVConstructor>
935 refit(const BVConstructor& a_bvConstructor);
960 template <class Q, class Converter>
1002 inline std::vector<BV>&
1019#include "EBGeometry_TreeBVHImplem.hpp"
A fixed-size array that compiles for both host and device.
Host-side BVH construction: the PackedBVH constructors that pack a TreeBVH, and PackedBVH's static bu...
Declarations of bounding volume types used in bounding volume hierarchies.
#define EBGEOMETRY_HOST
Mark a function as callable from host code only (no-op on host compilers).
Definition EBGeometry_GPU.hpp:83
Utility macros for EBGeometry.
#define EBGEOMETRY_REQUIRE(cond,...)
Always-on check of user input and one-time host setup.
Definition EBGeometry_Macros.hpp:84
#define EBGEOMETRY_EXPECT(cond)
Runtime precondition assertion for EBGeometry.
Definition EBGeometry_Macros.hpp:155
Scalar helpers and numeric limits that compile for both host and device.
The flattened, device-callable bounding volume hierarchy: PackedBVH, its node layout,...
Declaration of various space-filling curves.
Declaration of 2D and 3D point/vector classes with templated precision, and free functions on them.
Forward declaration of the linearised BVH, defined below.
Definition EBGeometry_PackedBVH.hpp:357
Forward declaration of the tree-structured BVH, defined in EBGeometry_TreeBVH.hpp....
Definition EBGeometry_TreeBVH.hpp:679
BVH::Partitioner< P, BV, K > Partitioner
Alias for the partitioner type.
Definition EBGeometry_TreeBVH.hpp:707
bool isLeaf() const noexcept
Return true if this is a leaf node (no children, non-empty primitive list).
const std::vector< BV > & getBoundingVolumes() const noexcept
Get the per-primitive bounding volumes stored in this node.
void bottomUpSortAndPartition(size_t a_targetLeafSize=1)
Recursively partition this node bottom-up along a space-filling curve.
const BV & refit(const BVConstructor &a_bvConstructor)
Refit this subtree's bounding volumes in place after its primitives have moved.
std::vector< BV > m_boundingVolumes
Per-primitive bounding volumes. Non-empty for leaf nodes only.
Definition EBGeometry_TreeBVH.hpp:984
TreeBVH()
Default constructor. Creates an empty interior node.
~TreeBVH() noexcept=default
Destructor.
const Array< std::shared_ptr< TreeBVH< T, P, BV, K > >, K > & getChildren() const noexcept
Get the K child nodes of this interior node.
std::shared_ptr< TreeBVH< T, P, BV, K > > deepCopy() const
Produce an independent deep copy of this tree.
BVH::PrimitiveList< P > PrimitiveList
Alias for the primitive list type.
Definition EBGeometry_TreeBVH.hpp:687
bool m_partitioned
True after topDownSortAndPartition() or bottomUpSortAndPartition() has been called.
Definition EBGeometry_TreeBVH.hpp:974
std::vector< std::shared_ptr< const P > > m_primitives
Primitives stored in this node. Non-empty for leaf nodes only.
Definition EBGeometry_TreeBVH.hpp:979
const PrimitiveList & getPrimitives() const noexcept
Get the primitives stored in this node.
T getDistanceToBoundingVolume(const Vec3 &a_point) const noexcept
Get the distance from a_point to this node's bounding volume.
PackedBVH< T, P, K > pack(Pool &a_pool) const
Flatten this tree into a cache-friendly PackedBVH with the same primitive type.
Array< std::shared_ptr< TreeBVH< T, P, BV, K > >, K > m_children
K child nodes. Non-null for interior nodes only.
Definition EBGeometry_TreeBVH.hpp:989
void topDownSortAndPartition(const Partitioner &a_partitioner=BVCentroidPartitioner< T, P, BV, K >, const LeafPredicate &a_stopCrit=DefaultLeafPredicate< T, P, BV, K >)
Recursively partition this node top-down.
void setChildren(const Array< std::shared_ptr< TreeBVH< T, P, BV, K > >, K > &a_children)
Set the K child nodes, converting this node from a leaf into an interior node.
TreeBVH(const std::vector< PrimAndBV< P, BV > > &a_primsAndBVs)
Construct a leaf node from a set of (primitive, BV) pairs.
BVH::LeafPredicate< T, P, BV, K > LeafPredicate
Alias for the stop-function type.
Definition EBGeometry_TreeBVH.hpp:712
PackedBVH< T, Q, K > packWith(Pool &a_pool, Converter &&a_converter) const
Flatten and convert this tree into a PackedBVH with a different primitive type Q.
BV m_boundingVolume
Bounding volume enclosing all primitives in this subtree.
Definition EBGeometry_TreeBVH.hpp:969
void traverse(const BVH::LeafEvaluator< P > &a_leafEvaluator, const BVH::PrunePredicate< Node, NodeKey > &a_prunePredicate, const BVH::ChildOrderer< Node, NodeKey, K > &a_childOrderer, const BVH::NodeKeyFactory< Node, NodeKey > &a_nodeKeyFactory) const
Recursion-free BVH traversal using an explicit LIFO stack (depth-first order).
TreeBVH(std::vector< PrimAndBV< P, BV > > &&a_primsAndBVs)
Construct a leaf node holding the given (primitive, bounding volume) pairs, moved in.
const BV & getBoundingVolume() const noexcept
Get the bounding volume for this node.
std::shared_ptr< Node > NodePtr
Alias for a shared pointer to a node.
Definition EBGeometry_TreeBVH.hpp:702
bool isPartitioned() const noexcept
Return true if the tree has already been partitioned.
Growable bump arena over a MemoryResource.
Definition EBGeometry_Pool.hpp:183
Three-dimensional vector class with arithmetic operators.
Definition EBGeometry_Vec.hpp:258
static constexpr Vec3T< T > max() noexcept
Return the most-positive representable vector.
void appendTreeLeaf(std::vector< P > &a_dst, const PrimitiveList< P > &a_leafPrims)
Append one TreeBVH leaf's primitives to a flat primitive array under construction.
Definition EBGeometry_TreeBVH.hpp:62
void requireLeafSetting(const char *a_who, const Construction a_construction, const ConstructionOptions &a_options) noexcept
Abort unless the leaf-size setting that a_construction reads is positive.
Definition EBGeometry_TreeBVH.hpp:137
void appendAliased(std::vector< P > &a_dst, const std::shared_ptr< std::vector< P > > &a_block)
Materialise a single contiguous buffer into a flat primitive array under construction.
Definition EBGeometry_TreeBVH.hpp:117
void requireNonEmptyPartitions(const Array< List, K > &a_partitions, const size_t a_numInput, const char *a_who)
Abort unless every partition a partitioner returned holds at least one primitive.
Definition EBGeometry_TreeBVH.hpp:89
size_t SAH2WaySplit(PrimAndBVList< P, BV > &a_list, const size_t a_begin, const size_t a_end, const bool a_longestAxisOnly=false) noexcept
Internal helper: 2-way binned SAH split on the sub-range [a_begin, a_end).
Definition EBGeometry_TreeBVH.hpp:290
auto EqualCounts
Utility: split a vector into K almost-equal contiguous chunks.
Definition EBGeometry_TreeBVH.hpp:176
std::vector< std::shared_ptr< const P > > PrimitiveList
Convenience alias for a list of shared primitive pointers.
Definition EBGeometry_PackedBVH.hpp:215
std::function< bool(const NodeType &a_node, const NodeKey &a_nodeKey)> PrunePredicate
Node-visit predicate for TreeBVH::traverse().
Definition EBGeometry_PackedBVH.hpp:288
std::function< Array< PrimAndBVList< P, BV >, K >(PrimAndBVList< P, BV > a_primsAndBVs)> Partitioner
Polymorphic partitioner: splits a list of (primitive, BV) pairs into K sub-lists.
Definition EBGeometry_PackedBVH.hpp:253
std::vector< PrimAndBV< P, BV > > PrimAndBVList
Convenience alias for a list of (primitive, bounding-volume) pairs.
Definition EBGeometry_PackedBVH.hpp:237
std::function< bool(const TreeBVH< T, P, BV, K > &a_node)> LeafPredicate
Predicate for deciding when a TreeBVH node should become a leaf (i.e., no further splitting).
Definition EBGeometry_PackedBVH.hpp:265
std::pair< std::shared_ptr< const P >, BV > PrimAndBV
Convenience alias for a (primitive, bounding-volume) pair.
Definition EBGeometry_PackedBVH.hpp:229
std::function< void(const PrimitiveList< P > &a_primitives)> LeafEvaluator
Leaf-evaluation callback for TreeBVH::traverse.
Definition EBGeometry_PackedBVH.hpp:274
std::function< NodeKey(const NodeType &a_node)> NodeKeyFactory
Node-key factory called once per node during TreeBVH::traverse().
Definition EBGeometry_PackedBVH.hpp:312
size_t Midpoint2WaySplit(PrimAndBVList< P, BV > &a_list, const size_t a_begin, const size_t a_end) noexcept
Internal helper: 2-way spatial-midpoint split on the sub-range [a_begin, a_end).
Definition EBGeometry_TreeBVH.hpp:525
auto PrimitiveCentroidPartitioner
Partitioner that sorts primitives by centroid along the longest axis and splits into K pieces.
Definition EBGeometry_TreeBVH.hpp:214
void MidpointKWaySplit(PrimAndBVList< P, BV > &a_list, const size_t a_begin, const size_t a_end, const size_t a_K, std::vector< std::pair< size_t, size_t > > &a_groups)
Internal helper: recursively split [a_begin, a_end) into a_K groups via 2-way midpoint splits.
Definition EBGeometry_TreeBVH.hpp:574
auto BVCentroidPartitioner
Partitioner that sorts primitives by bounding-volume centroid along the longest axis and splits into ...
Definition EBGeometry_TreeBVH.hpp:247
auto BinnedSAHPartitioner
Partitioner using binned SAH with recursive 2-way subdivision into K groups.
Definition EBGeometry_TreeBVH.hpp:488
auto DefaultLeafPredicate
Default stop function: stop partitioning when the node holds fewer than K primitives.
Definition EBGeometry_TreeBVH.hpp:653
std::function< void(Array< std::pair< std::shared_ptr< const NodeType >, NodeKey >, K > &a_children)> ChildOrderer
Child-ordering callback for TreeBVH traversal.
Definition EBGeometry_PackedBVH.hpp:300
Construction
The preset BVH construction methods that the library's own BVH users accept.
Definition EBGeometry_PackedBVH.hpp:65
@ Nested
Bottom-up: leaves of consecutive primitives along a Nested (row-major) curve.
@ Hilbert
Bottom-up: leaves of consecutive primitives along a Hilbert curve.
@ Morton
Bottom-up: leaves of consecutive primitives along a Morton (Z-order) curve.
void SAHKWaySplit(PrimAndBVList< P, BV > &a_list, const size_t a_begin, const size_t a_end, const size_t a_K, std::vector< std::pair< size_t, size_t > > &a_groups, const bool a_longestAxisOnly=false)
Internal helper: recursively split [a_begin, a_end) into a_K groups via 2-way SAH.
Definition EBGeometry_TreeBVH.hpp:429
auto MidpointPartitioner
Partitioner that recursively bisects primitives by spatial midpoint (no sorting).
Definition EBGeometry_TreeBVH.hpp:621
constexpr T max(const T &a_a, const T &a_b) noexcept
The larger of two values.
Definition EBGeometry_Math.hpp:61
constexpr T min(const T &a_a, const T &a_b) noexcept
The smaller of two values.
Definition EBGeometry_Math.hpp:44
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.
T length(const Vec2T< T > &v) noexcept
Euclidean length of a 2D vector.
Vec2T< T > max(const Vec2T< T > &u, const Vec2T< T > &v) noexcept
Component-wise maximum of two vectors.
Fixed-size array with host- and device-callable members.
Definition EBGeometry_Array.hpp:33
Leaf-size settings for the preset construction methods, one per family of methods.
Definition EBGeometry_PackedBVH.hpp:115
Numeric limits, with the meanings of the std::numeric_limits members of the same names.
Definition EBGeometry_Math.hpp:91