Convert Euler Angles to Ammo.js Quaternion
This article provides a straightforward guide on how to reliably convert standard Euler angles (pitch, yaw, and roll) into a valid Ammo.js quaternion. We will explore the native Ammo.js API method, demonstrate a common integration path using Three.js, and highlight key pitfalls like axis ordering and memory management to ensure your 3D physics rotations behave predictably.
The Native Ammo.js Method
Ammo.js (a direct Emscripten port of the Bullet Physics engine)
includes a built-in utility on the btQuaternion class
designed specifically for Euler conversions:
setEulerZYX().
To use this method successfully, you must pass your angles in radians and follow the Yaw-Pitch-Roll convention (which corresponds to rotations around the Y, X, and Z axes respectively).
// 1. Define your rotation angles in radians
const roll = 0.0; // Rotation around Z-axis
const pitch = Math.PI / 4; // Rotation around X-axis (45 degrees)
const yaw = Math.PI / 2; // Rotation around Y-axis (90 degrees)
// 2. Instantiate a new Ammo quaternion
const ammoQuaternion = new Ammo.btQuaternion();
// 3. Apply the Euler angles using the ZYX convention
// Note the parameter order: setEulerZYX(yaw, pitch, roll)
ammoQuaternion.setEulerZYX(yaw, pitch, roll);Understanding the Parameter Order
A common point of failure is passing parameters in the wrong order.
The setEulerZYX method expects: 1. First
argument: Yaw (rotation around the Y-axis) 2. Second
argument: Pitch (rotation around the X-axis) 3. Third
argument: Roll (rotation around the Z-axis)
The Three.js Integration Method
Because Ammo.js is frequently paired with Three.js, developers often
have rotation data stored in a THREE.Euler object. The most
reliable way to convert this is to let Three.js handle the
Euler-to-quaternion math, and then copy the resulting values into
Ammo.js.
// 1. Create a Three.js Euler angle (XYZ order by default)
const euler = new THREE.Euler(pitch, yaw, roll, 'XYZ');
// 2. Convert Euler to a Three.js Quaternion
const threeQuaternion = new THREE.Quaternion().setFromEuler(euler);
// 3. Create and populate the Ammo.js Quaternion
const ammoQuaternion = new Ammo.btQuaternion(
threeQuaternion.x,
threeQuaternion.y,
threeQuaternion.z,
threeQuaternion.w
);This approach is highly reliable because it leverages Three.js’s
robust handling of arbitrary rotation orders (such as YXZ
or ZYX) before passing the absolute spatial orientation
coordinates directly to Ammo.js.
Key Best Practices
Always Use Radians: Ammo.js operates strictly in radians. If your input angles are in degrees, convert them first using the formula:
radians = degrees * (Math.PI / 180).Memory Management: Ammo.js objects are compiled from C++ and do not benefit from automatic JavaScript garbage collection. If you are creating quaternions inside an animation or physics update loop, you must manually destroy them when they are no longer needed to prevent memory leaks:
Ammo.destroy(ammoQuaternion);Verify Normalization: A valid quaternion representing a rotation must have a length of 1. If you manually modify the coordinates of a quaternion, call
ammoQuaternion.normalize()to ensure it remains valid for the physics engine.