Anpassung der KArte
This commit is contained in:
@@ -1223,22 +1223,22 @@ public final class WorldMapRenderer {
|
||||
float[] voxelSurface, List<PlacedWater> waters) {
|
||||
final int SIZE = COLOR_MAP_SIZE;
|
||||
final int SS = MapData.SPLAT_SIZE;
|
||||
float[] heights = buildTerrainSamples(m, SIZE, voxelSurface);
|
||||
float[] waterH = buildWaterHeightMap(waters, SIZE);
|
||||
int[] tileAvg = computeTileAvgColors(tilePixels);
|
||||
int[] slotTypes = computeSlotTileTypes(m, slotColors);
|
||||
float cellW = WORLD_SIZE / (SIZE - 1);
|
||||
int[] result = new int[SIZE * SIZE];
|
||||
float[] heights = buildTerrainSamples(m, SIZE, voxelSurface);
|
||||
float[] waterH = buildWaterHeightMap(waters, SIZE);
|
||||
int[] tileAvg = computeTileAvgColors(tilePixels);
|
||||
int[] slotTypes = computeSlotTileTypes(m, slotColors);
|
||||
float cellW = WORLD_SIZE / (SIZE - 1);
|
||||
int[] terrainRGB = new int[SIZE * SIZE];
|
||||
float[] cliffMask = new float[SIZE * SIZE];
|
||||
for (int py = 0; py < SIZE; py++) {
|
||||
float wz = -WORLD_HALF + py * cellW;
|
||||
for (int px = 0; px < SIZE; px++) {
|
||||
float wx = -WORLD_HALF + px * cellW;
|
||||
int idx = py * SIZE + px;
|
||||
float h = heights[idx];
|
||||
int rgb;
|
||||
if (h < 0f || (waterH[idx] > 0f && waterH[idx] > h)) {
|
||||
int[] wc = TILE_FALLBACK_RGB[TILE_WATER];
|
||||
rgb = (wc[0]<<16)|(wc[1]<<8)|wc[2];
|
||||
terrainRGB[idx] = (wc[0]<<16)|(wc[1]<<8)|wc[2];
|
||||
} else {
|
||||
int dPx = Math.max(1, (int)(1.5f / cellW));
|
||||
float hR = heights[py * SIZE + Math.min(SIZE-1, px+dPx)];
|
||||
@@ -1248,15 +1248,24 @@ public final class WorldMapRenderer {
|
||||
float dist = dPx * cellW;
|
||||
double slope = Math.toDegrees(Math.atan(Math.sqrt(
|
||||
Math.pow((hR-hL)/(2*dist),2) + Math.pow((hD-hU)/(2*dist),2))));
|
||||
if (slope > 30.0) {
|
||||
rgb = tileAvg[Math.min(TILE_CLIFF, tileAvg.length-1)];
|
||||
} else {
|
||||
rgb = blendTileAvgColors(m, SS, wx, wz, tileAvg, slotTypes);
|
||||
}
|
||||
cliffMask[idx] = (slope > 30.0) ? 1f : 0f;
|
||||
terrainRGB[idx] = blendTileAvgColors(m, SS, wx, wz, tileAvg, slotTypes);
|
||||
}
|
||||
result[idx] = rgb;
|
||||
}
|
||||
}
|
||||
// Cliff-Maske weichzeichnen → weiche Klippen-Kanten ohne Änderung der Schwellwert-Logik
|
||||
float[] softMask = boxBlurFloat(cliffMask, SIZE, 3);
|
||||
int cliffRgb = tileAvg[Math.min(TILE_CLIFF, tileAvg.length-1)];
|
||||
int cr = (cliffRgb>>16)&0xFF, cg = (cliffRgb>>8)&0xFF, cb = cliffRgb&0xFF;
|
||||
int[] result = new int[SIZE * SIZE];
|
||||
for (int i = 0; i < SIZE * SIZE; i++) {
|
||||
float t = softMask[i];
|
||||
int tc = terrainRGB[i];
|
||||
int r = (tc>>16)&0xFF, g = (tc>>8)&0xFF, b = tc&0xFF;
|
||||
result[i] = (clamp((int)(r + (cr-r)*t)) << 16)
|
||||
| (clamp((int)(g + (cg-g)*t)) << 8)
|
||||
| clamp((int)(b + (cb-b)*t));
|
||||
}
|
||||
return boxBlur(result, SIZE, 2);
|
||||
}
|
||||
|
||||
@@ -1295,38 +1304,67 @@ public final class WorldMapRenderer {
|
||||
float cellW = WORLD_SIZE / (SIZE - 1);
|
||||
int written = 0;
|
||||
|
||||
final int CLIFF_BLUR_R = 4; // Blur-Radius für weiche Klippen-Kanten
|
||||
final int EXT = CLIFF_BLUR_R;
|
||||
final int EXTW = CS + 2 * EXT; // erweitertes Fenster inkl. Rand für nahtlosen Blur
|
||||
int dPxHires = Math.max(1, (int)(1.5f / cellW));
|
||||
|
||||
for (int cy = 0; cy < COLS; cy++) {
|
||||
for (int cx = 0; cx < COLS; cx++) {
|
||||
java.nio.file.Path p = chunkPath(cacheDir, cx, cy);
|
||||
if (!forceRegen && Files.exists(p)) continue;
|
||||
// Chunk-Pixel berechnen
|
||||
|
||||
// Erweiterte Cliff-Maske + Terrain-Farben (mit Rand über Chunk-Grenze)
|
||||
float[] cliffMaskExt = new float[EXTW * EXTW];
|
||||
boolean[] isWaterExt = new boolean[EXTW * EXTW];
|
||||
int[] terrainColExt = new int[EXTW * EXTW];
|
||||
for (int ely = 0; ely < EXTW; ely++) {
|
||||
int gy = cy * CS + ely - EXT;
|
||||
int gyC = Math.max(0, Math.min(SIZE-1, gy));
|
||||
float wz = -WORLD_HALF + gyC * cellW;
|
||||
for (int elx = 0; elx < EXTW; elx++) {
|
||||
int gx = cx * CS + elx - EXT;
|
||||
int gxC = Math.max(0, Math.min(SIZE-1, gx));
|
||||
float wx = -WORLD_HALF + gxC * cellW;
|
||||
int eidx = ely * EXTW + elx;
|
||||
int hidx = gyC * SIZE + gxC;
|
||||
float h = heights[hidx];
|
||||
if (h < 0f || (waterH[hidx] > 0f && waterH[hidx] > h)) {
|
||||
isWaterExt[eidx] = true;
|
||||
} else {
|
||||
float hR = heights[gyC * SIZE + Math.min(SIZE-1, gxC+dPxHires)];
|
||||
float hL = heights[gyC * SIZE + Math.max(0, gxC-dPxHires)];
|
||||
float hD = heights[Math.min(SIZE-1, gyC+dPxHires) * SIZE + gxC];
|
||||
float hU = heights[Math.max(0, gyC-dPxHires) * SIZE + gxC];
|
||||
float dist = dPxHires * cellW;
|
||||
double slope = Math.toDegrees(Math.atan(Math.sqrt(
|
||||
Math.pow((hR-hL)/(2*dist),2) + Math.pow((hD-hU)/(2*dist),2))));
|
||||
cliffMaskExt[eidx] = (slope > 30.0) ? 1f : 0f;
|
||||
terrainColExt[eidx] = blendTileAvgColors(m, SS, wx, wz, tileAvg, slotTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
float[] softMaskExt = boxBlurFloat(cliffMaskExt, EXTW, CLIFF_BLUR_R);
|
||||
int cliffRgb = tileAvg[Math.min(TILE_CLIFF, tileAvg.length-1)];
|
||||
int cr = (cliffRgb>>16)&0xFF, cg = (cliffRgb>>8)&0xFF, cb = cliffRgb&0xFF;
|
||||
|
||||
// Chunk-Pixel aus dem inneren Bereich der erweiterten Maske zusammensetzen
|
||||
int[] chunk = new int[CS * CS];
|
||||
for (int ly = 0; ly < CS; ly++) {
|
||||
int gy = cy * CS + ly; // globaler Y-Index in der HIRES-Karte
|
||||
float wz = -WORLD_HALF + gy * cellW;
|
||||
for (int lx = 0; lx < CS; lx++) {
|
||||
int gx = cx * CS + lx;
|
||||
float wx = -WORLD_HALF + gx * cellW;
|
||||
int idx = gy * SIZE + gx;
|
||||
float h = heights[idx];
|
||||
int extIdx = (ly + EXT) * EXTW + (lx + EXT);
|
||||
int tr, tg, tb;
|
||||
if (h < 0f || (waterH[idx] > 0f && waterH[idx] > h)) {
|
||||
if (isWaterExt[extIdx]) {
|
||||
tr = (WATER_COLOR >> 16) & 0xFF;
|
||||
tg = (WATER_COLOR >> 8) & 0xFF;
|
||||
tb = WATER_COLOR & 0xFF;
|
||||
} else {
|
||||
int dPx = Math.max(1, (int)(1.5f / cellW));
|
||||
float hR = heights[gy * SIZE + Math.min(SIZE-1, gx+dPx)];
|
||||
float hL = heights[gy * SIZE + Math.max(0, gx-dPx)];
|
||||
float hD = heights[Math.min(SIZE-1, gy+dPx) * SIZE + gx];
|
||||
float hU = heights[Math.max(0, gy-dPx) * SIZE + gx];
|
||||
float dist = dPx * cellW;
|
||||
double slope = Math.toDegrees(Math.atan(Math.sqrt(
|
||||
Math.pow((hR-hL)/(2*dist),2) + Math.pow((hD-hU)/(2*dist),2))));
|
||||
int rgb = (slope > 30.0)
|
||||
? tileAvg[Math.min(TILE_CLIFF, tileAvg.length-1)]
|
||||
: blendTileAvgColors(m, SS, wx, wz, tileAvg, slotTypes);
|
||||
tr = (rgb>>16)&0xFF; tg = (rgb>>8)&0xFF; tb = rgb&0xFF;
|
||||
float t = softMaskExt[extIdx];
|
||||
int tc = terrainColExt[extIdx];
|
||||
int r2 = (tc>>16)&0xFF, g2 = (tc>>8)&0xFF, b2 = tc&0xFF;
|
||||
tr = clamp((int)(r2 + (cr-r2)*t));
|
||||
tg = clamp((int)(g2 + (cg-g2)*t));
|
||||
tb = clamp((int)(b2 + (cb-b2)*t));
|
||||
}
|
||||
chunk[ly * CS + lx] = (0xFF << 24) | (tr << 16) | (tg << 8) | tb;
|
||||
}
|
||||
@@ -1360,6 +1398,32 @@ public final class WorldMapRenderer {
|
||||
return dir.resolve(String.format("chunk_%02x_%02x.png", cx, cy));
|
||||
}
|
||||
|
||||
/** Separabler Box-Blur auf float-Array (horizontal + vertikal), Radius in Pixeln. */
|
||||
private static float[] boxBlurFloat(float[] src, int size, int radius) {
|
||||
float[] tmp = new float[size * size];
|
||||
float[] dst = new float[size * size];
|
||||
float inv = 1f / (radius * 2 + 1);
|
||||
for (int py = 0; py < size; py++) {
|
||||
for (int px = 0; px < size; px++) {
|
||||
float sum = 0;
|
||||
for (int dx = -radius; dx <= radius; dx++) {
|
||||
sum += src[py * size + Math.max(0, Math.min(size-1, px+dx))];
|
||||
}
|
||||
tmp[py * size + px] = sum * inv;
|
||||
}
|
||||
}
|
||||
for (int py = 0; py < size; py++) {
|
||||
for (int px = 0; px < size; px++) {
|
||||
float sum = 0;
|
||||
for (int dz = -radius; dz <= radius; dz++) {
|
||||
sum += tmp[Math.max(0, Math.min(size-1, py+dz)) * size + px];
|
||||
}
|
||||
dst[py * size + px] = sum * inv;
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
/** Separabler Box-Blur (horizontal + vertikal), Radius in Pixeln. */
|
||||
private static int[] boxBlur(int[] src, int size, int radius) {
|
||||
int[] tmp = new int[size * size];
|
||||
|
||||
Reference in New Issue
Block a user