#[cfg(doc)]
use super::RigidBodyActivation;
use crate::math::Real;
use simba::simd::SimdRealField;
pub(crate) static BLOCK_SOLVER_ENABLED: bool = cfg!(feature = "dim2");
#[cfg(feature = "dim3")]
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub enum FrictionModel {
#[default]
Simplified,
Coulomb,
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct SpringCoefficients<N> {
pub natural_frequency: N,
pub damping_ratio: N,
}
impl<N: SimdRealField<Element = Real> + Copy> SpringCoefficients<N> {
pub fn new(natural_frequency: N, damping_ratio: N) -> Self {
Self {
natural_frequency,
damping_ratio,
}
}
pub fn contact_defaults() -> Self {
Self {
natural_frequency: N::splat(30.0),
damping_ratio: N::splat(5.0),
}
}
pub fn joint_defaults() -> Self {
Self {
natural_frequency: N::splat(1.0e6),
damping_ratio: N::splat(1.0),
}
}
pub fn angular_frequency(&self) -> N {
self.natural_frequency * N::simd_two_pi()
}
pub fn erp_inv_dt(&self, dt: N) -> N {
let ang_freq = self.angular_frequency();
ang_freq / (dt * ang_freq + N::splat(2.0) * self.damping_ratio)
}
pub fn erp(&self, dt: N) -> N {
dt * self.erp_inv_dt(dt)
}
pub fn cfm_coeff(&self, dt: N) -> N {
let one = N::one();
let erp = self.erp(dt);
let erp_is_not_zero = erp.simd_ne(N::zero());
let inv_erp_minus_one = one / erp - one;
let result = inv_erp_minus_one * inv_erp_minus_one
/ ((one + inv_erp_minus_one) * N::splat(4.0) * self.damping_ratio * self.damping_ratio);
result.select(erp_is_not_zero, N::zero())
}
pub fn cfm_factor(&self, dt: N) -> N {
let one = N::one();
let cfm_coeff = self.cfm_coeff(dt);
one / (one + cfm_coeff)
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct IntegrationParameters {
pub dt: Real,
pub min_ccd_dt: Real,
pub contact_softness: SpringCoefficients<Real>,
pub warmstart_coefficient: Real,
pub length_unit: Real,
pub normalized_allowed_linear_error: Real,
pub normalized_max_corrective_velocity: Real,
pub normalized_prediction_distance: Real,
pub num_solver_iterations: usize,
pub num_internal_pgs_iterations: usize,
pub num_internal_stabilization_iterations: usize,
pub min_island_size: usize,
pub max_ccd_substeps: usize,
#[cfg(feature = "dim3")]
pub friction_model: FrictionModel,
}
impl IntegrationParameters {
#[inline]
pub fn inv_dt(&self) -> Real {
if self.dt == 0.0 { 0.0 } else { 1.0 / self.dt }
}
#[inline]
#[deprecated = "You can just set the `IntegrationParams::dt` value directly"]
pub fn set_dt(&mut self, dt: Real) {
assert!(dt >= 0.0, "The time-stepping length cannot be negative.");
self.dt = dt;
}
#[inline]
pub fn set_inv_dt(&mut self, inv_dt: Real) {
if inv_dt == 0.0 {
self.dt = 0.0
} else {
self.dt = 1.0 / inv_dt
}
}
pub fn allowed_linear_error(&self) -> Real {
self.normalized_allowed_linear_error * self.length_unit
}
pub fn max_corrective_velocity(&self) -> Real {
if self.normalized_max_corrective_velocity != Real::MAX {
self.normalized_max_corrective_velocity * self.length_unit
} else {
Real::MAX
}
}
pub fn prediction_distance(&self) -> Real {
self.normalized_prediction_distance * self.length_unit
}
}
impl Default for IntegrationParameters {
fn default() -> Self {
Self {
dt: 1.0 / 60.0,
min_ccd_dt: 1.0 / 60.0 / 100.0,
contact_softness: SpringCoefficients::contact_defaults(),
warmstart_coefficient: 1.0,
num_internal_pgs_iterations: 1,
num_internal_stabilization_iterations: 1,
num_solver_iterations: 4,
min_island_size: 128,
normalized_allowed_linear_error: 0.001,
normalized_max_corrective_velocity: 10.0,
normalized_prediction_distance: 0.002,
max_ccd_substeps: 1,
length_unit: 1.0,
#[cfg(feature = "dim3")]
friction_model: FrictionModel::default(),
}
}
}