docs: water at rest across the Core/Client/Server READMEs (terrain-water task 13)
Core: BlockRegistry gains WATER, with the reason it is wire-safe (block IDs are never serialized) AND the reason it is a registry identity only rather than a voxel the terrain path writes. Corrects the now-false line "Nothing at runtime consumes the water data yet" -- it does, as of this task. ChunkData's new per-column water fields and the Constants tunables. Client: how the water sheet is built and, more importantly, WHY it is a second mesh instead of a block in the density field -- the trap here is that writing water into a Marching-Cubes field fuses it into the terrain instead of laying it on top, and that is not obvious until you have done it. Notes translucency came free from the separate material. Server: the per-column water rule, which section is the authority for what (WBID presence, WSRF level, WBTB fallback), that an unknown body leaves the column dry rather than guessing, and why depth for shading comes from blueprint heights rather than the clamped rendered geometry. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9c255a4fc6
commit
3b5bc5e5d6
3 changed files with 38 additions and 4 deletions
|
|
@ -17,6 +17,21 @@ A `MeshInstance3D` created per chunk by the server, which then calls `RenderChun
|
||||||
placed by their footprint and carry their full height internally.
|
placed by their footprint and carry their full height internally.
|
||||||
- **Backface rendering.** `CullMode` is disabled, so the world is still visible from underneath or
|
- **Backface rendering.** `CullMode` is disabled, so the world is still visible from underneath or
|
||||||
from inside terrain.
|
from inside terrain.
|
||||||
|
- **Water at rest** (task 13). `BuildWaterSurface` adds a second `MeshInstance3D` as a child, a flat
|
||||||
|
sheet at each cell's water level, from the per-column water data the server read out of the
|
||||||
|
blueprint. Skipped entirely for chunks with no water.
|
||||||
|
|
||||||
|
**Why a separate mesh rather than a water block.** The terrain is a Marching-Cubes iso-surface
|
||||||
|
over the density field. Putting water into that field would not lay a sheet on top of the seabed —
|
||||||
|
it would move the iso-surface, fusing the sea into the terrain as if it were solid ground. A
|
||||||
|
second surface is the only way water can sit at *its* level independent of the ground beneath it.
|
||||||
|
|
||||||
|
That also makes translucency nearly free: a distinct `MeshInstance3D` carries its own
|
||||||
|
`StandardMaterial3D`, so alpha is one flag and Godot sorts transparent surfaces after opaque ones
|
||||||
|
itself. Colour and alpha both ramp with depth (shallow teal and clearer → deep navy and near
|
||||||
|
opaque), so the shelved coast stays readable.
|
||||||
|
|
||||||
|
Water is **flat and static** — no waves, no displacement, no animation. Those are Phase C2+.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,11 @@ never track live game events — who is online, which chunks are loaded, what ti
|
||||||
### Voxel materials
|
### Voxel materials
|
||||||
- **`BlockData.cs`** — struct describing one block type (ID, name, IsSolid, BaseColor).
|
- **`BlockData.cs`** — struct describing one block type (ID, name, IsSolid, BaseColor).
|
||||||
- **`BlockRegistry.cs`** — the byte-ID master list (`AIR` 0, `BEDROCK`, `STONE`, `DIRT`, `SAND`, the
|
- **`BlockRegistry.cs`** — the byte-ID master list (`AIR` 0, `BEDROCK`, `STONE`, `DIRT`, `SAND`, the
|
||||||
three grasses, `SNOW`, `WASTELAND_DIRT`, `ASPHALT`) with a safe `GetBlock` lookup.
|
three grasses, `SNOW`, `WASTELAND_DIRT`, `ASPHALT`, `WATER`) with a safe `GetBlock` lookup.
|
||||||
|
**Block IDs are never serialized** — the blueprint stores heights, biome ordinals and water data,
|
||||||
|
never block IDs, and chunks are not persisted — so appending to this table is wire-safe.
|
||||||
|
`WATER` is a registry identity only: it is not written into `ChunkData.BlockIDs`, because water is
|
||||||
|
drawn as its own surface rather than as part of the terrain iso-surface (see `Client/README.md`).
|
||||||
- **`BiomePalette.cs`** — decides which material sits where, given biome, depth, and whether the
|
- **`BiomePalette.cs`** — decides which material sits where, given biome, depth, and whether the
|
||||||
column is roadbed. Two paths on purpose: an **integer** classification that decides what is stored
|
column is roadbed. Two paths on purpose: an **integer** classification that decides what is stored
|
||||||
in each voxel, and a **float-depth** version used for rendering that returns the two materials
|
in each voxel, and a **float-depth** version used for rendering that returns the two materials
|
||||||
|
|
@ -43,11 +47,17 @@ rendering.
|
||||||
flag, and the optional water-bodies data: `WaterBodyIds`, `WaterBodies` table, `WaterSurfaceQ`).
|
flag, and the optional water-bodies data: `WaterBodyIds`, `WaterBodies` table, `WaterSurfaceQ`).
|
||||||
Dispatches on the first byte: v2 tagged-section files get validation (version gate, size
|
Dispatches on the first byte: v2 tagged-section files get validation (version gate, size
|
||||||
bounds, section-length and ordinal range checks); legacy v1 files still load, intact, with a
|
bounds, section-length and ordinal range checks); legacy v1 files still load, intact, with a
|
||||||
deprecation warning. Nothing at runtime consumes the water data yet.
|
deprecation warning. **The water sections are consumed at runtime since task 13** — the server
|
||||||
|
reads them per column and the client draws the result (see `Server/README.md`).
|
||||||
- **`ChunkData.cs`** — one chunk's density and block-ID fields, `+1` padded on every axis so the
|
- **`ChunkData.cs`** — one chunk's density and block-ID fields, `+1` padded on every axis so the
|
||||||
mesher can reach into the neighbouring chunk, plus the per-column data the renderer needs.
|
mesher can reach into the neighbouring chunk, plus the per-column data the renderer needs —
|
||||||
|
including `WaterSurfaceY` (world Y of the water surface, or `Constants.NO_WATER`), `WaterDepthM`
|
||||||
|
(true depth from blueprint heights) and `HasAnyWater`.
|
||||||
- **`Constants.cs`** — chunk dimensions, `ISO_LEVEL`, `VOXEL_SCALE`, and the visual/road tunables
|
- **`Constants.cs`** — chunk dimensions, `ISO_LEVEL`, `VOXEL_SCALE`, and the visual/road tunables
|
||||||
(material blend band; per-tier road width, shoulder, grade smoothing and surface).
|
(material blend band; per-tier road width, shoulder, grade smoothing and surface), plus the
|
||||||
|
water-at-rest tunables: `HEIGHT_SCALE` (the one raw-height→metres mapping, shared by the terrain
|
||||||
|
surface and the water sheet so they cannot drift apart), `NO_WATER`, and the depth-shading
|
||||||
|
colour/alpha ramp.
|
||||||
|
|
||||||
### Maths
|
### Maths
|
||||||
- **`MarchingCubes.cs`** — density field → `ArrayMesh`, with analytical normals and deterministic
|
- **`MarchingCubes.cs`** — density field → `ArrayMesh`, with analytical normals and deterministic
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,15 @@ vector ends up parallel to the view direction, so camera roll is undefined and G
|
||||||
- **Road culling first.** Only the road segments whose bounding box reaches this chunk are kept,
|
- **Road culling first.** Only the road segments whose bounding box reaches this chunk are kept,
|
||||||
each tagged with its `RoadTier`. The padding is derived from the widest shoulder any tier has plus
|
each tagged with its `RoadTier`. The padding is derived from the widest shoulder any tier has plus
|
||||||
a margin, so widening a road cannot silently truncate it at chunk edges.
|
a margin, so widening a road cannot silently truncate it at chunk edges.
|
||||||
|
- **Water per column** (task 13) — the blueprint is the **authority** on where water is; the server
|
||||||
|
only reads it. `WBID` decides presence (it is the water stage's own classification output, the
|
||||||
|
same set the biome grid's Ocean/Lake pixels form by construction), `WSRF` gives the surface level
|
||||||
|
per pixel, and the `WBTB` body table is the fallback when a column is flagged wet but carries the
|
||||||
|
`WSRF` no-water sentinel. A body the table does not know leaves the column **dry** rather than
|
||||||
|
guessing a level. The level is scaled by the same `HEIGHT_SCALE` as the terrain, so the sheet and
|
||||||
|
the seabed cannot drift apart. Depth for shading is taken from **blueprint** heights, not rendered
|
||||||
|
geometry — the terrain render clamps its floor at `Y = 2`, which would otherwise flatten every
|
||||||
|
deep-ocean column to one value. Each run logs what it drew (`[Server] Water at rest: …`).
|
||||||
- **Surface height per column** (`GetExactSurface`) — the blueprint height scaled into the chunk's
|
- **Surface height per column** (`GetExactSurface`) — the blueprint height scaled into the chunk's
|
||||||
usable vertical band, then modified by any road carving.
|
usable vertical band, then modified by any road carving.
|
||||||
- **Density per voxel** — `(y − surfaceY)` normalised by the local slope, giving a signed distance to
|
- **Density per voxel** — `(y − surfaceY)` normalised by the local slope, giving a signed distance to
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue