How to Get Ammo.js Raycast Hit Fraction

This article explains how to retrieve the fraction of the total ray distance traveled when performing a raycast in Ammo.js. You will learn how to access the specific property on the raycast callback object that contains this value and how to use it to calculate the precise Euclidean distance of the collision from the ray’s origin.

In Ammo.js (the WebIDL/Emscripten port of the Bullet Physics library), raycasting is typically performed using the ClosestRayResultCallback class. When a ray intersects with a physics body, Ammo.js calculates the hit point as a normalized fraction between 0.0 (the start of the ray) and 1.0 (the end of the ray).

Accessing the Hit Fraction

To get this fraction, you must call the get_m_closestHitFraction() method on your raycast callback instance after the physics world performs the ray test.

Here is a practical code example demonstrating how to set up the raycast and retrieve the hit fraction:

// 1. Define the start and end vectors of the ray
const rayFrom = new Ammo.btVector3(0, 10, 0);
const rayTo = new Ammo.btVector3(0, -10, 0);

// 2. Create the raycast callback object
const rayCallback = new Ammo.ClosestRayResultCallback(rayFrom, rayTo);

// 3. Perform the raycast in the physics world
physicsWorld.rayTest(rayFrom, rayTo, rayCallback);

// 4. Check for a collision and retrieve the hit fraction
if (rayCallback.hasHit()) {
    // Access the fraction (a float value between 0.0 and 1.0)
    const hitFraction = rayCallback.get_m_closestHitFraction();
    
    console.log(`Hit Fraction: ${hitFraction}`);
}

// 5. Clean up memory
Ammo.destroy(rayFrom);
Ammo.destroy(rayTo);
Ammo.destroy(rayCallback);

Calculating the Actual Distance

Because the hit fraction is a normalized value representing the percentage of the ray traveled, you can easily calculate the actual distance in world units by multiplying the total length of the ray by the fraction.

// Calculate total length of the ray
const dx = rayTo.x() - rayFrom.x();
const dy = rayTo.y() - rayFrom.y();
const dz = rayTo.z() - rayFrom.z();
const totalRayLength = Math.sqrt(dx * dx + dy * dy + dz * dz);

// Calculate exact distance to the hit point
const hitDistance = totalRayLength * hitFraction;

console.log(`Distance to obstacle: ${hitDistance} units`);