diff options
| author | Sébastien Crozet <developer@crozet.re> | 2020-08-25 22:10:25 +0200 |
|---|---|---|
| committer | Sébastien Crozet <developer@crozet.re> | 2020-08-25 22:10:25 +0200 |
| commit | 754a48b7ff6d8c58b1ee08651e60112900b60455 (patch) | |
| tree | 7d777a6c003f1f5d8f8d24f533f35a95a88957fe /src/dynamics/integration_parameters.rs | |
| download | rapier-754a48b7ff6d8c58b1ee08651e60112900b60455.tar.gz rapier-754a48b7ff6d8c58b1ee08651e60112900b60455.tar.bz2 rapier-754a48b7ff6d8c58b1ee08651e60112900b60455.zip | |
First public release of Rapier.v0.1.0
Diffstat (limited to 'src/dynamics/integration_parameters.rs')
| -rw-r--r-- | src/dynamics/integration_parameters.rs | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/src/dynamics/integration_parameters.rs b/src/dynamics/integration_parameters.rs new file mode 100644 index 0000000..faf22e1 --- /dev/null +++ b/src/dynamics/integration_parameters.rs @@ -0,0 +1,207 @@ +/// Parameters for a time-step of the physics engine. +#[derive(Clone)] +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +pub struct IntegrationParameters { + /// The timestep (default: `1.0 / 60.0`) + dt: f32, + /// The inverse of `dt`. + inv_dt: f32, + // /// If `true` and if rapier is compiled with the `parallel` feature, this will enable rayon-based multithreading (default: `true`). + // /// + // /// This parameter is ignored if rapier is not compiled with is `parallel` feature. + // /// Refer to rayon's documentation regarding how to configure the number of threads with either + // /// `rayon::ThreadPoolBuilder::new().num_threads(4).build_global().unwrap()` or `ThreadPool::install`. + // /// Note that using only one thread with `multithreading_enabled` set to `true` will result on a slower + // /// simulation than setting `multithreading_enabled` to `false`. + // pub multithreading_enabled: bool, + /// If `true`, the world's `step` method will stop right after resolving exactly one CCD event (default: `false`). + /// This allows the user to take action during a timestep, in-between two CCD events. + pub return_after_ccd_substep: bool, + /// The Error Reduction Parameter in `[0, 1]` is the proportion of + /// the positional error to be corrected at each time step (default: `0.2`). + pub erp: f32, + /// The Error Reduction Parameter for joints in `[0, 1]` is the proportion of + /// the positional error to be corrected at each time step (default: `0.2`). + pub joint_erp: f32, + /// Each cached impulse are multiplied by this coefficient in `[0, 1]` + /// when they are re-used to initialize the solver (default `1.0`). + pub warmstart_coeff: f32, + /// Contacts at points where the involved bodies have a relative + /// velocity smaller than this threshold wont be affected by the restitution force (default: `1.0`). + pub restitution_velocity_threshold: f32, + /// Amount of penetration the engine wont attempt to correct (default: `0.001m`). + pub allowed_linear_error: f32, + /// The maximal distance separating two objects that will generate predictive contacts (default: `0.002`). + pub prediction_distance: f32, + /// Amount of angular drift of joint limits the engine wont + /// attempt to correct (default: `0.001rad`). + pub allowed_angular_error: f32, + /// Maximum linear correction during one step of the non-linear position solver (default: `0.2`). + pub max_linear_correction: f32, + /// Maximum angular correction during one step of the non-linear position solver (default: `0.2`). + pub max_angular_correction: f32, + /// Maximum nonlinear SOR-prox scaling parameter when the constraint + /// correction direction is close to the kernel of the involved multibody's + /// jacobian (default: `0.2`). + pub max_stabilization_multiplier: f32, + /// Maximum number of iterations performed by the velocity constraints solver (default: `4`). + pub max_velocity_iterations: usize, + /// Maximum number of iterations performed by the position-based constraints solver (default: `1`). + pub max_position_iterations: usize, + /// Minimum number of dynamic bodies in each active island (default: `128`). + pub min_island_size: usize, + /// Maximum number of iterations performed by the position-based constraints solver for CCD steps (default: `10`). + /// + /// This should be sufficiently high so all penetration get resolved. For example, if CCD cause your + /// objects to stutter, that may be because the number of CCD position iterations is too low, causing + /// them to remain stuck in a penetration configuration for a few frames. + /// + /// The highest this number, the highest its computational cost. + pub max_ccd_position_iterations: usize, + /// Maximum number of substeps performed by the solver (default: `1`). + pub max_ccd_substeps: usize, + /// Controls the number of Proximity::Intersecting events generated by a trigger during CCD resolution (default: `false`). + /// + /// If false, triggers will only generate one Proximity::Intersecting event during a step, even + /// if another colliders repeatedly enters and leaves the triggers during multiple CCD substeps. + /// + /// If true, triggers will generate as many Proximity::Intersecting and Proximity::Disjoint/Proximity::WithinMargin + /// events as the number of times a collider repeatedly enters and leaves the triggers during multiple CCD substeps. + /// This is more computationally intensive. + pub multiple_ccd_substep_sensor_events_enabled: bool, + /// Whether penetration are taken into account in CCD resolution (default: `false`). + /// + /// If this is set to `false` two penetrating colliders will not be considered to have any time of impact + /// while they are penetrating. This may end up allowing some tunelling, but will avoid stuttering effect + /// when the constraints solver fails to completely separate two colliders after a CCD contact. + /// + /// If this is set to `true`, two penetrating colliders will be considered to have a time of impact + /// equal to 0 until the constraints solver manages to separate them. This will prevent tunnelling + /// almost completely, but may introduce stuttering effects when the constraints solver fails to completely + /// separate two colliders after a CCD contact. + // FIXME: this is a very binary way of handling penetration. + // We should provide a more flexible solution by letting the user choose some + // minimal amount of movement applied to an object that get stuck. + pub ccd_on_penetration_enabled: bool, +} + +impl IntegrationParameters { + /// Creates a set of integration parameters with the given values. + pub fn new( + dt: f32, + // multithreading_enabled: bool, + erp: f32, + joint_erp: f32, + warmstart_coeff: f32, + restitution_velocity_threshold: f32, + allowed_linear_error: f32, + allowed_angular_error: f32, + max_linear_correction: f32, + max_angular_correction: f32, + prediction_distance: f32, + max_stabilization_multiplier: f32, + max_velocity_iterations: usize, + max_position_iterations: usize, + max_ccd_position_iterations: usize, + max_ccd_substeps: usize, + return_after_ccd_substep: bool, + multiple_ccd_substep_sensor_events_enabled: bool, + ccd_on_penetration_enabled: bool, + ) -> Self { + IntegrationParameters { + dt, + inv_dt: if dt == 0.0 { 0.0 } else { 1.0 / dt }, + // multithreading_enabled, + erp, + joint_erp, + warmstart_coeff, + restitution_velocity_threshold, + allowed_linear_error, + allowed_angular_error, + max_linear_correction, + max_angular_correction, + prediction_distance, + max_stabilization_multiplier, + max_velocity_iterations, + max_position_iterations, + // FIXME: what is the optimal value for min_island_size? + // It should not be too big so that we don't end up with + // huge islands that don't fit in cache. + // However we don't want it to be too small and end up with + // tons of islands, reducing SIMD parallelism opportunities. + min_island_size: 128, + max_ccd_position_iterations, + max_ccd_substeps, + return_after_ccd_substep, + multiple_ccd_substep_sensor_events_enabled, + ccd_on_penetration_enabled, + } + } + + /// The current time-stepping length. + #[inline(always)] + pub fn dt(&self) -> f32 { + self.dt + } + + /// The inverse of the time-stepping length. + /// + /// This is zero if `self.dt` is zero. + #[inline(always)] + pub fn inv_dt(&self) -> f32 { + self.inv_dt + } + + /// Sets the time-stepping length. + /// + /// This automatically recompute `self.inv_dt`. + #[inline] + pub fn set_dt(&mut self, dt: f32) { + assert!(dt >= 0.0, "The time-stepping length cannot be negative."); + self.dt = dt; + if dt == 0.0 { + self.inv_dt = 0.0 + } else { + self.inv_dt = 1.0 / dt + } + } + + /// Sets the inverse time-stepping length (i.e. the frequency). + /// + /// This automatically recompute `self.dt`. + #[inline] + pub fn set_inv_dt(&mut self, inv_dt: f32) { + self.inv_dt = inv_dt; + if inv_dt == 0.0 { + self.dt = 0.0 + } else { + self.dt = 1.0 / inv_dt + } + } +} + +impl Default for IntegrationParameters { + fn default() -> Self { + Self::new( + 1.0 / 60.0, + // true, + 0.2, + 0.2, + 1.0, + 1.0, + 0.005, + 0.001, + 0.2, + 0.2, + 0.002, + 0.2, + 4, + 1, + 10, + 1, + false, + false, + false, + ) + } +} |
