refactor(terrain): chunk-based TerrainChunkRenderer matching ACME architecture

Replace the single-giant-buffer TerrainRenderer with TerrainChunkRenderer
that groups landblocks into 16×16 chunks, each with its own VAO/VBO/EBO.
Matches ACME's ChunkMetrics/ChunkRenderData/TerrainGPUResourceManager
pattern:

- Pre-allocated max-size VBO (~3.75MB) + EBO per chunk with DynamicDraw
- Incremental glBufferSubData uploads per landblock slot (no full rebuild)
- Fixed slot layout: slot = (localX * 16 + localY), vertBase = slot * 384
- EBO contains only indices for occupied slots → tight draw calls
- One DrawElements per chunk with chunk-level AABB frustum culling
- Empty chunks auto-dispose GPU resources

Streaming-friendly: add/remove a single landblock touches only its slot
in the chunk buffer, not the entire terrain.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-13 21:50:40 +02:00
parent d35e4b6de7
commit 1b3387f991
2 changed files with 450 additions and 2 deletions

View file

@ -16,7 +16,7 @@ public sealed class GameWindow : IDisposable
private IWindow? _window;
private GL? _gl;
private IInputContext? _input;
private TerrainRenderer? _terrain;
private TerrainChunkRenderer? _terrain;
private Shader? _shader;
private CameraController? _cameraController;
private IMouse? _capturedMouse;
@ -339,7 +339,7 @@ public sealed class GameWindow : IDisposable
// Build the terrain atlas once from the Region dat.
var terrainAtlas = AcDream.App.Rendering.TerrainAtlas.Build(_gl, _dats);
_terrain = new TerrainRenderer(_gl, _shader, terrainAtlas);
_terrain = new TerrainChunkRenderer(_gl, _shader, terrainAtlas);
int centerX = (int)((centerLandblockId >> 24) & 0xFFu);
int centerY = (int)((centerLandblockId >> 16) & 0xFFu);