parry3d/partitioning/bvh/
bvh_binned_build.rs1use super::bvh_tree::{BvhBuildStrategy, BvhNodeIndex, BvhNodeWide};
2use super::{Bvh, BvhNode, BvhWorkspace};
3use crate::bounding_volume::{Aabb, BoundingVolume};
4use crate::math::Real;
5
6impl Bvh {
7 pub fn rebuild(&mut self, workspace: &mut BvhWorkspace, strategy: BvhBuildStrategy) {
12 if self.nodes.len() < 2 {
13 return;
16 }
17
18 workspace.rebuild_leaves.clear();
19 for node in self.nodes.iter() {
20 if node.left.is_leaf() {
21 workspace.rebuild_leaves.push(node.left);
22 }
23 if node.right.is_leaf() {
24 workspace.rebuild_leaves.push(node.right);
25 }
26 }
27
28 self.nodes.clear();
29 self.parents.clear();
30 self.nodes.push(BvhNodeWide::zeros());
31 self.parents.push(BvhNodeIndex::default());
32
33 match strategy {
34 BvhBuildStrategy::Binned => self.rebuild_range_binned(0, &mut workspace.rebuild_leaves),
35 BvhBuildStrategy::Ploc => self.rebuild_range_ploc(0, &mut workspace.rebuild_leaves),
36 }
37 }
38
39 pub(crate) fn rebuild_range_binned(&mut self, target_node_id: u32, leaves: &mut [BvhNode]) {
40 const NUM_BINS: usize = 8;
43 const BIN_EPSILON: Real = 1.0e-5;
44
45 let mut bins = [BvhBin::default(); NUM_BINS];
46
47 assert!(leaves.len() > 1);
48
49 let centroid_aabb = Aabb::from_points(leaves.iter().map(|node| node.center()));
50 let bins_axis = centroid_aabb.extents().imax();
51 let bins_range = [centroid_aabb.mins[bins_axis], centroid_aabb.maxs[bins_axis]];
52
53 let k1 = NUM_BINS as Real * (1.0 - BIN_EPSILON) / (bins_range[1] - bins_range[0]);
55 let k0 = bins_range[0];
56 for leaf in &*leaves {
57 let bin_id = (k1 * (leaf.center()[bins_axis] - k0)) as usize;
58 let bin = &mut bins[bin_id];
59 bin.aabb.merge(&leaf.aabb());
60 bin.leaf_count += 1;
61 }
62
63 let mut right_merges = bins;
65 let mut right_acc = bins[NUM_BINS - 1];
66
67 for i in 1..NUM_BINS - 1 {
68 right_acc.aabb.merge(&right_merges[NUM_BINS - 1 - i].aabb);
69 right_acc.leaf_count += &right_merges[NUM_BINS - 1 - i].leaf_count;
70 right_merges[NUM_BINS - 1 - i] = right_acc;
71 }
72
73 let mut best_cost = Real::MAX;
74 let mut best_plane = 0;
75 let mut left_merge = bins[0];
76 let mut best_leaf_count = bins[0].leaf_count;
77
78 for i in 0..NUM_BINS - 1 {
79 let right = &right_merges[i + 1];
80
81 let cost = left_merge.aabb.volume() * left_merge.leaf_count as Real
82 + right.aabb.volume() * right.leaf_count as Real;
83 if cost < best_cost {
84 best_cost = cost;
85 best_plane = i;
86 best_leaf_count = left_merge.leaf_count;
87 }
88
89 left_merge.aabb.merge(&bins[i + 1].aabb);
90 left_merge.leaf_count += bins[i + 1].leaf_count;
91 }
92
93 let mut mid = best_leaf_count as usize;
95
96 if mid == 0 || mid == leaves.len() {
99 mid = leaves.len() / 2;
100 } else {
101 let bin = |leaves: &mut [BvhNode], id: usize| {
104 let node = &leaves[id];
105 (k1 * (node.center()[bins_axis] - k0)) as usize
106 };
107
108 let mut left_id = 0;
109 let mut right_id = mid;
110
111 'outer: while left_id != mid && right_id != leaves.len() {
112 while bin(leaves, left_id) <= best_plane {
113 left_id += 1;
114
115 if left_id == mid {
116 break 'outer;
117 }
118 }
119
120 while bin(leaves, right_id) > best_plane {
121 right_id += 1;
122
123 if right_id == leaves.len() {
124 break 'outer;
125 }
126 }
127
128 leaves.swap(left_id, right_id);
129 left_id += 1;
130 right_id += 1;
131 }
132 }
133
134 let (left_leaves, right_leaves) = leaves.split_at_mut(mid);
136
137 assert!(!left_leaves.is_empty() && !right_leaves.is_empty());
138
139 if left_leaves.len() == 1 {
141 let target = &mut self.nodes[target_node_id as usize];
142 target.left = left_leaves[0];
143
144 if target.left.is_leaf() {
145 self.leaf_node_indices[target.left.children as usize] =
146 BvhNodeIndex::left(target_node_id);
147 } else {
148 self.parents[target.left.children as usize] = BvhNodeIndex::left(target_node_id);
149 }
150 } else {
151 let left_id = self.nodes.len() as u32;
152 self.nodes.push(BvhNodeWide::zeros());
153 self.parents.push(BvhNodeIndex::left(target_node_id));
154 self.rebuild_range_binned(left_id, left_leaves);
155 self.nodes[target_node_id as usize].left = self.nodes[left_id as usize].merged(left_id);
156 }
157
158 if right_leaves.len() == 1 {
159 let target = &mut self.nodes[target_node_id as usize];
160 target.right = right_leaves[0];
161
162 if target.right.is_leaf() {
163 self.leaf_node_indices[target.right.children as usize] =
164 BvhNodeIndex::right(target_node_id);
165 } else {
166 self.parents[target.right.children as usize] = BvhNodeIndex::right(target_node_id);
167 }
168 } else {
169 let right_id = self.nodes.len() as u32;
170 self.nodes.push(BvhNodeWide::zeros());
171 self.parents.push(BvhNodeIndex::right(target_node_id));
172 self.rebuild_range_binned(right_id, right_leaves);
173 self.nodes[target_node_id as usize].right =
174 self.nodes[right_id as usize].merged(right_id);
175 }
176 }
177}
178
179#[derive(Copy, Clone, Debug)]
180struct BvhBin {
181 aabb: Aabb,
182 leaf_count: u32,
183}
184
185impl Default for BvhBin {
186 fn default() -> Self {
187 Self {
188 aabb: Aabb::new_invalid(),
189 leaf_count: 0,
190 }
191 }
192}