Real-Time 3D Physics on the Web: Pairing Three.js with Rapier WebAssembly
Original Content Disclaimer: This article is based on my hands-on experience integrating physics engines with web graphics. All code examples are original and created for educational purposes.
Introduction
Adding gravity, collisions, and kinetic forces to a WebGL canvas turns a passive viewing experience into an interactive playground. But rendering 3D physics smoothly on low-power devices requires understanding where the calculations happen.
In this article, we’ll explore how to pair Three.js (the visual engine) with Rapier (a Rust-compiled WebAssembly physics engine) to run rigid body dynamics at 60 frames per second.
Why WebAssembly?
Traditionally, JavaScript-based physics engines (like Cannon.js or Ammo.js) suffered from garbage collection pauses or struggled with large object counts. Rapier runs its heavy mathematical calculations inside WebAssembly, bypassing JS engine overhead and providing predictable frame times.
<span <span class="vs-keyword">classspan>="vs-comment">// <span class="vs-class">Syncingspan> <span class="vs-class">Threespan>.js mesh <span class="vs-keyword">withspan> <span class="vs-class">Rapierspan> rigid bodyspan>
<span <span class="vs-keyword">classspan>="vs-keyword">functionspan> <span class="vs-function">updatePhysicsspan>() {
world.<span class="vs-function">stepspan>();
<span <span class="vs-keyword">classspan>="vs-comment">// <span class="vs-class">Updatespan> visual mesh coordinates <span class="vs-keyword">fromspan> physics bodyspan>
<span <span class="vs-keyword">classspan>="vs-keyword">constspan> position = body.<span class="vs-function">translationspan>();
<span <span class="vs-keyword">classspan>="vs-keyword">constspan> rotation = body.<span class="vs-function">rotationspan>();
mesh.position.<span class="vs-function">setspan>(position.x, position.y, position.z);
mesh.quaternion.<span class="vs-function">setspan>(rotation.x, rotation.y, rotation.z, rotation.w);
}
Implementing the Loop
To maintain separation of concerns:
- ✏️Define the World: Initialize the Rapier world with gravity variables.
- ✏️Bind the Meshes: Create corresponding physical colliders for each Three.js visual geometry.
- ✏️Step the Clock: Advance the physics step on every animation frame before letting WebGL render.
By using low-friction materials and keeping geometries basic, you can create immersive 3D simulations that run flawlessly in modern mobile browsers.