1#ifndef BVH_V2_SWEEP_SAH_BUILDER_H
2#define BVH_V2_SWEEP_SAH_BUILDER_H
17template <
typename Node>
31 std::span<const BBox> bboxes,
32 std::span<const Vec> centers,
50 std::span<const BBox> bboxes,
51 std::span<const Vec> centers,
55 marks_.resize(bboxes.size());
56 accum_.resize(bboxes.size());
61 return centers[i][axis] < centers[j][axis];
69 size_t first_right = begin;
73 for (
size_t i = end - 1; i > begin;) {
74 static constexpr size_t chunk_size = 32;
75 size_t next = i - std::min(i - begin, chunk_size);
76 auto right_cost =
static_cast<Scalar>(0.);
77 for (; i > next; --i) {
82 if (right_cost > best_split.
cost) {
90 for (
size_t i = begin; i < first_right; ++i)
92 for (
size_t i = first_right; i < end - 1; ++i) {
95 auto cost = left_cost +
accum_[i + 1];
96 if (cost < best_split.
cost)
97 best_split =
Split { i + 1, cost, axis };
98 else if (left_cost > best_split.
cost)
104 for (
size_t i = begin; i < split_pos; ++i)
marks_[
prim_ids_[axis][i]] =
true;
105 for (
size_t i = split_pos; i < end; ++i)
marks_[
prim_ids_[axis][i]] =
false;
108 std::optional<size_t>
try_split(
const BBox& bbox,
size_t begin,
size_t end)
override {
111 auto best_split =
Split { (begin + end + 1) / 2, leaf_cost, 0 };
116 if (best_split.cost >= leaf_cost) {
122 best_split.
pos = (begin + end + 1) / 2;
123 best_split.axis = bbox.
get_diagonal().get_largest_axis();
130 if (axis == best_split.axis)
132 std::stable_partition(
135 [&] (
size_t i) {
return marks_[i]; });
138 return std::make_optional(best_split.pos);
BVH_ALWAYS_INLINE T get_leaf_cost(size_t begin, size_t end, const BBox< T, N > &bbox) const
BVH_ALWAYS_INLINE T get_non_split_cost(size_t begin, size_t end, const BBox< T, N > &bbox) const
Single-threaded top-down builder that partitions primitives based on the Surface Area Heuristic (SAH)...
BVH_ALWAYS_INLINE SweepSahBuilder(std::span< const BBox > bboxes, std::span< const Vec > centers, const Config &config)
std::vector< size_t > & get_prim_ids() override
std::vector< size_t > prim_ids_[Node::dimension]
void find_best_split(size_t axis, size_t begin, size_t end, Split &best_split)
static BVH_ALWAYS_INLINE Bvh< Node > build(std::span< const BBox > bboxes, std::span< const Vec > centers, const Config &config={})
BVH_ALWAYS_INLINE void mark_primitives(size_t axis, size_t begin, size_t split_pos, size_t end)
std::vector< Scalar > accum_
std::optional< size_t > try_split(const BBox &bbox, size_t begin, size_t end) override
std::vector< bool > marks_
Base class for all SAH-based, top-down builders.
typename Node::Scalar Scalar
std::span< const BBox > bboxes_
BVH_ALWAYS_INLINE Vec< T, N > get_diagonal() const
static BVH_ALWAYS_INLINE constexpr BBox make_empty()
Binary BVH node, containing its bounds and an index into its children or the primitives it contains.
static constexpr size_t dimension
SplitHeuristic< Scalar > sah
SAH heuristic parameters that control how primitives are partitioned.
size_t max_leaf_size
Nodes that cannot be split based on the SAH and have a number of primitives larger than this will be ...