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}