diff options
| author | Thierry Berger <contact@thierryberger.com> | 2024-06-03 15:20:24 +0200 |
|---|---|---|
| committer | Thierry Berger <contact@thierryberger.com> | 2024-06-03 15:20:24 +0200 |
| commit | e1ed90603e618e28f48916690d761e0d8213e2ad (patch) | |
| tree | 8399da9825ca9ee8edd601b1265e818fa303b541 /src/pipeline | |
| parent | fe336b9b98d5825544ad3a153a84cb59dc9171c6 (diff) | |
| parent | 856675032e76b6eb4bc9e0be4dc87abdbcfe0421 (diff) | |
| download | rapier-e1ed90603e618e28f48916690d761e0d8213e2ad.tar.gz rapier-e1ed90603e618e28f48916690d761e0d8213e2ad.tar.bz2 rapier-e1ed90603e618e28f48916690d761e0d8213e2ad.zip | |
Merge branch 'master' into collider-builder-debug
Diffstat (limited to 'src/pipeline')
| -rw-r--r-- | src/pipeline/collision_pipeline.rs | 15 | ||||
| -rw-r--r-- | src/pipeline/debug_render_pipeline/debug_render_pipeline.rs | 12 | ||||
| -rw-r--r-- | src/pipeline/physics_pipeline.rs | 113 | ||||
| -rw-r--r-- | src/pipeline/query_pipeline.rs | 33 | ||||
| -rw-r--r-- | src/pipeline/user_changes.rs | 6 |
5 files changed, 136 insertions, 43 deletions
diff --git a/src/pipeline/collision_pipeline.rs b/src/pipeline/collision_pipeline.rs index 03396ed..9004946 100644 --- a/src/pipeline/collision_pipeline.rs +++ b/src/pipeline/collision_pipeline.rs @@ -43,7 +43,7 @@ impl CollisionPipeline { fn detect_collisions( &mut self, prediction_distance: Real, - broad_phase: &mut BroadPhase, + broad_phase: &mut dyn BroadPhase, narrow_phase: &mut NarrowPhase, bodies: &mut RigidBodySet, colliders: &mut ColliderSet, @@ -58,8 +58,10 @@ impl CollisionPipeline { self.broadphase_collider_pairs.clear(); broad_phase.update( + 0.0, prediction_distance, colliders, + bodies, modified_colliders, removed_colliders, &mut self.broad_phase_events, @@ -80,6 +82,7 @@ impl CollisionPipeline { narrow_phase.register_pairs(None, colliders, bodies, &self.broad_phase_events, events); narrow_phase.compute_contacts( prediction_distance, + 0.0, bodies, colliders, &ImpulseJointSet::new(), @@ -107,7 +110,7 @@ impl CollisionPipeline { pub fn step( &mut self, prediction_distance: Real, - broad_phase: &mut BroadPhase, + broad_phase: &mut dyn BroadPhase, narrow_phase: &mut NarrowPhase, bodies: &mut RigidBodySet, colliders: &mut ColliderSet, @@ -192,13 +195,13 @@ mod tests { let _ = collider_set.insert(collider_b); let integration_parameters = IntegrationParameters::default(); - let mut broad_phase = BroadPhase::new(); + let mut broad_phase = BroadPhaseMultiSap::new(); let mut narrow_phase = NarrowPhase::new(); let mut collision_pipeline = CollisionPipeline::new(); let physics_hooks = (); collision_pipeline.step( - integration_parameters.prediction_distance, + integration_parameters.prediction_distance(), &mut broad_phase, &mut narrow_phase, &mut rigid_body_set, @@ -244,13 +247,13 @@ mod tests { let _ = collider_set.insert(collider_b); let integration_parameters = IntegrationParameters::default(); - let mut broad_phase = BroadPhase::new(); + let mut broad_phase = BroadPhaseMultiSap::new(); let mut narrow_phase = NarrowPhase::new(); let mut collision_pipeline = CollisionPipeline::new(); let physics_hooks = (); collision_pipeline.step( - integration_parameters.prediction_distance, + integration_parameters.prediction_distance(), &mut broad_phase, &mut narrow_phase, &mut rigid_body_set, diff --git a/src/pipeline/debug_render_pipeline/debug_render_pipeline.rs b/src/pipeline/debug_render_pipeline/debug_render_pipeline.rs index b429c90..041862c 100644 --- a/src/pipeline/debug_render_pipeline/debug_render_pipeline.rs +++ b/src/pipeline/debug_render_pipeline/debug_render_pipeline.rs @@ -9,6 +9,7 @@ use crate::math::{Isometry, Point, Real, Vector, DIM}; use crate::pipeline::debug_render_pipeline::debug_render_backend::DebugRenderObject; use crate::pipeline::debug_render_pipeline::DebugRenderStyle; use crate::utils::SimdBasis; +use parry::utils::IsometryOpt; use std::any::TypeId; use std::collections::HashMap; @@ -115,16 +116,19 @@ impl DebugRenderPipeline { if backend.filter_object(object) { for manifold in &pair.manifolds { for contact in manifold.contacts() { + let world_subshape_pos1 = + manifold.subshape_pos1.prepend_to(co1.position()); backend.draw_line( object, - co1.position() * contact.local_p1, - co2.position() * contact.local_p2, + world_subshape_pos1 * contact.local_p1, + manifold.subshape_pos2.prepend_to(co2.position()) + * contact.local_p2, self.style.contact_depth_color, ); backend.draw_line( object, - co1.position() * contact.local_p1, - co1.position() + world_subshape_pos1 * contact.local_p1, + world_subshape_pos1 * (contact.local_p1 + manifold.local_n1 * self.style.contact_normal_length), self.style.contact_normal_color, diff --git a/src/pipeline/physics_pipeline.rs b/src/pipeline/physics_pipeline.rs index 6dbc4e5..95e408f 100644 --- a/src/pipeline/physics_pipeline.rs +++ b/src/pipeline/physics_pipeline.rs @@ -93,7 +93,7 @@ impl PhysicsPipeline { &mut self, integration_parameters: &IntegrationParameters, islands: &mut IslandManager, - broad_phase: &mut BroadPhase, + broad_phase: &mut dyn BroadPhase, narrow_phase: &mut NarrowPhase, bodies: &mut RigidBodySet, colliders: &mut ColliderSet, @@ -112,8 +112,10 @@ impl PhysicsPipeline { self.broad_phase_events.clear(); self.broadphase_collider_pairs.clear(); broad_phase.update( - integration_parameters.prediction_distance, + integration_parameters.dt, + integration_parameters.prediction_distance(), colliders, + bodies, modified_colliders, removed_colliders, &mut self.broad_phase_events, @@ -141,7 +143,8 @@ impl PhysicsPipeline { events, ); narrow_phase.compute_contacts( - integration_parameters.prediction_distance, + integration_parameters.prediction_distance(), + integration_parameters.dt, bodies, colliders, impulse_joints, @@ -171,6 +174,7 @@ impl PhysicsPipeline { self.counters.stages.island_construction_time.resume(); islands.update_active_set_with_contacts( integration_parameters.dt, + integration_parameters.length_unit, bodies, colliders, narrow_phase, @@ -178,7 +182,6 @@ impl PhysicsPipeline { multibody_joints, integration_parameters.min_island_size, ); - self.counters.stages.island_construction_time.pause(); if self.manifold_indices.len() < islands.num_islands() { self.manifold_indices @@ -203,6 +206,7 @@ impl PhysicsPipeline { bodies, &mut self.joint_constraint_indices, ); + self.counters.stages.island_construction_time.pause(); self.counters.stages.update_time.resume(); for handle in islands.active_dynamic_bodies() { @@ -406,7 +410,7 @@ impl PhysicsPipeline { gravity: &Vector<Real>, integration_parameters: &IntegrationParameters, islands: &mut IslandManager, - broad_phase: &mut BroadPhase, + broad_phase: &mut dyn BroadPhase, narrow_phase: &mut NarrowPhase, bodies: &mut RigidBodySet, colliders: &mut ColliderSet, @@ -421,6 +425,7 @@ impl PhysicsPipeline { self.counters.step_started(); // Apply some of delayed wake-ups. + self.counters.stages.user_changes.start(); for handle in impulse_joints .to_wake_up .drain(..) @@ -459,14 +464,15 @@ impl PhysicsPipeline { .copied() .filter(|h| colliders.get(*h).map(|c| !c.is_enabled()).unwrap_or(false)), ); + self.counters.stages.user_changes.pause(); // TODO: do this only on user-change. // TODO: do we want some kind of automatic inverse kinematics? for multibody in &mut multibody_joints.multibodies { - multibody.1.update_root_type(bodies); - // FIXME: what should we do here? We should not - // rely on the next state here. multibody.1.forward_kinematics(bodies, true); + multibody + .1 + .update_rigid_bodies_internal(bodies, true, false, false); } self.detect_collisions( @@ -486,12 +492,16 @@ impl PhysicsPipeline { ); if let Some(queries) = query_pipeline.as_deref_mut() { + self.counters.stages.query_pipeline_time.start(); queries.update_incremental(colliders, &modified_colliders, &removed_colliders, false); + self.counters.stages.query_pipeline_time.pause(); } + self.counters.stages.user_changes.resume(); self.clear_modified_colliders(colliders, &mut modified_colliders); self.clear_modified_bodies(bodies, &mut modified_bodies); removed_colliders.clear(); + self.counters.stages.user_changes.pause(); let mut remaining_time = integration_parameters.dt; let mut integration_parameters = *integration_parameters; @@ -508,7 +518,7 @@ impl PhysicsPipeline { // the timestep into multiple intervals. First, estimate the // size of the time slice we will integrate for this substep. // - // Note that we must do this now, before the constrains resolution + // Note that we must do this now, before the constraints resolution // because we need to use the correct timestep length for the // integration of external forces. // @@ -599,7 +609,9 @@ impl PhysicsPipeline { } } + self.counters.stages.update_time.resume(); self.advance_to_final_positions(islands, bodies, colliders, &mut modified_colliders); + self.counters.stages.update_time.pause(); self.detect_collisions( &integration_parameters, @@ -618,12 +630,14 @@ impl PhysicsPipeline { ); if let Some(queries) = query_pipeline.as_deref_mut() { + self.counters.stages.query_pipeline_time.resume(); queries.update_incremental( colliders, &modified_colliders, &[], remaining_substeps == 0, ); + self.counters.stages.query_pipeline_time.pause(); } self.clear_modified_colliders(colliders, &mut modified_colliders); @@ -635,10 +649,12 @@ impl PhysicsPipeline { // TODO: avoid updating the world mass properties twice (here, and // at the beginning of the next timestep) for bodies that were // not modified by the user in the mean time. + self.counters.stages.update_time.resume(); for handle in islands.active_dynamic_bodies() { let rb = bodies.index_mut_internal(*handle); rb.mprops.update_world_mass_properties(&rb.pos.position); } + self.counters.stages.update_time.pause(); self.counters.step_completed(); } @@ -650,10 +666,10 @@ mod test { CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, RigidBodyBuilder, RigidBodySet, }; - use crate::geometry::{BroadPhase, ColliderBuilder, ColliderSet, NarrowPhase}; + use crate::geometry::{BroadPhaseMultiSap, ColliderBuilder, ColliderSet, NarrowPhase}; use crate::math::Vector; use crate::pipeline::PhysicsPipeline; - use crate::prelude::MultibodyJointSet; + use crate::prelude::{MultibodyJointSet, RigidBodyType}; #[test] fn kinematic_and_fixed_contact_crash() { @@ -661,7 +677,7 @@ mod test { let mut impulse_joints = ImpulseJointSet::new(); let mut multibody_joints = MultibodyJointSet::new(); let mut pipeline = PhysicsPipeline::new(); - let mut bf = BroadPhase::new(); + let mut bf = BroadPhaseMultiSap::new(); let mut nf = NarrowPhase::new(); let mut bodies = RigidBodySet::new(); let mut islands = IslandManager::new(); @@ -699,7 +715,7 @@ mod test { let mut impulse_joints = ImpulseJointSet::new(); let mut multibody_joints = MultibodyJointSet::new(); let mut pipeline = PhysicsPipeline::new(); - let mut bf = BroadPhase::new(); + let mut bf = BroadPhaseMultiSap::new(); let mut nf = NarrowPhase::new(); let mut islands = IslandManager::new(); @@ -809,7 +825,7 @@ mod test { let mut pipeline = PhysicsPipeline::new(); let gravity = Vector::y() * -9.81; let integration_parameters = IntegrationParameters::default(); - let mut broad_phase = BroadPhase::new(); + let mut broad_phase = BroadPhaseMultiSap::new(); let mut narrow_phase = NarrowPhase::new(); let mut bodies = RigidBodySet::new(); let mut colliders = ColliderSet::new(); @@ -852,4 +868,73 @@ mod test { ); } } + + #[test] + fn rigid_body_type_changed_dynamic_is_in_active_set() { + let mut colliders = ColliderSet::new(); + let mut impulse_joints = ImpulseJointSet::new(); + let mut multibody_joints = MultibodyJointSet::new(); + let mut pipeline = PhysicsPipeline::new(); + let mut bf = BroadPhaseMultiSap::new(); + let mut nf = NarrowPhase::new(); + let mut islands = IslandManager::new(); + + let mut bodies = RigidBodySet::new(); + + // Initialize body as kinematic with mass + let rb = RigidBodyBuilder::kinematic_position_based() + .additional_mass(1.0) + .build(); + let h = bodies.insert(rb.clone()); + + // Step once + let gravity = Vector::y() * -9.81; + pipeline.step( + &gravity, + &IntegrationParameters::default(), + &mut islands, + &mut bf, + &mut nf, + &mut bodies, + &mut colliders, + &mut impulse_joints, + &mut multibody_joints, + &mut CCDSolver::new(), + None, + &(), + &(), + ); + + // Switch body type to Dynamic + bodies + .get_mut(h) + .unwrap() + .set_body_type(RigidBodyType::Dynamic, true); + + // Step again + pipeline.step( + &gravity, + &IntegrationParameters::default(), + &mut islands, + &mut bf, + &mut nf, + &mut bodies, + &mut colliders, + &mut impulse_joints, + &mut multibody_joints, + &mut CCDSolver::new(), + None, + &(), + &(), + ); + + let body = bodies.get(h).unwrap(); + let h_y = body.pos.position.translation.y; + + // Expect gravity to be applied on second step after switching to Dynamic + assert!(h_y < 0.0); + + // Expect body to now be in active_dynamic_set + assert!(islands.active_dynamic_set.contains(&h)); + } } diff --git a/src/pipeline/query_pipeline.rs b/src/pipeline/query_pipeline.rs index 4dc5652..f202107 100644 --- a/src/pipeline/query_pipeline.rs +++ b/src/pipeline/query_pipeline.rs @@ -6,17 +6,16 @@ use crate::math::{Isometry, Point, Real, Vector}; use crate::{dynamics::RigidBodySet, geometry::ColliderSet}; use parry::partitioning::{QbvhDataGenerator, QbvhUpdateWorkspace}; use parry::query::details::{ - NonlinearTOICompositeShapeShapeBestFirstVisitor, PointCompositeShapeProjBestFirstVisitor, - PointCompositeShapeProjWithFeatureBestFirstVisitor, + NonlinearTOICompositeShapeShapeBestFirstVisitor, NormalConstraints, + PointCompositeShapeProjBestFirstVisitor, PointCompositeShapeProjWithFeatureBestFirstVisitor, RayCompositeShapeToiAndNormalBestFirstVisitor, RayCompositeShapeToiBestFirstVisitor, - TOICompositeShapeShapeBestFirstVisitor, + ShapeCastOptions, TOICompositeShapeShapeBestFirstVisitor, }; use parry::query::visitors::{ BoundingVolumeIntersectionsVisitor, PointIntersectionsVisitor, RayIntersectionsVisitor, }; -use parry::query::{DefaultQueryDispatcher, NonlinearRigidMotion, QueryDispatcher, TOI}; +use parry::query::{DefaultQueryDispatcher, NonlinearRigidMotion, QueryDispatcher, ShapeCastHit}; use parry::shape::{FeatureId, Shape, TypedSimdCompositeShape}; -use parry::utils::DefaultStorage; use std::sync::Arc; /// A pipeline for performing queries on all the colliders of a scene. @@ -101,7 +100,7 @@ impl QueryFilterFlags { } } -/// A filter tha describes what collider should be included or excluded from a scene query. +/// A filter that describes what collider should be included or excluded from a scene query. #[derive(Copy, Clone, Default)] pub struct QueryFilter<'a> { /// Flags indicating what particular type of colliders should be excluded from the scene query. @@ -246,17 +245,21 @@ pub enum QueryPipelineMode { impl<'a> TypedSimdCompositeShape for QueryPipelineAsCompositeShape<'a> { type PartShape = dyn Shape; + type PartNormalConstraints = dyn NormalConstraints; type PartId = ColliderHandle; - type QbvhStorage = DefaultStorage; fn map_typed_part_at( &self, shape_id: Self::PartId, - mut f: impl FnMut(Option<&Isometry<Real>>, &Self::PartShape), + mut f: impl FnMut( + Option<&Isometry<Real>>, + &Self::PartShape, + Option<&Self::PartNormalConstraints>, + ), ) { if let Some(co) = self.colliders.get(shape_id) { if self.filter.test(self.bodies, shape_id, co) { - f(Some(&co.pos), &*co.shape) + f(Some(&co.pos), &*co.shape, None) } } } @@ -264,7 +267,7 @@ impl<'a> TypedSimdCompositeShape for QueryPipelineAsCompositeShape<'a> { fn map_untyped_part_at( &self, shape_id: Self::PartId, - f: impl FnMut(Option<&Isometry<Real>>, &Self::PartShape), + f: impl FnMut(Option<&Isometry<Real>>, &Self::PartShape, Option<&dyn NormalConstraints>), ) { self.map_typed_part_at(shape_id, f); } @@ -676,10 +679,9 @@ impl QueryPipeline { shape_pos: &Isometry<Real>, shape_vel: &Vector<Real>, shape: &dyn Shape, - max_toi: Real, - stop_at_penetration: bool, + options: ShapeCastOptions, filter: QueryFilter, - ) -> Option<(ColliderHandle, TOI)> { + ) -> Option<(ColliderHandle, ShapeCastHit)> { let pipeline_shape = self.as_composite_shape(bodies, colliders, filter); let mut visitor = TOICompositeShapeShapeBestFirstVisitor::new( &*self.query_dispatcher, @@ -687,8 +689,7 @@ impl QueryPipeline { shape_vel, &pipeline_shape, shape, - max_toi, - stop_at_penetration, + options, ); self.qbvh.traverse_best_first(&mut visitor).map(|h| h.1) } @@ -722,7 +723,7 @@ impl QueryPipeline { end_time: Real, stop_at_penetration: bool, filter: QueryFilter, - ) -> Option<(ColliderHandle, TOI)> { + ) -> Option<(ColliderHandle, ShapeCastHit)> { let pipeline_shape = self.as_composite_shape(bodies, colliders, filter); let pipeline_motion = NonlinearRigidMotion::identity(); let mut visitor = NonlinearTOICompositeShapeShapeBestFirstVisitor::new( diff --git a/src/pipeline/user_changes.rs b/src/pipeline/user_changes.rs index 7c3f1ac..a2b00a1 100644 --- a/src/pipeline/user_changes.rs +++ b/src/pipeline/user_changes.rs @@ -120,9 +120,9 @@ pub(crate) fn handle_user_changes_to_rigid_bodies( islands.active_kinematic_set.push(*handle); } - // Push the body to the active set if it is not - // sleeping and if it is not already inside of the active set. - if changes.contains(RigidBodyChanges::SLEEP) + // Push the body to the active set if it is not inside the active set yet, and + // is either not longer sleeping or became dynamic. + if (changes.contains(RigidBodyChanges::SLEEP) || changes.contains(RigidBodyChanges::TYPE)) && rb.is_enabled() && !rb.activation.sleeping // May happen if the body was put to sleep manually. && rb.is_dynamic() // Only dynamic bodies are in the active dynamic set. |
