parry3d/partitioning/bvh/
bvh_traverse.rs1use super::BvhNode;
2use crate::math::Real;
3use crate::partitioning::Bvh;
4use smallvec::SmallVec;
5
6const TRAVERSAL_STACK_SIZE: usize = 32;
7
8pub struct Leaves<'a, Check: Fn(&BvhNode) -> bool> {
9 tree: &'a Bvh,
10 next: Option<&'a BvhNode>,
11 stack: SmallVec<[&'a BvhNode; TRAVERSAL_STACK_SIZE]>,
12 check: Check,
13}
14
15impl<'a, Check: Fn(&BvhNode) -> bool> Iterator for Leaves<'a, Check> {
16 type Item = u32;
17 fn next(&mut self) -> Option<Self::Item> {
18 loop {
19 if self.next.is_none() {
20 self.next = self.stack.pop();
21 }
22
23 let node = self.next.take()?;
24
25 if node.is_leaf() {
26 return Some(node.children);
27 }
28
29 let children = &self.tree.nodes[node.children as usize];
30 let left = &children.left;
31 let right = &children.right;
32
33 if (self.check)(left) {
34 self.next = Some(left);
35 }
36
37 if (self.check)(right) {
38 if self.next.is_none() {
39 self.next = Some(right);
40 } else {
41 self.stack.push(right);
42 }
43 }
44 }
45 }
46}
47
48pub trait BvhLeafCost {
50 fn cost(&self) -> Real;
54}
55
56impl BvhLeafCost for Real {
57 #[inline(always)]
58 fn cost(&self) -> Real {
59 *self
60 }
61}
62
63impl<T> BvhLeafCost for (Real, T) {
64 #[inline(always)]
65 fn cost(&self) -> Real {
66 self.0
67 }
68}
69
70impl Bvh {
71 pub fn leaves<F: Fn(&BvhNode) -> bool>(&self, check_node: F) -> Leaves<'_, F> {
80 if let Some(root) = self.nodes.first() {
81 let mut stack = SmallVec::default();
82 if root.right.leaf_count() > 0 {
83 stack.push(&root.right);
84 }
85
86 Leaves {
87 tree: self,
88 next: Some(&root.left),
89 stack,
90 check: check_node,
91 }
92 } else {
93 Leaves {
94 tree: self,
95 next: None,
96 stack: Default::default(),
97 check: check_node,
98 }
99 }
100 }
101}
102
103pub enum TraversalAction {
105 Continue,
107 Prune,
109 EarlyExit,
111}
112
113impl Bvh {
114 #[inline(always)]
115 pub(crate) fn traversal_stack() -> SmallVec<[u32; 32]> {
116 Default::default()
117 }
118
119 pub fn traverse(&self, mut check_node: impl FnMut(&BvhNode) -> TraversalAction) {
131 let mut stack = Self::traversal_stack();
132 let mut curr_id = 0;
133
134 if self.nodes.is_empty() {
135 return;
136 } else if self.nodes[0].right.leaf_count() == 0 {
137 let _ = check_node(&self.nodes[0].left);
139 return;
140 }
141
142 loop {
143 let node = &self.nodes[curr_id as usize];
144 let left = &node.left;
145 let right = &node.right;
146 let go_left = match check_node(left) {
147 TraversalAction::Continue => !left.is_leaf(),
148 TraversalAction::Prune => false,
149 TraversalAction::EarlyExit => return,
150 };
151 let go_right = match check_node(right) {
152 TraversalAction::Continue => !right.is_leaf(),
153 TraversalAction::Prune => false,
154 TraversalAction::EarlyExit => return,
155 };
156
157 match (go_left, go_right) {
158 (true, true) => {
159 curr_id = left.children;
160 stack.push(right.children);
161 }
162 (true, false) => curr_id = left.children,
163 (false, true) => curr_id = right.children,
164 (false, false) => {
165 let Some(next) = stack.pop() else {
166 return;
167 };
168 curr_id = next;
169 }
170 }
171 }
172 }
173
174 pub fn find_best<L: BvhLeafCost>(
176 &self,
177 max_cost: Real,
178 aabb_cost: impl Fn(&BvhNode, Real) -> Real,
179 leaf_cost: impl Fn(u32, Real) -> Option<L>,
180 ) -> Option<(u32, L)> {
181 let mut stack = Self::traversal_stack();
183 let mut best_val = None;
184 let mut best_cost = max_cost;
185 let mut best_id = u32::MAX;
186 let mut curr_id = 0;
187
188 if self.nodes.is_empty() {
189 return None;
190 } else if self.nodes[0].right.leaf_count() == 0 {
191 let leaf = &self.nodes[0].left;
193 if aabb_cost(leaf, max_cost) < max_cost {
194 let cost = leaf_cost(leaf.children, best_cost)?;
195 return (cost.cost() < max_cost).then_some((leaf.children, cost));
196 } else {
197 return None;
198 }
199 }
200
201 loop {
202 let node = &self.nodes[curr_id as usize];
203 let mut left = &node.left;
204 let mut right = &node.right;
205
206 let mut left_score = aabb_cost(left, best_cost);
207 let mut right_score = aabb_cost(right, best_cost);
208
209 if left_score > right_score {
210 core::mem::swap(&mut left_score, &mut right_score);
211 core::mem::swap(&mut left, &mut right);
212 }
213
214 let mut found_next = false;
215 if left_score < best_cost && left_score != Real::MAX {
216 if left.is_leaf() {
217 if let Some(primitive_val) = leaf_cost(left.children, best_cost) {
218 let primitive_score = primitive_val.cost();
219 if primitive_score < best_cost {
220 best_val = Some(primitive_val);
221 best_cost = primitive_score;
222 best_id = left.children;
223 }
224 }
225 } else {
226 curr_id = left.children;
227 found_next = true;
228 }
229 }
230
231 if right_score < best_cost && right_score != Real::MAX {
232 if right.is_leaf() {
233 if let Some(primitive_val) = leaf_cost(right.children, best_cost) {
234 let primitive_score = primitive_val.cost();
235 if primitive_score < best_cost {
236 best_val = Some(primitive_val);
237 best_cost = primitive_score;
238 best_id = right.children;
239 }
240 }
241 } else if found_next {
242 stack.push(right.children);
243 } else {
244 curr_id = right.children;
245 found_next = true;
246 }
247 }
248
249 if !found_next {
250 if let Some(next) = stack.pop() {
251 curr_id = next;
252 } else {
253 return best_val.map(|val| (best_id, val));
254 }
255 }
256 }
257 }
258}