231 lines
12 KiB
Markdown
231 lines
12 KiB
Markdown
# BVLE Voxels - Prototype de Moteur Voxel Hybride
|
||
|
||
## Vue d'ensemble
|
||
|
||
Prototype de moteur voxel basé sur **Wicked Engine** (MIT, C++17, DX12/Vulkan) pour valider les performances de rendu sur GPU moderne (AMD RDNA 2+ / Nvidia RTX 3060+). Le document de spécification complet est dans `voxel_engine_spec.md` à la racine du projet.
|
||
|
||
Cible : 60+ fps en 1440p, monde de 512x512x256 voxels visibles.
|
||
|
||
## Architecture
|
||
|
||
```
|
||
bvle-voxels/
|
||
├── CMakeLists.txt # Build CMake racine
|
||
├── engine/ # Wicked Engine (clone --depth 1, branche main)
|
||
│ └── WickedEngine/shaders/voxel/ # Nos shaders copiés ici pour compilation DXC
|
||
├── src/
|
||
│ ├── voxel/ # Bibliothèque VoxelEngine (static lib)
|
||
│ │ ├── VoxelTypes.h # Types fondamentaux (VoxelData, PackedQuad, MaterialDesc, ChunkPos)
|
||
│ │ ├── VoxelWorld.h/.cpp # Monde voxel (hashmap de chunks, génération procédurale)
|
||
│ │ ├── VoxelMesher.h/.cpp # Binary Greedy Mesher CPU + SmoothMesher (Naive Surface Nets)
|
||
│ │ ├── VoxelRenderer.h/.cpp# Renderer + VoxelRenderPath (CameraController, AnimationState, VoxelProfiler)
|
||
│ │ ├── VoxelRTManager.h/.cpp # Ray tracing: BLAS/TLAS lifecycle, shadows+AO dispatches
|
||
│ │ ├── DeferredGPUBuffer.h # Utilitaire staging→dirty→capacity GPU buffer upload
|
||
│ │ └── TopingSystem.h/.cpp # Système de topings (biseaux décoratifs sur faces +Y)
|
||
│ └── app/
|
||
│ └── main.cpp # Point d'entrée Win32 + crash handler SEH
|
||
├── shaders/ # Sources HLSL des shaders voxel (copiés dans engine/ au build)
|
||
│ ├── voxelCommon.hlsli # Root signature et CB partagés (inclus par tous les shaders)
|
||
│ ├── voxelVS.hlsl # Vertex shader (vertex pulling, triple-mode: CPU/MDI/GPU mesh)
|
||
│ ├── voxelPS.hlsl # Pixel shader (triplanar + lighting)
|
||
│ ├── voxelCullCS.hlsl # Compute shader frustum+backface cull (Phase 2.3)
|
||
│ ├── voxelMeshCS.hlsl # Compute shader GPU mesher 1×1 (Phase 2.4-2.5)
|
||
│ ├── voxelTopingVS.hlsl # Vertex shader topings (instanced vertex pulling, t4/t5)
|
||
│ ├── voxelTopingPS.hlsl # Pixel shader topings (triplanar + directional lighting)
|
||
│ ├── voxelSmoothVS.hlsl # Vertex shader smooth Surface Nets (vertex pulling, t6)
|
||
│ ├── voxelSmoothPS.hlsl # Pixel shader smooth (triplanar + material blending)
|
||
│ ├── voxelBLASExtractCS.hlsl # Compute shader BLAS position extraction (Phase 6.1)
|
||
│ ├── voxelShadowCS.hlsl # Compute shader RT shadows + raw AO (inline ray queries, Phase 6.2+6.3)
|
||
│ ├── voxelAOBlurCS.hlsl # Compute shader bilateral AO blur (separable H/V, Phase 6.3)
|
||
│ └── voxelAOApplyCS.hlsl # Compute shader AO apply + tone mapping + saturation (Phase 6.3 + 7)
|
||
├── CLAUDE.md
|
||
└── TROUBLESHOOTING.md # Pièges techniques, debugging, APIs Wicked
|
||
```
|
||
|
||
## Build
|
||
|
||
### Prérequis
|
||
|
||
- CMake 3.19+ (`winget install Kitware.CMake`)
|
||
- Visual Studio 2022 Build Tools (`winget install Microsoft.VisualStudio.2022.BuildTools`)
|
||
- Windows SDK 10.0.26100+ (`winget install Microsoft.WindowsSDK.10.0.26100`)
|
||
|
||
### Commandes
|
||
|
||
```bash
|
||
# Configurer (depuis la racine du projet)
|
||
cmake -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_SYSTEM_VERSION=10.0.26100.0
|
||
|
||
# Compiler
|
||
cmake --build build --config Release --target BVLEVoxels --parallel
|
||
|
||
# Exécutable produit dans build/Release/BVLEVoxels.exe
|
||
```
|
||
|
||
Le SDK 10.0.26100 est requis car les headers DX12 (`d3dx12_check_feature_support.h`) fournis par Wicked Engine ne sont pas compatibles avec le SDK 22621.
|
||
|
||
### Exécution
|
||
|
||
**IMPORTANT** : Le CWD doit être la **racine du projet**, pas `build/Release/`.
|
||
L'exe utilise des chemins relatifs pour les assets (`Content/`) et la compilation shader (`engine/WickedEngine/shaders/`).
|
||
|
||
```bash
|
||
# Lancer normalement (fenêtre 1920x1080 centrée)
|
||
build/Release/BVLEVoxels.exe
|
||
|
||
# Mode screenshot (640x480, capture 3 vues, quitte automatiquement)
|
||
build/Release/BVLEVoxels.exe screenshot
|
||
|
||
# Autres arguments
|
||
build/Release/BVLEVoxels.exe debug # Faces colorées par direction
|
||
build/Release/BVLEVoxels.exe debugsmooth # Scène smooth debug
|
||
build/Release/BVLEVoxels.exe vulkan # Forcer backend Vulkan
|
||
```
|
||
|
||
**Fichiers de sortie** (écrits dans le CWD, donc la racine du projet) :
|
||
- `bvle_backlog.txt` — log Wicked Engine
|
||
- `bvle_crash.log` + `bvle_crash.dmp` — crash report SEH (si crash)
|
||
- `bvle_screenshot_*.png` — captures mode screenshot ou F6
|
||
|
||
**Raccourcis clavier** :
|
||
- `F2` — toggle backlog Wicked
|
||
- `F3` — toggle animation terrain (30 Hz)
|
||
- `F4` — toggle debug blend
|
||
- `F5` — cycle RT shadows/AO (ON → debug shadows → debug AO → OFF)
|
||
- `F6` — screenshot in-app (sauvegarde `voxelRT_` en PNG)
|
||
|
||
### Post-build automatique (CMakeLists.txt)
|
||
|
||
Le build copie automatiquement :
|
||
1. `dxcompiler.dll` → à côté de l'exe (requis pour la compilation runtime des shaders)
|
||
2. `shaders/*.hlsl` → `engine/WickedEngine/shaders/voxel/` (pour que `LoadShader` les trouve via `SHADERSOURCEPATH`)
|
||
3. `engine/Content/` → à côté de l'exe (assets Wicked Engine)
|
||
|
||
## Intégration Wicked Engine
|
||
|
||
### Backend graphique
|
||
|
||
Wicked Engine utilise **DX12 par défaut sur Windows**, Vulkan sur Linux. Les shaders sont écrits en **HLSL** et compilés via DXC. Pour forcer Vulkan sur Windows, passer `"vulkan"` en argument de ligne de commande.
|
||
|
||
### Point d'entrée et architecture de rendu
|
||
|
||
`VoxelRenderPath` hérite de `wi::RenderPath3D`. Le rendu voxel utilise ses propres render targets (`voxelRT_`, `voxelDepth_`) et est exécuté dans `Render()` sur un **command list dédié**. Le résultat est composité dans `Compose()` via `wi::image::Draw()`.
|
||
|
||
**NE JAMAIS créer un render pass dans `Compose()`** : cette méthode est appelée à l'intérieur du render pass du swapchain. Imbriquer des render passes est interdit en D3D12.
|
||
|
||
```
|
||
Render() → RenderPath3D::Render() // Wicked rend sa scène
|
||
→ device->BeginCommandList() // Nouveau cmd list
|
||
→ renderer.render(cmd, ...) // Notre render pass (clear + draw voxels → voxelRT_)
|
||
Compose() → RenderPath3D::Compose() // Wicked affiche son résultat
|
||
→ wi::image::Draw(voxelRT_) // On overlay nos voxels par-dessus
|
||
```
|
||
|
||
La caméra est gérée manuellement dans `Update()` en écrivant directement `camera->Eye`, `camera->At` (direction LookTo), `camera->Up`.
|
||
|
||
> See `TROUBLESHOOTING.md` for the detailed Wicked API reference table, shader binding pitfalls, DX12 resource state management, and debugging guides.
|
||
|
||
## Détails d'implémentation
|
||
|
||
### VoxelData (16 bits)
|
||
|
||
```
|
||
[15:8] material ID (256 matériaux)
|
||
[7:4] flags (smooth, transparent, emissive, custom)
|
||
[3:0] metadata (orientation, variant)
|
||
```
|
||
|
||
### PackedQuad (64 bits = 8 octets par quad)
|
||
|
||
```
|
||
[5:0] position X (0-63) [23:18] width (1-32)
|
||
[11:6] position Y (0-63) [29:24] height (1-32)
|
||
[17:12] position Z (0-63) [32:30] face (0-5)
|
||
[40:33] material ID [48:41] blendMatID
|
||
[59:49] chunkIndex (11 bits) [63:60] blendEdges (4 bits)
|
||
```
|
||
|
||
### Binary Greedy Mesher (CPU, `VoxelMesher.cpp`)
|
||
|
||
Masques binaires par axe, face culling par shift/XOR, greedy merge rectangulaire par tranche de profondeur.
|
||
|
||
### Génération procédurale (`VoxelWorld.cpp`)
|
||
|
||
Perlin noise 3D, fBm 5 octaves (2 en animation), caves 3D, matériaux par altitude. Chunks Y=0..7. Animation 60 Hz via `regenerateAnimated()` parallélisé avec `wi::jobsystem`.
|
||
|
||
### Renderer (`VoxelRenderer.cpp`)
|
||
|
||
- **Triple-mode VS** : CPU path, MDI path, GPU mesh path (défaut)
|
||
- **GPU mesh** : compute shader `voxelMeshCS` → barrier UAV→SRV → `DrawInstanced` (readback 1-frame-delay)
|
||
- **Vertex pulling** via `SV_VertexID`, pas de vertex buffer classique
|
||
- **Per-chunk info** : `StructuredBuffer<GPUChunkInfo>` (80 bytes/chunk)
|
||
- **Height-based blending** (Phase 3) : PS lit `voxelDataBuffer` (t3), winner-takes-all heightmap, corner attenuation
|
||
- **Render targets propres** : `voxelRT_` (R8G8B8A8) + `voxelDepth_` (D32_FLOAT)
|
||
- **CPU profiling** : `VoxelProfiler` (21 `ProfileAccum`, moyennes toutes les 5s)
|
||
- **DeferredGPUBuffer** : utilitaire pour buffers GPU avec staging CPU, dirty flag, capacity-based growth (25% headroom)
|
||
- **VoxelRTManager** (`VoxelRTManager.h/.cpp`) : gère BLAS/TLAS, dispatches RT shadows+AO, isolé du renderer
|
||
- **VoxelRenderPath** décomposé en : `CameraController` (mouvement/souris), `AnimationState` (tick terrain), `VoxelProfiler`
|
||
- **Toping sort** : counting sort O(n) par (type, variant) au lieu de `std::sort`
|
||
|
||
## Phases de développement
|
||
|
||
### Phase 1 - Setup et meshing de base [FAIT]
|
||
|
||
Fork Wicked Engine, VoxelWorld procédural, Binary Greedy Mesher CPU (~300K quads), rendu vertex pulling, caméra libre, crash handler SEH.
|
||
|
||
### Phase 2 - Performance GPU [FAIT]
|
||
|
||
- **2.1** : Mega-buffer + CPU frustum/backface cull + per-face DrawInstanced
|
||
- **2.2** : CPU-filled indirect args + DrawInstancedIndirectCount (MDI)
|
||
- **2.3** : GPU compute culling (0.006 ms / 168 chunks)
|
||
- **2.4** : GPU compute mesher benchmark (CPU 277ms vs GPU 5.3ms)
|
||
- **2.5** : GPU meshing production + CPU optimisations (fused regen+pack, memcpy, dirty cache)
|
||
- **Résultat** : 80-110 FPS avec animation 60 Hz, 700+ FPS statique
|
||
|
||
### Phase 3 - Texture blending [FAIT]
|
||
|
||
PS-based heightmap blending, winner-takes-all, corner attenuation subtractive. GPU mesh path uniquement.
|
||
|
||
### Phase 4 - Toping [EN COURS]
|
||
|
||
- **4.1** [FAIT] : TopingSystem infrastructure, 4-bit adjacency, priority-based, stone wedges + grass tufts
|
||
- **4.2** [FAIT] : Shaders dédiés, vertex pulling instancié, half-Lambert + translucency vegetation
|
||
- **4.3** [A FAIRE] : Plus de types, LOD, animation vent, compute shader instances
|
||
|
||
### Phase 5 - Rendu smooth [EN COURS]
|
||
|
||
- **5.1** [FAIT] : Naive Surface Nets CPU, SDF binaire, cross-chunk connectivity, smooth/blocky boundary
|
||
- **5.2** [FAIT] : Smooth vertex normals, geometric normals triplanar, optimisations CPU (560ms → 17ms)
|
||
- **5.3** [A FAIRE] : GPU compute Surface Nets
|
||
- **5.4** [A FAIRE] : SDF lissé, LOD, pipeline asynchrone
|
||
|
||
### Phase 6 - Ray tracing hybride [EN COURS]
|
||
|
||
- **6.1** [FAIT] : Normal RT (MRT), BLAS extraction CS, 3 BLAS (blocky+smooth+topings), TLAS
|
||
- **6.2** [FAIT] : RT shadows (3 jittered rays, TMin adaptatif, colored shadows)
|
||
- **6.3** [FAIT] : RT AO (4 cosine-weighted rays, IGN + Cranley-Patterson, temporal accumulation, bilateral blur)
|
||
- **6.4** [A FAIRE] : Fallback shadow maps + SSAO
|
||
|
||
### Phase 7 - Stylized Lighting [EN COURS]
|
||
|
||
- **7.1** [FAIT] : Hemisphere ambient, colored shadows, rim light, tone mapping + saturation, screenshot mode
|
||
|
||
## Métriques cibles et résultats
|
||
|
||
| Métrique | Cible | Résultat (Ryzen 7 9800X3D + RX 9070 XT) |
|
||
|----------|-------|---------------------------------------|
|
||
| FPS 1440p | > 60 fps | 80-110 FPS (anim blocky), 700+ FPS (statique) |
|
||
| FPS anim smooth+topings | > 15 fps | 17 FPS (smooth+topings+blocky anim 60Hz) |
|
||
| Meshing GPU (blocky) | < 200 us/chunk | ~0.6 us/chunk (0.1ms / 171 chunks) |
|
||
| Meshing CPU (smooth) | < 30ms | 17ms (parallele, 648 chunks) |
|
||
| Memoire GPU | < 500 Mo | ~30 Mo |
|
||
| Draw calls | < 100 | 1 (GPU mesh) ou 1 (MDI) |
|
||
|
||
## Conventions
|
||
|
||
- Namespaces : tout le code voxel est dans `namespace voxel`
|
||
- Chunks : 32x32x32, configurable via `CHUNK_SIZE`
|
||
- Coordonnées : Y = haut, monde infini en X/Z, hashmap sparse
|
||
- Matériaux : palette de 256, index 0 = air (vide), 1=grass, 2=dirt, 3=stone (blocky), 4=sand, 5=snow (smooth), 6=smoothstone (smooth)
|
||
- Faces : 0=+X, 1=-X, 2=+Y, 3=-Y, 4=+Z, 5=-Z
|
||
- Smooth flag : `FLAG_SMOOTH = 0x1` dans VoxelData flags — active Surface Nets au lieu du rendu blocky
|