Bug behoben, der das gebackene terrain zu hoch generiert hat

This commit is contained in:
2026-08-08 13:31:27 +02:00
parent 3b7f3b7e86
commit 96483fada9
26 changed files with 9 additions and 89 deletions

View File

@@ -2047,12 +2047,13 @@ public class VoxelEditorState extends BaseAppState {
// Rand hin auslaufende Rampe über die vollen RADIUS Meter, statt eines
// abrupten Sprungs zwischen "geramped" und "unverändert flach".
float smoothH;
if (hUp == null) {
smoothH = h0; // Plateau
} else if (hDown == null) {
// Kein niedrigerer Voxel-Nachbar: obere Rampe zum Rand hin auslaufen lassen.
float dDown = RADIUS - 1;
smoothH = (h0 * dUp + hUp * dDown) / (dUp + dDown);
if (hUp == null || hDown == null) {
// Plateau (kein höherer Nachbar) ODER unterste/äußerste Ebene
// (kein niedrigerer Voxel-Nachbar): Höhe unverändert lassen.
// Die Formel darf hier NICHT angewendet werden sie würde die
// unterste Terrasse künstlich in Richtung hUp anheben und das
// gebackene Terrain systematisch zu hoch machen.
smoothH = h0;
} else {
float dDown = dDownRaw - 1;
smoothH = (dDown <= 0f) ? h0 : (h0 * dUp + hUp * dDown) / (dUp + dDown);
@@ -2094,89 +2095,8 @@ public class VoxelEditorState extends BaseAppState {
// nicht mehr exakt dem Rampen-Winkel, ist aber garantiert monoton/glatt.
int[][] DIRS8 = {{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
// Kandidaten sammeln: alle leeren Zellen innerhalb RADIUS einer Rand-Spalte.
java.util.Set<Long> candidates = new java.util.HashSet<>();
for (long hk0 : hfMap.keySet()) {
int colZ = (int)(hk0 % 60001L) - 30000;
int colX = (int)(hk0 / 60001L) - 30000;
for (int dz = -RADIUS; dz <= RADIUS; dz++) {
for (int dx = -RADIUS; dx <= RADIUS; dx++) {
if (Math.max(Math.abs(dx), Math.abs(dz)) > RADIUS) continue;
long hkC = (long)(colX + dx + 30000) * 60001L + (colZ + dz + 30000);
if (!hfMap.containsKey(hkC)) candidates.add(hkC);
}
}
}
Map<Long, Float> extensionMap = new HashMap<>();
int extCount = 0, extLogged = 0;
for (long hkC : candidates) {
int colZ = (int)(hkC % 60001L) - 30000;
int colX = (int)(hkC / 60001L) - 30000;
// Nächsten Ring mit Struktur-Zellen isotrop suchen (gleiches Vorgehen wie
// Schritt 2), dann ALLE Struktur-Zellen in diesem Ring mitteln nicht nur die
// erste gefundene. Grund (Log-Befund): benachbarte Zielzellen fanden oft
// unterschiedliche einzelne "nächste" Zellen mit stark abweichender Höhe
// (edgeH schwankte 3,9 bis 5,33 nur 4 Zellen auseinander) → wildes Springen.
// Mittelung über den ganzen Ring glättet das.
int nearestDist = -1;
java.util.List<long[]> ringHits = new java.util.ArrayList<>(); // {colX,colZ}
outer:
for (int r = 1; r <= RADIUS; r++) {
for (int dz = -r; dz <= r; dz++) {
for (int dx = -r; dx <= r; dx++) {
if (Math.max(Math.abs(dx), Math.abs(dz)) != r) continue;
long hkN = (long)(colX + dx + 30000) * 60001L + (colZ + dz + 30000);
if (hfMap.containsKey(hkN)) ringHits.add(new long[]{colX + dx, colZ + dz});
}
}
if (!ringHits.isEmpty()) { nearestDist = r; break outer; }
}
if (nearestDist < 0) continue; // außerhalb der Reichweite, bleibt Klippe
float sumEdgeH = 0f; int hitCnt = 0;
for (long[] hit : ringHits) {
int hColX = (int) hit[0], hColZ = (int) hit[1];
long hKey = (long)(hColX + 30000) * 60001L + (hColZ + 30000);
Float hH = smoothMap.get(hKey);
if (hH == null) continue;
sumEdgeH += hH; hitCnt++;
}
if (hitCnt == 0) continue;
float edgeH = sumEdgeH / hitCnt;
// KEINE Steigungs-Extrapolation mehr (v4/v5 hatten das versucht eine an nur
// wenigen Pixeln gemessene Steigung ist zu verrauscht, verstärkt sich über die
// Distanz und erzeugte ein welliges/oszillierendes Band über eigentlich flachen
// Flächen, siehe Screenshot 22-43-57). Reiner, robuster Distanz-Blend von der
// (gemittelten) Kanten-Höhe zur tatsächlichen Basisterrain-Höhe: nah am Rand
// dominiert die Kante, weiter draußen die Terrainhöhe. Folgt nicht mehr exakt
// dem Winkel der letzten Rampe, ist aber garantiert monoton und ohne Rauschen.
float wx = colX - 2048f, wz = colZ - 2048f;
float th = terrainH(wx, wz);
float finalH = edgeH;
if (Float.isFinite(th)) {
float t = nearestDist / (float) RADIUS; // 0 am Rand, 1 bei RADIUS
finalH = edgeH * (1f - t) + th * t;
}
extensionMap.put(hkC, finalH);
extCount++;
if (extLogged < 20) {
log.info("Perimeter-Rampe: colX={} colZ={} dist={} edgeH={} th={} finalH={}",
colX, colZ, nearestDist, edgeH, th, finalH);
extLogged++;
}
}
log.info("Perimeter-Übergang: {} Erweiterungs-Spalten berechnet (aktuell deaktiviert saubere Kante).", extCount);
// Erweiterungs-Spalten DEAKTIVIERT: liefert saubere Kante an der Voxel-Grenze
// statt der problematischen flachen Rampe. Zum Reaktivieren diesen Block einkommentieren:
/* for (Map.Entry<Long, Float> e : extensionMap.entrySet()) {
long hk = e.getKey();
if (hfMap.containsKey(hk)) continue;
hfMap.put(hk, e.getValue());
smoothMap.put(hk, e.getValue());
} */
// Perimeter-Extension deaktiviert saubere Kante an der Voxel-Grenze.
// (Berechnung auskommentiert, Code bleibt für spätere Nutzung erhalten.)
// ── Schritt 3: Dichte anpassen ────────────────────────────────────
// ALLE Spalten aus hfMap bekommen den Dichte-Gradienten geschrieben, auch