Files
jbashrc/claude/integration-memory/project_island_terrain_design.md
2026-09-14 14:43:00 -04:00

2.8 KiB
Raw Blame History

name, description, metadata
name description metadata
project-island-terrain-design Design decisions for the downloadable-island terrain system (replaces Unreal Landscape)
node_type type originSessionId
memory project 38ffbfc6-93fe-4670-9015-1be594a56944

Game concept: like visiting Animal Crossing islands — client downloads an island (heightfield + weightmaps) from a server and builds terrain at runtime in a packaged build. Stock Landscape is unusable (editor-only construction). Terrain is smooth sculpted hills (heightfield, NOT voxels, NOT tile-based). Islands can be large (multi-km); ~5s load budget is fine.

Decisions as of 2026-06-11:

  • Patches: 256×256 quads = 257×257 vertices, driven by a 257×257 non-mipped height texture region (possibly a sub-rect of one big island texture — left open).
  • LOD: 3 levels (interiors 256/128/64 segments), but patch edges always stay at full 257-vertex resolution — only interiors decimate. Any two neighbor LODs fit seamlessly by construction; no stitching, no neighbor bookkeeping. Transition ring fans coarse interior to full-res edge (the tricky indexing part).
  • One shared mesh: a single flat (z=0) UStaticMesh with 3 LODs, built at runtime via FMeshDescription + BuildFromMeshDescriptions(bFastBuild=true), cached lazily in a GameInstanceSubsystem. Rendered via HISM instances (one per patch); HISM auto per-instance LOD selection is safe thanks to edge-preserving LODs.
  • Displacement: material WPO samples height texture (explicit mip 0, point filter, +half-texel offset). UVs NOT stored in mesh — derived from world position minus island origin (material params). No per-instance custom data needed. Pixel shader: splat weightmaps + heightfield-derived normal map (those DO get mips; weightmaps sized 4096², not 4097, so BC compression works).
  • Collision: custom UPrimitiveComponent wrapping Chaos::FHeightField (no cook, ~ms build, built from the same uint16 samples; crib from LandscapeCollision.cpp:1049). Nobody public has done this (verified via Sourcegraph 2026-06); trimesh PMC path is scaffolding only. Heightfield wins on memory (34MB vs GBs at 4097²) and query speed.
  • Height data: uint16 grid, Landscape convention ((worldZ/scale)+32768).
  • Lumen: project doesn't use it (no RendererSettings overrides; default GI=None). Flat-proxy WPO terrain is incompatible-ish with Lumen — accepted, documented risk.
  • Heightfield texture is NOT mipmapped (LODs sample full-res at sparse points — exact vs collision; Landscape instead resamples mips + geomorphs, its choice).

Code so far: Source/Integration/TerrainPatch.h/cpp — USTRUCT FlxTerrainPatch with stubbed static MakePatch() (returns UStaticMesh*) and editor-only SavePatch() (writes uasset for debugging; game always generates dynamically).