Fix smooth↔blocky gap by extending hasSmooth filter to adjacent cells

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.
This commit is contained in:
Samuel Bouchet 2026-03-27 14:39:54 +01:00
parent b45d5a1884
commit c755f20325
2 changed files with 20 additions and 3 deletions

View file

@ -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)

View file

@ -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)