diff options
| author | Sébastien Crozet <developer@crozet.re> | 2020-10-06 16:53:54 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-06 16:53:54 +0200 |
| commit | 24a25f8ae7a62c5c5afa24825b063fbb1b603922 (patch) | |
| tree | 5302f5282fe963b72dbd9e94f422994b6ab11eca /src/pipeline/query_pipeline.rs | |
| parent | 99f28ba4b4a14254b4160a191cbeb15211cdd2d2 (diff) | |
| parent | 25b8486ebf8bdfa0d165300a30877293e9e40c51 (diff) | |
| download | rapier-24a25f8ae7a62c5c5afa24825b063fbb1b603922.tar.gz rapier-24a25f8ae7a62c5c5afa24825b063fbb1b603922.tar.bz2 rapier-24a25f8ae7a62c5c5afa24825b063fbb1b603922.zip | |
Merge pull request #28 from dimforge/raycast
Add the QueryPipeline for ray-casting and other geometrical queries in the future
Diffstat (limited to 'src/pipeline/query_pipeline.rs')
| -rw-r--r-- | src/pipeline/query_pipeline.rs | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/src/pipeline/query_pipeline.rs b/src/pipeline/query_pipeline.rs new file mode 100644 index 0000000..32f59fc --- /dev/null +++ b/src/pipeline/query_pipeline.rs @@ -0,0 +1,113 @@ +use crate::dynamics::RigidBodySet; +use crate::geometry::{Collider, ColliderHandle, ColliderSet, Ray, RayIntersection, WQuadtree}; + +/// A pipeline for performing queries on all the colliders of a scene. +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +pub struct QueryPipeline { + quadtree: WQuadtree<ColliderHandle>, + tree_built: bool, + dilation_factor: f32, +} + +impl Default for QueryPipeline { + fn default() -> Self { + Self::new() + } +} + +impl QueryPipeline { + /// Initializes an empty query pipeline. + pub fn new() -> Self { + Self { + quadtree: WQuadtree::new(), + tree_built: false, + dilation_factor: 0.01, + } + } + + /// Update the acceleration structure on the query pipeline. + pub fn update(&mut self, bodies: &RigidBodySet, colliders: &ColliderSet) { + if !self.tree_built { + let data = colliders.iter().map(|(h, c)| (h, c.compute_aabb())); + self.quadtree.clear_and_rebuild(data, self.dilation_factor); + // FIXME: uncomment this once we handle insertion/removals properly. + // self.tree_built = true; + return; + } + + for (_, body) in bodies + .iter_active_dynamic() + .chain(bodies.iter_active_kinematic()) + { + for handle in &body.colliders { + self.quadtree.pre_update(*handle) + } + } + + self.quadtree.update(colliders, self.dilation_factor); + } + + /// Find the closest intersection between a ray and a set of collider. + /// + /// # Parameters + /// - `position`: the position of this shape. + /// - `ray`: the ray to cast. + /// - `max_toi`: the maximum time-of-impact that can be reported by this cast. This effectively + /// limits the length of the ray to `ray.dir.norm() * max_toi`. Use `f32::MAX` for an unbounded ray. + pub fn cast_ray<'a>( + &self, + colliders: &'a ColliderSet, + ray: &Ray, + max_toi: f32, + ) -> Option<(ColliderHandle, &'a Collider, RayIntersection)> { + // TODO: avoid allocation? + let mut inter = Vec::new(); + self.quadtree.cast_ray(ray, max_toi, &mut inter); + + let mut best = f32::MAX; + let mut result = None; + + for handle in inter { + let collider = &colliders[handle]; + if let Some(inter) = collider.shape().cast_ray(collider.position(), ray, max_toi) { + if inter.toi < best { + best = inter.toi; + result = Some((handle, collider, inter)); + } + } + } + + result + } + + /// Find the all intersections between a ray and a set of collider and passes them to a callback. + /// + /// # Parameters + /// - `position`: the position of this shape. + /// - `ray`: the ray to cast. + /// - `max_toi`: the maximum time-of-impact that can be reported by this cast. This effectively + /// limits the length of the ray to `ray.dir.norm() * max_toi`. Use `f32::MAX` for an unbounded ray. + /// - `callback`: function executed on each collider for which a ray intersection has been found. + /// There is no guarantees on the order the results will be yielded. If this callback returns `false`, + /// this method will exit early, ignory any further raycast. + pub fn interferences_with_ray<'a>( + &self, + colliders: &'a ColliderSet, + ray: &Ray, + max_toi: f32, + mut callback: impl FnMut(ColliderHandle, &'a Collider, RayIntersection) -> bool, + ) { + // TODO: avoid allocation? + let mut inter = Vec::new(); + self.quadtree.cast_ray(ray, max_toi, &mut inter); + + for handle in inter { + let collider = &colliders[handle]; + if let Some(inter) = collider.shape().cast_ray(collider.position(), ray, max_toi) { + if !callback(handle, collider, inter) { + return; + } + } + } + } +} |
