town tweak
This commit is contained in:
parent
84ad22f7af
commit
1ea8ba1701
12 changed files with 5005 additions and 379 deletions
79
renderer.js
79
renderer.js
|
|
@ -358,42 +358,45 @@ function terrainColorContinuous(map, fx, fy, mode) {
|
|||
}
|
||||
|
||||
function terrainShadeContinuous(map, fx, fy) {
|
||||
const eL = fieldSample(map.elevation, fx - 0.6, fy);
|
||||
const eR = fieldSample(map.elevation, fx + 0.6, fy);
|
||||
const eU = fieldSample(map.elevation, fx, fy - 0.6);
|
||||
const eD = fieldSample(map.elevation, fx, fy + 0.6);
|
||||
const step = 0.50;
|
||||
const eC = fieldSample(map.elevation, fx, fy);
|
||||
const eL = fieldSample(map.elevation, fx - step, fy);
|
||||
const eR = fieldSample(map.elevation, fx + step, fy);
|
||||
const eU = fieldSample(map.elevation, fx, fy - step);
|
||||
const eD = fieldSample(map.elevation, fx, fy + step);
|
||||
|
||||
// x は東向き, y は南向き。法線は (-dz/dx, -dz/dy, 1)。
|
||||
// 光源は北西上空(日本の地形表現で一般的な見え方)。
|
||||
const dzdx = (eR - eL) / 1.2;
|
||||
const dzdy = (eD - eU) / 1.2;
|
||||
const nx = -dzdx * 2.5;
|
||||
const ny = -dzdy * 2.5;
|
||||
// 描画では地形生成上の差分をやや誇張し、粗いDEMでも山腹の起伏を読ませる。
|
||||
const dzdx = (eR - eL) / (step * 2);
|
||||
const dzdy = (eD - eU) / (step * 2);
|
||||
const nx = -dzdx * 4.4;
|
||||
const ny = -dzdy * 4.4;
|
||||
const nz = 1.0;
|
||||
const nLen = Math.hypot(nx, ny, nz) || 1;
|
||||
|
||||
const lx = -0.5;
|
||||
const ly = -0.5;
|
||||
const lz = 0.7071067811865476;
|
||||
const hill = clamp((nx * lx + ny * ly + nz * lz) / nLen * 0.5 + 0.5);
|
||||
const hill = clamp((nx * lx + ny * ly + nz * lz) / nLen * 0.58 + 0.48);
|
||||
|
||||
const slope = map.slope ? fieldSample(map.slope, fx, fy) : 0;
|
||||
const valley = map.valleyField ? fieldSample(map.valleyField, fx, fy) : 0;
|
||||
const ravine = map.visibleRavineField ? fieldSample(map.visibleRavineField, fx, fy) : 0;
|
||||
const tex = map.surfaceTextureField ? fieldSample(map.surfaceTextureField, fx, fy) : 0;
|
||||
const rvL = map.visibleRavineField ? fieldSample(map.visibleRavineField, fx - 0.75, fy) : 0;
|
||||
const rvR = map.visibleRavineField ? fieldSample(map.visibleRavineField, fx + 0.75, fy) : 0;
|
||||
const rvU = map.visibleRavineField ? fieldSample(map.visibleRavineField, fx, fy - 0.75) : 0;
|
||||
const rvD = map.visibleRavineField ? fieldSample(map.visibleRavineField, fx, fy + 0.75) : 0;
|
||||
const ravineRelief = (rvL - rvR) * 0.16 + (rvU - rvD) * 0.12;
|
||||
const rvL = map.visibleRavineField ? fieldSample(map.visibleRavineField, fx - 0.90, fy) : 0;
|
||||
const rvR = map.visibleRavineField ? fieldSample(map.visibleRavineField, fx + 0.90, fy) : 0;
|
||||
const rvU = map.visibleRavineField ? fieldSample(map.visibleRavineField, fx, fy - 0.90) : 0;
|
||||
const rvD = map.visibleRavineField ? fieldSample(map.visibleRavineField, fx, fy + 0.90) : 0;
|
||||
const ravineRelief = (rvL - rvR) * 0.26 + (rvU - rvD) * 0.20;
|
||||
const concavity = clamp(((eL + eR + eU + eD) * 0.25 - eC) * 9.0, -0.18, 0.18);
|
||||
|
||||
// 谷底の低傾斜面では陰影を少し圧縮し、標高色がそのまま見えるようにする。
|
||||
const valleyFloor = clamp((valley - 0.16) * 1.8) * clamp((0.28 - slope) * 4.5);
|
||||
let shade = 0.76 + hill * 0.32 + ravineRelief - ravine * 0.08 - tex * 0.028;
|
||||
if (shade < 1) shade = 1 - (1 - shade) * (1 - valleyFloor * 0.52);
|
||||
else shade = 1 + (shade - 1) * (1 - valleyFloor * 0.20);
|
||||
// 谷底の色保持は少し残すが、以前より圧縮を弱めて陰影の振幅を大きくする。
|
||||
const valleyFloor = clamp((valley - 0.18) * 1.45) * clamp((0.24 - slope) * 3.6);
|
||||
let shade = 0.66 + hill * 0.50 + ravineRelief - ravine * 0.12 - tex * 0.042 - concavity * 0.16 + slope * 0.030;
|
||||
if (shade < 1) shade = 1 - (1 - shade) * (1 - valleyFloor * 0.26);
|
||||
else shade = 1 + (shade - 1) * (1 - valleyFloor * 0.12);
|
||||
|
||||
return clamp(shade, 0.66, 1.13);
|
||||
return clamp(shade, 0.54, 1.26);
|
||||
}
|
||||
|
||||
function discreteColor(map, x, y, mode) {
|
||||
|
|
@ -404,16 +407,16 @@ function discreteColor(map, x, y, mode) {
|
|||
color = [160, 205, 239];
|
||||
} else if (mode === "landuse") {
|
||||
const colors = {
|
||||
0: [242, 248, 238],
|
||||
1: [248, 250, 245],
|
||||
2: [240, 238, 232],
|
||||
3: [245, 230, 220],
|
||||
4: [250, 248, 245],
|
||||
5: [235, 235, 240],
|
||||
6: [240, 245, 240],
|
||||
7: [245, 248, 252],
|
||||
8: [250, 248, 240],
|
||||
9: [240, 245, 238],
|
||||
0: [242, 248, 238], // rural / natural land
|
||||
1: [238, 246, 222], // farmland
|
||||
2: [240, 238, 232], // old urban
|
||||
3: [245, 230, 220], // CBD / DID core
|
||||
4: [250, 248, 245], // suburb
|
||||
5: [235, 235, 240], // industrial
|
||||
6: [240, 245, 240], // logistics
|
||||
7: [245, 248, 252], // new town
|
||||
8: [250, 248, 240], // roadside
|
||||
9: [225, 238, 220], // forest / mountain land
|
||||
};
|
||||
color = colors[map.landuse[i]] || colors[0];
|
||||
} else if (mode === "admin") {
|
||||
|
|
@ -606,7 +609,8 @@ function drawDebugCells(ctx, map, field, color) {
|
|||
for (let y = 0; y < MAP_H; y++) {
|
||||
for (let x = 0; x < MAP_W; x++) {
|
||||
const i = indexOf(x, y);
|
||||
if (!map.prefectureMask[i] || map.sea[i]) continue;
|
||||
const debugMask = map.humanRegionMask || map.prefectureMask;
|
||||
if (!debugMask[i] || map.sea[i]) continue;
|
||||
const v = clamp(field[i] || 0, 0, 1);
|
||||
if (v <= 0.12) continue;
|
||||
ctx.fillStyle = color(v);
|
||||
|
|
@ -756,8 +760,10 @@ export function drawMap(canvas, map, options) {
|
|||
drawVectorSegments(ctx, map.adminBorders, "rgba(150, 140, 150, 0.9)", 1.2, true, { iterations: 1, tolerance: 0.05, offsetX: -0.5, offsetY: -0.5 });
|
||||
}
|
||||
if (mode === "admin-debug" || mode === "borders-debug") {
|
||||
drawDebugCells(ctx, map, map.naturalBarrierScore, (v) => `rgba(255, 120, 40, ${0.06 + v * 0.18})`);
|
||||
if (map.adminDebug?.compartmentBorders) drawSegments(ctx, map.adminDebug.compartmentBorders, "rgba(60, 110, 170, 0.42)", 0.8, true);
|
||||
// Keep the natural barrier heatmap subtle. A dense cell fill can look like
|
||||
// artificial horizontal hatching, so only strong terrain dividers are shown.
|
||||
drawDebugCells(ctx, map, map.naturalBarrierScore, (v) => v < 0.42 ? "rgba(0,0,0,0)" : `rgba(255, 120, 40, ${0.025 + v * 0.075})`);
|
||||
if (map.adminDebug?.compartmentBorders) drawSegments(ctx, map.adminDebug.compartmentBorders, "rgba(45, 95, 160, 0.72)", 1.0, true);
|
||||
for (const p of map.adminDebug?.lowlandAdminSeeds || []) dot(ctx, p, 3.2, "rgba(255,255,255,0.9)", "rgba(40,150,95,0.95)");
|
||||
if (map.regionalPrefectureBorders) drawVectorSegments(ctx, map.regionalPrefectureBorders, "rgba(70, 55, 95, 0.95)", 2.4, false, { iterations: 2, tolerance: 0.06, offsetX: -0.5, offsetY: -0.5 });
|
||||
}
|
||||
|
|
@ -818,6 +824,7 @@ export function drawMap(canvas, map, options) {
|
|||
const popRadius = p.population ? Math.min(8.5, 3.5 + Math.sqrt(p.population) / 400) : 4.5;
|
||||
dot(ctx, p, popRadius, "rgba(240, 110, 110, 0.95)", "rgba(255,255,255,0.9)");
|
||||
if (p.isPrefecturalCapital) dot(ctx, p, popRadius + 3.0, "transparent", "rgba(200,80,80,0.9)");
|
||||
else if (p.isRegionalCapital) dot(ctx, p, popRadius + 2.2, "transparent", "rgba(190,95,95,0.62)");
|
||||
}
|
||||
for (const p of map.interchanges || []) dot(ctx, p, 2.7, "rgba(250, 250, 245, 0.95)", "rgba(95, 125, 95, 0.95)");
|
||||
if (mode === "admin-debug" || mode === "borders-debug") {
|
||||
|
|
@ -832,14 +839,14 @@ export function drawMap(canvas, map, options) {
|
|||
return;
|
||||
}
|
||||
if (mode === "admin-debug" || mode === "borders-debug") {
|
||||
drawLabels(ctx, [...(map.adminCenters || []), ...(map.externalGateways || [])], Infinity);
|
||||
drawLabels(ctx, map.adminCenters || [], Infinity);
|
||||
return;
|
||||
}
|
||||
const important = [
|
||||
...map.modernCities,
|
||||
...map.ports,
|
||||
...(map.satelliteCities || []),
|
||||
].filter((p) => p.insidePrefecture || p.kind === "External Gateway");
|
||||
].filter((p) => p.insidePrefecture || p.isRegionalCapital || p.kind === "External Gateway");
|
||||
drawLabels(ctx, important, 60);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue