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}