aboutsummaryrefslogtreecommitdiff
path: root/src/pipeline
diff options
context:
space:
mode:
authorThierry Berger <contact@thierryberger.com>2024-06-03 15:20:24 +0200
committerThierry Berger <contact@thierryberger.com>2024-06-03 15:20:24 +0200
commite1ed90603e618e28f48916690d761e0d8213e2ad (patch)
tree8399da9825ca9ee8edd601b1265e818fa303b541 /src/pipeline
parentfe336b9b98d5825544ad3a153a84cb59dc9171c6 (diff)
parent856675032e76b6eb4bc9e0be4dc87abdbcfe0421 (diff)
downloadrapier-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.rs15
-rw-r--r--src/pipeline/debug_render_pipeline/debug_render_pipeline.rs12
-rw-r--r--src/pipeline/physics_pipeline.rs113
-rw-r--r--src/pipeline/query_pipeline.rs33
-rw-r--r--src/pipeline/user_changes.rs6
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.