rapier3d/geometry/
contact_pair.rs

1use crate::dynamics::{RigidBodyHandle, RigidBodySet};
2use crate::geometry::{ColliderHandle, ColliderSet, Contact, ContactManifold};
3use crate::math::{Point, Real, TangentImpulse, Vector};
4use crate::pipeline::EventHandler;
5use crate::prelude::CollisionEventFlags;
6use parry::query::ContactManifoldsWorkspace;
7
8use super::CollisionEvent;
9
10#[cfg(doc)]
11use super::Collider;
12
13bitflags::bitflags! {
14    #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
15    #[derive(Copy, Clone, PartialEq, Eq, Debug)]
16    /// Flags affecting the behavior of the constraints solver for a given contact manifold.
17    pub struct SolverFlags: u32 {
18        /// The constraint solver will take this contact manifold into
19        /// account for force computation.
20        const COMPUTE_IMPULSES = 0b001;
21    }
22}
23
24impl Default for SolverFlags {
25    fn default() -> Self {
26        SolverFlags::COMPUTE_IMPULSES
27    }
28}
29
30#[derive(Copy, Clone, Debug)]
31#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
32/// A single contact between two collider.
33pub struct ContactData {
34    /// The impulse, along the contact normal, applied by this contact to the first collider's rigid-body.
35    ///
36    /// The impulse applied to the second collider's rigid-body is given by `-impulse`.
37    pub impulse: Real,
38    /// The friction impulse along the vector orthonormal to the contact normal, applied to the first
39    /// collider's rigid-body.
40    pub tangent_impulse: TangentImpulse<Real>,
41    /// The impulse retained for warmstarting the next simulation step.
42    pub warmstart_impulse: Real,
43    /// The friction impulse retained for warmstarting the next simulation step.
44    pub warmstart_tangent_impulse: TangentImpulse<Real>,
45}
46
47impl Default for ContactData {
48    fn default() -> Self {
49        Self {
50            impulse: 0.0,
51            tangent_impulse: na::zero(),
52            warmstart_impulse: 0.0,
53            warmstart_tangent_impulse: na::zero(),
54        }
55    }
56}
57
58#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
59#[derive(Copy, Clone, Debug)]
60/// The description of all the contacts between a pair of colliders.
61pub struct IntersectionPair {
62    /// Are the colliders intersecting?
63    pub intersecting: bool,
64    /// Was a `CollisionEvent::Started` emitted for this collider?
65    pub(crate) start_event_emitted: bool,
66}
67
68impl IntersectionPair {
69    pub(crate) fn new() -> Self {
70        Self {
71            intersecting: false,
72            start_event_emitted: false,
73        }
74    }
75
76    pub(crate) fn emit_start_event(
77        &mut self,
78        bodies: &RigidBodySet,
79        colliders: &ColliderSet,
80        collider1: ColliderHandle,
81        collider2: ColliderHandle,
82        events: &dyn EventHandler,
83    ) {
84        self.start_event_emitted = true;
85        events.handle_collision_event(
86            bodies,
87            colliders,
88            CollisionEvent::Started(collider1, collider2, CollisionEventFlags::SENSOR),
89            None,
90        );
91    }
92
93    pub(crate) fn emit_stop_event(
94        &mut self,
95        bodies: &RigidBodySet,
96        colliders: &ColliderSet,
97        collider1: ColliderHandle,
98        collider2: ColliderHandle,
99        events: &dyn EventHandler,
100    ) {
101        self.start_event_emitted = false;
102        events.handle_collision_event(
103            bodies,
104            colliders,
105            CollisionEvent::Stopped(collider1, collider2, CollisionEventFlags::SENSOR),
106            None,
107        );
108    }
109}
110
111#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
112#[derive(Clone)]
113/// The description of all the contacts between a pair of colliders.
114pub struct ContactPair {
115    /// The first collider involved in the contact pair.
116    pub collider1: ColliderHandle,
117    /// The second collider involved in the contact pair.
118    pub collider2: ColliderHandle,
119    /// The set of contact manifolds between the two colliders.
120    ///
121    /// All contact manifold contain themselves contact points between the colliders.
122    /// Note that contact points in the contact manifold do not take into account the
123    /// [`Collider::contact_skin`] which only affects the constraint solver and the
124    /// [`SolverContact`].
125    pub manifolds: Vec<ContactManifold>,
126    /// Is there any active contact in this contact pair?
127    pub has_any_active_contact: bool,
128    /// Was a `CollisionEvent::Started` emitted for this collider?
129    pub(crate) start_event_emitted: bool,
130    pub(crate) workspace: Option<ContactManifoldsWorkspace>,
131}
132
133impl ContactPair {
134    pub(crate) fn new(collider1: ColliderHandle, collider2: ColliderHandle) -> Self {
135        Self {
136            collider1,
137            collider2,
138            has_any_active_contact: false,
139            manifolds: Vec::new(),
140            start_event_emitted: false,
141            workspace: None,
142        }
143    }
144
145    /// Clears all the contacts of this contact pair.
146    pub fn clear(&mut self) {
147        self.manifolds.clear();
148        self.has_any_active_contact = false;
149        self.workspace = None;
150    }
151
152    /// The sum of all the impulses applied by contacts on this contact pair.
153    pub fn total_impulse(&self) -> Vector<Real> {
154        self.manifolds
155            .iter()
156            .map(|m| m.total_impulse() * m.data.normal)
157            .sum()
158    }
159
160    /// The sum of the magnitudes of the contacts on this contact pair.
161    pub fn total_impulse_magnitude(&self) -> Real {
162        self.manifolds
163            .iter()
164            .fold(0.0, |a, m| a + m.total_impulse())
165    }
166
167    /// The magnitude and (unit) direction of the maximum impulse on this contact pair.
168    pub fn max_impulse(&self) -> (Real, Vector<Real>) {
169        let mut result = (0.0, Vector::zeros());
170
171        for m in &self.manifolds {
172            let impulse = m.total_impulse();
173
174            if impulse > result.0 {
175                result = (impulse, m.data.normal);
176            }
177        }
178
179        result
180    }
181
182    /// Finds the contact with the smallest signed distance.
183    ///
184    /// If the colliders involved in this contact pair are penetrating, then
185    /// this returns the contact with the largest penetration depth.
186    ///
187    /// Returns a reference to the contact, as well as the contact manifold
188    /// it is part of.
189    #[profiling::function]
190    pub fn find_deepest_contact(&self) -> Option<(&ContactManifold, &Contact)> {
191        let mut deepest = None;
192
193        for m2 in &self.manifolds {
194            let deepest_candidate = m2.find_deepest_contact();
195
196            deepest = match (deepest, deepest_candidate) {
197                (_, None) => deepest,
198                (None, Some(c2)) => Some((m2, c2)),
199                (Some((m1, c1)), Some(c2)) => {
200                    if c1.dist <= c2.dist {
201                        Some((m1, c1))
202                    } else {
203                        Some((m2, c2))
204                    }
205                }
206            }
207        }
208
209        deepest
210    }
211
212    pub(crate) fn emit_start_event(
213        &mut self,
214        bodies: &RigidBodySet,
215        colliders: &ColliderSet,
216        events: &dyn EventHandler,
217    ) {
218        self.start_event_emitted = true;
219
220        events.handle_collision_event(
221            bodies,
222            colliders,
223            CollisionEvent::Started(self.collider1, self.collider2, CollisionEventFlags::empty()),
224            Some(self),
225        );
226    }
227
228    pub(crate) fn emit_stop_event(
229        &mut self,
230        bodies: &RigidBodySet,
231        colliders: &ColliderSet,
232        events: &dyn EventHandler,
233    ) {
234        self.start_event_emitted = false;
235
236        events.handle_collision_event(
237            bodies,
238            colliders,
239            CollisionEvent::Stopped(self.collider1, self.collider2, CollisionEventFlags::empty()),
240            Some(self),
241        );
242    }
243}
244
245#[derive(Clone, Debug)]
246#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
247/// A contact manifold between two colliders.
248///
249/// A contact manifold describes a set of contacts between two colliders. All the contact
250/// part of the same contact manifold share the same contact normal and contact kinematics.
251pub struct ContactManifoldData {
252    // The following are set by the narrow-phase.
253    /// The first rigid-body involved in this contact manifold.
254    pub rigid_body1: Option<RigidBodyHandle>,
255    /// The second rigid-body involved in this contact manifold.
256    pub rigid_body2: Option<RigidBodyHandle>,
257    // We put the following fields here to avoids reading the colliders inside of the
258    // contact preparation method.
259    /// Flags used to control some aspects of the constraints solver for this contact manifold.
260    pub solver_flags: SolverFlags,
261    /// The world-space contact normal shared by all the contact in this contact manifold.
262    // NOTE: read the comment of `solver_contacts` regarding serialization. It applies
263    // to this field as well.
264    pub normal: Vector<Real>,
265    /// The contacts that will be seen by the constraints solver for computing forces.
266    // NOTE: unfortunately, we can't ignore this field when serialize
267    // the contact manifold data. The reason is that the solver contacts
268    // won't be updated for sleeping bodies. So it means that for one
269    // frame, we won't have any solver contacts when waking up an island
270    // after a deserialization. Not only does this break post-snapshot
271    // determinism, but it will also skip constraint resolution for these
272    // contacts during one frame.
273    //
274    // An alternative would be to skip the serialization of `solver_contacts` and
275    // find a way to recompute them right after the deserialization process completes.
276    // However, this would be an expensive operation. And doing this efficiently as part
277    // of the narrow-phase update or the contact manifold collect will likely lead to tricky
278    // bugs too.
279    //
280    // So right now it is best to just serialize this field and keep it that way until it
281    // is proven to be actually problematic in real applications (in terms of snapshot size for example).
282    pub solver_contacts: Vec<SolverContact>,
283    /// The relative dominance of the bodies involved in this contact manifold.
284    pub relative_dominance: i16,
285    /// A user-defined piece of data.
286    pub user_data: u32,
287}
288
289/// A contact seen by the constraints solver for computing forces.
290#[derive(Copy, Clone, Debug)]
291#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
292pub struct SolverContact {
293    /// The index of the manifold contact used to generate this solver contact.
294    pub(crate) contact_id: u8,
295    /// The contact point in world-space.
296    pub point: Point<Real>,
297    /// The distance between the two original contacts points along the contact normal.
298    /// If negative, this is measures the penetration depth.
299    pub dist: Real,
300    /// The effective friction coefficient at this contact point.
301    pub friction: Real,
302    /// The effective restitution coefficient at this contact point.
303    pub restitution: Real,
304    /// The desired tangent relative velocity at the contact point.
305    ///
306    /// This is set to zero by default. Set to a non-zero value to
307    /// simulate, e.g., conveyor belts.
308    pub tangent_velocity: Vector<Real>,
309    /// Whether or not this contact existed during the last timestep.
310    pub is_new: bool,
311    /// Impulse used to warmstart the solve for the normal constraint.
312    pub warmstart_impulse: Real,
313    /// Impulse used to warmstart the solve for the friction constraints.
314    pub warmstart_tangent_impulse: TangentImpulse<Real>,
315}
316
317impl SolverContact {
318    /// Should we treat this contact as a bouncy contact?
319    /// If `true`, use [`Self::restitution`].
320    pub fn is_bouncy(&self) -> bool {
321        if self.is_new {
322            // Treat new collisions as bouncing at first, unless we have zero restitution.
323            self.restitution > 0.0
324        } else {
325            // If the contact is still here one step later, it is now a resting contact.
326            // The exception is very high restitutions, which can never rest
327            self.restitution >= 1.0
328        }
329    }
330}
331
332impl Default for ContactManifoldData {
333    fn default() -> Self {
334        Self::new(None, None, SolverFlags::empty())
335    }
336}
337
338impl ContactManifoldData {
339    pub(crate) fn new(
340        rigid_body1: Option<RigidBodyHandle>,
341        rigid_body2: Option<RigidBodyHandle>,
342        solver_flags: SolverFlags,
343    ) -> ContactManifoldData {
344        Self {
345            rigid_body1,
346            rigid_body2,
347            solver_flags,
348            normal: Vector::zeros(),
349            solver_contacts: Vec::new(),
350            relative_dominance: 0,
351            user_data: 0,
352        }
353    }
354
355    /// Number of actives contacts, i.e., contacts that will be seen by
356    /// the constraints solver.
357    #[inline]
358    pub fn num_active_contacts(&self) -> usize {
359        self.solver_contacts.len()
360    }
361}
362
363/// Additional methods for the contact manifold.
364pub trait ContactManifoldExt {
365    /// Computes the sum of all the impulses applied by contacts from this contact manifold.
366    fn total_impulse(&self) -> Real;
367}
368
369impl ContactManifoldExt for ContactManifold {
370    fn total_impulse(&self) -> Real {
371        self.points.iter().map(|pt| pt.data.impulse).sum()
372    }
373}