Skip to main content

rapier3d/dynamics/soft_body/collision_mesh/
collision_mesh.rs

1//! The collision-mesh types: the mesh itself, its vertex mapping, its id and the remap tables.
2
3use crate::alloc_prelude::*;
4use crate::geometry::ColliderHandle;
5use crate::math::{DIM, Real, Vector};
6
7use super::super::{SoftEdgeContact, SoftVertexContact};
8use super::super::{SoftOverlapState, SoftOverlapWarm, SoftVolumeContact};
9
10/// Where a skinned collision-mesh vertex rides: the cell holding it, and its barycentric
11/// coordinates in that cell. The coordinates are not clamped, so a vertex the cells do not cover
12/// is bound to the closest one through an extrapolation and follows it.
13#[derive(Copy, Clone, Debug, PartialEq)]
14#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
15pub struct SoftMeshCellBinding {
16    /// The cell holding the vertex.
17    pub cell: u32,
18    /// Barycentric coordinates of the vertex in that cell, summing to one.
19    pub weights: [Real; DIM + 1],
20}
21
22/// Where a collision mesh lives in its soft body: the cluster owning it, and its slot in that
23/// cluster. Stable for the mesh's whole life (removed meshes leave a dead slot).
24#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
25#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
26pub struct SoftMeshId {
27    /// The cluster owning the mesh.
28    pub cluster: u32,
29    /// The mesh's slot in that cluster.
30    pub mesh: u32,
31}
32
33/// A collision mesh of a given soft body: what a deformable collider points back to.
34#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
35#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
36pub struct SoftMeshRef {
37    /// The soft body owning the mesh.
38    pub body: crate::dynamics::SoftBodyHandle,
39    /// Where the mesh sits in it.
40    pub id: SoftMeshId,
41}
42
43/// How a collision mesh's vertices are mapped onto a soft body's computational mesh, as
44/// resolved at insertion (see [`crate::dynamics::SoftMeshBinding`] for the request).
45#[derive(Clone, Debug)]
46#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
47pub enum SoftMeshMapping {
48    /// Vertex `i` of the mesh is the particle `particles[i]`: the mesh moves with the particles
49    /// one for one.
50    Direct {
51        /// The particle backing each vertex.
52        particles: Vec<u32>,
53    },
54    /// Vertex `i` of the mesh rides a cell of the computational mesh (cage simulation): the
55    /// cells only have to contain the mesh, not resolve it.
56    Skinned {
57        /// Where each vertex rides.
58        bindings: Vec<SoftMeshCellBinding>,
59    },
60}
61
62/// A mesh a soft body collides through: a polyline (2D) or triangle mesh (3D) whose vertices
63/// follow the body's particles, and the collider holding it. A skinned mesh carries thin features
64/// the coarse cells cannot: its vertices are barycentric combinations of the particles.
65#[derive(Clone, Debug)]
66#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
67pub struct SoftCollisionMesh {
68    /// How the vertices follow the computational mesh.
69    pub(crate) binding: SoftMeshMapping,
70    /// The mesh's elements: segments in 2D, triangles in 3D.
71    pub(crate) indices: Vec<[u32; DIM]>,
72    /// World-space vertices of a skinned mesh, updated from the particles after every step
73    /// (empty for a direct mesh, which reads its particles).
74    pub(crate) vertices: Vec<Vector>,
75    /// Surface 1-ring of every vertex (CSR over `ring`): the vertices sharing an element with
76    /// it. Self contacts against those elements are excluded.
77    pub(crate) ring_offsets: Vec<u32>,
78    pub(crate) ring: Vec<u32>,
79    /// Elements incident to every vertex (CSR over `vertex_elements`).
80    pub(crate) vertex_elements_offsets: Vec<u32>,
81    pub(crate) vertex_elements: Vec<u32>,
82    /// The mesh's unique edges (`[a, b]` with `a < b`) and the edge ids of every element (3D:
83    /// the triangle edges; the segments are their own edges in 2D).
84    #[cfg(feature = "dim3")]
85    pub(crate) edges: Vec<[u32; 2]>,
86    #[cfg(feature = "dim3")]
87    pub(crate) element_edges: Vec<[u32; DIM]>,
88    /// The element owning each edge (the first one containing it): edge-vs-edge tests of an
89    /// element pair only involve the edges each element owns, so every edge pair is tested once.
90    #[cfg(feature = "dim3")]
91    pub(crate) edge_owners: Vec<u32>,
92    /// Whether the mesh is closed (every segment vertex / triangle edge shared by exactly two
93    /// elements): its contacts with other bodies are then oriented outward, if it is oriented.
94    pub(crate) closed: bool,
95    /// Whether the collider's shape carries parry's `ORIENTED` flag, read back from it before
96    /// every step: closed, the mesh then encloses solid matter. Otherwise it is a shell: its
97    /// contacts are two-sided, a body inside it rests on its inner side, and it takes no patch.
98    #[cfg_attr(feature = "serde-serialize", serde(default))]
99    pub(crate) oriented: bool,
100    /// Signed area/volume enclosed by the mesh at rest: with `inverted`, it says which way the
101    /// winding points.
102    pub(crate) rest_signed_volume: Real,
103    /// Whether the closed mesh is currently inside out (its signed volume, updated with the
104    /// particles, has the opposite sign to the rest one): the winding is mirrored as a whole, so
105    /// the outward normals flip with it.
106    #[cfg_attr(feature = "serde-serialize", serde(skip))]
107    pub(crate) inverted: bool,
108    /// Whether the closed mesh's signed volume is currently so far below its rest magnitude
109    /// (inside the orientation hysteresis band) that the loop is likely self-crossed: part of
110    /// its winding is then mirrored and no global flag can say where the outside is.
111    #[cfg_attr(feature = "serde-serialize", serde(skip))]
112    pub(crate) orientation_unreliable: bool,
113    /// The cell owning each element (`u32::MAX`: none), for a direct mesh: the winding of an
114    /// element whose cell is inverted no longer tells where the outside is. Empty for a skinned
115    /// mesh, which has no cell of its own to check.
116    pub(crate) element_cells: Vec<u32>,
117    /// Where this mesh lives in its soft body (its cluster and slot).
118    pub(crate) id: SoftMeshId,
119    /// Whether this mesh is the computational mesh's boundary: it is re-derived from it after
120    /// every topology change, instead of being remapped.
121    pub(crate) follows_boundary: bool,
122    /// Whether this mesh is a collision mesh (`false`: it is only drawn, and has no
123    /// collider).
124    pub(crate) collision_enabled: bool,
125    /// The collider holding this mesh's shape (invalid until the soft body is inserted in a
126    /// set, like [`SoftBody::root_body`], and for a mesh that is only drawn).
127    pub(crate) collider: ColliderHandle,
128    /// Whether this mesh collides with itself.
129    pub(crate) self_contacts: bool,
130    /// Edge-vs-edge contacts of the last step (self contacts and contacts with other soft
131    /// bodies' meshes, owned by the body with the smaller handle): warm-start state.
132    pub(crate) edge_contacts: Vec<SoftEdgeContact>,
133    /// Vertex-vs-surface contacts of the last step against this mesh (self contacts and the
134    /// other soft bodies' vertices): warm-start state.
135    pub(crate) vertex_contacts: Vec<SoftVertexContact>,
136    /// The overlap corrections' progress per pair (see `SoftOverlapState`).
137    #[cfg_attr(feature = "serde-serialize", serde(skip))]
138    pub(crate) overlap_states: Vec<SoftOverlapState>,
139    /// The volume contacts' warm impulses (see `SoftOverlapWarm`).
140    #[cfg_attr(feature = "serde-serialize", serde(skip))]
141    pub(crate) overlap_warm: Vec<SoftOverlapWarm>,
142    /// The volume constraints assembled at the last step (see `SoftVolumeContact`).
143    #[cfg_attr(feature = "serde-serialize", serde(skip))]
144    pub(crate) volume_contacts: Vec<SoftVolumeContact>,
145    /// Surface travel accumulated since the last self-crossing sweep (the sweep is skipped
146    /// while this cannot have bridged half a skin).
147    #[cfg_attr(feature = "serde-serialize", serde(skip))]
148    pub(crate) crossing_sweep_travel: Real,
149    /// The surface colliders whose pair with this mesh crosses this step (its own collider
150    /// for a self tangle, a partner it is tangled with): the pairs the recovery owns.
151    #[cfg_attr(feature = "serde-serialize", serde(skip))]
152    pub(crate) crossed_partners: Vec<ColliderHandle>,
153    /// Bumped whenever this mesh's elements change (a tear): renderers keying their mesh on it
154    /// rebuild it on change.
155    #[cfg_attr(feature = "serde-serialize", serde(default))]
156    pub(crate) topology_version: u32,
157    /// The world-space vertices as of the last [`Self::refresh_vertex_cache`] (before every
158    /// narrow-phase update): the contact passes read this contiguous copy instead of walking
159    /// the particle array.
160    #[cfg_attr(feature = "serde-serialize", serde(skip))]
161    pub(crate) vertex_cache: Vec<Vector>,
162}
163
164/// How a topology change renumbered a soft body's cells and particles (old index to new,
165/// `u32::MAX` removed, empty when unchanged), the split particles as `(copy, source)`, and the
166/// segments a cut inserted into as `[a, b, p, q]` (`(a, b)` became `(a, p)` and `(q, b)`).
167#[derive(Copy, Clone, Debug, Default)]
168pub(crate) struct SoftTopologyRemap<'a> {
169    pub cells: &'a [u32],
170    pub particles: &'a [u32],
171    pub split: &'a [(u32, u32)],
172    pub inserted: &'a [[u32; 4]],
173}