1use core::f32;
2
3use crate::{
4 Boundable, INVALID,
5 aabb::Aabb,
6 bvh2::{Bvh2, Bvh2Node, update_primitives_to_nodes_for_node},
7 faststack::{FastStack, HeapStack},
8};
9
10use super::DEFAULT_MAX_STACK_DEPTH;
11
12#[doc(hidden)]
14#[derive(Debug, Default, Clone, Copy)]
15pub struct SiblingInsertionCandidate {
16 inherited_cost: f32,
17 index: u32,
18}
19
20impl Bvh2 {
21 pub fn remove_leaf(&mut self, node_id: usize) -> Bvh2Node {
32 assert!(
33 !self.uses_spatial_splits,
34 "Removing leaves while using spatial splits is currently unsupported as it would require a mapping \
35from one primitive to multiple nodes in `Bvh2::primitives_to_nodes`."
36 );
37
38 let node_to_remove = self.nodes[node_id];
39 assert!(node_to_remove.is_leaf());
40
41 if self.nodes.len() == 1 {
42 self.nodes.clear();
44 self.parents.clear();
45 self.primitives_to_nodes.clear();
46 return node_to_remove;
47 }
48
49 if !self.primitives_to_nodes.is_empty() {
51 for node_prim_id in
53 node_to_remove.first_index..node_to_remove.first_index + node_to_remove.prim_count
54 {
55 let direct_prim_id = self.primitive_indices[node_prim_id as usize];
56 self.primitives_to_nodes[direct_prim_id as usize] = INVALID;
57 }
58 }
59
60 let sibling_id = Bvh2Node::get_sibling_id(node_id);
61 debug_assert_eq!(self.parents[node_id], self.parents[sibling_id]); let mut parent_id = self.parents[node_id] as usize;
63
64 self.nodes[parent_id] = self.nodes[sibling_id];
66 let sibling = &mut self.nodes[parent_id];
67 if sibling.is_leaf() {
68 update_primitives_to_nodes_for_node(
70 sibling,
71 parent_id,
72 &self.primitive_indices,
73 &mut self.primitives_to_nodes,
74 )
75 } else {
76 let left_sibling_child = sibling.first_index as usize;
78 self.parents[left_sibling_child] = parent_id as u32;
79 self.parents[left_sibling_child + 1] = parent_id as u32;
80 }
81 let end_nodes = node_id >= self.nodes.len() - 2;
87 if end_nodes {
88 self.nodes.pop().unwrap();
90 self.nodes.pop().unwrap();
91 self.parents.pop().unwrap();
92 self.parents.pop().unwrap();
93 } else {
94 let dst_left_id = Bvh2Node::get_left_sibling_id(node_id);
95 let dst_right_id = Bvh2Node::get_right_sibling_id(node_id);
96
97 let src_left_id = self.nodes.len() as u32 - 2;
98 let src_right_id = Bvh2Node::get_sibling_id32(src_left_id);
99 let src_right_parent = self.parents.pop().unwrap();
100 let src_left_parent = self.parents.pop().unwrap();
101
102 self.parents[dst_left_id] = src_left_parent;
103 self.parents[dst_right_id] = src_right_parent;
104
105 debug_assert_eq!(src_left_parent, src_right_parent); let parent_of_relocated = &mut self.nodes[src_left_parent as usize];
107 debug_assert!(!parent_of_relocated.is_leaf());
108 debug_assert_eq!(parent_of_relocated.first_index, src_left_id);
109 debug_assert_eq!(parent_of_relocated.first_index + 1, src_right_id);
110 self.nodes[src_left_parent as usize].first_index = dst_left_id as u32;
112
113 let right_src_sibling = self.nodes.pop().unwrap(); if right_src_sibling.is_leaf() {
115 update_primitives_to_nodes_for_node(
117 &right_src_sibling,
118 dst_right_id,
119 &self.primitive_indices,
120 &mut self.primitives_to_nodes,
121 );
122 } else {
123 self.parents[right_src_sibling.first_index as usize] = dst_right_id as u32;
125 self.parents[right_src_sibling.first_index as usize + 1] = dst_right_id as u32;
126 }
127 self.nodes[dst_right_id] = right_src_sibling;
128
129 let left_src_sibling = self.nodes.pop().unwrap(); if left_src_sibling.is_leaf() {
131 update_primitives_to_nodes_for_node(
133 &left_src_sibling,
134 dst_left_id,
135 &self.primitive_indices,
136 &mut self.primitives_to_nodes,
137 );
138 } else {
139 self.parents[left_src_sibling.first_index as usize] = dst_left_id as u32;
141 self.parents[left_src_sibling.first_index as usize + 1] = dst_left_id as u32;
142 }
143 self.nodes[dst_left_id] = left_src_sibling;
144
145 if parent_id as u32 == src_left_id {
147 parent_id = dst_left_id;
148 }
149 if parent_id as u32 == src_right_id {
150 parent_id = dst_right_id;
151 }
152 }
153
154 self.refit_from_fast(parent_id);
156
157 self.children_are_ordered_after_parents = false;
158 node_to_remove
160 }
161
162 pub fn insert_leaf(
181 &mut self,
182 new_node: Bvh2Node,
183 stack: &mut HeapStack<SiblingInsertionCandidate>,
184 ) -> usize {
185 assert!(new_node.is_leaf());
186
187 if self.nodes.is_empty() {
188 self.nodes.push(new_node);
189 self.parents.clear();
190 self.parents.push(0);
191 return 0;
192 }
193
194 self.init_parents_if_uninit();
195
196 let mut min_cost = f32::MAX;
197 let mut best_sibling_candidate_id = 0;
198 let mut max_stack_len = 1;
199 let new_node_cost = new_node.aabb().half_area();
200
201 stack.clear();
202 let root_aabb = self.nodes[0].aabb();
203
204 stack.push(SiblingInsertionCandidate {
206 inherited_cost: root_aabb.union(new_node.aabb()).half_area() - root_aabb.half_area(),
207 index: 0,
208 });
209 while let Some(sibling_candidate) = stack.pop() {
210 let current_node_index = sibling_candidate.index as usize;
211
212 let candidate = &self.nodes[current_node_index];
213
214 let direct_cost = candidate.aabb().union(new_node.aabb()).half_area();
215 let total_cost = direct_cost + sibling_candidate.inherited_cost;
216
217 if total_cost < min_cost {
218 min_cost = total_cost;
219 best_sibling_candidate_id = current_node_index;
220 }
221
222 if !candidate.is_leaf() {
224 let inherited_cost = total_cost - candidate.aabb().half_area();
225 let min_subtree_cost = new_node_cost + inherited_cost;
226 if min_subtree_cost < min_cost {
227 stack.push(SiblingInsertionCandidate {
228 inherited_cost,
229 index: candidate.first_index,
230 });
231 stack.push(SiblingInsertionCandidate {
232 inherited_cost,
233 index: candidate.first_index + 1,
234 });
235 max_stack_len = stack.len().max(max_stack_len);
236 }
237 }
238 }
239
240 if max_stack_len * 2 > stack.cap() {
241 stack.reserve(max_stack_len * 2);
242 }
243
244 let best_sibling_candidate = self.nodes[best_sibling_candidate_id];
245
246 let new_sibling_id = self.nodes.len() as u32;
250 let new_parent = Bvh2Node::new(
251 new_node.aabb().union(best_sibling_candidate.aabb()),
252 0,
253 new_sibling_id,
254 );
255
256 let new_parent_id = best_sibling_candidate_id;
258 self.nodes[new_parent_id] = new_parent;
259
260 if best_sibling_candidate.is_leaf() {
261 update_primitives_to_nodes_for_node(
263 &best_sibling_candidate,
264 new_sibling_id as usize,
265 &self.primitive_indices,
266 &mut self.primitives_to_nodes,
267 )
268 } else {
269 self.parents[best_sibling_candidate.first_index as usize] = new_sibling_id;
272 self.parents[best_sibling_candidate.first_index as usize + 1] = new_sibling_id;
273 }
274 self.nodes.push(best_sibling_candidate);
275 let new_node_id = self.nodes.len();
276 self.nodes.push(new_node); self.parents.push(new_parent_id as u32);
278 self.parents.push(new_parent_id as u32);
279
280 if !self.primitives_to_nodes.is_empty() {
282 let end = new_node.first_index + new_node.prim_count;
284 if self.primitives_to_nodes.len() < end as usize {
285 self.primitives_to_nodes.resize(end as usize, INVALID);
287 }
288 update_primitives_to_nodes_for_node(
289 &new_node,
290 new_node_id,
291 &self.primitive_indices,
292 &mut self.primitives_to_nodes,
293 )
294 }
295
296 self.refit_from_fast(new_parent_id);
298
299 new_node_id
300 }
301
302 pub fn remove_primitive(&mut self, primitive_id: u32) {
309 assert!(
310 !self.uses_spatial_splits,
311 "Removing primitives while using spatial splits is currently unsupported as it would require a mapping \
312from one primitive to multiple nodes in `Bvh2::primitives_to_nodes`."
313 );
314 let remove_primitive_id = primitive_id;
315 self.init_parents_if_uninit();
316 self.init_primitives_to_nodes_if_uninit();
317
318 let node_id = self.primitives_to_nodes[remove_primitive_id as usize];
319
320 let node = &self.nodes[node_id as usize];
321 assert!(node.is_leaf());
322 if node.prim_count == 1 {
323 let removed_leaf = self.remove_leaf(node_id as usize);
324 self.primitive_indices_freelist
325 .push(removed_leaf.first_index);
326 self.primitive_indices[removed_leaf.first_index as usize] = INVALID;
327 } else {
328 let node = &mut self.nodes[node_id as usize];
332
333 let start = node.first_index as usize;
334 let end = (node.first_index + node.prim_count) as usize;
335 let last = end - 1;
336 let mut spare_spot_id = start;
337 for node_prim_id in start..end {
339 let direct_prim_id = self.primitive_indices[node_prim_id];
340 if direct_prim_id == remove_primitive_id {
341 break;
342 }
343 spare_spot_id += 1;
344 }
345 if spare_spot_id < last {
346 self.primitive_indices[spare_spot_id] = self.primitive_indices[last];
347 }
348 self.primitive_indices_freelist.push(last as u32);
350 self.primitive_indices[last] = INVALID;
351
352 assert!(node.prim_count > 1);
353 node.prim_count -= 1;
354 }
355
356 if self.primitives_to_nodes.len() > remove_primitive_id as usize {
357 self.primitives_to_nodes[remove_primitive_id as usize] = INVALID;
358 }
359 }
360
361 pub fn insert_primitive(
377 &mut self,
378 aabb: Aabb,
379 primitive_id: u32,
380 stack: &mut HeapStack<SiblingInsertionCandidate>,
381 ) -> usize {
382 self.init_primitives_to_nodes_if_uninit();
383 self.init_parents_if_uninit();
384 if self.primitives_to_nodes.len() <= primitive_id as usize {
385 self.primitives_to_nodes
386 .resize(primitive_id as usize + 1, INVALID);
387 }
388 let first_index = if let Some(free_slot) = self.primitive_indices_freelist.pop() {
389 self.primitive_indices[free_slot as usize] = primitive_id;
390 free_slot
391 } else {
392 self.primitive_indices.push(primitive_id);
393 self.primitive_indices.len() as u32 - 1
394 };
395 let new_node_id = self.insert_leaf(Bvh2Node::new(aabb, 1, first_index), stack);
396 self.primitives_to_nodes[primitive_id as usize] = new_node_id as u32;
397 new_node_id
398 }
399}
400
401#[doc(hidden)]
408pub fn build_bvh2_by_insertion<T: Boundable>(primitives: &[T]) -> Bvh2 {
409 let mut bvh = Bvh2::default();
410
411 let mut stack = HeapStack::new_with_capacity(1000);
412
413 for prim_id in 1..primitives.len() {
414 bvh.insert_primitive(primitives[prim_id].aabb(), prim_id as u32, &mut stack);
415 }
416
417 bvh.max_depth = (bvh.depth(0) + 1).max(DEFAULT_MAX_STACK_DEPTH);
419
420 #[cfg(debug_assertions)]
421 {
422 bvh.validate(primitives, false, true);
423 }
424
425 bvh
426}
427
428#[doc(hidden)]
432pub fn slow_leaf_reinsertion(bvh: &mut Bvh2) {
433 let mut stack = HeapStack::new_with_capacity(1000);
434 for node_id in 1..bvh.nodes.len() {
435 if bvh.nodes.len() <= node_id {
436 break;
437 }
438 if bvh.nodes[node_id].is_leaf() {
439 assert!(!bvh.nodes[bvh.parents[node_id] as usize].is_leaf());
441 let removed_leaf = bvh.remove_leaf(node_id);
443 bvh.insert_leaf(removed_leaf, &mut stack);
445 }
446 }
447 #[cfg(debug_assertions)]
448 {
449 bvh.validate_parents();
450 }
451}
452
453#[cfg(test)]
454mod tests {
455 use std::time::Duration;
456
457 use super::*;
458 use crate::{BvhBuildParams, bvh2::builder::build_bvh2, test_util::geometry::demoscene};
459
460 #[test]
461 fn build_by_insertion() {
462 for res in 30..=32 {
463 let tris = demoscene(res, 0);
464 let bvh = build_bvh2_by_insertion(&tris);
465 bvh.validate(&tris, false, false);
466 }
467 }
468
469 #[test]
470 fn test_slow_leaf_reinsertion() {
471 for res in 30..=32 {
472 let tris = demoscene(res, 0);
473
474 let mut bvh = build_bvh2(
475 &tris,
476 BvhBuildParams::medium_build(),
477 &mut Duration::default(),
478 );
479 bvh.init_primitives_to_nodes_if_uninit();
480 bvh.init_parents_if_uninit();
481 slow_leaf_reinsertion(&mut bvh);
482 bvh.validate(&tris, false, false);
483 bvh.reorder_in_stack_traversal_order();
484 bvh.validate(&tris, false, false);
485 }
486 }
487
488 #[test]
489 fn remove_all_primitives() {
490 let tris = demoscene(16, 0);
491
492 let bvh1 = build_bvh2(
495 &tris,
496 BvhBuildParams::fastest_build(),
497 &mut Duration::default(),
498 );
499 let bvh2 = build_bvh2(
500 &tris,
501 BvhBuildParams::medium_build(),
502 &mut Duration::default(),
503 );
504
505 let mut found_leaf_with_multiple_nodes = false;
506 for node in &bvh2.nodes {
507 if node.prim_count > 1 {
508 found_leaf_with_multiple_nodes = true;
509 break;
510 }
511 }
512 if !found_leaf_with_multiple_nodes {
513 panic!(
514 "Test remove_all_primitives bvh2 should have some nodes that contain multiple primitives"
515 );
516 }
517
518 for bvh in &mut [bvh1, bvh2] {
519 bvh.init_primitives_to_nodes_if_uninit();
520 bvh.init_parents_if_uninit();
521 bvh.validate(&tris, false, false);
522
523 for primitive_id in 0..tris.len() as u32 {
524 bvh.remove_primitive(primitive_id);
525 bvh.validate(&tris, false, false);
526 }
527
528 assert_eq!(bvh.nodes.len(), 0);
529 assert_eq!(bvh.parents.len(), 0);
530 assert_eq!(bvh.primitives_to_nodes.len(), 0);
531 bvh.validate(&tris, false, false);
532 }
533 }
534
535 #[test]
536 fn remove_and_insert_all_primitives() {
537 let tris = demoscene(16, 0);
538
539 let mut bvh = build_bvh2(
540 &tris,
541 BvhBuildParams::medium_build(),
542 &mut Duration::default(),
543 );
544 bvh.init_primitives_to_nodes_if_uninit();
545 bvh.init_parents_if_uninit();
546 bvh.validate(&tris, false, false);
547
548 let mut stack = HeapStack::new_with_capacity(1000);
549
550 for primitive_id in 0..tris.len() as u32 {
551 bvh.remove_primitive(primitive_id);
552 bvh.validate(&tris, false, false);
553 }
554
555 for primitive_id in 0..tris.len() as u32 {
556 bvh.insert_primitive(tris[primitive_id as usize].aabb(), primitive_id, &mut stack);
557 bvh.validate_primitives_to_nodes();
558 }
559
560 bvh.validate(&tris, false, false);
561 }
562}