diff options
| author | Crozet Sébastien <developer@crozet.re> | 2021-04-30 11:37:58 +0200 |
|---|---|---|
| committer | Crozet Sébastien <developer@crozet.re> | 2021-04-30 11:37:58 +0200 |
| commit | 2dfbd9ae92c139e306afc87994adac82489f30eb (patch) | |
| tree | c5b9c5e6fcb5561421e2b4b9d99f28e4c83c745e /src/dynamics/rigid_body_components.rs | |
| parent | ac8ec8e3517c8d9baf8219c04ce907028d70901b (diff) | |
| download | rapier-2dfbd9ae92c139e306afc87994adac82489f30eb.tar.gz rapier-2dfbd9ae92c139e306afc87994adac82489f30eb.tar.bz2 rapier-2dfbd9ae92c139e306afc87994adac82489f30eb.zip | |
Add comments.
Diffstat (limited to 'src/dynamics/rigid_body_components.rs')
| -rw-r--r-- | src/dynamics/rigid_body_components.rs | 172 |
1 files changed, 162 insertions, 10 deletions
diff --git a/src/dynamics/rigid_body_components.rs b/src/dynamics/rigid_body_components.rs index c87df1f..2a652f7 100644 --- a/src/dynamics/rigid_body_components.rs +++ b/src/dynamics/rigid_body_components.rs @@ -6,7 +6,7 @@ use crate::geometry::{ }; use crate::math::{AngVector, AngularInertia, Isometry, Point, Real, Translation, Vector}; use crate::parry::partitioning::IndexedData; -use crate::utils::WDot; +use crate::utils::{WCross, WDot}; use num::Zero; /// The unique handle of a rigid body added to a `RigidBodySet`. @@ -69,14 +69,17 @@ pub enum RigidBodyType { } impl RigidBodyType { + /// Is this rigid-body static (i.e. cannot move)? pub fn is_static(self) -> bool { self == RigidBodyType::Static } + /// Is this rigid-body dynamic (i.e. can move and be affected by forces)? pub fn is_dynamic(self) -> bool { self == RigidBodyType::Dynamic } + /// Is this rigid-body kinematic (i.e. can move but is unaffected by forces)? pub fn is_kinematic(self) -> bool { self == RigidBodyType::Kinematic } @@ -86,10 +89,15 @@ bitflags::bitflags! { #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] /// Flags describing how the rigid-body has been modified by the user. pub struct RigidBodyChanges: u32 { + /// Flag indicating that any component of this rigid-body has been modified. const MODIFIED = 1 << 0; + /// Flag indicating that the `RigidBodyPosition` component of this rigid-body has been modified. const POSITION = 1 << 1; + /// Flag indicating that the `RigidBodyActivation` component of this rigid-body has been modified. const SLEEP = 1 << 2; + /// Flag indicating that the `RigidBodyColliders` component of this rigid-body has been modified. const COLLIDERS = 1 << 3; + /// Flag indicating that the `RigidBodyType` component of this rigid-body has been modified. const TYPE = 1 << 4; } } @@ -102,6 +110,7 @@ impl Default for RigidBodyChanges { #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Copy)] +/// The position of this rigid-body. pub struct RigidBodyPosition { /// The world-space position of the rigid-body. pub position: Isometry<Real>, @@ -127,6 +136,8 @@ impl Default for RigidBodyPosition { } impl RigidBodyPosition { + /// Computes the velocity need to travel from `self.position` to `self.next_position` in + /// a time equal to `1.0 / inv_dt`. #[must_use] pub fn interpolate_velocity(&self, inv_dt: Real) -> RigidBodyVelocity { let dpos = self.next_position * self.position.inverse(); @@ -143,6 +154,9 @@ impl RigidBodyPosition { RigidBodyVelocity { linvel, angvel } } + /// Compute new positions after integrating the given forces and velocities. + /// + /// This uses a symplectic Euler integration scheme. #[must_use] pub fn integrate_forces_and_velocities( &self, @@ -173,16 +187,23 @@ bitflags::bitflags! { #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] /// Flags affecting the behavior of the constraints solver for a given contact manifold. pub struct RigidBodyMassPropsFlags: u8 { + /// Flag indicating that the rigid-body cannot translate along any direction. const TRANSLATION_LOCKED = 1 << 0; + /// Flag indicating that the rigid-body cannot rotate along the `X` axis. const ROTATION_LOCKED_X = 1 << 1; + /// Flag indicating that the rigid-body cannot rotate along the `X` axis. const ROTATION_LOCKED_Y = 1 << 2; + /// Flag indicating that the rigid-body cannot rotate along the `X` axis. const ROTATION_LOCKED_Z = 1 << 3; + /// Combination of flags indicating that the rigid-body cannot rotate along any axis. const ROTATION_LOCKED = Self::ROTATION_LOCKED_X.bits | Self::ROTATION_LOCKED_Y.bits | Self::ROTATION_LOCKED_Z.bits; } } +// TODO: split this into "LocalMassProps" and `WorldMassProps"? #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Copy)] +/// The mass properties of this rigid-bodies. pub struct RigidBodyMassProps { /// Flags for locking rotation and translation. pub flags: RigidBodyMassPropsFlags, @@ -219,16 +240,20 @@ impl From<RigidBodyMassPropsFlags> for RigidBodyMassProps { } impl RigidBodyMassProps { + /// The mass of the rigid-body. #[must_use] - pub fn with_translations_locked(mut self) -> Self { - self.flags |= RigidBodyMassPropsFlags::TRANSLATION_LOCKED; - self + pub fn mass(&self) -> Real { + crate::utils::inv(self.mass_properties.inv_mass) } + /// The effective mass (that takes the potential translation locking into account) of + /// this rigid-body. + #[must_use] pub fn effective_mass(&self) -> Real { crate::utils::inv(self.effective_inv_mass) } + /// Update the world-space mass properties of `self`, taking into account the new position. pub fn update_world_mass_properties(&mut self, position: &Isometry<Real>) { self.world_com = self.mass_properties.world_com(&position); self.effective_inv_mass = self.mass_properties.inv_mass; @@ -286,6 +311,7 @@ impl RigidBodyMassProps { #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Copy)] +/// The velocities of this rigid-body. pub struct RigidBodyVelocity { /// The linear velocity of the rigid-body. pub linvel: Vector<Real>, @@ -300,6 +326,7 @@ impl Default for RigidBodyVelocity { } impl RigidBodyVelocity { + /// Velocities set to zero. #[must_use] pub fn zero() -> Self { Self { @@ -308,11 +335,16 @@ impl RigidBodyVelocity { } } + /// The approximate kinetic energy of this rigid-body. + /// + /// This approximation does not take the rigid-body's mass and angular inertia + /// into account. #[must_use] pub fn pseudo_kinetic_energy(&self) -> Real { self.linvel.norm_squared() + self.angvel.gdot(self.angvel) } + /// Returns the update velocities after applying the given damping. #[must_use] pub fn apply_damping(&self, dt: Real, damping: &RigidBodyDamping) -> Self { RigidBodyVelocity { @@ -321,6 +353,15 @@ impl RigidBodyVelocity { } } + /// The velocity of the given world-space point on this rigid-body. + #[must_use] + pub fn velocity_at_point(&self, point: &Point<Real>, world_com: &Point<Real>) -> Vector<Real> { + let dpt = point - world_com; + self.linvel + self.angvel.gcross(dpt) + } + + /// Integrate the velocities in `self` to compute obtain new positions when moving from the given + /// inital position `init_pos`. #[must_use] pub fn integrate( &self, @@ -336,14 +377,81 @@ impl RigidBodyVelocity { result } + /// Are these velocities exactly equal to zero? #[must_use] pub fn is_zero(&self) -> bool { self.linvel.is_zero() && self.angvel.is_zero() } + + /// The kinetic energy of this rigid-body. + #[must_use] + pub fn kinetic_energy(&self, rb_mprops: &RigidBodyMassProps) -> Real { + let mut energy = (rb_mprops.mass() * self.linvel.norm_squared()) / 2.0; + + #[cfg(feature = "dim2")] + if !rb_mprops.effective_world_inv_inertia_sqrt.is_zero() { + let inertia_sqrt = 1.0 / rb_mprops.effective_world_inv_inertia_sqrt; + energy += (inertia_sqrt * self.angvel).powi(2) / 2.0; + } + + #[cfg(feature = "dim3")] + if !rb_mprops.effective_world_inv_inertia_sqrt.is_zero() { + let inertia_sqrt = rb_mprops + .effective_world_inv_inertia_sqrt + .inverse_unchecked(); + energy += (inertia_sqrt * self.angvel).norm_squared() / 2.0; + } + + energy + } + + /// Applies an impulse at the center-of-mass of this rigid-body. + /// The impulse is applied right away, changing the linear velocity. + /// This does nothing on non-dynamic bodies. + pub fn apply_impulse(&mut self, rb_mprops: &RigidBodyMassProps, impulse: Vector<Real>) { + self.linvel += impulse * rb_mprops.effective_inv_mass; + } + + /// Applies an angular impulse at the center-of-mass of this rigid-body. + /// The impulse is applied right away, changing the angular velocity. + /// This does nothing on non-dynamic bodies. + #[cfg(feature = "dim2")] + pub fn apply_torque_impulse(&mut self, rb_mprops: &RigidBodyMassProps, torque_impulse: Real) { + self.angvel += rb_mprops.effective_world_inv_inertia_sqrt + * (rb_mprops.effective_world_inv_inertia_sqrt * torque_impulse); + } + + /// Applies an angular impulse at the center-of-mass of this rigid-body. + /// The impulse is applied right away, changing the angular velocity. + /// This does nothing on non-dynamic bodies. + #[cfg(feature = "dim3")] + pub fn apply_torque_impulse( + &mut self, + rb_mprops: &RigidBodyMassProps, + torque_impulse: Vector<Real>, + ) { + self.angvel += rb_mprops.effective_world_inv_inertia_sqrt + * (rb_mprops.effective_world_inv_inertia_sqrt * torque_impulse); + } + + /// Applies an impulse at the given world-space point of this rigid-body. + /// The impulse is applied right away, changing the linear and/or angular velocities. + /// This does nothing on non-dynamic bodies. + pub fn apply_impulse_at_point( + &mut self, + rb_mprops: &RigidBodyMassProps, + impulse: Vector<Real>, + point: Point<Real>, + ) { + let torque_impulse = (point - rb_mprops.world_com).gcross(impulse); + self.apply_impulse(rb_mprops, impulse); + self.apply_torque_impulse(rb_mprops, torque_impulse); + } } #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Copy)] +/// Damping factors to progressively slow down a rigid-body. pub struct RigidBodyDamping { /// Damping factor for gradually slowing down the translational motion of the rigid-body. pub linear_damping: Real, @@ -362,11 +470,14 @@ impl Default for RigidBodyDamping { #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Copy)] +/// The user-defined external forces applied to this rigid-body. pub struct RigidBodyForces { /// Accumulation of external forces (only for dynamic bodies). pub force: Vector<Real>, /// Accumulation of external torques (only for dynamic bodies). pub torque: AngVector<Real>, + /// Gravity is multiplied by this scaling factor before it's + /// applied to this rigid-body. pub gravity_scale: Real, } @@ -381,6 +492,7 @@ impl Default for RigidBodyForces { } impl RigidBodyForces { + /// Integrate these forces to compute new velocities. #[must_use] pub fn integrate( &self, @@ -398,17 +510,41 @@ impl RigidBodyForces { } } - pub fn add_linear_acceleration(&mut self, gravity: &Vector<Real>, mass: Real) { + /// Adds to `self` the gravitational force that would result in a gravitational acceleration + /// equal to `gravity`. + pub fn add_gravity_acceleration(&mut self, gravity: &Vector<Real>, mass: Real) { self.force += gravity * self.gravity_scale * mass; } + + /// Applies a force at the given world-space point of the rigid-body with the given mass properties. + pub fn apply_force_at_point( + &mut self, + rb_mprops: &RigidBodyMassProps, + force: Vector<Real>, + point: Point<Real>, + ) { + self.force += force; + self.torque += (point - rb_mprops.world_com).gcross(force); + } } #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Copy)] +/// Information used for Continuous-Collision-Detection. pub struct RigidBodyCcd { + /// The distance used by the CCD solver to decide if a movement would + /// result in a tunnelling problem. pub ccd_thickness: Real, + /// The max distance between this rigid-body's center of mass and its + /// furthest collider point. pub ccd_max_dist: Real, + /// Is CCD active for this rigid-body? + /// + /// If `self.ccd_enabled` is `true`, then this is automatically set to + /// `true` when the CCD solver detects that the rigid-body is moving fast + /// enough to potential cause a tunneling problem. pub ccd_active: bool, + /// Is CCD enabled for this rigid-body? pub ccd_enabled: bool, } @@ -424,6 +560,8 @@ impl Default for RigidBodyCcd { } impl RigidBodyCcd { + /// The maximum velocity any point of any collider attached to this rigid-body + /// moving with the given velocity can have. pub fn max_point_velocity(&self, vels: &RigidBodyVelocity) -> Real { #[cfg(feature = "dim2")] return vels.linvel.norm() + vels.angvel.abs() * self.ccd_max_dist; @@ -431,6 +569,7 @@ impl RigidBodyCcd { return vels.linvel.norm() + vels.angvel.norm() * self.ccd_max_dist; } + /// Is this rigid-body moving fast enough so that it may cause a tunneling problem? pub fn is_moving_fast( &self, dt: Real, @@ -463,12 +602,13 @@ impl RigidBodyCcd { #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Copy)] +/// Internal identifiers used by the physics engine. pub struct RigidBodyIds { - pub joint_graph_index: RigidBodyGraphIndex, - pub active_island_id: usize, - pub active_set_id: usize, - pub active_set_offset: usize, - pub active_set_timestamp: u32, + pub(crate) joint_graph_index: RigidBodyGraphIndex, + pub(crate) active_island_id: usize, + pub(crate) active_set_id: usize, + pub(crate) active_set_offset: usize, + pub(crate) active_set_timestamp: u32, } impl Default for RigidBodyIds { @@ -485,6 +625,11 @@ impl Default for RigidBodyIds { #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone, Debug)] +/// The set of colliders attached to this rigid-bodies. +/// +/// This should not be modified manually unless you really know what +/// you are doing (for example if you are trying to integrate Rapier +/// to a game engine using its component-based interface). pub struct RigidBodyColliders(pub Vec<ColliderHandle>); impl Default for RigidBodyColliders { @@ -494,6 +639,7 @@ impl Default for RigidBodyColliders { } impl RigidBodyColliders { + /// Detach a collider from this rigid-body. pub fn detach_collider( &mut self, rb_changes: &mut RigidBodyChanges, @@ -508,6 +654,7 @@ impl RigidBodyColliders { } } + /// Attach a collider to this rigid-body. pub fn attach_collider( &mut self, rb_changes: &mut RigidBodyChanges, @@ -541,6 +688,7 @@ impl RigidBodyColliders { rb_mprops.update_world_mass_properties(&rb_pos.position); } + /// Update the positions of all the colliders attached to this rigid-body. pub fn update_positions<Colliders>( &self, colliders: &mut Colliders, @@ -574,6 +722,7 @@ impl RigidBodyColliders { #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Copy)] +/// The dominance groups of a rigid-body. pub struct RigidBodyDominance(pub i8); impl Default for RigidBodyDominance { @@ -583,6 +732,7 @@ impl Default for RigidBodyDominance { } impl RigidBodyDominance { + /// The actually dominance group of this rigid-body, after taking into account its type. pub fn effective_group(&self, status: &RigidBodyType) -> i16 { if status.is_dynamic() { self.0 as i16 @@ -643,6 +793,7 @@ impl RigidBodyActivation { self.energy != 0.0 } + /// Wakes up this rigid-body. #[inline] pub fn wake_up(&mut self, strong: bool) { self.sleeping = false; @@ -651,6 +802,7 @@ impl RigidBodyActivation { } } + /// Put this rigid-body to sleep. #[inline] pub fn sleep(&mut self) { self.energy = 0.0; |
