bevy_rapier3d/plugin/
narrow_phase.rs

1use crate::math::{Real, Vect};
2use crate::plugin::context::{RapierContextColliders, RapierContextSimulation, RapierRigidBodySet};
3use bevy::prelude::*;
4use rapier::geometry::{Contact, ContactManifold, ContactPair, SolverContact, SolverFlags};
5
6impl RapierContextSimulation {
7    /// All the contact pairs involving the non-sensor collider attached to the given entity.
8    ///
9    /// The returned contact pairs identify pairs of colliders with intersecting bounding-volumes.
10    /// To check if any geometric contact happened between the collider shapes, check
11    /// [`ContactPairView::has_any_active_contact`].
12    pub fn contact_pairs_with<'a, 'b: 'a>(
13        &'a self,
14        context_colliders: &'b RapierContextColliders,
15        rigidbody_set: &'b RapierRigidBodySet,
16        collider: Entity,
17    ) -> impl Iterator<Item = ContactPairView<'a>> {
18        context_colliders
19            .entity2collider
20            .get(&collider)
21            .into_iter()
22            .flat_map(|h| {
23                self.narrow_phase
24                    .contact_pairs_with(*h)
25                    .map(|raw| ContactPairView {
26                        context_colliders,
27                        rigidbody_set,
28                        raw,
29                    })
30            })
31    }
32
33    /// All the intersection pairs involving the collider attached to the given entity, where at least one collider
34    /// involved in the intersection is a sensor.
35    ///
36    /// The returned contact pairs identify pairs of colliders (where at least one is a sensor) with
37    /// intersecting bounding-volumes. To check if any geometric overlap happened between the collider shapes, check
38    /// the returned boolean.
39    pub fn intersection_pairs_with<'a, 'b: 'a>(
40        &'a self,
41        rapier_colliders: &'b RapierContextColliders,
42        collider: Entity,
43    ) -> impl Iterator<Item = (Entity, Entity, bool)> + 'a {
44        rapier_colliders
45            .entity2collider
46            .get(&collider)
47            .into_iter()
48            .flat_map(|h| {
49                self.narrow_phase
50                    .intersection_pairs_with(*h)
51                    .filter_map(|(h1, h2, inter)| {
52                        let e1 = rapier_colliders.collider_entity(h1);
53                        let e2 = rapier_colliders.collider_entity(h2);
54                        match (e1, e2) {
55                            (Some(e1), Some(e2)) => Some((e1, e2, inter)),
56                            _ => None,
57                        }
58                    })
59            })
60    }
61
62    /// The contact pair involving two specific colliders.
63    ///
64    /// If this returns `None`, there is no contact between the two colliders.
65    /// If this returns `Some`, then there may be a contact between the two colliders. Check the
66    /// result [`ContactPairView::has_any_active_contact`] method to see if there is an actual contact.
67    pub fn contact_pair<'a, 'b: 'a>(
68        &'a self,
69        context_colliders: &'b RapierContextColliders,
70        rigidbody_set: &'b RapierRigidBodySet,
71        collider1: Entity,
72        collider2: Entity,
73    ) -> Option<ContactPairView<'a>> {
74        let h1 = context_colliders.entity2collider.get(&collider1)?;
75        let h2 = context_colliders.entity2collider.get(&collider2)?;
76        self.narrow_phase
77            .contact_pair(*h1, *h2)
78            .map(|raw| ContactPairView {
79                context_colliders,
80                rigidbody_set,
81                raw,
82            })
83    }
84
85    /// The intersection pair involving two specific colliders (at least one being a sensor).
86    ///
87    /// If this returns `None` or `Some(false)`, then there is no intersection between the two colliders.
88    /// If this returns `Some(true)`, then there may be an intersection between the two colliders.
89    pub fn intersection_pair(
90        &self,
91        rapier_colliders: &RapierContextColliders,
92        collider1: Entity,
93        collider2: Entity,
94    ) -> Option<bool> {
95        let h1 = rapier_colliders.entity2collider.get(&collider1)?;
96        let h2 = rapier_colliders.entity2collider.get(&collider2)?;
97        self.narrow_phase.intersection_pair(*h1, *h2)
98    }
99
100    /// All the contact pairs detected during the last timestep.
101    pub fn contact_pairs<'a, 'b: 'a>(
102        &'a self,
103        context_colliders: &'b RapierContextColliders,
104        rigidbody_set: &'b RapierRigidBodySet,
105    ) -> impl Iterator<Item = ContactPairView<'a>> {
106        self.narrow_phase
107            .contact_pairs()
108            .map(|raw| ContactPairView {
109                context_colliders,
110                rigidbody_set,
111                raw,
112            })
113    }
114
115    /// All the intersection pairs detected during the last timestep.
116    pub fn intersection_pairs<'a, 'b: 'a>(
117        &'a self,
118        rapier_colliders: &'b RapierContextColliders,
119    ) -> impl Iterator<Item = (Entity, Entity, bool)> + 'a {
120        self.narrow_phase
121            .intersection_pairs()
122            .filter_map(|(h1, h2, inter)| {
123                let e1 = rapier_colliders.collider_entity(h1);
124                let e2 = rapier_colliders.collider_entity(h2);
125                match (e1, e2) {
126                    (Some(e1), Some(e2)) => Some((e1, e2, inter)),
127                    _ => None,
128                }
129            })
130    }
131}
132
133/// Read-only access to the properties of a contact manifold.
134pub struct ContactManifoldView<'a> {
135    rigidbody_set: &'a RapierRigidBodySet,
136    /// The raw contact manifold from Rapier.
137    pub raw: &'a ContactManifold,
138}
139
140impl ContactManifoldView<'_> {
141    /// The number of points on this contact manifold.
142    pub fn num_points(&self) -> usize {
143        self.raw.points.len()
144    }
145
146    /// Retrieves the i-th point of this contact manifold.
147    pub fn point(&self, i: usize) -> Option<ContactView<'_>> {
148        self.raw.points.get(i).map(|raw| ContactView { raw })
149    }
150
151    /// The contacts points.
152    pub fn points(&self) -> impl ExactSizeIterator<Item = ContactView<'_>> {
153        self.raw.points.iter().map(|raw| ContactView { raw })
154    }
155
156    /// The contact normal of all the contacts of this manifold, expressed in the local space of the first shape.
157    pub fn local_n1(&self) -> Vect {
158        self.raw.local_n1.into()
159    }
160
161    /// The contact normal of all the contacts of this manifold, expressed in the local space of the second shape.
162    pub fn local_n2(&self) -> Vect {
163        self.raw.local_n2.into()
164    }
165
166    /// The first subshape involved in this contact manifold.
167    ///
168    /// This is zero if the first shape is not a composite shape.
169    pub fn subshape1(&self) -> u32 {
170        self.raw.subshape1
171    }
172
173    /// The second subshape involved in this contact manifold.
174    ///
175    /// This is zero if the second shape is not a composite shape.
176    pub fn subshape2(&self) -> u32 {
177        self.raw.subshape2
178    }
179
180    /// The first rigid-body involved in this contact manifold.
181    pub fn rigid_body1(&self) -> Option<Entity> {
182        self.raw
183            .data
184            .rigid_body1
185            .and_then(|h| self.rigidbody_set.rigid_body_entity(h))
186    }
187
188    /// The second rigid-body involved in this contact manifold.
189    pub fn rigid_body2(&self) -> Option<Entity> {
190        self.raw
191            .data
192            .rigid_body2
193            .and_then(|h| self.rigidbody_set.rigid_body_entity(h))
194    }
195
196    /// Flags used to control some aspects of the constraints solver for this contact manifold.
197    pub fn solver_flags(&self) -> SolverFlags {
198        self.raw.data.solver_flags
199    }
200
201    /// The world-space contact normal shared by all the contact in this contact manifold.
202    pub fn normal(&self) -> Vect {
203        self.raw.data.normal.into()
204    }
205
206    /// The contacts that will be seen by the constraints solver for computing forces.
207    pub fn num_solver_contacts(&self) -> usize {
208        self.raw.data.solver_contacts.len()
209    }
210
211    /// Gets the i-th solver contact.
212    pub fn solver_contact(&self, i: usize) -> Option<SolverContactView<'_>> {
213        self.raw
214            .data
215            .solver_contacts
216            .get(i)
217            .map(|raw| SolverContactView { raw })
218    }
219
220    /// The contacts that will be seen by the constraints solver for computing forces.
221    pub fn solver_contacts(&self) -> impl ExactSizeIterator<Item = SolverContactView<'_>> {
222        self.raw
223            .data
224            .solver_contacts
225            .iter()
226            .map(|raw| SolverContactView { raw })
227    }
228
229    /// The relative dominance of the bodies involved in this contact manifold.
230    pub fn relative_dominance(&self) -> i16 {
231        self.raw.data.relative_dominance
232    }
233
234    /// A user-defined piece of data.
235    pub fn user_data(&self) -> u32 {
236        self.raw.data.user_data
237    }
238}
239
240impl ContactManifoldView<'_> {
241    /// Returns the contact with the smallest distance (i.e. the largest penetration depth).
242    pub fn find_deepest_contact(&self) -> Option<ContactView<'_>> {
243        self.raw
244            .find_deepest_contact()
245            .map(|raw| ContactView { raw })
246    }
247}
248
249/// Read-only access to the properties of a single contact.
250pub struct ContactView<'a> {
251    /// The raw contact from Rapier.
252    pub raw: &'a Contact,
253}
254
255impl ContactView<'_> {
256    /// The contact point in the local-space of the first shape.
257    pub fn local_p1(&self) -> Vect {
258        self.raw.local_p1.into()
259    }
260
261    /// The contact point in the local-space of the second shape.
262    pub fn local_p2(&self) -> Vect {
263        self.raw.local_p2.into()
264    }
265
266    /// The distance between the two contact points.
267    pub fn dist(&self) -> Real {
268        self.raw.dist
269    }
270
271    /// The feature ID of the first shape involved in the contact.
272    pub fn fid1(&self) -> u32 {
273        self.raw.fid1.0
274    }
275
276    /// The feature ID of the second shape involved in the contact.
277    pub fn fid2(&self) -> u32 {
278        self.raw.fid2.0
279    }
280
281    /// The impulse, along the contact normal, applied by this contact to the first collider's rigid-body.
282    ///
283    /// The impulse applied to the second collider's rigid-body is given by `-impulse`.
284    pub fn impulse(&self) -> Real {
285        self.raw.data.impulse
286    }
287
288    /// The friction impulse along the vector orthonormal to the contact normal, applied to the first
289    /// collider's rigid-body.
290    #[cfg(feature = "dim2")]
291    pub fn tangent_impulse(&self) -> Real {
292        self.raw.data.tangent_impulse.x
293    }
294
295    /// The friction impulse along the vector orthonormal to the contact normal, applied to the first
296    /// collider's rigid-body.
297    #[cfg(feature = "dim3")]
298    pub fn tangent_impulse(&self) -> [Real; 2] {
299        self.raw.data.tangent_impulse.into()
300    }
301}
302
303/// Read-only access to the properties of a single solver contact.
304pub struct SolverContactView<'a> {
305    /// The raw solver contact from Rapier.
306    pub raw: &'a SolverContact,
307}
308
309impl SolverContactView<'_> {
310    /// The world-space contact point.
311    pub fn point(&self) -> Vect {
312        self.raw.point.into()
313    }
314    /// The distance between the two original contacts points along the contact normal.
315    /// If negative, this is measures the penetration depth.
316    pub fn dist(&self) -> Real {
317        self.raw.dist
318    }
319    /// The effective friction coefficient at this contact point.
320    pub fn friction(&self) -> Real {
321        self.raw.friction
322    }
323    /// The effective restitution coefficient at this contact point.
324    pub fn restitution(&self) -> Real {
325        self.raw.restitution
326    }
327    /// The desired tangent relative velocity at the contact point.
328    ///
329    /// This is set to zero by default. Set to a non-zero value to
330    /// simulate, e.g., conveyor belts.
331    pub fn tangent_velocity(&self) -> Vect {
332        self.raw.tangent_velocity.into()
333    }
334    /// Whether or not this contact existed during the last timestep.
335    pub fn is_new(&self) -> bool {
336        self.raw.is_new == 1.0
337    }
338}
339
340/// Read-only access to the properties of a contact pair.
341pub struct ContactPairView<'a> {
342    context_colliders: &'a RapierContextColliders,
343    rigidbody_set: &'a RapierRigidBodySet,
344    /// The raw contact pair from Rapier.
345    pub raw: &'a ContactPair,
346}
347
348impl ContactPairView<'_> {
349    /// The first collider involved in this contact pair.
350    pub fn collider1(&self) -> Option<Entity> {
351        self.context_colliders.collider_entity(self.raw.collider1)
352    }
353
354    /// The second collider involved in this contact pair.
355    pub fn collider2(&self) -> Option<Entity> {
356        self.context_colliders.collider_entity(self.raw.collider2)
357    }
358
359    /// The number of contact manifolds detected for this contact pair.
360    pub fn manifolds_len(&self) -> usize {
361        self.raw.manifolds.len()
362    }
363
364    /// Gets the i-th contact manifold.
365    pub fn manifold(&self, i: usize) -> Option<ContactManifoldView<'_>> {
366        self.raw.manifolds.get(i).map(|raw| ContactManifoldView {
367            rigidbody_set: self.rigidbody_set,
368            raw,
369        })
370    }
371
372    /// Iterate through all the contact manifolds of this contact pair.
373    pub fn manifolds(&self) -> impl ExactSizeIterator<Item = ContactManifoldView<'_>> {
374        self.raw.manifolds.iter().map(|raw| ContactManifoldView {
375            rigidbody_set: self.rigidbody_set,
376            raw,
377        })
378    }
379
380    /// Is there any active contact in this contact pair?
381    pub fn has_any_active_contact(&self) -> bool {
382        self.raw.has_any_active_contact
383    }
384
385    /// Finds the contact with the smallest signed distance.
386    ///
387    /// If the colliders involved in this contact pair are penetrating, then
388    /// this returns the contact with the largest penetration depth.
389    ///
390    /// Returns a reference to the contact, as well as the contact manifold
391    /// it is part of.
392    pub fn find_deepest_contact(&self) -> Option<(ContactManifoldView<'_>, ContactView<'_>)> {
393        self.raw.find_deepest_contact().map(|(manifold, contact)| {
394            (
395                ContactManifoldView {
396                    rigidbody_set: self.rigidbody_set,
397                    raw: manifold,
398                },
399                ContactView { raw: contact },
400            )
401        })
402    }
403}