Start of terrain sculpting implementation

This commit is contained in:
2026-06-27 03:18:11 +03:00
parent e047f7bea1
commit 2c095de9f2
+100 -23
View File
@@ -1217,30 +1217,107 @@ JPH::EActivation::DontActivate)`.
Definition of done: ✅ rigid bodies collide flush with visible terrain; debug
draw off by default with toggle; removing and re-adding terrain is leak-free.
**Terrain cleanup on entity/component removal** (post-M2 fix):
`TerrainSystem::update()` tracks whether any matching terrain entity exists.
If `m_active` but no entity carries `TerrainComponent`, `deactivate()` is
called. Without this, deleting the entity or removing the component leaves
terrain and colliders orphaned.
### Milestone 3 — Serialization + heightmap editing + splat painting
- Scene serialization for `TerrainComponent` (save/load JSON round-trip).
**Terrain cleanup on entity/component removal** (added post-M2):
`TerrainSystem::update()` now tracks whether any matching terrain entity exists.
If `m_active` is true but the query returns no entity (because the terrain
entity was deleted or its TerrainComponent was removed), `deactivate()` is
called automatically. Without this, removing the component or deleting the
entity would leave the terrain and colliders orphaned in the scene.
- Binary heightmap file save/load alongside scene JSON.
- Brush tools (raise/lower/smooth/flatten) with curve-based brush profile.
- Splat paint brush (select layer, set opacity, paint blend values via
`TerrainLayerBlendMap`).
- Sparse 256x256 fixup chunk cache and file I/O (lazy creation, sentinel-based
override semantics).
- Mark affected pages dirty and rebuild them via CustomTerrainDefiner
re-sampling.
- Heightmap editor UI (brush radius, strength, type selector).
- `AuxMap` infrastructure (create, load, save, edit with brushes).
- Fixup chunk cleanup (clear all, delete individual chunks by world position).
**Scene serialization**:
- `SceneSerializer::serializeEntity()` / `deserializeEntity()` support for
`TerrainComponent` (save/load JSON round-trip with all parameters, layers,
road config, aux maps).
- Binary heightmap file save/load alongside scene JSON
(`heightmaps/<terrainId>/`).
Definition of done: user can sculpt the terrain in the editor; save scene,
reload, terrain restored with edited heightmap and layer paint; visual and
collision update after sculpting.
**Heightmap data manager** (`HeightmapData` class inside `TerrainSystem`):
- Loads/stores the `terrainSize × terrainSize` float array from/to binary
files.
- Provides `getHeightAt(worldX, worldZ)` combining base heightmap + fixup
chunks with bilinear sampling.
- `setHeightAt(worldX, worldZ, value)` writes to base heightmap or a fixup
chunk (permanent base edit vs road compliance fixup).
- `CustomTerrainDefiner` calls `HeightmapData::getHeightAt()` instead of
procedural — falls back to procedural if no file loaded yet.
**Fixup chunk cache and I/O**:
- Sparse 256×256 fixup chunks, lazy-created, sentinel-based override.
- `loadFixupChunk()` / `saveFixupChunk()` / `clearAllFixups()`.
- "Clear all fixups" button; individual chunk delete by world-position
right-click.
**3D world point selection and sculpting UX**:
The TerrainEditor panel gains a **Sculpting** section below the terrain
properties, grouping all brush controls together:
```
┌─ Sculpting ─────────────────────────────────────┐
│ [✓] Sculpt Mode │
│ Tool: [ Raise ▾ ] Radius: [====] 5.0 │
│ Strength: [====] 0.5 Curve: [====] │
│ Layer: [ Layer 1 ▾ ] (splat paint only) │
└──────────────────────────────────────────────────┘
```
**Sculpt Mode checkbox**: When checked, left-click on the terrain applies the
selected tool. When unchecked, clicks behave normally (entity selection,
camera). ESC also exits sculpt mode.
**Tool selector**: Combo box — Raise, Lower, Smooth, Flatten, Splat Paint.
Switching the tool immediately changes behavior; no separate "activate" step.
**Painting**: In sculpt mode, holding left mouse on the terrain continuously
applies the current tool at the brush position (determined by raycast against
terrain via `TerrainSystem::raycastTerrain()`). Releasing the mouse stops
painting. The brush follows the cursor — drag to paint a stroke. A
translucent circle decal on the terrain surface shows brush position and
radius.
**Camera interaction while sculpting**:
- Right mouse always controls camera (orbit/pan), even in sculpt mode.
- Middle mouse or Ctrl+Left also moves camera in sculpt mode, so the user
can reposition without toggling the mode off.
**Brush tools**:
- **Raise**: adds height (strength × radius curve) at brush center.
- **Lower**: subtracts height.
- **Smooth**: averages heights within brush radius.
- **Flatten**: pulls heights toward the height under brush center (plateau).
- **Splat Paint**: paints selected layer's blend weight via
`TerrainLayerBlendMap::setBlendValue()` + `dirtyRect()` + `update()`.
Layer selector appears when this tool is active.
**Brush application and dirty page marking**:
- During a stroke, `HeightmapData::setHeightAt()` is called for each affected
sample within the brush radius, weighted by the radius curve.
- At mouse release (end of stroke), determine which terrain pages overlap the
modified area and mark them dirty.
- `CustomTerrainDefiner` re-samples `HeightmapData::getHeightAtWorld()` on the
next `define()` call for dirty pages.
- If a modified page already has a physics collider, queue its removal and
recreation with updated heights.
**Heightmap file I/O and AuxMap controls**:
- "Save Heightmap" / "Load Heightmap" buttons in the TerrainEditor panel.
- AuxMap management: create, rename, delete, select active map for editing.
AuxMap editing uses the same brush tools but writes to the selected aux map
instead of the base heightmap.
- "Clear All Fixups" button — deletes all fixup chunks and marks affected
pages dirty for rebuild.
**Camera pivot above terrain** (on-demand, not automatic):
- "Snap Camera Above Terrain" button or hotkey in TerrainEditor.
- Raycast downward from camera at current XZ, get terrain height, place camera
at `(cam.x, terrainHeight + 5.0, cam.z)`.
- Only on user request — never auto-corrects.
**Definition of done**: user can sculpt terrain with visual brush feedback;
save scene, reload, terrain restored with edited heightmap and layer paint;
visual and collision update after sculpting; camera can be snapped above
terrain on demand.
### Milestone 4 — Procedural roads
- Node/edge editing UI (add, remove, split, join, select, move).
@@ -1249,8 +1326,8 @@ collision update after sculpting.
`Procedural::TriangleBuffer`.
- End cap generation for endpoints.
- Seam suppression via vertex shifting.
- LOD + visibility distance per road mesh segment.
- Road physics colliders (JPH::MeshShape per segment).
- LOD + visibility distance per road mesh.
- Road physics colliders (JPH::MeshShape per road mesh).
- "Comply terrain to roads" writing fixup chunks with smooth falloff.
Definition of done: user can draw a road network; road geometry appears with