-
-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf(bvh-region): more efficient range query
- Loading branch information
1 parent
dfc9989
commit d389485
Showing
7 changed files
with
190 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
mod closest; | ||
mod range; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use std::fmt::Debug; | ||
|
||
use arrayvec::ArrayVec; | ||
use geometry::aabb::Aabb; | ||
|
||
use crate::{Bvh, Node, utils::GetAabb}; | ||
|
||
impl<T: Debug> Bvh<T> { | ||
pub fn range<'a>( | ||
&'a self, | ||
target: Aabb, | ||
get_aabb: impl GetAabb<T> + 'a, | ||
) -> impl Iterator<Item = &'a T> + 'a { | ||
CollisionIter::new(self, target, get_aabb) | ||
} | ||
} | ||
|
||
pub struct CollisionIter<'a, T, F> { | ||
bvh: &'a Bvh<T>, | ||
target: Aabb, | ||
get_aabb: F, | ||
stack: ArrayVec<Node<'a, T>, 64>, | ||
current_leaf: Option<(&'a [T], usize)>, | ||
} | ||
|
||
impl<'a, T, F> CollisionIter<'a, T, F> | ||
where | ||
F: GetAabb<T>, | ||
{ | ||
fn new(bvh: &'a Bvh<T>, target: Aabb, get_aabb: F) -> Self { | ||
let mut stack = ArrayVec::new(); | ||
// Initialize stack with root if it collides | ||
match bvh.root() { | ||
Node::Internal(root) => { | ||
if root.aabb.collides(&target) { | ||
stack.push(Node::Internal(root)); | ||
} | ||
} | ||
Node::Leaf(leaf) => { | ||
// We'll handle collision checks in next() as we iterate through leaves | ||
stack.push(Node::Leaf(leaf)); | ||
} | ||
} | ||
|
||
Self { | ||
bvh, | ||
target, | ||
get_aabb, | ||
stack, | ||
current_leaf: None, | ||
} | ||
} | ||
} | ||
|
||
impl<'a, T, F> Iterator for CollisionIter<'a, T, F> | ||
where | ||
F: GetAabb<T>, | ||
{ | ||
type Item = &'a T; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
loop { | ||
// If we're currently iterating over a leaf's elements | ||
if let Some((leaf, index)) = &mut self.current_leaf { | ||
if *index < leaf.len() { | ||
let elem = &leaf[*index]; | ||
*index += 1; | ||
|
||
let elem_aabb = (self.get_aabb)(elem); | ||
if elem_aabb.collides(&self.target) { | ||
return Some(elem); | ||
} | ||
// If not colliding, continue to next element in leaf | ||
continue; | ||
} else { | ||
// Leaf exhausted | ||
self.current_leaf = None; | ||
} | ||
} | ||
|
||
// If no current leaf, pop from stack | ||
let node = self.stack.pop()?; | ||
match node { | ||
Node::Internal(internal) => { | ||
// Push children that potentially collide | ||
for child in internal.children(self.bvh) { | ||
match child { | ||
Node::Internal(child_node) => { | ||
if child_node.aabb.collides(&self.target) { | ||
self.stack.push(Node::Internal(child_node)); | ||
} | ||
} | ||
Node::Leaf(child_leaf) => { | ||
// We'll check collisions inside the leaf iteration | ||
self.stack.push(Node::Leaf(child_leaf)); | ||
} | ||
} | ||
} | ||
} | ||
Node::Leaf(leaf) => { | ||
// Start iterating over this leaf's elements | ||
self.current_leaf = Some((leaf, 0)); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters