diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynamics/rigid_body.rs | 221 | ||||
| -rw-r--r-- | src/dynamics/rigid_body_components.rs | 40 | ||||
| -rw-r--r-- | src/geometry/collider.rs | 100 | ||||
| -rw-r--r-- | src/geometry/collider_components.rs | 39 | ||||
| -rw-r--r-- | src/pipeline/physics_pipeline.rs | 10 | ||||
| -rw-r--r-- | src/pipeline/user_changes.rs | 36 |
6 files changed, 271 insertions, 175 deletions
diff --git a/src/dynamics/rigid_body.rs b/src/dynamics/rigid_body.rs index eaf3967..494dc6c 100644 --- a/src/dynamics/rigid_body.rs +++ b/src/dynamics/rigid_body.rs @@ -1,14 +1,14 @@ use crate::dynamics::{ - LockedAxes, MassProperties, RigidBodyActivation, RigidBodyCcd, RigidBodyChanges, - RigidBodyColliders, RigidBodyDamping, RigidBodyDominance, RigidBodyForces, RigidBodyIds, - RigidBodyMassProps, RigidBodyPosition, RigidBodyType, RigidBodyVelocity, + LockedAxes, MassProperties, RigidBodyActivation, RigidBodyAdditionalMassProps, RigidBodyCcd, + RigidBodyChanges, RigidBodyColliders, RigidBodyDamping, RigidBodyDominance, RigidBodyForces, + RigidBodyIds, RigidBodyMassProps, RigidBodyPosition, RigidBodyType, RigidBodyVelocity, }; use crate::geometry::{ - Collider, ColliderHandle, ColliderMassProps, ColliderParent, ColliderPosition, ColliderShape, + Collider, ColliderHandle, ColliderMassProps, ColliderParent, ColliderPosition, ColliderSet, + ColliderShape, }; use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector}; -use crate::utils::{self, WCross}; -use na::ComplexField; +use crate::utils::WCross; use num::Zero; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] @@ -123,7 +123,7 @@ impl RigidBody { } } - /// The mass properties of this rigid-body. + /// The mass-properties of this rigid-body. #[inline] pub fn mass_properties(&self) -> &MassProperties { &self.mprops.local_mprops @@ -310,26 +310,82 @@ impl RigidBody { self.ccd.ccd_active } - /// Sets the rigid-body's additional mass properties. + /// Recompute the mass-properties of this rigid-bodies based on its currently attached colliders. + pub fn recompute_mass_properties_from_colliders(&mut self, colliders: &ColliderSet) { + self.mprops.recompute_mass_properties_from_colliders( + colliders, + &self.colliders, + &self.pos.position, + ); + } + + /// Sets the rigid-body's additional mass. + /// + /// The total angular inertia of the rigid-body will be scaled automatically based on this + /// additional mass. If this scaling effect isn’t desired, use [`Self::additional_mass_properties`] + /// instead of this method. + /// + /// This is only the "additional" mass because the total mass of the rigid-body is + /// equal to the sum of this additional mass and the mass computed from the colliders + /// (with non-zero densities) attached to this rigid-body. + /// + /// That total mass (which includes the attached colliders’ contributions) + /// will be updated at the name physics step, or can be updated manually with + /// [`Self::recompute_mass_properties_from_colliders`]. + /// + /// This will override any previous mass-properties set by [`Self::set_additional_mass`], + /// [`Self::set_additional_mass_properties`], [`RigidBodyBuilder::additional_mass`], or + /// [`RigidBodyBuilder::additional_mass_properties`] for this rigid-body. + /// + /// If `wake_up` is `true` then the rigid-body will be woken up if it was + /// put to sleep because it did not move for a while. + #[inline] + pub fn set_additional_mass(&mut self, additional_mass: Real, wake_up: bool) { + self.do_set_additional_mass_properties( + RigidBodyAdditionalMassProps::Mass(additional_mass), + wake_up, + ) + } + + /// Sets the rigid-body's additional mass-properties. + /// + /// This is only the "additional" mass-properties because the total mass-properties of the + /// rigid-body is equal to the sum of this additional mass-properties and the mass computed from + /// the colliders (with non-zero densities) attached to this rigid-body. + /// + /// That total mass-properties (which include the attached colliders’ contributions) + /// will be updated at the name physics step, or can be updated manually with + /// [`Self::recompute_mass_properties_from_colliders`]. + /// + /// This will override any previous mass-properties set by [`Self::set_additional_mass`], + /// [`Self::set_additional_mass_properties`], [`RigidBodyBuilder::additional_mass`], or + /// [`RigidBodyBuilder::additional_mass_properties`] for this rigid-body. /// /// If `wake_up` is `true` then the rigid-body will be woken up if it was /// put to sleep because it did not move for a while. #[inline] pub fn set_additional_mass_properties(&mut self, props: MassProperties, wake_up: bool) { - if let Some(add_mprops) = &mut self.mprops.additional_local_mprops { - self.mprops.local_mprops += props; - self.mprops.local_mprops -= **add_mprops; - **add_mprops = props; - } else { - self.mprops.additional_local_mprops = Some(Box::new(props)); - self.mprops.local_mprops += props; - } + self.do_set_additional_mass_properties( + RigidBodyAdditionalMassProps::MassProps(props), + wake_up, + ) + } - if self.is_dynamic() && wake_up { - self.wake_up(true); - } + fn do_set_additional_mass_properties( + &mut self, + props: RigidBodyAdditionalMassProps, + wake_up: bool, + ) { + let new_mprops = Some(Box::new(props)); - self.update_world_mass_properties(); + if self.mprops.additional_local_mprops != new_mprops { + self.changes.insert(RigidBodyChanges::LOCAL_MASS_PROPERTIES); + self.mprops.additional_local_mprops = new_mprops; + + if self.is_dynamic() && wake_up { + self.wake_up(true); + } + } } /// The handles of colliders attached to this rigid body. @@ -432,12 +488,6 @@ impl RigidBody { if let Some(i) = self.colliders.0.iter().position(|e| *e == handle) { self.changes.set(RigidBodyChanges::COLLIDERS, true); self.colliders.0.swap_remove(i); - - let mass_properties = coll - .mass_properties() - .transform_by(coll.position_wrt_parent().unwrap()); - self.mprops.local_mprops -= mass_properties; - self.update_world_mass_properties(); } } @@ -859,8 +909,8 @@ pub struct RigidBodyBuilder { pub angular_damping: Real, body_type: RigidBodyType, mprops_flags: LockedAxes, - /// The additional mass properties of the rigid-body being built. See [`RigidBodyBuilder::additional_mass_properties`] for more information. - pub additional_mass_properties: MassProperties, + /// The additional mass-properties of the rigid-body being built. See [`RigidBodyBuilder::additional_mass_properties`] for more information. + additional_mass_properties: RigidBodyAdditionalMassProps, /// Whether or not the rigid-body to be created can sleep if it reaches a dynamic equilibrium. pub can_sleep: bool, /// Whether or not the rigid-body is to be created asleep. @@ -887,7 +937,7 @@ impl RigidBodyBuilder { angular_damping: 0.0, body_type, mprops_flags: LockedAxes::empty(), - additional_mass_properties: MassProperties::zero(), + additional_mass_properties: RigidBodyAdditionalMassProps::default(), can_sleep: true, sleeping: false, ccd_enabled: false, @@ -968,18 +1018,41 @@ impl RigidBodyBuilder { self } - /// Sets the additional mass properties of the rigid-body being built. + /// Sets the additional mass-properties of the rigid-body being built. /// - /// Note that "additional" means that the final mass properties of the rigid-bodies depends + /// This will be overridden by a call to [`Self::additional_mass`] so it only makes sense to call + /// either [`Self::additional_mass`] or [`Self::additional_mass_properties`]. + /// + /// Note that "additional" means that the final mass-properties of the rigid-bodies depends /// on the initial mass-properties of the rigid-body (set by this method) /// to which is added the contributions of all the colliders with non-zero density /// attached to this rigid-body. /// - /// Therefore, if you want your provided mass properties to be the final - /// mass properties of your rigid-body, don't attach colliders to it, or + /// Therefore, if you want your provided mass-properties to be the final + /// mass-properties of your rigid-body, don't attach colliders to it, or /// only attach colliders with densities equal to zero. - pub fn additional_mass_properties(mut self, props: MassProperties) -> Self { - self.additional_mass_properties = props; + pub fn additional_mass_properties(mut self, mprops: MassProperties) -> Self { + self.additional_mass_properties = RigidBodyAdditionalMassProps::MassProps(mprops); + self + } + + /// Sets the additional mass of the rigid-body being built. + /// + /// This will be overridden by a call to [`Self::additional_mass_properties`] so it only makes + /// sense to call either [`Self::additional_mass`] or [`Self::additional_mass_properties`]. + /// + /// This is only the "additional" mass because the total mass of the rigid-body is + /// equal to the sum of this additional mass and the mass computed from the colliders + /// (with non-zero densities) attached to this rigid-body. + /// + /// The total angular inertia of the rigid-body will be scaled automatically based on this + /// additional mass. If this scaling effect isn’t desired, use [`Self::additional_mass_properties`] + /// instead of this method. + /// + /// # Parameters + /// * `mass`- The mass that will be added to the created rigid-body. + pub fn additional_mass(mut self, mass: Real) -> Self { + self.additional_mass_properties = RigidBodyAdditionalMassProps::Mass(mass); self } @@ -1037,78 +1110,6 @@ impl RigidBodyBuilder { self } - /// Sets the additional mass of the rigid-body being built. - /// - /// This is only the "additional" mass because the total mass of the rigid-body is - /// equal to the sum of this additional mass and the mass computed from the colliders - /// (with non-zero densities) attached to this rigid-body. - pub fn additional_mass(mut self, mass: Real) -> Self { - self.additional_mass_properties.set_mass(mass, false); - self - } - - /// Sets the additional mass of the rigid-body being built. - /// - /// This is only the "additional" mass because the total mass of the rigid-body is - /// equal to the sum of this additional mass and the mass computed from the colliders - /// (with non-zero densities) attached to this rigid-body. - #[deprecated(note = "renamed to `additional_mass`.")] - pub fn mass(self, mass: Real) -> Self { - self.additional_mass(mass) - } - - /// Sets the additional angular inertia of this rigid-body. - /// - /// This is only the "additional" angular inertia because the total angular inertia of - /// the rigid-body is equal to the sum of this additional value and the angular inertia - /// computed from the colliders (with non-zero densities) attached to this rigid-body. - #[cfg(feature = "dim2")] - pub fn additional_principal_angular_inertia(mut self, inertia: Real) -> Self { - self.additional_mass_properties.inv_principal_inertia_sqrt = - utils::inv(ComplexField::sqrt(inertia.max(0.0))); - self - } - - /// Sets the angular inertia of this rigid-body. - #[cfg(feature = "dim2")] - #[deprecated(note = "renamed to `additional_principal_angular_inertia`.")] - pub fn principal_angular_inertia(self, inertia: Real) -> Self { - self.additional_principal_angular_inertia(inertia) - } - - /// Use `self.principal_angular_inertia` instead. - #[cfg(feature = "dim2")] - #[deprecated(note = "renamed to `additional_principal_angular_inertia`.")] - pub fn principal_inertia(self, inertia: Real) -> Self { - self.additional_principal_angular_inertia(inertia) - } - - /// Sets the additional principal angular inertia of this rigid-body. - /// - /// This is only the "additional" angular inertia because the total angular inertia of - /// the rigid-body is equal to the sum of this additional value and the angular inertia - /// computed from the colliders (with non-zero densities) attached to this rigid-body. - #[cfg(feature = "dim3")] - pub fn additional_principal_angular_inertia(mut self, inertia: AngVector<Real>) -> Self { - self.additional_mass_properties.inv_principal_inertia_sqrt = - inertia.map(|e| utils::inv(ComplexField::sqrt(e.max(0.0)))); - self - } - - /// Sets the principal angular inertia of this rigid-body. - #[cfg(feature = "dim3")] - #[deprecated(note = "renamed to `additional_principal_angular_inertia`.")] - pub fn principal_angular_inertia(self, inertia: AngVector<Real>) -> Self { - self.additional_principal_angular_inertia(inertia) - } - - /// Use `self.principal_angular_inertia` instead. - #[cfg(feature = "dim3")] - #[deprecated(note = "renamed to `additional_principal_angular_inertia`.")] - pub fn principal_inertia(self, inertia: AngVector<Real>) -> Self { - self.additional_principal_angular_inertia(inertia) - } - /// Sets the damping factor for the linear part of the rigid-body motion. /// /// The higher the linear damping factor is, the more quickly the rigid-body @@ -1169,9 +1170,11 @@ impl RigidBodyBuilder { rb.body_type = self.body_type; rb.user_data = self.user_data; - if self.additional_mass_properties != MassProperties::default() { + if self.additional_mass_properties + != RigidBodyAdditionalMassProps::MassProps(MassProperties::zero()) + && self.additional_mass_properties != RigidBodyAdditionalMassProps::Mass(0.0) + { rb.mprops.additional_local_mprops = Some(Box::new(self.additional_mass_properties)); - rb.mprops.local_mprops = self.additional_mass_properties; } rb.mprops.flags = self.mprops_flags; diff --git a/src/dynamics/rigid_body_components.rs b/src/dynamics/rigid_body_components.rs index 3d35d17..cabf6ca 100644 --- a/src/dynamics/rigid_body_components.rs +++ b/src/dynamics/rigid_body_components.rs @@ -110,6 +110,8 @@ bitflags::bitflags! { const TYPE = 1 << 4; /// Flag indicating that the `RigidBodyDominance` component of this rigid-body has been modified. const DOMINANCE = 1 << 5; + /// Flag indicating that the local mass-properties of this rigid-body must be recomputed. + const LOCAL_MASS_PROPERTIES = 1 << 6; } } @@ -222,7 +224,23 @@ bitflags::bitflags! { } } -// TODO: split this into "LocalMassProps" and `WorldMassProps"? +/// Mass and angular inertia added to a rigid-body on top of its attached colliders’ contributions. +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum RigidBodyAdditionalMassProps { + /// Mass properties to be added as-is. + MassProps(MassProperties), + /// Mass to be added to the rigid-body. This will also automatically scale + /// the attached colliders total angular inertia to account for the added mass. + Mass(Real), +} + +impl Default for RigidBodyAdditionalMassProps { + fn default() -> Self { + RigidBodyAdditionalMassProps::MassProps(MassProperties::default()) + } +} + #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone, Debug, PartialEq)] /// The mass properties of this rigid-bodies. @@ -232,7 +250,7 @@ pub struct RigidBodyMassProps { /// The local mass properties of the rigid-body. pub local_mprops: MassProperties, /// Mass-properties of this rigid-bodies, added to the contributions of its attached colliders. - pub additional_local_mprops: Option<Box<MassProperties>>, + pub additional_local_mprops: Option<Box<RigidBodyAdditionalMassProps>>, /// The world-space center of mass of the rigid-body. pub world_com: Point<Real>, /// The inverse mass taking into account translation locking. @@ -294,18 +312,20 @@ impl RigidBodyMassProps { self.effective_world_inv_inertia_sqrt.squared().inverse() } - /// Recompute the mass-properties of this rigid-bodies based on its currentely attached colliders. + /// Recompute the mass-properties of this rigid-bodies based on its currently attached colliders. pub fn recompute_mass_properties_from_colliders( &mut self, colliders: &ColliderSet, attached_colliders: &RigidBodyColliders, position: &Isometry<Real>, ) { - self.local_mprops = self + let added_mprops = self .additional_local_mprops .as_ref() .map(|mprops| **mprops) - .unwrap_or_else(MassProperties::default); + .unwrap_or_else(|| RigidBodyAdditionalMassProps::MassProps(MassProperties::default())); + + self.local_mprops = MassProperties::default(); for handle in &attached_colliders.0 { if let Some(co) = colliders.get(*handle) { @@ -319,6 +339,16 @@ impl RigidBodyMassProps { } } + match added_mprops { + RigidBodyAdditionalMassProps::MassProps(mprops) => { + self.local_mprops += mprops; + } + RigidBodyAdditionalMassProps::Mass(mass) => { + let new_mass = self.local_mprops.mass() + mass; + self.local_mprops.set_mass(new_mass, true); + } + } + self.update_world_mass_properties(position); } 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, } } } diff --git a/src/pipeline/physics_pipeline.rs b/src/pipeline/physics_pipeline.rs index d347637..71ab578 100644 --- a/src/pipeline/physics_pipeline.rs +++ b/src/pipeline/physics_pipeline.rs @@ -407,6 +407,9 @@ impl PhysicsPipeline { hooks: &dyn PhysicsHooks, events: &dyn EventHandler, ) { + self.counters.reset(); + self.counters.step_started(); + // Apply some of delayed wake-ups. for handle in impulse_joints .to_wake_up @@ -417,18 +420,15 @@ impl PhysicsPipeline { } // Apply modifications. - let modified_bodies = bodies.take_modified(); let mut modified_colliders = colliders.take_modified(); let mut removed_colliders = colliders.take_removed(); - - self.counters.reset(); - self.counters.step_started(); - super::user_changes::handle_user_changes_to_colliders( bodies, colliders, &modified_colliders[..], ); + + let modified_bodies = bodies.take_modified(); super::user_changes::handle_user_changes_to_rigid_bodies( Some(islands), bodies, diff --git a/src/pipeline/user_changes.rs b/src/pipeline/user_changes.rs index 9872208..e7da68a 100644 --- a/src/pipeline/user_changes.rs +++ b/src/pipeline/user_changes.rs @@ -2,17 +2,12 @@ use crate::dynamics::{ IslandManager, RigidBodyChanges, RigidBodyHandle, RigidBodySet, RigidBodyType, }; use crate::geometry::{ColliderChanges, ColliderHandle, ColliderPosition, ColliderSet}; -use parry::utils::hashmap::HashMap; pub(crate) fn handle_user_changes_to_colliders( bodies: &mut RigidBodySet, colliders: &mut ColliderSet, modified_colliders: &[ColliderHandle], ) { - // TODO: avoid this hashmap? We could perhaps add a new flag to RigidBodyChanges to - // indicated that the mass properties need to be recomputed? - let mut mprops_to_update = HashMap::default(); - for handle in modified_colliders { // NOTE: we use `get` because the collider may no longer // exist if it has been removed. @@ -26,22 +21,19 @@ pub(crate) fn handle_user_changes_to_colliders( } } - if co.changes.contains(ColliderChanges::SHAPE) { - if let Some(co_parent) = co.parent { - mprops_to_update.insert(co_parent.handle, ()); + if co + .changes + .intersects(ColliderChanges::SHAPE | ColliderChanges::LOCAL_MASS_PROPERTIES) + { + if let Some(rb) = co + .parent + .and_then(|p| bodies.get_mut_internal_with_modification_tracking(p.handle)) + { + rb.changes |= RigidBodyChanges::LOCAL_MASS_PROPERTIES; } } } } - - for (to_update, _) in mprops_to_update { - let rb = bodies.index_mut_internal(to_update); - rb.mprops.recompute_mass_properties_from_colliders( - colliders, - &rb.colliders, - &rb.pos.position, - ); - } } pub(crate) fn handle_user_changes_to_rigid_bodies( @@ -163,6 +155,16 @@ pub(crate) fn handle_user_changes_to_rigid_bodies( } } + if changes + .intersects(RigidBodyChanges::LOCAL_MASS_PROPERTIES | RigidBodyChanges::COLLIDERS) + { + rb.mprops.recompute_mass_properties_from_colliders( + colliders, + &rb.colliders, + &rb.pos.position, + ); + } + rb.changes = RigidBodyChanges::empty(); rb.ids = ids; rb.activation = activation; |
