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