Skip to content

Physics Overview (Rapier)

@orillusion/physics-rapier is a physics plugin based on Rapier (Rust → WASM), and is the recommended physics solution for new projects. It is independent of the Ammo-based @orillusion/physics and can coexist with it in the same project.

Which one should I use?

  • New projects / rigidbodies, joints, characters, vehicles, raycast queries@orillusion/physics-rapier is recommended (smaller size, official types included, deterministic simulation, built-in query/character/vehicle APIs).
  • Soft bodies (cloth, rope) → you currently still need @orillusion/physics (Ammo); the Rapier edition does not yet support soft bodies.

Comparison with the Ammo Edition

@orillusion/physics (Ammo)@orillusion/physics-rapier
BackendBullet 2.x (asm.js)Rapier (Rust → WASM)
Size~1.95 MB~600 KB
Type definitionsCommunity-maintainedOfficial
DeterministicNoYes
Raycast / sweep / overlap queriesNo public APIPhysicsQuery.*
Character controllerNoneCharacterController
VehicleBare btRaycastVehicleVehicleController
Soft bodiesSupported (cloth, rope)Not supported
Snapshot / replayPartialPhysics.snapshot / restore

Installation

Via NPM

bash
npm install @orillusion/core --save
npm install @orillusion/physics-rapier --save
ts
import { Engine3D } from '@orillusion/core';
import { Physics, Rigidbody, BodyType, CollisionShapeUtil } from '@orillusion/physics-rapier';

Via CDN (ESModule)

html
<script type="module">
  import { Engine3D } from 'https://unpkg.com/@orillusion/core/dist/orillusion.es.js'
  import { Physics } from 'https://unpkg.com/@orillusion/physics-rapier/dist/physics-rapier.es.js'
</script>

Quick Start

The physics system must first be initialized with await Physics.init(), and Physics.update() must be called in the engine render loop to advance the simulation:

ts
import { Engine3D, Object3D, MeshRenderer, BoxGeometry, LitMaterial, Vector3 } from '@orillusion/core';
import { Physics, Rigidbody, BodyType, CollisionShapeUtil } from '@orillusion/physics-rapier';

// Initialize the physics world (asynchronous, requires loading WASM)
await Physics.init();

// Advance physics in the render loop
const engine = await Engine3D.init({ renderLoop: () => Physics.update() });

// ……create scene / camera / view……

// A dynamic cube that will fall
const cube = new Object3D();
cube.y = 5;
const mr = cube.addComponent(MeshRenderer);
mr.geometry = new BoxGeometry(1, 1, 1);
mr.material = new LitMaterial();

const rb = cube.addComponent(Rigidbody);
rb.bodyType = BodyType.Dynamic;
rb.mass = 1;
rb.shape = CollisionShapeUtil.createBoxShape(cube, new Vector3(1, 1, 1));
scene.addChild(cube);

Module Overview

ClassPurposeTutorial
PhysicsPhysics world singleton: initialization, stepping, gravity, snapshotsThis page
Rigidbody / BodyTypeRigidbody component (dynamic / static / kinematic)Rigidbodies and Collision Shapes
CollisionShapeUtilCreates various collision shapesRigidbodies and Collision Shapes
HingeJoint / SliderJoint / FixedJoint / SphericalJoint / GenericJoint / RopeJoint / SpringJointJoint constraintsJoints
Rigidbody eventsTriggers and collision callbacksTriggers and Events
PhysicsQueryRaycast / sweep / overlap queriesPhysics Query
CharacterController / VehicleControllerCharacter controller / vehicleCharacter and Vehicle

Migrating from the Ammo Edition

Main changes:

ts
- import { Physics, Rigidbody, ColliderComponent, BoxColliderShape } from '@orillusion/physics';
+ import { Physics, Rigidbody, BodyType, CollisionShapeUtil } from '@orillusion/physics-rapier';
Ammo EditionRapier Edition
rb.mass = 0 means staticrb.bodyType = BodyType.Static (mass = 0 also works)
ColliderComponent + BoxColliderShaperb.shape = CollisionShapeUtil.createBoxShape(obj, ...) (no separate collider component needed)
setLinearFactor(x, y, z)rb.lockTranslations(x === 0, y === 0, z === 0)
Physics.world.rayTest(...) (private)PhysicsQuery.raycast(origin, dir, { ... })
Joints HingeConstraint / SliderConstraint, etc.Renamed to HingeJoint / SliderJoint, etc.
PointToPointConstraint + ConeTwistConstraintUnified into SphericalJoint
Soft bodies ClothSoftbody / RopeSoftbodyNot supported, keep using @orillusion/physics

Escape Hatch (Direct Rapier Access)

When you need native Rapier capabilities that the engine wrapper does not expose, you can access the underlying objects directly (this gives up cross-backend portability):

ts
import RAPIER from '@dimforge/rapier3d-compat';

const native = rb.native;     // Rapier native RigidBody
const world = Physics.world;  // Rapier native World
world.integrationParameters.numSolverIterations = 8;

Released under the MIT License