Skip to content

Commit 65f956f

Browse files
authored
fix edge-case in bvh object removal and creation logic (#367)
* fix edge-case in bvh object removal logic * chore: add regression test for bvh add/remove * fix bug in bvh creation from exactly two leaves * chore: update changelog
1 parent 8322854 commit 65f956f

File tree

4 files changed

+105
-1
lines changed

4 files changed

+105
-1
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## Unreleased
2+
3+
### Fixed
4+
5+
- Fix bug in BVH tree node removal.
6+
- Fix bug in BVH tree building from exactly two leaves.
7+
18
## 0.22.0-beta.1
29

310
### Fixed

src/partitioning/bvh/bvh_tests.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use crate::bounding_volume::Aabb;
2+
use crate::math::{Real, Vector};
3+
use crate::partitioning::{Bvh, BvhBuildStrategy};
4+
5+
fn make_test_aabb(i: usize) -> Aabb {
6+
Aabb::from_half_extents(Vector::repeat(i as Real).into(), Vector::repeat(1.0))
7+
}
8+
9+
#[test]
10+
fn bvh_build_and_removal() {
11+
// Check various combination of building pattern and removal pattern.
12+
// The tree validity is asserted at every step.
13+
#[derive(Copy, Clone, Debug)]
14+
enum BuildPattern {
15+
Ploc,
16+
Binned,
17+
Insert,
18+
}
19+
20+
#[derive(Copy, Clone, Debug)]
21+
enum RemovalPattern {
22+
InOrder,
23+
RevOrder,
24+
EvenOdd,
25+
}
26+
27+
for build_pattern in [
28+
BuildPattern::Ploc,
29+
BuildPattern::Binned,
30+
BuildPattern::Insert,
31+
] {
32+
for removal_pattern in [
33+
RemovalPattern::InOrder,
34+
RemovalPattern::RevOrder,
35+
RemovalPattern::EvenOdd,
36+
] {
37+
for len in 1..=100 {
38+
std::println!(
39+
"Testing build: {:?}, removal: {:?}, len: {}",
40+
build_pattern,
41+
removal_pattern,
42+
len
43+
);
44+
let leaves: std::vec::Vec<_> = (0..len).map(make_test_aabb).collect();
45+
46+
let mut bvh = match build_pattern {
47+
BuildPattern::Binned => Bvh::from_leaves(BvhBuildStrategy::Binned, &leaves),
48+
BuildPattern::Ploc => Bvh::from_leaves(BvhBuildStrategy::Ploc, &leaves),
49+
BuildPattern::Insert => {
50+
let mut bvh = Bvh::new();
51+
for i in 0..len {
52+
bvh.insert(make_test_aabb(i), i as u32);
53+
bvh.assert_well_formed();
54+
}
55+
bvh
56+
}
57+
};
58+
59+
bvh.assert_well_formed();
60+
61+
match removal_pattern {
62+
RemovalPattern::InOrder => {
63+
// Remove in insertion order.
64+
for i in 0..len {
65+
bvh.remove(i as u32);
66+
bvh.assert_well_formed();
67+
}
68+
}
69+
RemovalPattern::RevOrder => {
70+
// Remove in reverse insertion order.
71+
for i in (0..len).rev() {
72+
bvh.remove(i as u32);
73+
bvh.assert_well_formed();
74+
}
75+
}
76+
RemovalPattern::EvenOdd => {
77+
// Remove even indices first, then odd.
78+
for i in (0..len).filter(|i| i % 2 == 0) {
79+
bvh.remove(i as u32);
80+
bvh.assert_well_formed();
81+
}
82+
for i in (0..len).filter(|i| i % 2 != 0) {
83+
bvh.remove(i as u32);
84+
bvh.assert_well_formed();
85+
}
86+
}
87+
}
88+
}
89+
}
90+
}
91+
}

src/partitioning/bvh/bvh_tree.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,13 +557,16 @@ impl Bvh {
557557
right: BvhNode::zeros(),
558558
});
559559
result.parents.push(BvhNodeIndex::default());
560+
result.leaf_node_indices[0] = BvhNodeIndex::left(0);
560561
}
561562
2 => {
562563
result.nodes.push(BvhNodeWide {
563564
left: workspace.rebuild_leaves[0],
564565
right: workspace.rebuild_leaves[1],
565566
});
566567
result.parents.push(BvhNodeIndex::default());
568+
result.leaf_node_indices[0] = BvhNodeIndex::left(0);
569+
result.leaf_node_indices[1] = BvhNodeIndex::right(0);
567570
}
568571
_ => {
569572
result.nodes.reserve(capacity);
@@ -712,7 +715,7 @@ impl Bvh {
712715
self.nodes[0].right = BvhNode::zeros();
713716
} else {
714717
// The sibling isn’t a leaf. It becomes the new root at index 0.
715-
self.nodes[0] = self.nodes[sibling.decompose().0];
718+
self.nodes[0] = self.nodes[self.nodes[sibling].children as usize];
716719
// Both parent pointers need to be updated since both nodes moved to the root.
717720
let new_root = &mut self.nodes[0];
718721
if new_root.left.is_leaf() {

src/partitioning/bvh/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ mod bvh_traverse;
1313
mod bvh_traverse_bvtt;
1414
mod bvh_tree;
1515
mod bvh_validation;
16+
17+
#[cfg(test)]
18+
mod bvh_tests;

0 commit comments

Comments
 (0)