Ce prototype vise à valider la faisabilité et la performance d'un moteur de rendu voxel enrichi, inspiré de titres comme Enshrouded, sur du matériel GPU moderne (RDNA 2+ / RTX 3060+). Le moteur combine rasterisation haute performance pour le rendu primaire et ray tracing optionnel pour l'éclairage.
## 1.1 Objectifs du prototype
- Valider les performances de meshing et de rendu sur GPU moderne (cible : 60+ fps à 1440p, monde de 512×512×256 voxels visibles)
- Implémenter un pipeline de rendu hybride rasterisation + RT (ray queries pour ombres/AO)
- Démontrer les 4 fonctionnalités clés : meshing blocky, toping, texture blending, rendu smooth alternatif
- Mesurer les coûts relatifs de chaque technique pour guider les choix d'architecture du moteur final
## 1.2 Non-objectifs (hors scope prototype)
- Gameplay, UI in-game, sauvegarde/chargement de monde
- Multijoueur, streaming réseau
- Système de LOD distant (clipmaps, impostors) — uniquement LOD par taille de chunk
- Physique avancée (collisions basiques suffisantes pour la navigation caméra)
- Optimisation mobile / consoles
## 1.3 Plateforme technique
| Composant | Choix |
| --- | --- |
| Moteur de base | Wicked Engine (fork, branche dédiée) |
**Justification Wicked Engine : **Le moteur fournit un pipeline de rendu bindless GPU-driven moderne (vertex pulling, indirect draw), un ECS, la gestion d'input/audio/assets, le scripting Lua, et un éditeur. Le renderer est contrôlable et remplaçable pièce par pièce. Licence MIT.
# 2. Architecture générale
## 2.1 Vue d'ensemble du pipeline
Le pipeline de rendu se décompose en passes séquentielles. Les passes de rasterisation produisent le G-buffer. Les passes de ray tracing enrichissent l'éclairage. Le compositing final assemble le tout.
- Toutes les textures dans un texture array 2D bindless (512×512, max 256 layers)
**Toping registry**
- Tableau de TopingDef : mesh asset ID, conditions de placement (face, adjacence bitmask), LOD meshes
- Chaque TopingDef référence 1-6 mesh variants selon le bitmask d'adjacence des voisins
- Les mesh assets sont stockés dans le système d'assets standard de Wicked Engine
# 3. Fonctionnalité 1 : Meshing des voxels
## 3.1 Algorithme : Binary Greedy Meshing
Implémentation basée sur le binary greedy mesher de cgerikj (github.com/cgerikj/binary-greedy-meshing), adaptée pour fonctionner en compute shader GPU.
**Pipeline de meshing (compute shader)**
**Étape 1 — Masque binaire : **Pour chaque axe (X, Y, Z), générer un tableau 32×32 de uint32 où chaque bit représente la présence d'un voxel opaque sur cet axe. Une opération bitwise (col & !(col <<1))identifielesfacesvisibles.
**Étape 2 — Face culling : **Pour chaque direction (6 faces), un tableau 30×30 de uint32 encode les faces exposées à l'air. 64 faces sont cullées simultanément par opération bitwise.
**Étape 3 — Greedy merge : **Les faces visibles de même type de matériau sont fusionnées en quads maximaux via des opérations bitwise. Le type de voxel source est vérifié pour éviter de fusionner des matériaux différents.
**Étape 4 — Vertex output : **Chaque quad produit 8 octets : 6 bits X, 6 bits Y, 6 bits Z, 6 bits largeur, 6 bits hauteur, 8 bits material ID, reste pour AO et flags. Écriture dans un append buffer GPU.
**Vertex format packé (8 octets par quad)**
| Champ | Bits | Description |
| --- | --- | --- |
| position X | 6 | Position locale dans le chunk (0-63) |
| position Y | 6 | Position locale dans le chunk (0-63) |
| position Z | 6 | Position locale dans le chunk (0-63) |
| width | 6 | Largeur du quad fusionné (1-32) |
| height | 6 | Hauteur du quad fusionné (1-32) |
| face | 3 | Direction de la face (0-5 : +X,-X,+Y,-Y,+Z,-Z) |
| material ID | 8 | Index dans la palette de matériaux |
| AO | 8 | 4×2 bits : AO précalculé aux 4 coins du quad |
Le toping permet de remplacer ou décorer certaines faces de voxels par des meshes 3D arbitraires. Le mesh utilisé s'adapte automatiquement selon les blocs adjacents (connected models).
## 4.2 Système d'adjacence (bitmask)
Pour chaque face d'un voxel marqué « toping », le moteur lit les 4 voisins cardinaux de cette face et encode leur état dans un bitmask 4 bits (haut, droite, bas, gauche). Ce bitmask sert d'index dans une table de 16 variantes de mesh.
- Exemple : un rebord de fenêtre utilise un mesh droit si les voisins gauche et droite sont du même type, un coin si un seul est présent, un embout si aucun n'est présent
- Les variantes sont définies dans le TopingDef (asset data), pas en code
- Le calcul du bitmask se fait au moment du meshing du chunk (CPU ou compute)
## 4.3 Pipeline de rendu
- Les toping instances sont collectées lors du meshing : position monde + mesh variant ID + rotation
- Stockées dans un instance buffer GPU par chunk
- Rendues par instanced draw (un draw call par type de mesh, batched)
- Les meshes de toping écrivent dans le même G-buffer que les voxels
- Le fragment shader des toping utilise des UVs classiques (pas de triplanar), PBR standard
## 4.4 Critères de validation
- Support de 16 variantes par type de toping (bitmask 4 bits)
- Rendu de 50 000 instances de toping à <2msGPU
- Ajout/suppression d'un bloc met à jour les toping adjacents sans stutter
Certains voxels marqués avec le flag « smooth » dans leurs 4 bits de flags sont rendus avec un mesher alternatif qui produit une surface lisse au lieu de cubes.
**Algorithme recommandé : Naive Surface Nets**
- Plus simple que Dual Contouring, moins de cas edge que Marching Cubes
- Un vertex par cellule, positionné au centroïde des edge crossings
- Le champ de distance signé (SDF) est dérivé des voxels : voxel plein = -1, voxel vide = +1, lissé par les voisins
- Le mesh résultant est stocké dans un buffer séparé (pas mélangé avec les quads du greedy mesh)
**Alternative : Transvoxel**
- Si le LOD multi-résolution est nécessaire, Transvoxel gère le stitching entre niveaux de détail
- Plus complexe à implémenter, réserver pour une phase ultérieure
## 6.2 Coexistence blocky / smooth
- Un chunk peut contenir les deux types de voxels
- Le mesher produit deux outputs : quads (blocky) et triangles (smooth), dans des buffers séparés
- Les deux sont rendus dans le même G-buffer, dans deux draw calls distincts (passe 2 et passe 4)
- Le fragment shader smooth utilise le triplanar mapping (pas d'UVs générées)
- La frontière blocky/smooth est gérée par un falloff dans le SDF : les voxels « smooth » adjacents à des voxels « blocky » ont un SDF écrasé vers 0/1 pour éviter les gaps
## 6.3 Critères de validation
- Un terrain organique (collines, grottes) rendu sans arêtes visibles entre les voxels
- Coexistence blocky/smooth dans le même chunk sans cracks ni gaps visuels
- Performance du mesher smooth : <500µsparchunk32³surGPU
# 7. Ray tracing hybride (qualité d'éclairage)
## 7.1 Scope pour le prototype
Le ray tracing n'est pas utilisé pour le rendu primaire (la rasterisation est plus performante). Il est utilisé pour améliorer la qualité de l'éclairage via des ray queries dans un compute shader post-G-buffer.
**Effets RT implémentés**
- **RT Shadows : **1 rayon par pixel vers la lumière directionnelle. Hard shadows, avec option soft shadows (jittered area light, 4-8 samples).
- **RT Ambient Occlusion : **4-8 rayons par pixel en hémisphère cosine-weighted autour de la normale. Courte portée (2-4 mètres).
- Les deux effets utilisent VK_KHR_ray_query (ray queries inline dans le compute shader), pas un full RT pipeline
## 7.2 Acceleration structures
- BLAS : un BLAS de triangles par chunk meshé (le mesh issu du greedy mesher, reconstruit quand le chunk change)
- BLAS toping : les meshes de toping partagés, instanciés dans le TLAS
- TLAS : reconstruit chaque frame (les instances bougent peu, le rebuild est rapide)
- Les chunks hors frustum ne sont pas inclus dans le TLAS
## 7.3 Fallback sans RT
- Si le GPU ne supporte pas VK_KHR_ray_query : fallback vers shadow maps classiques + SSAO
- Le fallback est le pipeline d'éclairage standard de Wicked Engine (déjà implémenté)
- Détection au startup via vkGetPhysicalDeviceFeatures2 (rayQueryFeaturesKHR)
## 7.4 Critères de validation
- RT Shadows fonctionnels sur AMD RDNA 2+ et Nvidia RTX 3060+
- Coût GPU du RT pass (shadows + AO) <4msen1440p
- Fallback automatique vers shadow maps si RT non disponible
Le VoxelRenderer s'insère dans le render path de Wicked via des hooks dans le RenderPath3D. Les passes voxel custom sont exécutées entre le depth prepass et le deferred lighting, au même moment où Wicked rend normalement ses objets opaques.
# 9. Plan de développement
## Phase 1 — Setup et meshing de base
- Forker Wicked Engine, créer la structure de modules
J'aimerais tester quelque chose, c'est un nouveau type de block qui ne contient que des modèles 3D customs et qui aurait des comportements de jointure dynamique selon les blocs voisins identiques. Spécifiquement, j'aimerais créer des tuyaux qui se connectent les uns aux autres ou créent des nouvelles connexions pour toujours toucher les blocks tuyaux voisin.