Skip to main content

Module voxel

Module voxel 

Source
Expand description

The voxel system (ADR-0268): a 3D cellular automaton in a cube of cells, drawn as a glowing, absorbing volume — or as lit solid cells (ADR-0269) — seen through the shared orbit camera.

§The state

A ping-pong pair of 3D textures of side grid, one u32 a cell packing its state and its age (shader::STEP_SHADER). One generation is one compute dispatch that counts each cell’s live neighbours and applies the rule (rules). The pair is built when a preset is configured, never on a frame.

[voxel] grid is content, not a resolution: a structure is a fixed number of cells, so the grid decides how large every structure looks. A grid past the scene’s cap is clamped and announced from configure as a CapOverflow, never silently reduced.

§Generations, not frames

step_rate is in generations per second, integrated over the injected dt by the shared common::GenerationClock, so the automaton advances by the same count in the same wall time at any refresh rate.

§Every cell is drawn from the seed

The field is seeded from an integer hash of each cell’s coordinates and a seed derived from the preset’s pinned salt (ADR-0051) — never from a clock — and each step is integer counting, so a volume is a pure function of its config and the sequence of bound values and dts it was driven with. Each reseed rise refills a ball whose centre and cells are hashed from the rise count and the salt.

§The rule list and the music

[voxel] rules is a list of one to eight rules, and the structural rule parameter indexes it, so a preset moves the rule on the bar through [hold] without a mask ever passing through an f32 (ADR-0268). The rule a frame picks runs every generation that frame encodes. The spectrum lights the cube’s radial shells, bass at the centre, by 1 + shell_gain * level: an exact identity at zero gain, and the simulation never reads it.

§The present

A fullscreen march: each pixel’s ray is walked cell by cell through the cube [-1, 1]^3 under emission-absorption (shader::MARCH_SHADER), and stops once its transmittance is under one 8-bit step. The ray is recovered from the camera’s world-to-clip rows, whose aspect is the render target’s (ADR-0037). focus and aperture are inert here: the circle of confusion is per primitive (ADR-0257), and a march has no primitives.

The march draws into a target of its own — the tier’s voxel_march_scale of the render target, held to its voxel_march_cap — and a plain stretch presents it. The target is a resolution, not a shape: the march’s aspect stays the render target’s whatever the target’s own is.

§Solid

Under [voxel] present = "solid" (ADR-0269) the same march stops at the first live cell. The decay stages in front of it glow and absorb as they do under glow; the live cell is shaded as a face — its normal the face the ray entered through, exact from the traversal’s last step — under one directional key light and an ambient term:

shade = palette(age) * brightness * shell * (ambient * occ + key * max(0, n . l))

composited under the light gathered so far, at full coverage. The light is given in camera space (light_dir), so the lit side turns with an orbit. occ is the face’s voxel ambient occlusion: each of its four corners is closed by the live cells beside it in the layer in front of the face — two sides close it fully, otherwise each of the two sides and the diagonal a third — and the four are interpolated across the face at the hit point and mixed in by ao.

§Bounce

bounce (ADR-0272) lets a solid face take light from the live cells in front of it. A light field of side grid / LIGHT_CELL holds, per texel, the live fraction of the LIGHT_CELL³ block of cells it covers and that block’s summed age weighted the same way; a second texture holds it blurred once over 3³ texels by a 1-2-1 tent on each axis. The march samples the blurred field trilinearly half a cell in front of the face it hit, and adds

bounce * palette(coord at L.age) * L.intensity * brightness * fog * shell

where L.age is the sampled age over the sampled intensity. The colour is looked up at shade time, so only the intensity and the age wait for the next refill. The field has no occlusion: light passes through walls.

The field is refilled beside the brick pass, after every frame that changed the state, and on the first frame bounce turns on after frames that did not fill it. It exists only once a frame under solid has bounce > 0: before that the march binds a one-texel stand-in and the uniform skips the fetch, so a preset that never binds bounce builds and reads nothing.

§The section plane

cut, cut_yaw and cut_pitch (ADR-0271) hide every cell whose centre c, in the cube’s [-1, 1]^3 frame, lies beyond one plane:

dot(c, n) > sqrt(3) * (1 - 2 * cut)
n = (cos(cut_pitch) * sin(cut_yaw), sin(cut_pitch), cos(cut_pitch) * cos(cut_yaw))

so at cut = 0.5 the plane passes through the centre and at 1 it removes every cell. The normal is in the cube’s frame, not the camera’s, so the section turns with the structure. A cut cell is dead to the march, under either present, and to the solid present’s occlusion, which reads it as open. The automaton still runs it: only the view is cut. At cut = 0 the test is switched off by a flag, so every pixel is as it is without the params.

§Bricks

After every frame that changed the state, a pass marks each 8³ brick of cells that holds any non-dead cell. The march jumps a whole empty brick at once, landing on exactly the cell, crossing parameters and position stepping through it would have (the crossings are computed from the boundary index, never accumulated), so skipping bricks moves no pixel. A brick is skipped on its own empty flag alone: one holding cut cells is marched cell by cell, and the cut is applied there.

Re-exports§

pub use rules::DEFAULT_RULE;
pub use rules::Neighbourhood;
pub use rules::RosterRule;
pub use rules::Rule;
pub use rules::RuleList;

Modules§

rules
The voxel system’s rules: a 3D automaton in the Generations sense, and the closed roster of named ones a preset lists in [voxel] rules (ADR-0268).

Structs§

VoxelConfig
[voxel] — the structural configuration, fixed while the preset is loaded and delivered through Scene::configure.
VoxelScene
A 3D automaton in a cube, marched as an emitting, absorbing volume, or as lit solid cells inside the glow of their own decay.

Enums§

Present
[voxel] present — how the march draws a live cell (ADR-0269).

Constants§

DEFAULT_GRID
The grid an absent [voxel] grid means.
FAMILY_PARAMS
Every parameter only one present reads (ADR-0180 rule 4): the light, which a glowing volume has no surface to take. A parameter missing from here reads the same on both.
MAX_GRID
The largest grid the loader accepts and any tier runs: 2.1 M cells, two 4-byte texels each across the ping-pong pair, 16.8 MB.
MAX_SHELLS
The most radial shells the spectrum can be laid across: four vec4s of the march’s uniform.
MAX_STEP_RATE
The fastest step_rate the clock integrates, in generations per second. Well past the declared range’s top, so it bounds a runaway binding rather than an author.
MIN_GRID
The smallest grid the loader accepts. Below it a seeded ball is a handful of cells and every rule’s structure is cut by the faces.
PARAMS
The parameter names this scene consumes — the vocabulary a preset binding is checked against at load (ADR-0020). Keep in sync with set_param below; declared_params_match_set_param in core/tests/suite/preset.rs fails if the two drift.