feat: add configurable distance cap to soft-ccd
This commit is contained in:
committed by
Sébastien Crozet
parent
33dd38016c
commit
6635d49c8b
@@ -46,9 +46,9 @@ pub fn init_world(testbed: &mut Testbed) {
|
|||||||
.translation(vector![0.0, 5.0, 0.0])
|
.translation(vector![0.0, 5.0, 0.0])
|
||||||
.rotation(vector![0.5, 0.0, 0.5])
|
.rotation(vector![0.5, 0.0, 0.5])
|
||||||
.linvel(vector![0.0, -100.0, 0.0])
|
.linvel(vector![0.0, -100.0, 0.0])
|
||||||
.soft_ccd_enabled(true);
|
.soft_ccd_prediction(10.0);
|
||||||
let handle = bodies.insert(rigid_body);
|
let handle = bodies.insert(rigid_body);
|
||||||
let collider = ColliderBuilder::cuboid(0.01, 0.015, 5.0);
|
let collider = ColliderBuilder::cuboid(5.0, 0.015, 5.0);
|
||||||
colliders.insert_with_parent(collider, handle, &mut bodies);
|
colliders.insert_with_parent(collider, handle, &mut bodies);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -448,17 +448,26 @@ impl RigidBody {
|
|||||||
self.ccd.ccd_enabled
|
self.ccd.ccd_enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables of disable soft CCD (soft Continuous Collision-Detection) for this rigid-body.
|
/// Sets the maximum prediction distance Soft Continuous Collision-Detection.
|
||||||
///
|
///
|
||||||
/// Soft-CCD helps prevent tunneling, but may still let tunnelling happen depending on solver
|
/// When set to 0, soft-CCD is disabled. Soft-CCD helps prevent tunneling especially of
|
||||||
/// convergence. This is cheaper than the full ccd enabled by [`RigidBody::enable_ccd`].
|
/// slow-but-thin to moderately fast objects. The soft CCD prediction distance indicates how
|
||||||
pub fn enable_soft_ccd(&mut self, enabled: bool) {
|
/// far in the object’s path the CCD algorithm is allowed to inspect. Large values can impact
|
||||||
self.ccd.soft_ccd_enabled = enabled;
|
/// performance badly by increasing the work needed from the broad-phase.
|
||||||
|
///
|
||||||
|
/// It is a generally cheaper variant of regular CCD (that can be enabled with
|
||||||
|
/// [`RigidBody::enable_ccd`] since it relies on predictive constraints instead of
|
||||||
|
/// shape-cast and substeps.
|
||||||
|
pub fn set_soft_ccd_prediction(&mut self, prediction_distance: Real) {
|
||||||
|
self.ccd.soft_ccd_prediction = prediction_distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is Soft-CCD (Soft Continous Collision-Detection) enabled for this rigid-body?
|
/// The soft-CCD prediction distance for this rigid-body.
|
||||||
pub fn is_soft_ccd_enabled(&self) -> bool {
|
///
|
||||||
self.ccd.soft_ccd_enabled
|
/// See the documentation of [`RigidBody::set_soft_ccd_prediction`] for additional details on
|
||||||
|
/// soft-CCD.
|
||||||
|
pub fn soft_ccd_prediction(&self) -> Real {
|
||||||
|
self.ccd.soft_ccd_prediction
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is different from `is_ccd_enabled`. This checks that CCD
|
// This is different from `is_ccd_enabled`. This checks that CCD
|
||||||
@@ -878,6 +887,25 @@ impl RigidBody {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Predicts the next position of this rigid-body, by integrating its velocity and forces
|
||||||
|
/// by a time of `dt`.
|
||||||
|
pub(crate) fn predict_position_using_velocity_and_forces_with_max_dist(
|
||||||
|
&self,
|
||||||
|
dt: Real,
|
||||||
|
max_dist: Real,
|
||||||
|
) -> Isometry<Real> {
|
||||||
|
let new_vels = self.forces.integrate(dt, &self.vels, &self.mprops);
|
||||||
|
// Compute the clamped dt such that the body doesn’t travel more than `max_dist`.
|
||||||
|
let linvel_norm = new_vels.linvel.norm();
|
||||||
|
let clamped_linvel = linvel_norm.min(max_dist * crate::utils::inv(dt));
|
||||||
|
let clamped_dt = dt * clamped_linvel * crate::utils::inv(linvel_norm);
|
||||||
|
new_vels.integrate(
|
||||||
|
clamped_dt,
|
||||||
|
&self.pos.position,
|
||||||
|
&self.mprops.local_mprops.local_com,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Predicts the next position of this rigid-body, by integrating its velocity and forces
|
/// Predicts the next position of this rigid-body, by integrating its velocity and forces
|
||||||
/// by a time of `dt`.
|
/// by a time of `dt`.
|
||||||
pub fn predict_position_using_velocity_and_forces(&self, dt: Real) -> Isometry<Real> {
|
pub fn predict_position_using_velocity_and_forces(&self, dt: Real) -> Isometry<Real> {
|
||||||
@@ -1110,19 +1138,25 @@ pub struct RigidBodyBuilder {
|
|||||||
mprops_flags: LockedAxes,
|
mprops_flags: LockedAxes,
|
||||||
/// The additional mass-properties of the rigid-body being built. See [`RigidBodyBuilder::additional_mass_properties`] for more information.
|
/// The additional mass-properties of the rigid-body being built. See [`RigidBodyBuilder::additional_mass_properties`] for more information.
|
||||||
additional_mass_properties: RigidBodyAdditionalMassProps,
|
additional_mass_properties: RigidBodyAdditionalMassProps,
|
||||||
/// Whether or not the rigid-body to be created can sleep if it reaches a dynamic equilibrium.
|
/// Whether the rigid-body to be created can sleep if it reaches a dynamic equilibrium.
|
||||||
pub can_sleep: bool,
|
pub can_sleep: bool,
|
||||||
/// Whether or not the rigid-body is to be created asleep.
|
/// Whether the rigid-body is to be created asleep.
|
||||||
pub sleeping: bool,
|
pub sleeping: bool,
|
||||||
/// Whether Continuous Collision-Detection is enabled for the rigid-body to be built.
|
/// Whether Continuous Collision-Detection is enabled for the rigid-body to be built.
|
||||||
///
|
///
|
||||||
/// CCD prevents tunneling, but may still allow limited interpenetration of colliders.
|
/// CCD prevents tunneling, but may still allow limited interpenetration of colliders.
|
||||||
pub ccd_enabled: bool,
|
pub ccd_enabled: bool,
|
||||||
/// Whether Soft Continuous Collision-Detection is enabled for the rigid-body to be built.
|
/// The maximum prediction distance Soft Continuous Collision-Detection.
|
||||||
///
|
///
|
||||||
/// Soft-CCD helps prevent tunneling, but may still let tunnelling happen depending on solver
|
/// When set to 0, soft CCD is disabled. Soft-CCD helps prevent tunneling especially of
|
||||||
/// convergence. This is cheaper than the full ccd enabled by [`RigidBodyBuilder::ccd_enabled`].
|
/// slow-but-thin to moderately fast objects. The soft CCD prediction distance indicates how
|
||||||
pub soft_ccd_enabled: bool,
|
/// far in the object’s path the CCD algorithm is allowed to inspect. Large values can impact
|
||||||
|
/// performance badly by increasing the work needed from the broad-phase.
|
||||||
|
///
|
||||||
|
/// It is a generally cheaper variant of regular CCD (that can be enabled with
|
||||||
|
/// [`RigidBodyBuilder::ccd_enabled`] since it relies on predictive constraints instead of
|
||||||
|
/// shape-cast and substeps.
|
||||||
|
pub soft_ccd_prediction: Real,
|
||||||
/// The dominance group of the rigid-body to be built.
|
/// The dominance group of the rigid-body to be built.
|
||||||
pub dominance_group: i8,
|
pub dominance_group: i8,
|
||||||
/// Will the rigid-body being built be enabled?
|
/// Will the rigid-body being built be enabled?
|
||||||
@@ -1152,7 +1186,7 @@ impl RigidBodyBuilder {
|
|||||||
can_sleep: true,
|
can_sleep: true,
|
||||||
sleeping: false,
|
sleeping: false,
|
||||||
ccd_enabled: false,
|
ccd_enabled: false,
|
||||||
soft_ccd_enabled: false,
|
soft_ccd_prediction: 0.0,
|
||||||
dominance_group: 0,
|
dominance_group: 0,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
user_data: 0,
|
user_data: 0,
|
||||||
@@ -1391,13 +1425,13 @@ impl RigidBodyBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether or not the rigid-body to be created can sleep if it reaches a dynamic equilibrium.
|
/// Sets whether the rigid-body to be created can sleep if it reaches a dynamic equilibrium.
|
||||||
pub fn can_sleep(mut self, can_sleep: bool) -> Self {
|
pub fn can_sleep(mut self, can_sleep: bool) -> Self {
|
||||||
self.can_sleep = can_sleep;
|
self.can_sleep = can_sleep;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether or not Continuous Collision-Detection is enabled for this rigid-body.
|
/// Sets whether Continuous Collision-Detection is enabled for this rigid-body.
|
||||||
///
|
///
|
||||||
/// CCD prevents tunneling, but may still allow limited interpenetration of colliders.
|
/// CCD prevents tunneling, but may still allow limited interpenetration of colliders.
|
||||||
pub fn ccd_enabled(mut self, enabled: bool) -> Self {
|
pub fn ccd_enabled(mut self, enabled: bool) -> Self {
|
||||||
@@ -1405,16 +1439,22 @@ impl RigidBodyBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether or not Soft Continuous Collision-Detection is enabled for this rigid-body.
|
/// Sets the maximum prediction distance Soft Continuous Collision-Detection.
|
||||||
///
|
///
|
||||||
/// Soft-CCD helps prevent tunneling, but may still let tunnelling happen depending on solver
|
/// When set to 0, soft-CCD is disabled. Soft-CCD helps prevent tunneling especially of
|
||||||
/// convergence. This is cheaper than the full ccd enabled by [`RigidBodyBuilder::ccd_enabled`].
|
/// slow-but-thin to moderately fast objects. The soft CCD prediction distance indicates how
|
||||||
pub fn soft_ccd_enabled(mut self, enabled: bool) -> Self {
|
/// far in the object’s path the CCD algorithm is allowed to inspect. Large values can impact
|
||||||
self.soft_ccd_enabled = enabled;
|
/// performance badly by increasing the work needed from the broad-phase.
|
||||||
|
///
|
||||||
|
/// It is a generally cheaper variant of regular CCD (that can be enabled with
|
||||||
|
/// [`RigidBodyBuilder::ccd_enabled`] since it relies on predictive constraints instead of
|
||||||
|
/// shape-cast and substeps.
|
||||||
|
pub fn soft_ccd_prediction(mut self, prediction_distance: Real) -> Self {
|
||||||
|
self.soft_ccd_prediction = prediction_distance;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether or not the rigid-body is to be created asleep.
|
/// Sets whether the rigid-body is to be created asleep.
|
||||||
pub fn sleeping(mut self, sleeping: bool) -> Self {
|
pub fn sleeping(mut self, sleeping: bool) -> Self {
|
||||||
self.sleeping = sleeping;
|
self.sleeping = sleeping;
|
||||||
self
|
self
|
||||||
@@ -1451,7 +1491,7 @@ impl RigidBodyBuilder {
|
|||||||
rb.dominance = RigidBodyDominance(self.dominance_group);
|
rb.dominance = RigidBodyDominance(self.dominance_group);
|
||||||
rb.enabled = self.enabled;
|
rb.enabled = self.enabled;
|
||||||
rb.enable_ccd(self.ccd_enabled);
|
rb.enable_ccd(self.ccd_enabled);
|
||||||
rb.enable_soft_ccd(self.soft_ccd_enabled);
|
rb.set_soft_ccd_prediction(self.soft_ccd_prediction);
|
||||||
|
|
||||||
if self.can_sleep && self.sleeping {
|
if self.can_sleep && self.sleeping {
|
||||||
rb.sleep();
|
rb.sleep();
|
||||||
|
|||||||
@@ -821,8 +821,8 @@ pub struct RigidBodyCcd {
|
|||||||
pub ccd_active: bool,
|
pub ccd_active: bool,
|
||||||
/// Is CCD enabled for this rigid-body?
|
/// Is CCD enabled for this rigid-body?
|
||||||
pub ccd_enabled: bool,
|
pub ccd_enabled: bool,
|
||||||
/// Is soft-CCD enabled for this rigid-body?
|
/// The soft-CCD prediction distance for this rigid-body.
|
||||||
pub soft_ccd_enabled: bool,
|
pub soft_ccd_prediction: Real,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RigidBodyCcd {
|
impl Default for RigidBodyCcd {
|
||||||
@@ -832,7 +832,7 @@ impl Default for RigidBodyCcd {
|
|||||||
ccd_max_dist: 0.0,
|
ccd_max_dist: 0.0,
|
||||||
ccd_active: false,
|
ccd_active: false,
|
||||||
ccd_enabled: false,
|
ccd_enabled: false,
|
||||||
soft_ccd_enabled: false,
|
soft_ccd_prediction: 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -597,8 +597,11 @@ impl BroadPhase for BroadPhaseMultiSap {
|
|||||||
|
|
||||||
let next_pos = co.parent.and_then(|p| {
|
let next_pos = co.parent.and_then(|p| {
|
||||||
let parent = bodies.get(p.handle)?;
|
let parent = bodies.get(p.handle)?;
|
||||||
parent.is_soft_ccd_enabled().then(|| {
|
(parent.soft_ccd_prediction() > 0.0).then(|| {
|
||||||
parent.predict_position_using_velocity_and_forces(dt) * p.pos_wrt_parent
|
parent.predict_position_using_velocity_and_forces_with_max_dist(
|
||||||
|
dt,
|
||||||
|
parent.soft_ccd_prediction(),
|
||||||
|
) * p.pos_wrt_parent
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -898,19 +898,22 @@ impl NarrowPhase {
|
|||||||
|
|
||||||
let pos12 = co1.pos.inv_mul(&co2.pos);
|
let pos12 = co1.pos.inv_mul(&co2.pos);
|
||||||
|
|
||||||
let effective_prediction_distance = if rb1.map(|rb| rb.is_soft_ccd_enabled()) == Some(true) ||
|
let soft_ccd_prediction1 = rb1.map(|rb| rb.soft_ccd_prediction()).unwrap_or(0.0);
|
||||||
rb2.map(|rb| rb.is_soft_ccd_enabled()) == Some(true) {
|
let soft_ccd_prediction2 = rb2.map(|rb| rb.soft_ccd_prediction()).unwrap_or(0.0);
|
||||||
|
let effective_prediction_distance = if soft_ccd_prediction1 > 0.0 || soft_ccd_prediction2 > 0.0 {
|
||||||
|
let aabb1 = co1.compute_aabb();
|
||||||
|
let aabb2 = co2.compute_aabb();
|
||||||
|
let inv_dt = crate::utils::inv(dt);
|
||||||
|
|
||||||
let aabb1 = co1.compute_aabb();
|
let linvel1 = rb1.map(|rb| rb.linvel()
|
||||||
let aabb2 = co2.compute_aabb();
|
.cap_magnitude(soft_ccd_prediction1 * inv_dt)).unwrap_or_default();
|
||||||
|
let linvel2 = rb2.map(|rb| rb.linvel()
|
||||||
|
.cap_magnitude(soft_ccd_prediction2 * inv_dt)).unwrap_or_default();
|
||||||
|
|
||||||
let linvel1 = rb1.map(|rb| *rb.linvel()).unwrap_or_default();
|
if !aabb1.intersects(&aabb2) && !aabb1.intersects_moving_aabb(&aabb2, linvel2 - linvel1) {
|
||||||
let linvel2 = rb2.map(|rb| *rb.linvel()).unwrap_or_default();
|
pair.clear();
|
||||||
|
break 'emit_events;
|
||||||
if !aabb1.intersects(&aabb2) && !aabb1.intersects_moving_aabb(&aabb2, linvel2 - linvel1) {
|
}
|
||||||
pair.clear();
|
|
||||||
break 'emit_events;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
prediction_distance.max(
|
prediction_distance.max(
|
||||||
|
|||||||
Reference in New Issue
Block a user