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