Ragnavoxel docs

Voxels and units

The voxel size and the fixed storage hierarchy of chunks, blocks and bricks; how chunks compress; voxel types, materials and the six faces each voxel carries; and the heightfield patterns that give surfaces their relief.

The voxel size

core/Units.hpp. The edge of one voxel is a runtime setting, 1/64 m by default (LostVale’s microvoxels, about 1.5 cm):

rv::setVoxelSize(1.0f / 16.0f);  // before creating worlds, streamers, physics or renderers
rv::voxelSize();                 // metres per voxel
rv::blockSize();                 // a block: 64 voxels
rv::chunkSize();                 // a chunk: 1,024 voxels

The range is 1/4096 m to 16 m: 1/64 m for microvoxel worlds, 1/16 m for chunkier sculpting, 1 m for block worlds, 1/256 m for tabletop dioramas. AppConfig::voxelSize sets it for you at start-up. Values out of range throw std::invalid_argument, and setVoxelSize returns the previous scale.

Set it once, before anything is built at a scale. Everything that turns voxel coordinates into metres reads it: meshing bounds and cluster padding, physics colliders, streaming rings, the renderer’s volumes and the shaders (FrameUBO::units, MICRO in common.glsl). Changing it while worlds, streamers or renderers built at another scale are alive leaves them inconsistent; between worlds, call Renderer::resetWorld first. Heightfield relief reaches at most a brick out of a face at any scale.

The storage hierarchy

The hierarchy is fixed, so changing the voxel size scales blocks and chunks with it:

Level Holds At 1/64 m
Voxel one VoxelId 1.56 cm
Brick 8³ voxels 12.5 cm
Block 8³ bricks = 64³ voxels 1 m
Chunk 16³ blocks = 1,024³ voxels 16 m

Sparse, hierarchical chunks

voxel/Chunk.hpp stores a chunk sparsely:

  • a chunk is 16³ block entries;
  • a block is either uniform (one VoxelId fills all 64³ voxels) or a table of 8³ brick entries;
  • a brick is either uniform (one VoxelId for its 512 voxels) or a detail brick, palette-compressed at 1, 2, 4, 8 or 16 bits a voxel.

Each entry is a u32: with bit 31 clear, the low 16 bits are a uniform VoxelId; with it set, the low 31 bits index the next level. Air, solid rock and the inside of anything big collapse to a single id, so storage follows the surface, not the volume.

Voxel types and the palette

A VoxelId (a u16; 0 is always air) indexes the global VoxelPalette. Each entry is a voxel type: a material plus six face parameter sets, one for each face direction. intern(type) (or intern(material, faceParams)) returns the id of an identical type if there is one, so voxel types are deduplicated across the whole world.

Face parameters

Every face carries:

Parameter Range Meaning
pattern name the heightfield and surface pattern (below)
amplitude 0 to 255 displacement; 255 is 12.5 cm at the default scale
frequency 0 to 255 spatial frequency: 0.5 × 2f/32 cycles a metre
seed 0 to 255 pattern decorrelation
tint RGB 0 to 255 multiplies the albedo; 128 is 1.0
roughness 0 to 255 multiplies the material’s roughness; about 160 is 1.0
emissive 0 to 255 emissive boost
wetness 0 to 255 darkens and sharpens
sheen 0 to 255 back-lit translucency
seam 0 to 255 strength of the emissive seam round merged tiles; 128 is the material’s default

Materials

voxel/Material.hpp. A material carries albedo, roughness, subsurface, emission, a seam colour and strength, flags, and default face parameters. Material 0 is air and is registered automatically.

Flag Meaning
opaque blocks light and sight
water drawn by the water pass
foliage sways in the wind, back-lit translucency
emissive glows
collidable physics collides with it
dressed built by hand and laid true (walls, roofs, floors, paths): turned or pitched faces shade smooth
glass solid to the touch (collides, holds up a roof, encloses a room) but drawn by the glass pass, letting light and sight through; its albedo is the light one pane lets through, its seam colour the lead of its cames

A material may also grow grass: blades on its up-facing faces in the grass pass, with height, density, width, stiffness, root and tip colours and a share of flowers.

Heightfield patterns

Faces are not flat. On the GPU each face is tessellated and displaced by a procedural heightfield evaluated in world space, so neighbouring faces with the same parameters join seamlessly, and the displacement fades to zero at quad edges so neighbours never crack. The patterns:

  • General: flat, grain, strata, cells, bark, blades, ripples, pebbles, leafy.
  • Rocks and minerals modelled on real ones: granite (feldspar phenocrysts, quartz, biotite flecks, sheet joints), chalk (with bands of flint nodules), Carboniferous limestone (bedding planes, clints and grykes, crinoid ossicles), slate (cleavage laminae with stepped edges), sandstone (cross-bedded laminae), basalt (columnar joints, vesicles), schist (crenulated foliation with mica sheen), gneiss (banding), mudstone, quartzite, gritstone.
  • Ground: peat, clay (with desiccation cracks), shingle, dune sand (wind ripples), loam, turf, moss cushions, heather.
  • Bark: oak, beech, birch, pine and ash.
  • Leaves and flowers: lobed, oval, serrate, needle, pinnate, spiny, hawthorn, rowan, bracken, gorse, scale, pad and strap leaves, petals, blossom, berries and fungus caps. These are not noise: each grows individual leaves on the face from equations.
  • Built finishes: lime render, roof tiles, roof slates, shingles and thatch, laid in courses down the slope of the surface (frequency sets the courses per metre); glazing patterns for glass (quarries, leadwork, roundels, mosaic).

Bounded worlds

voxel/VoxelWorld.hpp is a bounded world of chunks on a dense grid. It lives as an ECS resource; per-chunk runtime state (meshes, physics bodies, dirty flags) lives on chunk entities that refer to grid cells by ChunkCoord. Most games use it through VoxelScene.

Written from the engine's headers and source as of commit 02e81b2 (2026-11-01).