diff options
Diffstat (limited to 'src/pipeline')
| -rw-r--r-- | src/pipeline/collision_pipeline.rs | 10 | ||||
| -rw-r--r-- | src/pipeline/event_handler.rs | 25 | ||||
| -rw-r--r-- | src/pipeline/mod.rs | 6 | ||||
| -rw-r--r-- | src/pipeline/physics_hooks.rs | 69 | ||||
| -rw-r--r-- | src/pipeline/physics_pipeline.rs | 56 | ||||
| -rw-r--r-- | src/pipeline/query_pipeline.rs | 42 | ||||
| -rw-r--r-- | src/pipeline/user_changes.rs | 3 |
7 files changed, 139 insertions, 72 deletions
diff --git a/src/pipeline/collision_pipeline.rs b/src/pipeline/collision_pipeline.rs index 455e75d..d789da7 100644 --- a/src/pipeline/collision_pipeline.rs +++ b/src/pipeline/collision_pipeline.rs @@ -6,7 +6,7 @@ use crate::dynamics::{ RigidBodyIds, RigidBodyPosition, RigidBodyType, RigidBodyVelocity, }; use crate::geometry::{ - BroadPhase, BroadPhasePairEvent, ColliderBroadPhaseData, ColliderChanges, ColliderGroups, + BroadPhase, BroadPhasePairEvent, ColliderBroadPhaseData, ColliderChanges, ColliderFlags, ColliderHandle, ColliderMaterial, ColliderPair, ColliderParent, ColliderPosition, ColliderShape, ColliderType, NarrowPhase, }; @@ -65,8 +65,8 @@ impl CollisionPipeline { + ComponentSet<ColliderShape> + ComponentSetOption<ColliderParent> + ComponentSet<ColliderType> - + ComponentSet<ColliderGroups> - + ComponentSet<ColliderMaterial>, + + ComponentSet<ColliderMaterial> + + ComponentSet<ColliderFlags>, { // Update broad-phase. self.broad_phase_events.clear(); @@ -172,8 +172,8 @@ impl CollisionPipeline { + ComponentSet<ColliderShape> + ComponentSetOption<ColliderParent> + ComponentSet<ColliderType> - + ComponentSet<ColliderGroups> - + ComponentSet<ColliderMaterial>, + + ComponentSet<ColliderMaterial> + + ComponentSet<ColliderFlags>, { super::user_changes::handle_user_changes_to_colliders( bodies, diff --git a/src/pipeline/event_handler.rs b/src/pipeline/event_handler.rs index 9d7b17a..c54acc2 100644 --- a/src/pipeline/event_handler.rs +++ b/src/pipeline/event_handler.rs @@ -1,6 +1,23 @@ -use crate::geometry::{ContactEvent, IntersectionEvent}; +use crate::geometry::{ContactEvent, ContactPair, IntersectionEvent}; use crossbeam::channel::Sender; +bitflags::bitflags! { + #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] + /// Flags affecting the events generated for this collider. + pub struct ActiveEvents: u32 { + /// If set, Rapier will call `EventHandler::handle_intersection_event` whenever relevant for this collider. + const INTERSECTION_EVENTS = 0b0001; + /// If set, Rapier will call `PhysicsHooks::handle_contact_event` whenever relevant for this collider. + const CONTACT_EVENTS = 0b0010; + } +} + +impl Default for ActiveEvents { + fn default() -> Self { + ActiveEvents::empty() + } +} + /// Trait implemented by structures responsible for handling events generated by the physics engine. /// /// Implementors of this trait will typically collect these events for future processing. @@ -13,12 +30,12 @@ pub trait EventHandler: Send + Sync { /// /// A contact event is emitted when two collider start or stop touching, independently from the /// number of contact points involved. - fn handle_contact_event(&self, event: ContactEvent); + fn handle_contact_event(&self, event: ContactEvent, contact_pair: &ContactPair); } impl EventHandler for () { fn handle_intersection_event(&self, _event: IntersectionEvent) {} - fn handle_contact_event(&self, _event: ContactEvent) {} + fn handle_contact_event(&self, _event: ContactEvent, _contact_pair: &ContactPair) {} } /// A physics event handler that collects events into a crossbeam channel. @@ -45,7 +62,7 @@ impl EventHandler for ChannelEventCollector { let _ = self.intersection_event_sender.send(event); } - fn handle_contact_event(&self, event: ContactEvent) { + fn handle_contact_event(&self, event: ContactEvent, _: &ContactPair) { let _ = self.contact_event_sender.send(event); } } diff --git a/src/pipeline/mod.rs b/src/pipeline/mod.rs index ad288d6..2c0393e 100644 --- a/src/pipeline/mod.rs +++ b/src/pipeline/mod.rs @@ -1,10 +1,8 @@ //! Structure for combining the various physics components to perform an actual simulation. pub use collision_pipeline::CollisionPipeline; -pub use event_handler::{ChannelEventCollector, EventHandler}; -pub use physics_hooks::{ - ContactModificationContext, PairFilterContext, PhysicsHooks, PhysicsHooksFlags, -}; +pub use event_handler::{ActiveEvents, ChannelEventCollector, EventHandler}; +pub use physics_hooks::{ActiveHooks, ContactModificationContext, PairFilterContext, PhysicsHooks}; pub use physics_pipeline::PhysicsPipeline; pub use query_pipeline::{QueryPipeline, QueryPipelineMode}; diff --git a/src/pipeline/physics_hooks.rs b/src/pipeline/physics_hooks.rs index c4ef245..68a05d1 100644 --- a/src/pipeline/physics_hooks.rs +++ b/src/pipeline/physics_hooks.rs @@ -118,30 +118,54 @@ impl<'a, Bodies, Colliders> ContactModificationContext<'a, Bodies, Colliders> { 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 PhysicsHooksFlags: u32 { + pub struct ActiveHooks: u32 { /// If set, Rapier will call `PhysicsHooks::filter_contact_pair` whenever relevant. - const FILTER_CONTACT_PAIR = 0b0001; + const FILTER_CONTACT_PAIRS = 0b0001; /// If set, Rapier will call `PhysicsHooks::filter_intersection_pair` whenever relevant. const FILTER_INTERSECTION_PAIR = 0b0010; /// If set, Rapier will call `PhysicsHooks::modify_solver_contact` whenever relevant. const MODIFY_SOLVER_CONTACTS = 0b0100; } } -impl Default for PhysicsHooksFlags { +impl Default for ActiveHooks { fn default() -> Self { - PhysicsHooksFlags::empty() + ActiveHooks::empty() } } +// TODO: right now, the wasm version don't have the Send+Sync bounds. +// This is because these bounds are very difficult to fulfill if we want to +// call JS closures. Also, parallelism cannot be enabled for wasm targets, so +// not having Send+Sync isn't a problem. /// User-defined functions called by the physics engines during one timestep in order to customize its behavior. -pub trait PhysicsHooks<Bodies, Colliders>: Send + Sync { - /// The sets of hooks that must be taken into account. - fn active_hooks(&self) -> PhysicsHooksFlags; +#[cfg(target_arch = "wasm32")] +pub trait PhysicsHooks<Bodies, Colliders> { + /// Applies the contact pair filter. + fn filter_contact_pair( + &self, + _context: &PairFilterContext<Bodies, Colliders>, + ) -> Option<SolverFlags> { + None + } + + /// Applies the intersection pair filter. + fn filter_intersection_pair(&self, _context: &PairFilterContext<Bodies, Colliders>) -> bool { + false + } + + /// Modifies the set of contacts seen by the constraints solver. + fn modify_solver_contacts(&self, _context: &mut ContactModificationContext<Bodies, Colliders>) { + } +} +/// User-defined functions called by the physics engines during one timestep in order to customize its behavior. +#[cfg(not(target_arch = "wasm32"))] +pub trait PhysicsHooks<Bodies, Colliders>: Send + Sync { /// Applies the contact pair filter. /// - /// Note that this method will only be called if `self.active_hooks()` - /// contains the `PhysicsHooksFlags::FILTER_CONTACT_PAIR` flags. + /// Note that this method will only be called if at least one of the colliders + /// involved in the contact contains the `ActiveHooks::FILTER_CONTACT_PAIRS` flags + /// in its physics hooks flags. /// /// User-defined filter for potential contact pairs detected by the broad-phase. /// This can be used to apply custom logic in order to decide whether two colliders @@ -165,13 +189,14 @@ pub trait PhysicsHooks<Bodies, Colliders>: Send + Sync { &self, _context: &PairFilterContext<Bodies, Colliders>, ) -> Option<SolverFlags> { - None + Some(SolverFlags::COMPUTE_IMPULSES) } /// Applies the intersection pair filter. /// - /// Note that this method will only be called if `self.active_hooks()` - /// contains the `PhysicsHooksFlags::FILTER_INTERSECTION_PAIR` flags. + /// Note that this method will only be called if at least one of the colliders + /// involved in the contact contains the `ActiveHooks::FILTER_INTERSECTION_PAIR` flags + /// in its physics hooks flags. /// /// User-defined filter for potential intersection pairs detected by the broad-phase. /// @@ -188,13 +213,14 @@ pub trait PhysicsHooks<Bodies, Colliders>: Send + Sync { /// If this return `true` then the narrow-phase will compute intersection /// information for this pair. fn filter_intersection_pair(&self, _context: &PairFilterContext<Bodies, Colliders>) -> bool { - false + true } /// Modifies the set of contacts seen by the constraints solver. /// - /// Note that this method will only be called if `self.active_hooks()` - /// contains the `PhysicsHooksFlags::MODIFY_SOLVER_CONTACTS` flags. + /// Note that this method will only be called if at least one of the colliders + /// involved in the contact contains the `ActiveHooks::MODIFY_SOLVER_CONTACTS` flags + /// in its physics hooks flags. /// /// By default, the content of `solver_contacts` is computed from `manifold.points`. /// This method will be called on each contact manifold which have the flag `SolverFlags::modify_solver_contacts` set. @@ -220,16 +246,15 @@ pub trait PhysicsHooks<Bodies, Colliders>: Send + Sync { } impl<Bodies, Colliders> PhysicsHooks<Bodies, Colliders> for () { - fn active_hooks(&self) -> PhysicsHooksFlags { - PhysicsHooksFlags::empty() - } - - fn filter_contact_pair(&self, _: &PairFilterContext<Bodies, Colliders>) -> Option<SolverFlags> { - None + fn filter_contact_pair( + &self, + _context: &PairFilterContext<Bodies, Colliders>, + ) -> Option<SolverFlags> { + Some(SolverFlags::default()) } fn filter_intersection_pair(&self, _: &PairFilterContext<Bodies, Colliders>) -> bool { - false + true } fn modify_solver_contacts(&self, _: &mut ContactModificationContext<Bodies, Colliders>) {} diff --git a/src/pipeline/physics_pipeline.rs b/src/pipeline/physics_pipeline.rs index 2f2a95d..a83240e 100644 --- a/src/pipeline/physics_pipeline.rs +++ b/src/pipeline/physics_pipeline.rs @@ -13,7 +13,7 @@ use crate::dynamics::{ #[cfg(feature = "parallel")] use crate::dynamics::{JointGraphEdge, ParallelIslandSolver as IslandSolver}; use crate::geometry::{ - BroadPhase, BroadPhasePairEvent, ColliderBroadPhaseData, ColliderChanges, ColliderGroups, + BroadPhase, BroadPhasePairEvent, ColliderBroadPhaseData, ColliderChanges, ColliderFlags, ColliderHandle, ColliderMaterial, ColliderPair, ColliderParent, ColliderPosition, ColliderShape, ColliderType, ContactManifoldIndex, NarrowPhase, }; @@ -103,8 +103,8 @@ impl PhysicsPipeline { + ComponentSet<ColliderShape> + ComponentSetOption<ColliderParent> + ComponentSet<ColliderType> - + ComponentSet<ColliderGroups> - + ComponentSet<ColliderMaterial>, + + ComponentSet<ColliderMaterial> + + ComponentSet<ColliderFlags>, { self.counters.stages.collision_detection_time.resume(); self.counters.cd.broad_phase_time.resume(); @@ -365,7 +365,8 @@ impl PhysicsPipeline { Colliders: ComponentSetOption<ColliderParent> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape> - + ComponentSet<ColliderType>, + + ComponentSet<ColliderType> + + ComponentSet<ColliderFlags>, { self.counters.ccd.toi_computation_time.start(); // Handle CCD @@ -428,7 +429,10 @@ impl PhysicsPipeline { islands: &IslandManager, bodies: &mut Bodies, ) where - Bodies: ComponentSetMut<RigidBodyVelocity> + ComponentSet<RigidBodyPosition>, + Bodies: ComponentSetMut<RigidBodyVelocity> + + ComponentSetMut<RigidBodyPosition> + + ComponentSet<RigidBodyType> + + ComponentSet<RigidBodyMassProps>, { // Update kinematic bodies velocities. // TODO: what is the best place for this? It should at least be @@ -436,9 +440,31 @@ impl PhysicsPipeline { // there to determine if this kinematic body should wake-up dynamic // bodies it is touching. for handle in islands.active_kinematic_bodies() { - let ppos: &RigidBodyPosition = bodies.index(handle.0); - let new_vel = ppos.interpolate_velocity(integration_parameters.inv_dt()); - bodies.set_internal(handle.0, new_vel); + let (rb_type, rb_pos, rb_vel, rb_mprops): ( + &RigidBodyType, + &RigidBodyPosition, + &RigidBodyVelocity, + &RigidBodyMassProps, + ) = bodies.index_bundle(handle.0); + + match rb_type { + RigidBodyType::KinematicPositionBased => { + let rb_pos: &RigidBodyPosition = bodies.index(handle.0); + let new_vel = rb_pos.interpolate_velocity(integration_parameters.inv_dt()); + bodies.set_internal(handle.0, new_vel); + } + RigidBodyType::KinematicVelocityBased => { + let new_pos = rb_vel.integrate( + integration_parameters.dt, + &rb_pos.position, + // NOTE: we don't use the `world_com` here because it is not + // really updated for kinematic bodies. + &(rb_pos.position * rb_mprops.local_mprops.local_com), + ); + bodies.set_internal(handle.0, RigidBodyPosition::from(new_pos)); + } + _ => {} + } } } @@ -519,8 +545,8 @@ impl PhysicsPipeline { + ComponentSet<ColliderShape> + ComponentSetOption<ColliderParent> + ComponentSet<ColliderType> - + ComponentSet<ColliderGroups> - + ComponentSet<ColliderMaterial>, + + ComponentSet<ColliderMaterial> + + ComponentSet<ColliderFlags>, { self.counters.reset(); self.counters.step_started(); @@ -719,12 +745,12 @@ mod test { let rb = RigidBodyBuilder::new_static().build(); let h1 = bodies.insert(rb.clone()); let co = ColliderBuilder::ball(10.0).build(); - colliders.insert(co.clone(), h1, &mut bodies); + colliders.insert_with_parent(co.clone(), h1, &mut bodies); // The same but with a kinematic body. - let rb = RigidBodyBuilder::new_kinematic().build(); + let rb = RigidBodyBuilder::new_kinematic_position_based().build(); let h2 = bodies.insert(rb.clone()); - colliders.insert(co, h2, &mut bodies); + colliders.insert_with_parent(co, h2, &mut bodies); pipeline.step( &Vector::zeros(), @@ -760,7 +786,7 @@ mod test { let h2 = bodies.insert(rb.clone()); // The same but with a kinematic body. - let rb = RigidBodyBuilder::new_kinematic().build(); + let rb = RigidBodyBuilder::new_kinematic_position_based().build(); let h3 = bodies.insert(rb.clone()); // The same but with a static body. @@ -838,7 +864,7 @@ mod test { let body = RigidBodyBuilder::new_dynamic().build(); let b_handle = bodies.insert(body); let collider = ColliderBuilder::ball(1.0).build(); - let c_handle = colliders.insert(collider, b_handle, &mut bodies); + let c_handle = colliders.insert_with_parent(collider, b_handle, &mut bodies); colliders.remove(c_handle, &mut islands, &mut bodies, true); bodies.remove(b_handle, &mut islands, &mut colliders, &mut joints); diff --git a/src/pipeline/query_pipeline.rs b/src/pipeline/query_pipeline.rs index 31bf3a4..733d767 100644 --- a/src/pipeline/query_pipeline.rs +++ b/src/pipeline/query_pipeline.rs @@ -4,7 +4,7 @@ use crate::dynamics::{ RigidBodyVelocity, }; use crate::geometry::{ - ColliderGroups, ColliderHandle, ColliderParent, ColliderPosition, ColliderShape, + ColliderFlags, ColliderHandle, ColliderParent, ColliderPosition, ColliderShape, InteractionGroups, PointProjection, Ray, RayIntersection, AABB, QBVH, }; use crate::math::{Isometry, Point, Real, Vector}; @@ -67,7 +67,7 @@ impl<'a, Colliders> TypedSimdCompositeShape for QueryPipelineAsCompositeShape<'a where // TODO ECS: make everything optional but the shape? Colliders: - ComponentSet<ColliderGroups> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, + ComponentSet<ColliderFlags> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, { type PartShape = dyn Shape; type PartId = ColliderHandle; @@ -77,10 +77,10 @@ where shape_id: Self::PartId, mut f: impl FnMut(Option<&Isometry<Real>>, &Self::PartShape), ) { - let co_groups: Option<&ColliderGroups> = self.colliders.get(shape_id.0); + let co_flags: Option<&ColliderFlags> = self.colliders.get(shape_id.0); - if let Some(co_groups) = co_groups { - if co_groups.collision_groups.test(self.query_groups) + if let Some(co_flags) = co_flags { + if co_flags.collision_groups.test(self.query_groups) && self.filter.map(|f| f(shape_id)).unwrap_or(true) { let (co_pos, co_shape): (&ColliderPosition, &ColliderShape) = @@ -384,7 +384,7 @@ impl QueryPipeline { filter: Option<&dyn Fn(ColliderHandle) -> bool>, ) -> Option<(ColliderHandle, Real)> where - Colliders: ComponentSet<ColliderGroups> + Colliders: ComponentSet<ColliderFlags> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, { @@ -420,7 +420,7 @@ impl QueryPipeline { filter: Option<&dyn Fn(ColliderHandle) -> bool>, ) -> Option<(ColliderHandle, RayIntersection)> where - Colliders: ComponentSet<ColliderGroups> + Colliders: ComponentSet<ColliderFlags> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, { @@ -463,16 +463,16 @@ impl QueryPipeline { filter: Option<&dyn Fn(ColliderHandle) -> bool>, mut callback: impl FnMut(ColliderHandle, RayIntersection) -> bool, ) where - Colliders: ComponentSet<ColliderGroups> + Colliders: ComponentSet<ColliderFlags> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, { let mut leaf_callback = &mut |handle: &ColliderHandle| { let co_shape: Option<&ColliderShape> = colliders.get(handle.0); if let Some(co_shape) = co_shape { - let (co_groups, co_pos): (&ColliderGroups, &ColliderPosition) = + let (co_flags, co_pos): (&ColliderFlags, &ColliderPosition) = colliders.index_bundle(handle.0); - if co_groups.collision_groups.test(query_groups) + if co_flags.collision_groups.test(query_groups) && filter.map(|f| f(*handle)).unwrap_or(true) { if let Some(hit) = co_shape.cast_ray_and_get_normal(co_pos, ray, max_toi, solid) @@ -509,7 +509,7 @@ impl QueryPipeline { filter: Option<&dyn Fn(ColliderHandle) -> bool>, ) -> Option<ColliderHandle> where - Colliders: ComponentSet<ColliderGroups> + Colliders: ComponentSet<ColliderFlags> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, { @@ -550,7 +550,7 @@ impl QueryPipeline { filter: Option<&dyn Fn(ColliderHandle) -> bool>, ) -> Option<(ColliderHandle, PointProjection)> where - Colliders: ComponentSet<ColliderGroups> + Colliders: ComponentSet<ColliderFlags> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, { @@ -583,7 +583,7 @@ impl QueryPipeline { filter: Option<&dyn Fn(ColliderHandle) -> bool>, mut callback: impl FnMut(ColliderHandle) -> bool, ) where - Colliders: ComponentSet<ColliderGroups> + Colliders: ComponentSet<ColliderFlags> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, { @@ -591,10 +591,10 @@ impl QueryPipeline { let co_shape: Option<&ColliderShape> = colliders.get(handle.0); if let Some(co_shape) = co_shape { - let (co_groups, co_pos): (&ColliderGroups, &ColliderPosition) = + let (co_flags, co_pos): (&ColliderFlags, &ColliderPosition) = colliders.index_bundle(handle.0); - if co_groups.collision_groups.test(query_groups) + if co_flags.collision_groups.test(query_groups) && filter.map(|f| f(*handle)).unwrap_or(true) && co_shape.contains_point(co_pos, point) { @@ -635,7 +635,7 @@ impl QueryPipeline { filter: Option<&dyn Fn(ColliderHandle) -> bool>, ) -> Option<(ColliderHandle, PointProjection, FeatureId)> where - Colliders: ComponentSet<ColliderGroups> + Colliders: ComponentSet<ColliderFlags> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, { @@ -685,7 +685,7 @@ impl QueryPipeline { filter: Option<&dyn Fn(ColliderHandle) -> bool>, ) -> Option<(ColliderHandle, TOI)> where - Colliders: ComponentSet<ColliderGroups> + Colliders: ComponentSet<ColliderFlags> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, { @@ -733,7 +733,7 @@ impl QueryPipeline { filter: Option<&dyn Fn(ColliderHandle) -> bool>, ) -> Option<(ColliderHandle, TOI)> where - Colliders: ComponentSet<ColliderGroups> + Colliders: ComponentSet<ColliderFlags> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, { @@ -774,7 +774,7 @@ impl QueryPipeline { filter: Option<&dyn Fn(ColliderHandle) -> bool>, mut callback: impl FnMut(ColliderHandle) -> bool, ) where - Colliders: ComponentSet<ColliderGroups> + Colliders: ComponentSet<ColliderFlags> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, { @@ -785,10 +785,10 @@ impl QueryPipeline { let co_shape: Option<&ColliderShape> = colliders.get(handle.0); if let Some(co_shape) = co_shape { - let (co_groups, co_pos): (&ColliderGroups, &ColliderPosition) = + let (co_flags, co_pos): (&ColliderFlags, &ColliderPosition) = colliders.index_bundle(handle.0); - if co_groups.collision_groups.test(query_groups) + if co_flags.collision_groups.test(query_groups) && filter.map(|f| f(*handle)).unwrap_or(true) { let pos12 = inv_shape_pos * co_pos.as_ref(); diff --git a/src/pipeline/user_changes.rs b/src/pipeline/user_changes.rs index 99c5cfe..699361c 100644 --- a/src/pipeline/user_changes.rs +++ b/src/pipeline/user_changes.rs @@ -100,7 +100,8 @@ pub(crate) fn handle_user_changes_to_rigid_bodies<Bodies, Colliders>( // the active_dynamic_set. changes.set(RigidBodyChanges::SLEEP, true); } - RigidBodyType::Kinematic => { + 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); |
