1use crate::counters::Counters;
4use crate::dynamics::IslandSolver;
6#[cfg(feature = "parallel")]
7use crate::dynamics::JointGraphEdge;
8use crate::dynamics::{
9 CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet,
10 RigidBodyChanges, RigidBodyType,
11};
12use crate::geometry::{
13 BroadPhaseBvh, BroadPhasePairEvent, ColliderChanges, ColliderHandle, ColliderPair,
14 ContactManifoldIndex, ModifiedColliders, NarrowPhase, TemporaryInteractionIndex,
15};
16use crate::math::{Real, Vector};
17use crate::pipeline::{EventHandler, PhysicsHooks};
18use crate::prelude::ModifiedRigidBodies;
19use {crate::dynamics::RigidBodySet, crate::geometry::ColliderSet};
20
21pub struct PhysicsPipeline {
41 pub counters: Counters,
43 contact_pair_indices: Vec<TemporaryInteractionIndex>,
44 manifold_indices: Vec<Vec<ContactManifoldIndex>>,
45 joint_constraint_indices: Vec<Vec<ContactManifoldIndex>>,
46 broadphase_collider_pairs: Vec<ColliderPair>,
47 broad_phase_events: Vec<BroadPhasePairEvent>,
48 solvers: Vec<IslandSolver>,
49}
50
51impl Default for PhysicsPipeline {
52 fn default() -> Self {
53 PhysicsPipeline::new()
54 }
55}
56
57#[allow(dead_code)]
58fn check_pipeline_send_sync() {
59 fn do_test<T: Sync>() {}
60 do_test::<PhysicsPipeline>();
61}
62
63impl PhysicsPipeline {
64 pub fn new() -> PhysicsPipeline {
69 PhysicsPipeline {
70 counters: Counters::new(true),
71 solvers: vec![],
72 contact_pair_indices: vec![],
73 manifold_indices: vec![],
74 joint_constraint_indices: vec![],
75 broadphase_collider_pairs: vec![],
76 broad_phase_events: vec![],
77 }
78 }
79
80 fn clear_modified_colliders(
81 &mut self,
82 colliders: &mut ColliderSet,
83 modified_colliders: &mut ModifiedColliders,
84 ) {
85 for co in colliders.colliders.iter_mut() {
92 co.1.changes = ColliderChanges::empty();
93 }
94 modified_colliders.clear();
101 }
102
103 fn clear_modified_bodies(
104 &mut self,
105 bodies: &mut RigidBodySet,
106 modified_bodies: &mut ModifiedRigidBodies,
107 ) {
108 for handle in modified_bodies.iter() {
109 if let Some(rb) = bodies.get_mut_internal(*handle) {
110 rb.changes = RigidBodyChanges::empty();
111 }
112 }
113
114 modified_bodies.clear();
115 }
116
117 fn detect_collisions(
118 &mut self,
119 integration_parameters: &IntegrationParameters,
120 islands: &mut IslandManager,
121 broad_phase: &mut BroadPhaseBvh,
122 narrow_phase: &mut NarrowPhase,
123 bodies: &mut RigidBodySet,
124 colliders: &mut ColliderSet,
125 impulse_joints: &ImpulseJointSet,
126 multibody_joints: &MultibodyJointSet,
127 modified_colliders: &[ColliderHandle],
128 removed_colliders: &[ColliderHandle],
129 hooks: &dyn PhysicsHooks,
130 events: &dyn EventHandler,
131 handle_user_changes: bool,
132 ) {
133 self.counters.stages.collision_detection_time.resume();
134 self.counters.cd.broad_phase_time.resume();
135
136 self.broad_phase_events.clear();
138 self.broadphase_collider_pairs.clear();
139 broad_phase.update(
140 integration_parameters,
141 colliders,
142 bodies,
143 modified_colliders,
144 removed_colliders,
145 &mut self.broad_phase_events,
146 );
147
148 self.counters.cd.broad_phase_time.pause();
149 self.counters.cd.narrow_phase_time.resume();
150
151 if handle_user_changes {
153 narrow_phase.handle_user_changes(
154 Some(islands),
155 modified_colliders,
156 removed_colliders,
157 colliders,
158 bodies,
159 events,
160 );
161 }
162 narrow_phase.register_pairs(
163 Some(islands),
164 colliders,
165 bodies,
166 &self.broad_phase_events,
167 events,
168 );
169 narrow_phase.compute_contacts(
170 integration_parameters.prediction_distance(),
171 integration_parameters.dt,
172 bodies,
173 colliders,
174 impulse_joints,
175 multibody_joints,
176 hooks,
177 events,
178 );
179 narrow_phase.compute_intersections(bodies, colliders, hooks, events);
180
181 self.counters.cd.narrow_phase_time.pause();
182 self.counters.stages.collision_detection_time.pause();
183 }
184
185 fn build_islands_and_solve_velocity_constraints(
186 &mut self,
187 gravity: &Vector<Real>,
188 integration_parameters: &IntegrationParameters,
189 islands: &mut IslandManager,
190 narrow_phase: &mut NarrowPhase,
191 bodies: &mut RigidBodySet,
192 colliders: &mut ColliderSet,
193 impulse_joints: &mut ImpulseJointSet,
194 multibody_joints: &mut MultibodyJointSet,
195 events: &dyn EventHandler,
196 ) {
197 self.counters.stages.island_construction_time.resume();
198 islands.update_active_set_with_contacts(
199 integration_parameters.dt,
200 integration_parameters.length_unit,
201 bodies,
202 colliders,
203 narrow_phase,
204 impulse_joints,
205 multibody_joints,
206 integration_parameters.min_island_size,
207 );
208
209 if self.manifold_indices.len() < islands.num_islands() {
210 self.manifold_indices
211 .resize(islands.num_islands(), Vec::new());
212 }
213
214 if self.joint_constraint_indices.len() < islands.num_islands() {
215 self.joint_constraint_indices
216 .resize(islands.num_islands(), Vec::new());
217 }
218
219 let mut manifolds = Vec::new();
220 narrow_phase.select_active_contacts(
221 islands,
222 bodies,
223 &mut self.contact_pair_indices,
224 &mut manifolds,
225 &mut self.manifold_indices,
226 );
227 impulse_joints.select_active_interactions(
228 islands,
229 bodies,
230 &mut self.joint_constraint_indices,
231 );
232 self.counters.stages.island_construction_time.pause();
233
234 self.counters.stages.update_time.resume();
235 for handle in islands.active_bodies() {
236 let rb = bodies.index_mut_internal(*handle);
239 rb.mprops
240 .update_world_mass_properties(rb.body_type, &rb.pos.position);
241 let effective_mass = rb.mprops.effective_mass();
242 rb.forces
243 .compute_effective_force_and_torque(gravity, &effective_mass);
244 }
245 self.counters.stages.update_time.pause();
246
247 self.counters.stages.solver_time.resume();
248 if self.solvers.len() < islands.num_islands() {
249 self.solvers
250 .resize_with(islands.num_islands(), IslandSolver::new);
251 }
252
253 #[cfg(not(feature = "parallel"))]
254 {
255 enable_flush_to_zero!();
256
257 for island_id in 0..islands.num_islands() {
258 self.solvers[island_id].init_and_solve(
259 island_id,
260 &mut self.counters,
261 integration_parameters,
262 islands,
263 bodies,
264 &mut manifolds[..],
265 &self.manifold_indices[island_id],
266 impulse_joints.joints_mut(),
267 &self.joint_constraint_indices[island_id],
268 multibody_joints,
269 )
270 }
271 }
272
273 #[cfg(feature = "parallel")]
274 {
275 use crate::geometry::ContactManifold;
276 use rayon::prelude::*;
277 use std::sync::atomic::Ordering;
278
279 let num_islands = islands.num_islands();
280 let solvers = &mut self.solvers[..num_islands];
281 let bodies = &std::sync::atomic::AtomicPtr::new(bodies as *mut _);
282 let manifolds = &std::sync::atomic::AtomicPtr::new(&mut manifolds as *mut _);
283 let impulse_joints =
284 &std::sync::atomic::AtomicPtr::new(impulse_joints.joints_vec_mut() as *mut _);
285 let multibody_joints = &std::sync::atomic::AtomicPtr::new(multibody_joints as *mut _);
286 let manifold_indices = &self.manifold_indices[..];
287 let joint_constraint_indices = &self.joint_constraint_indices[..];
288
289 self.counters.solver.velocity_resolution_time.resume();
293 rayon::scope(|_scope| {
294 enable_flush_to_zero!();
295
296 solvers
297 .par_iter_mut()
298 .enumerate()
299 .for_each(|(island_id, solver)| {
300 let bodies: &mut RigidBodySet =
301 unsafe { &mut *bodies.load(Ordering::Relaxed) };
302 let manifolds: &mut Vec<&mut ContactManifold> =
303 unsafe { &mut *manifolds.load(Ordering::Relaxed) };
304 let impulse_joints: &mut Vec<JointGraphEdge> =
305 unsafe { &mut *impulse_joints.load(Ordering::Relaxed) };
306 let multibody_joints: &mut MultibodyJointSet =
307 unsafe { &mut *multibody_joints.load(Ordering::Relaxed) };
308
309 let mut counters = Counters::new(false);
310 solver.init_and_solve(
311 island_id,
312 &mut counters,
313 integration_parameters,
314 islands,
315 bodies,
316 &mut manifolds[..],
317 &manifold_indices[island_id],
318 impulse_joints,
319 &joint_constraint_indices[island_id],
320 multibody_joints,
321 )
322 });
323 });
324 self.counters.solver.velocity_resolution_time.pause();
325 }
326
327 let inv_dt = crate::utils::inv(integration_parameters.dt);
329 for pair_id in self.contact_pair_indices.drain(..) {
330 let pair = narrow_phase.contact_pair_at_index(pair_id);
331 let co1 = &colliders[pair.collider1];
332 let co2 = &colliders[pair.collider2];
333 let threshold = co1
334 .effective_contact_force_event_threshold()
335 .min(co2.effective_contact_force_event_threshold());
336
337 if threshold < Real::MAX {
338 let total_magnitude = pair.total_impulse_magnitude() * inv_dt;
339
340 if total_magnitude > threshold {
343 events.handle_contact_force_event(
344 integration_parameters.dt,
345 bodies,
346 colliders,
347 pair,
348 total_magnitude,
349 );
350 }
351 }
352 }
353
354 self.counters.stages.solver_time.pause();
355 }
356
357 fn run_ccd_motion_clamping(
358 &mut self,
359 integration_parameters: &IntegrationParameters,
360 islands: &IslandManager,
361 bodies: &mut RigidBodySet,
362 colliders: &mut ColliderSet,
363 broad_phase: &mut BroadPhaseBvh,
364 narrow_phase: &NarrowPhase,
365 ccd_solver: &mut CCDSolver,
366 events: &dyn EventHandler,
367 ) {
368 self.counters.ccd.toi_computation_time.start();
369 let impacts = ccd_solver.predict_impacts_at_next_positions(
371 integration_parameters,
372 islands,
373 bodies,
374 colliders,
375 broad_phase,
376 narrow_phase,
377 events,
378 );
379 ccd_solver.clamp_motions(integration_parameters.dt, bodies, &impacts);
380 self.counters.ccd.toi_computation_time.pause();
381 }
382
383 fn advance_to_final_positions(
384 &mut self,
385 islands: &IslandManager,
386 bodies: &mut RigidBodySet,
387 colliders: &mut ColliderSet,
388 modified_colliders: &mut ModifiedColliders,
389 ) {
390 for handle in islands.active_bodies() {
392 let rb = bodies.index_mut_internal(*handle);
393 rb.pos.position = rb.pos.next_position;
394 rb.colliders
395 .update_positions(colliders, modified_colliders, &rb.pos.position);
396 }
397 }
398
399 fn interpolate_kinematic_velocities(
400 &mut self,
401 integration_parameters: &IntegrationParameters,
402 islands: &IslandManager,
403 bodies: &mut RigidBodySet,
404 ) {
405 for handle in islands.active_bodies() {
411 let rb = bodies.index_mut_internal(*handle);
413
414 match rb.body_type {
415 RigidBodyType::KinematicPositionBased => {
416 rb.vels = rb.pos.interpolate_velocity(
417 integration_parameters.inv_dt(),
418 &rb.mprops.local_mprops.local_com,
419 );
420 }
421 RigidBodyType::KinematicVelocityBased => {}
422 _ => {}
423 }
424 }
425 }
426
427 pub fn step(
478 &mut self,
479 gravity: &Vector<Real>,
480 integration_parameters: &IntegrationParameters,
481 islands: &mut IslandManager,
482 broad_phase: &mut BroadPhaseBvh,
483 narrow_phase: &mut NarrowPhase,
484 bodies: &mut RigidBodySet,
485 colliders: &mut ColliderSet,
486 impulse_joints: &mut ImpulseJointSet,
487 multibody_joints: &mut MultibodyJointSet,
488 ccd_solver: &mut CCDSolver,
489 hooks: &dyn PhysicsHooks,
490 events: &dyn EventHandler,
491 ) {
492 self.counters.reset();
493 self.counters.step_started();
494
495 self.counters.stages.user_changes.start();
497 #[cfg(feature = "enhanced-determinism")]
498 let impulse_joints_iterator = impulse_joints
499 .to_wake_up
500 .drain(..)
501 .chain(multibody_joints.to_wake_up.drain(..));
502 #[cfg(not(feature = "enhanced-determinism"))]
503 let impulse_joints_iterator = impulse_joints
504 .to_wake_up
505 .drain()
506 .chain(multibody_joints.to_wake_up.drain());
507 for handle in impulse_joints_iterator {
508 islands.wake_up(bodies, handle, true);
509 }
510
511 let mut modified_colliders = colliders.take_modified();
513 let mut removed_colliders = colliders.take_removed();
514
515 super::user_changes::handle_user_changes_to_colliders(
516 bodies,
517 colliders,
518 &modified_colliders[..],
519 );
520
521 let mut modified_bodies = bodies.take_modified();
522 super::user_changes::handle_user_changes_to_rigid_bodies(
523 Some(islands),
524 bodies,
525 colliders,
526 impulse_joints,
527 multibody_joints,
528 &modified_bodies,
529 &mut modified_colliders,
530 );
531
532 removed_colliders.extend(
536 modified_colliders
537 .iter()
538 .copied()
539 .filter(|h| colliders.get(*h).map(|c| !c.is_enabled()).unwrap_or(false)),
540 );
541 self.counters.stages.user_changes.pause();
542
543 for multibody in &mut multibody_joints.multibodies {
546 multibody.1.forward_kinematics(bodies, true);
547 multibody
548 .1
549 .update_rigid_bodies_internal(bodies, true, false, false);
550 }
551
552 self.detect_collisions(
553 integration_parameters,
554 islands,
555 broad_phase,
556 narrow_phase,
557 bodies,
558 colliders,
559 impulse_joints,
560 multibody_joints,
561 &modified_colliders,
562 &removed_colliders,
563 hooks,
564 events,
565 true,
566 );
567
568 self.counters.stages.user_changes.resume();
569 self.clear_modified_colliders(colliders, &mut modified_colliders);
570 self.clear_modified_bodies(bodies, &mut modified_bodies);
571 removed_colliders.clear();
572 self.counters.stages.user_changes.pause();
573
574 let mut remaining_time = integration_parameters.dt;
575 let mut integration_parameters = *integration_parameters;
576
577 let (ccd_is_enabled, mut remaining_substeps) =
578 if integration_parameters.max_ccd_substeps == 0 {
579 (false, 1)
580 } else {
581 (true, integration_parameters.max_ccd_substeps)
582 };
583
584 while remaining_substeps > 0 {
585 if ccd_is_enabled && remaining_substeps > 1 {
596 let ccd_active =
599 ccd_solver.update_ccd_active_flags(islands, bodies, remaining_time, true);
600 let first_impact = if ccd_active {
601 ccd_solver.find_first_impact(
602 remaining_time,
603 &integration_parameters,
604 islands,
605 bodies,
606 colliders,
607 broad_phase,
608 narrow_phase,
609 )
610 } else {
611 None
612 };
613
614 if let Some(toi) = first_impact {
615 let original_interval = remaining_time / (remaining_substeps as Real);
616
617 if toi < original_interval {
618 integration_parameters.dt = original_interval;
619 } else {
620 integration_parameters.dt =
621 toi + (remaining_time - toi) / (remaining_substeps as Real);
622 }
623
624 remaining_substeps -= 1;
625 } else {
626 integration_parameters.dt = remaining_time;
628 remaining_substeps = 0;
629 }
630
631 remaining_time -= integration_parameters.dt;
632
633 if remaining_time <= integration_parameters.min_ccd_dt {
635 integration_parameters.dt += remaining_time;
636 remaining_substeps = 0;
637 }
638 } else {
639 integration_parameters.dt = remaining_time;
640 remaining_time = 0.0;
641 remaining_substeps = 0;
642 }
643
644 self.counters.ccd.num_substeps += 1;
645
646 self.interpolate_kinematic_velocities(&integration_parameters, islands, bodies);
647 self.build_islands_and_solve_velocity_constraints(
648 gravity,
649 &integration_parameters,
650 islands,
651 narrow_phase,
652 bodies,
653 colliders,
654 impulse_joints,
655 multibody_joints,
656 events,
657 );
658
659 if ccd_is_enabled {
661 let ccd_active = ccd_solver.update_ccd_active_flags(
664 islands,
665 bodies,
666 integration_parameters.dt,
667 false,
668 );
669 if ccd_active {
670 self.run_ccd_motion_clamping(
671 &integration_parameters,
672 islands,
673 bodies,
674 colliders,
675 broad_phase,
676 narrow_phase,
677 ccd_solver,
678 events,
679 );
680 }
681 }
682
683 self.counters.stages.update_time.resume();
684 self.advance_to_final_positions(islands, bodies, colliders, &mut modified_colliders);
685 self.counters.stages.update_time.pause();
686
687 if remaining_substeps > 0 {
688 self.detect_collisions(
689 &integration_parameters,
690 islands,
691 broad_phase,
692 narrow_phase,
693 bodies,
694 colliders,
695 impulse_joints,
696 multibody_joints,
697 &modified_colliders,
698 &[],
699 hooks,
700 events,
701 false,
702 );
703
704 self.clear_modified_colliders(colliders, &mut modified_colliders);
705 } else {
706 for handle in modified_colliders.iter() {
709 let co = colliders.index_mut_internal(*handle);
710 if co.is_enabled() {
717 let aabb = co.compute_broad_phase_aabb(&integration_parameters, bodies);
718 broad_phase.set_aabb(&integration_parameters, *handle, aabb);
719 }
720
721 co.changes.remove(ColliderChanges::IN_MODIFIED_SET);
731 }
732
733 modified_colliders.clear();
735 }
736 }
737
738 self.counters.stages.update_time.resume();
745 for handle in islands.active_bodies() {
746 let rb = bodies.index_mut_internal(*handle);
747 rb.mprops
748 .update_world_mass_properties(rb.body_type, &rb.pos.position);
749 }
750 self.counters.stages.update_time.pause();
751
752 colliders.set_modified(modified_colliders);
754
755 self.counters.step_completed();
756 }
757}
758
759#[cfg(test)]
760mod test {
761 use na::point;
762
763 use crate::dynamics::{
764 CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, RigidBodyBuilder,
765 RigidBodySet,
766 };
767 use crate::geometry::{BroadPhaseBvh, ColliderBuilder, ColliderSet, NarrowPhase};
768 use crate::math::Vector;
769 use crate::pipeline::PhysicsPipeline;
770 use crate::prelude::{MultibodyJointSet, RevoluteJointBuilder, RigidBodyType};
771
772 #[test]
773 fn kinematic_and_fixed_contact_crash() {
774 let mut colliders = ColliderSet::new();
775 let mut impulse_joints = ImpulseJointSet::new();
776 let mut multibody_joints = MultibodyJointSet::new();
777 let mut pipeline = PhysicsPipeline::new();
778 let mut bf = BroadPhaseBvh::new();
779 let mut nf = NarrowPhase::new();
780 let mut bodies = RigidBodySet::new();
781 let mut islands = IslandManager::new();
782
783 let rb = RigidBodyBuilder::fixed().build();
784 let h1 = bodies.insert(rb.clone());
785 let co = ColliderBuilder::ball(10.0).build();
786 colliders.insert_with_parent(co.clone(), h1, &mut bodies);
787
788 let rb = RigidBodyBuilder::kinematic_position_based().build();
790 let h2 = bodies.insert(rb.clone());
791 colliders.insert_with_parent(co, h2, &mut bodies);
792
793 pipeline.step(
794 &Vector::zeros(),
795 &IntegrationParameters::default(),
796 &mut islands,
797 &mut bf,
798 &mut nf,
799 &mut bodies,
800 &mut colliders,
801 &mut impulse_joints,
802 &mut multibody_joints,
803 &mut CCDSolver::new(),
804 &(),
805 &(),
806 );
807 }
808
809 #[test]
810 fn rigid_body_removal_before_step() {
811 let mut colliders = ColliderSet::new();
812 let mut impulse_joints = ImpulseJointSet::new();
813 let mut multibody_joints = MultibodyJointSet::new();
814 let mut pipeline = PhysicsPipeline::new();
815 let mut bf = BroadPhaseBvh::new();
816 let mut nf = NarrowPhase::new();
817 let mut islands = IslandManager::new();
818
819 let mut bodies = RigidBodySet::new();
820
821 let rb = RigidBodyBuilder::dynamic().build();
825 let h1 = bodies.insert(rb.clone());
826 let h2 = bodies.insert(rb.clone());
827
828 let rb = RigidBodyBuilder::kinematic_position_based().build();
830 let h3 = bodies.insert(rb.clone());
831
832 let rb = RigidBodyBuilder::fixed().build();
834 let h4 = bodies.insert(rb.clone());
835
836 let to_delete = [h1, h2, h3, h4];
837 for h in &to_delete {
838 bodies.remove(
839 *h,
840 &mut islands,
841 &mut colliders,
842 &mut impulse_joints,
843 &mut multibody_joints,
844 true,
845 );
846 }
847
848 pipeline.step(
849 &Vector::zeros(),
850 &IntegrationParameters::default(),
851 &mut islands,
852 &mut bf,
853 &mut nf,
854 &mut bodies,
855 &mut colliders,
856 &mut impulse_joints,
857 &mut multibody_joints,
858 &mut CCDSolver::new(),
859 &(),
860 &(),
861 );
862 }
863
864 #[cfg(feature = "serde-serialize")]
865 #[test]
866 fn rigid_body_removal_snapshot_handle_determinism() {
867 let mut colliders = ColliderSet::new();
868 let mut impulse_joints = ImpulseJointSet::new();
869 let mut multibody_joints = MultibodyJointSet::new();
870 let mut islands = IslandManager::new();
871
872 let mut bodies = RigidBodySet::new();
873 let rb = RigidBodyBuilder::dynamic().build();
874 let h1 = bodies.insert(rb.clone());
875 let h2 = bodies.insert(rb.clone());
876 let h3 = bodies.insert(rb.clone());
877
878 bodies.remove(
879 h1,
880 &mut islands,
881 &mut colliders,
882 &mut impulse_joints,
883 &mut multibody_joints,
884 true,
885 );
886 bodies.remove(
887 h3,
888 &mut islands,
889 &mut colliders,
890 &mut impulse_joints,
891 &mut multibody_joints,
892 true,
893 );
894 bodies.remove(
895 h2,
896 &mut islands,
897 &mut colliders,
898 &mut impulse_joints,
899 &mut multibody_joints,
900 true,
901 );
902
903 let ser_bodies = bincode::serialize(&bodies).unwrap();
904 let mut bodies2: RigidBodySet = bincode::deserialize(&ser_bodies).unwrap();
905
906 let h1a = bodies.insert(rb.clone());
907 let h2a = bodies.insert(rb.clone());
908 let h3a = bodies.insert(rb.clone());
909
910 let h1b = bodies2.insert(rb.clone());
911 let h2b = bodies2.insert(rb.clone());
912 let h3b = bodies2.insert(rb.clone());
913
914 assert_eq!(h1a, h1b);
915 assert_eq!(h2a, h2b);
916 assert_eq!(h3a, h3b);
917 }
918
919 #[test]
920 fn collider_removal_before_step() {
921 let mut pipeline = PhysicsPipeline::new();
922 let gravity = Vector::y() * -9.81;
923 let integration_parameters = IntegrationParameters::default();
924 let mut broad_phase = BroadPhaseBvh::new();
925 let mut narrow_phase = NarrowPhase::new();
926 let mut bodies = RigidBodySet::new();
927 let mut colliders = ColliderSet::new();
928 let mut ccd = CCDSolver::new();
929 let mut impulse_joints = ImpulseJointSet::new();
930 let mut multibody_joints = MultibodyJointSet::new();
931 let mut islands = IslandManager::new();
932 let physics_hooks = ();
933 let event_handler = ();
934
935 let body = RigidBodyBuilder::dynamic().build();
936 let b_handle = bodies.insert(body);
937 let collider = ColliderBuilder::ball(1.0).build();
938 let c_handle = colliders.insert_with_parent(collider, b_handle, &mut bodies);
939 colliders.remove(c_handle, &mut islands, &mut bodies, true);
940 bodies.remove(
941 b_handle,
942 &mut islands,
943 &mut colliders,
944 &mut impulse_joints,
945 &mut multibody_joints,
946 true,
947 );
948
949 for _ in 0..10 {
950 pipeline.step(
951 &gravity,
952 &integration_parameters,
953 &mut islands,
954 &mut broad_phase,
955 &mut narrow_phase,
956 &mut bodies,
957 &mut colliders,
958 &mut impulse_joints,
959 &mut multibody_joints,
960 &mut ccd,
961 &physics_hooks,
962 &event_handler,
963 );
964 }
965 }
966
967 #[test]
968 fn rigid_body_type_changed_dynamic_is_in_active_set() {
969 let mut colliders = ColliderSet::new();
970 let mut impulse_joints = ImpulseJointSet::new();
971 let mut multibody_joints = MultibodyJointSet::new();
972 let mut pipeline = PhysicsPipeline::new();
973 let mut bf = BroadPhaseBvh::new();
974 let mut nf = NarrowPhase::new();
975 let mut islands = IslandManager::new();
976
977 let mut bodies = RigidBodySet::new();
978
979 let rb = RigidBodyBuilder::kinematic_position_based()
981 .additional_mass(1.0)
982 .build();
983 let h = bodies.insert(rb.clone());
984
985 let gravity = Vector::y() * -9.81;
987 pipeline.step(
988 &gravity,
989 &IntegrationParameters::default(),
990 &mut islands,
991 &mut bf,
992 &mut nf,
993 &mut bodies,
994 &mut colliders,
995 &mut impulse_joints,
996 &mut multibody_joints,
997 &mut CCDSolver::new(),
998 &(),
999 &(),
1000 );
1001
1002 bodies
1004 .get_mut(h)
1005 .unwrap()
1006 .set_body_type(RigidBodyType::Dynamic, true);
1007
1008 pipeline.step(
1010 &gravity,
1011 &IntegrationParameters::default(),
1012 &mut islands,
1013 &mut bf,
1014 &mut nf,
1015 &mut bodies,
1016 &mut colliders,
1017 &mut impulse_joints,
1018 &mut multibody_joints,
1019 &mut CCDSolver::new(),
1020 &(),
1021 &(),
1022 );
1023
1024 let body = bodies.get(h).unwrap();
1025 let h_y = body.pos.position.translation.y;
1026
1027 assert!(h_y < 0.0);
1029
1030 assert!(islands.active_set.contains(&h));
1032 }
1033
1034 #[test]
1035 fn joint_step_delta_time_0() {
1036 let mut colliders = ColliderSet::new();
1037 let mut impulse_joints = ImpulseJointSet::new();
1038 let mut multibody_joints = MultibodyJointSet::new();
1039 let mut pipeline = PhysicsPipeline::new();
1040 let mut bf = BroadPhaseBvh::new();
1041 let mut nf = NarrowPhase::new();
1042 let mut islands = IslandManager::new();
1043
1044 let mut bodies = RigidBodySet::new();
1045
1046 let rb = RigidBodyBuilder::fixed().additional_mass(1.0).build();
1048 let h = bodies.insert(rb.clone());
1049 let rb_dynamic = RigidBodyBuilder::dynamic().additional_mass(1.0).build();
1050 let h_dynamic = bodies.insert(rb_dynamic.clone());
1051
1052 #[cfg(feature = "dim2")]
1054 let joint = RevoluteJointBuilder::new()
1055 .local_anchor1(point![0.0, 1.0])
1056 .local_anchor2(point![0.0, -3.0]);
1057 #[cfg(feature = "dim3")]
1058 let joint = RevoluteJointBuilder::new(Vector::z_axis())
1059 .local_anchor1(point![0.0, 1.0, 0.0])
1060 .local_anchor2(point![0.0, -3.0, 0.0]);
1061 impulse_joints.insert(h, h_dynamic, joint, true);
1062
1063 let parameters = IntegrationParameters {
1064 dt: 0.0,
1065 ..Default::default()
1066 };
1067 let gravity = Vector::y() * -9.81;
1069 pipeline.step(
1070 &gravity,
1071 ¶meters,
1072 &mut islands,
1073 &mut bf,
1074 &mut nf,
1075 &mut bodies,
1076 &mut colliders,
1077 &mut impulse_joints,
1078 &mut multibody_joints,
1079 &mut CCDSolver::new(),
1080 &(),
1081 &(),
1082 );
1083 let translation = bodies[h_dynamic].translation();
1084 let rotation = bodies[h_dynamic].rotation();
1085 assert!(translation.x.is_finite());
1086 assert!(translation.y.is_finite());
1087 #[cfg(feature = "dim2")]
1088 assert!(rotation.is_finite());
1089 #[cfg(feature = "dim3")]
1090 {
1091 assert!(translation.z.is_finite());
1092 assert!(rotation.i.is_finite());
1093 assert!(rotation.j.is_finite());
1094 assert!(rotation.k.is_finite());
1095 assert!(rotation.w.is_finite());
1096 }
1097 }
1098
1099 #[test]
1100 #[cfg(feature = "dim2")]
1101 fn test_multi_sap_disable_body() {
1102 use na::vector;
1103 let mut rigid_body_set = RigidBodySet::new();
1104 let mut collider_set = ColliderSet::new();
1105
1106 let collider = ColliderBuilder::cuboid(100.0, 0.1).build();
1108 collider_set.insert(collider);
1109
1110 let rigid_body = RigidBodyBuilder::dynamic()
1112 .translation(vector![0.0, 10.0])
1113 .build();
1114 let collider = ColliderBuilder::ball(0.5).restitution(0.7).build();
1115 let ball_body_handle = rigid_body_set.insert(rigid_body);
1116 collider_set.insert_with_parent(collider, ball_body_handle, &mut rigid_body_set);
1117
1118 let gravity = vector![0.0, -9.81];
1120 let integration_parameters = IntegrationParameters::default();
1121 let mut physics_pipeline = PhysicsPipeline::new();
1122 let mut island_manager = IslandManager::new();
1123 let mut broad_phase = BroadPhaseBvh::new();
1124 let mut narrow_phase = NarrowPhase::new();
1125 let mut impulse_joint_set = ImpulseJointSet::new();
1126 let mut multibody_joint_set = MultibodyJointSet::new();
1127 let mut ccd_solver = CCDSolver::new();
1128 let physics_hooks = ();
1129 let event_handler = ();
1130
1131 physics_pipeline.step(
1132 &gravity,
1133 &integration_parameters,
1134 &mut island_manager,
1135 &mut broad_phase,
1136 &mut narrow_phase,
1137 &mut rigid_body_set,
1138 &mut collider_set,
1139 &mut impulse_joint_set,
1140 &mut multibody_joint_set,
1141 &mut ccd_solver,
1142 &physics_hooks,
1143 &event_handler,
1144 );
1145
1146 {
1148 let ball_body = &mut rigid_body_set[ball_body_handle];
1149
1150 ball_body.set_translation(vector![1.0, 1.0], true);
1152 ball_body.set_rotation(nalgebra::UnitComplex::new(1.0), true);
1153
1154 ball_body.set_enabled(false);
1155 }
1156
1157 physics_pipeline.step(
1158 &gravity,
1159 &integration_parameters,
1160 &mut island_manager,
1161 &mut broad_phase,
1162 &mut narrow_phase,
1163 &mut rigid_body_set,
1164 &mut collider_set,
1165 &mut impulse_joint_set,
1166 &mut multibody_joint_set,
1167 &mut ccd_solver,
1168 &physics_hooks,
1169 &event_handler,
1170 );
1171
1172 {
1174 let ball_body = &mut rigid_body_set[ball_body_handle];
1175
1176 ball_body.set_translation(vector![0.0, 0.0], true);
1178 ball_body.set_rotation(nalgebra::UnitComplex::new(0.0), true);
1179
1180 ball_body.set_enabled(true);
1181 }
1182
1183 physics_pipeline.step(
1184 &gravity,
1185 &integration_parameters,
1186 &mut island_manager,
1187 &mut broad_phase,
1188 &mut narrow_phase,
1189 &mut rigid_body_set,
1190 &mut collider_set,
1191 &mut impulse_joint_set,
1192 &mut multibody_joint_set,
1193 &mut ccd_solver,
1194 &physics_hooks,
1195 &event_handler,
1196 );
1197 }
1198}