// STAGE 3: HEIGHTFIELD MESH → ATLAS SPLAT
TERRAIN SPLAT LAB
The generated world is baked once per seed into four RGBA fields (height, splat, normal, flow), then rendered on a subdivided heightfield mesh. The vertex shader samples height before rasterization; the fragment shader uses splat weights as the blend mask between atlas tiles. Grass is the residual baseline; water, sand, forest, and high-rock are the splat channels, while the flow field also carries riverbanks, road shoulders, bridge decks, fords, and settlement structure. A final detail pass derives canopy clumps, scree, and roof marks from those same fields without adding another source texture.
PIPELINE
- 01
createTerrainWorld(seed)seeds channels, road hierarchy, explicit bridge/ford crossings, road shoulders, riverbanks, settlements, and sea level. - 02
generateTerrainFieldTextures()samples the world on a 320² grid covering 3600 world units, packs into fourRGBA8arrays. - 03
Vertex shader maps mesh vertex → world XY → field UV and displaces the grid from the baked height field. Fragment shader uses the same fields for stochastic atlas-tile blends and baked-normal lighting.
- 04
Channel views overlay raw splat / height / normal / relief / detail / flow back over the composite to verify the GPU is reading the right field.
STAGE 3 HANDOFF
Height, splat, normal, and flow fields drive a WebGL heightfield preview with a generated game-material atlas.
createTerrainRuntime() exposes world-coordinate height, material, movement, placement, chunk-key, and region-bake queries.
Seed and region screenshot cycles prove the GPU uploads distinct fields. Runtime assertions cover all seeds and regions.
Next work should consume this API in a player/camera scene with chunks, props, collision, and movement scale.