Voxel-Backen: Tunnel- und Höhlen-Support

Tunnel-Spalten werden im Gradientenschreiben jetzt vollständig geschützt:
Pre-Scan erkennt echte Tunnel (void ≥ Terrain-Höhe mit festem Voxel darüber)
und überspringt dann sämtliche negativen Zellen in dieser Spalte – auch
unter-terrain-liegende. Damit erzeugt MC keinen Plateau-Boden mehr am
Tunnel-Eingang.

Terrain-Übergang-Extrapolation bekommt zusätzlich einen hasVoidBelow-Check:
existieren leere Zellen unterhalb von yBot im geblurrten Chunk, wird die
Extrapolation übersprungen, statt den Hohlraum zuzuschütten.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-08-28 11:59:52 +02:00
parent 9842bf3248
commit 68ec75c41a
48 changed files with 49 additions and 10 deletions

View File

@@ -597,6 +597,11 @@ public class VoxelEditorState extends BaseAppState {
return (h & 0x7FFFFFFF) / (float) 0x7FFFFFFF;
}
/** Gibt eine Momentaufnahme aller aktuell geladenen Chunks zurück (thread-safe). */
public List<VoxelChunk> getChunksSnapshot() {
return new java.util.ArrayList<>(chunks.values());
}
/**
* Speichert alle dirty Chunks synchron.
* Kann von außen aufgerufen werden (z.B. beim globalen Speichern).
@@ -2476,20 +2481,45 @@ public class VoxelEditorState extends BaseAppState {
Float smoothH = smoothMap.get(hk0);
if (h0 == null || smoothH == null) continue;
// Wichtig: colX ist chunk-global (cx*CELLS+bx), kein World-X.
// World-X = colX - 2048 (VoxelChunk.toWorldX-Konvention).
float th = terrainH((float)(colX - 2048), (float)(colZ - 2048));
// Pre-Scan: hat diese Spalte einen echten Tunnel?
// (negative Zelle auf/über Terrain-Höhe mit festem Voxel darüber)
// Tunnel-Spalten bekommen gar keinen positiven Gradienten in
// negative Zellen weder Tunnel-Void noch Unter-Terrain-Cells
// damit kein Plateau auf dem Tunnelboden entsteht.
boolean hasTunnelVoid = false;
outer:
for (int ly = 0; ly < blurN; ly++) {
if ((wiyBase + ly) >= th
&& origChunk.getDensity(bx, ly, bz) < 0) {
for (int ly2 = ly + 1; ly2 < blurN; ly2++) {
if (origChunk.getDensity(bx, ly2, bz) > 0) {
hasTunnelVoid = true; break outer;
}
}
}
}
// Sub-voxel-genauen Dichte-Gradienten schreiben, damit MC die
// Isofläche auf die exakte smoothH-Höhe interpoliert.
// Ausnahme: manuell ausgegrabene Voxel (Tunnel/Höhlen) behalten
// ihren MIN_VALUE erkennbar daran dass Gradient solid will (d>0)
// aber die Original-Dichte bereits Luft ist (MIN_VALUE).
for (int by = 0; by < blurN; by++) {
float d = (smoothH - (wiyBase + by)) * 127f;
// Tunnel/Höhlen-Voxel schützen: Gradient will Solid (d>0),
// aber der Voxel wurde ausgegraben (Dichte negativ) →
// nicht mit Solid-Gradient überschreiben.
// Gilt sowohl für Byte.MIN_VALUE (setDensity) als auch für
// partiell-reduzierte Werte (reduceDensity im Cave-Modus).
float worldY = wiyBase + by;
float d = (smoothH - worldY) * 127f;
if (d > 0f && origChunk.getDensity(bx, by, bz) < 0) {
continue;
if (hasTunnelVoid) continue; // Tunnel-Spalte: alle negativen Zellen schützen
if (worldY >= th) {
// Über Terrain, kein Tunnel-Flag → offene Höhle prüfen
boolean solidAbove = false;
for (int ly = by + 1; ly < blurN; ly++) {
if (origChunk.getDensity(bx, ly, bz) > 0) {
solidAbove = true; break;
}
}
if (solidAbove) continue;
}
}
next[c.idx(bx, by, bz)] = Math.max(-128f, Math.min(127f, d));
}
@@ -2604,6 +2634,15 @@ public class VoxelEditorState extends BaseAppState {
}
if (hasVoid) continue;
// Tunnel-Check: gibt es negative (leere) Zellen UNTERHALB von yBot?
// Das passiert bei Tunneln/Höhlen, deren Decke yBot ist, aber das
// Innere darunter liegt. Extrapolation würde den Hohlraum zuschütten.
boolean hasVoidBelow = false;
for (int ly = 0; ly < yBot; ly++) {
if (blurred.getDensity(lx, ly, lz) < 0) { hasVoidBelow = true; break; }
}
if (hasVoidBelow) continue;
// Steigung aus den zwei Voxeln darüber bestimmen.
// slope < 0: Dichte nimmt nach unten ab (typisch für eine Oberfläche).
float d1 = blurred.getDensity(lx, yBot + 1, lz);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.