Rock is normal-mapped triplanar in world space at two scales, sand carries an oriented ripple normal map on the xz plane, and a grain map drives detail occlusion, albedo mottling and roughness. The three maps are seamless, seeded, mipmapped textures built synchronously by SeabedDetailTextures, so no asset is needed and builds are deterministic. The mesh has no tangents: perturbed normals are computed in world space and written to NORMAL. 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` | `count` demi-ellipsoïdes tirés par `RandomNumberGenerator` seedé dans le disque, combinés par **maximum** ; roche sur toute leur emprise |
|
||
| `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) | quantifie l'élévation en gradins de `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 |
|
||
|
||
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.
|