Spatial queries
Ask the physics world questions without stepping it — raycasts, shape casts, and overlap tests against the live world.
Three read-only queries let you interrogate the physics world between steps. None of them mutate the simulation, and all three run against the same spatial index the solver uses — one for static geometry, one for moving bodies — so they see exactly the world the simulation sees, and scale the same way.
Each takes an optional filter(entity, collider) => boolean, consulted before the expensive exact-shape test. Use it to skip the caller’s own body, allies, sensors, or whole layers.
Raycasts
raycast finds the nearest body a ray hits. The ray is origin + unit direction + tMax.
import { Ray3 } from "@woosh/meep-engine/src/core/geom/3d/ray/Ray3.js";
import { PhysicsSurfacePoint } from "@woosh/meep-engine/src/engine/physics/queries/PhysicsSurfacePoint.js";
const ray = Ray3.from(0, 50, 0, 0, -1, 0); // origin, unit direction, optional tMax
const hit = new PhysicsSurfacePoint();
if (physics.raycast(ray, hit)) {
// hit.point, hit.normal, hit.t
}
Bullets-as-rays, line-of-sight checks, mouse picking, ground probes.
Shape casts
shapeCast is a raycast with volume: it sweeps a convex shape along a ray and returns the first body it would hit. The shape starts at ray.origin oriented by rotation, translates along ray.direction for up to ray.tMax, and the result is the nearest time-of-impact.
import { CapsuleShape3D } from "@woosh/meep-engine/src/core/geom/3d/shape/CapsuleShape3D.js";
const probe = CapsuleShape3D.from(0.4, 1.2);
const identity = { x: 0, y: 0, z: 0, w: 1 };
const ray = Ray3.from(px, py, pz, dx, dy, dz, maxDistance); // unit direction
const hit = new PhysicsSurfacePoint();
if (physics.shapeCast(ray, probe, identity, hit, (entity) => entity !== self)) {
// first contact within maxDistance — hit.point, hit.normal, hit.t
}
Internally it quickly gathers the bodies the sweep could reach, then computes the exact moment of contact for each and keeps the nearest, stopping early once nothing closer is possible. This is the query behind character controllers (“how far can I step before I hit something?”), volumetric projectiles, and camera-collision that won’t clip through walls.
Overlap queries
overlap is speculative: given a convex shape at a world pose, it reports every body that shape would touch — without moving anything. It’s the “would I collide if I stood here?” test, the foundation of kinematic and character controllers.
It writes the overlapping bodies’ packed body ids into a buffer you size, returning the count. Map an id back to its entity with physics.entityOf(id).
import { BoxShape3D } from "@woosh/meep-engine/src/core/geom/3d/shape/BoxShape3D.js";
const probe = BoxShape3D.from_size(2, 2, 2);
const ids = new Uint32Array(64); // caller sizes the buffer
const count = physics.overlap(
probe,
{ x: 0, y: 1, z: 0 }, // world position
{ x: 0, y: 0, z: 0, w: 1 }, // world rotation (unit quaternion)
ids, 0, // output buffer + start offset
(entity) => entity !== self, // skip ourselves
);
for (let i = 0; i < count; i++) {
const entity = physics.entityOf(ids[i]);
// react to the overlap…
}
Ids past the end of the buffer are dropped silently and the count caps at the space available — size the buffer for the most you care to handle. The query shape must be convex; concave shapes (heightmaps, meshes) throw, since they’re terrain, not probes.
Explosion-radius damage, build-placement validity, hand-placed trigger volumes, “is this spawn point clear?” checks.
Where to go next
- Colliders & shapes — the shapes these queries take, and the layer/mask groups the filter complements.
- Rigid bodies — driving a kinematic controller from
shapeCast/overlapresults.