diff options
Diffstat (limited to 'src/geometry')
| -rw-r--r-- | src/geometry/collider.rs | 100 | ||||
| -rw-r--r-- | src/geometry/collider_components.rs | 39 |
2 files changed, 100 insertions, 39 deletions
diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 2f2e4ac..421523f 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -241,10 +241,54 @@ impl Collider { pub fn density(&self) -> Option<Real> { match &self.mprops { ColliderMassProps::Density(density) => Some(*density), + ColliderMassProps::Mass(_) => None, ColliderMassProps::MassProperties(_) => None, } } + /// Sets the uniform density of this collider. + /// + /// This will override any previous mass-properties set by [`Self::set_density`], + /// [`Self::set_mass`], [`Self::set_mass_properties`], [`ColliderBuilder::density`], + /// [`ColliderBuilder::mass`], or [`ColliderBuilder::mass_properties`] + /// for this collider. + /// + /// The mass and angular inertia of this collider will be computed automatically based on its + /// shape. + pub fn set_density(&mut self, density: Real) { + self.do_set_mass_properties(ColliderMassProps::Density(density)); + } + + /// Sets the mass of this collider. + /// + /// This will override any previous mass-properties set by [`Self::set_density`], + /// [`Self::set_mass`], [`Self::set_mass_properties`], [`ColliderBuilder::density`], + /// [`ColliderBuilder::mass`], or [`ColliderBuilder::mass_properties`] + /// for this collider. + /// + /// The angular inertia of this collider will be computed automatically based on its shape + /// and this mass value. + pub fn set_mass(&mut self, mass: Real) { + self.do_set_mass_properties(ColliderMassProps::Mass(mass)); + } + + /// Sets the mass properties of this collider. + /// + /// This will override any previous mass-properties set by [`Self::set_density`], + /// [`Self::set_mass`], [`Self::set_mass_properties`], [`ColliderBuilder::density`], + /// [`ColliderBuilder::mass`], or [`ColliderBuilder::mass_properties`] + /// for this collider. + pub fn set_mass_properties(&mut self, mass_properties: MassProperties) { + self.do_set_mass_properties(ColliderMassProps::MassProperties(Box::new(mass_properties))) + } + + fn do_set_mass_properties(&mut self, mprops: ColliderMassProps) { + if mprops != self.mprops { + self.changes |= ColliderChanges::LOCAL_MASS_PROPERTIES; + self.mprops = mprops; + } + } + /// The geometric shape of this collider. pub fn shape(&self) -> &dyn Shape { self.shape.as_ref() @@ -284,10 +328,7 @@ impl Collider { /// Compute the local-space mass properties of this collider. pub fn mass_properties(&self) -> MassProperties { - match &self.mprops { - ColliderMassProps::Density(density) => self.shape.mass_properties(*density), - ColliderMassProps::MassProperties(mass_properties) => **mass_properties, - } + self.mprops.mass_properties(&*self.shape) } /// The total force magnitude beyond which a contact force event can be emitted. @@ -303,11 +344,8 @@ impl Collider { pub struct ColliderBuilder { /// The shape of the collider to be built. pub shape: SharedShape, - /// The uniform density of the collider to be built. - pub density: Option<Real>, - /// Overrides automatic computation of `MassProperties`. - /// If None, it will be computed based on shape and density. - pub mass_properties: Option<MassProperties>, + /// Controls the way the collider’s mass-properties are computed. + pub mass_properties: ColliderMassProps, /// The friction coefficient of the collider to be built. pub friction: Real, /// The rule used to combine two friction coefficients. @@ -341,8 +379,7 @@ impl ColliderBuilder { pub fn new(shape: SharedShape) -> Self { Self { shape, - density: None, - mass_properties: None, + mass_properties: ColliderMassProps::default(), friction: Self::default_friction(), restitution: 0.0, position: Isometry::identity(), @@ -627,9 +664,6 @@ impl ColliderBuilder { } /// Sets whether or not the collider built by this builder is a sensor. - /// - /// Sensors will have a default density of zero, - /// but if you call [`Self::mass_properties`] you can assign a mass to a sensor. pub fn sensor(mut self, is_sensor: bool) -> Self { self.is_sensor = is_sensor; self @@ -679,19 +713,34 @@ impl ColliderBuilder { /// Sets the uniform density of the collider this builder will build. /// - /// This will be overridden by a call to [`Self::mass_properties`] so it only makes sense to call - /// either [`Self::density`] or [`Self::mass_properties`]. + /// This will be overridden by a call to [`Self::mass`] or [`Self::mass_properties`] so it only + /// makes sense to call either [`Self::density`] or [`Self::mass`] or [`Self::mass_properties`]. + /// + /// The mass and angular inertia of this collider will be computed automatically based on its + /// shape. pub fn density(mut self, density: Real) -> Self { - self.density = Some(density); + self.mass_properties = ColliderMassProps::Density(density); + self + } + + /// Sets the mass of the collider this builder will build. + /// + /// This will be overridden by a call to [`Self::density`] or [`Self::mass_properties`] so it only + /// makes sense to call either [`Self::density`] or [`Self::mass`] or [`Self::mass_properties`]. + /// + /// The angular inertia of this collider will be computed automatically based on its shape + /// and this mass value. + pub fn mass(mut self, mass: Real) -> Self { + self.mass_properties = ColliderMassProps::Mass(mass); self } /// Sets the mass properties of the collider this builder will build. /// - /// If this is set, [`Self::density`] will be ignored, so it only makes sense to call - /// either [`Self::density`] or [`Self::mass_properties`]. + /// This will be overridden by a call to [`Self::density`] or [`Self::mass`] so it only + /// makes sense to call either [`Self::density`] or [`Self::mass`] or [`Self::mass_properties`]. pub fn mass_properties(mut self, mass_properties: MassProperties) -> Self { - self.mass_properties = Some(mass_properties); + self.mass_properties = ColliderMassProps::MassProperties(Box::new(mass_properties)); self } @@ -745,16 +794,7 @@ impl ColliderBuilder { /// Builds a new collider attached to the given rigid-body. pub fn build(&self) -> Collider { - let mass_info = if let Some(mp) = self.mass_properties { - ColliderMassProps::MassProperties(Box::new(mp)) - } else { - let default_density = Self::default_density(); - let density = self.density.unwrap_or(default_density); - ColliderMassProps::Density(density) - }; - let shape = self.shape.clone(); - let mprops = mass_info; let material = ColliderMaterial { friction: self.friction, restitution: self.restitution, @@ -779,7 +819,7 @@ impl ColliderBuilder { Collider { shape, - mprops, + mprops: self.mass_properties.clone(), material, parent: None, changes, diff --git a/src/geometry/collider_components.rs b/src/geometry/collider_components.rs index 22f75e7..29a24b5 100644 --- a/src/geometry/collider_components.rs +++ b/src/geometry/collider_components.rs @@ -47,21 +47,23 @@ bitflags::bitflags! { pub struct ColliderChanges: u32 { /// Flag indicating that any component of the collider has been modified. const MODIFIED = 1 << 0; + /// Flag indicating that the density or mass-properties of this collider was changed. + const LOCAL_MASS_PROPERTIES = 1 << 1; // => RigidBody local mass-properties update. /// Flag indicating that the `ColliderParent` component of the collider has been modified. - const PARENT = 1 << 1; // => BF & NF updates. + const PARENT = 1 << 2; // => BF & NF updates. /// Flag indicating that the `ColliderPosition` component of the collider has been modified. - const POSITION = 1 << 2; // => BF & NF updates. + const POSITION = 1 << 3; // => BF & NF updates. /// Flag indicating that the collision groups of the collider have been modified. - const GROUPS = 1 << 3; // => NF update. + const GROUPS = 1 << 4; // => NF update. /// Flag indicating that the `ColliderShape` component of the collider has been modified. - const SHAPE = 1 << 4; // => BF & NF update. NF pair workspace invalidation. + const SHAPE = 1 << 5; // => BF & NF update. NF pair workspace invalidation. /// Flag indicating that the `ColliderType` component of the collider has been modified. - const TYPE = 1 << 5; // => NF update. NF pair invalidation. + const TYPE = 1 << 6; // => NF update. NF pair invalidation. /// Flag indicating that the dominance groups of the parent of this collider have been modified. /// /// This flags is automatically set by the `PhysicsPipeline` when the `RigidBodyChanges::DOMINANCE` /// or `RigidBodyChanges::TYPE` of the parent rigid-body of this collider is detected. - const PARENT_EFFECTIVE_DOMINANCE = 1 << 6; // NF update. + const PARENT_EFFECTIVE_DOMINANCE = 1 << 7; // NF update. } } @@ -86,7 +88,7 @@ impl ColliderChanges { // bottleneck at some point in the future (which is very unlikely) // we could do a special-case for dominance-only change (so that // we only update the relative_dominance of the pre-existing contact. - self.bits() > 1 + self.bits() > 2 } } @@ -134,6 +136,10 @@ pub enum ColliderMassProps { /// Its actual `MassProperties` are computed automatically with /// the help of [`SharedShape::mass_properties`]. Density(Real), + /// The collider is given a mass. + /// + /// Its angular inertia will be computed automatically based on this mass. + Mass(Real), /// The collider is given explicit mass-properties. MassProperties(Box<MassProperties>), } @@ -159,8 +165,23 @@ impl ColliderMassProps { /// If `self` is the `MassProperties` variant, then this returns the stored mass-properties. pub fn mass_properties(&self, shape: &dyn Shape) -> MassProperties { match self { - Self::Density(density) => shape.mass_properties(*density), - Self::MassProperties(mprops) => **mprops, + ColliderMassProps::Density(density) => { + if *density != 0.0 { + shape.mass_properties(*density) + } else { + MassProperties::default() + } + } + ColliderMassProps::Mass(mass) => { + if *mass != 0.0 { + let mut mprops = shape.mass_properties(1.0); + mprops.set_mass(*mass, true); + mprops + } else { + MassProperties::default() + } + } + ColliderMassProps::MassProperties(mass_properties) => **mass_properties, } } } |
