rapier3d/geometry/collider_components.rs
1use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle, RigidBodyType};
2use crate::geometry::{InteractionGroups, Shape, SharedShape};
3use crate::math::{Isometry, Real};
4use crate::pipeline::{ActiveEvents, ActiveHooks};
5use std::ops::{Deref, DerefMut};
6
7/// The unique identifier of a collider added to a collider set.
8#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
9#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
10#[repr(transparent)]
11pub struct ColliderHandle(pub crate::data::arena::Index);
12
13impl ColliderHandle {
14 /// Converts this handle into its (index, generation) components.
15 pub fn into_raw_parts(self) -> (u32, u32) {
16 self.0.into_raw_parts()
17 }
18
19 /// Reconstructs an handle from its (index, generation) components.
20 pub fn from_raw_parts(id: u32, generation: u32) -> Self {
21 Self(crate::data::arena::Index::from_raw_parts(id, generation))
22 }
23
24 /// An always-invalid collider handle.
25 pub fn invalid() -> Self {
26 Self(crate::data::arena::Index::from_raw_parts(
27 crate::INVALID_U32,
28 crate::INVALID_U32,
29 ))
30 }
31}
32
33bitflags::bitflags! {
34 #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
35 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
36 /// Flags describing how the collider has been modified by the user.
37 pub struct ColliderChanges: u32 {
38 /// Flag indicating that any component of the collider has been modified.
39 const MODIFIED = 1 << 0;
40 /// Flag indicating that the density or mass-properties of this collider was changed.
41 const LOCAL_MASS_PROPERTIES = 1 << 1; // => RigidBody local mass-properties update.
42 /// Flag indicating that the `ColliderParent` component of the collider has been modified.
43 const PARENT = 1 << 2; // => BF & NF updates.
44 /// Flag indicating that the `ColliderPosition` component of the collider has been modified.
45 const POSITION = 1 << 3; // => BF & NF updates.
46 /// Flag indicating that the collision groups of the collider have been modified.
47 const GROUPS = 1 << 4; // => NF update.
48 /// Flag indicating that the `ColliderShape` component of the collider has been modified.
49 const SHAPE = 1 << 5; // => BF & NF update. NF pair workspace invalidation.
50 /// Flag indicating that the `ColliderType` component of the collider has been modified.
51 const TYPE = 1 << 6; // => NF update. NF pair invalidation.
52 /// Flag indicating that the dominance groups of the parent of this collider have been modified.
53 ///
54 /// This flags is automatically set by the `PhysicsPipeline` when the `RigidBodyChanges::DOMINANCE`
55 /// or `RigidBodyChanges::TYPE` of the parent rigid-body of this collider is detected.
56 const PARENT_EFFECTIVE_DOMINANCE = 1 << 7; // NF update.
57 /// Flag indicating that whether or not the collider is enabled was changed.
58 const ENABLED_OR_DISABLED = 1 << 8; // BF & NF updates.
59 }
60}
61
62impl Default for ColliderChanges {
63 fn default() -> Self {
64 ColliderChanges::empty()
65 }
66}
67
68impl ColliderChanges {
69 /// Do these changes justify a broad-phase update?
70 pub fn needs_broad_phase_update(self) -> bool {
71 self.intersects(
72 ColliderChanges::PARENT
73 | ColliderChanges::POSITION
74 | ColliderChanges::SHAPE
75 | ColliderChanges::ENABLED_OR_DISABLED,
76 )
77 }
78
79 /// Do these changes justify a narrow-phase update?
80 pub fn needs_narrow_phase_update(self) -> bool {
81 // NOTE: for simplicity of implementation, we return `true` even if
82 // we only need a dominance update. If this does become a
83 // bottleneck at some point in the future (which is very unlikely)
84 // we could do a special-case for dominance-only change (so that
85 // we only update the relative_dominance of the pre-existing contact.
86 self.bits() > 2
87 }
88}
89
90#[derive(Copy, Clone, Debug, PartialEq, Eq)]
91#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
92/// The type of collider.
93pub enum ColliderType {
94 /// A collider that can generate contacts and contact events.
95 Solid,
96 /// A collider that can generate intersection and intersection events.
97 Sensor,
98}
99
100impl ColliderType {
101 /// Is this collider a sensor?
102 pub fn is_sensor(self) -> bool {
103 self == ColliderType::Sensor
104 }
105}
106
107/// The shape of a collider.
108pub type ColliderShape = SharedShape;
109
110#[derive(Clone, PartialEq, Debug)]
111#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
112/// The mass-properties of a collider.
113pub enum ColliderMassProps {
114 /// The collider is given a density.
115 ///
116 /// Its actual `MassProperties` are computed automatically with
117 /// the help of [`Shape::mass_properties`].
118 Density(Real),
119 /// The collider is given a mass.
120 ///
121 /// Its angular inertia will be computed automatically based on this mass.
122 Mass(Real),
123 /// The collider is given explicit mass-properties.
124 MassProperties(Box<MassProperties>),
125}
126
127impl Default for ColliderMassProps {
128 fn default() -> Self {
129 ColliderMassProps::Density(1.0)
130 }
131}
132
133impl From<MassProperties> for ColliderMassProps {
134 fn from(mprops: MassProperties) -> Self {
135 ColliderMassProps::MassProperties(Box::new(mprops))
136 }
137}
138
139impl ColliderMassProps {
140 /// The mass-properties of this collider.
141 ///
142 /// If `self` is the `Density` variant, then this computes the mass-properties based
143 /// on the given shape.
144 ///
145 /// If `self` is the `MassProperties` variant, then this returns the stored mass-properties.
146 pub fn mass_properties(&self, shape: &dyn Shape) -> MassProperties {
147 match self {
148 ColliderMassProps::Density(density) => {
149 if *density != 0.0 {
150 shape.mass_properties(*density)
151 } else {
152 MassProperties::default()
153 }
154 }
155 ColliderMassProps::Mass(mass) => {
156 if *mass != 0.0 {
157 let mut mprops = shape.mass_properties(1.0);
158 mprops.set_mass(*mass, true);
159 mprops
160 } else {
161 MassProperties::default()
162 }
163 }
164 ColliderMassProps::MassProperties(mass_properties) => **mass_properties,
165 }
166 }
167}
168
169#[derive(Copy, Clone, Debug, PartialEq)]
170#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
171/// Information about the rigid-body this collider is attached to.
172pub struct ColliderParent {
173 /// Handle of the rigid-body this collider is attached to.
174 pub handle: RigidBodyHandle,
175 /// Const position of this collider relative to its parent rigid-body.
176 pub pos_wrt_parent: Isometry<Real>,
177}
178
179#[derive(Copy, Clone, Debug, PartialEq)]
180#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
181/// The position of a collider.
182pub struct ColliderPosition(pub Isometry<Real>);
183
184impl AsRef<Isometry<Real>> for ColliderPosition {
185 #[inline]
186 fn as_ref(&self) -> &Isometry<Real> {
187 &self.0
188 }
189}
190
191impl AsMut<Isometry<Real>> for ColliderPosition {
192 fn as_mut(&mut self) -> &mut Isometry<Real> {
193 &mut self.0
194 }
195}
196
197impl Deref for ColliderPosition {
198 type Target = Isometry<Real>;
199 #[inline]
200 fn deref(&self) -> &Isometry<Real> {
201 &self.0
202 }
203}
204
205impl DerefMut for ColliderPosition {
206 fn deref_mut(&mut self) -> &mut Self::Target {
207 &mut self.0
208 }
209}
210
211impl Default for ColliderPosition {
212 fn default() -> Self {
213 Self::identity()
214 }
215}
216
217impl ColliderPosition {
218 /// The identity position.
219 #[must_use]
220 pub fn identity() -> Self {
221 ColliderPosition(Isometry::identity())
222 }
223}
224
225impl<T> From<T> for ColliderPosition
226where
227 Isometry<Real>: From<T>,
228{
229 fn from(position: T) -> Self {
230 Self(position.into())
231 }
232}
233
234#[derive(Copy, Clone, Debug, PartialEq)]
235#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
236/// The constraints solver-related properties of this collider (friction, restitution, etc.)
237pub struct ColliderMaterial {
238 /// The friction coefficient of this collider.
239 ///
240 /// The greater the value, the stronger the friction forces will be.
241 /// Should be `>= 0`.
242 pub friction: Real,
243 /// The restitution coefficient of this collider.
244 ///
245 /// Increase this value to make contacts with this collider more "bouncy".
246 /// Should be `>= 0` and should generally not be greater than `1` (perfectly elastic
247 /// collision).
248 pub restitution: Real,
249 /// The rule applied to combine the friction coefficients of two colliders in contact.
250 pub friction_combine_rule: CoefficientCombineRule,
251 /// The rule applied to combine the restitution coefficients of two colliders.
252 pub restitution_combine_rule: CoefficientCombineRule,
253}
254
255impl ColliderMaterial {
256 /// Creates a new collider material with the given friction and restitution coefficients.
257 pub fn new(friction: Real, restitution: Real) -> Self {
258 Self {
259 friction,
260 restitution,
261 ..Default::default()
262 }
263 }
264}
265
266impl Default for ColliderMaterial {
267 fn default() -> Self {
268 Self {
269 friction: 1.0,
270 restitution: 0.0,
271 friction_combine_rule: CoefficientCombineRule::default(),
272 restitution_combine_rule: CoefficientCombineRule::default(),
273 }
274 }
275}
276
277bitflags::bitflags! {
278 #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
279 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
280 /// Flags affecting whether or not collision-detection happens between two colliders
281 /// depending on the type of rigid-bodies they are attached to.
282 pub struct ActiveCollisionTypes: u16 {
283 /// Enable collision-detection between a collider attached to a dynamic body
284 /// and another collider attached to a dynamic body.
285 const DYNAMIC_DYNAMIC = 0b0000_0000_0000_0001;
286 /// Enable collision-detection between a collider attached to a dynamic body
287 /// and another collider attached to a kinematic body.
288 const DYNAMIC_KINEMATIC = 0b0000_0000_0000_1100;
289 /// Enable collision-detection between a collider attached to a dynamic body
290 /// and another collider attached to a fixed body (or not attached to any body).
291 const DYNAMIC_FIXED = 0b0000_0000_0000_0010;
292 /// Enable collision-detection between a collider attached to a kinematic body
293 /// and another collider attached to a kinematic body.
294 const KINEMATIC_KINEMATIC = 0b1100_1100_0000_0000;
295
296 /// Enable collision-detection between a collider attached to a kinematic body
297 /// and another collider attached to a fixed body (or not attached to any body).
298 const KINEMATIC_FIXED = 0b0010_0010_0000_0000;
299
300 /// Enable collision-detection between a collider attached to a fixed body (or
301 /// not attached to any body) and another collider attached to a fixed body (or
302 /// not attached to any body).
303 const FIXED_FIXED = 0b0000_0000_0010_0000;
304 }
305}
306
307impl ActiveCollisionTypes {
308 /// Test whether contact should be computed between two rigid-bodies with the given types.
309 pub fn test(self, rb_type1: RigidBodyType, rb_type2: RigidBodyType) -> bool {
310 // NOTE: This test is quite complicated so here is an explanation.
311 // First, we associate the following bit masks:
312 // - DYNAMIC = 0001
313 // - FIXED = 0010
314 // - KINEMATIC = 1100
315 // These are equal to the bits indexed by `RigidBodyType as u32`.
316 // The bit masks defined by ActiveCollisionTypes are defined is such a way
317 // that the first part of the variant name (e.g. DYNAMIC_*) indicates which
318 // groups of four bits should be considered:
319 // - DYNAMIC_* = the first group of four bits.
320 // - FIXED_* = the second group of four bits.
321 // - KINEMATIC_* = the third and fourth groups of four bits.
322 // The second part of the variant name (e.g. *_DYNAMIC) indicates the value
323 // of the aforementioned groups of four bits.
324 // For example, DYNAMIC_FIXED means that the first group of four bits (because
325 // of DYNAMIC_*) must have the value 0010 (because of *_FIXED). That gives
326 // us 0b0000_0000_0000_0010 for the DYNAMIC_FIXED_VARIANT.
327 //
328 // The KINEMATIC_* is special because it occupies two groups of four bits. This is
329 // because it combines both KinematicPositionBased and KinematicVelocityBased.
330 //
331 // Now that we have a way of building these bit masks, let's see how we use them.
332 // Given a pair of rigid-body types, the first rigid-body type is used to select
333 // the group of four bits we want to test (the selection is done by to the
334 // `>> (rb_type1 as u32 * 4) & 0b0000_1111`) and the second rigid-body type is
335 // used to form the bit mask we test this group of four bits against.
336 // In other word, the selection of the group of four bits tells us "for this type
337 // of rigid-body I can have collision with rigid-body types with these bit representation".
338 // Then the `(1 << rb_type2)` gives us the bit-representation of the rigid-body type,
339 // which needs to be checked.
340 //
341 // Because that test must be symmetric, we perform two similar tests by swapping
342 // rb_type1 and rb_type2.
343 ((self.bits() >> (rb_type1 as u32 * 4)) & 0b0000_1111) & (1 << rb_type2 as u32) != 0
344 || ((self.bits() >> (rb_type2 as u32 * 4)) & 0b0000_1111) & (1 << rb_type1 as u32) != 0
345 }
346}
347
348impl Default for ActiveCollisionTypes {
349 fn default() -> Self {
350 ActiveCollisionTypes::DYNAMIC_DYNAMIC
351 | ActiveCollisionTypes::DYNAMIC_KINEMATIC
352 | ActiveCollisionTypes::DYNAMIC_FIXED
353 }
354}
355
356#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
357#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
358/// Enum indicating whether or not a collider is enabled.
359pub enum ColliderEnabled {
360 /// The collider is enabled.
361 Enabled,
362 /// The collider wasn’t disabled by the user explicitly but it is attached to
363 /// a disabled rigid-body.
364 DisabledByParent,
365 /// The collider is disabled by the user explicitly.
366 Disabled,
367}
368
369#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
370#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
371/// A set of flags for controlling collision/intersection filtering, modification, and events.
372pub struct ColliderFlags {
373 /// Controls whether collision-detection happens between two colliders depending on
374 /// the type of the rigid-bodies they are attached to.
375 pub active_collision_types: ActiveCollisionTypes,
376 /// The groups controlling the pairs of colliders that can interact (generate
377 /// interaction events or contacts).
378 pub collision_groups: InteractionGroups,
379 /// The groups controlling the pairs of collider that have their contact
380 /// points taken into account for force computation.
381 pub solver_groups: InteractionGroups,
382 /// The physics hooks enabled for contact pairs and intersection pairs involving this collider.
383 pub active_hooks: ActiveHooks,
384 /// The events enabled for this collider.
385 pub active_events: ActiveEvents,
386 /// Whether or not the collider is enabled.
387 pub enabled: ColliderEnabled,
388}
389
390impl Default for ColliderFlags {
391 fn default() -> Self {
392 Self {
393 active_collision_types: ActiveCollisionTypes::default(),
394 collision_groups: InteractionGroups::all(),
395 solver_groups: InteractionGroups::all(),
396 active_hooks: ActiveHooks::empty(),
397 active_events: ActiveEvents::empty(),
398 enabled: ColliderEnabled::Enabled,
399 }
400 }
401}
402
403impl From<ActiveHooks> for ColliderFlags {
404 fn from(active_hooks: ActiveHooks) -> Self {
405 Self {
406 active_hooks,
407 ..Default::default()
408 }
409 }
410}
411
412impl From<ActiveEvents> for ColliderFlags {
413 fn from(active_events: ActiveEvents) -> Self {
414 Self {
415 active_events,
416 ..Default::default()
417 }
418 }
419}