bvle-voxels/CLAUDE.md

250 lines
13 KiB
Markdown
Raw Permalink Normal View History

# 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)
├── assets/
│ ├── voxel/ # Textures stylisées (6 albedo+height RGBA + 6 normal GL, 512x512)
│ └── raw/ # ZIPs sources FreeStylized.com (CC0)
├── tools/
│ └── prepare_textures.py # Script: ZIP → albedo+heightmap RGBA + normal PNG (512x512)
├── 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.
2026-03-31 20:04:00 +02:00
### 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 + `.log` compagnon)
- `F7` — toggle sun orbit (cycle 10s, altitude sinusoïdale)
- `F8` — toggle crosshair + debug face info (camera, target, face, normal map proj)
2026-03-31 20:04:00 +02:00
### 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
### Phase 8 - Textures stylisées réelles [EN COURS]
- **8.1** [FAIT] : Chargement textures CC0 FreeStylized (6 matériaux, albedo+heightmap RGBA, normal maps GL)
- **8.2** [FAIT] : Texture2DArray (t1=albedo+height, t7=normals), triplanar sampling, stb_image loading
- **8.3** [FAIT] : Height-based texture blending (winner-takes-all, sharpness=16, corner attenuation)
- **8.4** [FAIT] : Asymmetric blend pour resistBleed (coeff 1.6), zone de blend 40%
- **8.5** [FAIT] : UDN triplanar normal mapping (sign correction, GL green flip Y-proj only, NO abs)
- **8.6** [FAIT] : Dirt rendu smooth (FLAG_SMOOTH), ground_02 texture assombrie 0.75
- **8.7** [FAIT] : Sun orbit debug (F7, cycle 10s), crosshair + face debug HUD (F8)
- **8.8** [FAIT] : Screenshot F6 avec .log compagnon (camera, target, debug states, RT stats)
## 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