Calculate Velocity in Ammo.js with btTransformUtil

This article explains how to use the btTransformUtil class in ammo.js to calculate linear and angular velocities between two transforms over a given time step. You will learn the purpose of this utility class, the mathematical context behind its velocity calculation method, and how to implement it directly in your JavaScript 3D physics projects.

Understanding btTransformUtil

In physics-based applications, you often need to manually move an object (such as a kinematic body) and have the physics engine compute the corresponding velocities. Instead of manually calculating delta positions and quaternion differences, ammo.js provides the static utility class btTransformUtil.

The primary method used for this is calculateVelocity, which takes a starting transform, an ending transform, and a time delta to compute the exact linear and angular velocity vectors required to move an object from the first transform to the second.

Implementation Steps

To calculate velocities using btTransformUtil, you must prepare two btTransform instances representing the start and end states, define the time step, and allocate btVector3 instances to receive the calculated outputs.

1. Initialize the Transforms and Vectors

First, instantiate the necessary ammo.js objects. You need the starting transform, the target transform, and two empty vectors to store the calculated linear and angular velocities.

// Assume Ammo has already been initialized

// Create the starting transform (Position: 0, 0, 0)
const transformStart = new Ammo.btTransform();
transformStart.setIdentity();
transformStart.setOrigin(new Ammo.btVector3(0, 0, 0));

// Create the ending transform (Position: 2, 0, 0 - moved 2 units on X-axis)
const transformEnd = new Ammo.btTransform();
transformEnd.setIdentity();
transformEnd.setOrigin(new Ammo.btVector3(2, 0, 0));

// Define the time difference between the two transforms (e.g., 1/60th of a second)
const timeStep = 1 / 60;

// Create vector objects to hold the output velocities
const linearVelocity = new Ammo.btVector3();
const angularVelocity = new Ammo.btVector3();

2. Execute the Velocity Calculation

Use the static calculateVelocity method of Ammo.btTransformUtil to perform the math. This method modifies the linearVelocity and angularVelocity vectors in place.

Ammo.btTransformUtil.prototype.calculateVelocity(
    transformStart,
    transformEnd,
    timeStep,
    linearVelocity,
    angularVelocity
);

// Access the calculated values
console.log(`Linear Velocity: X=${linearVelocity.x()}, Y=${linearVelocity.y()}, Z=${linearVelocity.z()}`);
console.log(`Angular Velocity: X=${angularVelocity.x()}, Y=${angularVelocity.y()}, Z=${angularVelocity.z()}`);

Note: Depending on your specific build of ammo.js, the utility functions might be bound directly to the global Ammo scope. If the prototype method call throws an error, try calling it directly via Ammo.btTransformUtil.calculateVelocity(...).

3. Apply the Velocities

Once calculated, you can apply these velocities directly to a rigid body. This is highly useful for matching the physics simulation of kinematic bodies to custom gameplay animations.

// Example: Applying the calculated velocity to a rigid body
rigidBody.setLinearVelocity(linearVelocity);
rigidBody.setAngularVelocity(angularVelocity);

4. Memory Management

Because ammo.js is a WebAssembly/asm.js port of the C++ Bullet Physics library, you must manually free the allocated memory to prevent memory leaks in your application.

Ammo.destroy(transformStart);
Ammo.destroy(transformEnd);
Ammo.destroy(linearVelocity);
Ammo.destroy(angularVelocity);