1use crate::{
24 core::{
25 algebra::{
26 Isometry2, Isometry3, Matrix4, Point2, Rotation3, Translation2, Translation3,
27 UnitComplex, UnitQuaternion, UnitVector2, Vector2, Vector3,
28 },
29 arrayvec::ArrayVec,
30 instant,
31 log::{Log, MessageKind},
32 math::Matrix4Ext,
33 parking_lot::Mutex,
34 pool::Handle,
35 reflect::prelude::*,
36 variable::{InheritableVariable, VariableFlags},
37 visitor::prelude::*,
38 BiDirHashMap, ImmutableString,
39 },
40 graph::{BaseSceneGraph, SceneGraphNode},
41 scene::{
42 self,
43 collider::{self},
44 debug::SceneDrawingContext,
45 dim2::{
46 self, collider::ColliderShape, collider::TileMapShape, joint::JointLocalFrames,
47 joint::JointParams, rigidbody::ApplyAction,
48 },
49 graph::{
50 isometric_global_transform,
51 physics::{FeatureId, IntegrationParameters, PhysicsPerformanceStatistics},
52 Graph, NodePool,
53 },
54 node::{Node, NodeTrait},
55 tilemap::TileMap,
56 },
57};
58pub use rapier2d::geometry::shape::*;
59use rapier2d::{
60 dynamics::{
61 CCDSolver, GenericJoint, GenericJointBuilder, ImpulseJointHandle, ImpulseJointSet,
62 IslandManager, JointAxesMask, JointAxis, MultibodyJointHandle, MultibodyJointSet,
63 RigidBody, RigidBodyActivation, RigidBodyBuilder, RigidBodyHandle, RigidBodySet,
64 RigidBodyType,
65 },
66 geometry::{
67 Collider, ColliderBuilder, ColliderHandle, ColliderSet, Cuboid, DefaultBroadPhase,
68 InteractionGroups, NarrowPhase, Ray, SharedShape,
69 },
70 parry::query::ShapeCastOptions,
71 pipeline::{DebugRenderPipeline, EventHandler, PhysicsPipeline, QueryPipeline},
72};
73use std::{
74 cell::RefCell,
75 cmp::Ordering,
76 fmt::{Debug, Formatter},
77 hash::Hash,
78 num::NonZeroUsize,
79 sync::Arc,
80};
81
82use super::collider::GeometrySource;
83
84pub trait QueryResultsStorage {
88 fn push(&mut self, intersection: Intersection) -> bool;
91
92 fn clear(&mut self);
94
95 fn sort_intersections_by<C: FnMut(&Intersection, &Intersection) -> Ordering>(&mut self, cmp: C);
97}
98
99impl QueryResultsStorage for Vec<Intersection> {
100 fn push(&mut self, intersection: Intersection) -> bool {
101 self.push(intersection);
102 true
103 }
104
105 fn clear(&mut self) {
106 self.clear()
107 }
108
109 fn sort_intersections_by<C>(&mut self, cmp: C)
110 where
111 C: FnMut(&Intersection, &Intersection) -> Ordering,
112 {
113 self.sort_by(cmp);
114 }
115}
116
117impl<const CAP: usize> QueryResultsStorage for ArrayVec<Intersection, CAP> {
118 fn push(&mut self, intersection: Intersection) -> bool {
119 self.try_push(intersection).is_ok()
120 }
121
122 fn clear(&mut self) {
123 self.clear()
124 }
125
126 fn sort_intersections_by<C>(&mut self, cmp: C)
127 where
128 C: FnMut(&Intersection, &Intersection) -> Ordering,
129 {
130 self.sort_by(cmp);
131 }
132}
133
134#[derive(Debug, Clone, PartialEq)]
136pub struct Intersection {
137 pub collider: Handle<Node>,
139
140 pub normal: Vector2<f32>,
142
143 pub position: Point2<f32>,
145
146 pub feature: FeatureId,
156
157 pub toi: f32,
159}
160
161pub struct RayCastOptions {
163 pub ray_origin: Point2<f32>,
165
166 pub ray_direction: Vector2<f32>,
168
169 pub max_len: f32,
171
172 pub groups: collider::InteractionGroups,
174
175 pub sort_results: bool,
177}
178
179#[derive(Debug, Clone, PartialEq)]
181pub struct ContactData {
182 pub local_p1: Vector2<f32>,
184 pub local_p2: Vector2<f32>,
186 pub dist: f32,
188 pub impulse: f32,
191 pub tangent_impulse: f32,
194}
195
196#[derive(Debug, Clone, PartialEq)]
198pub struct ContactManifold {
199 pub points: Vec<ContactData>,
201 pub local_n1: Vector2<f32>,
203 pub local_n2: Vector2<f32>,
205 pub rigid_body1: Handle<Node>,
207 pub rigid_body2: Handle<Node>,
209 pub normal: Vector2<f32>,
211}
212
213#[derive(Debug, Clone, PartialEq)]
215pub struct ContactPair {
216 pub collider1: Handle<Node>,
218 pub collider2: Handle<Node>,
220 pub manifolds: Vec<ContactManifold>,
223 pub has_any_active_contact: bool,
225}
226
227impl ContactPair {
228 fn from_native(c: &rapier2d::geometry::ContactPair, physics: &PhysicsWorld) -> Option<Self> {
229 Some(ContactPair {
230 collider1: Handle::decode_from_u128(physics.colliders.get(c.collider1)?.user_data),
231 collider2: Handle::decode_from_u128(physics.colliders.get(c.collider2)?.user_data),
232 manifolds: c
233 .manifolds
234 .iter()
235 .filter_map(|m| {
236 Some(ContactManifold {
237 points: m
238 .points
239 .iter()
240 .map(|p| ContactData {
241 local_p1: p.local_p1.coords,
242 local_p2: p.local_p2.coords,
243 dist: p.dist,
244 impulse: p.data.impulse,
245 tangent_impulse: p.data.tangent_impulse.x,
246 })
247 .collect(),
248 local_n1: m.local_n1,
249 local_n2: m.local_n2,
250 rigid_body1: m.data.rigid_body1.and_then(|h| {
251 physics
252 .bodies
253 .get(h)
254 .map(|b| Handle::decode_from_u128(b.user_data))
255 })?,
256 rigid_body2: m.data.rigid_body2.and_then(|h| {
257 physics
258 .bodies
259 .get(h)
260 .map(|b| Handle::decode_from_u128(b.user_data))
261 })?,
262 normal: m.data.normal,
263 })
264 })
265 .collect(),
266 has_any_active_contact: c.has_any_active_contact,
267 })
268 }
269}
270
271#[derive(Debug, Clone, PartialEq)]
273pub struct IntersectionPair {
274 pub collider1: Handle<Node>,
276 pub collider2: Handle<Node>,
278 pub has_any_active_contact: bool,
280}
281
282pub(super) struct Container<S, A>
283where
284 A: Hash + Eq + Clone,
285{
286 set: S,
287 map: BiDirHashMap<A, Handle<Node>>,
288}
289
290fn convert_joint_params(
291 params: scene::dim2::joint::JointParams,
292 local_frame1: Isometry2<f32>,
293 local_frame2: Isometry2<f32>,
294) -> GenericJoint {
295 let locked_axis = match params {
296 JointParams::BallJoint(_) => JointAxesMask::LOCKED_REVOLUTE_AXES,
297 JointParams::FixedJoint(_) => JointAxesMask::LOCKED_FIXED_AXES,
298 JointParams::PrismaticJoint(_) => JointAxesMask::LOCKED_PRISMATIC_AXES,
299 };
300
301 let mut joint = GenericJointBuilder::new(locked_axis)
302 .local_frame1(local_frame1)
303 .local_frame2(local_frame2)
304 .build();
305
306 match params {
307 scene::dim2::joint::JointParams::BallJoint(v) => {
308 if v.limits_enabled {
309 joint.set_limits(
310 JointAxis::AngX,
311 [v.limits_angles.start, v.limits_angles.end],
312 );
313 }
314 }
315 scene::dim2::joint::JointParams::FixedJoint(_) => {}
316 scene::dim2::joint::JointParams::PrismaticJoint(v) => {
317 if v.limits_enabled {
318 joint.set_limits(JointAxis::LinX, [v.limits.start, v.limits.end]);
319 }
320 }
321 }
322
323 joint
324}
325
326fn tile_map_to_collider_shape(
327 tile_map: &GeometrySource,
328 owner_inv_transform: Matrix4<f32>,
329 nodes: &NodePool,
330 collider_name: &ImmutableString,
331) -> Option<SharedShape> {
332 let tile_map = nodes.try_borrow(tile_map.0)?.component_ref::<TileMap>()?;
333
334 let tile_set_resource = tile_map.tile_set()?.data_ref();
335 let tile_set = tile_set_resource.as_loaded_ref()?;
336
337 let tile_scale = tile_map.tile_scale();
338 let global_transform = owner_inv_transform
339 * tile_map.global_transform()
340 * Matrix4::new_nonuniform_scaling(&Vector3::new(-tile_scale.x, tile_scale.y, 1.0));
341
342 let mut vertices = Vec::new();
343 let mut triangles = Vec::new();
344
345 let collider_uuid = tile_set.collider_name_to_uuid(collider_name)?;
346 let tile_data = tile_map.tiles()?.data_ref();
347 let tile_data = tile_data.as_loaded_ref()?;
348 for (position, handle) in tile_data.iter() {
349 let Some(tile_definition) = tile_set.get_tile_data(handle.into()) else {
350 continue;
351 };
352
353 if let Some(collider) = tile_definition.colliders.get(&collider_uuid) {
354 let position = position.cast::<f32>().to_homogeneous();
355 collider.build_collider_shape(
356 &global_transform,
357 position,
358 &mut vertices,
359 &mut triangles,
360 );
361 }
362 }
363
364 SharedShape::trimesh(vertices, triangles).ok()
365}
366
367fn collider_shape_into_native_shape(
369 shape: &ColliderShape,
370 owner_inv_transform: Matrix4<f32>,
371 nodes: &NodePool,
372) -> Option<SharedShape> {
373 match shape {
374 ColliderShape::Ball(ball) => Some(SharedShape::ball(ball.radius)),
375 ColliderShape::Cuboid(cuboid) => {
376 Some(SharedShape(Arc::new(Cuboid::new(cuboid.half_extents))))
377 }
378 ColliderShape::Capsule(capsule) => Some(SharedShape::capsule(
379 Point2::from(capsule.begin),
380 Point2::from(capsule.end),
381 capsule.radius,
382 )),
383 ColliderShape::Segment(segment) => Some(SharedShape::segment(
384 Point2::from(segment.begin),
385 Point2::from(segment.end),
386 )),
387 ColliderShape::Triangle(triangle) => Some(SharedShape::triangle(
388 Point2::from(triangle.a),
389 Point2::from(triangle.b),
390 Point2::from(triangle.c),
391 )),
392 ColliderShape::Trimesh(_) => {
393 None }
395 ColliderShape::Heightfield(_) => {
396 None }
398 ColliderShape::TileMap(TileMapShape {
399 tile_map,
400 layer_name: collider_layer_name,
401 }) => tile_map_to_collider_shape(tile_map, owner_inv_transform, nodes, collider_layer_name),
402 }
403}
404
405fn isometry2_to_mat4(isometry: &Isometry2<f32>) -> Matrix4<f32> {
406 Isometry3 {
407 rotation: UnitQuaternion::from_euler_angles(0.0, 0.0, isometry.rotation.angle()),
408 translation: Translation3 {
409 vector: Vector3::new(isometry.translation.x, isometry.translation.y, 0.0),
410 },
411 }
412 .to_homogeneous()
413}
414
415#[derive(Visit, Reflect)]
419pub struct PhysicsWorld {
420 pub enabled: InheritableVariable<bool>,
422
423 pub integration_parameters: InheritableVariable<IntegrationParameters>,
425
426 pub gravity: InheritableVariable<Vector2<f32>>,
428
429 #[visit(skip)]
431 #[reflect(hidden)]
432 pub performance_statistics: PhysicsPerformanceStatistics,
433
434 #[visit(skip)]
436 #[reflect(hidden)]
437 pipeline: PhysicsPipeline,
438 #[visit(skip)]
440 #[reflect(hidden)]
441 broad_phase: DefaultBroadPhase,
442 #[visit(skip)]
444 #[reflect(hidden)]
445 narrow_phase: NarrowPhase,
446 #[visit(skip)]
448 #[reflect(hidden)]
449 ccd_solver: CCDSolver,
450 #[visit(skip)]
453 #[reflect(hidden)]
454 islands: IslandManager,
455 #[visit(skip)]
457 #[reflect(hidden)]
458 bodies: RigidBodySet,
459 #[visit(skip)]
461 #[reflect(hidden)]
462 pub(crate) colliders: ColliderSet,
463 #[visit(skip)]
465 #[reflect(hidden)]
466 joints: Container<ImpulseJointSet, ImpulseJointHandle>,
467 #[visit(skip)]
469 #[reflect(hidden)]
470 multibody_joints: Container<MultibodyJointSet, MultibodyJointHandle>,
471 #[visit(skip)]
473 #[reflect(hidden)]
474 event_handler: Box<dyn EventHandler>,
475 #[visit(skip)]
476 #[reflect(hidden)]
477 query: RefCell<QueryPipeline>,
478 #[visit(skip)]
479 #[reflect(hidden)]
480 debug_render_pipeline: Mutex<DebugRenderPipeline>,
481}
482
483impl Clone for PhysicsWorld {
484 fn clone(&self) -> Self {
485 PhysicsWorld {
486 enabled: self.enabled.clone(),
487 integration_parameters: self.integration_parameters.clone(),
488 gravity: self.gravity.clone(),
489 ..Default::default()
490 }
491 }
492}
493
494fn isometry_from_global_transform(transform: &Matrix4<f32>) -> Isometry2<f32> {
495 Isometry2 {
496 translation: Translation2::new(transform[12], transform[13]),
497 rotation: UnitComplex::from_angle(
498 Rotation3::from_matrix_eps(&transform.basis(), f32::EPSILON, 16, Rotation3::identity())
499 .euler_angles()
500 .2,
501 ),
502 }
503}
504
505fn calculate_local_frames(
506 joint: &dyn NodeTrait,
507 body1: &dyn NodeTrait,
508 body2: &dyn NodeTrait,
509) -> (Isometry2<f32>, Isometry2<f32>) {
510 let joint_isometry = isometry_from_global_transform(&joint.global_transform());
511
512 (
513 joint_isometry * isometry_from_global_transform(&body1.global_transform()).inverse(),
514 joint_isometry * isometry_from_global_transform(&body2.global_transform()).inverse(),
515 )
516}
517
518fn u32_to_group(v: u32) -> rapier2d::geometry::Group {
519 rapier2d::geometry::Group::from_bits(v).unwrap_or_else(rapier2d::geometry::Group::all)
520}
521
522#[derive(Copy, Clone, Default)]
524#[allow(clippy::type_complexity)]
525pub struct QueryFilter<'a> {
526 pub flags: collider::QueryFilterFlags,
528 pub groups: Option<collider::InteractionGroups>,
531 pub exclude_collider: Option<Handle<Node>>,
533 pub exclude_rigid_body: Option<Handle<Node>>,
535 pub predicate: Option<&'a dyn Fn(Handle<Node>, &collider::Collider) -> bool>,
537}
538
539#[derive(Copy, Clone, Debug)]
541pub struct TOI {
542 pub toi: f32,
544 pub witness1: Point2<f32>,
548 pub witness2: Point2<f32>,
552 pub normal1: UnitVector2<f32>,
556 pub normal2: UnitVector2<f32>,
560 pub status: collider::TOIStatus,
562}
563
564impl PhysicsWorld {
565 pub(crate) fn new() -> Self {
567 Self {
568 enabled: true.into(),
569 pipeline: PhysicsPipeline::new(),
570 gravity: Vector2::new(0.0, -9.81).into(),
571 integration_parameters: IntegrationParameters::default().into(),
572 broad_phase: DefaultBroadPhase::new(),
573 narrow_phase: NarrowPhase::new(),
574 ccd_solver: CCDSolver::new(),
575 islands: IslandManager::new(),
576 bodies: RigidBodySet::new(),
577 colliders: ColliderSet::new(),
578 joints: Container {
579 set: ImpulseJointSet::new(),
580 map: Default::default(),
581 },
582 multibody_joints: Container {
583 set: MultibodyJointSet::new(),
584 map: Default::default(),
585 },
586 event_handler: Box::new(()),
587 query: RefCell::new(Default::default()),
588 performance_statistics: Default::default(),
589 debug_render_pipeline: Default::default(),
590 }
591 }
592
593 pub(crate) fn update(&mut self, dt: f32) {
594 let time = instant::Instant::now();
595
596 if *self.enabled {
597 let integration_parameters = rapier2d::dynamics::IntegrationParameters {
598 dt: self.integration_parameters.dt.unwrap_or(dt),
599 min_ccd_dt: self.integration_parameters.min_ccd_dt,
600 contact_damping_ratio: self.integration_parameters.contact_damping_ratio,
601 contact_natural_frequency: self.integration_parameters.contact_natural_frequency,
602 joint_natural_frequency: self.integration_parameters.joint_natural_frequency,
603 joint_damping_ratio: self.integration_parameters.joint_damping_ratio,
604 warmstart_coefficient: self.integration_parameters.warmstart_coefficient,
605 length_unit: self.integration_parameters.length_unit,
606 normalized_allowed_linear_error: self.integration_parameters.allowed_linear_error,
607 normalized_max_corrective_velocity: self
608 .integration_parameters
609 .normalized_max_corrective_velocity,
610 normalized_prediction_distance: self.integration_parameters.prediction_distance,
611 num_solver_iterations: NonZeroUsize::new(
612 self.integration_parameters.num_solver_iterations,
613 )
614 .unwrap(),
615 num_additional_friction_iterations: self
616 .integration_parameters
617 .num_additional_friction_iterations,
618 num_internal_pgs_iterations: self
619 .integration_parameters
620 .num_internal_pgs_iterations,
621 num_internal_stabilization_iterations: self
622 .integration_parameters
623 .num_internal_stabilization_iterations,
624 min_island_size: self.integration_parameters.min_island_size as usize,
625 max_ccd_substeps: self.integration_parameters.max_ccd_substeps as usize,
626 };
627
628 self.pipeline.step(
629 &self.gravity,
630 &integration_parameters,
631 &mut self.islands,
632 &mut self.broad_phase,
633 &mut self.narrow_phase,
634 &mut self.bodies,
635 &mut self.colliders,
636 &mut self.joints.set,
637 &mut self.multibody_joints.set,
638 &mut self.ccd_solver,
639 None,
642 &(),
643 &*self.event_handler,
644 );
645 }
646
647 self.performance_statistics.step_time += instant::Instant::now() - time;
648 }
649
650 pub(crate) fn add_body(&mut self, owner: Handle<Node>, mut body: RigidBody) -> RigidBodyHandle {
651 body.user_data = owner.encode_to_u128();
652 self.bodies.insert(body)
653 }
654
655 pub(crate) fn remove_body(&mut self, handle: RigidBodyHandle) {
656 self.bodies.remove(
657 handle,
658 &mut self.islands,
659 &mut self.colliders,
660 &mut self.joints.set,
661 &mut self.multibody_joints.set,
662 true,
663 );
664 }
665
666 pub(crate) fn add_collider(
667 &mut self,
668 owner: Handle<Node>,
669 parent_body: RigidBodyHandle,
670 mut collider: Collider,
671 ) -> ColliderHandle {
672 collider.user_data = owner.encode_to_u128();
673 self.colliders
674 .insert_with_parent(collider, parent_body, &mut self.bodies)
675 }
676
677 pub(crate) fn remove_collider(&mut self, handle: ColliderHandle) -> bool {
678 self.colliders
679 .remove(handle, &mut self.islands, &mut self.bodies, false)
680 .is_some()
681 }
682
683 pub(crate) fn add_joint(
684 &mut self,
685 owner: Handle<Node>,
686 body1: RigidBodyHandle,
687 body2: RigidBodyHandle,
688 params: GenericJoint,
689 ) -> ImpulseJointHandle {
690 let handle = self.joints.set.insert(body1, body2, params, false);
691 self.joints.map.insert(handle, owner);
692 handle
693 }
694
695 pub(crate) fn remove_joint(&mut self, handle: ImpulseJointHandle) {
696 if self.joints.set.remove(handle, false).is_some() {
697 assert!(self.joints.map.remove_by_key(&handle).is_some());
698 }
699 }
700
701 pub fn draw(&self, context: &mut SceneDrawingContext) {
704 self.debug_render_pipeline.lock().render(
705 context,
706 &self.bodies,
707 &self.colliders,
708 &self.joints.set,
709 &self.multibody_joints.set,
710 &self.narrow_phase,
711 );
712 }
713
714 pub fn cast_ray<S: QueryResultsStorage>(&self, opts: RayCastOptions, query_buffer: &mut S) {
716 let time = instant::Instant::now();
717
718 let mut query = self.query.borrow_mut();
719
720 query.update(&self.colliders);
726
727 query_buffer.clear();
728 let ray = Ray::new(
729 opts.ray_origin,
730 opts.ray_direction
731 .try_normalize(f32::EPSILON)
732 .unwrap_or_default(),
733 );
734 query.intersections_with_ray(
735 &self.bodies,
736 &self.colliders,
737 &ray,
738 opts.max_len,
739 true,
740 rapier2d::pipeline::QueryFilter::new().groups(InteractionGroups::new(
741 u32_to_group(opts.groups.memberships.0),
742 u32_to_group(opts.groups.filter.0),
743 )),
744 |handle, intersection| {
745 query_buffer.push(Intersection {
746 collider: Handle::decode_from_u128(
747 self.colliders.get(handle).unwrap().user_data,
748 ),
749 normal: intersection.normal,
750 position: ray.point_at(intersection.time_of_impact),
751 feature: intersection.feature.into(),
752 toi: intersection.time_of_impact,
753 })
754 },
755 );
756 if opts.sort_results {
757 query_buffer.sort_intersections_by(|a, b| {
758 if a.toi > b.toi {
759 Ordering::Greater
760 } else if a.toi < b.toi {
761 Ordering::Less
762 } else {
763 Ordering::Equal
764 }
765 })
766 }
767
768 self.performance_statistics.total_ray_cast_time.set(
769 self.performance_statistics.total_ray_cast_time.get()
770 + (instant::Instant::now() - time),
771 );
772 }
773
774 pub fn cast_shape(
794 &self,
795 graph: &Graph,
796 shape: &dyn Shape,
797 shape_pos: &Isometry2<f32>,
798 shape_vel: &Vector2<f32>,
799 max_toi: f32,
800 stop_at_penetration: bool,
801 filter: QueryFilter,
802 ) -> Option<(Handle<Node>, TOI)> {
803 let predicate = |handle: ColliderHandle, _: &Collider| -> bool {
804 if let Some(pred) = filter.predicate {
805 let h = Handle::decode_from_u128(self.colliders.get(handle).unwrap().user_data);
806 pred(
807 h,
808 graph.node(h).component_ref::<collider::Collider>().unwrap(),
809 )
810 } else {
811 true
812 }
813 };
814
815 let filter = rapier2d::pipeline::QueryFilter {
816 flags: rapier2d::pipeline::QueryFilterFlags::from_bits(filter.flags.bits()).unwrap(),
817 groups: filter.groups.map(|g| {
818 InteractionGroups::new(u32_to_group(g.memberships.0), u32_to_group(g.filter.0))
819 }),
820 exclude_collider: filter
821 .exclude_collider
822 .and_then(|h| graph.try_get(h))
823 .and_then(|n| n.component_ref::<dim2::collider::Collider>())
824 .map(|c| c.native.get()),
825 exclude_rigid_body: filter
826 .exclude_collider
827 .and_then(|h| graph.try_get(h))
828 .and_then(|n| n.component_ref::<dim2::rigidbody::RigidBody>())
829 .map(|c| c.native.get()),
830 predicate: Some(&predicate),
831 };
832
833 let query = self.query.borrow_mut();
834
835 let opts = ShapeCastOptions {
836 max_time_of_impact: max_toi,
837 target_distance: 0.0,
838 stop_at_penetration,
839 compute_impact_geometry_on_penetration: true,
840 };
841
842 query
843 .cast_shape(
844 &self.bodies,
845 &self.colliders,
846 shape_pos,
847 shape_vel,
848 shape,
849 opts,
850 filter,
851 )
852 .map(|(handle, toi)| {
853 (
854 Handle::decode_from_u128(self.colliders.get(handle).unwrap().user_data),
855 TOI {
856 toi: toi.time_of_impact,
857 witness1: toi.witness1,
858 witness2: toi.witness2,
859 normal1: toi.normal1,
860 normal2: toi.normal2,
861 status: toi.status.into(),
862 },
863 )
864 })
865 }
866
867 pub(crate) fn set_rigid_body_position(
868 &mut self,
869 rigid_body: &scene::dim2::rigidbody::RigidBody,
870 new_global_transform: &Matrix4<f32>,
871 ) {
872 if let Some(native) = self.bodies.get_mut(rigid_body.native.get()) {
873 native.set_position(
874 isometry_from_global_transform(new_global_transform),
875 false,
878 );
879 }
880 }
881
882 pub(crate) fn sync_rigid_body_node(
883 &mut self,
884 rigid_body: &mut scene::dim2::rigidbody::RigidBody,
885 parent_transform: Matrix4<f32>,
886 ) {
887 if *self.enabled {
888 if let Some(native) = self.bodies.get(rigid_body.native.get()) {
889 if native.body_type() == RigidBodyType::Dynamic {
890 let local_transform: Matrix4<f32> = parent_transform
891 .try_inverse()
892 .unwrap_or_else(Matrix4::identity)
893 * isometry2_to_mat4(native.position());
894
895 let new_local_rotation = UnitQuaternion::from_matrix_eps(
896 &local_transform.basis(),
897 f32::EPSILON,
898 16,
899 UnitQuaternion::identity(),
900 );
901 let new_local_position =
902 Vector3::new(local_transform[12], local_transform[13], 0.0);
903
904 let local_transform = rigid_body.local_transform();
908 if **local_transform.position() != new_local_position
909 || **local_transform.rotation() != new_local_rotation
910 {
911 rigid_body
912 .local_transform_mut()
913 .set_position(new_local_position)
914 .set_rotation(new_local_rotation);
915 }
916
917 rigid_body
918 .lin_vel
919 .set_value_with_flags(*native.linvel(), VariableFlags::MODIFIED);
920 rigid_body
921 .ang_vel
922 .set_value_with_flags(native.angvel(), VariableFlags::MODIFIED);
923 rigid_body.sleeping = native.is_sleeping();
924 }
925 }
926 }
927 }
928
929 pub(crate) fn sync_to_rigid_body_node(
930 &mut self,
931 handle: Handle<Node>,
932 rigid_body_node: &scene::dim2::rigidbody::RigidBody,
933 ) {
934 if !rigid_body_node.is_globally_enabled() {
935 self.remove_body(rigid_body_node.native.get());
936 rigid_body_node.native.set(Default::default());
937 return;
938 }
939
940 if rigid_body_node.native.get() != RigidBodyHandle::invalid() {
944 let mut actions = rigid_body_node.actions.lock();
945 if rigid_body_node.need_sync_model() || !actions.is_empty() {
946 if let Some(native) = self.bodies.get_mut(rigid_body_node.native.get()) {
947 rigid_body_node
950 .body_type
951 .try_sync_model(|v| native.set_body_type(v.into(), false));
952 rigid_body_node
953 .lin_vel
954 .try_sync_model(|v| native.set_linvel(v, false));
955 rigid_body_node
956 .ang_vel
957 .try_sync_model(|v| native.set_angvel(v, false));
958 rigid_body_node.mass.try_sync_model(|v| {
959 native.set_additional_mass(v, true);
960 });
961 rigid_body_node
962 .lin_damping
963 .try_sync_model(|v| native.set_linear_damping(v));
964 rigid_body_node
965 .ang_damping
966 .try_sync_model(|v| native.set_angular_damping(v));
967 rigid_body_node
968 .ccd_enabled
969 .try_sync_model(|v| native.enable_ccd(v));
970 rigid_body_node.can_sleep.try_sync_model(|v| {
971 let activation = native.activation_mut();
972 if v {
973 activation.normalized_linear_threshold =
974 RigidBodyActivation::default_normalized_linear_threshold();
975 activation.angular_threshold =
976 RigidBodyActivation::default_angular_threshold();
977 } else {
978 activation.sleeping = false;
979 activation.normalized_linear_threshold = -1.0;
980 activation.angular_threshold = -1.0;
981 };
982 });
983 rigid_body_node
984 .translation_locked
985 .try_sync_model(|v| native.lock_translations(v, false));
986 rigid_body_node.rotation_locked.try_sync_model(|v| {
987 native.set_enabled_rotations(!v, !v, !v, false);
988 });
989 rigid_body_node
990 .dominance
991 .try_sync_model(|v| native.set_dominance_group(v));
992 rigid_body_node
993 .gravity_scale
994 .try_sync_model(|v| native.set_gravity_scale(v, false));
995
996 if rigid_body_node.reset_forces.replace(false) {
999 native.reset_forces(false);
1000 native.reset_torques(false);
1001 }
1002
1003 while let Some(action) = actions.pop_front() {
1004 match action {
1005 ApplyAction::Force(force) => {
1006 native.add_force(force, false);
1007 rigid_body_node.reset_forces.set(true);
1008 }
1009 ApplyAction::Torque(torque) => {
1010 native.add_torque(torque, false);
1011 rigid_body_node.reset_forces.set(true);
1012 }
1013 ApplyAction::ForceAtPoint { force, point } => {
1014 native.add_force_at_point(force, Point2::from(point), false);
1015 rigid_body_node.reset_forces.set(true);
1016 }
1017 ApplyAction::Impulse(impulse) => native.apply_impulse(impulse, false),
1018 ApplyAction::TorqueImpulse(impulse) => {
1019 native.apply_torque_impulse(impulse, false)
1020 }
1021 ApplyAction::ImpulseAtPoint { impulse, point } => {
1022 native.apply_impulse_at_point(impulse, Point2::from(point), false)
1023 }
1024 ApplyAction::WakeUp => native.wake_up(true),
1025 }
1026 }
1027 }
1028 }
1029 } else {
1030 let mut builder = RigidBodyBuilder::new(rigid_body_node.body_type().into())
1031 .position(isometry_from_global_transform(
1032 &rigid_body_node.global_transform(),
1033 ))
1034 .ccd_enabled(rigid_body_node.is_ccd_enabled())
1035 .additional_mass(rigid_body_node.mass())
1036 .angvel(*rigid_body_node.ang_vel)
1037 .linvel(*rigid_body_node.lin_vel)
1038 .linear_damping(*rigid_body_node.lin_damping)
1039 .angular_damping(*rigid_body_node.ang_damping)
1040 .can_sleep(rigid_body_node.is_can_sleep())
1041 .sleeping(rigid_body_node.is_sleeping())
1042 .dominance_group(rigid_body_node.dominance())
1043 .gravity_scale(rigid_body_node.gravity_scale());
1044
1045 if rigid_body_node.is_translation_locked() {
1046 builder = builder.lock_translations();
1047 }
1048
1049 let mut body = builder.build();
1050
1051 body.set_enabled_rotations(
1052 !rigid_body_node.is_rotation_locked(),
1053 !rigid_body_node.is_rotation_locked(),
1054 !rigid_body_node.is_rotation_locked(),
1055 false,
1056 );
1057
1058 rigid_body_node.native.set(self.add_body(handle, body));
1059
1060 Log::writeln(
1061 MessageKind::Information,
1062 format!(
1063 "Native rigid body was created for node {}",
1064 rigid_body_node.name()
1065 ),
1066 );
1067 }
1068 }
1069
1070 pub(crate) fn sync_to_collider_node(
1071 &mut self,
1072 nodes: &NodePool,
1073 handle: Handle<Node>,
1074 collider_node: &scene::dim2::collider::Collider,
1075 ) {
1076 if !collider_node.is_globally_enabled() {
1077 self.remove_collider(collider_node.native.get());
1078 collider_node.native.set(Default::default());
1079 return;
1080 }
1081
1082 let anything_changed = collider_node.needs_sync_model();
1083
1084 if collider_node.native.get() != ColliderHandle::invalid() {
1090 if anything_changed {
1091 if let Some(native) = self.colliders.get_mut(collider_node.native.get()) {
1092 collider_node
1093 .restitution
1094 .try_sync_model(|v| native.set_restitution(v));
1095 collider_node.collision_groups.try_sync_model(|v| {
1096 native.set_collision_groups(InteractionGroups::new(
1097 u32_to_group(v.memberships.0),
1098 u32_to_group(v.filter.0),
1099 ))
1100 });
1101 collider_node.solver_groups.try_sync_model(|v| {
1102 native.set_solver_groups(InteractionGroups::new(
1103 u32_to_group(v.memberships.0),
1104 u32_to_group(v.filter.0),
1105 ))
1106 });
1107 collider_node
1108 .friction
1109 .try_sync_model(|v| native.set_friction(v));
1110 collider_node
1111 .is_sensor
1112 .try_sync_model(|v| native.set_sensor(v));
1113 collider_node
1114 .friction_combine_rule
1115 .try_sync_model(|v| native.set_friction_combine_rule(v.into()));
1116 collider_node
1117 .restitution_combine_rule
1118 .try_sync_model(|v| native.set_restitution_combine_rule(v.into()));
1119 let mut remove_collider = false;
1120 collider_node.shape.try_sync_model(|v| {
1121 let inv_global_transform = isometric_global_transform(nodes, handle)
1122 .try_inverse()
1123 .unwrap_or_default();
1124
1125 if let Some(shape) =
1126 collider_shape_into_native_shape(&v, inv_global_transform, nodes)
1127 {
1128 native.set_shape(shape);
1129 } else {
1130 remove_collider = true;
1131 }
1132 });
1133 if remove_collider {
1134 self.remove_collider(collider_node.native.get());
1135 collider_node.native.set(ColliderHandle::invalid());
1136 }
1137 }
1138 }
1139 } else if let Some(parent_body) = nodes
1140 .try_borrow(collider_node.parent())
1141 .and_then(|n| n.cast::<dim2::rigidbody::RigidBody>())
1142 {
1143 if parent_body.native.get() != RigidBodyHandle::invalid() {
1144 let rigid_body_native = parent_body.native.get();
1145 let inv_global_transform = isometric_global_transform(nodes, handle)
1146 .try_inverse()
1147 .unwrap();
1148 if let Some(shape) = collider_shape_into_native_shape(
1149 collider_node.shape(),
1150 inv_global_transform,
1151 nodes,
1152 ) {
1153 let mut builder = ColliderBuilder::new(shape)
1154 .position(Isometry2 {
1155 rotation: UnitComplex::from_angle(
1156 collider_node.local_transform().rotation().euler_angles().2,
1157 ),
1158 translation: Translation2 {
1159 vector: collider_node.local_transform().position().xy(),
1160 },
1161 })
1162 .friction(collider_node.friction())
1163 .restitution(collider_node.restitution())
1164 .collision_groups(InteractionGroups::new(
1165 u32_to_group(collider_node.collision_groups().memberships.0),
1166 u32_to_group(collider_node.collision_groups().filter.0),
1167 ))
1168 .friction_combine_rule(collider_node.friction_combine_rule().into())
1169 .restitution_combine_rule(collider_node.restitution_combine_rule().into())
1170 .solver_groups(InteractionGroups::new(
1171 u32_to_group(collider_node.solver_groups().memberships.0),
1172 u32_to_group(collider_node.solver_groups().filter.0),
1173 ))
1174 .sensor(collider_node.is_sensor());
1175
1176 if let Some(density) = collider_node.density() {
1177 builder = builder.density(density);
1178 }
1179
1180 let native_handle =
1181 self.add_collider(handle, rigid_body_native, builder.build());
1182
1183 collider_node.native.set(native_handle);
1184
1185 Log::writeln(
1186 MessageKind::Information,
1187 format!(
1188 "Native collider was created for node {}",
1189 collider_node.name()
1190 ),
1191 );
1192 }
1193 }
1194 }
1195 }
1196
1197 pub(crate) fn sync_to_joint_node(
1198 &mut self,
1199 nodes: &NodePool,
1200 handle: Handle<Node>,
1201 joint: &scene::dim2::joint::Joint,
1202 ) {
1203 if !joint.is_globally_enabled() {
1204 self.remove_joint(joint.native.get());
1205 joint.native.set(ImpulseJointHandle(Default::default()));
1206 return;
1207 }
1208
1209 if let Some(native) = self.joints.set.get_mut(joint.native.get(), false) {
1210 joint.body1.try_sync_model(|v| {
1211 if let Some(rigid_body_node) = nodes
1212 .try_borrow(v)
1213 .and_then(|n| n.cast::<dim2::rigidbody::RigidBody>())
1214 {
1215 native.body1 = rigid_body_node.native.get();
1216 }
1217 });
1218 joint.body2.try_sync_model(|v| {
1219 if let Some(rigid_body_node) = nodes
1220 .try_borrow(v)
1221 .and_then(|n| n.cast::<dim2::rigidbody::RigidBody>())
1222 {
1223 native.body2 = rigid_body_node.native.get();
1224 }
1225 });
1226 joint.params.try_sync_model(|v| {
1227 native.data =
1228 convert_joint_params(v, native.data.local_frame1, native.data.local_frame2)
1230 });
1231 joint.contacts_enabled.try_sync_model(|v| {
1232 native.data.set_contacts_enabled(v);
1233 });
1234 let mut local_frames = joint.local_frames.borrow_mut();
1235 if local_frames.is_none() {
1236 if let (Some(body1), Some(body2)) = (
1237 nodes
1238 .try_borrow(joint.body1())
1239 .and_then(|n| n.cast::<scene::rigidbody::RigidBody>()),
1240 nodes
1241 .try_borrow(joint.body2())
1242 .and_then(|n| n.cast::<scene::rigidbody::RigidBody>()),
1243 ) {
1244 let (local_frame1, local_frame2) = calculate_local_frames(joint, body1, body2);
1245 native.data =
1246 convert_joint_params((*joint.params).clone(), local_frame1, local_frame2);
1247 *local_frames = Some(JointLocalFrames::new(&local_frame1, &local_frame2));
1248 }
1249 }
1250 } else {
1251 let body1_handle = joint.body1();
1252 let body2_handle = joint.body2();
1253 let params = joint.params().clone();
1254
1255 if let (Some(body1), Some(body2)) = (
1257 nodes
1258 .try_borrow(body1_handle)
1259 .and_then(|n| n.cast::<dim2::rigidbody::RigidBody>()),
1260 nodes
1261 .try_borrow(body2_handle)
1262 .and_then(|n| n.cast::<dim2::rigidbody::RigidBody>()),
1263 ) {
1264 let mut local_frames = joint.local_frames.borrow_mut();
1266 let (local_frame1, local_frame2) = local_frames
1267 .clone()
1268 .map(|frames| {
1269 (
1270 Isometry2 {
1271 rotation: frames.body1.rotation,
1272 translation: Translation2 {
1273 vector: frames.body1.position,
1274 },
1275 },
1276 Isometry2 {
1277 rotation: frames.body2.rotation,
1278 translation: Translation2 {
1279 vector: frames.body2.position,
1280 },
1281 },
1282 )
1283 })
1284 .unwrap_or_else(|| calculate_local_frames(joint, body1, body2));
1285
1286 let native_body1 = body1.native.get();
1287 let native_body2 = body2.native.get();
1288
1289 assert!(self.bodies.get(native_body1).is_some());
1290 assert!(self.bodies.get(native_body2).is_some());
1291
1292 let mut native_joint = convert_joint_params(params, local_frame1, local_frame2);
1293 native_joint.contacts_enabled = joint.is_contacts_enabled();
1294 let native_handle =
1295 self.add_joint(handle, native_body1, native_body2, native_joint);
1296
1297 joint.native.set(native_handle);
1298 *local_frames = Some(JointLocalFrames::new(&local_frame1, &local_frame2));
1299
1300 Log::writeln(
1301 MessageKind::Information,
1302 format!("Native joint was created for node {}", joint.name()),
1303 );
1304 }
1305 }
1306 }
1307
1308 pub(crate) fn intersections_with(
1310 &self,
1311 collider: ColliderHandle,
1312 ) -> impl Iterator<Item = IntersectionPair> + '_ {
1313 self.narrow_phase
1314 .intersection_pairs_with(collider)
1315 .filter_map(|(collider1, collider2, intersecting)| {
1316 Some(IntersectionPair {
1317 collider1: Handle::decode_from_u128(self.colliders.get(collider1)?.user_data),
1318 collider2: Handle::decode_from_u128(self.colliders.get(collider2)?.user_data),
1319 has_any_active_contact: intersecting,
1320 })
1321 })
1322 }
1323
1324 pub(crate) fn contacts_with(
1326 &self,
1327 collider: ColliderHandle,
1328 ) -> impl Iterator<Item = ContactPair> + '_ {
1329 self.narrow_phase
1330 .contact_pairs_with(collider)
1331 .filter_map(|c| ContactPair::from_native(c, self))
1332 }
1333
1334 pub fn contacts(&self) -> impl Iterator<Item = ContactPair> + '_ {
1336 self.narrow_phase
1337 .contact_pairs()
1338 .filter_map(|c| ContactPair::from_native(c, self))
1339 }
1340}
1341
1342impl Default for PhysicsWorld {
1343 fn default() -> Self {
1344 Self::new()
1345 }
1346}
1347
1348impl Debug for PhysicsWorld {
1349 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1350 write!(f, "PhysicsWorld")
1351 }
1352}