soft_body_contacts
A soft-body collides through the collider covering its surface, which is a deformable triangle-mesh (a polyline in 2D) built from the template given to the builder.
Thickness
The radius of the particles
(particle_radiussetParticleRadiusparticleRadius field of R3SoftBodyDescSoftBodyBuilder.particle_radius
Oriented surfaces and shells
A closed surface (a balloon, a jelly cube, a filled polygon) is oriented: its contacts are generated on its outward
side only, like for an oriented triangle-mesh, so nothing is held
inside it. An open surface (a rope, a cloth) is two-sided, because a body arriving from either side must be stopped.
This is what the builder does by default, and it is what a solid body wants. A shell, i.e., a closed surface which
inner side must hold the bodies contained in it, is obtained by asking for a surface that is not oriented
(orientedsetOrientedoriented field of R3SoftBodyDescSoftBodyBuilder.oriented
- Example 2D
- Example 3D
// A shell: a closed surface that is not oriented, so its inner side holds the bodies put
// inside it (a bowl, a box, a container). A closed surface is oriented by default.
let bowl = SoftBodyBuilder::disk(Vector::new(-3.0, 2.0), 0.8, 24)
.oriented(false)
.softness(SpringCoefficients::new(60.0, 1.0));
let _bowl_handle = world.insert_soft_body(bowl);
// A shell: a closed surface that is not oriented, so its inner side holds the bodies put
// inside it (a bowl, a box, a container). A closed surface is oriented by default.
let bowl = SoftBodyBuilder::sphere(Vector::new(-3.0, 2.0, 0.0), 0.8, 2)
.oriented(false)
.softness(SpringCoefficients::new(60.0, 1.0));
let _bowl_handle = world.insert_soft_body(bowl);
- Example 2D
- Example 3D
// A shell: a closed surface that is not oriented, so its inner side holds the bodies put
// inside it (a bowl, a box, a container). A closed surface is oriented by default.
let bowlDesc = RAPIER.SoftBodyDesc.disk({ x: -3.0, y: 2.0 }, 0.8, 24)
.setOriented(false)
.setSoftness(60.0, 1.0);
let bowl = world.createSoftBody(bowlDesc);
// A shell: a closed surface that is not oriented, so its inner side holds the bodies put
// inside it (a bowl, a box, a container). A closed surface is oriented by default.
let bowlDesc = RAPIER.SoftBodyDesc.sphere({ x: -3.0, y: 2.0, z: 0.0 }, 0.8, 2)
.setOriented(false)
.setSoftness(60.0, 1.0);
let bowl = world.createSoftBody(bowlDesc);
- Example 2D
- Example 3D
// A shell: a closed surface that is not oriented, so its inner side holds the bodies put
// inside it (a bowl, a box, a container). A closed surface is oriented by default.
commands.spawn((
Transform::from_xyz(-3.0, 2.0, 0.0),
SoftBody::disk(0.8, 24).map(|builder| {
builder
.oriented(false)
.softness(SpringCoefficients::new(60.0, 1.0))
}),
));
// A shell: a closed surface that is not oriented, so its inner side holds the bodies put
// inside it (a bowl, a box, a container). A closed surface is oriented by default.
commands.spawn((
Transform::from_xyz(-3.0, 2.0, 0.0),
SoftBody::sphere(0.8, 2).map(|builder| {
builder
.oriented(false)
.softness(SpringCoefficients::new(60.0, 1.0))
}),
));
- Example 2D
- Example 3D
// A shell: a closed surface that is not oriented, so its inner side holds the bodies put
// inside it (a bowl, a box, a container). A closed surface is oriented by default.
R2SoftBodyDesc bowl = r2DiskSoftBodyDesc(r2Vector(-3.0, 2.0), 0.8, 24);
// Default: disabled, i.e., oriented if the surface is closed.
bowl.oriented = (R2OptionalBool){1, 0};
bowl.material = r2UniformSoftBodyMaterial((R2SpringCoefficients){60.0, 1.0});
R2SoftBodyHandle bowl_handle = r2InsertSoftBody(world, &bowl);
// A shell: a closed surface that is not oriented, so its inner side holds the bodies put
// inside it (a bowl, a box, a container). A closed surface is oriented by default.
R3SoftBodyDesc bowl = r3SphereSoftBodyDesc(r3Vector(-3.0, 2.0, 0.0), 0.8, 2);
// Default: disabled, i.e., oriented if the surface is closed.
bowl.oriented = (R3OptionalBool){1, 0};
bowl.material = r3UniformSoftBodyMaterial((R3SpringCoefficients){60.0, 1.0});
R3SoftBodyHandle bowl_handle = r3InsertSoftBody(world, &bowl);
# A shell: a closed surface that is not oriented, so its inner side holds the bodies put
# inside it (a bowl, a box, a container). A closed surface is oriented by default.
bowl = rp.SoftBody.sphere((-3.0, 2.0, 0.0), 0.8, 2).oriented(False).softness((60.0, 1.0))
bowl_handle = world.add_soft_body(bowl)
After the insertion, the shape of the ColliderColliderr3SoftBody_MeshColliders)SoftBody.collision_mesh().collider)shape a triangle-mesh with the TriMeshFlags.ORIENTED flag toggled)
Self-contacts
A soft-body doesn't collide with itself by default. Self-contacts are enabled by
SoftBodyBuilder::self_contactsSoftBodyDesc.setSelfContactsselfContacts field of R3SoftBodyDescSoftBodyBuilder.self_contacts
Penetrations and tangles
The contacts between two meshes are computed triangle by triangle (segment by segment in 2D), without any notion of their interiors. As long as the two surfaces don't penetrate, this works well. But as soon as they do, some of these local contacts start pointing the wrong way, and actively keep the two surfaces in their penetrating state instead of separating them. Deformations make it worse, since a single surface can also cross itself and end up tangled:
Rapier handles these configurations by measuring the volume of the overlap between the two surfaces. The gradient of that volume gives a good approximation of the direction separating the two bodies, aka. the volume normal, which is used both to push the overlapping regions apart, and to correct the direction of the local contacts inside them:
This is enabled by default for the closed surfaces, against other soft-bodies as well as against rigid colliders.
It is configured, along with the detection and the recovery of the tangled configurations, by the recovery settings of
the global settings
(IntegrationParameters::soft_bodies.recoveryintegration_parameters.soft_bodies.recovery of the
RapierContextSimulation componentIntegrationParameters.softBodiesRecoverysoftBodies.recovery of R3IntegrationParametersIntegrationParameters.soft_bodies.recovery
| Problem | What to change |
|---|---|
| Thin or fast objects pass through a surface. | Raise the particle radius (particle_radiussetParticleRadiusparticleRadiusparticle_radiusmax_extra_substepssoftBodiesMaxExtraSubstepsmaxExtraSubstepsmax_extra_substeps |
| Two bodies crossing corner-first don't collide. | Enable edge_speculationedgeSpeculationedgeSpeculationedge_speculation |
| A body stays tangled with itself. | Keep self_stand_downselfStandDownselfStandDownself_stand_downcrossing_repulsioncrossingRepulsioncrossingRepulsioncrossing_repulsion |
| The recovery from a penetration is too slow, or too violent. | Change the recovery_pacerecoveryPacerecoveryPacerecovery_pace |
| Soft contacts feel too spongy. | Raise the contact_stiffeningsoftBodiesContactStiffeningcontactStiffeningcontact_stiffening |
| The overlap of two bodies isn't resolved at all. | Make sure both surfaces are closed: the intersection-volume constraints (overlap_constraintsoverlapConstraintsoverlapConstraintsoverlap_constraints |
Each of these settings has its own setter (and getter), named after its field: r3SoftBodiesSetMaxExtraSubsteps and
r3SoftBodiesSetContactStiffening for the settings of the soft-bodies, and r3RecoverySetEdgeSpeculation,
r3RecoverySetSelfStandDown, r3RecoverySetCrossingRepulsion, etc. for the recovery settings. See the
global settings for an example.