Summary
A terrain hole carves cleanly at LOD0 but its rim can drift by up to one cell at coarser LOD levels, opening a thin gap around the void that appears only at distance (when a coarse LOD swaps in) and vanishes up close. This is visible when a building is dropped into a footprint-sized hole: a ring gap shows around the building at distance.
Root cause
In crates/mogen-dsl/src/lower/terrain/emit.rs (build_chunk_lod_mesh), a cell is dropped from the surface only when its centre lands inside the hole footprint (hole_at(ccx, ccz)). At LOD level the sampling stride is 1 << level, so the cell centre tested is the centre of the coarse cell. Unless a wall happens to land on a grid line that is a multiple of the coarsest stride 2^(lod_levels-1), the drop boundary quantizes differently at each LOD and the rim edge shifts by up to a fine cell. The rim walls (append_wall) follow that same quantized boundary, so the gap is real geometry, not just shading.
The same applies to cap="floor" cells (append_floor) — the sealed floor extent also shifts per LOD.
Current workaround (example level)
examples/procgen/building_in_terrain.mog sidesteps this by sizing the patch so each building wall lands on a grid line that is a multiple of 4 (the coarsest stride for lod_levels=3). Verified: 0 surface triangles intrude into the footprint and rim vertices land on the walls to <=1mm at all three LODs. But this requires the author to hand-compute patch size against wall positions and pick cell counts divisible by 2^(lod_levels-1) — fragile and not possible when the footprint isn't author-controlled.
Proposed fix
Make the hole boundary LOD-invariant in the generator so any terrain + hole is gap-free regardless of patch size or hole placement. Options:
- Snap the drop test to the coarsest grid. Decide cell membership on the coarsest stride (
2^(lod_levels-1)) for all LODs, so every level drops the same set of fine cells. The hole is then identical across LODs by construction (it grows to the coarse-grid envelope of the footprint).
- Carve at LOD0 and reuse that boundary. Compute the dropped-cell set once at stride 1, then for coarser LODs drop any coarse cell whose fine footprint overlaps a dropped fine cell (or is fully inside). Keeps the hole as tight as possible while staying consistent.
- Rim-wall skirt. Extend the existing cross-LOD skirt approach to the hole rim so any per-LOD drift is hidden by a downward skirt on the rim walls, the same way chunk edges are handled.
Option 1 is simplest and matches the existing "centre test" model; option 2 keeps holes tightest. Either removes the need for the example's manual alignment trick.
Acceptance
- A
terrain with a hole and lod_levels > 1, at an arbitrary patch size, shows no rim drift between LODs (rim vertices coincide within tolerance at every level; 0 surface triangles inside the footprint at every level).
- Add a regression test asserting the dropped-cell boundary is identical (or skirted) across LODs for a non-aligned hole.
- Once landed,
examples/procgen/building_in_terrain.mog can drop its multiple-of-4 sizing constraint and use a natural patch size.
Summary
A
terrainholecarves cleanly at LOD0 but its rim can drift by up to one cell at coarser LOD levels, opening a thin gap around the void that appears only at distance (when a coarse LOD swaps in) and vanishes up close. This is visible when a building is dropped into a footprint-sized hole: a ring gap shows around the building at distance.Root cause
In
crates/mogen-dsl/src/lower/terrain/emit.rs(build_chunk_lod_mesh), a cell is dropped from the surface only when its centre lands inside the hole footprint (hole_at(ccx, ccz)). At LODlevelthe sampling stride is1 << level, so the cell centre tested is the centre of the coarse cell. Unless a wall happens to land on a grid line that is a multiple of the coarsest stride2^(lod_levels-1), the drop boundary quantizes differently at each LOD and the rim edge shifts by up to a fine cell. The rim walls (append_wall) follow that same quantized boundary, so the gap is real geometry, not just shading.The same applies to
cap="floor"cells (append_floor) — the sealed floor extent also shifts per LOD.Current workaround (example level)
examples/procgen/building_in_terrain.mogsidesteps this by sizing the patch so each building wall lands on a grid line that is a multiple of 4 (the coarsest stride forlod_levels=3). Verified: 0 surface triangles intrude into the footprint and rim vertices land on the walls to <=1mm at all three LODs. But this requires the author to hand-compute patch size against wall positions and pick cell counts divisible by2^(lod_levels-1)— fragile and not possible when the footprint isn't author-controlled.Proposed fix
Make the hole boundary LOD-invariant in the generator so any
terrain+holeis gap-free regardless of patch size or hole placement. Options:2^(lod_levels-1)) for all LODs, so every level drops the same set of fine cells. The hole is then identical across LODs by construction (it grows to the coarse-grid envelope of the footprint).Option 1 is simplest and matches the existing "centre test" model; option 2 keeps holes tightest. Either removes the need for the example's manual alignment trick.
Acceptance
terrainwith aholeandlod_levels > 1, at an arbitrary patch size, shows no rim drift between LODs (rim vertices coincide within tolerance at every level; 0 surface triangles inside the footprint at every level).examples/procgen/building_in_terrain.mogcan drop its multiple-of-4 sizing constraint and use a natural patch size.