bevy_rapier3d/geometry/
mod.rs

1pub use self::collider::*;
2pub use self::shape_views::ColliderView;
3pub use rapier::geometry::SolverFlags;
4pub use rapier::parry::query::{ShapeCastOptions, ShapeCastStatus};
5pub use rapier::parry::shape::TriMeshFlags;
6pub use rapier::parry::transformation::{vhacd::VHACDParameters, voxelization::FillMode};
7
8use crate::math::{Real, Vect};
9use rapier::prelude::FeatureId;
10
11mod collider;
12mod collider_impl;
13/// Wrappers around Rapier shapes to access their properties.
14pub mod shape_views;
15#[cfg(feature = "to-bevy-mesh")]
16pub mod to_bevy_mesh;
17
18/// Result of the projection of a point on a shape.
19#[derive(Copy, Clone, Debug, PartialEq)]
20pub struct PointProjection {
21    /// Whether or not the point to project was inside of the shape.
22    pub is_inside: bool,
23    /// The projection result.
24    pub point: Vect,
25}
26
27impl PointProjection {
28    pub(crate) fn from_rapier(raw: rapier::parry::query::PointProjection) -> Self {
29        Self {
30            is_inside: raw.is_inside,
31            point: raw.point.into(),
32        }
33    }
34}
35impl From<rapier::parry::query::PointProjection> for PointProjection {
36    fn from(projection: rapier::parry::query::PointProjection) -> PointProjection {
37        PointProjection {
38            is_inside: projection.is_inside,
39            point: projection.point.into(),
40        }
41    }
42}
43
44/// Structure containing the result of a successful ray cast.
45#[derive(Copy, Clone, Debug, PartialEq)]
46pub struct RayIntersection {
47    /// The time of impact of the ray with the object.  The exact contact point can be computed
48    /// with `origin + dir * time_of_impact` where `origin` is the origin of the ray;
49    /// `dir` is its direction and `time_of_impact` is the value of this field.
50    pub time_of_impact: Real,
51
52    /// The intersection point between the ray and the object.
53    pub point: Vect,
54
55    /// The normal at the intersection point.
56    ///
57    /// If the `toi` is exactly zero, the normal might not be reliable.
58    pub normal: Vect,
59
60    /// Feature at the intersection point.
61    pub feature: FeatureId,
62}
63
64impl RayIntersection {
65    pub(crate) fn from_rapier(
66        inter: rapier::parry::query::RayIntersection,
67        unscaled_origin: Vect,
68        unscaled_dir: Vect,
69    ) -> Self {
70        Self {
71            time_of_impact: inter.time_of_impact,
72            point: unscaled_origin + unscaled_dir * inter.time_of_impact,
73            normal: inter.normal.into(),
74            feature: inter.feature,
75        }
76    }
77}
78
79/// The result of a shape cast.
80#[derive(Copy, Clone, Debug, PartialEq)]
81pub struct ShapeCastHit {
82    /// The time at which the objects touch.
83    pub time_of_impact: Real,
84    /// Detail about the impact points.
85    ///
86    /// `None` if `status` is `PenetratingOrWithinTargetDist` and
87    /// [`ShapeCastOptions::compute_impact_geometry_on_penetration`] was `false`.
88    pub details: Option<ShapeCastHitDetails>,
89    /// The way the time-of-impact computation algorithm terminated.
90    pub status: ShapeCastStatus,
91}
92
93/// In depth information about a shape-cast hit.
94#[derive(Copy, Clone, Debug, PartialEq)]
95pub struct ShapeCastHitDetails {
96    /// The local-space closest point on the first shape at the time of impact.
97    pub witness1: Vect,
98    /// The local-space closest point on the second shape at the time of impact.
99    pub witness2: Vect,
100    /// The local-space outward normal on the first shape at the time of impact.
101    pub normal1: Vect,
102    /// The local-space outward normal on the second shape at the time of impact.
103    pub normal2: Vect,
104}
105
106impl ShapeCastHit {
107    /// Convert from internal `rapier::query::ShapeCastHit`.
108    pub fn from_rapier(
109        hit: rapier::parry::query::ShapeCastHit,
110        details_always_computed: bool,
111    ) -> Self {
112        let details = match (details_always_computed, hit.status) {
113            (_, ShapeCastStatus::Failed) => None,
114            (false, ShapeCastStatus::PenetratingOrWithinTargetDist) => None,
115            _ => Some(ShapeCastHitDetails {
116                witness1: hit.witness1.into(),
117                witness2: hit.witness2.into(),
118                normal1: hit.normal1.into(),
119                normal2: hit.normal2.into(),
120            }),
121        };
122        Self {
123            time_of_impact: hit.time_of_impact,
124            status: hit.status,
125            details,
126        }
127    }
128}