- Rust 83%
- Slang 17%
Flying ~1.7 km from the world origin produced a vertical band of dark streaks and nearly doubled GPU time (16.3 -> 28.4 ms). The step-count debug view showed that band saturating the traversal step limit: rays were not advancing at all. exitT computed a cell face as (face - rayOrigin) * invRd from absolute world coordinates. At 1.7 km an f32 has ~1.2e-4 m of resolution left, so subtracting two large nearly-equal coordinates loses most of it, and a near-axis-aligned ray multiplies the residual by a huge 1/rd. The computed step fell below the rounding error and the walk stalled. Traversal now runs entirely in camera-relative space. Level corners are supplied as camera-relative offsets computed in f64 on the CPU, brick indices are resolved within a level from small coordinates, and wrapping is done on integer global brick coordinates so it stays exact at any distance from the origin. At the same position: 28.4 -> 17.8 ms with the artifacts gone. 10 km out renders clean at 16.9 ms, and behaviour at the origin is unchanged. Reproduced with zero edits, which ruled out the editing system. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|---|---|---|
| crates | ||
| shaders | ||
| .DS_Store | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
Overrun
A high-performance voxel engine with path-traced PBR lighting, built around two bets: 6.25 cm voxels in an unbounded streamed world, and simulation — every voxel carrying material state so fire, heat, liquids and structural collapse are first-class rather than cosmetic.
Rust + wgpu, shaders in Slang. Targets Metal on Apple silicon, portable to Vulkan/DX12.
Status: engine work. You can walk around, dig, build, and stream an infinite world at 60 fps. The simulation layer is not written yet.
Requirements
- Rust 1.97+
- Slang shader compiler —
slangcmust be onPATH, or setSLANGCto its location. Shaders are compiled to WGSL at build time, so this is a hard build dependency.
Running
cargo run --release -p ovr-client
The traversal benchmark from the initial feasibility spike still builds and runs, and is the reference for renderer performance numbers:
cargo run --release -p ovr-spike
Controls
WASD |
move |
Space / Ctrl |
up / down (fly), jump (walk) |
Shift |
boost |
G |
toggle fly / walk |
| Left mouse | dig |
| Right mouse | place |
| Scroll | brush size |
1–4 |
material |
F3 |
debug overlay |
Tab |
cycle view: shaded / clipmap level / normals / step heatmap |
L |
limit clipmap levels traversed |
F |
toggle shadows |
R |
cycle internal resolution |
Esc |
release mouse |
Editing any shaders/*.slang while the client is running recompiles and swaps
pipelines live. A failed compile is logged and the previous pipelines stay
bound.
OVR_* environment variables (OVR_POS, OVR_YAW, OVR_PITCH, OVR_MODE,
OVR_LEVELS, OVR_SHADOWS, OVR_WALK, OVR_AUTOWALK) set startup state, so a
specific view can be reproduced without touching the keyboard.
Layout
crates/
ovr-voxel brick/clipmap data model, palette compression, edits
ovr-worldgen terrain generation + background streaming workers
ovr-render wgpu renderer, GPU timing, shader hot reload, debug overlay
ovr-client window, player, input
ovr-spike traversal benchmark
shaders/ Slang modules shared by every kernel
How it works
Voxel data. A voxel is 1/16 m. Bricks are 8³ voxels carrying a 512-bit
occupancy mask plus a palette-compressed payload; a coarse grid sits above them
at 8³ bricks. Bricks are encoded as 0 empty, 1 fully solid (no payload at
all), n+2 sparse pool slot. That singleton encoding is what makes terrain
affordable — on heightfield terrain only ~1% of bricks need a pool slot, so a
256 m view radius spanning 4.3 billion virtual voxels fits in ~60 MB.
Clipmap. Four nested levels, each 2× coarser and covering 2× the distance, so cost is linear in level count rather than cubic in view distance. Brick coordinates are anchored to the world and wrap into the index texture modulo the level size, so moving a level costs a regenerated shell rather than a rebuild. Shells are generated on worker threads, and a level's origin is not moved until every brick is back — moving it early aliases new world coordinates onto stale texture contents.
Traversal. A four-level walk: clipmap level → coarse block → brick → voxel bitmask. Rays are split into segments at the nested box boundaries and each segment is walked at the finest level that actually contains it. Walking innermost-first is only correct for rays starting at the clipmap centre, which no shadow or secondary ray does.
Traversal runs entirely in camera-relative coordinates, with wrapping done
on integer global brick coordinates. This is required, not an optimisation: in
world space, finding a cell face means subtracting two large nearly-equal
floats, and at 1.7 km an f32 has ~0.1 mm of resolution left. Multiplied by a
near-axis-aligned ray's huge 1/rd, the step error exceeds the cell size, the
walk stops advancing, and rays grind to the step limit in a visible band.
Lighting. Two rays per pixel — a primary and one shadow ray with a bias scaled to the hit voxel's size. Indirect light is deliberately not traced per pixel: measurement showed an incoherent bounce costs ~25 ms/frame at 1080p even capped to 1 m, so it will come from a world-space irradiance probe cache instead.
License
MIT OR Apache-2.0