Skip to content

Rigidbodies and Collision Shapes

The rigidbody (Rigidbody) is the core component of physics simulation, and the collision shape (created via CollisionShapeUtil) describes the geometric outline that an object uses to participate in collisions.

Rigidbody Types

Set the rigidbody type via rb.bodyType:

TypeDescription
BodyType.DynamicDynamic rigidbody, driven by gravity and collisions, requires mass to be set
BodyType.StaticStatic rigidbody, never moves (ground, walls, etc.)
BodyType.KinematicKinematic rigidbody, its position driven by code, unaffected by forces but pushes dynamic objects
ts
import { Object3D, MeshRenderer, BoxGeometry, LitMaterial, Vector3 } from '@orillusion/core';
import { Rigidbody, BodyType, CollisionShapeUtil } from '@orillusion/physics-rapier';

// Static ground
const floor = new Object3D();
const fb = floor.addComponent(Rigidbody);
fb.bodyType = BodyType.Static;
fb.shape = CollisionShapeUtil.createPlaneShape(250, 0.05);
scene.addChild(floor);

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

Collision Shapes

CollisionShapeUtil provides factory methods for common shapes:

MethodShape
createBoxShape(obj, halfExtents)Box
createSphereShape(obj, radius)Sphere
createCapsuleShape(...)Capsule
createCylinderShape(...)Cylinder
createConeShape(...)Cone
createPlaneShape(size, thickness)Plane
createConvexHullShape(...)Convex hull
createTrimeshShape(...)Triangle mesh (static)
createHeightfieldShape(...)Heightfield terrain
createCompoundShape(...)Compound shape
ts
rb.shape = CollisionShapeUtil.createSphereShape(sphere, 1);

Common Properties and Methods

MemberDescription
bodyTypeRigidbody type (see above)
massMass (dynamic rigidbody)
shapeCollision shape
nativeUnderlying Rapier native RigidBody (escape hatch)
enableCcd(true)Enables continuous collision detection (prevents fast-moving objects from tunneling)
lockTranslations(x, y, z)Locks translation on the specified axes
lockRotations(x, y, z)Locks rotation on the specified axes
ts
// High-speed bullet: enable CCD to prevent tunneling
rb.enableCcd(true);

// Allow movement only on the XZ plane (lock Y-axis translation) — equivalent to Ammo's setLinearFactor(1,0,1)
rb.lockTranslations(false, true, false);

Shape creation depends on the object's current geometry/scale, so it is recommended to create the shape after setting up the MeshRenderer and Transform.

Example

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { CameraUtil, HoverCameraController, View3D, DirectLight, AtmosphericComponent, Scene3D, Object3D, LitMaterial, Engine3D, BoxGeometry, MeshRenderer, Vector3, PlaneGeometry, Color, SphereGeometry } from "@orillusion/core";
import { Physics, Rigidbody, BodyType, CollisionShapeUtil } from "@orillusion/physics-rapier";

class Sample_Rigidbody {
    engine!: Engine3D;
    scene!: Scene3D;
    materials!: LitMaterial[];
    boxGeometry!: BoxGeometry;

    async run() {
        await Physics.init();

        const engine = this.engine = await Engine3D.init({
            renderLoop: () => Physics.update(),
            setting: {
                shadow: {
                    autoUpdate: true,
                    updateFrameRate: 1,
                    shadowSize: 2048,
                },
            },
        });

        this.scene = new Scene3D();

        let camera = CameraUtil.createCamera3DObject(this.scene);
        camera.perspective(60, this.engine.aspect, 0.1, 800.0);

        let hoverCtrl = camera.object3D.addComponent(HoverCameraController);
        hoverCtrl.setCamera(0, -25, 100);
        hoverCtrl.dragSmooth = 4;

        let lightObj3D = new Object3D();
        lightObj3D.localRotation = new Vector3(-35, -143, 92);

        let light = lightObj3D.addComponent(DirectLight);
        light.lightColor = Color.COLOR_WHITE;
        light.castShadow = true;
        light.enableCSM = true;
        light.intensity = 2.2;
        this.scene.addChild(light.object3D);

        let atmosphericSky = this.scene.addComponent(AtmosphericComponent);
        atmosphericSky.sunY = 0.6;

        await this.initScene(this.scene);

        let view = new View3D();
        view.camera = camera;
        view.scene = this.scene;
        engine.startRenderView(view);
    }

    async initScene(scene: Scene3D) {
        this.initMaterials();
        this.createGround();
        this.dropSphere();

        let interval = setInterval(() => {
            this.addRandomBox();
            if (scene.entityChildren.length > 200) clearInterval(interval);
        }, 100);
    }

    private initMaterials() {
        this.materials = [];
        for (let i = 0; i < 20; i++) {
            const mat = new LitMaterial();
            mat.baseColor = new Color(Math.random(), Math.random(), Math.random(), 1.0);
            mat.metallic = Math.min(Math.random() * 0.1 + 0.2, 1.0);
            mat.roughness = Math.min(Math.random() * 0.5, 1.0);
            this.materials.push(mat);
        }
    }

    private get randomMaterial(): LitMaterial {
        return this.materials[Math.floor(this.materials.length * Math.random())];
    }

    private createGround() {
        const floorMat = new LitMaterial();
        floorMat.baseMap = this.engine.res.grayTexture;
        floorMat.roughness = 0.85;
        floorMat.metallic = 0.01;

        const floor = new Object3D();
        const renderer = floor.addComponent(MeshRenderer);
        renderer.castShadow = true;
        renderer.receiveShadow = true;
        renderer.geometry = new PlaneGeometry(500, 500, 1, 1);
        renderer.material = floorMat;

        const rb = floor.addComponent(Rigidbody);
        rb.bodyType = BodyType.Static;
        rb.shape = CollisionShapeUtil.createPlaneShape(250, 0.05);
        rb.friction = 1.0;

        this.scene.addChild(floor);
    }

    private dropSphere() {
        const sphere = new Object3D();
        const mr = sphere.addComponent(MeshRenderer);
        mr.geometry = new SphereGeometry(1, 32, 32);
        mr.material = this.randomMaterial;
        mr.castShadow = true;
        mr.receiveShadow = true;

        sphere.y = 25;

        const rb = sphere.addComponent(Rigidbody);
        rb.bodyType = BodyType.Dynamic;
        rb.mass = 1;
        rb.restitution = 0.7;
        rb.shape = CollisionShapeUtil.createSphereShape(sphere, 1);

        this.scene.addChild(sphere);
    }

    private addRandomBox() {
        this.boxGeometry ||= new BoxGeometry(1, 1, 1);
        const box = new Object3D();

        const mr = box.addComponent(MeshRenderer);
        mr.geometry = this.boxGeometry;
        mr.material = this.randomMaterial;
        mr.castShadow = true;
        mr.receiveShadow = true;

        box.y = 20;
        box.x = Math.random() * 20 - 10;
        box.z = Math.random() * 20 - 10;

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

        this.scene.addChild(box);
    }
}

new Sample_Rigidbody().run();

Released under the MIT License