avian3d/dynamics/solver/softness_parameters/
mod.rs

1//! Soft constraints are spring-like constraints that dampen constraint responses
2//! using intuitive tuning parameters, a damping ratio and a frequency in Hertz.
3//!
4//! The following section contains an overview of soft constraints
5//! and their mathematical background.
6//!
7#![doc = include_str!("README.md")]
8
9use bevy::reflect::Reflect;
10
11use crate::{Scalar, TAU};
12
13/// Soft constraint tuning parameters used for dampening
14/// constraint response and controlling stiffness.
15#[derive(Clone, Copy, Debug, PartialEq, Reflect)]
16pub struct SoftnessParameters {
17    /// 2x the damping ratio (zeta ζ). Controls the amount of oscillation.
18    ///
19    /// This is stored as two times the damping ratio to avoid
20    /// unnecessary computations in [`SoftnessParameters::compute_coefficients`].
21    double_damping_ratio: Scalar,
22
23    /// The angular frequency (omega ω). Controls the rate of oscillation.
24    angular_frequency: Scalar,
25}
26
27impl SoftnessParameters {
28    /// Creates a new [`SoftnessParameters`] configuration based on
29    /// a given damping ratio and a frequency in Hertz.
30    ///
31    /// The damping ratio (zeta ζ) controls the amount of oscillation,
32    /// and the frequency controls the constraint's cycles per second.
33    #[inline]
34    pub fn new(damping_ratio: Scalar, frequency_hz: Scalar) -> Self {
35        Self {
36            double_damping_ratio: 2.0 * damping_ratio,
37            angular_frequency: TAU * frequency_hz,
38        }
39    }
40
41    /// Returns the damping ratio that controls the amount of oscillation.
42    #[inline]
43    pub fn damping_ratio(self) -> Scalar {
44        self.double_damping_ratio * 0.5
45    }
46
47    /// Returns the frequency that controls the rate of oscillation.
48    #[inline]
49    pub fn frequency(self) -> Scalar {
50        self.angular_frequency / TAU
51    }
52
53    /// Returns the angular frequency that controls the rate of oscillation.
54    /// This is the [`frequency`](Self::frequency) multiplied by `2.0 * PI`.
55    #[inline]
56    pub const fn angular_frequency(self) -> Scalar {
57        self.angular_frequency
58    }
59
60    /// Computes [`SoftnessCoefficients`] based on the parameters in `self` and the time step.
61    #[inline]
62    pub fn compute_coefficients(self, delta_secs: Scalar) -> SoftnessCoefficients {
63        // Largely based on Erin Catto's Solver2D and Box2D: https://box2d.org/posts/2024/02/solver2d#soft-constraints
64        // See /docs/soft_constraint.md for in-depth explanation and derivation.
65
66        // Expressions shared by computations.
67        let a1 = self.double_damping_ratio + self.angular_frequency * delta_secs;
68        let a2 = self.angular_frequency * delta_secs * a1;
69        let a3 = 1.0 / (1.0 + a2);
70
71        // The coefficients used for soft constraints.
72        SoftnessCoefficients {
73            bias: self.angular_frequency / a1,
74            impulse_scale: a3,
75            mass_scale: a2 * a3,
76        }
77    }
78}
79
80/// Coefficients used by soft constraints.
81#[derive(Clone, Copy, Debug, PartialEq, Reflect)]
82pub struct SoftnessCoefficients {
83    /// The bias coefficient used for scaling how strongly impulses
84    /// are biased based on the separation distance.
85    pub bias: Scalar,
86
87    /// The mass coefficient used for scaling the effective mass
88    /// "seen" by the constraint.
89    pub mass_scale: Scalar,
90
91    /// The impulse coefficient used for scaling the accumulated impulse
92    /// that is subtracted from the total impulse to prevent
93    /// the total impulse from becoming too large.
94    pub impulse_scale: Scalar,
95}