bvle-voxels/research_connected_meshes.md
Samuel Bouchet 9e777d653b Phase 4.1: TopingSystem infrastructure + procedural mesh generation
- TopingSystem with TopingDef registry, procedural mesh gen, instance collection
- 2 toping types: stone bevel (h=0.06, smooth) + grass edge (h=0.12, bumpy)
- 16 mesh variants per type indexed by 4-bit adjacency bitmask (~6 unique with symmetry)
- Wedge cross-section: outer wall + sloped top, grass has sinusoidal height profile
- Instance collection scans exposed +Y faces, checks same-material neighbors
- Cross-chunk adjacency via VoxelWorld::getVoxel()
- Integrated into VoxelRenderPath: init at Start(), stats in HUD
- ~191K instances, 1920 mesh vertices for 170 chunks (validated)
- Research doc (research_connected_meshes.md) + plan (plan_phase4.md)
2026-03-26 15:27:15 +01:00

15 KiB
Raw Blame History

Recherche : Systèmes de meshes connectés/contextuels pour moteurs voxel

Objectif : Trouver le meilleur système (bitmask, WFC, dual grid, hybride) pour placer automatiquement des meshes décoratifs adaptatifs sur un terrain voxel temps réel.

Mots-clés : auto-tiling 3D, connected meshes, Wave Function Collapse, dual grid, marching squares mesh variants, modular mesh kit, contextual mesh placement.


1. Taxonomie des approches

1.1 Bitmask auto-tiling (lookup table)

Le plus simple : examiner les N voisins d'une cellule, construire un bitmask, indexer une table de mesh variants.

Variante Voisins Cas bruts Cas uniques (symétrie) Meshes à créer
4-bit cardinal (2D) 4 16 ~6 6 + rotations
8-bit blob (2D) 8 256 47 47
4-bit per-face (3D) 4 par face 16 par face ~6 par face ~30 (6 faces × 5)
6-bit face (3D) 6 64 ~18 18

Avantages : O(1), trivial à implémenter, déterministe, mise à jour instantanée. Inconvénients : pas de cohérence globale, nombre de meshes croît vite avec la complexité.

Implémentations notables : Godot TileMap, RPG Maker, Vintage Story (JSON block models avec variantes par adjacence).

1.2 Wave Function Collapse (WFC)

Solveur de contraintes itératif : maintenir un ensemble de tiles possibles par cellule, collapser la cellule de moindre entropie, propager les contraintes aux voisins. Backtracking si contradiction.

