Skip to main content

fyrox_impl/scene/graph/
physics.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Scene physics module.
22
23use crate::{
24    core::{
25        algebra::{
26            Isometry3, Matrix4, Point3, Translation, Translation3, UnitQuaternion, UnitVector3,
27            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        uuid_provider,
37        variable::{InheritableVariable, VariableFlags},
38        visitor::prelude::*,
39        BiDirHashMap, SafeLock,
40    },
41    scene::{
42        self,
43        collider::{self, ColliderShape, GeometrySource},
44        debug::SceneDrawingContext,
45        graph::{isometric_global_transform, Graph, NodePool},
46        joint::{JointLocalFrames, JointMotorParams, JointParams},
47        mesh::{
48            buffer::{VertexAttributeUsage, VertexReadTrait},
49            Mesh,
50        },
51        node::{Node, NodeTrait},
52        rigidbody::{self, ApplyAction, RigidBodyMassPropertiesType},
53        terrain::{Chunk, Terrain},
54    },
55    utils::raw_mesh::{RawMeshBuilder, RawVertex},
56};
57use rapier3d::geometry::Array2;
58use rapier3d::{
59    dynamics::{
60        CCDSolver, GenericJoint, GenericJointBuilder, ImpulseJointHandle, ImpulseJointSet,
61        IslandManager, JointAxesMask, MultibodyJointHandle, MultibodyJointSet, RigidBody,
62        RigidBodyActivation, RigidBodyBuilder, RigidBodyHandle, RigidBodySet, RigidBodyType,
63    },
64    geometry::{
65        Collider, ColliderBuilder, ColliderHandle, ColliderSet, Cuboid, DefaultBroadPhase,
66        InteractionGroups, NarrowPhase, Ray, SharedShape,
67    },
68    parry::{query::ShapeCastOptions, shape::HeightField},
69    pipeline::{DebugRenderPipeline, EventHandler, PhysicsPipeline},
70    prelude::{HeightFieldCellStatus, JointAxis, MassProperties},
71};
72use std::{
73    cell::Cell,
74    cmp::Ordering,
75    fmt::{Debug, Formatter},
76    hash::Hash,
77    sync::Arc,
78    time::Duration,
79};
80use strum_macros::{AsRefStr, EnumString, VariantNames};
81
82use fyrox_graph::{SceneGraph, SceneGraphNode};
83pub use rapier3d::geometry::shape::*;
84use rapier3d::math::{Pose3, Vec3};
85use rapier3d::parry::query::DefaultQueryDispatcher;
86use rapier3d::prelude::FrictionModel;
87
88/// Shape-dependent identifier.
89#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
90pub enum FeatureId {
91    /// Shape-dependent identifier of a vertex.
92    Vertex(u32),
93    /// Shape-dependent identifier of an edge.
94    Edge(u32),
95    /// Shape-dependent identifier of a face.
96    Face(u32),
97    /// Unknown identifier.
98    Unknown,
99}
100
101impl From<rapier3d::geometry::FeatureId> for FeatureId {
102    fn from(v: rapier3d::geometry::FeatureId) -> Self {
103        match v {
104            rapier3d::geometry::FeatureId::Vertex(v) => FeatureId::Vertex(v),
105            rapier3d::geometry::FeatureId::Edge(v) => FeatureId::Edge(v),
106            rapier3d::geometry::FeatureId::Face(v) => FeatureId::Face(v),
107            rapier3d::geometry::FeatureId::Unknown => FeatureId::Unknown,
108        }
109    }
110}
111
112impl From<rapier2d::geometry::FeatureId> for FeatureId {
113    fn from(v: rapier2d::geometry::FeatureId) -> Self {
114        match v {
115            rapier2d::geometry::FeatureId::Vertex(v) => FeatureId::Vertex(v),
116            rapier2d::geometry::FeatureId::Face(v) => FeatureId::Face(v),
117            rapier2d::geometry::FeatureId::Unknown => FeatureId::Unknown,
118        }
119    }
120}
121
122/// Rules used to combine two coefficients.
123///
124/// # Notes
125///
126/// This is used to determine the effective restitution and friction coefficients for a contact
127/// between two colliders. Each collider has its combination rule of type `CoefficientCombineRule`,
128/// the rule actually used is given by `max(first_combine_rule, second_combine_rule)`.
129#[derive(
130    Copy, Clone, Debug, PartialEq, Eq, Visit, Reflect, VariantNames, EnumString, AsRefStr, Default,
131)]
132#[repr(u32)]
133pub enum CoefficientCombineRule {
134    /// The two coefficients are averaged.
135    #[default]
136    Average = 0,
137    /// The smallest coefficient is chosen.
138    Min,
139    /// The two coefficients are multiplied.
140    Multiply,
141    /// The greatest coefficient is chosen.
142    Max,
143    /// The clamped sum of the two coefficients.
144    ClampedSum = 4,
145}
146
147uuid_provider!(CoefficientCombineRule = "775d5598-c283-4b44-9cc0-2e23dc8936f4");
148
149impl From<rapier3d::dynamics::CoefficientCombineRule> for CoefficientCombineRule {
150    fn from(v: rapier3d::dynamics::CoefficientCombineRule) -> Self {
151        match v {
152            rapier3d::dynamics::CoefficientCombineRule::Average => CoefficientCombineRule::Average,
153            rapier3d::dynamics::CoefficientCombineRule::Min => CoefficientCombineRule::Min,
154            rapier3d::dynamics::CoefficientCombineRule::Multiply => {
155                CoefficientCombineRule::Multiply
156            }
157            rapier3d::dynamics::CoefficientCombineRule::Max => CoefficientCombineRule::Max,
158            rapier3d::dynamics::CoefficientCombineRule::ClampedSum => {
159                CoefficientCombineRule::ClampedSum
160            }
161        }
162    }
163}
164
165impl Into<rapier3d::dynamics::CoefficientCombineRule> for CoefficientCombineRule {
166    fn into(self) -> rapier3d::dynamics::CoefficientCombineRule {
167        match self {
168            CoefficientCombineRule::Average => rapier3d::dynamics::CoefficientCombineRule::Average,
169            CoefficientCombineRule::Min => rapier3d::dynamics::CoefficientCombineRule::Min,
170            CoefficientCombineRule::Multiply => {
171                rapier3d::dynamics::CoefficientCombineRule::Multiply
172            }
173            CoefficientCombineRule::Max => rapier3d::dynamics::CoefficientCombineRule::Max,
174            CoefficientCombineRule::ClampedSum => {
175                rapier3d::dynamics::CoefficientCombineRule::ClampedSum
176            }
177        }
178    }
179}
180
181impl Into<rapier2d::dynamics::CoefficientCombineRule> for CoefficientCombineRule {
182    fn into(self) -> rapier2d::dynamics::CoefficientCombineRule {
183        match self {
184            CoefficientCombineRule::Average => rapier2d::dynamics::CoefficientCombineRule::Average,
185            CoefficientCombineRule::Min => rapier2d::dynamics::CoefficientCombineRule::Min,
186            CoefficientCombineRule::Multiply => {
187                rapier2d::dynamics::CoefficientCombineRule::Multiply
188            }
189            CoefficientCombineRule::Max => rapier2d::dynamics::CoefficientCombineRule::Max,
190            CoefficientCombineRule::ClampedSum => {
191                rapier2d::dynamics::CoefficientCombineRule::ClampedSum
192            }
193        }
194    }
195}
196
197/// Performance statistics for the physics part of the engine.
198#[derive(Debug, Default, Clone)]
199pub struct PhysicsPerformanceStatistics {
200    /// A time that was needed to perform a single simulation step.
201    pub step_time: Duration,
202
203    /// A time that was needed to perform all ray casts.
204    pub total_ray_cast_time: Cell<Duration>,
205}
206
207impl PhysicsPerformanceStatistics {
208    /// Resets performance statistics to default values.
209    pub fn reset(&mut self) {
210        *self = Default::default();
211    }
212
213    /// Returns total amount of time for every part of statistics.
214    pub fn total(&self) -> Duration {
215        self.step_time + self.total_ray_cast_time.get()
216    }
217}
218
219/// A ray intersection result.
220#[derive(Debug, Clone, PartialEq)]
221pub struct Intersection {
222    /// A handle of the collider with which intersection was detected.
223    pub collider: Handle<collider::Collider>,
224
225    /// A normal at the intersection position.
226    pub normal: Vector3<f32>,
227
228    /// A position of the intersection in world coordinates.
229    pub position: Point3<f32>,
230
231    /// Additional data that contains a kind of the feature with which
232    /// intersection was detected as well as its index.
233    ///
234    /// # Important notes.
235    ///
236    /// FeatureId::Face might have index that is greater than amount of triangles in
237    /// a triangle mesh, this means that intersection was detected from "back" side of
238    /// a face. To "fix" that index, simply subtract amount of triangles of a triangle
239    /// mesh from the value.
240    pub feature: FeatureId,
241
242    /// Distance from the ray origin.
243    pub toi: f32,
244}
245
246/// A set of options for the ray cast.
247pub struct RayCastOptions {
248    /// A ray origin.
249    pub ray_origin: Point3<f32>,
250
251    /// A ray direction. Can be non-normalized.
252    pub ray_direction: Vector3<f32>,
253
254    /// Maximum distance of cast.
255    pub max_len: f32,
256
257    /// Groups to check.
258    pub groups: collider::InteractionGroups,
259
260    /// Whether to sort intersections from closest to farthest.
261    pub sort_results: bool,
262}
263
264/// A trait for ray cast results storage. It has two implementations: Vec and ArrayVec.
265/// Latter is needed for the cases where you need to avoid runtime memory allocations
266/// and do everything on stack.
267pub trait QueryResultsStorage {
268    /// Pushes new intersection in the storage. Returns true if intersection was
269    /// successfully inserted, false otherwise.
270    fn push(&mut self, intersection: Intersection) -> bool;
271
272    /// Clears the storage.
273    fn clear(&mut self);
274
275    /// Sorts intersections by given compare function.
276    fn sort_intersections_by<C: FnMut(&Intersection, &Intersection) -> Ordering>(&mut self, cmp: C);
277}
278
279impl QueryResultsStorage for Vec<Intersection> {
280    fn push(&mut self, intersection: Intersection) -> bool {
281        self.push(intersection);
282        true
283    }
284
285    fn clear(&mut self) {
286        self.clear()
287    }
288
289    fn sort_intersections_by<C>(&mut self, cmp: C)
290    where
291        C: FnMut(&Intersection, &Intersection) -> Ordering,
292    {
293        self.sort_by(cmp);
294    }
295}
296
297impl<const CAP: usize> QueryResultsStorage for ArrayVec<Intersection, CAP> {
298    fn push(&mut self, intersection: Intersection) -> bool {
299        self.try_push(intersection).is_ok()
300    }
301
302    fn clear(&mut self) {
303        self.clear()
304    }
305
306    fn sort_intersections_by<C>(&mut self, cmp: C)
307    where
308        C: FnMut(&Intersection, &Intersection) -> Ordering,
309    {
310        self.sort_by(cmp);
311    }
312}
313
314/// Data of the contact.
315#[derive(Debug, Clone, PartialEq)]
316pub struct ContactData {
317    /// The contact point in the local-space of the first shape.
318    pub local_p1: Vector3<f32>,
319    /// The contact point in the local-space of the second shape.
320    pub local_p2: Vector3<f32>,
321    /// The distance between the two contact points.
322    pub dist: f32,
323    /// The impulse, along the contact normal, applied by this contact to the first collider's rigid-body.
324    /// The impulse applied to the second collider's rigid-body is given by `-impulse`.
325    pub impulse: f32,
326    /// The friction impulses along the basis orthonormal to the contact normal, applied to the first
327    /// collider's rigid-body.
328    pub tangent_impulse: Vector2<f32>,
329}
330
331/// A contact manifold between two colliders.
332#[derive(Debug, Clone, PartialEq)]
333pub struct ContactManifold {
334    /// The contacts points.
335    pub points: Vec<ContactData>,
336    /// The contact normal of all the contacts of this manifold, expressed in the local space of the first shape.
337    pub local_n1: Vector3<f32>,
338    /// The contact normal of all the contacts of this manifold, expressed in the local space of the second shape.
339    pub local_n2: Vector3<f32>,
340    /// The first rigid-body involved in this contact manifold.
341    pub rigid_body1: Handle<rigidbody::RigidBody>,
342    /// The second rigid-body involved in this contact manifold.
343    pub rigid_body2: Handle<rigidbody::RigidBody>,
344    /// The world-space contact normal shared by all the contact in this contact manifold.
345    pub normal: Vector3<f32>,
346}
347
348/// Contact info for pair of colliders.
349#[derive(Debug, Clone, PartialEq)]
350pub struct ContactPair {
351    /// The first collider involved in the contact pair.
352    pub collider1: Handle<collider::Collider>,
353    /// The second collider involved in the contact pair.
354    pub collider2: Handle<collider::Collider>,
355    /// The set of contact manifolds between the two colliders.
356    /// All contact manifold contain themselves contact points between the colliders.
357    pub manifolds: Vec<ContactManifold>,
358    /// Is there any active contact in this contact pair?
359    pub has_any_active_contact: bool,
360}
361
362impl ContactPair {
363    /// Given the handle of a collider that is expected to be part of the collision,
364    /// return the other node involved in the collision.
365    /// Often one will have a list of contact pairs for some collider, but that collider
366    /// may be the first member of some pairs and the second member of other pairs.
367    /// This method simplifies determining which objects a collider has collided with.
368    #[inline]
369    pub fn other(&self, subject: Handle<collider::Collider>) -> Handle<collider::Collider> {
370        if subject == self.collider1 {
371            self.collider2
372        } else {
373            self.collider1
374        }
375    }
376
377    fn from_native(c: &rapier3d::geometry::ContactPair, physics: &PhysicsWorld) -> Option<Self> {
378        Some(ContactPair {
379            collider1: Handle::decode_from_u128(physics.colliders.get(c.collider1)?.user_data),
380            collider2: Handle::decode_from_u128(physics.colliders.get(c.collider2)?.user_data),
381            manifolds: c
382                .manifolds
383                .iter()
384                .filter_map(|m| {
385                    Some(ContactManifold {
386                        points: m
387                            .points
388                            .iter()
389                            .map(|p| ContactData {
390                                local_p1: p.local_p1.into(),
391                                local_p2: p.local_p2.into(),
392                                dist: p.dist,
393                                impulse: p.data.impulse,
394                                tangent_impulse: p.data.tangent_impulse,
395                            })
396                            .collect(),
397                        local_n1: m.local_n1.into(),
398                        local_n2: m.local_n2.into(),
399                        rigid_body1: m.data.rigid_body1.and_then(|h| {
400                            physics
401                                .bodies
402                                .get(h)
403                                .map(|b| Handle::decode_from_u128(b.user_data))
404                        })?,
405                        rigid_body2: m.data.rigid_body2.and_then(|h| {
406                            physics
407                                .bodies
408                                .get(h)
409                                .map(|b| Handle::decode_from_u128(b.user_data))
410                        })?,
411                        normal: m.data.normal.into(),
412                    })
413                })
414                .collect(),
415            has_any_active_contact: c.has_any_active_contact(),
416        })
417    }
418}
419
420/// Intersection info for pair of colliders.
421#[derive(Debug, Clone, PartialEq)]
422pub struct IntersectionPair {
423    /// The first collider involved in the contact pair.
424    pub collider1: Handle<collider::Collider>,
425    /// The second collider involved in the contact pair.
426    pub collider2: Handle<collider::Collider>,
427    /// Is there any active contact in this contact pair?
428    /// When false, this pair may just mean that bounding boxes are touching.
429    pub has_any_active_contact: bool,
430}
431
432impl IntersectionPair {
433    /// Given the handle of a collider that is expected to be part of the collision,
434    /// return the other node involved in the collision.
435    /// Often one will have a list of contact pairs for some collider, but that collider
436    /// may be the first member of some pairs and the second member of other pairs.
437    /// This method simplifies determining which objects a collider has collided with.
438    #[inline]
439    pub fn other(&self, subject: Handle<collider::Collider>) -> Handle<collider::Collider> {
440        if subject == self.collider1 {
441            self.collider2
442        } else {
443            self.collider1
444        }
445    }
446}
447
448pub(super) struct Container<S, A>
449where
450    A: Hash + Eq + Clone,
451{
452    set: S,
453    map: BiDirHashMap<A, Handle<Node>>,
454}
455
456fn convert_joint_params(
457    params: scene::joint::JointParams,
458    local_frame1: Isometry3<f32>,
459    local_frame2: Isometry3<f32>,
460) -> GenericJoint {
461    let locked_axis = match params {
462        JointParams::BallJoint(_) => JointAxesMask::LOCKED_SPHERICAL_AXES,
463        JointParams::FixedJoint(_) => JointAxesMask::LOCKED_FIXED_AXES,
464        JointParams::PrismaticJoint(_) => JointAxesMask::LOCKED_PRISMATIC_AXES,
465        JointParams::RevoluteJoint(_) => JointAxesMask::LOCKED_REVOLUTE_AXES,
466    };
467
468    let mut joint = GenericJointBuilder::new(locked_axis)
469        .local_frame1(local_frame1.into())
470        .local_frame2(local_frame2.into())
471        .build();
472
473    match params {
474        scene::joint::JointParams::BallJoint(v) => {
475            if v.x_limits_enabled {
476                joint.set_limits(
477                    JointAxis::AngX,
478                    [v.x_limits_angles.start, v.x_limits_angles.end],
479                );
480            }
481            if v.y_limits_enabled {
482                joint.set_limits(
483                    JointAxis::AngY,
484                    [v.y_limits_angles.start, v.y_limits_angles.end],
485                );
486            }
487            if v.z_limits_enabled {
488                joint.set_limits(
489                    JointAxis::AngZ,
490                    [v.z_limits_angles.start, v.z_limits_angles.end],
491                );
492            }
493        }
494        scene::joint::JointParams::FixedJoint(_) => {}
495        scene::joint::JointParams::PrismaticJoint(v) => {
496            if v.limits_enabled {
497                joint.set_limits(JointAxis::LinX, [v.limits.start, v.limits.end]);
498            }
499        }
500        scene::joint::JointParams::RevoluteJoint(v) => {
501            if v.limits_enabled {
502                joint.set_limits(JointAxis::AngX, [v.limits.start, v.limits.end]);
503            }
504        }
505    }
506
507    joint
508}
509
510/// Creates new trimesh collider shape from given mesh node. It also bakes scale into
511/// vertices of trimesh because rapier does not support collider scaling yet.
512fn make_trimesh(
513    owner_inv_transform: Matrix4<f32>,
514    owner: Handle<Node>,
515    sources: &[GeometrySource],
516    nodes: &NodePool,
517) -> Option<SharedShape> {
518    let mut mesh_builder = RawMeshBuilder::new(0, 0);
519
520    // Create inverse transform that will discard rotation and translation, but leave scaling and
521    // other parameters of global transform.
522    // When global transform of node is combined with this transform, we'll get relative transform
523    // with scale baked in. We need to do this because root's transform will be synced with body's
524    // but we don't want to bake entire transform including root's transform.
525    let root_inv_transform = owner_inv_transform;
526
527    for &source in sources {
528        if let Ok(mesh) = nodes.try_get_component_of_type::<Mesh>(source.0) {
529            let global_transform = root_inv_transform * mesh.global_transform();
530
531            for surface in mesh.surfaces() {
532                let shared_data = surface.data();
533                if !shared_data.is_ok() {
534                    continue;
535                }
536                let shared_data = shared_data.data_ref();
537
538                let vertices = &shared_data.vertex_buffer;
539                for triangle in shared_data.geometry_buffer.iter() {
540                    let a = RawVertex::from(
541                        global_transform
542                            .transform_point(&Point3::from(
543                                vertices
544                                    .get(triangle[0] as usize)
545                                    .unwrap()
546                                    .read_3_f32(VertexAttributeUsage::Position)
547                                    .unwrap(),
548                            ))
549                            .coords,
550                    );
551                    let b = RawVertex::from(
552                        global_transform
553                            .transform_point(&Point3::from(
554                                vertices
555                                    .get(triangle[1] as usize)
556                                    .unwrap()
557                                    .read_3_f32(VertexAttributeUsage::Position)
558                                    .unwrap(),
559                            ))
560                            .coords,
561                    );
562                    let c = RawVertex::from(
563                        global_transform
564                            .transform_point(&Point3::from(
565                                vertices
566                                    .get(triangle[2] as usize)
567                                    .unwrap()
568                                    .read_3_f32(VertexAttributeUsage::Position)
569                                    .unwrap(),
570                            ))
571                            .coords,
572                    );
573
574                    mesh_builder.insert(a);
575                    mesh_builder.insert(b);
576                    mesh_builder.insert(c);
577                }
578            }
579        }
580    }
581
582    let raw_mesh = mesh_builder.build();
583
584    let vertices: Vec<Vec3> = raw_mesh
585        .vertices
586        .into_iter()
587        .map(|v| Vec3::new(v.x, v.y, v.z))
588        .collect();
589
590    let indices = raw_mesh
591        .triangles
592        .into_iter()
593        .map(|t| [t.0[0], t.0[1], t.0[2]])
594        .collect::<Vec<_>>();
595
596    if indices.is_empty() {
597        Log::writeln(
598            MessageKind::Warning,
599            format!(
600                "Failed to create triangle mesh collider for {}, it has no vertices!",
601                nodes[owner].name()
602            ),
603        );
604
605        SharedShape::trimesh(vec![Vec3::new(0.0, 0.0, 0.0)], vec![[0, 0, 0]]).ok()
606    } else {
607        SharedShape::trimesh(vertices, indices).ok()
608    }
609}
610
611/// Creates new convex polyhedron collider shape from given mesh node. It also bakes scale into
612/// vertices of trimesh because rapier does not support collider scaling yet.
613fn make_polyhedron_shape(owner_inv_transform: Matrix4<f32>, mesh: &Mesh) -> SharedShape {
614    let mut mesh_builder = RawMeshBuilder::new(0, 0);
615
616    // Create inverse transform that will discard rotation and translation, but leave scaling and
617    // other parameters of global transform.
618    // When global transform of node is combined with this transform, we'll get relative transform
619    // with scale baked in. We need to do this because root's transform will be synced with body's
620    // but we don't want to bake entire transform including root's transform.
621    let root_inv_transform = owner_inv_transform;
622
623    let global_transform = root_inv_transform * mesh.global_transform();
624
625    for surface in mesh.surfaces() {
626        let shared_data = surface.data();
627        let shared_data = shared_data.data_ref();
628
629        let vertices = &shared_data.vertex_buffer;
630        for triangle in shared_data.geometry_buffer.iter() {
631            let a = RawVertex::from(
632                global_transform
633                    .transform_point(&Point3::from(
634                        vertices
635                            .get(triangle[0] as usize)
636                            .unwrap()
637                            .read_3_f32(VertexAttributeUsage::Position)
638                            .unwrap(),
639                    ))
640                    .coords,
641            );
642            let b = RawVertex::from(
643                global_transform
644                    .transform_point(&Point3::from(
645                        vertices
646                            .get(triangle[1] as usize)
647                            .unwrap()
648                            .read_3_f32(VertexAttributeUsage::Position)
649                            .unwrap(),
650                    ))
651                    .coords,
652            );
653            let c = RawVertex::from(
654                global_transform
655                    .transform_point(&Point3::from(
656                        vertices
657                            .get(triangle[2] as usize)
658                            .unwrap()
659                            .read_3_f32(VertexAttributeUsage::Position)
660                            .unwrap(),
661                    ))
662                    .coords,
663            );
664
665            mesh_builder.insert(a);
666            mesh_builder.insert(b);
667            mesh_builder.insert(c);
668        }
669    }
670
671    let raw_mesh = mesh_builder.build();
672
673    let vertices: Vec<Vec3> = raw_mesh
674        .vertices
675        .into_iter()
676        .map(|v| Vec3::new(v.x, v.y, v.z))
677        .collect();
678
679    let indices = raw_mesh
680        .triangles
681        .into_iter()
682        .map(|t| [t.0[0], t.0[1], t.0[2]])
683        .collect::<Vec<_>>();
684
685    SharedShape::convex_decomposition(&vertices, &indices)
686}
687
688/// Creates height field shape from given terrain.
689fn make_heightfield(terrain: &Terrain) -> Option<SharedShape> {
690    assert!(!terrain.chunks_ref().is_empty());
691
692    // HACK: Temporary solution for https://github.com/FyroxEngine/Fyrox/issues/365
693    let scale = terrain.local_transform().scale();
694
695    // Count rows and columns.
696    let height_map_size = terrain.height_map_size();
697    let chunk_size = height_map_size.map(|x| x - 3);
698    let chunk_min = terrain
699        .chunks_ref()
700        .iter()
701        .map(Chunk::grid_position)
702        .reduce(|a, b| a.inf(&b));
703    let chunk_max = terrain
704        .chunks_ref()
705        .iter()
706        .map(Chunk::grid_position)
707        .reduce(|a, b| a.sup(&b));
708    let (Some(chunk_min), Some(chunk_max)) = (chunk_min, chunk_max) else {
709        return None;
710    };
711    let row_range = chunk_max.y - chunk_min.y + 1;
712    let col_range = chunk_max.x - chunk_min.x + 1;
713    let nrows = chunk_size.y * row_range as u32 + 1;
714    let ncols = chunk_size.x * col_range as u32 + 1;
715
716    // Combine height map of each chunk into bigger one.
717    let mut data = vec![0.0; (nrows * ncols) as usize];
718    for chunk in terrain.chunks_ref() {
719        let texture = chunk.heightmap().data_ref();
720        let height_map = texture.data_of_type::<f32>().unwrap();
721        let pos = (chunk.grid_position() - chunk_min).map(|x| x as u32);
722        let (ox, oy) = (pos.x * chunk_size.x, pos.y * chunk_size.y);
723        for iy in 0..height_map_size.y - 2 {
724            for ix in 0..height_map_size.x - 2 {
725                let (x, y) = (ix + 1, iy + 1);
726                let value = height_map[(y * height_map_size.x + x) as usize] * scale.y;
727                data[((ox + ix) * nrows + oy + iy) as usize] = value;
728            }
729        }
730    }
731    let x_scale = terrain.chunk_size().x * scale.x * col_range as f32;
732    let z_scale = terrain.chunk_size().y * scale.z * row_range as f32;
733    let mut hf = HeightField::new(
734        Array2::new(nrows as usize, ncols as usize, data),
735        Vec3::new(x_scale, 1.0, z_scale),
736    );
737    if terrain.holes_enabled() {
738        let hole_mask_size = terrain.hole_mask_size();
739        for chunk in terrain.chunks_ref() {
740            let texture = chunk.hole_mask().map(|t| t.data_ref());
741            let hole_mask = texture.as_ref().map(|t| t.data_of_type::<u8>().unwrap());
742            let pos = (chunk.grid_position() - chunk_min).map(|x| x as u32);
743            let (ox, oy) = (pos.x * chunk_size.x, pos.y * chunk_size.y);
744
745            for iy in 0..hole_mask_size.y {
746                for ix in 0..hole_mask_size.x {
747                    let is_hole = hole_mask
748                        .map(|m| m[(iy * hole_mask_size.x + ix) as usize] < 128)
749                        .unwrap_or_default();
750                    let (x, y) = (ox + ix, oy + iy);
751                    if is_hole {
752                        hf.set_cell_status(
753                            y as usize,
754                            x as usize,
755                            HeightFieldCellStatus::CELL_REMOVED,
756                        );
757                    } else {
758                        hf.set_cell_status(y as usize, x as usize, HeightFieldCellStatus::empty());
759                    }
760                }
761            }
762        }
763    }
764    // HeightField colliders naturally have their origin at their centers,
765    // so to position the collider correctly we must add half of the size to x and z.
766    Some(SharedShape::new(hf))
767}
768
769// Converts descriptor in a shared shape.
770fn collider_shape_into_native_shape(
771    shape: &ColliderShape,
772    owner_inv_global_transform: Matrix4<f32>,
773    owner_collider: Handle<Node>,
774    pool: &NodePool,
775) -> Option<SharedShape> {
776    match shape {
777        ColliderShape::Ball(ball) => Some(SharedShape::ball(ball.radius)),
778
779        ColliderShape::Cylinder(cylinder) => {
780            Some(SharedShape::cylinder(cylinder.half_height, cylinder.radius))
781        }
782        ColliderShape::Cone(cone) => Some(SharedShape::cone(cone.half_height, cone.radius)),
783        ColliderShape::Cuboid(cuboid) => Some(SharedShape(Arc::new(Cuboid::new(
784            cuboid.half_extents.into(),
785        )))),
786        ColliderShape::Capsule(capsule) => Some(SharedShape::capsule(
787            capsule.begin.into(),
788            capsule.end.into(),
789            capsule.radius,
790        )),
791        ColliderShape::Segment(segment) => Some(SharedShape::segment(
792            segment.begin.into(),
793            segment.end.into(),
794        )),
795        ColliderShape::Triangle(triangle) => Some(SharedShape::triangle(
796            triangle.a.into(),
797            triangle.b.into(),
798            triangle.c.into(),
799        )),
800        ColliderShape::Trimesh(trimesh) => {
801            if trimesh.sources.is_empty() {
802                None
803            } else {
804                make_trimesh(
805                    owner_inv_global_transform,
806                    owner_collider,
807                    &trimesh.sources,
808                    pool,
809                )
810            }
811        }
812        ColliderShape::Heightfield(heightfield) => pool
813            .try_get_component_of_type::<Terrain>(heightfield.geometry_source.0)
814            .ok()
815            .and_then(make_heightfield),
816        ColliderShape::Polyhedron(polyhedron) => pool
817            .try_get_component_of_type::<Mesh>(polyhedron.geometry_source.0)
818            .ok()
819            .map(|mesh| make_polyhedron_shape(owner_inv_global_transform, mesh)),
820    }
821}
822
823/// Parameters for a time-step of the physics engine.
824///
825/// # Notes
826///
827/// This is almost one-to-one copy of Rapier's integration parameters with custom attributes for
828/// each parameter.
829#[derive(Copy, Clone, Visit, Reflect, Debug, PartialEq)]
830#[visit(optional)]
831pub struct IntegrationParameters {
832    /// The time step length, default is None - this means that physics simulation will use engine's
833    /// time step.
834    #[reflect(min_value = 0.0)]
835    pub dt: Option<f32>,
836
837    /// Minimum timestep size when using CCD with multiple substeps (default `1.0 / 60.0 / 100.0`)
838    ///
839    /// When CCD with multiple substeps is enabled, the timestep is subdivided into smaller pieces.
840    /// This timestep subdivision won't generate timestep lengths smaller than `min_ccd_dt`.
841    ///
842    /// Setting this to a large value will reduce the opportunity to performing CCD substepping,
843    /// resulting in potentially more time dropped by the motion-clamping mechanism. Setting this
844    /// to an very small value may lead to numerical instabilities.
845    #[reflect(min_value = 0.0)]
846    pub min_ccd_dt: f32,
847
848    /// Amount of penetration the engine wont attempt to correct (default: `0.002m`).
849    #[reflect(min_value = 0.0)]
850    pub allowed_linear_error: f32,
851
852    /// Maximum amount of penetration the solver will attempt to resolve in one timestep (default: `10.0`).
853    #[reflect(min_value = 0.0)]
854    pub normalized_max_corrective_velocity: f32,
855
856    /// The maximal distance separating two objects that will generate predictive contacts (default: `0.002`).
857    #[reflect(min_value = 0.0)]
858    pub prediction_distance: f32,
859
860    /// The number of solver iterations run by the constraints solver for calculating forces (default: `4`).
861    #[reflect(min_value = 0.0)]
862    pub num_solver_iterations: usize,
863
864    /// Number of internal Project Gauss Seidel (PGS) iterations run at each solver iteration (default: `1`).
865    #[reflect(min_value = 0.0)]
866    pub num_internal_pgs_iterations: usize,
867
868    /// Minimum number of dynamic bodies in each active island (default: `128`).
869    #[reflect(min_value = 0.0)]
870    pub min_island_size: u32,
871
872    /// Maximum number of substeps performed by the  solver (default: `4`).
873    #[reflect(min_value = 0.0)]
874    pub max_ccd_substeps: u32,
875
876    /// The coefficient in `[0, 1]` applied to warmstart impulses, i.e., impulses that are used as the
877    /// initial solution (instead of 0) at the next simulation step. Default `1.0`.
878    pub warmstart_coefficient: f32,
879
880    /// The approximate size of most dynamic objects in the scene.
881    ///
882    /// This value can be understood as the number of units-per-meter in your physical world compared
883    /// to a human-sized world in meter. For example, in a 2d game, if your typical object size is 100
884    /// pixels, set the `[`Self::length_unit`]` parameter to 100.0. The physics engine will interpret
885    /// it as if 100 pixels is equivalent to 1 meter in its various internal threshold.
886    /// (default `1.0`).
887    pub length_unit: f32,
888
889    /// The number of stabilization iterations run at each solver iterations (default: `2`).
890    pub num_internal_stabilization_iterations: usize,
891}
892
893impl Default for IntegrationParameters {
894    fn default() -> Self {
895        Self {
896            dt: None,
897            min_ccd_dt: 1.0 / 60.0 / 100.0,
898            warmstart_coefficient: 1.0,
899            allowed_linear_error: 0.002,
900            normalized_max_corrective_velocity: 10.0,
901            prediction_distance: 0.002,
902            num_internal_pgs_iterations: 1,
903            num_solver_iterations: 4,
904            min_island_size: 128,
905            max_ccd_substeps: 4,
906            length_unit: 1.0,
907            num_internal_stabilization_iterations: 4,
908        }
909    }
910}
911
912/// Physics world is responsible for physics simulation in the engine. There is a very few public
913/// methods, mostly for ray casting. You should add physical entities using scene graph nodes, such
914/// as RigidBody, Collider, Joint.
915#[derive(Visit, Reflect)]
916pub struct PhysicsWorld {
917    /// A flag that defines whether physics simulation is enabled or not.
918    pub enabled: InheritableVariable<bool>,
919
920    /// A set of parameters that define behavior of every rigid body.
921    #[visit(optional)]
922    pub integration_parameters: InheritableVariable<IntegrationParameters>,
923
924    /// Current gravity vector. Default is (0.0, -9.81, 0.0)
925    pub gravity: InheritableVariable<Vector3<f32>>,
926
927    /// Performance statistics of a single simulation step.
928    #[visit(skip)]
929    #[reflect(hidden)]
930    pub performance_statistics: PhysicsPerformanceStatistics,
931
932    // Current physics pipeline.
933    #[visit(skip)]
934    #[reflect(hidden)]
935    pipeline: PhysicsPipeline,
936    // Broad phase performs rough intersection checks.
937    #[visit(skip)]
938    #[reflect(hidden)]
939    broad_phase: DefaultBroadPhase,
940    // Narrow phase is responsible for precise contact generation.
941    #[visit(skip)]
942    #[reflect(hidden)]
943    narrow_phase: NarrowPhase,
944    // A continuous collision detection solver.
945    #[visit(skip)]
946    #[reflect(hidden)]
947    ccd_solver: CCDSolver,
948    // Structure responsible for maintaining the set of active rigid-bodies, and putting non-moving
949    // rigid-bodies to sleep to save computation times.
950    #[visit(skip)]
951    #[reflect(hidden)]
952    islands: IslandManager,
953    // A container of rigid bodies.
954    #[visit(skip)]
955    #[reflect(hidden)]
956    bodies: RigidBodySet,
957    // A container of colliders.
958    #[visit(skip)]
959    #[reflect(hidden)]
960    pub(crate) colliders: ColliderSet,
961    // A container of impulse joints.
962    #[visit(skip)]
963    #[reflect(hidden)]
964    joints: Container<ImpulseJointSet, ImpulseJointHandle>,
965    // A container of multibody joints.
966    #[visit(skip)]
967    #[reflect(hidden)]
968    multibody_joints: Container<MultibodyJointSet, MultibodyJointHandle>,
969    // Event handler collects info about contacts and proximity events.
970    #[visit(skip)]
971    #[reflect(hidden)]
972    event_handler: Box<dyn EventHandler>,
973    #[visit(skip)]
974    #[reflect(hidden)]
975    debug_render_pipeline: Mutex<DebugRenderPipeline>,
976}
977
978impl Clone for PhysicsWorld {
979    fn clone(&self) -> Self {
980        PhysicsWorld {
981            enabled: self.enabled.clone(),
982            integration_parameters: self.integration_parameters.clone(),
983            gravity: self.gravity.clone(),
984            ..Default::default()
985        }
986    }
987}
988
989fn isometry_from_global_transform(transform: &Matrix4<f32>) -> Isometry3<f32> {
990    Isometry3 {
991        translation: Translation3::new(transform[12], transform[13], transform[14]),
992        rotation: UnitQuaternion::from_matrix_eps(
993            &transform.basis(),
994            f32::EPSILON,
995            16,
996            UnitQuaternion::identity(),
997        ),
998    }
999}
1000
1001fn calculate_local_frames(
1002    joint: &dyn NodeTrait,
1003    body1: &dyn NodeTrait,
1004    body2: &dyn NodeTrait,
1005) -> (Isometry3<f32>, Isometry3<f32>) {
1006    let joint_isometry = isometry_from_global_transform(&joint.global_transform());
1007
1008    (
1009        isometry_from_global_transform(&body1.global_transform()).inverse() * joint_isometry,
1010        isometry_from_global_transform(&body2.global_transform()).inverse() * joint_isometry,
1011    )
1012}
1013
1014fn u32_to_group(v: u32) -> rapier3d::geometry::Group {
1015    rapier3d::geometry::Group::from_bits(v).unwrap_or_else(rapier3d::geometry::Group::all)
1016}
1017
1018/// A filter tha describes what collider should be included or excluded from a scene query.
1019#[derive(Copy, Clone, Default)]
1020#[allow(clippy::type_complexity)]
1021pub struct QueryFilter<'a> {
1022    /// Flags indicating what particular type of colliders should be excluded from the scene query.
1023    pub flags: collider::QueryFilterFlags,
1024    /// If set, only colliders with collision groups compatible with this one will
1025    /// be included in the scene query.
1026    pub groups: Option<collider::InteractionGroups>,
1027    /// If set, this collider will be excluded from the scene query.
1028    pub exclude_collider: Option<Handle<Node>>,
1029    /// If set, any collider attached to this rigid-body will be excluded from the scene query.
1030    pub exclude_rigid_body: Option<Handle<Node>>,
1031    /// If set, any collider for which this closure returns false will be excluded from the scene query.
1032    pub predicate: Option<&'a dyn Fn(Handle<Node>, &collider::Collider) -> bool>,
1033}
1034
1035/// The result of a time-of-impact (TOI) computation.
1036#[derive(Copy, Clone, Debug)]
1037pub struct TOI {
1038    /// The time at which the objects touch.
1039    pub toi: f32,
1040    /// The local-space closest point on the first shape at the time of impact.
1041    ///
1042    /// Undefined if `status` is `Penetrating`.
1043    pub witness1: Point3<f32>,
1044    /// The local-space closest point on the second shape at the time of impact.
1045    ///
1046    /// Undefined if `status` is `Penetrating`.
1047    pub witness2: Point3<f32>,
1048    /// The local-space outward normal on the first shape at the time of impact.
1049    ///
1050    /// Undefined if `status` is `Penetrating`.
1051    pub normal1: UnitVector3<f32>,
1052    /// The local-space outward normal on the second shape at the time of impact.
1053    ///
1054    /// Undefined if `status` is `Penetrating`.
1055    pub normal2: UnitVector3<f32>,
1056    /// The way the time-of-impact computation algorithm terminated.
1057    pub status: collider::TOIStatus,
1058}
1059
1060impl PhysicsWorld {
1061    /// Creates a new instance of the physics world.
1062    pub(super) fn new() -> Self {
1063        Self {
1064            enabled: true.into(),
1065            pipeline: PhysicsPipeline::new(),
1066            gravity: Vector3::new(0.0, -9.81, 0.0).into(),
1067            integration_parameters: IntegrationParameters::default().into(),
1068            broad_phase: DefaultBroadPhase::new(),
1069            narrow_phase: NarrowPhase::new(),
1070            ccd_solver: CCDSolver::new(),
1071            islands: IslandManager::new(),
1072            bodies: RigidBodySet::new(),
1073            colliders: ColliderSet::new(),
1074            joints: Container {
1075                set: ImpulseJointSet::new(),
1076                map: Default::default(),
1077            },
1078            multibody_joints: Container {
1079                set: MultibodyJointSet::new(),
1080                map: Default::default(),
1081            },
1082            event_handler: Box::new(()),
1083            performance_statistics: Default::default(),
1084            debug_render_pipeline: Default::default(),
1085        }
1086    }
1087
1088    /// Update the physics pipeline with a timestep of the given length.
1089    ///
1090    /// * `dt`: The amount of time that has passed since the previous update.
1091    ///   This may be overriden by [`PhysicsWorld::integration_parameters`] if
1092    ///   `integration_parameters.dt` is `Some`, in which case that value is used
1093    ///   instead of this argument.
1094    /// * `dt_enabled`: If this is true then `dt` is used as usual, but if this is false
1095    ///   then both the `dt` argument and `integration_parameters.dt` are ignored and
1096    ///   a `dt` of zero is used instead, freezing all physics. This corresponds to the
1097    ///   [`GraphUpdateSwitches::physics_dt`](crate::scene::graph::GraphUpdateSwitches::physics_dt).
1098    pub(super) fn update(&mut self, dt: f32, dt_enabled: bool) {
1099        let time = instant::Instant::now();
1100        let parameter_dt = self.integration_parameters.dt;
1101        let parameter_dt = if parameter_dt == Some(0.0) {
1102            None
1103        } else {
1104            parameter_dt
1105        };
1106        let dt = if dt_enabled {
1107            parameter_dt.unwrap_or(dt)
1108        } else {
1109            0.0
1110        };
1111
1112        if *self.enabled {
1113            let integration_parameters = rapier3d::dynamics::IntegrationParameters {
1114                dt,
1115                min_ccd_dt: self.integration_parameters.min_ccd_dt,
1116                contact_softness: rapier3d::dynamics::SpringCoefficients::contact_defaults(),
1117                warmstart_coefficient: self.integration_parameters.warmstart_coefficient,
1118                length_unit: self.integration_parameters.length_unit,
1119                normalized_allowed_linear_error: self.integration_parameters.allowed_linear_error,
1120                normalized_max_corrective_velocity: self
1121                    .integration_parameters
1122                    .normalized_max_corrective_velocity,
1123                normalized_prediction_distance: self.integration_parameters.prediction_distance,
1124                num_solver_iterations: self.integration_parameters.num_solver_iterations,
1125                num_internal_pgs_iterations: self
1126                    .integration_parameters
1127                    .num_internal_pgs_iterations,
1128                num_internal_stabilization_iterations: self
1129                    .integration_parameters
1130                    .num_internal_stabilization_iterations,
1131                min_island_size: self.integration_parameters.min_island_size as usize,
1132                max_ccd_substeps: self.integration_parameters.max_ccd_substeps as usize,
1133                friction_model: FrictionModel::default(),
1134            };
1135
1136            self.pipeline.step(
1137                (*self.gravity).into(),
1138                &integration_parameters,
1139                &mut self.islands,
1140                &mut self.broad_phase,
1141                &mut self.narrow_phase,
1142                &mut self.bodies,
1143                &mut self.colliders,
1144                &mut self.joints.set,
1145                &mut self.multibody_joints.set,
1146                &mut self.ccd_solver,
1147                &(),
1148                &*self.event_handler,
1149            );
1150        }
1151
1152        self.performance_statistics.step_time += instant::Instant::now() - time;
1153    }
1154
1155    pub(super) fn add_body(&mut self, owner: Handle<Node>, mut body: RigidBody) -> RigidBodyHandle {
1156        body.user_data = owner.encode_to_u128();
1157        self.bodies.insert(body)
1158    }
1159
1160    pub(crate) fn remove_body(&mut self, handle: RigidBodyHandle) {
1161        self.bodies.remove(
1162            handle,
1163            &mut self.islands,
1164            &mut self.colliders,
1165            &mut self.joints.set,
1166            &mut self.multibody_joints.set,
1167            true,
1168        );
1169    }
1170
1171    pub(super) fn add_collider(
1172        &mut self,
1173        owner: Handle<Node>,
1174        parent_body: RigidBodyHandle,
1175        mut collider: Collider,
1176    ) -> ColliderHandle {
1177        collider.user_data = owner.encode_to_u128();
1178        self.colliders
1179            .insert_with_parent(collider, parent_body, &mut self.bodies)
1180    }
1181
1182    pub(crate) fn remove_collider(&mut self, handle: ColliderHandle) -> bool {
1183        self.colliders
1184            .remove(handle, &mut self.islands, &mut self.bodies, false)
1185            .is_some()
1186    }
1187
1188    pub(super) fn add_joint(
1189        &mut self,
1190        owner: Handle<Node>,
1191        body1: RigidBodyHandle,
1192        body2: RigidBodyHandle,
1193        joint: GenericJoint,
1194    ) -> ImpulseJointHandle {
1195        let handle = self.joints.set.insert(body1, body2, joint, false);
1196        self.joints.map.insert(handle, owner);
1197        handle
1198    }
1199
1200    pub(crate) fn remove_joint(&mut self, handle: ImpulseJointHandle) {
1201        if self.joints.set.remove(handle, false).is_some() {
1202            assert!(self.joints.map.remove_by_key(&handle).is_some());
1203        }
1204    }
1205
1206    /// Draws physics world. Very useful for debugging, it allows you to see where are
1207    /// rigid bodies, which colliders they have and so on.
1208    pub fn draw(&self, context: &mut SceneDrawingContext) {
1209        self.debug_render_pipeline.safe_lock().render(
1210            context,
1211            &self.bodies,
1212            &self.colliders,
1213            &self.joints.set,
1214            &self.multibody_joints.set,
1215            &self.narrow_phase,
1216        );
1217    }
1218
1219    /// Casts a ray with given options.
1220    pub fn cast_ray<S: QueryResultsStorage>(&self, opts: RayCastOptions, query_buffer: &mut S) {
1221        let time = instant::Instant::now();
1222
1223        let query = self.broad_phase.as_query_pipeline(
1224            &DefaultQueryDispatcher,
1225            &self.bodies,
1226            &self.colliders,
1227            rapier3d::pipeline::QueryFilter::new().groups(InteractionGroups::new(
1228                u32_to_group(opts.groups.memberships.0),
1229                u32_to_group(opts.groups.filter.0),
1230                Default::default(),
1231            )),
1232        );
1233
1234        query_buffer.clear();
1235        let ray = Ray::new(
1236            opts.ray_origin.into(),
1237            opts.ray_direction
1238                .try_normalize(f32::EPSILON)
1239                .unwrap_or_default()
1240                .into(),
1241        );
1242        for (_, collider, intersection) in query.intersect_ray(ray, opts.max_len, true) {
1243            query_buffer.push(Intersection {
1244                collider: Handle::decode_from_u128(collider.user_data),
1245                normal: intersection.normal.into(),
1246                position: ray.point_at(intersection.time_of_impact).into(),
1247                feature: intersection.feature.into(),
1248                toi: intersection.time_of_impact,
1249            });
1250        }
1251        if opts.sort_results {
1252            query_buffer.sort_intersections_by(|a, b| {
1253                if a.toi > b.toi {
1254                    Ordering::Greater
1255                } else if a.toi < b.toi {
1256                    Ordering::Less
1257                } else {
1258                    Ordering::Equal
1259                }
1260            })
1261        }
1262
1263        self.performance_statistics.total_ray_cast_time.set(
1264            self.performance_statistics.total_ray_cast_time.get()
1265                + (instant::Instant::now() - time),
1266        );
1267    }
1268
1269    /// Casts a shape at a constant linear velocity and retrieve the first collider it hits.
1270    ///
1271    /// This is similar to ray-casting except that we are casting a whole shape instead of just a
1272    /// point (the ray origin). In the resulting `TOI`, witness and normal 1 refer to the world
1273    /// collider, and are in world space.
1274    ///
1275    /// # Parameters
1276    ///
1277    /// * `graph` - a reference to the scene graph.
1278    /// * `shape` - The shape to cast.
1279    /// * `shape_pos` - The initial position of the shape to cast.
1280    /// * `shape_vel` - The constant velocity of the shape to cast (i.e. the cast direction).
1281    /// * `max_toi` - The maximum time-of-impact that can be reported by this cast. This effectively
1282    ///   limits the distance traveled by the shape to `shapeVel.norm() * maxToi`.
1283    /// * `stop_at_penetration` - If set to `false`, the linear shape-cast won’t immediately stop if
1284    ///   the shape is penetrating another shape at its starting point **and** its trajectory is such
1285    ///   that it’s on a path to exist that penetration state.
1286    /// * `filter`: set of rules used to determine which collider is taken into account by this scene
1287    ///   query.
1288    pub fn cast_shape(
1289        &self,
1290        graph: &Graph,
1291        shape: &dyn Shape,
1292        shape_pos: &Isometry3<f32>,
1293        shape_vel: &Vector3<f32>,
1294        max_toi: f32,
1295        stop_at_penetration: bool,
1296        filter: QueryFilter,
1297    ) -> Option<(Handle<Node>, TOI)> {
1298        let predicate = |handle: ColliderHandle, _: &Collider| -> bool {
1299            if let Some(pred) = filter.predicate {
1300                let h = Handle::decode_from_u128(self.colliders.get(handle).unwrap().user_data);
1301                pred(
1302                    h,
1303                    graph.node(h).component_ref::<collider::Collider>().unwrap(),
1304                )
1305            } else {
1306                true
1307            }
1308        };
1309
1310        let filter = rapier3d::pipeline::QueryFilter {
1311            flags: rapier3d::pipeline::QueryFilterFlags::from_bits(filter.flags.bits()).unwrap(),
1312            groups: filter.groups.map(|g| {
1313                InteractionGroups::new(
1314                    u32_to_group(g.memberships.0),
1315                    u32_to_group(g.filter.0),
1316                    Default::default(),
1317                )
1318            }),
1319            exclude_collider: filter
1320                .exclude_collider
1321                .and_then(|h| graph.try_get_of_type::<collider::Collider>(h).ok())
1322                .map(|c| c.native.get()),
1323            exclude_rigid_body: filter
1324                .exclude_collider
1325                .and_then(|h| graph.try_get_of_type::<rigidbody::RigidBody>(h).ok())
1326                .map(|c| c.native.get()),
1327            predicate: Some(&predicate),
1328        };
1329
1330        let query = self.broad_phase.as_query_pipeline(
1331            &DefaultQueryDispatcher,
1332            &self.bodies,
1333            &self.colliders,
1334            filter,
1335        );
1336
1337        let opts = ShapeCastOptions {
1338            max_time_of_impact: max_toi,
1339            target_distance: 0.0,
1340            stop_at_penetration,
1341            compute_impact_geometry_on_penetration: true,
1342        };
1343
1344        query
1345            .cast_shape(&Pose3::from(*shape_pos), (*shape_vel).into(), shape, opts)
1346            .map(|(handle, toi)| {
1347                (
1348                    Handle::decode_from_u128(self.colliders.get(handle).unwrap().user_data),
1349                    TOI {
1350                        toi: toi.time_of_impact,
1351                        witness1: toi.witness1.into(),
1352                        witness2: toi.witness2.into(),
1353                        normal1: UnitVector3::new_normalize(toi.normal1.into()),
1354                        normal2: UnitVector3::new_normalize(toi.normal2.into()),
1355                        status: toi.status.into(),
1356                    },
1357                )
1358            })
1359    }
1360
1361    pub(crate) fn set_rigid_body_position(
1362        &mut self,
1363        rigid_body: &scene::rigidbody::RigidBody,
1364        new_global_transform: &Matrix4<f32>,
1365    ) {
1366        if let Some(native) = self.bodies.get_mut(rigid_body.native.get()) {
1367            native.set_position(
1368                isometry_from_global_transform(new_global_transform).into(),
1369                // Do not wake up body, it is too expensive and must be done **only** by explicit
1370                // `wake_up` call!
1371                false,
1372            );
1373        }
1374    }
1375
1376    pub(crate) fn sync_rigid_body_node(
1377        &mut self,
1378        rigid_body: &mut scene::rigidbody::RigidBody,
1379        parent_transform: Matrix4<f32>,
1380    ) {
1381        if *self.enabled {
1382            if let Some(native) = self.bodies.get(rigid_body.native.get()) {
1383                if native.body_type() != RigidBodyType::Fixed {
1384                    let local_transform: Matrix4<f32> = parent_transform
1385                        .try_inverse()
1386                        .unwrap_or_else(Matrix4::identity)
1387                        * Isometry3::from(*native.position()).to_homogeneous();
1388
1389                    let new_local_rotation = UnitQuaternion::from_matrix_eps(
1390                        &local_transform.basis(),
1391                        f32::EPSILON,
1392                        16,
1393                        UnitQuaternion::identity(),
1394                    );
1395                    let new_local_position = Vector3::new(
1396                        local_transform[12],
1397                        local_transform[13],
1398                        local_transform[14],
1399                    );
1400
1401                    // Do not touch local transform if position/rotation is not changing. This will
1402                    // prevent redundant update of its global transform, which in its turn save some
1403                    // CPU cycles.
1404                    let local_transform = rigid_body.local_transform();
1405                    if **local_transform.position() != new_local_position
1406                        || **local_transform.rotation() != new_local_rotation
1407                    {
1408                        rigid_body
1409                            .local_transform_mut()
1410                            .set_position(new_local_position)
1411                            .set_rotation(new_local_rotation);
1412                    }
1413
1414                    rigid_body
1415                        .lin_vel
1416                        .set_value_with_flags(native.linvel().into(), VariableFlags::MODIFIED);
1417                    rigid_body
1418                        .ang_vel
1419                        .set_value_with_flags(native.angvel().into(), VariableFlags::MODIFIED);
1420                    rigid_body.sleeping = native.is_sleeping();
1421                }
1422            }
1423        }
1424    }
1425
1426    pub(crate) fn sync_to_rigid_body_node(
1427        &mut self,
1428        handle: Handle<Node>,
1429        rigid_body_node: &scene::rigidbody::RigidBody,
1430    ) {
1431        if !rigid_body_node.is_globally_enabled() {
1432            self.remove_body(rigid_body_node.native.get());
1433            rigid_body_node.native.set(Default::default());
1434            return;
1435        }
1436
1437        // Important notes!
1438        // 1) `get_mut` is **very** expensive because it forces physics engine to recalculate contacts
1439        //    and a lot of other stuff, this is why we need `anything_changed` flag.
1440        if rigid_body_node.native.get() != RigidBodyHandle::invalid() {
1441            let mut actions = rigid_body_node.actions.safe_lock();
1442            if rigid_body_node.need_sync_model() || !actions.is_empty() {
1443                if let Some(native) = self.bodies.get_mut(rigid_body_node.native.get()) {
1444                    // Sync native rigid body's properties with scene node's in case if they
1445                    // were changed by user.
1446                    rigid_body_node
1447                        .body_type
1448                        .try_sync_model(|v| native.set_body_type(v.into(), false));
1449                    rigid_body_node
1450                        .lin_vel
1451                        .try_sync_model(|v| native.set_linvel(v.into(), true));
1452                    rigid_body_node
1453                        .ang_vel
1454                        .try_sync_model(|v| native.set_angvel(v.into(), true));
1455                    rigid_body_node.mass.try_sync_model(|v| {
1456                        match *rigid_body_node.mass_properties_type {
1457                            RigidBodyMassPropertiesType::Default => {
1458                                native.set_additional_mass(v, false);
1459                            }
1460                            RigidBodyMassPropertiesType::Additional {
1461                                center_of_mass,
1462                                principal_inertia,
1463                            } => {
1464                                native.set_additional_mass_properties(
1465                                    MassProperties::new(
1466                                        center_of_mass.into(),
1467                                        v,
1468                                        principal_inertia.into(),
1469                                    ),
1470                                    false,
1471                                );
1472                            }
1473                        };
1474                    });
1475                    rigid_body_node.mass_properties_type.try_sync_model(|v| {
1476                        match v {
1477                            RigidBodyMassPropertiesType::Default => {
1478                                native.set_additional_mass(*rigid_body_node.mass, false);
1479                            }
1480                            RigidBodyMassPropertiesType::Additional {
1481                                center_of_mass,
1482                                principal_inertia,
1483                            } => {
1484                                native.set_additional_mass_properties(
1485                                    MassProperties::new(
1486                                        center_of_mass.into(),
1487                                        *rigid_body_node.mass,
1488                                        principal_inertia.into(),
1489                                    ),
1490                                    false,
1491                                );
1492                            }
1493                        };
1494                    });
1495                    rigid_body_node
1496                        .lin_damping
1497                        .try_sync_model(|v| native.set_linear_damping(v));
1498                    rigid_body_node
1499                        .ang_damping
1500                        .try_sync_model(|v| native.set_angular_damping(v));
1501                    rigid_body_node
1502                        .ccd_enabled
1503                        .try_sync_model(|v| native.enable_ccd(v));
1504                    rigid_body_node.can_sleep.try_sync_model(|v| {
1505                        if v {
1506                            *native.activation_mut() = RigidBodyActivation::active();
1507                        } else {
1508                            *native.activation_mut() = RigidBodyActivation::cannot_sleep();
1509                        };
1510                    });
1511                    rigid_body_node
1512                        .translation_locked
1513                        .try_sync_model(|v| native.lock_translations(v, false));
1514                    rigid_body_node.x_rotation_locked.try_sync_model(|v| {
1515                        native.set_enabled_rotations(
1516                            !v,
1517                            !native.is_rotation_locked()[1],
1518                            !native.is_rotation_locked()[2],
1519                            false,
1520                        );
1521                    });
1522                    rigid_body_node.y_rotation_locked.try_sync_model(|v| {
1523                        native.set_enabled_rotations(
1524                            !native.is_rotation_locked()[0],
1525                            !v,
1526                            !native.is_rotation_locked()[2],
1527                            false,
1528                        );
1529                    });
1530                    rigid_body_node.z_rotation_locked.try_sync_model(|v| {
1531                        native.set_enabled_rotations(
1532                            !native.is_rotation_locked()[0],
1533                            !native.is_rotation_locked()[1],
1534                            !v,
1535                            false,
1536                        );
1537                    });
1538                    rigid_body_node
1539                        .dominance
1540                        .try_sync_model(|v| native.set_dominance_group(v));
1541                    rigid_body_node
1542                        .gravity_scale
1543                        .try_sync_model(|v| native.set_gravity_scale(v, false));
1544
1545                    // We must reset any forces applied at previous update step, otherwise physics engine
1546                    // will keep pushing the rigid body infinitely.
1547                    if rigid_body_node.reset_forces.replace(false) {
1548                        native.reset_forces(false);
1549                        native.reset_torques(false);
1550                    }
1551
1552                    while let Some(action) = actions.pop_front() {
1553                        match action {
1554                            ApplyAction::Force(force) => {
1555                                native.add_force(force.into(), false);
1556                                rigid_body_node.reset_forces.set(true);
1557                            }
1558                            ApplyAction::Torque(torque) => {
1559                                native.add_torque(torque.into(), false);
1560                                rigid_body_node.reset_forces.set(true);
1561                            }
1562                            ApplyAction::ForceAtPoint { force, point } => {
1563                                native.add_force_at_point(force.into(), point.into(), false);
1564                                rigid_body_node.reset_forces.set(true);
1565                            }
1566                            ApplyAction::Impulse(impulse) => {
1567                                native.apply_impulse(impulse.into(), false)
1568                            }
1569                            ApplyAction::TorqueImpulse(impulse) => {
1570                                native.apply_torque_impulse(impulse.into(), false)
1571                            }
1572                            ApplyAction::ImpulseAtPoint { impulse, point } => {
1573                                native.apply_impulse_at_point(impulse.into(), point.into(), false)
1574                            }
1575                            ApplyAction::WakeUp => native.wake_up(true),
1576                            ApplyAction::NextTranslation(position) => {
1577                                native.set_next_kinematic_translation(position.into())
1578                            }
1579                            ApplyAction::NextRotation(rotation) => {
1580                                native.set_next_kinematic_rotation(rotation.into())
1581                            }
1582                            ApplyAction::NextPosition(position) => {
1583                                native.set_next_kinematic_position(position.into())
1584                            }
1585                        }
1586                    }
1587                }
1588            }
1589        } else {
1590            let mut builder = RigidBodyBuilder::new(rigid_body_node.body_type().into())
1591                .pose(isometry_from_global_transform(&rigid_body_node.global_transform()).into())
1592                .ccd_enabled(rigid_body_node.is_ccd_enabled())
1593                .additional_mass(rigid_body_node.mass())
1594                .angvel((*rigid_body_node.ang_vel).into())
1595                .linvel((*rigid_body_node.lin_vel).into())
1596                .linear_damping(*rigid_body_node.lin_damping)
1597                .angular_damping(*rigid_body_node.ang_damping)
1598                .can_sleep(rigid_body_node.is_can_sleep())
1599                .dominance_group(rigid_body_node.dominance())
1600                .gravity_scale(rigid_body_node.gravity_scale())
1601                .enabled_rotations(
1602                    !rigid_body_node.is_x_rotation_locked(),
1603                    !rigid_body_node.is_y_rotation_locked(),
1604                    !rigid_body_node.is_z_rotation_locked(),
1605                );
1606
1607            match *rigid_body_node.mass_properties_type {
1608                RigidBodyMassPropertiesType::Default => {
1609                    builder = builder.additional_mass(*rigid_body_node.mass);
1610                }
1611                RigidBodyMassPropertiesType::Additional {
1612                    center_of_mass,
1613                    principal_inertia,
1614                } => {
1615                    builder = builder.additional_mass_properties(MassProperties::new(
1616                        center_of_mass.into(),
1617                        *rigid_body_node.mass,
1618                        principal_inertia.into(),
1619                    ));
1620                }
1621            };
1622            if rigid_body_node.is_translation_locked() {
1623                builder = builder.lock_translations();
1624            }
1625
1626            rigid_body_node
1627                .native
1628                .set(self.add_body(handle, builder.build()));
1629
1630            Log::writeln(
1631                MessageKind::Information,
1632                format!(
1633                    "Native rigid body was created for node {}",
1634                    rigid_body_node.name()
1635                ),
1636            );
1637        }
1638    }
1639
1640    pub(crate) fn sync_to_collider_node(
1641        &mut self,
1642        nodes: &NodePool,
1643        handle: Handle<Node>,
1644        collider_node: &scene::collider::Collider,
1645    ) {
1646        if !collider_node.is_globally_enabled() {
1647            self.remove_collider(collider_node.native.get());
1648            collider_node.native.set(Default::default());
1649            return;
1650        }
1651
1652        let anything_changed = collider_node.needs_sync_model();
1653
1654        // Important notes!
1655        // 1) The collider node may lack backing native physics collider in case if it
1656        //    is not attached to a rigid body.
1657        // 2) `get_mut` is **very** expensive because it forces physics engine to recalculate contacts
1658        //    and a lot of other stuff, this is why we need `anything_changed` flag.
1659        if collider_node.native.get() != ColliderHandle::invalid() {
1660            if anything_changed {
1661                if let Some(native) = self.colliders.get_mut(collider_node.native.get()) {
1662                    collider_node
1663                        .restitution
1664                        .try_sync_model(|v| native.set_restitution(v));
1665                    collider_node.collision_groups.try_sync_model(|v| {
1666                        native.set_collision_groups(InteractionGroups::new(
1667                            u32_to_group(v.memberships.0),
1668                            u32_to_group(v.filter.0),
1669                            Default::default(),
1670                        ))
1671                    });
1672                    collider_node.solver_groups.try_sync_model(|v| {
1673                        native.set_solver_groups(InteractionGroups::new(
1674                            u32_to_group(v.memberships.0),
1675                            u32_to_group(v.filter.0),
1676                            Default::default(),
1677                        ))
1678                    });
1679                    collider_node
1680                        .friction
1681                        .try_sync_model(|v| native.set_friction(v));
1682                    collider_node
1683                        .is_sensor
1684                        .try_sync_model(|v| native.set_sensor(v));
1685                    collider_node
1686                        .friction_combine_rule
1687                        .try_sync_model(|v| native.set_friction_combine_rule(v.into()));
1688                    collider_node
1689                        .restitution_combine_rule
1690                        .try_sync_model(|v| native.set_restitution_combine_rule(v.into()));
1691                    let mut remove_collider = false;
1692                    collider_node.shape.try_sync_model(|v| {
1693                        let inv_global_transform = isometric_global_transform(nodes, handle)
1694                            .try_inverse()
1695                            .unwrap_or_default();
1696
1697                        if let Some(shape) = collider_shape_into_native_shape(
1698                            &v,
1699                            inv_global_transform,
1700                            handle,
1701                            nodes,
1702                        ) {
1703                            native.set_shape(shape);
1704                        } else {
1705                            remove_collider = true;
1706                        }
1707                    });
1708                    if remove_collider {
1709                        self.remove_collider(collider_node.native.get());
1710                        collider_node.native.set(ColliderHandle::invalid());
1711                    }
1712                }
1713            }
1714        } else if let Ok(parent_body) =
1715            nodes.try_get_component_of_type::<scene::rigidbody::RigidBody>(collider_node.parent())
1716        {
1717            if parent_body.native.get() != RigidBodyHandle::invalid() {
1718                let inv_global_transform = isometric_global_transform(nodes, handle)
1719                    .try_inverse()
1720                    .unwrap();
1721                let rigid_body_native = parent_body.native.get();
1722                if let Some(shape) = collider_shape_into_native_shape(
1723                    collider_node.shape(),
1724                    inv_global_transform,
1725                    handle,
1726                    nodes,
1727                ) {
1728                    let mut builder = ColliderBuilder::new(shape)
1729                        .position(
1730                            Isometry3 {
1731                                rotation: **collider_node.local_transform().rotation(),
1732                                translation: Translation3 {
1733                                    vector: **collider_node.local_transform().position(),
1734                                },
1735                            }
1736                            .into(),
1737                        )
1738                        .friction(collider_node.friction())
1739                        .restitution(collider_node.restitution())
1740                        .collision_groups(InteractionGroups::new(
1741                            u32_to_group(collider_node.collision_groups().memberships.0),
1742                            u32_to_group(collider_node.collision_groups().filter.0),
1743                            Default::default(),
1744                        ))
1745                        .friction_combine_rule(collider_node.friction_combine_rule().into())
1746                        .restitution_combine_rule(collider_node.restitution_combine_rule().into())
1747                        .solver_groups(InteractionGroups::new(
1748                            u32_to_group(collider_node.solver_groups().memberships.0),
1749                            u32_to_group(collider_node.solver_groups().filter.0),
1750                            Default::default(),
1751                        ))
1752                        .sensor(collider_node.is_sensor());
1753
1754                    if let Some(density) = collider_node.density() {
1755                        builder = builder.density(density);
1756                    }
1757
1758                    let native_handle =
1759                        self.add_collider(handle, rigid_body_native, builder.build());
1760
1761                    collider_node.native.set(native_handle);
1762
1763                    Log::writeln(
1764                        MessageKind::Information,
1765                        format!(
1766                            "Native collider was created for node {}",
1767                            collider_node.name()
1768                        ),
1769                    );
1770                }
1771            }
1772        }
1773    }
1774
1775    pub(crate) fn sync_to_joint_node(
1776        &mut self,
1777        nodes: &NodePool,
1778        handle: Handle<Node>,
1779        joint: &scene::joint::Joint,
1780    ) {
1781        if !joint.is_globally_enabled() {
1782            self.remove_joint(joint.native.get());
1783            joint.native.set(ImpulseJointHandle(Default::default()));
1784            return;
1785        }
1786
1787        if let Some(native) = self.joints.set.get_mut(joint.native.get(), false) {
1788            joint.body1.try_sync_model(|v| {
1789                if let Ok(rigid_body_node) = nodes.try_get(v) {
1790                    native.body1 = rigid_body_node.native.get();
1791                }
1792            });
1793            joint.body2.try_sync_model(|v| {
1794                if let Ok(rigid_body_node) = nodes.try_get(v) {
1795                    native.body2 = rigid_body_node.native.get();
1796                }
1797            });
1798            joint.params.try_sync_model(|v| {
1799                native.data =
1800                    // Preserve local frames.
1801                    convert_joint_params(v, native.data.local_frame1.into(), native.data.local_frame2.into())
1802            });
1803            joint.motor_params.try_sync_model(|v|{
1804                // For prismatic and revolute joints, the free axis is defined to be the x axis.
1805                // If you want the joint to translate / rotate along a different axis, you can rotate the joint itself.
1806                let joint_axes: &[JointAxis] = match joint.params.get_value_ref(){
1807                    JointParams::PrismaticJoint(_) => &[JointAxis::LinX][..], // slice the array to unify arrays of different lengths.
1808                    JointParams::RevoluteJoint(_) => &[JointAxis::AngX][..],
1809                    JointParams::BallJoint(_) => &[JointAxis::AngX, JointAxis::AngY, JointAxis::AngZ][..],
1810                    _ => {
1811                        Log::warn("Try to modify motor parameters for unsupported joint type, this operation will be ignored.");
1812                        return;
1813                    }
1814                };
1815                for joint_axis in joint_axes {
1816                    // Force based motor model is better in the Fyrox's context
1817                    native.data.set_motor_model(*joint_axis, rapier3d::prelude::MotorModel::ForceBased);
1818                    let JointMotorParams {
1819                        target_vel,
1820                        target_pos,
1821                        stiffness,
1822                        damping,
1823                        max_force
1824                    } = v;
1825                    native.data.set_motor(*joint_axis, target_pos, target_vel, stiffness, damping);
1826                    native.data.set_motor_max_force(*joint_axis, max_force);
1827                }
1828                // wake up the bodies connected to the joint to ensure they respond to the motor changes immediately
1829                // however, the rigid bodies may fall asleep any time later unless Joint::set_motor_* functions are called periodically,
1830                // or the rigid bodies are set to cannot sleep
1831                let Some(body1) = self.bodies.get_mut(native.body1) else {
1832                    return;
1833                };
1834                body1.wake_up(true);
1835                let Some(body2) = self.bodies.get_mut(native.body2) else {
1836                    return;
1837                };
1838                body2.wake_up(true);
1839            });
1840            joint.contacts_enabled.try_sync_model(|v| {
1841                native.data.set_contacts_enabled(v);
1842            });
1843
1844            let mut local_frames = joint.local_frames.borrow_mut();
1845            if local_frames.is_none() {
1846                if let (Ok(body1), Ok(body2)) =
1847                    (nodes.try_get(joint.body1()), nodes.try_get(joint.body2()))
1848                {
1849                    let (local_frame1, local_frame2) = calculate_local_frames(joint, body1, body2);
1850                    native.data =
1851                        convert_joint_params((*joint.params).clone(), local_frame1, local_frame2);
1852                    *local_frames = Some(JointLocalFrames::new(&local_frame1, &local_frame2));
1853                }
1854            }
1855        } else {
1856            let body1_handle = joint.body1();
1857            let body2_handle = joint.body2();
1858            let params = joint.params().clone();
1859
1860            // A native joint can be created iff both rigid bodies are correctly assigned and their respective
1861            // native bodies exists.
1862            if let (Some(body1), Some(body2)) = (
1863                nodes
1864                    .try_get(body1_handle)
1865                    .ok()
1866                    .filter(|b| self.bodies.get(b.native.get()).is_some()),
1867                nodes
1868                    .try_get(body2_handle)
1869                    .ok()
1870                    .filter(|b| self.bodies.get(b.native.get()).is_some()),
1871            ) {
1872                let native_body1 = body1.native.get();
1873                let native_body2 = body2.native.get();
1874
1875                if self.bodies.get(native_body1).is_none()
1876                    || self.bodies.get(native_body2).is_none()
1877                {
1878                    // A joint may be synced before the connected bodies, this way the connected
1879                    // rigid bodies does not have native rigid bodies, and in this case we should
1880                    // simply skip the joint and initialize it on the next frame.
1881                    return;
1882                }
1883
1884                // Calculate local frames first (if needed).
1885                let mut local_frames = joint.local_frames.borrow_mut();
1886                let (local_frame1, local_frame2) = local_frames
1887                    .clone()
1888                    .map(|frames| {
1889                        (
1890                            Isometry3 {
1891                                rotation: frames.body1.rotation,
1892                                translation: Translation {
1893                                    vector: frames.body1.position,
1894                                },
1895                            },
1896                            Isometry3 {
1897                                rotation: frames.body2.rotation,
1898                                translation: Translation {
1899                                    vector: frames.body2.position,
1900                                },
1901                            },
1902                        )
1903                    })
1904                    .unwrap_or_else(|| calculate_local_frames(joint, body1, body2));
1905
1906                let mut native_joint = convert_joint_params(params, local_frame1, local_frame2);
1907                native_joint.contacts_enabled = joint.is_contacts_enabled();
1908                let native_handle =
1909                    self.add_joint(handle, native_body1, native_body2, native_joint);
1910
1911                joint.native.set(native_handle);
1912                *local_frames = Some(JointLocalFrames::new(&local_frame1, &local_frame2));
1913
1914                Log::writeln(
1915                    MessageKind::Information,
1916                    format!("Native joint was created for node {}", joint.name()),
1917                );
1918            }
1919        }
1920    }
1921
1922    /// Intersections checks between regular colliders and sensor colliders
1923    pub(crate) fn intersections_with(
1924        &self,
1925        collider: ColliderHandle,
1926    ) -> impl Iterator<Item = IntersectionPair> + '_ {
1927        self.narrow_phase
1928            .intersection_pairs_with(collider)
1929            .filter_map(|(collider1, collider2, intersecting)| {
1930                Some(IntersectionPair {
1931                    collider1: Handle::decode_from_u128(self.colliders.get(collider1)?.user_data),
1932                    collider2: Handle::decode_from_u128(self.colliders.get(collider2)?.user_data),
1933                    has_any_active_contact: intersecting,
1934                })
1935            })
1936    }
1937
1938    /// Contacts checks between two regular colliders
1939    pub(crate) fn contacts_with(
1940        &self,
1941        collider: ColliderHandle,
1942    ) -> impl Iterator<Item = ContactPair> + '_ {
1943        self.narrow_phase
1944            // Note: contacts with will only return the interaction between 2 non-sensor nodes
1945            // https://rapier.rs/docs/user_guides/rust/advanced_collision_detection/#the-contact-graph
1946            .contact_pairs_with(collider)
1947            .filter_map(|c| ContactPair::from_native(c, self))
1948    }
1949
1950    /// Returns an iterator over all contact pairs generated in this frame.
1951    pub fn contacts(&self) -> impl Iterator<Item = ContactPair> + '_ {
1952        self.narrow_phase
1953            .contact_pairs()
1954            .filter_map(|c| ContactPair::from_native(c, self))
1955    }
1956}
1957
1958impl Default for PhysicsWorld {
1959    fn default() -> Self {
1960        Self::new()
1961    }
1962}
1963
1964impl Debug for PhysicsWorld {
1965    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1966        write!(f, "PhysicsWorld")
1967    }
1968}