nphysics2d/solver/
integration_parameters.rs

1use na::{self, RealField};
2
3/// Parameters for a time-step of the physics engine.
4#[derive(Clone)]
5pub struct IntegrationParameters<N: RealField + Copy> {
6    /// The timestep (default: `1.0 / 60.0`)
7    dt: N,
8    /// The inverse of `dt`.
9    inv_dt: N,
10    /// If `true`, the world's `step` method will stop right after resolving exactly one CCD event (default: `false`).
11    /// This allows the user to take action during a timestep, in-between two CCD events.
12    pub return_after_ccd_substep: bool,
13    /// The total elapsed time in the physics world.
14    ///
15    /// This is the accumulation of the `dt` of all the calls to `world.step()`.
16    pub t: N,
17    /// The Error Reduction Parameter in `[0, 1]` is the proportion of
18    /// the positional error to be corrected at each time step (default: `0.2`).
19    pub erp: N,
20    /// Each cached impulse are multiplied by this coefficient in `[0, 1]`
21    /// when they are re-used to initialize the solver (default `1.0`).
22    pub warmstart_coeff: N,
23    /// Contacts at points where the involved bodies have a relative
24    /// velocity smaller than this threshold wont be affected by the restitution force (default: `1.0`).
25    pub restitution_velocity_threshold: N,
26    /// Ammount of penetration the engine wont attempt to correct (default: `0.001m`).
27    pub allowed_linear_error: N,
28    /// Ammount of angular drift of joint limits the engine wont
29    /// attempt to correct (default: `0.001rad`).
30    pub allowed_angular_error: N,
31    /// Maximum linear correction during one step of the non-linear position solver (default: `0.2`).
32    pub max_linear_correction: N,
33    /// Maximum angular correction during one step of the non-linear position solver (default: `0.2`).
34    pub max_angular_correction: N,
35    /// Maximum nonlinear SOR-prox scaling parameter when the constraint
36    /// correction direction is close to the kernel of the involved multibody's
37    /// jacobian (default: `0.2`).
38    pub max_stabilization_multiplier: N,
39    /// Maximum number of iterations performed by the velocity constraints solver (default: `8`).
40    pub max_velocity_iterations: usize,
41    /// Maximum number of iterations performed by the position-based constraints solver (default: `3`).
42    pub max_position_iterations: usize,
43    /// Maximum number of iterations performed by the position-based constraints solver for CCD steps (default: `10`).
44    ///
45    /// This should be sufficiently high so all penetration get resolved. For example, if CCD cause your
46    /// objects to stutter, that may be because the number of CCD position iterations is too low, causing
47    /// them to remain stuck in a penetration configuration for a few frames.
48    ///
49    /// The highest this number, the highest its computational cost.
50    pub max_ccd_position_iterations: usize,
51    /// Maximum number of substeps performed by the  solver (default: `1`).
52    pub max_ccd_substeps: usize,
53    /// Controls the number of Proximity::Intersecting events generated by a trigger during CCD resolution (default: `false`).
54    ///
55    /// If false, triggers will only generate one Proximity::Intersecting event during a step, even
56    /// if another colliders repeatedly enters and leaves the triggers during multiple CCD substeps.
57    ///
58    /// If true, triggers will generate as many Proximity::Intersecting and Proximity::Disjoint/Proximity::WithinMargin
59    /// events as the number of times a collider repeatedly enters and leaves the triggers during multiple CCD substeps.
60    /// This is more computationally intensive.
61    pub multiple_ccd_substep_sensor_events_enabled: bool,
62    /// Whether penetration are taken into account in CCD resolution (default: `false`).
63    ///
64    /// If this is set to `false` two penetrating colliders will not be considered to have any time of impact
65    /// while they are penetrating. This may end up allowing some tunelling, but will avoid stuttering effect
66    /// when the constraints solver fails to completely separate two colliders after a CCD contact.
67    ///
68    /// If this is set to `true`, two penetrating colliders will be considered to have a time of impact
69    /// equal to 0 until the constraints solver manages to separate them. This will prevent tunnelling
70    /// almost completely, but may introduce stuttering effects when the constraints solver fails to completely
71    /// seperate two colliders after a CCD contact.
72    // FIXME: this is a very binary way of handling penetration.
73    // We should provide a more flexible solution by letting the user choose some
74    // minimal amount of movement applied to an object that get stuck.
75    pub ccd_on_penetration_enabled: bool,
76}
77
78impl<N: RealField + Copy> IntegrationParameters<N> {
79    /// Creates a set of integration parameters with the given values.
80    pub fn new(
81        dt: N,
82        erp: N,
83        warmstart_coeff: N,
84        restitution_velocity_threshold: N,
85        allowed_linear_error: N,
86        allowed_angular_error: N,
87        max_linear_correction: N,
88        max_angular_correction: N,
89        max_stabilization_multiplier: N,
90        max_velocity_iterations: usize,
91        max_position_iterations: usize,
92        max_ccd_position_iterations: usize,
93        max_ccd_substeps: usize,
94        return_after_ccd_substep: bool,
95        multiple_ccd_substep_sensor_events_enabled: bool,
96        ccd_on_penetration_enabled: bool,
97    ) -> Self {
98        IntegrationParameters {
99            t: N::zero(),
100            dt,
101            inv_dt: if dt == N::zero() {
102                N::zero()
103            } else {
104                N::one() / dt
105            },
106            erp,
107            warmstart_coeff,
108            restitution_velocity_threshold,
109            allowed_linear_error,
110            allowed_angular_error,
111            max_linear_correction,
112            max_angular_correction,
113            max_stabilization_multiplier,
114            max_velocity_iterations,
115            max_position_iterations,
116            max_ccd_position_iterations,
117            max_ccd_substeps,
118            return_after_ccd_substep,
119            multiple_ccd_substep_sensor_events_enabled,
120            ccd_on_penetration_enabled,
121        }
122    }
123
124    /// The current time-stepping length.
125    #[inline(always)]
126    pub fn dt(&self) -> N {
127        self.dt
128    }
129
130    /// The inverse of the time-stepping length.
131    ///
132    /// This is zero if `self.dt` is zero.
133    #[inline(always)]
134    pub fn inv_dt(&self) -> N {
135        self.inv_dt
136    }
137
138    /// Sets the time-stepping length.
139    ///
140    /// This automatically recompute `self.inv_dt`.
141    #[inline]
142    pub fn set_dt(&mut self, dt: N) {
143        assert!(
144            dt >= N::zero(),
145            "The time-stepping length cannot be negative."
146        );
147        self.dt = dt;
148        if dt == N::zero() {
149            self.inv_dt = N::zero()
150        } else {
151            self.inv_dt = N::one() / dt
152        }
153    }
154
155    /// Sets the inverse time-stepping length (i.e. the frequency).
156    ///
157    /// This automatically recompute `self.dt`.
158    #[inline]
159    pub fn set_inv_dt(&mut self, inv_dt: N) {
160        self.inv_dt = inv_dt;
161        if inv_dt == N::zero() {
162            self.dt = N::zero()
163        } else {
164            self.dt = N::one() / inv_dt
165        }
166    }
167}
168
169impl<N: RealField + Copy> Default for IntegrationParameters<N> {
170    fn default() -> Self {
171        Self::new(
172            na::convert(1.0 / 60.0),
173            na::convert(0.2),
174            na::convert(1.0),
175            na::convert(1.0),
176            na::convert(0.001),
177            na::convert(0.001),
178            na::convert(0.2),
179            na::convert(0.2),
180            na::convert(0.2),
181            8,
182            3,
183            10,
184            1,
185            false,
186            false,
187            false,
188        )
189    }
190}