Skip to main content

bevy_rapier2d/reflect/
mod.rs

1use crate::math::Real;
2use bevy::reflect::reflect_remote;
3use rapier::{dynamics::IntegrationParameters, prelude::SpringCoefficients};
4
5#[cfg(feature = "dim3")]
6use rapier::dynamics::FrictionModel;
7
8/// Friction models used for all contact constraints between two rigid-bodies.
9///
10/// This selection does not apply to multibodies that always rely on the [`FrictionModel::Coulomb`].
11#[cfg(feature = "dim3")]
12#[reflect_remote(FrictionModel)]
13#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
14#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
15pub enum FrictionModelWrapper {
16    /// A simplified friction model significantly faster to solve than [`Self::Coulomb`]
17    /// but less accurate.
18    ///
19    /// Instead of solving one Coulomb friction constraint per contact in a contact manifold,
20    /// this approximation only solves one Coulomb friction constraint per group of 4 contacts
21    /// in a contact manifold, plus one "twist" constraint. The "twist" constraint is purely
22    /// rotational and aims to eliminate angular movement in the manifold’s tangent plane.
23    #[default]
24    Simplified,
25    /// The coulomb friction model.
26    ///
27    /// This results in one Coulomb friction constraint per contact point.
28    Coulomb,
29}
30
31#[reflect_remote(SpringCoefficients<Real>)]
32#[derive(Copy, Clone, Debug, PartialEq)]
33/// Coefficients for a spring, typically used for configuring constraint softness for contacts and
34/// joints.
35pub struct SpringCoefficientsWrapper {
36    /// Sets the natural frequency (Hz) of the spring-like constraint.
37    ///
38    /// Higher values make the constraint stiffer and resolve constraint violations more quickly.
39    pub natural_frequency: Real,
40    /// Sets the damping ratio for the spring-like constraint.
41    ///
42    /// Larger values make the joint more compliant (allowing more drift before stabilization).
43    pub damping_ratio: Real,
44}
45
46#[cfg(not(feature = "dim3"))]
47#[reflect_remote(IntegrationParameters)]
48#[derive(Copy, Clone, Debug, PartialEq)]
49/// Parameters for a time-step of the physics engine.
50pub struct IntegrationParametersWrapper {
51    /// The timestep length (default: `1.0 / 60.0`).
52    pub dt: Real,
53    /// Minimum timestep size when using CCD with multiple substeps (default: `1.0 / 60.0 / 100.0`).
54    ///
55    /// When CCD with multiple substeps is enabled, the timestep is subdivided
56    /// into smaller pieces. This timestep subdivision won't generate timestep
57    /// lengths smaller than `min_ccd_dt`.
58    ///
59    /// Setting this to a large value will reduce the opportunity to performing
60    /// CCD substepping, resulting in potentially more time dropped by the
61    /// motion-clamping mechanism. Setting this to an very small value may lead
62    /// to numerical instabilities.
63    pub min_ccd_dt: Real,
64
65    /// Softness coefficients for contact constraints.
66    #[reflect(remote = SpringCoefficientsWrapper)]
67    pub contact_softness: SpringCoefficients<Real>,
68
69    /// Softness coefficients for contact constraints where one side is a fixed body.
70    ///
71    /// Stiffer than [`IntegrationParameters::contact_softness`] by default so bodies are
72    /// held firmly against static walls/floors; set equal to
73    /// [`IntegrationParameters::contact_softness`] to disable.
74    #[reflect(remote = SpringCoefficientsWrapper)]
75    pub static_contact_softness: SpringCoefficients<Real>,
76
77    /// The coefficient in `[0, 1]` applied to warmstart impulses, i.e., impulses that are used as the
78    /// initial solution (instead of 0) at the next simulation step.
79    ///
80    /// This should generally be set to 1.
81    ///
82    /// (default `1.0`).
83    pub warmstart_coefficient: Real,
84
85    /// The approximate size of most dynamic objects in the scene.
86    ///
87    /// This value is used internally to estimate some length-based tolerance. In particular, the
88    /// values [`IntegrationParameters::allowed_linear_error`],
89    /// [`IntegrationParameters::max_corrective_velocity`],
90    /// [`IntegrationParameters::prediction_distance`], [`RigidBodyActivation::normalized_linear_threshold`]
91    /// are scaled by this value implicitly.
92    ///
93    /// This value can be understood as the number of units-per-meter in your physical world compared
94    /// to a human-sized world in meter. For example, in a 2d game, if your typical object size is 100
95    /// pixels, set the [`Self::length_unit`] parameter to 100.0. The physics engine will interpret
96    /// it as if 100 pixels is equivalent to 1 meter in its various internal threshold.
97    /// (default `1.0`).
98    pub length_unit: Real,
99
100    /// Amount of penetration the engine won’t attempt to correct (default: `0.001m`).
101    ///
102    /// This value is implicitly scaled by [`IntegrationParameters::length_unit`].
103    pub normalized_allowed_linear_error: Real,
104    /// Maximum amount of penetration the solver will attempt to resolve in one timestep (default: `10.0`).
105    ///
106    /// This value is implicitly scaled by [`IntegrationParameters::length_unit`].
107    pub normalized_max_corrective_velocity: Real,
108    /// The maximal distance separating two objects that will generate predictive contacts (default: `0.002m`).
109    ///
110    /// This value is implicitly scaled by [`IntegrationParameters::length_unit`].
111    pub normalized_prediction_distance: Real,
112    /// Maximum linear velocity a body may have after each solver substep (default: `400.0` m/s).
113    ///
114    /// This value is implicitly scaled by [`IntegrationParameters::length_unit`].
115    pub normalized_max_linear_velocity: Real,
116    /// The number of solver iterations run by the constraints solver for calculating forces (default: `4`).
117    pub num_solver_iterations: usize,
118    /// Number of internal Project Gauss Seidel (PGS) iterations run at each solver iteration (default: `1`).
119    pub num_internal_pgs_iterations: usize,
120    /// The number of stabilization iterations run at each solver iterations (default: `1`).
121    pub num_internal_stabilization_iterations: usize,
122    /// Maximum number of substeps performed by the  solver (default: `1`).
123    pub max_ccd_substeps: usize,
124    /// If enabled, contact manifolds of a collider pair sharing (nearly) the same normal are
125    /// merged into one "cluster" manifold before constraint generation (default: `true`, 3D only).
126    pub contact_clustering: bool,
127    /// If enabled, a contact pair that barely moved since its last full narrow-phase update
128    /// skips contact determination and keeps its existing contact points (default: `true`).
129    pub contact_recycling: bool,
130    /// Maximum relative-pose drift below which a contact pair may be recycled instead of fully
131    /// updated (default: `0.05`). Only used when contact recycling is enabled.
132    ///
133    /// This value is implicitly scaled by [`IntegrationParameters::length_unit`].
134    pub normalized_contact_recycle_distance: Real,
135    /// If `false`, friction is only solved during the unbiased (relax) pass of each substep
136    /// instead of both passes (default: `false`).
137    pub friction_in_bias_pass: bool,
138    /// If enabled, impulse-joint constraints are warm-started like contacts (default: `false`).
139    pub warmstart_joints: bool,
140}
141
142// These structs are duplicated in their entirety due to [`FrictionModel`] not being available in 2D, and `bevy::reflect_remote` not supporting conditional fields.
143#[cfg(feature = "dim3")]
144#[reflect_remote(IntegrationParameters)]
145#[derive(Copy, Clone, Debug, PartialEq)]
146/// Parameters for a time-step of the physics engine.
147pub struct IntegrationParametersWrapper {
148    /// The timestep length (default: `1.0 / 60.0`).
149    pub dt: Real,
150    /// Minimum timestep size when using CCD with multiple substeps (default: `1.0 / 60.0 / 100.0`).
151    ///
152    /// When CCD with multiple substeps is enabled, the timestep is subdivided
153    /// into smaller pieces. This timestep subdivision won't generate timestep
154    /// lengths smaller than `min_ccd_dt`.
155    ///
156    /// Setting this to a large value will reduce the opportunity to performing
157    /// CCD substepping, resulting in potentially more time dropped by the
158    /// motion-clamping mechanism. Setting this to an very small value may lead
159    /// to numerical instabilities.
160    pub min_ccd_dt: Real,
161
162    /// Softness coefficients for contact constraints.
163    #[reflect(remote = SpringCoefficientsWrapper)]
164    pub contact_softness: SpringCoefficients<Real>,
165
166    /// Softness coefficients for contact constraints where one side is a fixed body.
167    ///
168    /// Stiffer than [`IntegrationParameters::contact_softness`] by default so bodies are
169    /// held firmly against static walls/floors; set equal to
170    /// [`IntegrationParameters::contact_softness`] to disable.
171    #[reflect(remote = SpringCoefficientsWrapper)]
172    pub static_contact_softness: SpringCoefficients<Real>,
173
174    /// The coefficient in `[0, 1]` applied to warmstart impulses, i.e., impulses that are used as the
175    /// initial solution (instead of 0) at the next simulation step.
176    ///
177    /// This should generally be set to 1.
178    ///
179    /// (default `1.0`).
180    pub warmstart_coefficient: Real,
181
182    /// The approximate size of most dynamic objects in the scene.
183    ///
184    /// This value is used internally to estimate some length-based tolerance. In particular, the
185    /// values [`IntegrationParameters::allowed_linear_error`],
186    /// [`IntegrationParameters::max_corrective_velocity`],
187    /// [`IntegrationParameters::prediction_distance`], [`RigidBodyActivation::normalized_linear_threshold`]
188    /// are scaled by this value implicitly.
189    ///
190    /// This value can be understood as the number of units-per-meter in your physical world compared
191    /// to a human-sized world in meter. For example, in a 2d game, if your typical object size is 100
192    /// pixels, set the [`Self::length_unit`] parameter to 100.0. The physics engine will interpret
193    /// it as if 100 pixels is equivalent to 1 meter in its various internal threshold.
194    /// (default `1.0`).
195    pub length_unit: Real,
196
197    /// Amount of penetration the engine won’t attempt to correct (default: `0.001m`).
198    ///
199    /// This value is implicitly scaled by [`IntegrationParameters::length_unit`].
200    pub normalized_allowed_linear_error: Real,
201    /// Maximum amount of penetration the solver will attempt to resolve in one timestep (default: `10.0`).
202    ///
203    /// This value is implicitly scaled by [`IntegrationParameters::length_unit`].
204    pub normalized_max_corrective_velocity: Real,
205    /// The maximal distance separating two objects that will generate predictive contacts (default: `0.002m`).
206    ///
207    /// This value is implicitly scaled by [`IntegrationParameters::length_unit`].
208    pub normalized_prediction_distance: Real,
209    /// Maximum linear velocity a body may have after each solver substep (default: `400.0` m/s).
210    ///
211    /// This value is implicitly scaled by [`IntegrationParameters::length_unit`].
212    pub normalized_max_linear_velocity: Real,
213    /// The number of solver iterations run by the constraints solver for calculating forces (default: `4`).
214    pub num_solver_iterations: usize,
215    /// Number of internal Project Gauss Seidel (PGS) iterations run at each solver iteration (default: `1`).
216    pub num_internal_pgs_iterations: usize,
217    /// The number of stabilization iterations run at each solver iterations (default: `1`).
218    pub num_internal_stabilization_iterations: usize,
219    /// Maximum number of substeps performed by the  solver (default: `1`).
220    pub max_ccd_substeps: usize,
221    /// If enabled, contact manifolds of a collider pair sharing (nearly) the same normal are
222    /// merged into one "cluster" manifold before constraint generation (default: `true`, 3D only).
223    pub contact_clustering: bool,
224    /// If enabled, a contact pair that barely moved since its last full narrow-phase update
225    /// skips contact determination and keeps its existing contact points (default: `true`).
226    pub contact_recycling: bool,
227    /// Maximum relative-pose drift below which a contact pair may be recycled instead of fully
228    /// updated (default: `0.05`). Only used when contact recycling is enabled.
229    ///
230    /// This value is implicitly scaled by [`IntegrationParameters::length_unit`].
231    pub normalized_contact_recycle_distance: Real,
232    /// If `false`, friction is only solved during the unbiased (relax) pass of each substep
233    /// instead of both passes (default: `false`).
234    pub friction_in_bias_pass: bool,
235    /// If enabled, impulse-joint constraints are warm-started like contacts (default: `false`).
236    pub warmstart_joints: bool,
237    /// Friction models used for all contact constraints between two rigid-bodies.
238    #[reflect(remote = FrictionModelWrapper)]
239    pub friction_model: FrictionModel,
240}