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}