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