16template <
typename Node>
70 template <
bool IsAnyHit,
typename Stack,
typename LeafFn,
typename InnerFn>
78 template <
bool IsAnyHit,
bool IsRobust,
typename Stack,
typename LeafFn,
typename InnerFn = IgnoreArgs>
83 template <
typename LeafFn = IgnoreArgs,
typename InnerFn = IgnoreArgs>
87 template <
typename LeafFn = IgnoreArgs>
88 inline void refit(LeafFn&& = {});
94template <
typename Node>
99 bvh.nodes.emplace_back();
101 std::stack<std::pair<size_t, size_t>> stack;
102 stack.emplace(root_id, 0);
103 while (!stack.empty()) {
104 auto [src_id, dst_id] = stack.top();
106 const auto& src_node = nodes[src_id];
107 auto& dst_node =
bvh.nodes[dst_id];
109 if (src_node.is_leaf()) {
110 dst_node.index.set_first_id(
bvh.prim_ids.size());
112 prim_ids.begin() + src_node.index.first_id(),
113 src_node.index.prim_count(),
114 std::back_inserter(
bvh.prim_ids));
116 dst_node.index.set_first_id(
bvh.nodes.size());
117 stack.emplace(src_node.index.first_id() + 0,
bvh.nodes.size() + 0);
118 stack.emplace(src_node.index.first_id() + 1,
bvh.nodes.size() + 1);
120 bvh.nodes.emplace_back();
121 bvh.nodes.emplace_back();
127template <
typename Node>
128template <
bool IsAnyHit,
typename Stack,
typename LeafFn,
typename InnerFn>
133 while (!stack.is_empty()) {
134 auto top = stack.pop();
135 while (top.prim_count() == 0) {
136 auto& left = nodes[top.first_id()];
137 auto& right = nodes[top.first_id() + 1];
138 auto [hit_left, hit_right, should_swap] = inner_fn(left, right);
141 auto near_index = left.index;
143 auto far_index = right.index;
145 std::swap(near_index, far_index);
146 stack.push(far_index);
149 }
else if (hit_right) {
157 [[maybe_unused]]
auto was_hit = leaf_fn(top.first_id(), top.first_id() + top.prim_count());
158 if constexpr (IsAnyHit) {
164template <
typename Node>
165template <
bool IsAnyHit,
bool IsRobust,
typename Stack,
typename LeafFn,
typename InnerFn>
167 auto inv_dir = ray.template get_inv_dir<!IsRobust>();
168 auto inv_dir_pad_or_inv_org = IsRobust ? ray.
pad_inv_dir(inv_dir) : -inv_dir * ray.
org;
171 traverse_top_down<IsAnyHit>(start, stack, leaf_fn, [&] (
const Node& left,
const Node& right) {
172 inner_fn(left, right);
173 std::pair<Scalar, Scalar> intr_left, intr_right;
174 if constexpr (IsRobust) {
175 intr_left = left .
intersect_robust(ray, inv_dir, inv_dir_pad_or_inv_org, octant);
176 intr_right = right.
intersect_robust(ray, inv_dir, inv_dir_pad_or_inv_org, octant);
178 intr_left = left .
intersect_fast(ray, inv_dir, inv_dir_pad_or_inv_org, octant);
179 intr_right = right.
intersect_fast(ray, inv_dir, inv_dir_pad_or_inv_org, octant);
181 return std::make_tuple(
182 intr_left.first <= intr_left.second,
183 intr_right.first <= intr_right.second,
184 !IsAnyHit && intr_left.first > intr_right.first);
188template <
typename Node>
189template <
typename LeafFn,
typename InnerFn>
191 std::vector<size_t> parents(nodes.size(), 0);
192 for (
size_t i = 0; i < nodes.size(); ++i) {
193 if (nodes[i].is_leaf())
195 parents[nodes[i].index.first_id()] = i;
196 parents[nodes[i].index.first_id() + 1] = i;
198 std::vector<bool> seen(nodes.size(),
false);
199 for (
size_t i = nodes.size(); i-- > 0;) {
200 if (!nodes[i].is_leaf())
204 for (
size_t j = parents[i];; j = parents[j]) {
205 auto& node = nodes[j];
206 if (seen[j] || !seen[node.index.first_id()] || !seen[node.index.first_id() + 1])
214template <
typename Node>
215template <
typename LeafFn>
217 traverse_bottom_up(leaf_fn, [&] (
Node& node) {
220 node.
set_bbox(left.get_bbox().extend(right.get_bbox()));
224template <
typename Node>
226 stream.
write(nodes.size());
227 stream.
write(prim_ids.size());
228 for (
auto&& node : nodes)
229 node.serialize(stream);
230 for (
auto&& prim_id : prim_ids)
231 stream.
write(prim_id);
234template <
typename Node>
237 bvh.nodes.resize(stream.
read<
size_t>());
238 bvh.prim_ids.resize(stream.
read<
size_t>());
239 for (
auto& node :
bvh.nodes)
241 for (
auto& prim_id :
bvh.prim_ids)
242 prim_id = stream.
read<
size_t>();
Stream of data that can be used to serialize data structures.
bool write(const T &data)
bool operator==(const Bvh &other) const
bool operator!=(const Bvh &other) const
std::vector< Node > nodes
void refit(LeafFn &&={})
Refits the BVH, using the given function object to recompute the bounding box of the leaves.
static BVH_ALWAYS_INLINE bool is_left_sibling(size_t node_id)
Returns whether the node located at the given index is the left child of its parent.
void intersect(const Ray &ray, Index start, Stack &, LeafFn &&, InnerFn &&={}) const
Intersects the BVH with a single ray, using the given function to intersect the contents of a leaf.
void serialize(OutputStream &) const
static Bvh deserialize(InputStream &)
Bvh extract_bvh(size_t root_id) const
Extracts the BVH rooted at the given node index.
Bvh & operator=(Bvh &&)=default
typename Node::Scalar Scalar
static BVH_ALWAYS_INLINE size_t get_sibling_id(size_t node_id)
Returns the index of a sibling of a node.
void traverse_top_down(Index start, Stack &, LeafFn &&, InnerFn &&) const
Traverses the BVH from the given index in start using the provided stack.
static BVH_ALWAYS_INLINE size_t get_left_sibling_id(size_t node_id)
Returns the index of the left sibling of the node.
static BVH_ALWAYS_INLINE size_t get_right_sibling_id(size_t node_id)
Returns the index of the right sibling of the node.
std::vector< size_t > prim_ids
typename Node::Index Index
void traverse_bottom_up(LeafFn &&={}, InnerFn &&={})
Traverses this BVH from the bottom to the top, using the given function objects to process leaves and...
BVH_ALWAYS_INLINE const Node & get_root() const
Returns the root node of this BVH.
BVH_ALWAYS_INLINE Type first_id() const
Binary BVH node, containing its bounds and an index into its children or the primitives it contains.
static BVH_ALWAYS_INLINE Node deserialize(InputStream &stream)
bvh::v2::Index< IndexBits, PrimCountBits > Index
BVH_ALWAYS_INLINE std::pair< T, T > intersect_robust(const Ray< T, Dim > &ray, const Vec< T, Dim > &inv_dir, const Vec< T, Dim > &inv_dir_pad, const Octant &octant) const
Robust ray-node intersection routine. See "Robust BVH Ray Traversal", by T. Ize.
BVH_ALWAYS_INLINE void set_bbox(const BBox< T, Dim > &bbox)
Index index
Index to the children of an inner node, or to the primitives for a leaf node.
BVH_ALWAYS_INLINE std::pair< T, T > intersect_fast(const Ray< T, Dim > &ray, const Vec< T, Dim > &inv_dir, const Vec< T, Dim > &inv_org, const Octant &octant) const
static BVH_ALWAYS_INLINE Vec< T, N > pad_inv_dir(const Vec< T, N > &inv_dir)
BVH_ALWAYS_INLINE Octant get_octant() const