Create btMatrix3x3 from Column Vectors in Ammo.js
This article explains how to construct and populate a
btMatrix3x3 rotation matrix using three individual
btVector3 column vectors in ammo.js (the
WebAssembly/Emscripten port of the Bullet physics engine). You will
learn the most memory-efficient way to map column vector components to
the row-major structure of btMatrix3x3 without causing
WebAssembly memory leaks.
In ammo.js, btMatrix3x3 is represented
internally in row-major order. When you have three column vectors
representing the basis of a coordinate system (such as the Right, Up,
and Forward vectors), they must be transposed into the rows of the
matrix.
The most efficient way to achieve this—without creating temporary row
vectors that require manual memory cleanup—is by using the
setValue method.
Step-by-Step Implementation
Assume you have three btVector3 objects representing
your columns: col0, col1, and
col2.
// 1. Define your three column vectors (e.g., Right, Up, Forward)
const col0 = new Ammo.btVector3(1.0, 0.0, 0.0); // Column 0
const col1 = new Ammo.btVector3(0.0, 1.0, 0.0); // Column 1
const col2 = new Ammo.btVector3(0.0, 0.0, 1.0); // Column 2
// 2. Instantiate an empty btMatrix3x3
const matrix = new Ammo.btMatrix3x3();
// 3. Map column elements to row elements using setValue
matrix.setValue(
col0.x(), col1.x(), col2.x(), // Row 0: X components of columns 0, 1, 2
col0.y(), col1.y(), col2.y(), // Row 1: Y components of columns 0, 1, 2
col0.z(), col1.z(), col2.z() // Row 2: Z components of columns 0, 1, 2
);How It Works
The setValue method of btMatrix3x3 accepts
nine scalar values in row-major order:
\[\begin{bmatrix} xx & xy & xz \\ yx & yy & yz \\ zx & zy & zz \end{bmatrix}\]
To construct the matrix from column vectors \(C_0, C_1, C_2\), we assign the vector
components to the matrix coordinates as follows: * Row
0 receives the X-coordinates of all three columns:
(col0.x, col1.x, col2.x) * Row 1 receives
the Y-coordinates of all three columns:
(col0.y, col1.y, col2.y) * Row 2 receives
the Z-coordinates of all three columns:
(col0.z, col1.z, col2.z)
Why Use
setValue Instead of setRow?
While you can construct a matrix by creating three temporary
btVector3 row vectors and calling
matrix.setRow(index, vector), doing so requires you to
allocate new WebAssembly memory for each row vector. Because
ammo.js does not have automatic garbage collection for
WebAssembly objects, you would have to manually call
Ammo.destroy(rowVector) on each temporary row to avoid
memory leaks.
Using setValue extracts the float values directly and
passes them to the matrix, making it the fastest and safest
approach.