Skip to main content

fyrox_impl/scene/
collider.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//! Collider is a geometric entity that can be attached to a rigid body to allow participate it
22//! participate in contact generation, collision response and proximity queries.
23
24use crate::scene::node::constructor::NodeConstructor;
25use crate::{
26    core::{
27        algebra::Vector3,
28        log::Log,
29        math::aabb::AxisAlignedBoundingBox,
30        num_traits::{NumCast, One, ToPrimitive, Zero},
31        pool::Handle,
32        reflect::prelude::*,
33        type_traits::prelude::*,
34        uuid::{uuid, Uuid},
35        variable::InheritableVariable,
36        visitor::prelude::*,
37    },
38    scene::{
39        base::{Base, BaseBuilder},
40        graph::{
41            physics::{CoefficientCombineRule, ContactPair, IntersectionPair, PhysicsWorld},
42            Graph,
43        },
44        node::{Node, NodeTrait, SyncContext},
45        rigidbody::RigidBody,
46        Scene,
47    },
48};
49use fyrox_core::algebra::{Isometry3, Translation3};
50use fyrox_core::uuid_provider;
51
52use fyrox_graph::constructor::ConstructorProvider;
53use fyrox_graph::SceneGraph;
54use rapier3d::geometry::{self, ColliderHandle};
55use std::fmt::Write;
56use std::{
57    cell::Cell,
58    ops::{Add, BitAnd, BitOr, Deref, DerefMut, Mul, Not, Shl},
59};
60use strum_macros::{AsRefStr, EnumString, VariantNames};
61
62/// Ball is an idea sphere shape defined by a single parameters - its radius.
63#[derive(Clone, Debug, PartialEq, Visit, Reflect)]
64pub struct BallShape {
65    /// Radius of the sphere.
66    #[reflect(min_value = 0.001, step = 0.05)]
67    pub radius: f32,
68}
69
70impl Default for BallShape {
71    fn default() -> Self {
72        Self { radius: 0.5 }
73    }
74}
75
76/// Cylinder shape aligned in Y axis.
77#[derive(Clone, Debug, Visit, Reflect, PartialEq)]
78pub struct CylinderShape {
79    /// Half height of the cylinder, actual height will be 2 times bigger.
80    #[reflect(min_value = 0.001, step = 0.05)]
81    pub half_height: f32,
82    /// Radius of the cylinder.
83    #[reflect(min_value = 0.001, step = 0.05)]
84    pub radius: f32,
85}
86
87impl Default for CylinderShape {
88    fn default() -> Self {
89        Self {
90            half_height: 0.5,
91            radius: 0.5,
92        }
93    }
94}
95
96/// Cone shape aligned in Y axis.
97#[derive(Clone, Debug, Visit, Reflect, PartialEq)]
98pub struct ConeShape {
99    /// Half height of the cone, actual height will be 2 times bigger.
100    #[reflect(min_value = 0.001, step = 0.05)]
101    pub half_height: f32,
102    /// Radius of the cone base.
103    #[reflect(min_value = 0.001, step = 0.05)]
104    pub radius: f32,
105}
106
107impl Default for ConeShape {
108    fn default() -> Self {
109        Self {
110            half_height: 0.5,
111            radius: 0.5,
112        }
113    }
114}
115
116/// Cuboid shape (box).
117#[derive(Clone, Debug, Visit, Reflect, PartialEq)]
118pub struct CuboidShape {
119    /// Half extents of the box. X - half width, Y - half height, Z - half depth.
120    /// Actual _size_ will be 2 times bigger.
121    #[reflect(min_value = 0.001, step = 0.05)]
122    pub half_extents: Vector3<f32>,
123}
124
125impl Default for CuboidShape {
126    fn default() -> Self {
127        Self {
128            half_extents: Vector3::new(0.5, 0.5, 0.5),
129        }
130    }
131}
132
133/// Arbitrary capsule shape defined by 2 points (which forms axis) and a radius.
134#[derive(Clone, Debug, Visit, Reflect, PartialEq)]
135pub struct CapsuleShape {
136    /// Begin point of the capsule.
137    pub begin: Vector3<f32>,
138    /// End point of the capsule.
139    pub end: Vector3<f32>,
140    /// Radius of the capsule.
141    #[reflect(min_value = 0.001, step = 0.05)]
142    pub radius: f32,
143}
144
145impl Default for CapsuleShape {
146    // Y-capsule
147    fn default() -> Self {
148        Self {
149            begin: Default::default(),
150            end: Vector3::new(0.0, 1.0, 0.0),
151            radius: 0.5,
152        }
153    }
154}
155
156/// Arbitrary segment shape defined by two points.
157#[derive(Clone, Debug, Visit, Reflect, PartialEq)]
158pub struct SegmentShape {
159    /// Begin point of the capsule.
160    pub begin: Vector3<f32>,
161    /// End point of the capsule.
162    pub end: Vector3<f32>,
163}
164
165impl Default for SegmentShape {
166    fn default() -> Self {
167        Self {
168            begin: Default::default(),
169            end: Vector3::new(0.0, 1.0, 0.0),
170        }
171    }
172}
173
174/// Arbitrary triangle shape.
175#[derive(Clone, Debug, Visit, Reflect, PartialEq)]
176pub struct TriangleShape {
177    /// First point of the triangle shape.
178    pub a: Vector3<f32>,
179    /// Second point of the triangle shape.
180    pub b: Vector3<f32>,
181    /// Third point of the triangle shape.
182    pub c: Vector3<f32>,
183}
184
185impl Default for TriangleShape {
186    fn default() -> Self {
187        Self {
188            a: Default::default(),
189            b: Vector3::new(1.0, 0.0, 0.0),
190            c: Vector3::new(0.0, 0.0, 1.0),
191        }
192    }
193}
194
195/// Geometry source for colliders with complex geometry.
196///
197/// # Notes
198///
199/// Currently there is only one way to set geometry - using a scene node as a source of data.
200#[derive(Default, Clone, Copy, PartialEq, Hash, Debug, Visit, Reflect, Eq)]
201pub struct GeometrySource(pub Handle<Node>);
202
203uuid_provider!(GeometrySource = "6fea7c72-c488-48a1-935f-2752a8a10e9a");
204
205/// Arbitrary triangle mesh shape.
206#[derive(Default, Clone, Debug, Visit, Reflect, PartialEq, Eq)]
207pub struct TrimeshShape {
208    /// Geometry sources for the shape.
209    pub sources: Vec<GeometrySource>,
210}
211
212/// Arbitrary height field shape.
213#[derive(Default, Clone, Debug, Visit, Reflect, PartialEq, Eq)]
214pub struct HeightfieldShape {
215    /// A handle to terrain scene node.
216    pub geometry_source: GeometrySource,
217}
218
219/// Arbitrary convex polyhedron shape.
220#[derive(Default, Clone, Debug, Visit, Reflect, PartialEq, Eq)]
221pub struct ConvexPolyhedronShape {
222    /// A handle to a mesh node.
223    pub geometry_source: GeometrySource,
224}
225
226/// A set of bits used for pairwise collision filtering.
227#[derive(Clone, Copy, Default, PartialEq, Reflect, Eq)]
228pub struct BitMask(pub u32);
229
230uuid_provider!(BitMask = "f2db0c2a-921b-4728-9ce4-2506d95c60fa");
231
232impl BitMask {
233    /// BitMask with all bits set. BitMask(u32::MAX)
234    pub const fn all() -> Self {
235        Self(u32::MAX)
236    }
237    /// BitMask with no bits set. BitMask(0)
238    pub const fn none() -> Self {
239        Self(0)
240    }
241    /// Construct BitMask from this BitMask plus setting bit at the given index to 1.
242    pub const fn with(self, index: usize) -> Self {
243        Self(self.0 | (1 << index))
244    }
245    /// Construct BitMask from this BitMask plus resetting the bit at the given index to 0.
246    pub const fn without(self, index: usize) -> Self {
247        Self(self.0 & !(1 << index))
248    }
249    /// True if the bit at `index` is set.
250    pub fn bit(&self, index: usize) -> bool {
251        (self.0 >> index) & 1 != 0
252    }
253    /// Set or reset the bit at `index`.
254    pub fn set_bit(&mut self, index: usize, value: bool) {
255        if value {
256            self.0 |= 1 << index;
257        } else {
258            self.0 &= !(1 << index);
259        }
260    }
261}
262
263impl std::fmt::Debug for BitMask {
264    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265        write!(f, "BitMask({:08x})", self.0)
266    }
267}
268
269impl std::fmt::Display for BitMask {
270    /// Represent the bit mask in the same way it is shown in the editor, with bit 0 on the left and bit 31 on the right.
271    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
272        let mut value = self.0;
273        for i in 0..4 {
274            if i != 0 {
275                f.write_char(' ')?;
276            }
277            for _ in 0..8 {
278                let bit = if value & 1 == 1 { '1' } else { '0' };
279                value >>= 1;
280                f.write_char(bit)?;
281            }
282        }
283        Ok(())
284    }
285}
286
287impl Visit for BitMask {
288    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
289        self.0.visit(name, visitor)
290    }
291}
292
293impl BitOr for BitMask {
294    type Output = Self;
295
296    fn bitor(self, rhs: Self) -> Self::Output {
297        Self(self.0 | rhs.0)
298    }
299}
300
301impl BitAnd for BitMask {
302    type Output = Self;
303
304    fn bitand(self, rhs: Self) -> Self::Output {
305        Self(self.0 & rhs.0)
306    }
307}
308
309impl Mul for BitMask {
310    type Output = Self;
311
312    fn mul(self, rhs: Self) -> Self::Output {
313        Self(self.0 * rhs.0)
314    }
315}
316
317impl One for BitMask {
318    fn one() -> Self {
319        Self(1)
320    }
321}
322
323impl Add for BitMask {
324    type Output = Self;
325
326    fn add(self, rhs: Self) -> Self::Output {
327        Self(self.0 + rhs.0)
328    }
329}
330
331impl Zero for BitMask {
332    fn zero() -> Self {
333        Self(0)
334    }
335
336    fn is_zero(&self) -> bool {
337        self.0 == 0
338    }
339}
340
341impl Shl for BitMask {
342    type Output = Self;
343
344    fn shl(self, rhs: Self) -> Self::Output {
345        Self(self.0 << rhs.0)
346    }
347}
348
349impl Not for BitMask {
350    type Output = Self;
351
352    fn not(self) -> Self::Output {
353        Self(!self.0)
354    }
355}
356
357impl ToPrimitive for BitMask {
358    fn to_i64(&self) -> Option<i64> {
359        Some(self.0 as i64)
360    }
361
362    fn to_u64(&self) -> Option<u64> {
363        Some(self.0 as u64)
364    }
365}
366
367impl NumCast for BitMask {
368    fn from<T: ToPrimitive>(n: T) -> Option<Self> {
369        n.to_u32().map(Self)
370    }
371}
372
373/// Pairwise filtering using bit masks.
374///
375/// This filtering method is based on two 32-bit values:
376/// - The interaction groups memberships.
377/// - The interaction groups filter.
378///
379/// An interaction is allowed between two filters `a` and `b` when two conditions
380/// are met simultaneously:
381/// - The groups membership of `a` has at least one bit set to `1` in common with the groups filter of `b`.
382/// - The groups membership of `b` has at least one bit set to `1` in common with the groups filter of `a`.
383///
384/// In other words, interactions are allowed between two filter iff. the following condition is met:
385/// ```ignore
386/// (self.memberships & rhs.filter) != 0 && (rhs.memberships & self.filter) != 0
387/// ```
388#[derive(Visit, Debug, Clone, Copy, PartialEq, Reflect, Eq)]
389pub struct InteractionGroups {
390    /// Groups memberships.
391    pub memberships: BitMask,
392    /// Groups filter.
393    pub filter: BitMask,
394}
395
396impl InteractionGroups {
397    /// Creates new interaction group using given values.
398    pub fn new(memberships: BitMask, filter: BitMask) -> Self {
399        Self {
400            memberships,
401            filter,
402        }
403    }
404}
405
406impl std::fmt::Display for InteractionGroups {
407    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
408        write!(f, "{} (filter: {})", self.memberships, self.filter)
409    }
410}
411
412impl Default for InteractionGroups {
413    fn default() -> Self {
414        Self {
415            memberships: BitMask::all(),
416            filter: BitMask::all(),
417        }
418    }
419}
420
421impl From<geometry::InteractionGroups> for InteractionGroups {
422    fn from(g: geometry::InteractionGroups) -> Self {
423        Self {
424            memberships: BitMask(g.memberships.bits()),
425            filter: BitMask(g.filter.bits()),
426        }
427    }
428}
429
430bitflags::bitflags! {
431    #[derive(Default, Copy, Clone)]
432    /// Flags for excluding whole sets of colliders from a scene query.
433    pub struct QueryFilterFlags: u32 {
434        /// Exclude from the query any collider attached to a fixed rigid-body and colliders with no rigid-body attached.
435        const EXCLUDE_FIXED = 1 << 1;
436        /// Exclude from the query any collider attached to a kinematic rigid-body.
437        const EXCLUDE_KINEMATIC = 1 << 2;
438        /// Exclude from the query any collider attached to a dynamic rigid-body.
439        const EXCLUDE_DYNAMIC = 1 << 3;
440        /// Exclude from the query any collider that is a sensor.
441        const EXCLUDE_SENSORS = 1 << 4;
442        /// Exclude from the query any collider that is not a sensor.
443        const EXCLUDE_SOLIDS = 1 << 5;
444        /// Excludes all colliders not attached to a dynamic rigid-body.
445        const ONLY_DYNAMIC = Self::EXCLUDE_FIXED.bits() | Self::EXCLUDE_KINEMATIC.bits();
446        /// Excludes all colliders not attached to a kinematic rigid-body.
447        const ONLY_KINEMATIC = Self::EXCLUDE_DYNAMIC.bits() | Self::EXCLUDE_FIXED.bits();
448        /// Exclude all colliders attached to a non-fixed rigid-body
449        /// (this will not exclude colliders not attached to any rigid-body).
450        const ONLY_FIXED = Self::EXCLUDE_DYNAMIC.bits() | Self::EXCLUDE_KINEMATIC.bits();
451    }
452}
453
454/// The status of the time-of-impact computation algorithm.
455#[derive(Copy, Clone, Debug, PartialEq, Eq)]
456pub enum TOIStatus {
457    /// The TOI algorithm ran out of iterations before achieving convergence.
458    ///
459    /// The content of the `TOI` will still be a conservative approximation of the actual result so
460    /// it is often fine to interpret this case as a success.
461    OutOfIterations,
462    /// The TOI algorithm converged successfully.
463    Converged,
464    /// Something went wrong during the TOI computation, likely due to numerical instabilities.
465    ///
466    /// The content of the `TOI` will still be a conservative approximation of the actual result so
467    /// it is often fine to interpret this case as a success.
468    Failed,
469    /// The two shape already overlap at the time 0.
470    ///
471    /// The witness points and normals provided by the `TOI` will have undefined values.
472    Penetrating,
473}
474
475impl From<rapier3d::parry::query::ShapeCastStatus> for TOIStatus {
476    fn from(value: rapier3d::parry::query::ShapeCastStatus) -> Self {
477        match value {
478            rapier3d::parry::query::ShapeCastStatus::OutOfIterations => Self::OutOfIterations,
479            rapier3d::parry::query::ShapeCastStatus::Converged => Self::Converged,
480            rapier3d::parry::query::ShapeCastStatus::Failed => Self::Failed,
481            rapier3d::parry::query::ShapeCastStatus::PenetratingOrWithinTargetDist => {
482                Self::Penetrating
483            }
484        }
485    }
486}
487
488impl From<rapier2d::parry::query::ShapeCastStatus> for TOIStatus {
489    fn from(value: rapier2d::parry::query::ShapeCastStatus) -> Self {
490        match value {
491            rapier2d::parry::query::ShapeCastStatus::OutOfIterations => Self::OutOfIterations,
492            rapier2d::parry::query::ShapeCastStatus::Converged => Self::Converged,
493            rapier2d::parry::query::ShapeCastStatus::Failed => Self::Failed,
494            rapier2d::parry::query::ShapeCastStatus::PenetratingOrWithinTargetDist => {
495                Self::Penetrating
496            }
497        }
498    }
499}
500
501/// Possible collider shapes.
502#[derive(Clone, Debug, PartialEq, Visit, Reflect, AsRefStr, EnumString, VariantNames)]
503pub enum ColliderShape {
504    /// See [`BallShape`] docs.
505    Ball(BallShape),
506    /// See [`CylinderShape`] docs.
507    Cylinder(CylinderShape),
508    /// See [`ConeShape`] docs.
509    Cone(ConeShape),
510    /// See [`CuboidShape`] docs.
511    Cuboid(CuboidShape),
512    /// See [`CapsuleShape`] docs.
513    Capsule(CapsuleShape),
514    /// See [`SegmentShape`] docs.
515    Segment(SegmentShape),
516    /// See [`TriangleShape`] docs.
517    Triangle(TriangleShape),
518    /// See [`TrimeshShape`] docs.
519    Trimesh(TrimeshShape),
520    /// See [`HeightfieldShape`] docs.
521    Heightfield(HeightfieldShape),
522    /// See [`ConvexPolyhedronShape`] docs.
523    Polyhedron(ConvexPolyhedronShape),
524}
525
526uuid_provider!(ColliderShape = "2e627337-71ea-4b33-a5f1-be697f705a86");
527
528impl Default for ColliderShape {
529    fn default() -> Self {
530        Self::Ball(Default::default())
531    }
532}
533
534impl ColliderShape {
535    /// Initializes a ball shape defined by its radius.
536    pub fn ball(radius: f32) -> Self {
537        Self::Ball(BallShape { radius })
538    }
539
540    /// Initializes a cylindrical shape defined by its half-height (along along the y axis) and its
541    /// radius.
542    pub fn cylinder(half_height: f32, radius: f32) -> Self {
543        Self::Cylinder(CylinderShape {
544            half_height,
545            radius,
546        })
547    }
548
549    /// Initializes a cone shape defined by its half-height (along along the y axis) and its basis
550    /// radius.
551    pub fn cone(half_height: f32, radius: f32) -> Self {
552        Self::Cone(ConeShape {
553            half_height,
554            radius,
555        })
556    }
557
558    /// Initializes a cuboid shape defined by its half-extents.
559    pub fn cuboid(hx: f32, hy: f32, hz: f32) -> Self {
560        Self::Cuboid(CuboidShape {
561            half_extents: Vector3::new(hx, hy, hz),
562        })
563    }
564
565    /// Initializes a capsule shape from its endpoints and radius.
566    pub fn capsule(begin: Vector3<f32>, end: Vector3<f32>, radius: f32) -> Self {
567        Self::Capsule(CapsuleShape { begin, end, radius })
568    }
569
570    /// Initializes a new collider builder with a capsule shape aligned with the `x` axis.
571    pub fn capsule_x(half_height: f32, radius: f32) -> Self {
572        let p = Vector3::x() * half_height;
573        Self::capsule(-p, p, radius)
574    }
575
576    /// Initializes a new collider builder with a capsule shape aligned with the `y` axis.
577    pub fn capsule_y(half_height: f32, radius: f32) -> Self {
578        let p = Vector3::y() * half_height;
579        Self::capsule(-p, p, radius)
580    }
581
582    /// Initializes a new collider builder with a capsule shape aligned with the `z` axis.
583    pub fn capsule_z(half_height: f32, radius: f32) -> Self {
584        let p = Vector3::z() * half_height;
585        Self::capsule(-p, p, radius)
586    }
587
588    /// Initializes a segment shape from its endpoints.
589    pub fn segment(begin: Vector3<f32>, end: Vector3<f32>) -> Self {
590        Self::Segment(SegmentShape { begin, end })
591    }
592
593    /// Initializes a triangle shape.
594    pub fn triangle(a: Vector3<f32>, b: Vector3<f32>, c: Vector3<f32>) -> Self {
595        Self::Triangle(TriangleShape { a, b, c })
596    }
597
598    /// Initializes a triangle mesh shape defined by a set of handles to mesh nodes that will be
599    /// used to create physical shape.
600    pub fn trimesh(geometry_sources: Vec<GeometrySource>) -> Self {
601        Self::Trimesh(TrimeshShape {
602            sources: geometry_sources,
603        })
604    }
605
606    /// Initializes a heightfield shape defined by a handle to terrain node.
607    pub fn heightfield(geometry_source: GeometrySource) -> Self {
608        Self::Heightfield(HeightfieldShape { geometry_source })
609    }
610}
611
612/// Collider is a geometric entity that can be attached to a rigid body to allow participate it
613/// participate in contact generation, collision response and proximity queries.
614#[derive(Reflect, Visit, Debug, ComponentProvider)]
615#[reflect(derived_type = "Node")]
616pub struct Collider {
617    base: Base,
618
619    #[reflect(setter = "set_shape")]
620    pub(crate) shape: InheritableVariable<ColliderShape>,
621
622    #[reflect(min_value = 0.0, step = 0.05, setter = "set_friction")]
623    pub(crate) friction: InheritableVariable<f32>,
624
625    #[reflect(setter = "set_density")]
626    pub(crate) density: InheritableVariable<Option<f32>>,
627
628    #[reflect(min_value = 0.0, step = 0.05, setter = "set_restitution")]
629    pub(crate) restitution: InheritableVariable<f32>,
630
631    #[reflect(setter = "set_is_sensor")]
632    pub(crate) is_sensor: InheritableVariable<bool>,
633
634    #[reflect(setter = "set_collision_groups")]
635    pub(crate) collision_groups: InheritableVariable<InteractionGroups>,
636
637    #[reflect(setter = "set_solver_groups")]
638    pub(crate) solver_groups: InheritableVariable<InteractionGroups>,
639
640    #[reflect(setter = "set_friction_combine_rule")]
641    pub(crate) friction_combine_rule: InheritableVariable<CoefficientCombineRule>,
642
643    #[reflect(setter = "set_restitution_combine_rule")]
644    pub(crate) restitution_combine_rule: InheritableVariable<CoefficientCombineRule>,
645
646    #[visit(skip)]
647    #[reflect(hidden)]
648    pub(crate) native: Cell<ColliderHandle>,
649}
650
651impl Default for Collider {
652    fn default() -> Self {
653        Self {
654            base: Default::default(),
655            shape: Default::default(),
656            friction: InheritableVariable::new_modified(0.0),
657            density: InheritableVariable::new_modified(None),
658            restitution: InheritableVariable::new_modified(0.0),
659            is_sensor: InheritableVariable::new_modified(false),
660            collision_groups: Default::default(),
661            solver_groups: Default::default(),
662            friction_combine_rule: Default::default(),
663            restitution_combine_rule: Default::default(),
664            native: Cell::new(ColliderHandle::invalid()),
665        }
666    }
667}
668
669impl Deref for Collider {
670    type Target = Base;
671
672    fn deref(&self) -> &Self::Target {
673        &self.base
674    }
675}
676
677impl DerefMut for Collider {
678    fn deref_mut(&mut self) -> &mut Self::Target {
679        &mut self.base
680    }
681}
682
683impl Clone for Collider {
684    fn clone(&self) -> Self {
685        Self {
686            base: self.base.clone(),
687            shape: self.shape.clone(),
688            friction: self.friction.clone(),
689            density: self.density.clone(),
690            restitution: self.restitution.clone(),
691            is_sensor: self.is_sensor.clone(),
692            collision_groups: self.collision_groups.clone(),
693            solver_groups: self.solver_groups.clone(),
694            friction_combine_rule: self.friction_combine_rule.clone(),
695            restitution_combine_rule: self.restitution_combine_rule.clone(),
696            // Do not copy. The copy will have its own native representation (for example - Rapier's collider)
697            native: Cell::new(ColliderHandle::invalid()),
698        }
699    }
700}
701
702impl TypeUuidProvider for Collider {
703    fn type_uuid() -> Uuid {
704        uuid!("bfaa2e82-9c19-4b99-983b-3bc115744a1d")
705    }
706}
707
708impl Collider {
709    /// Sets the new shape to the collider.
710    ///
711    /// # Performance
712    ///
713    /// This is relatively expensive operation - it forces the physics engine to recalculate contacts,
714    /// perform collision response, etc. Try avoid calling this method each frame for better
715    /// performance.
716    pub fn set_shape(&mut self, shape: ColliderShape) -> ColliderShape {
717        self.shape.set_value_and_mark_modified(shape)
718    }
719
720    /// Returns shared reference to the collider shape.
721    pub fn shape(&self) -> &ColliderShape {
722        &self.shape
723    }
724
725    /// Returns a copy of the collider shape.
726    pub fn shape_value(&self) -> ColliderShape {
727        (*self.shape).clone()
728    }
729
730    /// Returns mutable reference to the current collider shape.
731    ///
732    /// # Performance
733    ///
734    /// This is relatively expensive operation - it forces the physics engine to recalculate contacts,
735    /// perform collision response, etc. Try avoid calling this method each frame for better
736    /// performance.
737    pub fn shape_mut(&mut self) -> &mut ColliderShape {
738        self.shape.get_value_mut_and_mark_modified()
739    }
740
741    /// Sets the new restitution value. The exact meaning of possible values is somewhat complex,
742    /// check [Wikipedia page](https://en.wikipedia.org/wiki/Coefficient_of_restitution) for more
743    /// info.
744    ///
745    /// # Performance
746    ///
747    /// This is relatively expensive operation - it forces the physics engine to recalculate contacts,
748    /// perform collision response, etc. Try avoid calling this method each frame for better
749    /// performance.
750    pub fn set_restitution(&mut self, restitution: f32) -> f32 {
751        self.restitution.set_value_and_mark_modified(restitution)
752    }
753
754    /// Returns current restitution value of the collider.
755    pub fn restitution(&self) -> f32 {
756        *self.restitution
757    }
758
759    /// Sets the new density value of the collider. Density defines actual mass of the rigid body to
760    /// which the collider is attached. Final mass will be a sum of `ColliderVolume * ColliderDensity`
761    /// of each collider. In case if density is undefined, the mass of the collider will be zero,
762    /// which will lead to two possible effects:
763    ///
764    /// 1) If a rigid body to which collider is attached have no additional mass, then the rigid body
765    ///    won't rotate, only move.
766    /// 2) If the rigid body have some additional mass, then the rigid body will have normal behaviour.
767    ///
768    /// # Performance
769    ///
770    /// This is relatively expensive operation - it forces the physics engine to recalculate contacts,
771    /// perform collision response, etc. Try avoid calling this method each frame for better
772    /// performance.
773    pub fn set_density(&mut self, density: Option<f32>) -> Option<f32> {
774        self.density.set_value_and_mark_modified(density)
775    }
776
777    /// Returns current density of the collider.
778    pub fn density(&self) -> Option<f32> {
779        *self.density
780    }
781
782    /// Sets friction coefficient for the collider. The greater value is the more kinematic energy
783    /// will be converted to heat (in other words - lost), the parent rigid body will slowdown much
784    /// faster and so on.
785    ///
786    /// # Performance
787    ///
788    /// This is relatively expensive operation - it forces the physics engine to recalculate contacts,
789    /// perform collision response, etc. Try avoid calling this method each frame for better
790    /// performance.
791    pub fn set_friction(&mut self, friction: f32) -> f32 {
792        self.friction.set_value_and_mark_modified(friction)
793    }
794
795    /// Return current friction of the collider.
796    pub fn friction(&self) -> f32 {
797        *self.friction
798    }
799
800    /// Sets the new collision filtering options. See [`InteractionGroups`] docs for more info.
801    ///
802    /// # Performance
803    ///
804    /// This is relatively expensive operation - it forces the physics engine to recalculate contacts,
805    /// perform collision response, etc. Try avoid calling this method each frame for better
806    /// performance.
807    pub fn set_collision_groups(&mut self, groups: InteractionGroups) -> InteractionGroups {
808        self.collision_groups.set_value_and_mark_modified(groups)
809    }
810
811    /// Returns current collision filtering options.
812    pub fn collision_groups(&self) -> InteractionGroups {
813        *self.collision_groups
814    }
815
816    /// Sets the new joint solver filtering options. See [`InteractionGroups`] docs for more info.
817    ///
818    /// # Performance
819    ///
820    /// This is relatively expensive operation - it forces the physics engine to recalculate contacts,
821    /// perform collision response, etc. Try avoid calling this method each frame for better
822    /// performance.
823    pub fn set_solver_groups(&mut self, groups: InteractionGroups) -> InteractionGroups {
824        self.solver_groups.set_value_and_mark_modified(groups)
825    }
826
827    /// Returns current solver groups.
828    pub fn solver_groups(&self) -> InteractionGroups {
829        *self.solver_groups
830    }
831
832    /// If true is passed, the method makes collider a sensor. Sensors will not participate in
833    /// collision response, but it is still possible to query contact information from them.
834    ///
835    /// # Performance
836    ///
837    /// This is relatively expensive operation - it forces the physics engine to recalculate contacts,
838    /// perform collision response, etc. Try avoid calling this method each frame for better
839    /// performance.
840    pub fn set_is_sensor(&mut self, is_sensor: bool) -> bool {
841        self.is_sensor.set_value_and_mark_modified(is_sensor)
842    }
843
844    /// Returns true if the collider is sensor, false - otherwise.
845    pub fn is_sensor(&self) -> bool {
846        *self.is_sensor
847    }
848
849    /// Sets the new friction combine rule. See [`CoefficientCombineRule`] docs for more info.
850    ///
851    /// # Performance
852    ///
853    /// This is relatively expensive operation - it forces the physics engine to recalculate contacts,
854    /// perform collision response, etc. Try avoid calling this method each frame for better
855    /// performance.
856    pub fn set_friction_combine_rule(
857        &mut self,
858        rule: CoefficientCombineRule,
859    ) -> CoefficientCombineRule {
860        self.friction_combine_rule.set_value_and_mark_modified(rule)
861    }
862
863    /// Returns current friction combine rule of the collider.
864    pub fn friction_combine_rule(&self) -> CoefficientCombineRule {
865        *self.friction_combine_rule
866    }
867
868    /// Sets the new restitution combine rule. See [`CoefficientCombineRule`] docs for more info.
869    ///
870    /// # Performance
871    ///
872    /// This is relatively expensive operation - it forces the physics engine to recalculate contacts,
873    /// perform collision response, etc. Try avoid calling this method each frame for better
874    /// performance.
875    pub fn set_restitution_combine_rule(
876        &mut self,
877        rule: CoefficientCombineRule,
878    ) -> CoefficientCombineRule {
879        self.restitution_combine_rule
880            .set_value_and_mark_modified(rule)
881    }
882
883    /// Returns current restitution combine rule of the collider.
884    pub fn restitution_combine_rule(&self) -> CoefficientCombineRule {
885        *self.restitution_combine_rule
886    }
887
888    /// Returns an iterator that yields contact information for the collider.
889    /// Contacts checks between two non-sensor colliders.
890    /// This includes only cases where two colliders are pressing against each other,
891    /// and only if [`ContactPair::has_any_active_contact`] is true.
892    /// When `has_any_active_contact` is false, the colliders may merely have overlapping
893    /// bounding boxes. See [`Collider::active_contacts`] for an interator that yields
894    /// only pairs where `has_any_active_contact` is true.
895    ///
896    /// When a collider is passing through a sensor collider, that goes into the
897    /// [`Collider::intersects`] list. Those intersections will not be produced by
898    /// this iterator.
899    ///
900    /// Each pair produced by this iterator includes the handles of two colliders,
901    /// this collider and some other collider. There is no guarantee about whether
902    /// this collider will be the first member of the pair or the second,
903    /// but [`ContactPair::other`] can be used to get the handle of the other collider
904    /// given the handle of this collider.
905    pub fn contacts<'a>(
906        &self,
907        physics: &'a PhysicsWorld,
908    ) -> impl Iterator<Item = ContactPair> + 'a {
909        physics.contacts_with(self.native.get())
910    }
911
912    /// Returns an iterator that yields contact information for the collider.
913    /// Contacts checks between two non-sensor colliders that are actually touching.
914    /// This includes only cases where two colliders are pressing against each other.
915    /// When a collider is passing through a sensor collider, that goes into the
916    /// [`Collider::intersects`] list.
917    ///
918    /// [`ContactPair::has_any_active_contact`] is guaranteed to be true for every pair
919    /// produced by this iterator.
920    ///
921    /// Each pair produced by this iterator includes the handles of two colliders,
922    /// this collider and some other collider. There is no guarantee about whether
923    /// this collider will be the first member of the pair or the second,
924    /// but [`ContactPair::other`] can be used to get the handle of the other collider
925    /// given the handle of this collider.
926    pub fn active_contacts<'a>(
927        &self,
928        physics: &'a PhysicsWorld,
929    ) -> impl Iterator<Item = ContactPair> + 'a {
930        self.contacts(physics)
931            .filter(|pair| pair.has_any_active_contact)
932    }
933
934    /// Returns an iterator that yields intersection information for the collider.
935    /// Intersections checks for colliders passing through each other due to at least
936    /// one of the colliders being a sensor.
937    /// If [`IntersectionPair::has_any_active_contact`] is true, that means the colliders are actually touching.
938    /// When `has_any_active_contact` is false, the colliders may merely have overlapping
939    /// bounding boxes. See [`Collider::active_intersects`] for an interator that yields
940    /// only colliders that actually overlap this collider.
941    ///
942    /// Each pair produced by this iterator includes the handles of two colliders,
943    /// this collider and some other collider. There is no guarantee about whether
944    /// this collider will be the first member of the pair or the second,
945    /// but [`IntersectionPair::other`] can be used to get the handle of the other collider
946    /// given the handle of this collider.
947    pub fn intersects<'a>(
948        &self,
949        physics: &'a PhysicsWorld,
950    ) -> impl Iterator<Item = IntersectionPair> + 'a {
951        physics.intersections_with(self.native.get())
952    }
953
954    /// Returns an iterator that yields intersection information for the collider.
955    /// Intersections checks for colliders passing through each other due to at least
956    /// one of the colliders being a sensor.
957    pub fn active_intersects<'a>(
958        &self,
959        physics: &'a PhysicsWorld,
960    ) -> impl Iterator<Item = Handle<Collider>> + 'a {
961        let self_handle = self.handle().to_variant();
962        self.intersects(physics)
963            .filter(|pair| pair.has_any_active_contact)
964            .map(move |pair| pair.other(self_handle))
965    }
966
967    pub(crate) fn needs_sync_model(&self) -> bool {
968        self.shape.need_sync()
969            || self.friction.need_sync()
970            || self.density.need_sync()
971            || self.restitution.need_sync()
972            || self.is_sensor.need_sync()
973            || self.collision_groups.need_sync()
974            || self.solver_groups.need_sync()
975            || self.friction_combine_rule.need_sync()
976            || self.restitution_combine_rule.need_sync()
977    }
978}
979
980impl ConstructorProvider<Node, Graph> for Collider {
981    fn constructor() -> NodeConstructor {
982        NodeConstructor::new::<Self>()
983            .with_variant("Collider", |_| {
984                ColliderBuilder::new(BaseBuilder::new().with_name("Collider"))
985                    .with_shape(ColliderShape::Cuboid(Default::default()))
986                    .build_node()
987                    .into()
988            })
989            .with_group("Physics")
990    }
991}
992
993impl NodeTrait for Collider {
994    fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
995        self.base.local_bounding_box()
996    }
997
998    fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
999        self.base.world_bounding_box()
1000    }
1001
1002    fn id(&self) -> Uuid {
1003        Self::type_uuid()
1004    }
1005
1006    fn on_removed_from_graph(&mut self, graph: &mut Graph) {
1007        graph.physics.remove_collider(self.native.get());
1008        self.native.set(ColliderHandle::invalid());
1009
1010        Log::info(format!(
1011            "Native collider was removed for node: {}",
1012            self.name()
1013        ));
1014    }
1015
1016    fn on_unlink(&mut self, graph: &mut Graph) {
1017        if graph.physics.remove_collider(self.native.get()) {
1018            // Remove native collider when detaching a collider node from rigid body node.
1019            self.native.set(ColliderHandle::invalid());
1020        }
1021    }
1022
1023    fn on_local_transform_changed(&self, context: &mut SyncContext) {
1024        if self.native.get() != ColliderHandle::invalid() {
1025            if let Some(native) = context.physics.colliders.get_mut(self.native.get()) {
1026                native.set_position_wrt_parent(Isometry3 {
1027                    rotation: **self.local_transform().rotation(),
1028                    translation: Translation3 {
1029                        vector: **self.local_transform().position(),
1030                    },
1031                });
1032            }
1033        }
1034    }
1035
1036    fn sync_native(&self, self_handle: Handle<Node>, context: &mut SyncContext) {
1037        context
1038            .physics
1039            .sync_to_collider_node(context.nodes, self_handle, self);
1040    }
1041
1042    fn validate(&self, scene: &Scene) -> Result<(), String> {
1043        let mut message = String::new();
1044
1045        if scene
1046            .graph
1047            .try_get_of_type::<RigidBody>(self.parent())
1048            .is_err()
1049        {
1050            message += "3D Collider must be a direct child of a 3D Rigid Body node, \
1051            otherwise it will not have any effect!";
1052        }
1053
1054        match &*self.shape {
1055            ColliderShape::Trimesh(trimesh) => {
1056                for source in trimesh.sources.iter() {
1057                    if !scene.graph.is_valid_handle(source.0) {
1058                        message += &format!("Trimesh data source {} handle is invalid!", source.0);
1059                    }
1060                }
1061            }
1062            ColliderShape::Heightfield(heightfield) => {
1063                if !scene.graph.is_valid_handle(heightfield.geometry_source.0) {
1064                    message += &format!(
1065                        "Heightfield data source {} handle is invalid!",
1066                        heightfield.geometry_source.0
1067                    );
1068                }
1069            }
1070            ColliderShape::Polyhedron(polyhedron) => {
1071                if !scene.graph.is_valid_handle(polyhedron.geometry_source.0) {
1072                    message += &format!(
1073                        "Polyhedron data source {} handle is invalid!",
1074                        polyhedron.geometry_source.0
1075                    );
1076                }
1077            }
1078            _ => (),
1079        }
1080
1081        if message.is_empty() {
1082            Ok(())
1083        } else {
1084            Err(message)
1085        }
1086    }
1087}
1088
1089/// Collider builder allows you to build a collider node in declarative mannner.
1090pub struct ColliderBuilder {
1091    base_builder: BaseBuilder,
1092    shape: ColliderShape,
1093    friction: f32,
1094    density: Option<f32>,
1095    restitution: f32,
1096    is_sensor: bool,
1097    collision_groups: InteractionGroups,
1098    solver_groups: InteractionGroups,
1099    friction_combine_rule: CoefficientCombineRule,
1100    restitution_combine_rule: CoefficientCombineRule,
1101}
1102
1103impl ColliderBuilder {
1104    /// Creates new collider builder.
1105    pub fn new(base_builder: BaseBuilder) -> Self {
1106        Self {
1107            base_builder,
1108            shape: Default::default(),
1109            friction: 0.0,
1110            density: None,
1111            restitution: 0.0,
1112            is_sensor: false,
1113            collision_groups: Default::default(),
1114            solver_groups: Default::default(),
1115            friction_combine_rule: Default::default(),
1116            restitution_combine_rule: Default::default(),
1117        }
1118    }
1119
1120    /// Sets desired shape of the collider.
1121    pub fn with_shape(mut self, shape: ColliderShape) -> Self {
1122        self.shape = shape;
1123        self
1124    }
1125
1126    /// Sets desired density value.
1127    pub fn with_density(mut self, density: Option<f32>) -> Self {
1128        self.density = density;
1129        self
1130    }
1131
1132    /// Sets desired restitution value.
1133    pub fn with_restitution(mut self, restitution: f32) -> Self {
1134        self.restitution = restitution;
1135        self
1136    }
1137
1138    /// Sets desired friction value.
1139    pub fn with_friction(mut self, friction: f32) -> Self {
1140        self.friction = friction;
1141        self
1142    }
1143
1144    /// Sets whether this collider will be used a sensor or not.
1145    pub fn with_sensor(mut self, sensor: bool) -> Self {
1146        self.is_sensor = sensor;
1147        self
1148    }
1149
1150    /// Sets desired solver groups.
1151    pub fn with_solver_groups(mut self, solver_groups: InteractionGroups) -> Self {
1152        self.solver_groups = solver_groups;
1153        self
1154    }
1155
1156    /// Sets desired collision groups.
1157    pub fn with_collision_groups(mut self, collision_groups: InteractionGroups) -> Self {
1158        self.collision_groups = collision_groups;
1159        self
1160    }
1161
1162    /// Sets desired friction combine rule.
1163    pub fn with_friction_combine_rule(mut self, rule: CoefficientCombineRule) -> Self {
1164        self.friction_combine_rule = rule;
1165        self
1166    }
1167
1168    /// Sets desired restitution combine rule.
1169    pub fn with_restitution_combine_rule(mut self, rule: CoefficientCombineRule) -> Self {
1170        self.restitution_combine_rule = rule;
1171        self
1172    }
1173
1174    /// Creates collider node, but does not add it to a graph.
1175    pub fn build_collider(self) -> Collider {
1176        Collider {
1177            base: self.base_builder.build_base(),
1178            shape: self.shape.into(),
1179            friction: self.friction.into(),
1180            density: self.density.into(),
1181            restitution: self.restitution.into(),
1182            is_sensor: self.is_sensor.into(),
1183            collision_groups: self.collision_groups.into(),
1184            solver_groups: self.solver_groups.into(),
1185            friction_combine_rule: self.friction_combine_rule.into(),
1186            restitution_combine_rule: self.restitution_combine_rule.into(),
1187            native: Cell::new(ColliderHandle::invalid()),
1188        }
1189    }
1190
1191    /// Creates collider node, but does not add it to a graph.
1192    pub fn build_node(self) -> Node {
1193        Node::new(self.build_collider())
1194    }
1195
1196    /// Creates collider node and adds it to the graph.
1197    pub fn build(self, graph: &mut Graph) -> Handle<Collider> {
1198        graph.add_node(self.build_node()).to_variant()
1199    }
1200}
1201
1202#[cfg(test)]
1203mod test {
1204    use super::*;
1205    use crate::core::algebra::Vector2;
1206    use crate::scene::{
1207        base::BaseBuilder,
1208        collider::{ColliderBuilder, ColliderShape},
1209        graph::Graph,
1210        rigidbody::{RigidBodyBuilder, RigidBodyType},
1211    };
1212
1213    #[test]
1214    fn test_collider_intersect() {
1215        let mut graph = Graph::new();
1216
1217        let mut create_rigid_body = |is_sensor| {
1218            let cube_half_size = 0.5;
1219            let collider_sensor = ColliderBuilder::new(BaseBuilder::new())
1220                .with_shape(ColliderShape::cuboid(
1221                    cube_half_size,
1222                    cube_half_size,
1223                    cube_half_size,
1224                ))
1225                .with_sensor(is_sensor)
1226                .build(&mut graph);
1227
1228            RigidBodyBuilder::new(BaseBuilder::new().with_child(collider_sensor))
1229                .with_body_type(RigidBodyType::Static)
1230                .build(&mut graph);
1231
1232            collider_sensor
1233        };
1234
1235        let collider_sensor = create_rigid_body(true);
1236        let collider_non_sensor = create_rigid_body(false);
1237
1238        // need to call two times for the physics engine to execute
1239        graph.update(Vector2::new(800.0, 600.0), 1.0, Default::default());
1240        graph.update(Vector2::new(800.0, 600.0), 1.0, Default::default());
1241
1242        // we don't expect contact between regular body and sensor
1243        assert_eq!(0, graph[collider_sensor].contacts(&graph.physics).count());
1244        assert_eq!(
1245            0,
1246            graph[collider_non_sensor].contacts(&graph.physics).count()
1247        );
1248
1249        // we expect intersection between regular body and sensor
1250        assert_eq!(1, graph[collider_sensor].intersects(&graph.physics).count());
1251        assert_eq!(
1252            1,
1253            graph[collider_non_sensor]
1254                .intersects(&graph.physics)
1255                .count()
1256        );
1257    }
1258    #[test]
1259    fn test_bitmask_display() {
1260        assert_eq!(
1261            BitMask(1).to_string(),
1262            "10000000 00000000 00000000 00000000"
1263        );
1264        assert_eq!(
1265            BitMask(15).to_string(),
1266            "11110000 00000000 00000000 00000000"
1267        );
1268        assert_eq!(
1269            BitMask(16).to_string(),
1270            "00001000 00000000 00000000 00000000"
1271        );
1272        assert_eq!(
1273            BitMask(256).to_string(),
1274            "00000000 10000000 00000000 00000000"
1275        );
1276        assert_eq!(
1277            BitMask(1 << 31).to_string(),
1278            "00000000 00000000 00000000 00000001"
1279        );
1280    }
1281    #[test]
1282    fn test_bitmask_debug() {
1283        assert_eq!(format!("{:?}", BitMask(1)), "BitMask(00000001)");
1284        assert_eq!(format!("{:?}", BitMask(15)), "BitMask(0000000f)");
1285        assert_eq!(format!("{:?}", BitMask(16)), "BitMask(00000010)");
1286        assert_eq!(format!("{:?}", BitMask(256)), "BitMask(00000100)");
1287        assert_eq!(format!("{:?}", BitMask(1 << 31)), "BitMask(80000000)");
1288    }
1289    #[test]
1290    fn test_bitmask_set_bit() {
1291        let mut mask = BitMask::none();
1292        mask.set_bit(0, true);
1293        assert!(mask.bit(0));
1294        assert_eq!(mask.to_string(), "10000000 00000000 00000000 00000000");
1295        mask.set_bit(3, true);
1296        assert!(mask.bit(3));
1297        assert_eq!(mask.to_string(), "10010000 00000000 00000000 00000000");
1298        mask.set_bit(0, false);
1299        assert!(!mask.bit(0));
1300        assert_eq!(mask.to_string(), "00010000 00000000 00000000 00000000");
1301    }
1302    #[test]
1303    fn test_bitmask_with() {
1304        let mask = BitMask::none().with(8);
1305        assert_eq!(mask.to_string(), "00000000 10000000 00000000 00000000");
1306        let mask = BitMask::all().without(8);
1307        assert_eq!(mask.to_string(), "11111111 01111111 11111111 11111111");
1308        let mask = BitMask::none().with(1).with(2).with(3);
1309        assert_eq!(mask.to_string(), "01110000 00000000 00000000 00000000");
1310    }
1311}