-
Notifications
You must be signed in to change notification settings - Fork 0
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.
File: src/engine/graphics/rhi.zig
The RHI provides an abstract graphics API that backends implement. This decouples game logic from Vulkan specifics.
BufferHandle = u32 // GPU buffers (vertex, index, uniform)
ShaderHandle = u32 // Shader pipelines
TextureHandle = u32 // Texturespub 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)
};| 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()
|
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
| 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 |
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
| UBO | Contents |
|---|---|
GlobalUniforms |
view_proj, camera, lighting, fog, clouds |
ShadowUniforms |
CSM matrices, cascade splits |
ModelUniforms |
Push constant: model matrix, mask radius |
File: src/engine/graphics/camera.zig
First-person camera with mouse look and WASD movement.
| 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 |
| 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 |
To prevent precision issues at large coordinates:
- Camera stays at origin
- World translates relative to camera
- Chunks use
chunk_pos - camera_posfor rendering
File: src/engine/graphics/csm.zig
Multi-cascade shadow mapping for high-quality shadows at all distances.
| 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) |
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
| Quality | Resolution |
|---|---|
| Low | 1024 |
| Medium | 2048 |
| High | 4096 |
| Ultra | 8192 |
File: src/engine/graphics/render_graph.zig
Orchestrates render pass ordering and execution.
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
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();
}File: src/engine/graphics/render_device.zig
High-level GPU resource lifetime management with pooling.
Manages pools for:
- BufferPool: Track size, usage, creation frame
- TexturePool: Track dimensions, format, mip levels
- ShaderCache: Track source code, backend data
| Method | Description |
|---|---|
createBuffer(size, usage) |
Allocate buffer handle |
destroyBuffer(handle) |
Mark for deferred deletion |
gc() |
Process deferred deletions |
getStats() |
Memory usage statistics |
File: src/engine/graphics/texture_atlas.zig
Procedurally generated block texture atlas.
TILE_SIZE = 16 // Pixels per tile
TILES_PER_ROW = 16 // Atlas layout
ATLAS_SIZE = 256 // 256x256 total| 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) |
| 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 |
pub const BlockTiles = struct {
top: u8, // +Y face tile
bottom: u8, // -Y face tile
side: u8, // X/Z faces tile
};┌─────────────────────────────────────────────────────────────────┐
│ 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 │
└─────────────────────────────────────────────────────────────────┘
- Architecture - System overview
- World System - Chunk rendering
- Block Types - Block textures
Source: src/engine/graphics/ | Last updated: January 2026