Expand description
Reference mesh for the per-chunk triangular grid (Phase 2, CEL-62).
§Canonical vertex order
Vertices are enumerated in row-major order by (i, j) where:
i= row index (thewbaxis),0 ≤ i ≤ resj= column index (thewcaxis),0 ≤ j ≤ res − i
The linear index L for vertex at (i, j) is:
L(i, j) = i*(2*res + 3 − i)/2 + j(Equivalently: L(i, j) = i*(res+1) − i*(i−1)/2 + j.)
Row i starts at L_row(i) = i*(2*res + 3 − i)/2, with res+1−i vertices.
Special corner vertices:
L = 0→(i,j) = (0,0)→ corner A:wa=1, wb=0, wc=0L = res→(i,j) = (0,res)→ corner C:wa=0, wb=0, wc=1L = verts_per_chunk(res)−1→(i,j) = (res,0)→ corner B:wa=0, wb=1, wc=0
ChunkRealize.slang (Task 7) must enumerate local vertices in this same order
and decode L using the same formula.
§Vertex storage convention
Each vertex is stored as [wa, wb, wc] — the full barycentric triplet (wa+wb+wc=1):
wa = (res − i − j) as f32 / res as f32
wb = i as f32 / res as f32
wc = j as f32 / res as f32§Triangle winding
Triangles are output in two interleaved passes for each cell (i, j) with i+j < res:
- Upward triangle:
L(i,j),L(i,j+1),L(i+1,j)— always present. - Downward triangle (only when
i+j+1 < res):L(i+1,j),L(i,j+1),L(i+1,j+1).
Both share the same (uniform) winding, ordered so the OUTWARD surface is front
under render_mode cull_back in terrain_chunk.gdshader.
§Perimeter skirts (Phase 3 crack fix)
Adjacent chunks at different quadtree depths tessellate their shared edge at different resolutions → T-junctions where heights differ → cracks. To hide them we append a skirt: a ring of extra vertices at the same edge positions as the interior perimeter, but pushed radially inward (toward the planet centre) by a per-chunk depth, connected to the interior edge by triangles. A crack then shows skirt terrain instead of a hole.
§Skirt vertex numbering (mirrored EXACTLY in ChunkRealize.slang)
Interior verts occupy L ∈ [0, interior_verts_per_chunk(res)). Skirt verts are
appended at L = interior + s, s ∈ [0, 3*(res+1)), with
edge = s / (res+1) and t = s % (res+1) (the along-edge position 0..=res):
edge 0(A→B): interior lattice point(i,j) = (t, 0)edge 1(B→C):(i,j) = (res−t, t)edge 2(C→A):(i,j) = (0, res−t)
A skirt vert stores the SAME barycentric as its interior edge vert (so its TEX_UV samples the same atlas texel and it shades like the edge); the realize shader drops its position inward. Corners are duplicated (each of the 3 edges owns its own ring), so skirt vertices are always DISTINCT pool entries from the interior edge verts they mirror.
§Skirt triangles
For each edge and each of the res segments k (interior verts E_k, E_{k+1};
skirt verts S_k, S_{k+1}) two triangles T1 = (E_k, E_{k+1}, S_{k+1}),
T2 = (E_k, S_{k+1}, S_k). The interior triangle adjacent to every perimeter
segment traverses the boundary edge as E_{k+1} → E_k; the skirt traverses it the
opposite way (E_k → E_{k+1}), so the skirt is consistently oriented with the
interior — i.e. the same front/back class under cull_back.
Functions§
- chunk_
grid - Generate the triangular grid vertices and triangle indices for a chunk at resolution
res. - reference_
chunk_ mesh - Build a Godot
ArrayMeshreference chunk at resolutionres.