voxelRaycast()
CPU voxel raycast (Amanatides-Woo DDA), the same walk shaders/trace.wesl does on the GPU minus the coarse skip. dir need not be normalised; t is in units of dir (so origin + dir t is the hit point). Cells count as solid when data[i] !== 0 unless a solid predicate is given. Returns null when...
function voxelRaycast(
size: object,
data: Uint8Array,
origin: Vec3,
dir: Vec3,
maxT: number,
solid?: (value: number, x: number, y: number, z: number) => boolean
): VoxelHit | null;Defined in: ray.ts:102
CPU voxel raycast (Amanatides-Woo DDA), the same walk shaders/trace.wesl
does on the GPU minus the coarse skip. dir need not be normalised; t is
in units of dir (so origin + dir * t is the hit point). Cells count as
solid when data[i] !== 0 unless a solid predicate is given. Returns null
when nothing is hit within maxT.
Headless and cheap (at most one step per cell crossed), so it suits per-frame collision tests as well as picking. It walks one dense grid; a scene held only as bricks has no such array to pass.
Parameters
| Parameter | Type | Description |
|---|---|---|
size | { x: number; y: number; z: number; } | Grid extent in voxels. |
size.x | number | - |
size.y | number | - |
size.z | number | - |
data | Uint8Array | Dense grid, x + y*sx + z*sx*sy. |
origin | Vec3 | Ray start in grid space; it may lie outside the grid. |
dir | Vec3 | Ray direction; its length sets the unit of t and maxT. |
maxT | number | Give up beyond origin + dir * maxT. |
solid? | (value: number, x: number, y: number, z: number) => boolean | Narrows which non-zero cells stop the ray (water, glass, the shooter's own voxels). |
Returns
VoxelHit | null
The first solid cell and its entry face, or null.
Example
import { voxelRaycast, type Vec3 } from "@voxolith/renderer/core";
// Will a ball at `p` moving by `move` this step hit anything?
const hit = voxelRaycast(size, data, p, move, 1);
if (hit) {
const at: Vec3 = [p[0] + move[0] * hit.t, p[1] + move[1] * hit.t, p[2] + move[2] * hit.t];
bounce(at, hit.normal);
}