Skip to main content

rapier3d/geometry/
collider_components.rs

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