Allow locking individual translational axes

This commit is contained in:
Sébastien Crozet
2022-01-09 22:15:36 +01:00
parent 2bfceadf06
commit b631fe9193
16 changed files with 216 additions and 105 deletions

View File

@@ -203,14 +203,20 @@ 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 the `X` axis.
const TRANSLATION_LOCKED_X = 1 << 0;
/// Flag indicating that the rigid-body cannot translate along the `Y` axis.
const TRANSLATION_LOCKED_Y = 1 << 1;
/// Flag indicating that the rigid-body cannot translate along the `Z` axis.
const TRANSLATION_LOCKED_Z = 1 << 2;
/// Flag indicating that the rigid-body cannot translate along any direction.
const TRANSLATION_LOCKED = 1 << 0;
const TRANSLATION_LOCKED = Self::TRANSLATION_LOCKED_X.bits | Self::TRANSLATION_LOCKED_Y.bits | Self::TRANSLATION_LOCKED_Z.bits;
/// Flag indicating that the rigid-body cannot rotate along the `X` axis.
const ROTATION_LOCKED_X = 1 << 1;
const ROTATION_LOCKED_X = 1 << 3;
/// Flag indicating that the rigid-body cannot rotate along the `Y` axis.
const ROTATION_LOCKED_Y = 1 << 2;
const ROTATION_LOCKED_Y = 1 << 4;
/// Flag indicating that the rigid-body cannot rotate along the `Z` axis.
const ROTATION_LOCKED_Z = 1 << 3;
const ROTATION_LOCKED_Z = 1 << 5;
/// 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;
}
@@ -228,7 +234,7 @@ pub struct RigidBodyMassProps {
/// The world-space center of mass of the rigid-body.
pub world_com: Point<Real>,
/// The inverse mass taking into account translation locking.
pub effective_inv_mass: Real,
pub effective_inv_mass: Vector<Real>,
/// The square-root of the world-space inverse angular inertia tensor of the rigid-body,
/// taking into account rotation locking.
pub effective_world_inv_inertia_sqrt: AngularInertia<Real>,
@@ -240,7 +246,7 @@ impl Default for RigidBodyMassProps {
flags: RigidBodyMassPropsFlags::empty(),
local_mprops: MassProperties::zero(),
world_com: Point::origin(),
effective_inv_mass: 0.0,
effective_inv_mass: Vector::zero(),
effective_world_inv_inertia_sqrt: AngularInertia::zero(),
}
}
@@ -274,8 +280,8 @@ impl RigidBodyMassProps {
/// 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)
pub fn effective_mass(&self) -> Vector<Real> {
self.effective_inv_mass.map(crate::utils::inv)
}
/// The effective world-space angular inertia (that takes the potential rotation locking into account) of
@@ -288,16 +294,31 @@ impl RigidBodyMassProps {
/// 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.local_mprops.world_com(&position);
self.effective_inv_mass = self.local_mprops.inv_mass;
self.effective_inv_mass = Vector::repeat(self.local_mprops.inv_mass);
self.effective_world_inv_inertia_sqrt =
self.local_mprops.world_inv_inertia_sqrt(&position.rotation);
// Take into account translation/rotation locking.
if self
.flags
.contains(RigidBodyMassPropsFlags::TRANSLATION_LOCKED)
.contains(RigidBodyMassPropsFlags::TRANSLATION_LOCKED_X)
{
self.effective_inv_mass = 0.0;
self.effective_inv_mass.x = 0.0;
}
if self
.flags
.contains(RigidBodyMassPropsFlags::TRANSLATION_LOCKED_Y)
{
self.effective_inv_mass.y = 0.0;
}
#[cfg(feature = "dim3")]
if self
.flags
.contains(RigidBodyMassPropsFlags::TRANSLATION_LOCKED_Z)
{
self.effective_inv_mass.z = 0.0;
}
#[cfg(feature = "dim2")]
@@ -536,7 +557,7 @@ impl RigidBodyVelocity {
/// 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;
self.linvel += impulse.component_mul(&rb_mprops.effective_inv_mass);
}
/// Applies an angular impulse at the center-of-mass of this rigid-body.
@@ -659,7 +680,7 @@ impl RigidBodyForces {
init_vels: &RigidBodyVelocity,
mprops: &RigidBodyMassProps,
) -> RigidBodyVelocity {
let linear_acc = self.force * mprops.effective_inv_mass;
let linear_acc = self.force.component_mul(&mprops.effective_inv_mass);
let angular_acc = mprops.effective_world_inv_inertia_sqrt
* (mprops.effective_world_inv_inertia_sqrt * self.torque);
@@ -671,8 +692,8 @@ impl RigidBodyForces {
/// 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;
pub fn add_gravity_acceleration(&mut self, gravity: &Vector<Real>, mass: &Vector<Real>) {
self.force += gravity.component_mul(&mass) * self.gravity_scale;
}
/// Applies a force at the given world-space point of the rigid-body with the given mass properties.