Avantages : diversité visuelle, cohérence globale, flexible (n'importe quel tileset). Inconvénients : coût CPU non-trivial, backtracking imprévisible, design de tilesets complexe, mal adapté au temps réel 60Hz.

Implémentations notables :

1.3 Dual grid (marching squares/cubes avec meshes artisanaux)

La grille logique (données voxel) est décalée d'une demi-cellule par rapport à la grille visuelle. Chaque cellule visuelle examine 4 (2D) ou 8 (3D) coins de la grille logique → bitmask → lookup dans une table de mesh pré-modélisés.

C'est mathématiquement équivalent à Marching Cubes, mais au lieu de générer des triangles procéduralement, chaque cas est un mesh artisanal.

Dimension Coins Cas bruts Cas uniques (symétrie)
2D 4 16 6
3D 8 256 15 (MC classique) ou ~23 (ambiguïtés)

Avantages : très peu de meshes à créer (~10-15), transitions automatiquement seamless (bords partagés par construction), O(1) par cellule. Inconvénients : la grille visuelle ne correspond pas à la grille logique (décalage ½ cellule → complique physique/gameplay), courbes limitées à un rayon de ½ cellule, multi-matériaux nécessite un traitement spécial.

Sources clés :

1.4 Quarter-tile / Eighth-tile (Boris the Brave)

Alternative au dual grid sans décalage de grille. Chaque cellule est subdivisée en 4 quadrants (2D) ou 8 octants (3D). Chaque quadrant sélectionne un sous-mesh basé sur 3 voisins (la cellule + 2 adjacents).

Dimension Sous-meshes uniques Qualité visuelle
2D (quarter-tile) 5-6 Équivalent blob (47 tiles)
3D (eighth-tile) ~10 Équivalent MC (15 cas)

Avantages : données restent sur les cellules (pas de décalage), peu de meshes à créer, qualité blob avec effort minimal. Inconvénients : 4-8× plus de sous-meshes à instancier par cellule (mais GPU instancing amortit).

Source : https://www.boristhebrave.com/2023/05/31/quarter-tile-autotiling/

1.5 Marching cubes multi-matériaux (Boris the Brave)

Extension de marching squares/cubes pour N matériaux au lieu de 2 (solide/vide). Seulement 15 cas topologiques quel que soit le nombre de matériaux — seul le pattern de relations entre coins compte, pas les valeurs absolues.

Insight clé : une frontière herbe-pierre et une frontière sable-neige utilisent le même template de mesh, juste avec des textures différentes.

Recommandation de l'auteur pour la 3D : "In 3D, I'd recommend that you just do regular marching cubes to get a single surface for all colors, then use a pixel shader to colorize that surface." — c'est exactement notre approche Phase 3.

Source : https://www.boristhebrave.com/2021/12/29/2d-marching-cubes-with-multiple-colors/


2. Études de cas — Jeux et moteurs

2.1 Townscaper (Oskar Stålberg, 2020)

Le cas de référence pour les meshes connectés procéduraux.

Technique : pas du WFC standard, mais un système de contraintes déterministe sur dual grid :

  • L'utilisateur peint des blocs solides/vides sur une grille irrégulière (Voronoi relaxé)
  • Chaque point du dual grid examine les 8 cellules environnantes → bitmask → sélection de module
  • ~80 modules pré-modélisés couvrent toutes les configurations
  • Pas de backtracking : chaque configuration est valide par design ("every configuration must be valid")
  • Pas de randomness : sélection déterministe (1 seul module valide par état)

Différences clés vs WFC standard :

Aspect WFC standard Townscaper
Contradictions Possibles → backtracking Impossibles par design
Propagation Globale Locale uniquement
Sélection Aléatoire parmi les valides Déterministe (1 module/état)
Modules 100+ ~80 (~15-20 canoniques)
Performance Variable (backtracking) O(1) par cellule
Grille Régulière Irrégulière (Voronoi)

Principes réutilisables :

  1. Bitmask → lookup déterministe (pas besoin de solveur)
  2. Exploiter les symétries (rotation/reflection) : 256 → ~15-20 cas uniques
  3. Mise à jour locale uniquement (le voxel modifié + ses voisins immédiats)
  4. Couleurs/matériaux = variations de texture sur les mêmes modules, pas des modules séparés

Sources :

2.2 Wonderbox (Aquiris, Amilton Diesel)

Statut : pas de documentation technique publique trouvée. Amilton Diesel (Technical Art Director chez Aquiris, maintenant chez Epic Games) n'a pas publié de breakdown technique indexable. Le style visuel (blocs modulaires colorés en diorama) suggère un système de modules connectés, mais les détails techniques restent propriétaires.

Sources :

2.3 Enshrouded (Keen Games, Holistic Engine)

Technique : moteur voxel propriétaire avec terrain SDF (signed distance field) + isosurface extraction lisse. Fondamentalement différent d'un moteur blocky — les voxels stockent des distances, pas des matériaux binaires.

Décoration : meshes placés sur la surface du terrain (vegetation, rochers) séparément du mesh voxel. Le système est hand-crafted par les artistes avec outils internes + Substance Painter.

Pertinence : limitée pour notre cas (terrain blocky, pas SDF). Le pattern architectural "terrain voxel + meshes décoratifs instanciés séparément" est par contre le même que notre Phase 4.

2.4 Portal Knights (Keen Games)

Technique : rendu blocky standard (cubes). Pas de système de décoration par adjacence documenté. Pertinence limitée.

2.5 Vintage Story (2024)

Technique : block models définis en JSON avec variantes sélectionnées par règles d'adjacence. Chaque bloc peut avoir plusieurs mesh variants, la sélection dépend du contexte (voisins, face exposée). Système data-driven (pas de code par type de bloc).

Pertinence : bon modèle pour un système de toping data-driven, mais le code source n'est pas ouvert pour la partie rendering.

2.6 Veloren (open source, Rust)

Technique : voxel RPG open source avec système de décoration combinant structures pré-créées + scatter-based placement. Codebase bien documentée sur gitlab.com/veloren/veloren.


3. "Driven WFC" — L'approche hybride (Boris the Brave)

L'article le plus pertinent pour notre cas : Driven WFC.

Concept : utiliser WFC comme "remplisseur de détails", pas comme générateur de structure. Un système externe (utilisateur, heightmap, algorithme) détermine la macro-structure ; WFC sélectionne les variantes compatibles dans les contraintes.

Application au toping :

  1. Le monde voxel détermine la macro-structure (quels blocs existent, quels matériaux)
  2. Le bitmask d'adjacence contraint quelles variantes de toping sont valides
  3. Optionnellement, WFC sélectionne parmi les variantes valides pour de la variété visuelle

C'est exactement le workflow de Townscaper : l'utilisateur peint la structure → le système contraint les modules possibles → sélection déterministe (ou aléatoire pour plus de variété).

Pour notre prototype : commencer par la sélection déterministe (bitmask → lookup), ajouter la variété WFC plus tard si nécessaire.


4. Articles techniques clés (Boris the Brave)

Article URL Pertinence
Quarter-Tile Autotiling https://www.boristhebrave.com/2023/05/31/quarter-tile-autotiling/ Alternative au dual grid, ~5-6 meshes pour qualité blob
Beyond Basic Autotiling https://www.boristhebrave.com/2021/09/12/beyond-basic-autotiling/ Multi-matériaux, composition par couches
Multi-Color Marching Squares https://www.boristhebrave.com/2021/12/29/2d-marching-cubes-with-multiple-colors/ 15 cas quel que soit le nombre de matériaux
Driven WFC https://www.boristhebrave.com/2021/06/06/driven-wavefunctioncollapse/ WFC comme détail-filler, pas générateur
Classification of Tilesets https://www.boristhebrave.com/2021/11/14/classification-of-tilesets/ Taxonomie formelle, aide au design
WFC Explained https://www.boristhebrave.com/2020/04/13/wave-function-collapse-explained/ Comprendre AC-4, support counting
Editable WFC https://www.boristhebrave.com/2022/04/25/editable-wfc/ Re-solving local pour édition temps réel
Constraint-Based Tile Generators https://www.boristhebrave.com/2021/10/31/constraint-based-tile-generators/ Comparaison WFC vs Model Synthesis
Marching Cubes Tutorials (2D/3D) https://www.boristhebrave.com/2018/04/15/marching-cubes-tutorial/ Fondamentaux dual grid

5. Comparaison pour notre cas d'usage

Notre besoin : placer des meshes décoratifs 3D sur les faces exposées de voxels dans un moteur temps réel (60+ FPS, monde dynamique animé).

Critère Bitmask 4-bit Quarter-tile Dual grid 3D WFC Driven WFC
Complexité code Très faible Faible Moyen Élevé Moyen
Meshes à créer 16 (~6 uniques) 5-6 10-15 Variable Variable
Qualité visuelle Basique Blob-quality Smooth transitions Excellent Très bon
Performance O(1) lookup O(1) lookup × 4 O(1) lookup O(N) solver O(1) + O(N) init
Multi-matériaux N² explosion Couches 15 cas pour N mat Naturel Naturel
Mise à jour dynamique Instantanée Instantanée Instantanée Re-solve local Re-solve local
Cohérence globale Non Non Non Oui Partielle
Adapté à 60Hz anim ⚠️ (init seul)

6. Recommandation

Approche recommandée : Bitmask 4-bit + Quarter-tile optionnel

Phase 4.1 : Bitmask 4-bit simple (16 cas, ~6 uniques avec symétrie)

  • Implémentation triviale, validé rapidement
  • Suffisant pour le prototype (rebords, bordures)
  • Le plan existant dans plan_phase4.md est adapté

Phase 4.2 (optionnel) : Upgrade vers Quarter-tile

  • Même données voxel, meilleure qualité visuelle
  • Chaque face subdivisée en 4 quadrants, ~5-6 sous-meshes
  • Qualité visuelle blob (47 tiles) avec seulement 5-6 meshes par type de toping
  • Référence : Boris the Brave quarter-tile article

Non recommandé pour le prototype :

  • WFC complet : trop complexe, mal adapté à l'animation 60Hz
  • Dual grid 3D : nécessiterait de refactorer le mesher (décalage de ½ cellule)
  • Socket-based modules : overhead d'authoring trop important

Insight clé de Townscaper applicable directement

"Every configuration must be valid" — concevoir les meshes de toping pour que TOUTE combinaison de bitmask produise un résultat visuellement acceptable. Pas de fallback, pas de cas d'erreur. Chaque bitmask (0-15) a un mesh dédié, même si certains sont dégénérés (mesh vide pour bitmask 0 = pas de voisins du bon type).

Multi-matériaux via composition par couches

Au lieu de créer des meshes séparés pour chaque paire de matériaux (explosion N²), utiliser des meshes de bordure composés par couche :

  • Un set de meshes "bordure" par matériau qui se compose par-dessus le quad voxel de base
  • La texture/couleur vient du matériau, pas du mesh
  • C'est l'approche "Beyond Basic Autotiling" de Boris the Brave

Sources complètes

Articles techniques

Repos open source

Talks et vidéos

  • Oskar Stålberg talks (YouTube : "Oskar Stålberg Townscaper", "Oskar Stålberg procedural")
  • Sebastian Lague voxel terrain (YouTube, 2023-2024)