Skip to main content

bevy_rapier3d/dynamics/
mod.rs

1pub use self::generic_joint::*;
2pub use self::joint::*;
3pub use self::multibody::*;
4pub use self::rigid_body::*;
5pub use self::soft_body::*;
6
7pub use self::fixed_joint::*;
8pub use self::prismatic_joint::*;
9pub use self::revolute_joint::*;
10pub use self::rope_joint::*;
11pub use self::spring_joint::*;
12
13use bevy::reflect::Reflect;
14use rapier::dynamics::CoefficientCombineRule as RapierCoefficientCombineRule;
15
16#[cfg(feature = "dim2")]
17pub use self::pin_slot_joint::*;
18#[cfg(feature = "dim3")]
19pub use self::spherical_joint::*;
20
21mod generic_joint;
22mod joint;
23mod multibody;
24mod rigid_body;
25pub mod soft_body;
26
27mod fixed_joint;
28mod prismatic_joint;
29mod revolute_joint;
30mod rope_joint;
31
32#[cfg(feature = "dim2")]
33mod pin_slot_joint;
34#[cfg(feature = "dim3")]
35mod spherical_joint;
36mod spring_joint;
37
38/// Rules used to combine two coefficients.
39///
40/// This is used to determine the effective restitution and
41/// friction coefficients for a contact between two colliders.
42/// Each collider has its combination rule of type
43/// `CoefficientCombineRule`. And the rule
44/// actually used is given by `max(first_combine_rule as usize, second_combine_rule as usize)`,
45/// i.e., `GeometricMean > ClampedSum > Max > Multiply > Min > Average`.
46///
47/// It is set by the [`Friction`] and [`Restitution`] components of colliders, and applies to
48/// every contact between colliders, whether they are attached to a rigid-body or not.
49///
50/// [`Friction`]: crate::geometry::Friction
51/// [`Restitution`]: crate::geometry::Restitution
52#[derive(Copy, Clone, Debug, PartialEq, Eq, Reflect, Default)]
53#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
54pub enum CoefficientCombineRule {
55    #[default]
56    /// The two coefficients are averaged.
57    Average = 0,
58    /// The smallest coefficient is chosen.
59    Min,
60    /// The two coefficients are multiplied.
61    Multiply,
62    /// The greatest coefficient is chosen.
63    Max,
64    /// The sum of the two coefficients, clamped to the range `[0, 1]`.
65    ClampedSum,
66    /// The square root of the product of the two coefficients.
67    ///
68    /// This is zero if either coefficient is zero.
69    GeometricMean,
70}
71
72impl CoefficientCombineRule {
73    /// Combines two coefficients according to their respective combine rules.
74    ///
75    /// If the two rules differ, the one with the highest priority is used
76    /// (`GeometricMean > ClampedSum > Max > Multiply > Min > Average`).
77    pub fn combine(coeff1: f32, coeff2: f32, rule1: Self, rule2: Self) -> f32 {
78        RapierCoefficientCombineRule::combine(coeff1, coeff2, rule1.into(), rule2.into())
79    }
80}
81
82impl From<CoefficientCombineRule> for RapierCoefficientCombineRule {
83    fn from(combine_rule: CoefficientCombineRule) -> RapierCoefficientCombineRule {
84        match combine_rule {
85            CoefficientCombineRule::Average => RapierCoefficientCombineRule::Average,
86            CoefficientCombineRule::Min => RapierCoefficientCombineRule::Min,
87            CoefficientCombineRule::Multiply => RapierCoefficientCombineRule::Multiply,
88            CoefficientCombineRule::Max => RapierCoefficientCombineRule::Max,
89            CoefficientCombineRule::ClampedSum => RapierCoefficientCombineRule::ClampedSum,
90            CoefficientCombineRule::GeometricMean => RapierCoefficientCombineRule::GeometricMean,
91        }
92    }
93}
94
95impl From<RapierCoefficientCombineRule> for CoefficientCombineRule {
96    fn from(combine_rule: RapierCoefficientCombineRule) -> CoefficientCombineRule {
97        match combine_rule {
98            RapierCoefficientCombineRule::Average => CoefficientCombineRule::Average,
99            RapierCoefficientCombineRule::Min => CoefficientCombineRule::Min,
100            RapierCoefficientCombineRule::Multiply => CoefficientCombineRule::Multiply,
101            RapierCoefficientCombineRule::Max => CoefficientCombineRule::Max,
102            RapierCoefficientCombineRule::ClampedSum => CoefficientCombineRule::ClampedSum,
103            RapierCoefficientCombineRule::GeometricMean => CoefficientCombineRule::GeometricMean,
104        }
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::CoefficientCombineRule as Rule;
111
112    #[test]
113    fn combine_rules() {
114        assert_eq!(Rule::combine(0.2, 0.6, Rule::Average, Rule::Average), 0.4);
115        assert_eq!(Rule::combine(0.2, 0.6, Rule::Min, Rule::Average), 0.2);
116        assert_eq!(Rule::combine(0.5, 0.6, Rule::Multiply, Rule::Min), 0.3);
117        assert_eq!(Rule::combine(0.2, 0.6, Rule::Max, Rule::Multiply), 0.6);
118        assert_eq!(Rule::combine(0.7, 0.6, Rule::ClampedSum, Rule::Max), 1.0);
119        assert_eq!(
120            Rule::combine(0.2, 0.3, Rule::Average, Rule::ClampedSum),
121            0.5
122        );
123        assert_eq!(
124            Rule::combine(0.25, 1.0, Rule::ClampedSum, Rule::GeometricMean),
125            0.5
126        );
127        assert_eq!(
128            Rule::combine(0.0, 0.8, Rule::GeometricMean, Rule::Average),
129            0.0
130        );
131    }
132
133    #[test]
134    fn combine_rule_conversions_round_trip() {
135        for rule in [
136            Rule::Average,
137            Rule::Min,
138            Rule::Multiply,
139            Rule::Max,
140            Rule::ClampedSum,
141            Rule::GeometricMean,
142        ] {
143            let raw: rapier::dynamics::CoefficientCombineRule = rule.into();
144            assert_eq!(raw as u32, rule as u32);
145            assert_eq!(Rule::from(raw), rule);
146        }
147    }
148}