Skip to content

ENG2-P8-10: Chunked heightmap terrain component #808

Description

@aram-devdocs

Parent

  • Program: ENG2 — GoudEngine v2 Rebuild (see the pinned master tracking issue)
  • Phase / Milestone: Phase 8 — Capability Gaps (eng2-p8-capabilities)
  • Batch / Group: Batch 8.3 — Big-world, Group B
  • Runbook spec: docs/src/runbook/phases/phase-8.md (committed with the roadmap)

Summary

Add a chunked heightmap terrain component: heightfield-driven mesh generation split into fixed-size chunks, so large terrains render at bounded per-chunk cost and can be culled/streamed chunk-by-chunk.

Architecture Context

Layer: Layer 4 (Engine, libs/graphics/renderer3d/ for mesh generation from heightfield data) with a Layer 3 (Services) component (ecs/components/) describing terrain placement/chunk membership.
Modules/types touched:

  • goud_engine/src/libs/graphics/renderer3d/terrain.rs (new) — heightfield-to-mesh generation (grid of vertices with height-sampled Y, per-vertex normals), chunked into fixed-size tiles.
  • goud_engine/src/ecs/components/terrain/ (new) — a TerrainChunk/Heightmap component describing chunk origin, size, and its heightfield data source.
  • goud_engine/src/ffi/renderer3d/terrain.rs (new) — FFI exports to create a heightmap terrain, query height at a world position, and manage chunk lifecycle.

Boundary constraints (only those that apply):

  • Raw GPU calls stay in libs/graphics/backend/ — chunk mesh upload goes through the existing backend buffer APIs, not a new direct wgpu:: call site.
  • FFI exports: #[no_mangle] extern "C", #[repr(C)], null checks, // SAFETY: comments.

Pattern to follow: The chunking/windowing strategy established by ENG2-P2-11 (chunked/scrollable 3D tilemap-grid primitive) — terrain chunks should reuse that primitive's chunk-loading/unloading and coordinate-to-chunk mapping approach rather than inventing a second chunking scheme for a different large-world use case.

Scope

  • Heightfield data representation: a 2D grid of height samples (from a raster image, a procedural function, or raw float array) per chunk.
  • Mesh generation: turn a chunk's heightfield into a renderable grid mesh with computed vertex normals (for correct lighting).
  • Chunk lifecycle reusing ENG2-P2-11's chunk-loading pattern: chunks load/unload based on camera/view distance, not the whole terrain resident at once.
  • FFI exports: create a heightmap terrain from a data source, query height at (x, z), configure chunk size/resolution.
  • Tests: spec test + unit tests for mesh generation correctness (vertex positions match height samples, normals are correct for a known slope fixture) and height-query accuracy (interpolated height between samples).
  • Docs/rules updates: mdBook page covering heightmap terrain authoring (data format, chunk size tuning) and extend .agents/rules/graphics-patterns.md with the terrain chunk pattern.

Acceptance Criteria

  • A generated terrain chunk's mesh vertices match the input heightfield within float tolerance, with correctly-oriented normals verified against a known-slope fixture.
  • Height-at-world-position queries return correctly bilinearly-interpolated values between sample points.
  • Chunk load/unload follows the ENG2-P2-11 windowing pattern (no full-terrain-resident assumption) verified on a multi-chunk fixture scene.
  • FFI terrain exports have wrappers in all 10 SDKs and pass python codegen/validate_coverage.py.
  • cargo check && cargo fmt --all -- --check && cargo clippy -- -D warnings clean; cargo test green; ./codegen.sh && git diff --exit-code (drift gate)

Breaking Change & Throne Follow-up

None — additive/internal (new component, new FFI surface).

Blocked By

ENG2-P2-11 (chunked/scrollable 3D tilemap-grid primitive, windowless terrain — this issue's chunk loading/unloading and coordinate-to-chunk mapping must reuse that primitive's windowing strategy rather than building a second, inconsistent chunking scheme).

Files Likely Touched

  • New: goud_engine/src/libs/graphics/renderer3d/terrain.rs, goud_engine/src/ecs/components/terrain/mod.rs, goud_engine/src/ffi/renderer3d/terrain.rs
  • Generated: SDK bindings under sdks/*/ for the new terrain FFI exports
  • Modified: codegen/goud_sdk.schema.json

Agent Notes

  • No terrain or heightmap functionality exists in any form today: grep for heightfield, height_map, and height_data (case-insensitive) across goud_engine/src returns zero matches. The only pre-existing "terrain" hits are incidental: a comment in ecs/components/rigidbody/body_type.rs:46 listing "walls, floors, terrain, static obstacles" as example use cases for a rigidbody type, and a "terrain" string used purely as an example category label in rendering/texture_atlas/atlas.rs:64's doc comment — neither is a real terrain system.
  • This is explicitly the big-world capability that depends on ENG2-P2-11's chunking work landing first: ENG2-P2-11 is described in the roadmap as solving the "windowless terrain" chunking problem generically (the "scrollable 3D tilemap-grid primitive"), and this issue is one concrete consumer of that primitive rather than a second implementation of chunk windowing.
  • Watch for confusion with the codebase's existing "LOD" terminology: every current LOD hit in the tree (libs/graphics/renderer3d/config.rs:80,195,199, core_model_animation/mod.rs:134,195) refers exclusively to animation update-rate LOD (skipping or half-rating skeletal animation evaluation at distance), not geometric mesh LOD or texture LOD. This issue's chunking is a prerequisite for ENG2-P8-11's terrain-specific mesh/texture LOD, which is a distinct, new concept in this codebase.

Verification

cargo check && cargo fmt --all -- --check && cargo clippy -- -D warnings
cargo test
./codegen.sh && git diff --exit-code

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions