Ray casting straight from the descriptor (provisional)

Updated 2026-10-30 17:22; written from docs/raycast.md on branch raycast-slab (sections/raycast/README.txt).

Work in progress: these numbers will change. Bench prototypes on branch raycast-slab (commit 0031825c), not in the package; four objects (mug, dino, skillet, bowl), 128 layers, 6144 atoms. CPU: i5-10400F, 12 threads; GPU: GTX 1650. Rays go straight from the descriptor: no decode grid, no marching cubes, no mesh BVH.

The slab tracer bins the ring edges on one xy grid per layer, skips uniform voxels with a 3D walk (a regular grid built from the rings in about 20 ms, 14 MB at 128 layers), and finds hits in closed form on walls and caps. It has two modes. Exact follows the package's SDF surface, evaluating the field only where two neighbouring layers disagree. Staircase extrudes each layer's rings half a layer up and down, the collision study's rule: no field evaluations, but up to half a layer off the SDF surface on sloped walls (median 0.02–0.2 % of the diagonal, p99 0.1–14 % on grazing rays). The earlier field tracer (certified segment tracing on the field) is the reference it is checked against.

ns per ray (mug / dino / skillet / bowl)640×480 view1M random rays (200k on the CPU)setup
slab, exact, numba1034 / 1078 / 958 / 13071008 / 1006 / 1004 / 1386about 20 ms tables
slab, exact, GPU (two passes)437 / 861 / 435 / 332922 / 1016 / 699 / 835+ 8–13 ms upload
slab, staircase, numba386 / 320 / 380 / 576353 / 304 / 403 / 505as above
slab, staircase, GPU11 / 19 / 5 / 1442 / 37 / 35 / 43as above
field tracer, numba6400 / 3700 / 4900 / 590010800 / 4100 / 10500 / 1270013 ms
Embree (Open3D RaycastingScene)13 / 8 / 7 / 1322 / 11 / 15 / 23decode 120–340 ms + 1–6 ms
Warp GPU BVH (mesh_query_ray)6.9 / 3.9 / 2.6 / 5.254 / 22 / 31 / 62decode + 1–3 ms

Time: the staircase on the GPU is on par with Embree and a GPU BVH per ray (views 5–19 ns against Embree's 7–13 and Warp's 3–7; random rays 35–43 against 11–23 and 22–62), without a decode. The exact mode now runs on the GPU in two passes, so the rays tracing blend intervals no longer hold up the others: 0.33–1.02 µs per ray, 26–108× slower than Embree, and faster than the 12 CPU threads (0.96–1.4 µs, 46–137×). On the CPU it is 3–11× faster than the field tracer. The CPU rows of this table are one run with another job on the machine, so 10–30 % above the quietest runs. Setup is the remaining edge: about 20 ms of tables (plus 8–13 ms upload on the GPU) instead of a 120–340 ms decode, so the descriptor wins in total time up to roughly 107 staircase rays or 105 exact rays per object.

Accuracy: against a fine march on 4 views of 64×48 plus 2000 random, 2000 grazing and 2000 inside rays per object, exact mode had 0 missed and 0 late hits on all four objects, in numba and on the GPU (float32). On grazing rays the GPU has 1–5 of 2000 tangent touches, where the field stays below the hit tolerance between its hit and the reference's. GPU and numba agree to 1e-5 % of the diagonal (median). The staircase equals a fine staircase march on every set.

Next: fewer field evaluations in the blend intervals, tuning the staircase, then a decision on Shape.raycast and which surface it uses.