soft_body_particles
The state of a soft-body is the state of its particles, which are identified by their index in the body. Their positions
and their velocities can be read (r3SoftBody_ParticlePosition, r3SoftBody_ParticlePositions, r3SoftBody_ParticleVelocity, r3SoftBody_ParticleVelocities) and modified (r3SoftBody_SetParticlePosition, r3SoftBody_SetParticleVelocity) at any time, one by one or all at
once. The elements built from them (r3SoftBody_Edges, r3SoftBody_Cells, and r3SoftBody_Boundary) can be read as well, e.g., in order to render the body with your own mesh. These arrays are copied into a buffer of your own, which capacity is given as the last argument, and a NULL buffer with a zero capacity only returns the length of the array. The elements are given as flat arrays of particle indices: 2 per edge, 3 (2D) or 4 (3D) per cell, and 2 (2D) or 3 (3D) per boundary element.
A particle can also be pinned (r3SoftBody_SetParticlePinned). A pinned particle is kinematic: it is no longer affected by the forces
nor by the contacts, and it will simply hold its position, or follow the kinematic target
(r3SoftBody_SetParticleKinematicTarget) or the velocity it is given. This is, e.g., how a piece of cloth
is hung on a wall, or how a rope is dragged by the player. Releasing the particle gives it back its nominal mass and
lets it keep its current velocity:
- Example 2D
- Example 3D
// Read the particles.
R2Vector position = r2SoftBody_ParticlePosition(sheet_handle, 0);
R2Vector velocity = r2SoftBody_ParticleVelocity(sheet_handle, 0);
size_t num_particles = r2SoftBody_NumParticles(sheet_handle);
R2Vector *positions = malloc(num_particles * sizeof(R2Vector));
r2SoftBody_ParticlePositions(sheet_handle, positions, num_particles);
// Move a particle.
r2SoftBody_SetParticlePosition(sheet_handle, 1, r2VectorAdd(position, r2Vector(0.0, 0.1)));
r2SoftBody_SetParticleVelocity(sheet_handle, 1, velocity);
// Pin (or release) a particle; a pinned particle can be driven like a kinematic body.
r2SoftBody_SetParticlePinned(sheet_handle, 2, 1);
r2SoftBody_SetParticleKinematicTarget(sheet_handle, 2, r2Vector(-3.5, 3.5));
// The elements: edges, cells and the boundary segments, as flat arrays of particle indices
// (2, 3, and 2 indices per element). A NULL buffer with a zero capacity gives their length.
size_t num_edges = r2SoftBody_Edges(sheet_handle, NULL, 0) / 2;
size_t num_cells = r2SoftBody_Cells(sheet_handle, NULL, 0) / 3;
size_t boundary_len = r2SoftBody_Boundary(sheet_handle, NULL, 0);
uint32_t *boundary = malloc(boundary_len * sizeof(uint32_t));
r2SoftBody_Boundary(sheet_handle, boundary, boundary_len);
assert(num_edges > 0 && num_cells > 0 && boundary_len > 0);
free(positions);
free(boundary);
// Read the particles.
R3Vector position = r3SoftBody_ParticlePosition(cloth_handle, 0);
R3Vector velocity = r3SoftBody_ParticleVelocity(cloth_handle, 0);
size_t num_particles = r3SoftBody_NumParticles(cloth_handle);
R3Vector *positions = malloc(num_particles * sizeof(R3Vector));
r3SoftBody_ParticlePositions(cloth_handle, positions, num_particles);
// Move a particle.
r3SoftBody_SetParticlePosition(cloth_handle, 1, r3VectorAdd(position, r3Vector(0.0, 0.1, 0.0)));
r3SoftBody_SetParticleVelocity(cloth_handle, 1, velocity);
// Pin (or release) a particle; a pinned particle can be driven like a kinematic body.
r3SoftBody_SetParticlePinned(cloth_handle, 2, 1);
r3SoftBody_SetParticleKinematicTarget(cloth_handle, 2, r3Vector(-1.0, 2.5, -0.8));
// The elements: edges, cells and the boundary triangles, as flat arrays of particle indices
// (2, 4, and 3 indices per element). A NULL buffer with a zero capacity gives their length.
size_t num_edges = r3SoftBody_Edges(cloth_handle, NULL, 0) / 2;
size_t num_cells = r3SoftBody_Cells(cloth_handle, NULL, 0) / 4;
size_t boundary_len = r3SoftBody_Boundary(cloth_handle, NULL, 0);
uint32_t *boundary = malloc(boundary_len * sizeof(uint32_t));
r3SoftBody_Boundary(cloth_handle, boundary, boundary_len);
assert(num_edges > 0 && num_cells == 0 && boundary_len > 0);
free(positions);
free(boundary);
Setting the position of a particle explicitly teleports it: no contact is taken into account along the way, so a particle can be moved inside of another object this way. Whenever the motion must be seen by the contacts and by the friction (to drag a piece of cloth, for example), it is recommended to pin the particle and to give it a kinematic target instead.
Controlling a region kinematically
A whole region of the body is controlled at once through a cluster covering it. Pinning
the cluster (r3SoftBody_SetClusterPinned) pins all of its particles, and its kinematic target
(r3SoftBody_SetClusterKinematicTarget) moves them
rigidly: each pinned particle is sent where the rest shape of the cluster places it at the target pose, with the
matching velocity. The rest of the body is then simulated as usual, and drags behind the controlled region, e.g., the
hand of a soft character carrying something:
- Example 2D
- Example 3D
// Pin every particle of the cluster, then move it along a path: the cluster behaves like a
// kinematic rigid part dragging the rest of the body.
r2SoftBody_SetClusterPinned(jelly_handle, cluster, 1);
r2SoftBody_SetClusterKinematicTarget(jelly_handle, cluster, r2TranslationPose(r2Vector(3.0, 2.5)));
// Release it: the cluster is simulated again.
r2SoftBody_SetClusterPinned(jelly_handle, cluster, 0);
// Pin every particle of the cluster, then move it along a path: the cluster behaves like a
// kinematic rigid part dragging the rest of the body.
r3SoftBody_SetClusterPinned(jelly_handle, cluster, 1);
r3SoftBody_SetClusterKinematicTarget(jelly_handle, cluster, r3TranslationPose(r3Vector(3.0, 2.0, 0.0)));
// Release it: the cluster is simulated again.
r3SoftBody_SetClusterPinned(jelly_handle, cluster, 0);