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}