Per-frame CreateRaytracingAccelerationStructure calls during F3 animation caused VRAM explosion (especially toping BLAS at ~23M vertices). Now all 3 BLASes use capacity-based allocation with 25% headroom — only recreated when vertex count exceeds capacity, otherwise just BuildRaytracingAS with updated desc.vertex_count. TLAS only recreated when instance count changes. Also adds deferred toping BLAS position upload via UpdateBuffer in Render() (topingBLASDirty_ flag), enabling toping shadows to update during animation. Split CLAUDE.md into CLAUDE.md + TROUBLESHOOTING.md for maintainability.
9.7 KiB
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 (sous-classe RenderPath3D)
│ │ └── 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
# 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.
Post-build automatique (CMakeLists.txt)
Le build copie automatiquement :
dxcompiler.dll→ à côté de l'exe (requis pour la compilation runtime des shaders)shaders/*.hlsl→engine/WickedEngine/shaders/voxel/(pour queLoadShaderles trouve viaSHADERSOURCEPATH)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.mdfor 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 :
ProfileAccumavec moyennes toutes les 5s
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 = 0x1dans VoxelData flags — active Surface Nets au lieu du rendu blocky