From dc417a1f1a8b0f1ed47f2a2ae4957497384418d7 Mon Sep 17 00:00:00 2001 From: como Date: Thu, 26 Mar 2026 10:17:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=A9=E5=A4=A7=E9=99=86=E5=9C=B0=E9=9D=A2?= =?UTF-8?q?=E7=A7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/OceanScene.js | 19 +++++++++++----- src/TerrainGenerator.js | 48 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/OceanScene.js b/src/OceanScene.js index 940a1fe..3af48b1 100644 --- a/src/OceanScene.js +++ b/src/OceanScene.js @@ -280,11 +280,20 @@ export class OceanScene { async initTerrain() { const terrainGen = new TerrainGenerator({ - size: 1200, - segments: 200, - maxHeight: 30, - waterLevel: 0, - seed: 42 + size: 1200, // 地形平面尺寸 + segments: 200, // 网格细分数,越高细节越多 + maxHeight: 34, // 海面以上地形的最大起伏高度 + waterLevel: 0, // 海平面基准高度 + underwaterDepthBias: 4.5, // 整体压低海面以下地形,避免浅滩露出 + landBias: 0.2, // 整体抬升陆地倾向,增大陆地露出面积 + falloffStartRatio: 0.22, // 从中心向外开始下沉的起始比例 + maxLandRatio: 0.46, // 大陆海岸线的大致外缘比例 + edgeDepth: 12, // 海岸外侧向海底下沉的强度 + coreRadiusRatio: 0.24, // 大陆核心高地区域半径比例 + continentLift: 0.55, // 核心大陆的额外抬升强度 + coastVariance: 0.05, // 海岸线形状起伏幅度,越大越不规则 + outerShelfDepth: 4, // 大陆外侧陆架的额外下沉深度 + seed: 42 // 固定随机种子,保证地形稳定复现 }); this.terrain = terrainGen.generate(); diff --git a/src/TerrainGenerator.js b/src/TerrainGenerator.js index b77288c..9681952 100644 --- a/src/TerrainGenerator.js +++ b/src/TerrainGenerator.js @@ -10,6 +10,15 @@ export class TerrainGenerator { this.beachWidth = options.beachWidth || 20; this.shoreWidth = options.shoreWidth || 3.5; this.shoreDepth = options.shoreDepth || 1.5; + this.underwaterDepthBias = options.underwaterDepthBias || 3.5; + this.landBias = options.landBias ?? 0.18; + this.falloffStartRatio = options.falloffStartRatio || 0.24; + this.maxLandRatio = options.maxLandRatio || 0.48; + this.edgeDepth = options.edgeDepth || 10; + this.coreRadiusRatio = options.coreRadiusRatio || 0.2; + this.continentLift = options.continentLift || 0.35; + this.coastVariance = options.coastVariance || 0.08; + this.outerShelfDepth = options.outerShelfDepth || 2.5; this.noise = new SimplexNoise(options.seed || 42); this.terrain = null; @@ -65,19 +74,44 @@ export class TerrainGenerator { height += detail; const distFromCenter = Math.sqrt(x * x + y * y); - const maxLandDist = this.size * 0.45; - const falloffStart = this.size * 0.2; + const angle = Math.atan2(y, x); + const coastNoise = this.noise.fbm( + Math.cos(angle) * 1.7 + 11.3, + Math.sin(angle) * 1.7 - 4.8, + 3, + 2.0, + 0.5 + ); + const coastlineRadius = this.size * this.maxLandRatio * (1 + coastNoise * this.coastVariance); + const falloffStart = coastlineRadius * (this.falloffStartRatio / this.maxLandRatio); + const coreRadius = this.size * this.coreRadiusRatio; + + let continentLift = 1.0; + if (distFromCenter < coreRadius) { + const t = distFromCenter / coreRadius; + continentLift += (1 - t * t) * this.continentLift; + } let continentMask = 1.0; let edgeDepth = 0; if (distFromCenter > falloffStart) { - const t = (distFromCenter - falloffStart) / (maxLandDist - falloffStart); + const t = (distFromCenter - falloffStart) / Math.max(0.0001, coastlineRadius - falloffStart); continentMask = Math.max(0, 1 - Math.pow(t, 1.2)); - edgeDepth = -15 * Math.pow(Math.max(0, t), 2); + edgeDepth = -this.edgeDepth * Math.pow(Math.max(0, t), 2); } - height = height * continentMask + edgeDepth; + height = ((height * continentLift) + this.landBias) * continentMask + edgeDepth; height = height * this.maxHeight * 0.5; + + if (distFromCenter > coastlineRadius) { + const t = THREE.MathUtils.clamp( + (distFromCenter - coastlineRadius) / (this.size * 0.08), + 0, + 1 + ); + const forcedSeaFloor = this.waterLevel - this.outerShelfDepth * Math.pow(t, 1.1); + height = Math.min(height, forcedSeaFloor); + } const shoreMin = this.waterLevel - this.shoreWidth; const shoreMax = this.waterLevel + this.shoreWidth; @@ -91,6 +125,10 @@ export class TerrainGenerator { } } + if (height < this.waterLevel) { + height -= this.underwaterDepthBias; + } + if (Math.abs(height - this.waterLevel) < 0.06) { height = this.waterLevel - 0.06; }