Attach Rigid Body to Moving Soft Body in Ammo.js
This article explains how to dynamically attach a rigid body to a moving soft body mesh using the ammo.js physics library. You will learn the core concepts behind soft body anchors, how to identify the correct attachment point on a mesh at runtime, and the specific ammo.js API methods required to establish a stable, physical connection between the two bodies.
To connect a rigid body to a soft body dynamically in ammo.js, you must use anchors. Anchors bind a specific node (vertex) of the soft body to a rigid body. When the soft body moves or deforms, the attached rigid body moves with it, and vice versa.
Here is the step-by-step process to implement this programmatically.
Step 1: Find the Closest Soft Body Node
Before attaching the rigid body, you need to determine which vertex (node) of the soft body mesh should be the anchor point. Usually, this is the node closest to the rigid body’s current position.
function findClosestNode(softBody, position) {
const nodes = softBody.get_m_nodes();
const numNodes = nodes.size();
let closestNodeIndex = -1;
let minDistance = Infinity;
for (let i = 0; i < numNodes; i++) {
const node = nodes.at(i);
const nodePos = node.get_m_x(); // Current position of the node
const dx = nodePos.x() - position.x();
const dy = nodePos.y() - position.y();
const dz = nodePos.z() - position.z();
const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
if (distance < minDistance) {
minDistance = distance;
closestNodeIndex = i;
}
}
return closestNodeIndex;
}Step 2: Append the Anchor
Once you have the index of the closest node, use the
appendAnchor method on the soft body instance to link it to
the rigid body.
The appendAnchor method signature in ammo.js is:
softBody.appendAnchor(nodeIndex, rigidBody, disableCollisionBetweenLinkedBodies, influence);
- nodeIndex: The index of the soft body node (calculated in Step 1).
- rigidBody: The
btRigidBodyinstance you want to attach. - disableCollisionBetweenLinkedBodies: A boolean
(usually
true) to prevent the rigid body and soft body from colliding with each other, which prevents physics glitches. - influence: A float value (typically
1.0for a rigid connection) representing how strongly the anchor forces affect the bodies.
// Get the rigid body's current position
const rbTransform = rigidBody.getWorldTransform();
const rbOrigin = rbTransform.getOrigin();
// Find the closest node on the soft body
const nodeIndex = findClosestNode(softBody, rbOrigin);
if (nodeIndex !== -1) {
// Dynamically attach the rigid body to the soft body node
softBody.appendAnchor(nodeIndex, rigidBody, true, 1.0);
}Step 3: Configure Rigid Body Mass and Activation
For the physics simulation to behave correctly after the attachment:
- Keep Both Active: Soft bodies and rigid bodies can “sleep” (deactivate) when they stop moving. Force both bodies to remain active so the physics solver continuously processes the joint.
- Adjust Mass: Ensure the rigid body’s mass is realistic compared to the soft body’s total mass to prevent extreme stretching or jittering.
// Force activation states
const ACTIVE_TAG = 1;
rigidBody.forceActivationState(ACTIVE_TAG);
softBody.activate();How the Physics Solver Handles the Connection
Once appendAnchor is called, the Ammo.js constraint
solver handles the link automatically during the physics world step. The
rigid body will now inherit the velocity and position shifts of the soft
body node, while the weight and inertia of the rigid body will pull back
on the soft body mesh, creating a realistic, bidirectional physical
interaction.