feat: add soft (solver-based) ccd implementation
This commit is contained in:
committed by
Sébastien Crozet
parent
3ddf2441ea
commit
404e032433
@@ -436,7 +436,7 @@ impl RigidBody {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables of disable CCD (continuous collision-detection) for this rigid-body.
|
/// Enables of disable CCD (Continuous Collision-Detection) 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 enable_ccd(&mut self, enabled: bool) {
|
pub fn enable_ccd(&mut self, enabled: bool) {
|
||||||
@@ -448,6 +448,19 @@ impl RigidBody {
|
|||||||
self.ccd.ccd_enabled
|
self.ccd.ccd_enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enables of disable soft CCD (soft Continuous Collision-Detection) for this rigid-body.
|
||||||
|
///
|
||||||
|
/// Soft-CCD helps prevent tunneling, but may still let tunnelling happen depending on solver
|
||||||
|
/// convergence. This is cheaper than the full ccd enabled by [`RigidBody::enable_ccd`].
|
||||||
|
pub fn enable_soft_ccd(&mut self, enabled: bool) {
|
||||||
|
self.ccd.soft_ccd_enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is Soft-CCD (Soft Continous Collision-Detection) enabled for this rigid-body?
|
||||||
|
pub fn is_soft_ccd_enabled(&self) -> bool {
|
||||||
|
self.ccd.soft_ccd_enabled
|
||||||
|
}
|
||||||
|
|
||||||
// This is different from `is_ccd_enabled`. This checks that CCD
|
// This is different from `is_ccd_enabled`. This checks that CCD
|
||||||
// is active for this rigid-body, i.e., if it was seen to move fast
|
// is active for this rigid-body, i.e., if it was seen to move fast
|
||||||
// enough to justify a CCD run.
|
// enough to justify a CCD run.
|
||||||
@@ -1101,10 +1114,15 @@ pub struct RigidBodyBuilder {
|
|||||||
pub can_sleep: bool,
|
pub can_sleep: bool,
|
||||||
/// Whether or not the rigid-body is to be created asleep.
|
/// Whether or not 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.
|
||||||
|
///
|
||||||
|
/// Soft-CCD helps prevent tunneling, but may still let tunnelling happen depending on solver
|
||||||
|
/// convergence. This is cheaper than the full ccd enabled by [`RigidBodyBuilder::ccd_enabled`].
|
||||||
|
pub soft_ccd_enabled: bool,
|
||||||
/// 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?
|
||||||
@@ -1134,6 +1152,7 @@ impl RigidBodyBuilder {
|
|||||||
can_sleep: true,
|
can_sleep: true,
|
||||||
sleeping: false,
|
sleeping: false,
|
||||||
ccd_enabled: false,
|
ccd_enabled: false,
|
||||||
|
soft_ccd_enabled: false,
|
||||||
dominance_group: 0,
|
dominance_group: 0,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
user_data: 0,
|
user_data: 0,
|
||||||
@@ -1378,7 +1397,7 @@ impl RigidBodyBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether or not continuous collision-detection is enabled for this rigid-body.
|
/// Sets whether or not 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 {
|
||||||
@@ -1386,6 +1405,15 @@ impl RigidBodyBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets whether or not Soft Continuous Collision-Detection is enabled for this rigid-body.
|
||||||
|
///
|
||||||
|
/// Soft-CCD helps prevent tunneling, but may still let tunnelling happen depending on solver
|
||||||
|
/// convergence. This is cheaper than the full ccd enabled by [`RigidBodyBuilder::ccd_enabled`].
|
||||||
|
pub fn soft_ccd_enabled(mut self, enabled: bool) -> Self {
|
||||||
|
self.soft_ccd_enabled = enabled;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets whether or not the rigid-body is to be created asleep.
|
/// Sets whether or not 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;
|
||||||
@@ -1423,6 +1451,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);
|
||||||
|
|
||||||
if self.can_sleep && self.sleeping {
|
if self.can_sleep && self.sleeping {
|
||||||
rb.sleep();
|
rb.sleep();
|
||||||
|
|||||||
@@ -821,6 +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?
|
||||||
|
pub soft_ccd_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RigidBodyCcd {
|
impl Default for RigidBodyCcd {
|
||||||
@@ -830,6 +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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::dynamics::RigidBodySet;
|
||||||
use crate::geometry::{BroadPhasePairEvent, ColliderHandle, ColliderSet};
|
use crate::geometry::{BroadPhasePairEvent, ColliderHandle, ColliderSet};
|
||||||
use parry::math::Real;
|
use parry::math::Real;
|
||||||
|
|
||||||
@@ -38,8 +39,10 @@ pub trait BroadPhase {
|
|||||||
/// are still touching or closer than `prediction_distance`.
|
/// are still touching or closer than `prediction_distance`.
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
dt: Real,
|
||||||
prediction_distance: Real,
|
prediction_distance: Real,
|
||||||
colliders: &mut ColliderSet,
|
colliders: &mut ColliderSet,
|
||||||
|
bodies: &RigidBodySet,
|
||||||
modified_colliders: &[ColliderHandle],
|
modified_colliders: &[ColliderHandle],
|
||||||
removed_colliders: &[ColliderHandle],
|
removed_colliders: &[ColliderHandle],
|
||||||
events: &mut Vec<BroadPhasePairEvent>,
|
events: &mut Vec<BroadPhasePairEvent>,
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use crate::geometry::{
|
|||||||
BroadPhaseProxyIndex, ColliderBroadPhaseData, ColliderChanges, ColliderHandle,
|
BroadPhaseProxyIndex, ColliderBroadPhaseData, ColliderChanges, ColliderHandle,
|
||||||
ColliderPosition, ColliderSet, ColliderShape,
|
ColliderPosition, ColliderSet, ColliderShape,
|
||||||
};
|
};
|
||||||
use crate::math::Real;
|
use crate::math::{Isometry, Real};
|
||||||
use crate::prelude::BroadPhase;
|
use crate::prelude::{BroadPhase, RigidBodySet};
|
||||||
use crate::utils::IndexMut2;
|
use crate::utils::IndexMut2;
|
||||||
use parry::bounding_volume::BoundingVolume;
|
use parry::bounding_volume::BoundingVolume;
|
||||||
use parry::utils::hashmap::HashMap;
|
use parry::utils::hashmap::HashMap;
|
||||||
@@ -354,6 +354,7 @@ impl BroadPhaseMultiSap {
|
|||||||
handle: ColliderHandle,
|
handle: ColliderHandle,
|
||||||
proxy_index: &mut u32,
|
proxy_index: &mut u32,
|
||||||
collider: (&ColliderPosition, &ColliderShape, &ColliderChanges),
|
collider: (&ColliderPosition, &ColliderShape, &ColliderChanges),
|
||||||
|
next_position: Option<&Isometry<Real>>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let (co_pos, co_shape, co_changes) = collider;
|
let (co_pos, co_shape, co_changes) = collider;
|
||||||
|
|
||||||
@@ -361,6 +362,13 @@ impl BroadPhaseMultiSap {
|
|||||||
.compute_aabb(co_pos)
|
.compute_aabb(co_pos)
|
||||||
.loosened(prediction_distance / 2.0);
|
.loosened(prediction_distance / 2.0);
|
||||||
|
|
||||||
|
if let Some(next_position) = next_position {
|
||||||
|
let next_aabb = co_shape
|
||||||
|
.compute_aabb(next_position)
|
||||||
|
.loosened(prediction_distance / 2.0);
|
||||||
|
aabb.merge(&next_aabb);
|
||||||
|
}
|
||||||
|
|
||||||
if aabb.mins.coords.iter().any(|e| !e.is_finite())
|
if aabb.mins.coords.iter().any(|e| !e.is_finite())
|
||||||
|| aabb.maxs.coords.iter().any(|e| !e.is_finite())
|
|| aabb.maxs.coords.iter().any(|e| !e.is_finite())
|
||||||
{
|
{
|
||||||
@@ -563,8 +571,10 @@ impl BroadPhase for BroadPhaseMultiSap {
|
|||||||
/// Updates the broad-phase, taking into account the new collider positions.
|
/// Updates the broad-phase, taking into account the new collider positions.
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
dt: Real,
|
||||||
prediction_distance: Real,
|
prediction_distance: Real,
|
||||||
colliders: &mut ColliderSet,
|
colliders: &mut ColliderSet,
|
||||||
|
bodies: &RigidBodySet,
|
||||||
modified_colliders: &[ColliderHandle],
|
modified_colliders: &[ColliderHandle],
|
||||||
removed_colliders: &[ColliderHandle],
|
removed_colliders: &[ColliderHandle],
|
||||||
events: &mut Vec<BroadPhasePairEvent>,
|
events: &mut Vec<BroadPhasePairEvent>,
|
||||||
@@ -585,11 +595,19 @@ impl BroadPhase for BroadPhaseMultiSap {
|
|||||||
|
|
||||||
let mut new_proxy_id = co.bf_data.proxy_index;
|
let mut new_proxy_id = co.bf_data.proxy_index;
|
||||||
|
|
||||||
|
let next_pos = co.parent.and_then(|p| {
|
||||||
|
let parent = bodies.get(p.handle)?;
|
||||||
|
parent.is_soft_ccd_enabled().then(|| {
|
||||||
|
parent.predict_position_using_velocity_and_forces(dt) * p.pos_wrt_parent
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
if self.handle_modified_collider(
|
if self.handle_modified_collider(
|
||||||
prediction_distance,
|
prediction_distance,
|
||||||
*handle,
|
*handle,
|
||||||
&mut new_proxy_id,
|
&mut new_proxy_id,
|
||||||
(&co.pos, &co.shape, &co.changes),
|
(&co.pos, &co.shape, &co.changes),
|
||||||
|
next_pos.as_ref(),
|
||||||
) {
|
) {
|
||||||
need_region_propagation = true;
|
need_region_propagation = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ use crate::dynamics::{
|
|||||||
RigidBodyType,
|
RigidBodyType,
|
||||||
};
|
};
|
||||||
use crate::geometry::{
|
use crate::geometry::{
|
||||||
BroadPhasePairEvent, ColliderChanges, ColliderGraphIndex, ColliderHandle, ColliderPair,
|
BoundingVolume, BroadPhasePairEvent, ColliderChanges, ColliderGraphIndex, ColliderHandle,
|
||||||
ColliderSet, CollisionEvent, ContactData, ContactManifold, ContactManifoldData, ContactPair,
|
ColliderPair, ColliderSet, CollisionEvent, ContactData, ContactManifold, ContactManifoldData,
|
||||||
InteractionGraph, IntersectionPair, SolverContact, SolverFlags, TemporaryInteractionIndex,
|
ContactPair, InteractionGraph, IntersectionPair, SolverContact, SolverFlags,
|
||||||
|
TemporaryInteractionIndex,
|
||||||
};
|
};
|
||||||
use crate::math::{Real, Vector};
|
use crate::math::{Real, Vector};
|
||||||
use crate::pipeline::{
|
use crate::pipeline::{
|
||||||
@@ -896,11 +897,33 @@ 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) ||
|
||||||
|
rb2.map(|rb| rb.is_soft_ccd_enabled()) == Some(true) {
|
||||||
|
|
||||||
|
let aabb1 = co1.compute_aabb();
|
||||||
|
let aabb2 = co2.compute_aabb();
|
||||||
|
|
||||||
|
let linvel1 = rb1.map(|rb| *rb.linvel()).unwrap_or_default();
|
||||||
|
let linvel2 = rb2.map(|rb| *rb.linvel()).unwrap_or_default();
|
||||||
|
|
||||||
|
if !aabb1.intersects(&aabb2) && !aabb1.intersects_moving_aabb(&aabb2, linvel2 - linvel1) {
|
||||||
|
pair.clear();
|
||||||
|
break 'emit_events;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
prediction_distance.max(
|
||||||
|
dt * (linvel1 - linvel2).norm())
|
||||||
|
} else {
|
||||||
|
prediction_distance
|
||||||
|
};
|
||||||
|
|
||||||
let _ = query_dispatcher.contact_manifolds(
|
let _ = query_dispatcher.contact_manifolds(
|
||||||
&pos12,
|
&pos12,
|
||||||
&*co1.shape,
|
&*co1.shape,
|
||||||
&*co2.shape,
|
&*co2.shape,
|
||||||
prediction_distance,
|
effective_prediction_distance,
|
||||||
&mut pair.manifolds,
|
&mut pair.manifolds,
|
||||||
&mut pair.workspace,
|
&mut pair.workspace,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -58,8 +58,10 @@ impl CollisionPipeline {
|
|||||||
self.broadphase_collider_pairs.clear();
|
self.broadphase_collider_pairs.clear();
|
||||||
|
|
||||||
broad_phase.update(
|
broad_phase.update(
|
||||||
|
0.0,
|
||||||
prediction_distance,
|
prediction_distance,
|
||||||
colliders,
|
colliders,
|
||||||
|
bodies,
|
||||||
modified_colliders,
|
modified_colliders,
|
||||||
removed_colliders,
|
removed_colliders,
|
||||||
&mut self.broad_phase_events,
|
&mut self.broad_phase_events,
|
||||||
|
|||||||
@@ -112,8 +112,10 @@ impl PhysicsPipeline {
|
|||||||
self.broad_phase_events.clear();
|
self.broad_phase_events.clear();
|
||||||
self.broadphase_collider_pairs.clear();
|
self.broadphase_collider_pairs.clear();
|
||||||
broad_phase.update(
|
broad_phase.update(
|
||||||
|
integration_parameters.dt,
|
||||||
integration_parameters.prediction_distance,
|
integration_parameters.prediction_distance,
|
||||||
colliders,
|
colliders,
|
||||||
|
bodies,
|
||||||
modified_colliders,
|
modified_colliders,
|
||||||
removed_colliders,
|
removed_colliders,
|
||||||
&mut self.broad_phase_events,
|
&mut self.broad_phase_events,
|
||||||
|
|||||||
Reference in New Issue
Block a user