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