-
Notifications
You must be signed in to change notification settings - Fork 0
World System
The world system implements Minecraft-style voxel terrain with streaming chunk loading, greedy mesh optimization, and multi-level LOD for extreme render distances.
| Component | Responsibility |
|---|---|
World |
Chunk orchestration, loading/unloading, rendering |
Chunk |
16x256x16 block storage with lighting |
ChunkMesh |
GPU mesh from block data |
GlobalVertexAllocator |
4GB GPU megabuffer |
LODManager |
Distant Horizons-style LOD system |
File: src/world/chunk.zig
| Constant | Value | Description |
|---|---|---|
CHUNK_SIZE_X |
16 | Width in blocks |
CHUNK_SIZE_Y |
256 | Height in blocks |
CHUNK_SIZE_Z |
16 | Depth in blocks |
CHUNK_VOLUME |
65,536 | Total blocks per chunk |
MAX_LIGHT |
15 | Maximum light level |
| Field | Type | Description |
|---|---|---|
chunk_x, chunk_z
|
i32 |
Chunk coordinates |
blocks |
[65536]BlockType |
Block data |
light |
[65536]PackedLight |
Per-block lighting |
biomes |
[256]BiomeId |
Biome per column |
heightmap |
[256]i16 |
Surface Y per column |
state |
State |
Pipeline state |
pin_count |
atomic.Value(u32) |
Async protection |
packed struct {
block_light: u4 = 0, // Lower 4 bits
sky_light: u4 = 0, // Upper 4 bits
}Index formula: x + z * 16 + y * 256 (Y-major for cache-efficient layer iteration)
missing → generating → generated → meshing → mesh_ready → uploading → renderable
| Function | Description |
|---|---|
worldToChunk(world_x, world_z) |
Convert world to chunk coords |
worldToLocal(world_x, world_z) |
Convert world to local (0-15) |
getIndex(x, y, z) |
Local coords to flat index |
File: src/world/world.zig
| Field | Description |
|---|---|
chunks |
HashMap of loaded chunks |
chunks_mutex |
Thread-safe access |
generator |
Terrain generator |
render_distance |
Visible chunk radius |
gen_queue / mesh_queue
|
Priority job queues |
gen_pool (4) / mesh_pool (3) |
Worker threads |
upload_queue |
Pending GPU uploads |
vertex_allocator |
4GB megabuffer |
lod_manager |
Optional LOD system |
| Method | Description |
|---|---|
init(allocator, distance, seed, rhi) |
Standard init |
initWithLOD(allocator, distance, seed, rhi, lod_config) |
Init with LOD |
update(player_pos, dt) |
Queue chunks, process uploads |
render(view_proj, camera_pos) |
Render with frustum culling |
renderShadowPass(light_matrix, camera_pos) |
Shadow map rendering |
getBlock(x, y, z) |
Read block at world coords |
setBlock(x, y, z, block) |
Set block, update neighbors |
fn update(self, player_pos, dt) {
const player_cx = worldToChunk(player_pos.x);
const player_cz = worldToChunk(player_pos.z);
// Queue chunks within render distance
for (-render_distance..render_distance) |dx| {
for (-render_distance..render_distance) |dz| {
const cx = player_cx + dx;
const cz = player_cz + dz;
if (!self.hasChunk(cx, cz)) {
self.queueGeneration(cx, cz);
}
}
}
// Process uploads (max 32/frame)
while (upload_queue.pop()) |chunk| {
chunk.mesh.upload(vertex_allocator);
}
// Unload distant chunks
self.unloadDistant(player_cx, player_cz);
}pub const RenderStats = struct {
chunks_rendered: u32,
chunks_culled: u32,
vertices_rendered: u64,
};File: src/world/chunk_mesh.zig
- For each axis (Y, X, Z), iterate through boundary planes
- Compare adjacent blocks across the boundary
- Create mask of faces needing rendering
- Merge adjacent faces with matching properties:
- Same block type
- Same light level
- Same biome color
- Generate quads with UVs, normals, and lighting
| Field | Description |
|---|---|
solid_allocation |
GPU buffer for opaque geometry |
fluid_allocation |
GPU buffer for transparent geometry |
pending_solid/fluid |
CPU data awaiting upload |
mutex |
Thread safety |
Cross-chunk face culling requires neighbor access:
pub const NeighborChunks = struct {
north: ?*const Chunk = null, // -Z
south: ?*const Chunk = null, // +Z
east: ?*const Chunk = null, // +X
west: ?*const Chunk = null, // -X
};| Pass | Blocks |
|---|---|
| Solid | Opaque blocks (stone, dirt, etc.) and leaves |
| Fluid | Transparent blocks (water) |
Fluid pass renders after solid for correct blending.
File: src/world/chunk_allocator.zig
Single large GPU buffer (default 4GB) for all chunk vertices.
| Field | Description |
|---|---|
buffer |
Single GPU buffer handle |
capacity |
Total buffer size in bytes |
free_blocks |
Sorted free-list |
mutex |
Thread-safe allocation |
- Best-fit: Smallest block that fits request
- Coalescing: Merge adjacent free blocks on free
- No buffer switching: Same buffer for all chunks
pub const VertexAllocation = struct {
offset: usize, // Byte offset in megabuffer
count: u32, // Vertex count
handle: BufferHandle, // Same for all allocations
};File: src/world/lod_manager.zig
Distant Horizons-style multi-level LOD for extreme render distances (100+ chunks).
| Level | Scale | Grid Size | Description |
|---|---|---|---|
| LOD0 | 1 (2x2) | Full | Standard voxel chunks |
| LOD1 | 2 (4x4) | 32x32 | 2-block resolution |
| LOD2 | 4 (8x8) | 32x32 | 4-block resolution |
| LOD3 | 8 (16x16) | 32x32 | Heightmap only |
| Parameter | Default | Description |
|---|---|---|
lod0_radius |
16 | Matches render_distance |
lod1_radius |
40 | Extended distance |
lod2_radius |
80 | Extended distance |
lod3_radius |
160 | Horizon distance |
- LOD regions hide when all underlying chunks are renderable
- Rendered with -3.0 Y offset to prevent terrain poking
- Frustum culled per region
struct {
width: u32, // Grid size (32)
heightmap: []i16, // Height per cell
biomes: []BiomeId, // Biome per cell
top_blocks: []BlockType, // Surface block
colors: []u32, // Packed RGB
}| Pool | Threads | Purpose |
|---|---|---|
gen_pool |
4 | Terrain generation |
mesh_pool |
3 | Greedy meshing |
lod_gen_pool |
3 | LOD generation/meshing |
- RwLock on chunk map (shared reads, exclusive writes)
- Mutex on job queues and mesh data
- Atomic pin_count prevents unload during async work
Jobs sorted by squared distance to player. Closer chunks processed first.
Maximum 32 GPU uploads per frame to prevent stalls.
Player Position
↓
World.update() → Queue chunks needing generation
↓
gen_pool (4 workers) → TerrainGenerator.generate()
↓
mesh_pool (3 workers) → ChunkMesh.buildWithNeighbors()
↓
upload_queue → GlobalVertexAllocator.allocate() [main thread]
↓
World.render() → Frustum cull, draw solid, draw fluid
LODManager (parallel):
↓
lod_gen_pool (3 workers) → Generate heightmap, build LODMesh
↓
LODManager.render() → Draw LOD3, LOD2, LOD1 (far to near)
| Coordinate | Type | Range | Conversion |
|---|---|---|---|
| World | i32 |
Infinite | Base unit |
| Chunk | i32 |
Infinite | @divFloor(world, 16) |
| Local | u32 |
0-15 (X/Z), 0-255 (Y) | @mod(world, 16) |
| Region (LODn) | i32 |
Infinite | @divFloor(chunk, chunksPerSide) |
- Block Types - Block definitions
- World Generation - Terrain generation
- Rendering - GPU rendering
Source: src/world/ | Last updated: January 2026