Skip to content

Rendering

MichaelFisher1997 edited this page Jan 5, 2026 · 1 revision

Rendering

ZigCraft uses a Vulkan-based rendering system with a clean abstraction layer. This document covers the graphics pipeline, camera system, shadows, and resource management.


Render Hardware Interface (RHI)

File: src/engine/graphics/rhi.zig

The RHI provides an abstract graphics API that backends implement. This decouples game logic from Vulkan specifics.

Handle Types

BufferHandle  = u32   // GPU buffers (vertex, index, uniform)
ShaderHandle  = u32   // Shader pipelines
TextureHandle = u32   // Textures

Vertex Format

pub const Vertex = extern struct {
    pos: [3]f32,        // Position
    color: [3]f32,      // Vertex color
    normal: [3]f32,     // Surface normal
    uv: [2]f32,         // Texture coordinates
    tile_id: u32,       // Texture atlas tile
    skylight: u8,       // Sky light level (0-15)
    blocklight: u8,     // Block light level (0-15)
};

Key Operations

Category Functions
Lifecycle init(), deinit(), gc()
Buffers createBuffer(), uploadBuffer(), updateBuffer(), destroyBuffer()
Shaders createShader(), bindShader(), shaderSetMat4/Vec3/Float/Int()
Frame beginFrame(), endFrame(), abortFrame()
Passes beginMainPass(), endMainPass(), beginShadowPass(), endShadowPass()
Drawing draw(), drawOffset(), drawSky(), drawClouds()
Textures createTexture(), bindTexture(), updateTexture(), destroyTexture()
UI beginUI(), endUI(), drawUIQuad(), drawUITexturedQuad()
Settings setViewport(), setWireframe(), setVSync(), setMSAA()

Vulkan Backend

File: src/engine/graphics/rhi_vulkan.zig

Implements the RHI interface for Vulkan with support for:

  • Double buffering (2 frames in flight)
  • MSAA (1x/2x/4x/8x)
  • Reverse-Z depth for better precision
  • Deferred buffer deletion

Pipelines

Pipeline Purpose
pipeline Main terrain (fill mode)
wireframe_pipeline Debug wireframe
shadow_pipeline Depth-only shadow maps
sky_pipeline Procedural sky
ui_pipeline Solid color UI
ui_tex_pipeline Textured UI
cloud_pipeline Volumetric clouds

Frame Lifecycle

1. beginFrame()    → Wait fence, acquire swapchain, begin command buffer
2. beginMainPass() → Start color/depth render pass
3. draw*()         → Record draw commands
4. endMainPass()   → End render pass
5. endFrame()      → Submit commands, present swapchain

Uniform Buffers

UBO Contents
GlobalUniforms view_proj, camera, lighting, fog, clouds
ShadowUniforms CSM matrices, cascade splits
ModelUniforms Push constant: model matrix, mask radius

Camera

File: src/engine/graphics/camera.zig

First-person camera with mouse look and WASD movement.

Camera Struct

Field Type Default Description
position Vec3 World position
yaw f32 Horizontal rotation (radians)
pitch f32 Vertical rotation (radians)
fov f32 70° Field of view
near f32 0.5 Near clip plane
far f32 10000 Far clip plane
move_speed f32 10.0 Movement speed
sensitivity f32 0.002 Mouse sensitivity

Key Methods

Method Description
getViewMatrix() Standard view matrix
getViewMatrixOriginCentered() Floating-origin (camera at 0,0,0)
getProjectionMatrix(aspect) Perspective projection
getViewProjectionMatrixOriginCentered(aspect) Combined VP for chunks
getInvViewProjectionMatrix(aspect) For sky ray reconstruction

Floating-Origin Rendering

To prevent precision issues at large coordinates:

  • Camera stays at origin
  • World translates relative to camera
  • Chunks use chunk_pos - camera_pos for rendering

Cascaded Shadow Maps

File: src/engine/graphics/csm.zig

Multi-cascade shadow mapping for high-quality shadows at all distances.

ShadowCascades

Field Type Description
light_space_matrices [3]Mat4 Per-cascade orthographic projections
cascade_splits [3]f32 View-space Z boundaries
texel_sizes [3]f32 Shadow map texel sizes (for PCF)

