Strata gain a dip, a slow seeded warp that bends and notches the beds, and a per-bed thickness and hardness jitter with ordered boundaries, so walls never invert. BoulderField gains an angularity parameter: elongated super-ellipse slabs with flat tops, sharp shoulders, random heading and tilt, footprint area preserved. Both sites are re-baked with the new settings; the coral heads stay rounded. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
205 lines
12 KiB
Markdown
205 lines
12 KiB
Markdown
# Proposition — formes de relief variées pour les sites de plongée
|
||
|
||
**Statut : exécuté en autonomie le 2026-10-06** sur demande d'Olivier
|
||
(« implémente ce genre de terrains variés, terrain statique, ne te concentre que
|
||
sur le terrain, pas les effets de rendu ou la végétation »). Les décisions
|
||
ouvertes sont listées en §8.
|
||
|
||
Rédigée à partir de cinq photos de référence fournies par Olivier, de l'ADR
|
||
0012, de `tools/site_terrain_baker.gd` et du brief
|
||
`docs/briefs/terrain-site-zone1-gameplay.md`.
|
||
|
||
---
|
||
|
||
## 1. Objectif
|
||
|
||
Étendre le vocabulaire de formes du script de cuisson pour que les sites
|
||
suivants (U-Boot « sous falaise », navire océanographique « dans un canyon »,
|
||
GDP §15) puissent être authorés avec le même pipeline que le Banc du Vigilant :
|
||
canyons à parois raides et strates, crevasses étroites, éperons et chaos de
|
||
blocs, buttes rocheuses, falaises sinueuses. Terrain statique, surface unique
|
||
(ADR 0010), aucun changement de rendu ni de végétation.
|
||
|
||
Terminé quand :
|
||
|
||
- chaque forme des cinq références a une primitive nommée, testée unitairement,
|
||
dans `tools/site_terrain_baker.gd` ;
|
||
- un site de démonstration cuit (`content/sites/terrain_showcase.tres`) montre
|
||
les cinq formes côte à côte, se charge en moins de 3 s et passe des tests de
|
||
contrat géométriques (profondeur, pente, largeur, matériau) ;
|
||
- le Banc du Vigilant est cuit à l'identique (aucun octet de
|
||
`zone1_vigilant_terrain.res` ne change) ;
|
||
- `bash scripts/quality_gate.sh` passe.
|
||
|
||
## 2. Lecture des références
|
||
|
||
| Photo | Ce qu'on voit | Forme de relief | Ce qu'un champ de hauteur peut en garder |
|
||
|---|---|---|---|
|
||
| 1 | Deux masses rocheuses alvéolées encadrant un chenal de sable grossier | éperons rocheux + chenal | deux buttes aux bords irréguliers, chenal plat entre elles, rugosité forte sur la roche |
|
||
| 2 | Fente très étroite et profonde entre deux parois quasi verticales | crevasse | sillon de 5–6 m de large, 20 m de profondeur, parois à 80°+ ; pas de surplomb |
|
||
| 3 | Pente de mamelons rocheux arrondis | mamelons | buttes à flancs doux sur une pente, rugosité moyenne |
|
||
| 4 | Canyon aux parois verticales **stratifiées**, fond de sable plat **ridé**, mesas en haut | canyon à strates | tranchée à fond plat, parois raides quantifiées en gradins horizontaux, rides sur le fond, plateaux sommitaux |
|
||
| 5 | Platier : têtes de corail et blocs épars sur sable ridé | chaos de blocs | champ de demi-ellipsoïdes de 2–6 m de rayon, matériau roche, sable ridé entre |
|
||
|
||
Hors périmètre, volontairement : lumière, caustiques, couleur de l'eau,
|
||
herbier, corail (rendu et végétation).
|
||
|
||
## 3. Ce qui existe et ce qui manque
|
||
|
||
Le cuiseur additionne des primitives `elevation_delta(x, z)` puis déduit le
|
||
matériau de la pente (roche au-dessus de 20°) et applique des `MaterialPatch`
|
||
circulaires. Les primitives actuelles (`SlopedPlane`, `Blob`, `Ridge`,
|
||
`Groove`, `Step`, `Ripples`, `Roughness`) sont toutes **lisses** (gaussiennes
|
||
ou `smoothstep`) et **mono-segment**. Il manque :
|
||
|
||
1. des **tracés en polyligne** (canyon, crevasse, falaise sinueuse) ;
|
||
2. des **bords irréguliers** (bruit de contour) pour casser l'aspect « gaussien » ;
|
||
3. des **formes à sommet plat et flancs raides** (butte, mesa) ;
|
||
4. des **champs d'objets discrets** combinés par maximum, pas par somme
|
||
(blocs qui ne fusionnent pas en bosse) ;
|
||
5. une phase de **modification** après la somme, qui connaît la pente locale,
|
||
pour quantifier les parois en **strates** ;
|
||
6. un **matériau imposé par une primitive** (un bloc est roche même sur son
|
||
sommet plat).
|
||
|
||
## 4. Décision : extension du cuiseur
|
||
|
||
### 4.1 Contrat
|
||
|
||
- `Primitive.elevation_delta(x_m, z_m) -> float` : inchangé, additif.
|
||
- `Primitive.material_at(x_m, z_m) -> int` : nouveau, renvoie
|
||
`NO_MATERIAL` (-1) par défaut ; une valeur `SonarMaterial.Value` l'emporte sur
|
||
la règle de pente, dans l'ordre des primitives, avant les `MaterialPatch`.
|
||
- `Modifier.modify(x_m, z_m, elevation_m, gradient) -> float` : nouvelle phase.
|
||
`gradient` est la pente locale `Vector2(dE/dx, dE/dz)` calculée par
|
||
différences centrées sur le champ courant ; les modificateurs s'enchaînent
|
||
dans l'ordre de `Recipe.modifiers`, après la somme et avant le plancher.
|
||
- Ordre de cuisson : somme des primitives → modificateurs → plancher
|
||
`floor_elevation_m` → matériau par pente → matériau par primitive →
|
||
`MaterialPatch`.
|
||
|
||
### 4.2 Nouvelles primitives
|
||
|
||
| Primitive | Paramètres | Forme |
|
||
|---|---|---|
|
||
| `Canyon` | `path: PackedVector2Array`, `half_width_m`, `depth_m`, `wall_softness_m`, `edge_seed`, `edge_amplitude_m`, `floor_material` | tranchée à fond plat le long d'une polyligne ; parois `smoothstep` sur `wall_softness_m` ; distance au tracé perturbée par un bruit de contour ; se referme sur une demi-largeur à chaque bout ; impose `floor_material` (sable en général) sur le fond plat, même à travers une butte rocheuse |
|
||
| `Outcrop` | `centre`, `radius_x_m`, `radius_z_m`, `height_m`, `wall_width_m`, `edge_seed`, `edge_amplitude_m`, `rock_top` | butte elliptique à sommet plat, flanc de largeur `wall_width_m`, contour perturbé ; matériau roche partout où elle dépasse 30 % de sa hauteur si `rock_top` |
|
||
| `BoulderField` | `centre`, `radius_m`, `seed`, `count`, `boulder_radius_min_m`, `boulder_radius_max_m`, `height_ratio`, `angularity` (0–1) | `count` blocs tirés par `RandomNumberGenerator` seedé dans le disque, combinés par **maximum** ; roche sur toute leur emprise ; `angularity` 0 = demi-ellipsoïdes, 1 = dalles en super-ellipse allongées, orientées et basculées au hasard, sommet plat et épaules vives |
|
||
| `Escarpment` | `path: PackedVector2Array`, `drop_m`, `softness_m`, `slope_beyond`, `edge_seed`, `edge_amplitude_m` | `Step` le long d'une polyligne : le terrain descend à **droite** du sens de parcours ; ligne de crête perturbée par un bruit de contour |
|
||
|
||
### 4.3 Nouveau modificateur
|
||
|
||
| Modificateur | Paramètres | Effet |
|
||
|---|---|---|
|
||
| `Strata` | `layer_height_m`, `sharpness` (0–1), `minimum_slope_degrees`, `full_slope_degrees`, `region_m: Rect2` (vide = partout), `dip`, `warp_seed`, `warp_amplitude_m`, `thickness_variation` | quantifie l'élévation en gradins d'environ `layer_height_m` là où la pente dépasse `minimum_slope_degrees` (plein effet à `full_slope_degrees`) ; `sharpness` 0 = aucun effet, 1 = marches franches ; le fond plat et le plateau ne bougent pas ; `dip` incline la pile, le warp courbe et encoche les bancs, chaque banc a son épaisseur et sa dureté, les bornes restent ordonnées (pas d'inversion) |
|
||
|
||
Formule : `f = frac(e / h)`, `f' = clamp((f - 0.5) / (1 - s) + 0.5, 0, 1)`,
|
||
`e' = lerp(e, floor(e / h) * h + h * f', w)` avec
|
||
`w = smoothstep(tan(min), tan(full), |gradient|) * masque`.
|
||
|
||
### 4.3 bis Relief de fond (ajout du 2026-10-06, demande d'Olivier)
|
||
|
||
Les plateaux cuits avec la seule `Roughness` à 50 m (± 0,6 m) restaient
|
||
plats. `Roughness` prend maintenant un nombre d'octaves et un type fractal
|
||
(`FRACTAL_FBM` roulant, `FRACTAL_RIDGED` à crêtes) : une fréquence de 0,004
|
||
sur cinq octaves donne des mamelons et des cuvettes de 250 m à 15 m en une
|
||
primitive. Le modificateur `SlopeRoughness` (`seed`, `frequency`,
|
||
`amplitude_m`, `minimum_slope_degrees`, `full_slope_degrees`) ajoute un bruit
|
||
à crêtes pondéré par la pente : la roche s'éraille, le sable reste lisse. Les
|
||
deux sites l'utilisent (ondulation ± 2,2 m, roche ± 0,7 m).
|
||
|
||
### 4.4 Ce qui ne change pas
|
||
|
||
Le contrat de données (`SiteTerrainData`, ADR 0012 §2), l'acteur de monde, la
|
||
collision, le sonar, le shader. Les `.res` restent les artefacts dérivés ; la
|
||
recette reste le document d'auteur. Le bruit de contour est un
|
||
`FastNoiseLite` seedé, donc déterministe.
|
||
|
||
## 5. Site de démonstration : `terrain_showcase`
|
||
|
||
But : prouver chaque forme en jeu et au sonar, servir de catalogue pour
|
||
l'auteur des sites suivants. Pas un site de mission : un seul placement
|
||
(balise de mouillage), aucune épave, aucune route.
|
||
|
||
| Donnée | Valeur |
|
||
|---|---|
|
||
| Champ | 513 × 513 cellules, 1,0 m, origine (-256, -256) |
|
||
| Zone jouable | 440 × 440 m centrée |
|
||
| Plateau de base | 30 m, incliné de 4 m vers le sud |
|
||
| Profondeur min / max | 18 m / 80 m |
|
||
| Départ | (0, -12, 0), cap nord |
|
||
|
||
Plan de masse (nord en haut) :
|
||
|
||
```text
|
||
+---------------------------------------------+
|
||
| NW : canyon à strates NE : crevasse |
|
||
| mesa à -24 m, tranchée fente 6 m de |
|
||
| 28 m de large au sommet, large, 20 m |
|
||
| 20 m de profond, parois à de profond, |
|
||
| 55°, gradins 4 m, fond ridé entre buttes |
|
||
| [départ] |
|
||
| SW : chaos de blocs SE : éperons |
|
||
| 90 blocs r 2–6 m sur deux buttes |
|
||
| sable ridé alvéolées, |
|
||
| chenal 20 m |
|
||
| ====== falaise sinueuse (Escarpment) ===== |
|
||
| tombant vers -80 m, mamelons sur la pente |
|
||
+---------------------------------------------+
|
||
```
|
||
|
||
## 6. Tests
|
||
|
||
- **Unitaires (`run_site_baker_tests.gd`)** : `Canyon` (fond plat à la
|
||
profondeur demandée, nul hors tracé, suit le coude d'une polyligne,
|
||
fermeture aux bouts) ; `Outcrop` (sommet à `height_m`, roche sur le sommet
|
||
si `rock_top`, nul à deux rayons) ; `BoulderField` (déterministe, nul hors
|
||
disque, roche sur un bloc, maximum et non somme) ; `Escarpment` (côté droit
|
||
plus bas, drop égal à `drop_m`) ; `Strata` (une pente raide devient des
|
||
gradins : au moins deux niveaux plats ; un fond plat ne bouge pas) ;
|
||
cuisson du Banc du Vigilant identique à l'artefact versionné.
|
||
- **Contrat (`run_site_content_tests.gd`, section showcase)** : canyon
|
||
(profondeur ≥ 18 m sous le sommet bruité de la mesa, fond de sable plat à
|
||
± 1 m sur 10 m, paroi ≥ 60° quelque part sur une transversale, ≥ 2 replats
|
||
distincts) ; crevasse (fond de sable ≥ 16 m sous le plateau ouvert, 3 à 8 m
|
||
de large à 10 m sous le plateau) ; chaos (roche sur un
|
||
bloc, sable entre deux blocs, ≥ 40 cellules de roche distinctes… mesuré par
|
||
fraction de roche dans le disque) ; éperons (chenal plus bas que les deux
|
||
buttes, roche sur chaque butte) ; falaise (marche ≥ 18 m mesurée dans la
|
||
seule bande de crête, pour que la pente en contrebas ne masque pas une
|
||
marche absente) ; bornes et profondeurs globales.
|
||
- **Intégration (`run_site_terrain_integration.gd`)** : chargement du showcase
|
||
sous 3 s, rayon dans le canyon plus bas que sur la mesa, scan de référence
|
||
lisant roche et sable.
|
||
|
||
## 7. Documentation
|
||
|
||
- ADR 0012 : amendement §3 (liste des primitives, phase de modification,
|
||
matériau par primitive), sans changer le contrat de données.
|
||
- `content/README.md`, `tests/README.md` : le site de démonstration.
|
||
- Captures sous `docs/briefs/captures/` : `terrain_showcase_terrain_preview.png`
|
||
(champ de hauteur vu de dessus, roche teintée) et cinq vues en jeu, graybox,
|
||
`terrain_showcase_canyon.png` (gradins et fond ridé), `_crevasse.png`,
|
||
`_boulders.png`, `_spurs.png`, `_escarpment.png` (face de la falaise vue du
|
||
pied) ; pour le Banc du Vigilant recuit, `zone1_vigilant_tombant.png`
|
||
(gradins du tombant) et `zone1_vigilant_plateau.png` (plateau ondulé). Les
|
||
captures sont faites avec le shader à normal maps et ombrage de détail
|
||
(brief du Banc du Vigilant, §7) ; brouillard et lumière restent ceux de la
|
||
scène de site.
|
||
|
||
## 8. Décisions laissées à Olivier
|
||
|
||
1. **Résolution** : le showcase est cuit à 1,0 m par cellule (crevasse de 6 m
|
||
lisible). Les gradins imposent une paroi d'au moins 2 à 3 cellules par
|
||
couche : à 1 m par cellule, des couches de 4 m sur une paroi à 55° ; une
|
||
paroi à 76° (première cuisson) ne montrait aucun gradin. Les sites de mission restent à 1,5 m sauf décision contraire ; une
|
||
crevasse de 5 m à 1,5 m par cellule n'a que trois cellules de large.
|
||
2. **Strates sur le Banc du Vigilant** : décidé par Olivier le 2026-10-06,
|
||
appliquées à la rupture et au tombant (bande z ≥ 118 m, couches de 4 m,
|
||
plein effet dès 40° ; la Saignée, l'Échine et les amers sont hors bande).
|
||
Le `.res` du site a été recuit ; l'objet secondaire, les débris et les
|
||
routes restent dans leurs contrats.
|
||
3. **Sites de mission suivants** (U-Boot sous falaise, océanographique en
|
||
canyon) : les primitives sont prêtes ; le plan de masse de chaque site
|
||
reste à proposer et valider séparément.
|