parry3d/partitioning/bvh/
bvh_refit.rs

1use super::bvh_tree::{BvhNodeIndex, BvhNodeVec, BvhNodeWide};
2use super::{Bvh, BvhNode, BvhWorkspace};
3use crate::utils::VecMap;
4use alloc::vec::Vec;
5
6impl Bvh {
7    /// Performs a tree refitting with internal storage cache optimizations.
8    ///
9    /// Refitting is the action of ensuring that every node’s AABB encloses the AABBs of its
10    /// children. In addition, this method will:
11    /// - Ensure that nodes are stored internally in depth-first order for better cache locality
12    ///   on depth-first searches.
13    /// - Ensure that the leaf count on each node is correct.
14    /// - Propagate the [`BvhNode::is_changed`] flag changes detected by [`Self::insert_or_update_partially`]
15    ///   (if `change_detection_margin` was nonzero) from leaves to its ascendants.
16    pub fn refit(&mut self, workspace: &mut BvhWorkspace) {
17        Self::refit_buffers(
18            &mut self.nodes,
19            &mut workspace.refit_tmp,
20            &mut self.leaf_node_indices,
21            &mut self.parents,
22        );
23
24        // Swap the old nodes with the refitted ones.
25        core::mem::swap(&mut self.nodes, &mut workspace.refit_tmp);
26    }
27
28    pub(super) fn refit_buffers(
29        source: &mut BvhNodeVec,
30        target: &mut BvhNodeVec,
31        leaf_data: &mut VecMap<BvhNodeIndex>,
32        parents: &mut Vec<BvhNodeIndex>,
33    ) {
34        if source.is_empty() {
35            target.clear();
36            parents.clear();
37        } else if source[0].leaf_count() <= 2 {
38            // No actual refit to apply, just copy the root wide node.
39            target.clear();
40            parents.clear();
41            target.push(source[0]);
42            target[0].left.data.resolve_pending_change();
43            if target[0].right.leaf_count() > 0 {
44                target[0].right.data.resolve_pending_change();
45            }
46            parents.push(BvhNodeIndex::default());
47        } else if !source.is_empty() && source[0].leaf_count() > 2 {
48            target.resize(
49                source.len(),
50                BvhNodeWide {
51                    left: BvhNode::zeros(),
52                    right: BvhNode::zeros(),
53                },
54            );
55
56            let mut len = 1;
57
58            // Start with a special case for the root then recurse.
59            let left_child_id = source[0].left.children;
60            let right_child_id = source[0].right.children;
61
62            if !source[0].left.is_leaf() {
63                Self::refit_recurse(
64                    source,
65                    target,
66                    leaf_data,
67                    parents,
68                    left_child_id,
69                    &mut len,
70                    BvhNodeIndex::left(0),
71                );
72            } else {
73                target[0].left = source[0].left;
74                target[0].left.data.resolve_pending_change();
75
76                // NOTE: updating the leaf_data shouldn’t be needed here since the root
77                //       is always at 0.
78                // *self.leaf_data.get_mut_unknown_gen(left_child_id).unwrap() = BvhNodeIndex::left(0);
79            }
80
81            if !source[0].right.is_leaf() {
82                Self::refit_recurse(
83                    source,
84                    target,
85                    leaf_data,
86                    parents,
87                    right_child_id,
88                    &mut len,
89                    BvhNodeIndex::right(0),
90                );
91            } else {
92                target[0].right = source[0].right;
93                target[0].right.data.resolve_pending_change();
94                // NOTE: updating the leaf_data shouldn’t be needed here since the root
95                //       is always at 0.
96                // *self.leaf_data.get_mut_unknown_gen(right_child_id).unwrap() = BvhNodeIndex::right(0);
97            }
98
99            source.truncate(len as usize);
100            target.truncate(len as usize);
101            parents.truncate(len as usize);
102        }
103    }
104
105    fn refit_recurse(
106        source: &BvhNodeVec,
107        target: &mut BvhNodeVec,
108        leaf_data: &mut VecMap<BvhNodeIndex>,
109        parents: &mut [BvhNodeIndex],
110        source_id: u32,
111        target_id_mut: &mut u32,
112        parent: BvhNodeIndex,
113    ) {
114        let target_id = *target_id_mut;
115        *target_id_mut += 1;
116
117        let node = &source[source_id as usize];
118        let left_is_leaf = node.left.is_leaf();
119        let right_is_leaf = node.right.is_leaf();
120        let left_source_id = node.left.children;
121        let right_source_id = node.right.children;
122
123        if !left_is_leaf {
124            Self::refit_recurse(
125                source,
126                target,
127                leaf_data,
128                parents,
129                left_source_id,
130                target_id_mut,
131                BvhNodeIndex::left(target_id),
132            );
133        } else {
134            let node = &source[source_id as usize];
135            target[target_id as usize].left = node.left;
136            target[target_id as usize]
137                .left
138                .data
139                .resolve_pending_change();
140            leaf_data[node.left.children as usize] = BvhNodeIndex::left(target_id);
141        }
142
143        if !right_is_leaf {
144            Self::refit_recurse(
145                source,
146                target,
147                leaf_data,
148                parents,
149                right_source_id,
150                target_id_mut,
151                BvhNodeIndex::right(target_id),
152            );
153        } else {
154            let node = &source[source_id as usize];
155            target[target_id as usize].right = node.right;
156            target[target_id as usize]
157                .right
158                .data
159                .resolve_pending_change();
160            leaf_data[node.right.children as usize] = BvhNodeIndex::right(target_id);
161        }
162
163        let node = &target[target_id as usize];
164        target[parent] = node.left.merged(&node.right, target_id);
165        parents[target_id as usize] = parent;
166    }
167
168    /// Similar to [`Self::refit`] but without any optimization of the internal node storage layout.
169    ///
170    /// This can be faster than [`Self::refit`] but doesn’t reorder node to be more cache-efficient
171    /// on tree traversals.
172    pub fn refit_without_opt(&mut self) {
173        if self.leaf_count() > 2 {
174            let root = &self.nodes[0];
175            let left = root.left.children;
176            let right = root.right.children;
177            let left_is_leaf = root.left.is_leaf();
178            let right_is_leaf = root.right.is_leaf();
179
180            if !left_is_leaf {
181                self.recurse_refit_without_opt(left, BvhNodeIndex::left(0));
182            }
183            if !right_is_leaf {
184                self.recurse_refit_without_opt(right, BvhNodeIndex::right(0));
185            }
186        }
187    }
188
189    fn recurse_refit_without_opt(&mut self, node_id: u32, parent: BvhNodeIndex) {
190        let node = &self.nodes[node_id as usize];
191        let left = &node.left;
192        let right = &node.right;
193        let left_is_leaf = left.is_leaf();
194        let right_is_leaf = right.is_leaf();
195        let left_children = left.children;
196        let right_children = right.children;
197
198        if !left_is_leaf {
199            self.recurse_refit_without_opt(left_children, BvhNodeIndex::left(node_id));
200        } else {
201            self.nodes[node_id as usize]
202                .left
203                .data
204                .resolve_pending_change();
205        }
206        if !right_is_leaf {
207            self.recurse_refit_without_opt(right_children, BvhNodeIndex::right(node_id));
208        } else {
209            self.nodes[node_id as usize]
210                .right
211                .data
212                .resolve_pending_change();
213        }
214
215        let node = &self.nodes[node_id as usize];
216        let left = &node.left;
217        let right = &node.right;
218        let merged = left.merged(right, node_id);
219
220        self.nodes[parent] = merged;
221    }
222}