voxolith

orbit

A voxel grid written by hand, drawn with the engine's orbit camera controller (drag, wheel, pinch, right-drag pan), rendering only when the view changes.

Open the live page · Source

Sine-wave hills with water in the hollows, 96 × 32 × 96 voxels, written straight into a Uint8Array. Drag to turn, wheel or pinch to zoom, right-drag or two fingers to pan.

What it shows

The interesting part

// Nothing animates here, so render on demand: the loop only draws when
// input or a resize invalidates it.
const camera = makeCamera({ target: [size.x / 2, 8, size.z / 2], distance: 200, pitchDeg: 32, fovDeg: 35 });
const loop = runLoop(() => {
  resizeToDisplay(gpu);
  renderer.render({ ...camera(orbit.yaw(), orbit.distance(), orbit.target(), orbit.pitch()), ...DAYLIGHT });
}, false);
observeResize(canvas, loop);

// One input per surface; the controller reads it. Passing the loop makes
// every input event request a frame.
prepareSurface(canvas, { contextMenu: false });
const input = createInput(canvas, { loop });
const orbit = makeOrbitController(input, {
  yaw: 35, pitch: 32, distance: 200, distanceLimits: [40, 600], pitchLimits: [8, 85],
  target: [size.x / 2, 8, size.z / 2], pan: "secondary", fovDeg: 35,
});
loop.invalidate();

runLoop is the examples' two-line wrapper round makeFrameLoop (src/shared/boot.ts); false means not continuous. prepareSurface(canvas, { contextMenu: false }) also suppresses the context menu, so right-drag can pan.

URL options

optioneffect
?selftest=1, 2, 3debug bands showing which stage of the voxel lookup works on this GPU, for diagnosing a blank canvas

Plus the common ones.

See also Cameras and Input.

On this page