Skip to main content

rapier3d/dynamics/soft_body/
soft_body.rs

1//! The `SoftBody` struct and the shared constants of the soft-body constraints.
2#[cfg(feature = "dim3")]
3use super::SoftBodyDihedral;
4#[cfg(feature = "fem")]
5use super::SoftBodySolver;
6#[cfg(feature = "serde-serialize")]
7use super::soft_body_material::default_true;
8use super::{
9    SoftBodyCell, SoftBodyCellModel, SoftBodyEdge, SoftBodyMaterial, SoftBodyParticle,
10    SoftParticleAttachment,
11};
12use crate::alloc_prelude::*;
13use crate::dynamics::RigidBodyHandle;
14use crate::math::{DIM, Real, Vector};
15
16/// Number of particles a soft-body constraint can touch (a simplex cell).
17pub const SOFT_BODY_MAX_CONSTRAINT_PARTICLES: usize = DIM + 1;
18
19/// Color id marking a soft-body element that could not be given a parallel color
20/// (solved serially by the solver).
21pub(crate) const SOFT_BODY_OVERFLOW_COLOR: u8 = 128;
22
23/// A deformable body: [`SoftBodyParticle`]s linked by elastic elements ([`SoftBodyEdge`]s, bending,
24/// [`SoftBodyCell`]s, volume preservation, shape matching). Its hidden root rigid body (tagged by
25/// [`crate::dynamics::RigidBody::soft_body`]) must never be moved, removed or attached to joints.
26#[derive(Clone, Debug)]
27#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
28pub struct SoftBody {
29    pub(crate) particles: Vec<SoftBodyParticle>,
30    /// The hidden rigid body standing for this soft body in the islands and holding its
31    /// colliders (invalid until the soft body is inserted in a set): the whole-body cluster's
32    /// proxy, re-pointed to another live cluster's proxy if that cluster is removed.
33    pub(crate) root_body: RigidBodyHandle,
34    /// The clusters of this soft body (index 0: the whole-body cluster, created at insertion).
35    /// Removed clusters leave a dead slot so indices stay stable.
36    pub(crate) clusters: Vec<super::SoftBodyCluster>,
37    /// Number of live clusters referencing each particle: a particle is removed when it drops
38    /// to zero.
39    pub(crate) cluster_refs: Vec<u32>,
40    /// The particles attached to rigid bodies.
41    pub(crate) attachments: Vec<SoftParticleAttachment>,
42    /// Whether the soft body is currently asleep (mirrors the root body's state at the end of
43    /// each step).
44    #[cfg_attr(feature = "serde-serialize", serde(default))]
45    pub(crate) sleeping: bool,
46    /// Whether the soft body takes part in the simulation (applied to the root body at the start
47    /// of the next step; cleared by the NaN quarantine).
48    #[cfg_attr(feature = "serde-serialize", serde(default = "default_true"))]
49    pub(crate) enabled: bool,
50    /// Set by the setters that move particles between steps (positions, pinning): the colliders
51    /// are updated at the start of the next step so the narrow phase sees the new geometry.
52    #[cfg_attr(feature = "serde-serialize", serde(skip))]
53    pub(crate) positions_modified: bool,
54    /// Set when the attachments changed since the last step: the island links are updated at
55    /// the start of the next step.
56    #[cfg_attr(feature = "serde-serialize", serde(skip))]
57    pub(crate) attachments_modified: bool,
58    pub(crate) edges: Vec<SoftBodyEdge>,
59    #[cfg(feature = "dim3")]
60    pub(crate) dihedrals: Vec<SoftBodyDihedral>,
61    pub(crate) cells: Vec<SoftBodyCell>,
62    /// The computational mesh's boundary: segments (2D) or triangles (3D), oriented outward.
63    /// Used by the volume constraints, and as the geometry of the default collision mesh.
64    pub(crate) boundary: Vec<[u32; DIM]>,
65    /// Whether the boundary is closed (every segment vertex / triangle edge shared by exactly
66    /// two elements).
67    pub(crate) boundary_closed: bool,
68    /// The cell owning each boundary element (`u32::MAX`: none): the tearing pass follows it,
69    /// and the winding of an element whose cell is inverted no longer tells where the outside
70    /// is.
71    #[cfg_attr(feature = "serde-serialize", serde(default))]
72    pub(crate) boundary_element_cells: Vec<u32>,
73    pub(crate) material: SoftBodyMaterial,
74    pub(crate) cell_model: SoftBodyCellModel,
75    /// Which solver simulates this body's elasticity.
76    #[cfg(feature = "fem")]
77    #[cfg_attr(feature = "serde-serialize", serde(default))]
78    pub(crate) solver: SoftBodySolver,
79    /// Whether the volume pieces are constrained (only set while there is at least one piece).
80    pub(crate) volume_preservation: bool,
81    /// The pieces of material enclosed by a closed boundary, each with its own volume constraint
82    /// (rebuilt with the boundary tables).
83    #[cfg_attr(feature = "serde-serialize", serde(default))]
84    pub(crate) volume_pieces: Vec<super::SoftVolumePiece>,
85    /// Multiplier of the target volume (`> 1` inflates the body).
86    pub(crate) volume_factor: Real,
87    /// The rest shape's center of mass at insertion (world space).
88    pub(crate) rest_com: Vector,
89    /// The particle spacing: the impact-adaptive substeps bound the travel per substep by it,
90    /// and the collision meshes' colliders take their default contact skin from it.
91    pub(crate) particle_radius: Real,
92    /// Rigid-body settings applied to the particles at insertion.
93    pub(crate) particle_settings: super::SoftBodyParticleSettings,
94    /// Number of parallel colors used by the elements (`0..num_colors`, plus possibly the
95    /// overflow color).
96    pub(crate) num_colors: u8,
97    /// Whether some element has the overflow color.
98    pub(crate) has_overflow_color: bool,
99    /// Set by the setters that change the dynamics (material, volume factor, shape matching...):
100    /// the pipeline wakes the soft body up at the start of the next step so the change takes
101    /// effect even if it was sleeping.
102    #[cfg_attr(feature = "serde-serialize", serde(skip))]
103    pub(crate) modified: bool,
104    /// Set by the solver when a cell flowed plastically by a significant amount during the last
105    /// step: the body is kept awake so its creep goes on.
106    #[cfg_attr(feature = "serde-serialize", serde(skip))]
107    pub(crate) plastic_flowing: bool,
108    /// Set when the elements flowed plastically: the particles' rest positions are fitted to the
109    /// flowed rest shapes at the end of the step, over the following steps until they settle
110    /// (see `SoftBody::fit_rest_positions`).
111    #[cfg_attr(feature = "serde-serialize", serde(skip))]
112    pub(crate) rest_fit_pending: bool,
113    /// The speed the sleep rule reads for this body's cluster proxies: the fastest particle at the
114    /// end of the last step, or `Real::MAX` while the body flows plastically (kept awake).
115    /// `RigidBodyActivation::update_energy` compares it against the proxies' activation threshold.
116    #[cfg_attr(feature = "serde-serialize", serde(default))]
117    pub(crate) sleep_speed: Real,
118    /// Set when some edge or cell has a `torn` mark: the tearing pass at the end of the step
119    /// removes them (see `SoftBodySet::tear`).
120    #[cfg_attr(feature = "serde-serialize", serde(skip))]
121    pub(crate) tearing_pending: bool,
122    /// Bumped whenever the topology changes (a tear removed elements or duplicated particles):
123    /// renderers keying their meshes on the particles and elements rebuild them on change.
124    #[cfg_attr(feature = "serde-serialize", serde(default))]
125    pub(crate) topology_version: u32,
126    /// Largest normal approach speed of the rigid bodies met by the surface, for the last step
127    /// and the one before (`None`: no contact constraint that step); with the particle speeds, it drives
128    /// the impact-adaptive substeps (`IntegrationParameters::soft_bodies.max_extra_substeps`).
129    /// A step split into several CCD passes counts once, with the largest speed of its passes.
130    #[cfg_attr(feature = "serde-serialize", serde(default))]
131    pub(crate) contact_approach_speeds: [Option<Real>; 2],
132    /// Set by the first solve of a step, which shifted `contact_approach_speeds`: the step's later
133    /// CCD passes merge into its entry. Cleared by the end-of-step sync.
134    #[cfg_attr(feature = "serde-serialize", serde(skip))]
135    pub(crate) contact_approach_step_open: bool,
136    /// Total normal impulse of the surface's contact constraints over the last step, and the extra
137    /// substeps currently requested from that load (see `sync_particle_positions`).
138    #[cfg_attr(feature = "serde-serialize", serde(default))]
139    pub(crate) contact_load: Real,
140    #[cfg_attr(feature = "serde-serialize", serde(default))]
141    pub(crate) load_extra_substeps: u8,
142    /// The soft body this one was split off from by a tear or a cut (see
143    /// [`Self::origin`]).
144    #[cfg_attr(feature = "serde-serialize", serde(default))]
145    pub(crate) origin: Option<crate::dynamics::SoftBodyHandle>,
146    /// The soft bodies split off from this one, in creation order (see [`Self::pieces`]).
147    #[cfg_attr(feature = "serde-serialize", serde(default))]
148    pub(crate) pieces: Vec<crate::dynamics::SoftBodyHandle>,
149    /// User-defined data associated to this soft body.
150    pub user_data: u128,
151}