Implementing Springs with Ammo.js Constraints
This article explains how to implement artificial spring behavior in physics simulations using native Ammo.js constraints. You will learn which constraints support spring dynamics, how to configure their stiffness and damping properties, and see a practical code implementation to create realistic elastic connections between rigid bodies.
To create spring behavior in Ammo.js (the WebAssembly/JavaScript port
of the Bullet Physics engine), you must use the
btGeneric6DofSpringConstraint. This
powerful constraint restricts motion along six degrees of freedom (three
translational axes and three rotational axes) and allows you to turn any
of these axes into an active spring.
The
btGeneric6DofSpringConstraint Class
The btGeneric6DofSpringConstraint maps its degrees of
freedom to indices from 0 to 5: * 0, 1, 2:
Translational axes (X, Y, Z) * 3, 4, 5: Rotational axes
(X, Y, Z)
To turn a specific axis into a spring, you must enable the spring for that axis index, set its stiffness, and apply a damping factor to prevent endless oscillation.
Step-by-Step Implementation
1. Define the Transforms and Create the Constraint
First, define the attachment points (frames of reference) for both rigid bodies. If you want to connect a rigid body to a static point in space, you can pass an empty rigid body or a static body as the second participant.
// Define local attachment points for Body A and Body B
const transformA = new Ammo.btTransform();
transformA.setIdentity();
transformA.setOrigin(new Ammo.btVector3(0, 0, 0)); // Center of Body A
const transformB = new Ammo.btTransform();
transformB.setIdentity();
transformB.setOrigin(new Ammo.btVector3(0, 2, 0)); // Offset 2 units above Body B
// Create the 6-DoF Spring Constraint
const useLinearReferenceFrameA = true;
const spring = new Ammo.btGeneric6DofSpringConstraint(
bodyA,
bodyB,
transformA,
transformB,
useLinearReferenceFrameA
);2. Configure Spring Limits
Before configuring the spring behavior, define the motion limits for the axes. If an axis is completely locked or free, the spring will behave differently.
// Allow translation along the Y-axis (index 1) between -5 and 5 units
spring.setLinearLowerLimit(new Ammo.btVector3(-10, -5, -10));
spring.setLinearUpperLimit(new Ammo.btVector3(10, 5, 10));3. Enable and Tune the Spring
Enable the spring behavior on your target axis (in this case, the Y-axis, which is index 1).
const yAxis = 1;
// Enable spring behavior on the Y-axis
spring.enableSpring(yAxis, true);
// Set Stiffness: Higher values make the spring tighter and faster
spring.setStiffness(yAxis, 35.0);
// Set Damping: Controls energy loss.
// A value of 0.0 is no damping (infinite bounce), 1.0 is critically damped
spring.setDamping(yAxis, 0.5);4. Set the Equilibrium Point
The equilibrium point is the resting position of the spring. You can
set it to the current constraint configuration using
setEquilibriumPoint().
// Sets the current position of the constraint as the default rest length
spring.setEquilibriumPoint(); 5. Add the Constraint to the Physics World
Finally, add the newly configured spring constraint to your Ammo.js physics world.
// The second parameter disables collisions between the two linked bodies
physicsWorld.addConstraint(spring, true);Key Configuration Tuning
- Stiffness (
setStiffness): If your objects feel sluggish or fail to return to their origin, increase the stiffness. If the simulation explodes or jitter occurs, lower the stiffness or decrease the physics step size. - Damping (
setDamping): Increase damping if the connected body oscillates indefinitely. Keep the value between0.1and1.0for natural-looking physical decay.