Skip to main content

rapier3d/dynamics/soft_body/soft_body_set/
soft_body_set_insert_remove.rs

1//! Insertion and removal of the soft bodies of a `SoftBodySet`.
2use super::soft_body_set_proxies::{spawn_mesh_collider, spawn_proxy};
3use super::{SoftBodyIslandEvent, SoftBodySet};
4use crate::alloc_prelude::*;
5use crate::dynamics::soft_body::{SoftBody, SoftBodyCluster, SoftBodyHandle, SoftMeshId};
6use crate::dynamics::{
7    ImpulseJointSet, IslandManager, MultibodyJointSet, RigidBodyHandle, RigidBodySet,
8    SoftBodyBuilder,
9};
10use crate::geometry::ColliderSet;
11use crate::math::{Pose, Rotation};
12
13impl SoftBodySet {
14    /// Inserts a soft body, creating its root rigid body and the deformable colliders of its
15    /// collision meshes from the collider template; its element topology must index valid
16    /// particles.
17    pub fn insert(
18        &mut self,
19        soft_body_builder: SoftBodyBuilder,
20        bodies: &mut RigidBodySet,
21        colliders: &mut ColliderSet,
22    ) -> SoftBodyHandle {
23        let mut soft_body = soft_body_builder.build();
24        soft_body.sleeping = false;
25        soft_body.enabled = true;
26        soft_body.positions_modified = false;
27        // Attachments made before the insertion get their island links with the insertion event.
28        soft_body.attachments_modified = !soft_body.attachments.is_empty();
29        // Reserve the handle first: the root body stores it.
30        let handle = SoftBodyHandle(self.bodies.insert_with(|_| SoftBody {
31            particles: Vec::new(),
32            clusters: Vec::new(),
33            cluster_refs: Vec::new(),
34            root_body: RigidBodyHandle::invalid(),
35            attachments: Vec::new(),
36            sleeping: false,
37            enabled: true,
38            positions_modified: false,
39            attachments_modified: false,
40            edges: Vec::new(),
41            #[cfg(feature = "dim3")]
42            dihedrals: Vec::new(),
43            cells: Vec::new(),
44            boundary: Vec::new(),
45            boundary_closed: false,
46            boundary_element_cells: Vec::new(),
47            material: soft_body.material,
48            cell_model: soft_body.cell_model,
49            #[cfg(feature = "fem")]
50            solver: soft_body.solver,
51            volume_preservation: false,
52            volume_pieces: Vec::new(),
53            volume_factor: 1.0,
54            rest_com: soft_body.rest_com,
55            particle_radius: soft_body.particle_radius,
56            particle_settings: soft_body.particle_settings,
57            num_colors: 0,
58            has_overflow_color: false,
59            modified: false,
60            plastic_flowing: false,
61            rest_fit_pending: false,
62            sleep_speed: 0.0,
63            tearing_pending: false,
64            topology_version: 0,
65            contact_approach_speeds: [None; 2],
66            contact_approach_step_open: false,
67            contact_load: 0.0,
68            load_extra_substeps: 0,
69            origin: None,
70            pieces: Vec::new(),
71            user_data: 0,
72        }));
73
74        soft_body.root_body = spawn_proxy(
75            &soft_body.particle_settings,
76            soft_body.user_data,
77            handle,
78            0,
79            bodies,
80        );
81        let meshes = soft_body_builder.build_meshes(&soft_body);
82        soft_body.clusters = alloc::vec![SoftBodyCluster {
83            particles: (0..soft_body.particles.len() as u32).collect(),
84            proxy: soft_body.root_body,
85            rotation: Rotation::IDENTITY,
86            cell: u32::MAX,
87            shape_matching: soft_body_builder.shape_matching,
88            shape_matching_target: None,
89            prev_shape_matching_target: None,
90            last_gather: Default::default(),
91            shape_impulses: Vec::new(),
92            meshes: meshes.into_iter().map(Some).collect(),
93        }];
94        soft_body.cluster_refs = alloc::vec![1; soft_body.particles.len()];
95        // The whole-body frame first: the colliders are expressed in it.
96        Self::update_cluster_proxies(&mut soft_body, bodies, colliders);
97        let frame = bodies
98            .get(soft_body.root_body)
99            .map(|rb| rb.pos.position)
100            .unwrap_or(Pose::IDENTITY);
101
102        // The deformable meshes' colliders attach to the root body (so they link islands and wake
103        // the soft body), with vertices in the whole-body cluster's frame (the proxy's pose holds
104        // the rigid motion). They collide with everything, fixed and kinematic colliders included.
105        if let Some(template) = soft_body_builder.collider_template.as_ref() {
106            let mut clusters = core::mem::take(&mut soft_body.clusters);
107            for (ci, cluster) in clusters.iter_mut().enumerate() {
108                for (mi, mesh) in cluster.meshes.iter_mut().enumerate() {
109                    let Some(mesh) = mesh else { continue };
110                    mesh.set_id(SoftMeshId {
111                        cluster: ci as u32,
112                        mesh: mi as u32,
113                    });
114                    if !mesh.collision_enabled() {
115                        continue;
116                    }
117                    let Some(co_handle) = spawn_mesh_collider(
118                        template,
119                        handle,
120                        mesh,
121                        &soft_body,
122                        cluster.proxy,
123                        &frame,
124                        bodies,
125                        colliders,
126                    ) else {
127                        // No shape to build (no element): the mesh collides through nothing,
128                        // and says so rather than holding an invalid collider.
129                        mesh.collision_enabled = false;
130                        continue;
131                    };
132                    mesh.collider = co_handle;
133                }
134            }
135            soft_body.clusters = clusters;
136        }
137
138        *self.bodies.get_mut(handle.0).unwrap() = soft_body;
139        self.island_events.push(SoftBodyIslandEvent { handle });
140        handle
141    }
142
143    /// Removes a soft body, its cluster proxies (root rigid body included) and its colliders.
144    pub fn remove(
145        &mut self,
146        handle: SoftBodyHandle,
147        islands: &mut IslandManager,
148        bodies: &mut RigidBodySet,
149        colliders: &mut ColliderSet,
150        impulse_joints: &mut ImpulseJointSet,
151        multibody_joints: &mut MultibodyJointSet,
152    ) -> Option<SoftBody> {
153        let soft_body = self.bodies.remove(handle.0)?;
154        // Unlink the attachment and proxy-chain links while the proxies still exist.
155        islands.persistent.unlink_soft_body_attachments(handle);
156        islands.persistent.unlink_soft_body_proxy_chain(handle);
157        self.attached_to_stale |= !soft_body.attachments.is_empty();
158        for cluster in &soft_body.clusters {
159            if cluster.is_live() {
160                // The soft body is out of the arena already, so the proxy-removal hook no-ops.
161                bodies.remove(
162                    cluster.proxy,
163                    islands,
164                    colliders,
165                    impulse_joints,
166                    multibody_joints,
167                    self,
168                    true,
169                );
170            }
171        }
172        Some(soft_body)
173    }
174}