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.children_are_ordered_after_parents = false;
277 }
278 self.nodes.push(best_sibling_candidate);
279 let new_node_id = self.nodes.len();
280 self.nodes.push(new_node); self.parents.push(new_parent_id as u32);
282 self.parents.push(new_parent_id as u32);
283
284 if !self.primitives_to_nodes.is_empty() {
286 let end = new_node.first_index + new_node.prim_count;
288 if self.primitives_to_nodes.len() < end as usize {
289 self.primitives_to_nodes.resize(end as usize, INVALID);
291 }
292 update_primitives_to_nodes_for_node(
293 &new_node,
294 new_node_id,
295 &self.primitive_indices,
296 &mut self.primitives_to_nodes,
297 )
298 }
299
300 self.refit_from_fast(new_parent_id);
302
303 new_node_id
304 }
305
306 pub fn remove_primitive(&mut self, primitive_id: u32) {
313 assert!(
314 !self.uses_spatial_splits,
315 "Removing primitives while using spatial splits is currently unsupported as it would require a mapping \
316from one primitive to multiple nodes in `Bvh2::primitives_to_nodes`."
317 );
318 let remove_primitive_id = primitive_id;
319 self.init_parents_if_uninit();
320 self.init_primitives_to_nodes_if_uninit();
321
322 let node_id = self.primitives_to_nodes[remove_primitive_id as usize];
323
324 let node = &self.nodes[node_id as usize];
325 assert!(node.is_leaf());
326 if node.prim_count == 1 {
327 let removed_leaf = self.remove_leaf(node_id as usize);
328 self.primitive_indices_freelist
329 .push(removed_leaf.first_index);
330 self.primitive_indices[removed_leaf.first_index as usize] = INVALID;
331 } else {
332 let node = &mut self.nodes[node_id as usize];
336
337 let start = node.first_index as usize;
338 let end = (node.first_index + node.prim_count) as usize;
339 let last = end - 1;
340 let mut spare_spot_id = start;
341 for node_prim_id in start..end {
343 let direct_prim_id = self.primitive_indices[node_prim_id];
344 if direct_prim_id == remove_primitive_id {
345 break;
346 }
347 spare_spot_id += 1;
348 }
349 if spare_spot_id < last {
350 self.primitive_indices[spare_spot_id] = self.primitive_indices[last];
351 }
352 self.primitive_indices_freelist.push(last as u32);
354 self.primitive_indices[last] = INVALID;
355
356 assert!(node.prim_count > 1);
357 node.prim_count -= 1;
358 }
359
360 if self.primitives_to_nodes.len() > remove_primitive_id as usize {
361 self.primitives_to_nodes[remove_primitive_id as usize] = INVALID;
362 }
363 }
364
365 pub fn insert_primitive(
381 &mut self,
382 aabb: Aabb,
383 primitive_id: u32,
384 stack: &mut HeapStack<SiblingInsertionCandidate>,
385 ) -> usize {
386 self.init_primitives_to_nodes_if_uninit();
387 self.init_parents_if_uninit();
388 if self.primitives_to_nodes.len() <= primitive_id as usize {
389 self.primitives_to_nodes
390 .resize(primitive_id as usize + 1, INVALID);
391 }
392 let first_index = if let Some(free_slot) = self.primitive_indices_freelist.pop() {
393 self.primitive_indices[free_slot as usize] = primitive_id;
394 free_slot
395 } else {
396 self.primitive_indices.push(primitive_id);
397 self.primitive_indices.len() as u32 - 1
398 };
399 let new_node_id = self.insert_leaf(Bvh2Node::new(aabb, 1, first_index), stack);
400 self.primitives_to_nodes[primitive_id as usize] = new_node_id as u32;
401 new_node_id
402 }
403}
404
405#[doc(hidden)]
412pub fn build_bvh2_by_insertion<T: Boundable>(primitives: &[T]) -> Bvh2 {
413 let mut bvh = Bvh2::default();
414
415 let mut stack = HeapStack::new_with_capacity(1000);
416
417 for prim_id in 1..primitives.len() {
418 bvh.insert_primitive(primitives[prim_id].aabb(), prim_id as u32, &mut stack);
419 }
420
421 bvh.max_depth = (bvh.depth(0) + 1).max(DEFAULT_MAX_STACK_DEPTH);
423
424 #[cfg(debug_assertions)]
425 {
426 bvh.validate(primitives, false, true);
427 }
428
429 bvh
430}
431
432#[doc(hidden)]
436pub fn slow_leaf_reinsertion(bvh: &mut Bvh2) {
437 let mut stack = HeapStack::new_with_capacity(1000);
438 for node_id in 1..bvh.nodes.len() {
439 if bvh.nodes.len() <= node_id {
440 break;
441 }
442 if bvh.nodes[node_id].is_leaf() {
443 assert!(!bvh.nodes[bvh.parents[node_id] as usize].is_leaf());
445 let removed_leaf = bvh.remove_leaf(node_id);
447 bvh.insert_leaf(removed_leaf, &mut stack);
449 }
450 }
451 #[cfg(debug_assertions)]
452 {
453 bvh.validate_parents();
454 }
455}
456
457#[cfg(test)]
458mod tests {
459 use std::time::Duration;
460
461 use super::*;
462 use crate::{BvhBuildParams, bvh2::builder::build_bvh2, test_util::geometry::demoscene};
463
464 #[test]
465 fn build_by_insertion() {
466 for res in 30..=32 {
467 let tris = demoscene(res, 0);
468 let bvh = build_bvh2_by_insertion(&tris);
469 bvh.validate(&tris, false, false);
470 }
471 }
472
473 #[test]
474 fn test_slow_leaf_reinsertion() {
475 for res in 30..=32 {
476 let tris = demoscene(res, 0);
477
478 let mut bvh = build_bvh2(
479 &tris,
480 BvhBuildParams::medium_build(),
481 &mut Duration::default(),
482 );
483 bvh.init_primitives_to_nodes_if_uninit();
484 bvh.init_parents_if_uninit();
485 slow_leaf_reinsertion(&mut bvh);
486 bvh.validate(&tris, false, false);
487 bvh.reorder_in_stack_traversal_order();
488 bvh.validate(&tris, false, false);
489 }
490 }
491
492 #[test]
493 fn remove_all_primitives() {
494 let tris = demoscene(16, 0);
495
496 let bvh1 = build_bvh2(
499 &tris,
500 BvhBuildParams::fastest_build(),
501 &mut Duration::default(),
502 );
503 let bvh2 = build_bvh2(
504 &tris,
505 BvhBuildParams::medium_build(),
506 &mut Duration::default(),
507 );
508
509 let mut found_leaf_with_multiple_nodes = false;
510 for node in &bvh2.nodes {
511 if node.prim_count > 1 {
512 found_leaf_with_multiple_nodes = true;
513 break;
514 }
515 }
516 if !found_leaf_with_multiple_nodes {
517 panic!(
518 "Test remove_all_primitives bvh2 should have some nodes that contain multiple primitives"
519 );
520 }
521
522 for bvh in &mut [bvh1, bvh2] {
523 bvh.init_primitives_to_nodes_if_uninit();
524 bvh.init_parents_if_uninit();
525 bvh.validate(&tris, false, false);
526
527 for primitive_id in 0..tris.len() as u32 {
528 bvh.remove_primitive(primitive_id);
529 bvh.validate(&tris, false, false);
530 }
531
532 assert_eq!(bvh.nodes.len(), 0);
533 assert_eq!(bvh.parents.len(), 0);
534 assert_eq!(bvh.primitives_to_nodes.len(), 0);
535 bvh.validate(&tris, false, false);
536 }
537 }
538
539 #[test]
540 fn remove_and_insert_all_primitives() {
541 let tris = demoscene(16, 0);
542
543 let mut bvh = build_bvh2(
544 &tris,
545 BvhBuildParams::medium_build(),
546 &mut Duration::default(),
547 );
548 bvh.init_primitives_to_nodes_if_uninit();
549 bvh.init_parents_if_uninit();
550 bvh.validate(&tris, false, false);
551
552 let mut stack = HeapStack::new_with_capacity(1000);
553
554 for primitive_id in 0..tris.len() as u32 {
555 bvh.remove_primitive(primitive_id);
556 bvh.validate(&tris, false, false);
557 }
558
559 for primitive_id in 0..tris.len() as u32 {
560 bvh.insert_primitive(tris[primitive_id as usize].aabb(), primitive_id, &mut stack);
561 bvh.validate_primitives_to_nodes();
562 }
563
564 bvh.validate(&tris, false, false);
565 }
566
567 #[test]
568 fn insert_leaf_clears_children_are_ordered_after_parents() {
569 let tris = demoscene(16, 0);
576
577 let mut bvh = build_bvh2(
578 &tris,
579 BvhBuildParams::medium_build(),
580 &mut Duration::default(),
581 );
582 bvh.init_primitives_to_nodes_if_uninit();
583 bvh.init_parents_if_uninit();
584
585 let mut stack = HeapStack::new_with_capacity(1000);
587 let primitive_ids = (0..tris.len() as u32).step_by(32).collect::<Vec<_>>();
588
589 for &primitive_id in &primitive_ids {
590 bvh.remove_primitive(primitive_id);
591 }
592
593 bvh.reorder_in_stack_traversal_order();
596 assert!(bvh.children_are_ordered_after_parents);
597
598 for &primitive_id in &primitive_ids {
599 let mut aabb = tris[primitive_id as usize].aabb();
600 aabb.min -= 0.05;
601 aabb.max += 0.05;
602 bvh.insert_primitive(aabb, primitive_id, &mut stack);
603 }
604
605 bvh.max_depth = (bvh.depth(0) + 1).max(DEFAULT_MAX_STACK_DEPTH);
606
607 bvh.validate(&tris, false, false);
608
609 for node in &mut bvh.nodes {
611 if node.is_leaf() {
612 let mut aabb = *node.aabb();
613 aabb.max += 0.1;
614 node.set_aabb(aabb);
615 }
616 }
617 bvh.refit_all();
618
619 for (node_id, node) in bvh.nodes.iter().enumerate() {
621 if !node.is_leaf() {
622 let children_aabb = bvh.nodes[node.first_index as usize]
623 .aabb()
624 .union(bvh.nodes[node.first_index as usize + 1].aabb());
625 assert_eq!(
626 *node.aabb(),
627 children_aabb,
628 "node {node_id} does not fit its children after refit_all()"
629 );
630 }
631 }
632 }
633}