How to Pin Soft Body Cloth in Ammo.js
This article provides a step-by-step guide on how to securely anchor or pin the corners of a soft body cloth to specific points in 3D space using the Ammo.js physics engine. You will learn how to identify the correct nodes of the cloth mesh and use two primary methods—setting node mass to zero for fixed global positioning, or using anchors to attach the cloth to rigid bodies—to ensure stable and realistic cloth simulation.
Understanding Cloth Nodes in Ammo.js
A soft body cloth in Ammo.js is composed of a collection of vertices, referred to as nodes. To pin a specific corner of the cloth, you must first identify the index of that node.
When you create a cloth patch using
btSoftBodyHelpers.CreatePatch, the cloth is generated as a
grid. If your cloth has a resolution of numColumns by
numRows, the corner nodes are located at the following
indices:
- Top-Left Corner: Node index
0 - Top-Right Corner: Node index
numColumns - 1 - Bottom-Left Corner: Node index
numColumns * (numRows - 1) - Bottom-Right Corner: Node index
(numColumns * numRows) - 1
Method 1: Setting Node Mass to Zero (Fixed in Space)
If you want to pin a cloth corner to a static coordinate in the 3D
world, the most efficient method is to set the mass of that specific
node to zero. In Bullet/Ammo.js physics, an object or node with a mass
of 0 becomes static and unaffected by gravity or external
forces.
Step-by-Step Implementation
- Create the Soft Body: Generate your cloth patch and add it to your physics world.
- Access the Node: Use the soft body’s
get_m_nodes()array to access the node configuration. - Set Mass to Zero: Call the
setMassmethod on the soft body for the specific node index.
// Assuming 'clothSoftBody' is your btSoftBody instance
// and 'numColumns' and 'numRows' define your grid resolution.
const topLeftIndex = 0;
const topRightIndex = numColumns - 1;
// Set mass of the top-left corner node to 0 (pinned)
clothSoftBody.setMass(topLeftIndex, 0);
// Set mass of the top-right corner node to 0 (pinned)
clothSoftBody.setMass(topRightIndex, 0);This method locks the designated corners to their initial spawning coordinates. They will remain suspended in the air, allowing the rest of the cloth to dangle and react naturally to wind, gravity, and collisions.
Method 2: Anchoring to a Rigid Body (Dynamic Pinning)
If you need the cloth to be pinned to an object that moves (such as a
flagpole, a character’s hand, or a moving platform), you must anchor the
cloth node to a btRigidBody.
Ammo.js provides the appendAnchor method to link a soft
body node to a rigid body.
Step-by-Step Implementation
- Create or Reference a Rigid Body: This can be a static anchor point or a dynamic moving object.
- Identify the Node Index: Determine which cloth node you want to attach.
- Append the Anchor: Call
appendAnchor(nodeIndex, rigidBody, disableCollisions, influence)on your soft body.
// 1. Create a static anchor rigid body at your target coordinate
const colShape = new Ammo.btSphereShape(0.1); // Small invisible sphere
const transform = new Ammo.btTransform();
transform.setIdentity();
transform.setOrigin(new Ammo.btVector3(x, y, z)); // Pin position
const localInertia = new Ammo.btVector3(0, 0, 0);
const motionState = new Ammo.btDefaultMotionState(transform);
const rbInfo = new Ammo.btRigidBodyConstructionInfo(0, motionState, colShape, localInertia); // Mass = 0 (static)
const anchorBody = new Ammo.btRigidBody(rbInfo);
physicsWorld.addRigidBody(anchorBody);
// 2. Append the cloth corner node to the anchor rigid body
const nodeIndex = 0; // Top-left corner
const disableCollisionBetweenLinkedBodies = true;
const influence = 1.0; // Rigid attachment strength (0.0 to 1.0)
clothSoftBody.appendAnchor(
nodeIndex,
anchorBody,
disableCollisionBetweenLinkedBodies,
influence
);Best Practices for Stability
Matching Initial Positions: Ensure that the rigid body anchor is positioned exactly at the 3D coordinates of the cloth node’s initial position. If they are far apart at initialization, the cloth will stretch violently on the first frame.
Solver Iterations: If your cloth slips or stretches away from the pin point under heavy loads, increase the positioning solver iterations of your soft body:
const sbConfig = clothSoftBody.get_m_cfg(); sbConfig.set_piterations(10); // Default is usually 2 or 4