New version of Rapier physics + three.js demo app

Rapier is a high-performance physics engine, written in Rust, which can be loaded as a WASM bundle. I’ve been using it in my FRPG game for the last couple of years.

I’ve recently updated my example app which shows how to get Rapier and Three.js working together. This shows how to load the WASM bundle, initialize it, and create some basic rigid bodies and colliders as well as a terrain heightfield. It also shows how to set up a basic Vite build configuration, unit tests, eslint, prettier and all of the other infrastructure that is great to have if you are doing a serious project with three.js.

The demo now uses the regular “@dimforge/rapier3d” instead of the less efficient “@dimforge/rapier3d-compat” (the latter is meant for bundlers which have trouble loading WASM bundles, which is no longer an issue.)

4 Likes

Can you suggest any React three with electron boilerplate

Thanks for sharing - nice demo! I’m working on writing a vanilla JS example of how to use Rapier with a triMesh from a loaded 3D model (which is literally a cube).

The code is still quite raw. In general, it works great with RAPIER.ColliderDesc.cuboid, but it doesn’t with RAPIER.ColliderDesc.trimesh(trimesh).

Maybe I’ve missed something in my snippet; anyone who is more familiar with RAPIER might be able to identify what’s wrong here?

/* TriMesh Collider */

import('@dimforge/rapier3d').then(rapierModule => {
    RAPIER = rapierModule;
    console.log("initRapier()");

    let gravity = { x: 0.0, y: -2.1, z: 0.0 };
    let world = new RAPIER.World(gravity);
    const eventQueue = new RAPIER.EventQueue(true);

    // Load the 3D model using Three.js's GLTFLoader
    const loader = new GLTFLoader();

    loader.load('models/floor1.glb', function (gltf) {

      const model = gltf.scene.children[0].geometry;

          // Ensure vertices and indices are correctly defined and formatted
          const vertices = new Float32Array(model.attributes.position.array);

          let indices;
          if (model.index) {
              indices = new Uint32Array(model.index.array);
          } else {
              // Handle unindexed geometry by generating indices
              indices = new Uint32Array([...Array(vertices.length / 3).keys()]);
          }


          console.log('Vertices:', vertices);
          console.log('Indices:', indices);

        try {
            const trimesh = new RAPIER.TriMesh(vertices, indices);
            console.log('TriMesh created successfully', trimesh);

            const isValid = validateMapping(trimesh.vertices, trimesh.indices);
            console.log("isValid",isValid)

            console.log('Vertices length:', vertices.length);
            console.log('Indices length:', indices.length);


            let groundColliderDesc = RAPIER.ColliderDesc.trimesh(trimesh)
                .setTranslation(0, groundHeight, 0)
                .setActiveEvents(RAPIER.ActiveEvents.COLLISION_EVENTS);

            let groundCollider = world.createCollider(groundColliderDesc);

            window.groundColliderHandle = groundCollider.handle;
            window.myRapierWorld = world;
            window.eventQueue = eventQueue;
            
        } catch (error) {
            console.error('Failed to create TriMesh:', error);
        }
    });
});

It producing an error: