From c755f20325de587f6f741369decd1c480e6990f9 Mon Sep 17 00:00:00 2001 From: Samuel Bouchet Date: Fri, 27 Mar 2026 14:39:54 +0100 Subject: [PATCH] =?UTF-8?q?Fix=20smooth=E2=86=94blocky=20gap=20by=20extend?= =?UTF-8?q?ing=20hasSmooth=20filter=20to=20adjacent=20cells?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cells at the smooth↔blocky boundary had no smooth corners themselves, so the strict hasSmooth filter skipped them entirely. This prevented quad emission between the smooth mesh and blocky territory, leaving a visible gap. Now checks 6-connected neighbor cells for smooth corners, ensuring boundary vertices exist for connecting quads. --- CLAUDE.md | 2 +- src/voxel/VoxelMesher.cpp | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index cdfa49d..774a2b9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -462,7 +462,7 @@ Système de biseaux décoratifs (« topings ») sur les faces +Y exposées pour - **Canonical ownership** : chaque edge est émise par un seul chunk (celui contenant le grid point inférieur), pas de duplication **Smooth↔blocky boundary** : -- **`hasSmooth` filter** : ne génère des vertices que si au moins un coin de la cellule est un voxel smooth (évite le débordement sur territoire blocky) +- **`hasSmooth` filter étendu** : génère des vertices si la cellule OU une cellule 6-connectée adjacente contient un coin smooth. Sans cet élargissement, les cellules à la frontière smooth↔blocky (100% blocky mais adjacentes à du smooth) n'ont pas de vertex → les quads de connexion ne peuvent pas être émis → trou de génération - **Per-axis boundary clamping** : les vertices aux frontières smooth↔blocky sont clampés vers la grille entière (empêche le mesh smooth de dépasser sur les faces blocky) - **GPU mesher** : les voxels smooth sont traités comme solides dans `isNeighborAir()` — les faces blocky ne sont pas émises vers les voxels smooth (le mesh smooth couvre la frontière) diff --git a/src/voxel/VoxelMesher.cpp b/src/voxel/VoxelMesher.cpp index b5ec146..8c983f1 100644 --- a/src/voxel/VoxelMesher.cpp +++ b/src/voxel/VoxelMesher.cpp @@ -377,8 +377,11 @@ uint32_t SmoothMesher::meshChunk(Chunk& chunk, const VoxelWorld& world) { for (int z = VERT_MIN; z < VERT_MAX; z++) { for (int y = VERT_MIN; y < VERT_MAX; y++) { for (int x = VERT_MIN; x < VERT_MAX; x++) { - // Strict hasSmooth: at least one corner of the cell must be a smooth voxel. - // This prevents generating vertices in entirely-blocky territory. + // hasSmooth check: at least one corner of THIS cell or an ADJACENT + // cell must be a smooth voxel. This ensures that cells at the + // smooth↔blocky boundary (all blocky corners but neighbor cell has + // smooth) still generate vertices — otherwise the quad connecting + // them can't be emitted, leaving a gap. bool hasSmooth = false; for (int dz = 0; dz <= 1 && !hasSmooth; dz++) for (int dy = 0; dy <= 1 && !hasSmooth; dy++) @@ -386,6 +389,20 @@ uint32_t SmoothMesher::meshChunk(Chunk& chunk, const VoxelWorld& world) { if (smoothGrid[gridIdx(x + dx, y + dy, z + dz)]) hasSmooth = true; } + if (!hasSmooth) { + // Check 6-connected neighbor cells for smooth corners + // (extend reach by 1 cell in each direction) + static const int nbr[6][3] = {{-1,0,0},{1,0,0},{0,-1,0},{0,1,0},{0,0,-1},{0,0,1}}; + for (int n = 0; n < 6 && !hasSmooth; n++) { + int nx = x + nbr[n][0], ny = y + nbr[n][1], nz = z + nbr[n][2]; + for (int dz = 0; dz <= 1 && !hasSmooth; dz++) + for (int dy = 0; dy <= 1 && !hasSmooth; dy++) + for (int dx = 0; dx <= 1 && !hasSmooth; dx++) { + if (smoothGrid[gridIdx(nx + dx, ny + dy, nz + dz)]) + hasSmooth = true; + } + } + } if (!hasSmooth) continue; // Get SDF at 8 corners of cell (x,y,z)