nphysics3d 0.24.0

3-dimensional physics engine in Rust. This crate is being superseded by the rapier3d crate.
Documentation
use na::{self, RealField};

/// Parameters for a time-step of the physics engine.
#[derive(Clone)]
pub struct IntegrationParameters<N: RealField + Copy> {
    /// The timestep (default: `1.0 / 60.0`)
    dt: N,
    /// The inverse of `dt`.
    inv_dt: N,
    /// 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 total elapsed time in the physics world.
    ///
    /// This is the accumulation of the `dt` of all the calls to `world.step()`.
    pub t: N,
    /// 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: N,
    /// 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: N,
    /// 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: N,
    /// Ammount of penetration the engine wont attempt to correct (default: `0.001m`).
    pub allowed_linear_error: N,
    /// Ammount of angular drift of joint limits the engine wont
    /// attempt to correct (default: `0.001rad`).
    pub allowed_angular_error: N,
    /// Maximum linear correction during one step of the non-linear position solver (default: `0.2`).
    pub max_linear_correction: N,
    /// Maximum angular correction during one step of the non-linear position solver (default: `0.2`).
    pub max_angular_correction: N,
    /// 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: N,
    /// Maximum number of iterations performed by the velocity constraints solver (default: `8`).
    pub max_velocity_iterations: usize,
    /// Maximum number of iterations performed by the position-based constraints solver (default: `3`).
    pub max_position_iterations: 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
    /// seperate 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<N: RealField + Copy> IntegrationParameters<N> {
    /// Creates a set of integration parameters with the given values.
    pub fn new(
        dt: N,
        erp: N,
        warmstart_coeff: N,
        restitution_velocity_threshold: N,
        allowed_linear_error: N,
        allowed_angular_error: N,
        max_linear_correction: N,
        max_angular_correction: N,
        max_stabilization_multiplier: N,
        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 {
            t: N::zero(),
            dt,
            inv_dt: if dt == N::zero() {
                N::zero()
            } else {
                N::one() / dt
            },
            erp,
            warmstart_coeff,
            restitution_velocity_threshold,
            allowed_linear_error,
            allowed_angular_error,
            max_linear_correction,
            max_angular_correction,
            max_stabilization_multiplier,
            max_velocity_iterations,
            max_position_iterations,
            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) -> N {
        self.dt
    }

    /// The inverse of the time-stepping length.
    ///
    /// This is zero if `self.dt` is zero.
    #[inline(always)]
    pub fn inv_dt(&self) -> N {
        self.inv_dt
    }

    /// Sets the time-stepping length.
    ///
    /// This automatically recompute `self.inv_dt`.
    #[inline]
    pub fn set_dt(&mut self, dt: N) {
        assert!(
            dt >= N::zero(),
            "The time-stepping length cannot be negative."
        );
        self.dt = dt;
        if dt == N::zero() {
            self.inv_dt = N::zero()
        } else {
            self.inv_dt = N::one() / 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: N) {
        self.inv_dt = inv_dt;
        if inv_dt == N::zero() {
            self.dt = N::zero()
        } else {
            self.dt = N::one() / inv_dt
        }
    }
}

impl<N: RealField + Copy> Default for IntegrationParameters<N> {
    fn default() -> Self {
        Self::new(
            na::convert(1.0 / 60.0),
            na::convert(0.2),
            na::convert(1.0),
            na::convert(1.0),
            na::convert(0.001),
            na::convert(0.001),
            na::convert(0.2),
            na::convert(0.2),
            na::convert(0.2),
            8,
            3,
            10,
            1,
            false,
            false,
            false,
        )
    }
}