Algorithm

For each cascade:
1. Compute split distance (λ=0.92 log/linear blend)
2. Calculate bounding sphere of frustum slice
3. Transform to world space
4. Build light-space rotation matrix
5. Snap to texel grid (prevents shadow swimming)
6. Create orthographic projection

Shadow Quality Settings

Quality Resolution
Low 1024
Medium 2048
High 4096
Ultra 8192

Render Graph

File: src/engine/graphics/render_graph.zig

Orchestrates render pass ordering and execution.

Pass Order

1. shadow_cascade_0   → Near shadow map
2. shadow_cascade_1   → Medium shadow map
3. shadow_cascade_2   → Far shadow map
4. sky                → Procedural sky
5. main_opaque        → Terrain rendering
6. clouds             → Cloud layer
7. ui                 → User interface

Execute Flow

pub fn execute(rhi, world, camera, sun_dir, ...) {
    // Shadow passes
    for (0..3) |cascade| {
        const csm = computeCascades(cascade, ...);
        rhi.beginShadowPass(cascade);
        world.renderShadowPass(csm.light_space_matrices[cascade]);
        rhi.endShadowPass();
    }
    
    // Main pass
    rhi.beginMainPass();
    rhi.drawSky(sky_params);
    world.render(view_proj, camera_pos);
    rhi.drawClouds(cloud_params);
    rhi.endMainPass();
}

Resource Management

File: src/engine/graphics/render_device.zig

High-level GPU resource lifetime management with pooling.

RenderDevice

Manages pools for:

  • BufferPool: Track size, usage, creation frame
  • TexturePool: Track dimensions, format, mip levels
  • ShaderCache: Track source code, backend data

Key Methods

Method Description
createBuffer(size, usage) Allocate buffer handle
destroyBuffer(handle) Mark for deferred deletion
gc() Process deferred deletions
getStats() Memory usage statistics

Texture Atlas

File: src/engine/graphics/texture_atlas.zig

Procedurally generated block texture atlas.

Constants

TILE_SIZE = 16        // Pixels per tile
TILES_PER_ROW = 16    // Atlas layout
ATLAS_SIZE = 256      // 256x256 total

Tile Indices

Tile Index Description
TILE_STONE 0 Stone texture
TILE_DIRT 1 Dirt texture
TILE_GRASS_TOP 2 Grass top (green)
TILE_GRASS_SIDE 3 Grass side (green/brown)
TILE_SAND 4 Sand texture
TILE_WATER 11 Water texture
TILE_GLOWSTONE 13 Glowstone (emissive)

Procedural Patterns

Pattern Description
noise Random brightness variation
stone Noise with crack lines
grass_side Green top 4px, dirt below
wood_side Vertical grain lines
wood_top Concentric rings
leaves Noise with gap holes
cobble Cell-based stone

BlockTiles Structure

pub const BlockTiles = struct {
    top: u8,     // +Y face tile
    bottom: u8,  // -Y face tile
    side: u8,    // X/Z faces tile
};

Rendering Pipeline Flow

┌─────────────────────────────────────────────────────────────────┐
│                         Game Loop                                │
├─────────────────────────────────────────────────────────────────┤
│  1. camera.update(input, dt)                                     │
│  2. world.update()                                               │
│  3. rhi.beginFrame()                                             │
│  4. render_graph.execute(rhi, world, camera, ...)               │
│     ├─ Shadow Pass 0: CSM compute → beginShadowPass → render    │
│     ├─ Shadow Pass 1: CSM compute → beginShadowPass → render    │
│     ├─ Shadow Pass 2: CSM compute → beginShadowPass → render    │
│     ├─ beginMainPass() (clears color/depth)                     │
│     ├─ Sky Pass: drawSky(params)                                 │
│     ├─ Main Pass: world.render(view_proj, cam_pos)              │
│     └─ Clouds Pass: drawClouds(params)                           │
│  5. ui_system.render()                                           │
│  6. rhi.endMainPass()                                            │
│  7. rhi.endFrame() → submit → present                            │
└─────────────────────────────────────────────────────────────────┘

See Also


Source: src/engine/graphics/ | Last updated: January 2026

Clone this wiki locally