aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien Crozet <developer@crozet.re>2022-11-19 16:05:46 +0100
committerSébastien Crozet <developer@crozet.re>2022-12-11 15:20:33 +0100
commit46d976d97bc9334004a58a19bc9cab3ea78e9569 (patch)
tree0437f81f4c7882c89aafa685b2822b8c3e462b3c
parentc600549aacbde1361eba862b34a23f63d806d6a9 (diff)
downloadrapier-46d976d97bc9334004a58a19bc9cab3ea78e9569.tar.gz
rapier-46d976d97bc9334004a58a19bc9cab3ea78e9569.tar.bz2
rapier-46d976d97bc9334004a58a19bc9cab3ea78e9569.zip
Allow disabling colliders, rigid-bodies and impulse joints
-rw-r--r--src/control/character_controller.rs2
-rw-r--r--src/dynamics/island_manager.rs7
-rw-r--r--src/dynamics/joint/generic_joint.rs38
-rw-r--r--src/dynamics/joint/impulse_joint/impulse_joint_set.rs46
-rw-r--r--src/dynamics/joint/multibody_joint/multibody_joint_set.rs17
-rw-r--r--src/dynamics/rigid_body.rs34
-rw-r--r--src/dynamics/rigid_body_components.rs16
-rw-r--r--src/geometry/broad_phase_multi_sap/broad_phase.rs16
-rw-r--r--src/geometry/collider.rs41
-rw-r--r--src/geometry/collider_components.rs18
-rw-r--r--src/geometry/collider_set.rs25
-rw-r--r--src/pipeline/collision_pipeline.rs11
-rw-r--r--src/pipeline/physics_pipeline.rs13
-rw-r--r--src/pipeline/query_pipeline.rs6
-rw-r--r--src/pipeline/user_changes.rs227
15 files changed, 409 insertions, 108 deletions
diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs
index ebed952..28ba475 100644
--- a/src/control/character_controller.rs
+++ b/src/control/character_controller.rs
@@ -133,7 +133,7 @@ impl Default for KinematicCharacterController {
pub struct EffectiveCharacterMovement {
/// The movement to apply.
pub translation: Vector<Real>,
- /// Is the character touching the ground after applying `EffictiveKineamticMovement::translation`?
+ /// Is the character touching the ground after applying `EffectiveKineamticMovement::translation`?
pub grounded: bool,
}
diff --git a/src/dynamics/island_manager.rs b/src/dynamics/island_manager.rs
index 1295f14..edd2579 100644
--- a/src/dynamics/island_manager.rs
+++ b/src/dynamics/island_manager.rs
@@ -98,7 +98,8 @@ impl IslandManager {
let rb = bodies.index_mut_internal(handle);
rb.activation.wake_up(strong);
- if self.active_dynamic_set.get(rb.ids.active_set_id) != Some(&handle) {
+ if rb.is_enabled() && self.active_dynamic_set.get(rb.ids.active_set_id) != Some(&handle)
+ {
rb.ids.active_set_id = self.active_dynamic_set.len();
self.active_dynamic_set.push(handle);
}
@@ -256,12 +257,12 @@ impl IslandManager {
// in contact or joined with this collider.
push_contacting_bodies(&rb.colliders, colliders, narrow_phase, &mut self.stack);
- for inter in impulse_joints.attached_joints(handle) {
+ for inter in impulse_joints.attached_enabled_joints(handle) {
let other = crate::utils::select_other((inter.0, inter.1), handle);
self.stack.push(other);
}
- for other in multibody_joints.attached_bodies(handle) {
+ for other in multibody_joints.bodies_attached_with_enabled_joint(handle) {
self.stack.push(other);
}
diff --git a/src/dynamics/joint/generic_joint.rs b/src/dynamics/joint/generic_joint.rs
index bb1598d..4f0a791 100644
--- a/src/dynamics/joint/generic_joint.rs
+++ b/src/dynamics/joint/generic_joint.rs
@@ -5,6 +5,7 @@ use crate::utils::{WBasis, WReal};
#[cfg(feature = "dim3")]
use crate::dynamics::SphericalJoint;
+use crate::geometry::ColliderEnabled;
#[cfg(feature = "dim3")]
bitflags::bitflags! {
@@ -182,6 +183,19 @@ impl JointMotor {
}
}
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
+/// Enum indicating whether or not a joint is enabled.
+pub enum JointEnabled {
+ /// The joint is enabled.
+ Enabled,
+ /// The joint wasn’t disabled by the user explicitly but it is attached to
+ /// a disabled rigid-body.
+ DisabledByAttachedBody,
+ /// The joint is disabled by the user explicitly.
+ Disabled,
+}
+
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq)]
/// A generic joint.
@@ -208,6 +222,8 @@ pub struct GenericJoint {
pub motors: [JointMotor; SPATIAL_DIM],
/// Are contacts between the attached rigid-bodies enabled?
pub contacts_enabled: bool,
+ /// Whether or not the joint is enabled.
+ pub enabled: JointEnabled,
}
impl Default for GenericJoint {
@@ -222,6 +238,7 @@ impl Default for GenericJoint {
limits: [JointLimits::default(); SPATIAL_DIM],
motors: [JointMotor::default(); SPATIAL_DIM],
contacts_enabled: true,
+ enabled: JointEnabled::Enabled,
}
}
}
@@ -260,6 +277,27 @@ impl GenericJoint {
}
}
+ /// Is this joint enabled?
+ pub fn is_enabled(&self) -> bool {
+ self.enabled == JointEnabled::Enabled
+ }
+
+ /// Set whether this joint is enabled or not.
+ pub fn set_enabled(&mut self, enabled: bool) {
+ match self.enabled {
+ JointEnabled::Enabled | JointEnabled::DisabledByAttachedBody => {
+ if !enabled {
+ self.enabled = JointEnabled::Disabled;
+ }
+ }
+ JointEnabled::Disabled => {
+ if enabled {
+ self.enabled = JointEnabled::Enabled;
+ }
+ }
+ }
+ }
+
/// Add the specified axes to the set of axes locked by this joint.
pub fn lock_axes(&mut self, axes: JointAxesMask) -> &mut Self {
self.locked_axes |= axes;
diff --git a/src/dynamics/joint/impulse_joint/impulse_joint_set.rs b/src/dynamics/joint/impulse_joint/impulse_joint_set.rs
index 7409172..f21f950 100644
--- a/src/dynamics/joint/impulse_joint/impulse_joint_set.rs
+++ b/src/dynamics/joint/impulse_joint/impulse_joint_set.rs
@@ -72,11 +72,11 @@ impl ImpulseJointSet {
}
/// Iterates through all the joints between two rigid-bodies.
- pub fn joints_between<'a>(
- &'a self,
+ pub fn joints_between(
+ &self,
body1: RigidBodyHandle,
body2: RigidBodyHandle,
- ) -> impl Iterator<Item = (ImpulseJointHandle, &'a ImpulseJoint)> {
+ ) -> impl Iterator<Item = (ImpulseJointHandle, &ImpulseJoint)> {
self.rb_graph_ids
.get(body1.0)
.zip(self.rb_graph_ids.get(body2.0))
@@ -86,15 +86,15 @@ impl ImpulseJointSet {
}
/// Iterates through all the impulse joints attached to the given rigid-body.
- pub fn attached_joints<'a>(
- &'a self,
+ pub fn attached_joints(
+ &self,
body: RigidBodyHandle,
) -> impl Iterator<
Item = (
RigidBodyHandle,
RigidBodyHandle,
ImpulseJointHandle,
- &'a ImpulseJoint,
+ &ImpulseJoint,
),
> {
self.rb_graph_ids
@@ -104,6 +104,35 @@ impl ImpulseJointSet {
.map(|inter| (inter.0, inter.1, inter.2.handle, inter.2))
}
+ /// Iterates through all the impulse joints attached to the given rigid-body.
+ pub fn map_attached_joints_mut<'a>(
+ &'a mut self,
+ body: RigidBodyHandle,
+ mut f: impl FnMut(RigidBodyHandle, RigidBodyHandle, ImpulseJointHandle, &mut ImpulseJoint),
+ ) {
+ self.rb_graph_ids.get(body.0).into_iter().for_each(|id| {
+ for inter in self.joint_graph.interactions_with_mut(*id) {
+ (f)(inter.0, inter.1, inter.3.handle, inter.3)
+ }
+ })
+ }
+
+ /// Iterates through all the enabled impulse joints attached to the given rigid-body.
+ pub fn attached_enabled_joints(
+ &self,
+ body: RigidBodyHandle,
+ ) -> impl Iterator<
+ Item = (
+ RigidBodyHandle,
+ RigidBodyHandle,
+ ImpulseJointHandle,
+ &ImpulseJoint,
+ ),
+ > {
+ self.attached_joints(body)
+ .filter(|inter| inter.3.data.is_enabled())
+ }
+
/// Is the given joint handle valid?
pub fn contains(&self, handle: ImpulseJointHandle) -> bool {
self.joint_ids.contains(handle.0)
@@ -246,7 +275,7 @@ impl ImpulseJointSet {
ImpulseJointHandle(handle)
}
- /// Retrieve all the impulse_joints happening between two active bodies.
+ /// Retrieve all the enabled impulse joints happening between two active bodies.
// NOTE: this is very similar to the code from NarrowPhase::select_active_interactions.
pub(crate) fn select_active_interactions(
&self,
@@ -264,7 +293,8 @@ impl ImpulseJointSet {
let rb1 = &bodies[joint.body1];
let rb2 = &bodies[joint.body2];
- if (rb1.is_dynamic() || rb2.is_dynamic())
+ if joint.data.is_enabled()
+ && (rb1.is_dynamic() || rb2.is_dynamic())
&& (!rb1.is_dynamic() || !rb1.is_sleeping())
&& (!rb2.is_dynamic() || !rb2.is_sleeping())
{
diff --git a/src/dynamics/joint/multibody_joint/multibody_joint_set.rs b/src/dynamics/joint/multibody_joint/multibody_joint_set.rs
index c25de73..a4b338a 100644
--- a/src/dynamics/joint/multibody_joint/multibody_joint_set.rs
+++ b/src/dynamics/joint/multibody_joint/multibody_joint_set.rs
@@ -372,7 +372,7 @@ impl MultibodyJointSet {
}
/// Iterate through the handles of all the rigid-bodies attached to this rigid-body
- /// by an multibody_joint.
+ /// by a multibody_joint.
pub fn attached_bodies<'a>(
&'a self,
body: RigidBodyHandle,
@@ -384,6 +384,21 @@ impl MultibodyJointSet {
.map(move |inter| crate::utils::select_other((inter.0, inter.1), body))
}
+ /// Iterate through the handles of all the rigid-bodies attached to this rigid-body
+ /// by an enabled multibody_joint.
+ pub fn bodies_attached_with_enabled_joint<'a>(
+ &'a self,
+ body: RigidBodyHandle,
+ ) -> impl Iterator<Item = RigidBodyHandle> + 'a {
+ self.attached_bodies(body).filter(move |other| {
+ if let Some((_, _, link)) = self.joint_between(body, *other) {
+ link.joint.data.is_enabled()
+ } else {
+ false
+ }
+ })
+ }
+
/// Iterates through all the multibodies on this set.
pub fn multibodies(&self) -> impl Iterator<Item = &Multibody> {
self.multibodies.iter().map(|e| e.1)
diff --git a/src/dynamics/rigid_body.rs b/src/dynamics/rigid_body.rs
index 9c38eee..a6384b7 100644
--- a/src/dynamics/rigid_body.rs
+++ b/src/dynamics/rigid_body.rs
@@ -35,6 +35,7 @@ pub struct RigidBody {
pub(crate) body_type: RigidBodyType,
/// The dominance group this rigid-body is part of.
pub(crate) dominance: RigidBodyDominance,
+ pub(crate) enabled: bool,
/// User-defined data associated to this rigid-body.
pub user_data: u128,
}
@@ -61,6 +62,7 @@ impl RigidBody {
changes: RigidBodyChanges::all(),
body_type: RigidBodyType::Dynamic,
dominance: RigidBodyDominance::default(),
+ enabled: true,
user_data: 0,
}
}
@@ -81,6 +83,28 @@ impl RigidBody {
&mut self.activation
}
+ /// Is this rigid-body enabled?
+ pub fn is_enabled(&self) -> bool {
+ self.enabled
+ }
+
+ /// Sets whether this rigid-body is enabled or not.
+ pub fn set_enabled(&mut self, enabled: bool) {
+ if enabled != self.enabled {
+ if enabled {
+ // NOTE: this is probably overkill, but it makes sure we don’t
+ // forget anything that needs to be updated because the rigid-body
+ // was basically interpreted as if it was removed while it was
+ // disabled.
+ self.changes = RigidBodyChanges::all();
+ } else {
+ self.changes |= RigidBodyChanges::ENABLED_OR_DISABLED;
+ }
+
+ self.enabled = enabled;
+ }
+ }
+
/// The linear damping coefficient of this rigid-body.
#[inline]
pub fn linear_damping(&self) -> Real {
@@ -963,6 +987,8 @@ pub struct RigidBodyBuilder {
pub ccd_enabled: bool,
/// The dominance group of the rigid-body to be built.
pub dominance_group: i8,
+ /// Will the rigid-body being built be enabled?
+ pub enabled: bool,
/// An arbitrary user-defined 128-bit integer associated to the rigid-bodies built by this builder.
pub user_data: u128,
}
@@ -984,6 +1010,7 @@ impl RigidBodyBuilder {
sleeping: false,
ccd_enabled: false,
dominance_group: 0,
+ enabled: true,
user_data: 0,
}
}
@@ -1230,6 +1257,12 @@ impl RigidBodyBuilder {
self
}
+ /// Enable or disable the rigid-body after its creation.
+ pub fn enabled(mut self, enabled: bool) -> Self {
+ self.enabled = enabled;
+ self
+ }
+
/// Build a new rigid-body with the parameters configured with this builder.
pub fn build(&self) -> RigidBody {
let mut rb = RigidBody::new();
@@ -1252,6 +1285,7 @@ impl RigidBodyBuilder {
rb.damping.angular_damping = self.angular_damping;
rb.forces.gravity_scale = self.gravity_scale;
rb.dominance = RigidBodyDominance(self.dominance_group);
+ rb.enabled = self.enabled;
rb.enable_ccd(self.ccd_enabled);
if self.can_sleep && self.sleeping {
diff --git a/src/dynamics/rigid_body_components.rs b/src/dynamics/rigid_body_components.rs
index cabf6ca..eb94c6b 100644
--- a/src/dynamics/rigid_body_components.rs
+++ b/src/dynamics/rigid_body_components.rs
@@ -112,6 +112,8 @@ bitflags::bitflags! {
const DOMINANCE = 1 << 5;
/// Flag indicating that the local mass-properties of this rigid-body must be recomputed.
const LOCAL_MASS_PROPERTIES = 1 << 6;
+ /// Flag indicating that the rigid-body was enabled or disabled.
+ const ENABLED_OR_DISABLED = 1 << 7;
}
}
@@ -329,12 +331,14 @@ impl RigidBodyMassProps {
for handle in &attached_colliders.0 {
if let Some(co) = colliders.get(*handle) {
- if let Some(co_parent) = co.parent {
- let to_add = co
- .mprops
- .mass_properties(&*co.shape)
- .transform_by(&co_parent.pos_wrt_parent);
- self.local_mprops += to_add;
+ if co.is_enabled() {
+ if let Some(co_parent) = co.parent {
+ let to_add = co
+ .mprops
+ .mass_properties(&*co.shape)
+ .transform_by(&co_parent.pos_wrt_parent);
+ self.local_mprops += to_add;
+ }
}
}
}
diff --git a/src/geometry/broad_phase_multi_sap/broad_phase.rs b/src/geometry/broad_phase_multi_sap/broad_phase.rs
index 915017d..0667184 100644
--- a/src/geometry/broad_phase_multi_sap/broad_phase.rs
+++ b/src/geometry/broad_phase_multi_sap/broad_phase.rs
@@ -176,7 +176,11 @@ impl BroadPhase {
/// This method will actually remove from the proxy list all the proxies
/// marked as deletable by `self.predelete_proxy`, making their proxy
/// handles re-usable by new proxies.
- fn complete_removals(&mut self, removed_colliders: &[ColliderHandle]) {
+ fn complete_removals(
+ &mut self,
+ colliders: &mut ColliderSet,
+ removed_colliders: &[ColliderHandle],
+ ) {
// If there is no layer, there is nothing to remove.
if self.layers.is_empty() {
return;
@@ -224,6 +228,11 @@ impl BroadPhase {
self.proxies.remove(proxy_id);
}
}
+
+ if let Some(co) = colliders.get_mut_internal(*removed) {
+ // Reset the proxy index.
+ co.bf_data.proxy_index = crate::INVALID_U32;
+ }
}
}
@@ -460,9 +469,10 @@ impl BroadPhase {
// NOTE: we use `get` because the collider may no longer
// exist if it has been removed.
if let Some(co) = colliders.get_mut_internal(*handle) {
- if !co.changes.needs_broad_phase_update() {
+ if !co.is_enabled() || !co.changes.needs_broad_phase_update() {
continue;
}
+
let mut new_proxy_id = co.bf_data.proxy_index;
if self.handle_modified_collider(
@@ -496,7 +506,7 @@ impl BroadPhase {
// Phase 5: bottom-up pass to remove proxies, and propagate region removed from smaller
// layers to possible remove regions from larger layers that would become empty that way.
- self.complete_removals(removed_colliders);
+ self.complete_removals(colliders, removed_colliders);
}
/// Propagate regions from the smallest layers up to the larger layers.
diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs
index 95ae273..6759b81 100644
--- a/src/geometry/collider.rs
+++ b/src/geometry/collider.rs
@@ -7,6 +7,7 @@ use crate::geometry::{
use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector, DIM};
use crate::parry::transformation::vhacd::VHACDParameters;
use crate::pipeline::{ActiveEvents, ActiveHooks};
+use crate::prelude::ColliderEnabled;
use na::Unit;
use parry::bounding_volume::Aabb;
use parry::shape::{Shape, TriMeshFlags};
@@ -154,6 +155,32 @@ impl Collider {
}
}
+ /// Is this collider enabled?
+ pub fn is_enabled(&self) -> bool {
+ match self.flags.enabled {
+ ColliderEnabled::Enabled => true,
+ _ => false,
+ }
+ }
+
+ /// Sets whether or not this collider is enabled.
+ pub fn set_enabled(&mut self, enabled: bool) {
+ match self.flags.enabled {
+ ColliderEnabled::Enabled | ColliderEnabled::DisabledByParent => {
+ if !enabled {
+ self.changes.insert(ColliderChanges::ENABLED_OR_DISABLED);
+ self.flags.enabled = ColliderEnabled::Disabled;
+ }
+ }
+ ColliderEnabled::Disabled => {
+ if enabled {
+ self.changes.insert(ColliderChanges::ENABLED_OR_DISABLED);
+ self.flags.enabled = ColliderEnabled::Enabled;
+ }
+ }
+ }
+ }
+
/// Sets the translational part of this collider's position.
pub fn set_translation(&mut self, translation: Vector<Real>) {
self.changes.insert(ColliderChanges::POSITION);
@@ -402,6 +429,8 @@ pub struct ColliderBuilder {
pub collision_groups: InteractionGroups,
/// The solver groups for the collider being built.
pub solver_groups: InteractionGroups,
+ /// Will the collider being built be enabled?
+ pub enabled: bool,
/// The total force magnitude beyond which a contact force event can be emitted.
pub contact_force_event_threshold: Real,
}
@@ -424,6 +453,7 @@ impl ColliderBuilder {
active_collision_types: ActiveCollisionTypes::default(),
active_hooks: ActiveHooks::empty(),
active_events: ActiveEvents::empty(),
+ enabled: true,
contact_force_event_threshold: 0.0,
}
}
@@ -834,6 +864,12 @@ impl ColliderBuilder {
self
}
+ /// Enable or disable the collider after its creation.
+ pub fn enabled(mut self, enabled: bool) -> Self {
+ self.enabled = enabled;
+ self
+ }
+
/// Builds a new collider attached to the given rigid-body.
pub fn build(&self) -> Collider {
let shape = self.shape.clone();
@@ -849,6 +885,11 @@ impl ColliderBuilder {
active_collision_types: self.active_collision_types,
active_hooks: self.active_hooks,
active_events: self.active_events,
+ enabled: if self.enabled {
+ ColliderEnabled::Enabled
+ } else {
+ ColliderEnabled::Disabled
+ },
};
let changes = ColliderChanges::all();
let pos = ColliderPosition(self.position);
diff --git a/src/geometry/collider_components.rs b/src/geometry/collider_components.rs
index 29a24b5..0e65bac 100644
--- a/src/geometry/collider_components.rs
+++ b/src/geometry/collider_components.rs
@@ -64,6 +64,8 @@ bitflags::bitflags! {
/// 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 << 7; // NF update.
+ /// Flag indicating that whether or not the collider is enabled was changed.
+ const ENABLED_OR_DISABLED = 1 << 8; // BF & NF updates.
}
}
@@ -374,6 +376,19 @@ impl Default for ActiveCollisionTypes {
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
+/// Enum indicating whether or not a collider is enabled.
+pub enum ColliderEnabled {
+ /// The collider is enabled.
+ Enabled,
+ /// The collider wasn’t disabled by the user explicitly but it is attached to
+ /// a disabled rigid-body.
+ DisabledByParent,
+ /// The collider is disabled by the user explicitly.
+ Disabled,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// A set of flags for controlling collision/intersection filtering, modification, and events.
pub struct ColliderFlags {
/// Controls whether collision-detection happens between two colliders depending on
@@ -389,6 +404,8 @@ pub struct ColliderFlags {
pub active_hooks: ActiveHooks,
/// The events enabled for this collider.
pub active_events: ActiveEvents,
+ /// Whether or not the collider is enabled.
+ pub enabled: ColliderEnabled,
}
impl Default for ColliderFlags {
@@ -399,6 +416,7 @@ impl Default for ColliderFlags {
solver_groups: InteractionGroups::all(),
active_hooks: ActiveHooks::empty(),
active_events: ActiveEvents::empty(),
+ enabled: ColliderEnabled::Enabled,
}
}
}
diff --git a/src/geometry/collider_set.rs b/src/geometry/collider_set.rs
index b141445..1069f1b 100644
--- a/src/geometry/collider_set.rs
+++ b/src/geometry/collider_set.rs
@@ -41,6 +41,14 @@ impl ColliderSet {
self.colliders.iter().map(|(h, c)| (ColliderHandle(h), c))
}
+ /// Iterate through all the enabled colliders on this set.
+ pub fn iter_enabled(&self) -> impl Iterator<Item = (ColliderHandle, &Collider)> {
+ self.colliders
+ .iter()
+ .map(|(h, c)| (ColliderHandle(h), c))
+ .filter(|(_, c)| c.is_enabled())
+ }
+
/// Iterates mutably through all the colliders on this set.
#[cfg(not(feature = "dev-remove-slow-accessors"))]
pub fn iter_mut(&mut self) -> impl Iterator<Item = (ColliderHandle, &mut Collider)> {
@@ -52,6 +60,12 @@ impl ColliderSet {
})
}
+ /// Iterates mutably through all the enabled colliders on this set.
+ #[cfg(not(feature = "dev-remove-slow-accessors"))]
+ pub fn iter_enabled_mut(&mut self) -> impl Iterator<Item = (ColliderHandle, &mut Collider)> {
+ self.iter_mut().filter(|(_, c)| c.is_enabled())
+ }
+
/// The number of colliders on this set.
pub fn len(&self) -> usize {
self.colliders.len()
@@ -268,6 +282,17 @@ impl ColliderSet {
pub(crate) fn get_mut_internal(&mut self, handle: ColliderHandle) -> Option<&mut Collider> {
self.colliders.get_mut(handle.0)
}
+
+ // Just a very long name instead of `.get_mut` to make sure
+ // this is really the method we wanted to use instead of `get_mut_internal`.
+ pub(crate) fn get_mut_internal_with_modification_tracking(
+ &mut self,
+ handle: ColliderHandle,
+ ) -> Option<&mut Collider> {
+ let result = self.colliders.get_mut(handle.0)?;
+ Self::mark_as_modified(handle, result, &mut self.modified_colliders);
+ Some(result)
+ }
}
impl Index<crate::data::Index> for ColliderSet {
diff --git a/src/pipeline/collision_pipeline.rs b/src/pipeline/collision_pipeline.rs
index ac92a04..631388b 100644
--- a/src/pipeline/collision_pipeline.rs
+++ b/src/pipeline/collision_pipeline.rs
@@ -127,9 +127,20 @@ impl CollisionPipeline {
None,
bodies,
colliders,
+ &mut ImpulseJointSet::new(),
+ &mut MultibodyJointSet::new(),
&modified_bodies,
&mut modified_colliders,
);
+
+ // Disabled colliders are treated as if they were removed.
+ removed_colliders.extend(
+ modified_colliders
+ .iter()
+ .copied()
+ .filter(|h| colliders.get(*h).map(|c| !c.is_enabled()).unwrap_or(false)),
+ );
+
self.detect_collisions(
prediction_distance,
broad_phase,
diff --git a/src/pipeline/physics_pipeline.rs b/src/pipeline/physics_pipeline.rs
index 391b39a..f05a3f0 100644
--- a/src/pipeline/physics_pipeline.rs
+++ b/src/pipeline/physics_pipeline.rs
@@ -422,6 +422,7 @@ impl PhysicsPipeline {
// Apply modifications.
let mut modified_colliders = colliders.take_modified();
let mut removed_colliders = colliders.take_removed();
+
super::user_changes::handle_user_changes_to_colliders(
bodies,
colliders,
@@ -433,10 +434,22 @@ impl PhysicsPipeline {
Some(islands),
bodies,
colliders,
+ impulse_joints,
+ multibody_joints,
&modified_bodies,
&mut modified_colliders,
);
+ // Disabled colliders are treated as if they were removed.
+ // NOTE: this must be called here, after handle_user_changes_to_rigid_bodies to take into
+ // account colliders disabled because of their parent rigid-body.
+ removed_colliders.extend(
+ modified_colliders
+ .iter()
+ .copied()
+ .filter(|h| colliders.get(*h).map(|c| !c.is_enabled()).unwrap_or(false)),
+ );
+
// TODO: do this only on user-change.
// TODO: do we want some kind of automatic inverse kinematics?
for multibody in &mut multibody_joints.multibodies {
diff --git a/src/pipeline/query_pipeline.rs b/src/pipeline/query_pipeline.rs
index 00825e2..6682370 100644
--- a/src/pipeline/query_pipeline.rs
+++ b/src/pipeline/query_pipeline.rs
@@ -358,12 +358,12 @@ impl QueryPipeline {
fn for_each(&mut self, mut f: impl FnMut(ColliderHandle, Aabb)) {
match self.mode {
QueryPipelineMode::CurrentPosition => {
- for (h, co) in self.colliders.iter() {
+ for (h, co) in self.colliders.iter_enabled() {
f(h, co.shape.compute_aabb(&co.pos))
}
}
QueryPipelineMode::SweepTestWithNextPosition => {
- for (h, co) in self.colliders.iter() {
+ for (h, co) in self.colliders.iter_enabled() {
if let Some(co_parent) = co.parent {
let rb_next_pos = &self.bodies[co_parent.handle].pos.next_position;
let next_position = rb_next_pos * co_parent.pos_wrt_parent;
@@ -374,7 +374,7 @@ impl QueryPipeline {
}
}
QueryPipelineMode::SweepTestWithPredictedPosition { dt } => {
- for (h, co) in self.colliders.iter() {
+ for (h, co) in self.colliders.iter_enabled() {
if let Some(co_parent) = co.parent {
let rb = &self.bodies[co_parent.handle];
let predicted_pos = rb.pos.integrate_forces_and_velocities(
diff --git a/src/pipeline/user_changes.rs b/src/pipeline/user_changes.rs
index e7da68a..adfd023 100644
--- a/src/pipeline/user_changes.rs
+++ b/src/pipeline/user_changes.rs
@@ -1,7 +1,10 @@
use crate::dynamics::{
- IslandManager, RigidBodyChanges, RigidBodyHandle, RigidBodySet, RigidBodyType,
+ ImpulseJointSet, IslandManager, JointEnabled, MultibodyJointSet, RigidBodyChanges,
+ RigidBodyHandle, RigidBodySet, RigidBodyType,
+};
+use crate::geometry::{
+ ColliderChanges, ColliderEnabled, ColliderHandle, ColliderPosition, ColliderSet,
};
-use crate::geometry::{ColliderChanges, ColliderHandle, ColliderPosition, ColliderSet};
pub(crate) fn handle_user_changes_to_colliders(
bodies: &mut RigidBodySet,
@@ -21,10 +24,12 @@ pub(crate) fn handle_user_changes_to_colliders(
}
}
- if co
- .changes
- .intersects(ColliderChanges::SHAPE | ColliderChanges::LOCAL_MASS_PROPERTIES)
- {
+ if co.changes.intersects(
+ ColliderChanges::SHAPE
+ | ColliderChanges::LOCAL_MASS_PROPERTIES
+ | ColliderChanges::ENABLED_OR_DISABLED
+ | ColliderChanges::PARENT,
+ ) {
if let Some(rb) = co
.parent
.and_then(|p| bodies.get_mut_internal_with_modification_tracking(p.handle))
@@ -40,12 +45,15 @@ pub(crate) fn handle_user_changes_to_rigid_bodies(
mut islands: Option<&mut IslandManager>,
bodies: &mut RigidBodySet,
colliders: &mut ColliderSet,
+ impulse_joints: &mut ImpulseJointSet,
+ multibody_joints: &mut MultibodyJointSet,
modified_bodies: &[RigidBodyHandle],
modified_colliders: &mut Vec<ColliderHandle>,
) {
enum FinalAction {
- UpdateActiveKinematicSetId,
- UpdateActiveDynamicSetId,
+ UpdateActiveKinematicSetId(usize),
+ UpdateActiveDynamicSetId(usize),
+ RemoveFromIsland,
}
for handle in modified_bodies {
@@ -62,89 +70,95 @@ pub(crate) fn handle_user_changes_to_rigid_bodies(
let mut activation = rb.activation;
{
- // The body's status changed. We need to make sure
- // it is on the correct active set.
- if let Some(islands) = islands.as_deref_mut() {
- if changes.contains(RigidBodyChanges::TYPE) {
- match rb.body_type {
- RigidBodyType::Dynamic => {
- // Remove from the active kinematic set if it was there.
- if islands.active_kinematic_set.get(ids.active_set_id) == Some(handle) {
- islands.active_kinematic_set.swap_remove(ids.active_set_id);
- final_action = Some((
- FinalAction::UpdateActiveKinematicSetId,
- ids.active_set_id,
- ));
- }
-
- // Add to the active dynamic set.
- activation.wake_up(true);
- // Make sure the sleep change flag is set (even if for some
- // reasons the rigid-body was already awake) to make
- // sure the code handling sleeping change adds the body to
- // the active_dynamic_set.
- changes.set(RigidBodyChanges::SLEEP, true);
- }
- RigidBodyType::KinematicVelocityBased
- | RigidBodyType::KinematicPositionBased => {
- // Remove from the active dynamic set if it was there.
- if islands.active_dynamic_set.get(ids.active_set_id) == Some(handle) {
- islands.active_dynamic_set.swap_remove(ids.active_set_id);
- final_action = Some((
- FinalAction::UpdateActiveDynamicSetId,
- ids.active_set_id,
- ));
+ if rb.is_enabled() {
+ // The body's status changed. We need to make sure
+ // it is on the correct active set.
+ if let Some(islands) = islands.as_deref_mut() {
+ if changes.contains(RigidBodyChanges::TYPE) {