Create Anti-Gravity Fields with Ammo.js Trigger Volumes

This guide explains how to implement a custom anti-gravity field in a 3D environment using the Ammo.js physics engine. You will learn how to set up a ghost object as a trigger volume, detect when rigid bodies enter this zone, and apply a counter-gravity force to simulate weightlessness or upward lift.


1. Initialize the Ghost Pair Callback

Before creating a trigger volume (ghost object) in Ammo.js, you must configure the physics world to calculate overlapping pairs for ghost objects. Add the btGhostPairCallback to your dynamics world during your physics initialization:

// Enable ghost object collision tracking in the physics world
const ghostCallback = new Ammo.btGhostPairCallback();
physicsWorld.getPairCache().getOverlappingPairCache().setInternalGhostPairCallback(ghostCallback);

Without this callback, your trigger volume will not register when other rigid bodies enter its boundaries.


2. Create the Trigger Volume (Ghost Object)

A trigger volume in Ammo.js is represented by a btGhostObject. It acts as a sensor zone that detects collisions without physically blocking or colliding with other objects.

// Create the ghost object
const triggerVolume = new Ammo.btGhostObject();

// Define the shape of the anti-gravity field (e.g., a 10x10x10 box)
const halfExtents = new Ammo.btVector3(5, 5, 5);
const triggerShape = new Ammo.btBoxShape(halfExtents);
triggerVolume.setCollisionShape(triggerShape);

// Position the trigger volume in the world
const triggerTransform = new Ammo.btTransform();
triggerTransform.setIdentity();
triggerTransform.setOrigin(new Ammo.btVector3(0, 5, 0)); // Placed at Y = 5
triggerVolume.setWorldTransform(triggerTransform);

// Set collision flags to make it a non-solid trigger zone
triggerVolume.setCollisionFlags(triggerVolume.getCollisionFlags() | 4); // 4 corresponds to CF_NO_CONTACT_RESPONSE

// Add the ghost object to the dynamics world
physicsWorld.addCollisionObject(triggerVolume, 2, -1); // 2: Collision group, -1: Collision mask

3. Apply the Anti-Gravity Force in the Physics Loop

To make the anti-gravity field work, you must query the trigger volume during your application’s update loop. For every rigid body inside the volume, calculate and apply a force that counteracts the engine’s default gravity.

function updateAntiGravityField() {
    const numOverlapping = triggerVolume.getNumOverlappingObjects();

    for (let i = 0; i < numOverlapping; i++) {
        const obj = triggerVolume.getOverlappingObject(i);
        const body = Ammo.btRigidBody.prototype.upcast(obj);

        // Ensure the object is a dynamic rigid body
        if (body && !body.isStaticOrKinematicObject()) {
            // Wake up the body so physics calculations continue to run
            body.activate(true);

            // Get body mass (mass = 1 / inverseMass)
            const invMass = body.getInvMass();
            if (invMass > 0) {
                const mass = 1.0 / invMass;
                const worldGravity = physicsWorld.getGravity();

                // Calculate the force needed to negate gravity
                // You can add an extra upward force (e.g., mass * 2) to lift objects slowly
                const antiGravityForce = new Ammo.btVector3(
                    -worldGravity.x() * mass,
                    -worldGravity.y() * mass + (mass * 1.5), // Negates gravity and adds light upward lift
                    -worldGravity.z() * mass
                );

                // Apply the force directly to the center of the body
                body.applyCentralForce(antiGravityForce);
            }
        }
    }
}

4. Run the Update Function

Call updateAntiGravityField() in your main render or physics tick loop right before stepping the physics simulation:

function tick(deltaTime) {
    // 1. Apply custom forces (including anti-gravity)
    updateAntiGravityField();

    // 2. Step the physics world
    physicsWorld.stepSimulation(deltaTime, 10);

    // 3. Render your scene...
}

When dynamic objects enter the coordinates defined by the triggerVolume, the custom force will continuously act upon them. Once they drift out of the boundaries, normal gravity rules instantly resume.