6.6 KiB
Hex terrain capability audit
Result
EVEngine can generate and render a medium-size Civilization-style hex terrain
prototype today. The procgen registry, deterministic parameters, CPU mesh upload,
custom Mesh3D shaders, camera, lighting and shadow systems are sufficient for the
included examples/hex-terrain proof. mesh.hexterrain adds the missing world
generator and produces ocean, deep ocean, rivers, grassland, mountains, hills,
coast, cliffs, forest, swamp, rainforest and ice without source art.
It is not yet a production-scale terrain renderer. The proof deliberately uses a documented UV packing bridge because the current graphics API has no terrain material-layer abstraction.
Requirement audit
- Basic Civilization-style hex terrain: implemented and rendered by the
mesh.hexterrainrecipe andexamples/hex-terrain. - Required terrain classes: deep ocean, ocean, coast, grassland, hills, mountains, forest, swamp, rainforest, ice, cliffs and rivers are all present in the acceptance seed and checked through generated metadata.
- No supplied art: satisfied; geometry, vegetation, albedo, normals, roughness, metallic response, AO-like detail, snow, foam, caustics and weather motion are generated by C++ or GLSL.
- Material transitions: implemented as world-space noisy two-biome blending, slope-aware cliff selection, dedicated shore bands and connected river edge geometry.
- Engine API review and completion: this proof added boolean procgen parameters, a script-safe two-stage Mesh3D shader constructor, the missing cloud-shadow script binding, recipe schema/metadata and repeatable visual capture tooling.
- Reference-based evaluation: three downloaded Civilization V screenshots and
their source pages are stored under
docs/dev/reference/civ5-terrainand are compared against the current acceptance frame below.
Rendered acceptance frame
examples/hex-terrain/hex-terrain-vulkan-latest.png is captured from the current
binary on Mesa Lavapipe through an isolated 800x600 Xvfb display. Unlike earlier
desktop screenshots, it is reproducible and corresponds to the checked source.
The acceptance seed contains all requested terrain classes; exact per-class
counts are exposed in mesh metadata and asserted by the procgen test.
Compared with the downloaded Civilization V references, the proof now matches the broad readability targets: layered deep/shallow sea, a coast ring, connected rivers, forest density changes, independent snow mountains, biome color zones, cliffs, atmospheric falloff and directional lighting. Remaining visual gaps are the still-visible (but material-smoothed) hex elevation steps, angular river centerlines, simplified peak silhouettes, lack of transparent/refraction water and the absence of production props such as resources, roads, farms and settlements.
Existing API coverage
TerrainSampler/Heightmap: continuous deterministic elevation and editable scalar fields.Grid2D, semantic generation and hex tile systems: gameplay topology, pathfinding, FOV and cell costs.MeshBuildandgenerateMesh: CPU procedural geometry and Vulkan upload. Squirrel callers consume the canonical Result projection (okthenvalue).- PBR recipes: aligned albedo, normal, roughness, metallic, height and AO image generation from a shared displacement field.
- Mesh3D custom shaders: world position, normal, UV, camera and frame lighting.
- Tree, bush and rock mesh recipes, plus the proof's deterministic broadleaf, conifer and peak geometry: enough to validate biome decoration and wind sway.
- Per-frame cloud-shadow controls and two-stage custom Mesh3D shaders: enough for animated water normals, shoreline foam, vegetation wind and moving cloud shade.
Gaps exposed by the proof
MeshBuildcarries only position, normal and one UV channel. Terrain needs an integer cell/biome id and typically four to eight normalized layer weights.Materialbinds albedo, normal and height, but generated roughness, metallic and AO maps cannot be attached independently. Its scalar roughness/metallic values apply to the whole draw.- Custom Mesh3D shaders inherit a fixed descriptor layout. There is no public texture-array or arbitrary named texture binding API, so a shader cannot sample a biome PBR array plus a cell-data texture.
PbrTextureSetis CPU-only. There is no one-call upload/ownership object that converts the six generated images into a renderable material.- There is no chunked terrain resource, dirty-region mesh update, terrain LOD, seam stitching, asynchronous generation or cell-to-world picking API tied to 3D hex geometry.
- Rivers are generated as drainage paths, but production hydrology still needs basin filling, flow accumulation, confluences, lake outlets and navigable river graph queries.
- Forest, rainforest and swamp decorations are currently baked into one mesh. Production terrain needs instance buffers, chunk culling, indirect drawing and independent vegetation regeneration instead of rebuilding the terrain mesh.
Recommended engine API completion
Introduce TerrainLayerSet (texture arrays for albedo/normal/ORM/height),
TerrainCellBuffer (biome ids, weights, elevation, moisture, temperature and
river edges), and HexTerrain (chunk generation, picking, neighbour/edge queries,
LOD and dirty updates). Extend MeshBuild with optional typed custom streams and
extend custom materials with reflected texture/buffer bindings. Preserve the
existing compact vertex path for ordinary meshes.
The recommended shader path samples triplanar texture arrays, blends height-aware weights, normalizes reoriented normals, packs AO/roughness/metallic as ORM and uses the existing GGX lighting. Coast foam and river wetness should be edge masks in cell data rather than separate meshes; cliffs should select a world-space triplanar rock layer based on slope.
The proof now implements the visual approximation entirely from shader math: height-aware noisy biome blending, procedural normals, GGX lighting, animated water, coast foam, snow-line breakup, distance fog, moving cloud shade and vertex wind. It validates shader programmability, but is not a replacement for bindable PBR texture arrays or terrain data buffers.
Current proof encoding
UV.x = primaryBiome + transitionWeight and
UV.y = secondaryBiome + riverCoverage. The fragment shader reconstructs two
procedural PBR surfaces, perturbs the boundary with world-space FBM and performs a
GGX metallic-roughness lighting evaluation. This gives stable, asset-free
transitions and validates the end-to-end path, but it supports only two layers per
vertex and should not become the permanent terrain data format.