soft_body_creation_and_insertion
A soft-body is described by a SoftBodyBuilder (wrapped by the SoftBody
component), which constructors build the lattice of the most common shapes:
| Constructor | Dimension | Lattice |
|---|---|---|
rope | 2D, 3D | Structural and bending edges between the particles of a line. |
cloth, cloth_anisotropic, cloth_tube | 3D | Structural, shear and bending edges, with a triangle surface. |
grid | 2D | Triangle cells filling a rectangle. |
cuboid | 3D | Tetrahedral cells filling a box. |
polygon, disk | 2D | A closed boundary preserving its area. |
sphere | 3D | A closed surface preserving its volume, with dihedral bending constraints. |
trimesh, polyline | 2D, 3D (trimesh), 2D (polyline) | The vertices and edges of a mesh, held by shape matching. |
volumetric | 2D, 3D | Cells filling a closed mesh. |
The SoftBody component provides shortcuts for most of these constructors (SoftBody::rope,
SoftBody::cloth, SoftBody::cuboid, SoftBody::grid, SoftBody::volumetric, etc.), which positions are expressed in
the local frame of the entity: the cuboid, sphere, grid, and disk shortcuts are centered at its origin. The
other constructors are used with SoftBody::new(SoftBodyBuilder::...), and the methods of the builder are chained with
SoftBody::map, e.g., SoftBody::rope(a, b, 20).map(|b| b.particle_mass(0.1)).
The volumetric constructor is the one to use for an arbitrary solid: it fills a closed mesh (segments in 2D, triangles
in 3D, oriented outward) with cells of about the requested size. The interior of the mesh is triangulated by Delaunay
refinement in 2D, whereas in 3D every cell of a lattice the mesh reaches is kept whole: the result contains the mesh
instead of following it exactly, and its boundary is as blocky as its cells. The meshing parameters are spelled
out by volumetric_with: the size of the cells, how much the cover is smoothed and subdivided around the boundary in
3D, i.e., how closely it follows the mesh, and whether the surface alone is covered, leaving the interior
empty.
- Example 2D
- Example 3D
// Fill a closed, counter-clockwise polyline with triangle cells of about 0.2 in size.
let vertices = vec![
Vec2::new(-0.5, -0.25),
Vec2::new(0.5, -0.25),
Vec2::new(0.5, 0.25),
Vec2::new(-0.5, 0.25),
];
let indices = vec![[0, 1], [1, 2], [2, 3], [3, 0]];
let block = SoftBody::volumetric(&vertices, &indices, 0.2)
.expect("the polyline must be closed and enclose some area");
commands.spawn((Transform::from_xyz(-3.0, 1.0, 0.0), block));
// Fill a closed, outward-oriented triangle mesh with tetrahedral cells of about 0.2 in size.
let (vertices, indices) = CuboidShape::new(Vec3::new(0.5, 0.25, 0.25)).to_trimesh();
let block = SoftBody::volumetric(&vertices, &indices, 0.2)
.expect("the mesh must be closed and enclose some volume");
commands.spawn((Transform::from_xyz(-3.0, 1.0, 0.0), block));
The builder allows the definition of everything else that is specific to one soft-body: the particles held in place (the
pinned particles, pinned_particles), the softness of its constraints
(softness), the mass of its particles (one mass for every particle with
particle_mass, a total mass for the whole body with
mass, or one mass per particle with
masses), their radius
(particle_radius), the collider its surface is made of, and whether that
surface is allowed to collide with itself (self_contacts). The particles
can also be given a linear damping (linear_damping), a gravity scale
(gravity_scale), a dominance group
(SoftBodyParticleSettings::dominance_group), and be allowed to sleep or
not (can_sleep), exactly like a rigid-body. Inserting the
soft-body into the world (i.e., spawning an entity with the
SoftBody component) will
automatically create the rigid-body standing for it (its root body), as well as the
colliders covering its surface:
- Example 2D
- Example 3D
// A ground.
commands.spawn((
Transform::from_xyz(0.0, -0.1, 0.0),
Collider::cuboid(10.0, 0.1),
));
// A rope of 20 particles between two points (in the local frame of the entity).
let _ = SoftBody::rope(Vec2::ZERO, Vec2::new(2.0, 0.0), 20);
// A grid of `nx` by `ny` particles filled with triangle cells, centered on the entity.
let _ = SoftBody::grid(Vec2::new(1.0, 1.0), 6, 6);
// A disk: a ring of particles holding its area (a pressurized blob), centered on the entity.
let _ = SoftBody::disk(0.8, 24);
// A closed polygon of particles holding its area.
let _ = SoftBody::polygon(vec![
Vec2::new(0.0, 0.0),
Vec2::new(2.0, 0.0),
Vec2::new(2.0, 2.0),
Vec2::new(0.0, 2.0),
]);
// Any constructor of the Rapier builder can be used too.
let _ = SoftBody::new(SoftBodyBuilder::grid(Vec2::ZERO, Vec2::new(1.0, 0.5), 6, 3));
let n = 20;
commands.spawn((
Sheet,
// The particles are placed by the transform of the entity when the soft-body is
// created. Then, the entity follows the center of mass of the particles.
Transform::from_xyz(-3.0, 3.0, 0.0),
SoftBody::grid(Vec2::new(1.0, 1.0), n, n).map(|builder| {
// Particles held in place.
builder
.pinned_particles([0, (n - 1) as u32])
// A uniform softness (frequency in Hz, damping ratio) for every constraint.
.softness(SpringCoefficients::new(30.0, 1.0))
// The mass of each particle.
// Default: 1.0
.particle_mass(0.05)
// The thickness of the particles, for collisions.
// Default: 0.01
.particle_radius(0.05)
// Whether the body may fall asleep.
// Default: true
.can_sleep(true)
}),
// The collider components of the entity configure the colliders of its surface.
Friction::coefficient(0.8),
// Render the soft-body with a mesh kept in sync with its particles.
SoftBodyMeshSync::default(),
MeshMaterial2d(materials.add(Color::srgb(0.8, 0.2, 0.2))),
));
// A ground.
commands.spawn((
Transform::from_xyz(0.0, -0.1, 0.0),
Collider::cuboid(10.0, 0.1, 10.0),
));
// A rope of 20 particles between two points (in the local frame of the entity).
let _ = SoftBody::rope(Vec3::ZERO, Vec3::new(2.0, 0.0, 0.0), 20);
// A cloth: `nu` by `nv` particles, particle `(i, j)` at `origin + i * du + j * dv`.
let _ = SoftBody::cloth(Vec3::ZERO, Vec3::X * 0.1, Vec3::Z * 0.1, 20, 20);
// A box of `nx * ny * nz` particles filled with tetrahedral cells, centered on the entity.
let _ = SoftBody::cuboid(Vec3::splat(0.5), 4, 4, 4);
// A hollow sphere holding its volume (a balloon), centered on the entity.
let _ = SoftBody::sphere(0.8, 2);
// Any constructor of the Rapier builder can be used too.
let _ = SoftBody::new(SoftBodyBuilder::cloth_tube(
Vec3::ZERO,
Vec3::Y,
0.3,
0.3,
12,
10,
));
let n = 20;
let corners = [0, (n - 1) as u32, (n * (n - 1)) as u32, (n * n - 1) as u32];
let cloth = commands
.spawn((
Cloth,
// The particles are placed by the transform of the entity when the soft-body is
// created. Then, the entity follows the center of mass of the particles.
Transform::from_xyz(-1.0, 2.0, -1.0),
SoftBody::cloth(Vec3::ZERO, Vec3::X * 0.1, Vec3::Z * 0.1, n, n).map(|builder| {
// Particles held in place.
builder
.pinned_particles(corners)
// A uniform softness (frequency in Hz, damping ratio) for every constraint.
.softness(SpringCoefficients::new(30.0, 1.0))
// The mass of each particle.
// Default: 1.0
.particle_mass(0.05)
// The thickness of the particles, for collisions.
// Default: 0.01
.particle_radius(0.02)
// Whether the surface collides with itself.
// Default: false
.self_contacts(true)
// Whether the body may fall asleep.
// Default: true
.can_sleep(true)
}),
// The collider components of the entity configure the colliders of its surface.
Friction::coefficient(0.8),
// Render the soft-body with a mesh kept in sync with its particles.
SoftBodyMeshSync::default(),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgb(0.8, 0.2, 0.2),
double_sided: true,
cull_mode: None,
..default()
})),
))
.id();
The collider given to SoftBodyBuilder::surface_collider is
only a template: its shape is replaced by the deformable surface of the soft-body, and its density is ignored, whereas
all its other properties are kept. Therefore this is where the friction, the collision
groups, or the active events of
the soft-body must be set. A body that should only collide through colliders of your own can be built without any
default one (no_surface_collider). The
collider components of the soft-body entity (Friction, Restitution, CollisionGroups, ActiveEvents, Sensor,
etc.) override the properties of that template, exactly like for a Collider: their later modifications are applied to
the colliders of the surface as well, and removing one of them restores the value of the template (the particle radius
for the ContactSkin).
Two builders can be merged into a single soft-body with append, and their pieces
sewn together with additional edges (add_edges), which rest length is the distance
their particles have when they are added. This is, e.g., how the sleeves of a shirt are attached to its body.