预设
This commit is contained in:
@@ -9,6 +9,7 @@ import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
|
|||||||
import Stats from 'three/addons/libs/stats.module.js';
|
import Stats from 'three/addons/libs/stats.module.js';
|
||||||
import { TerrainGenerator } from './TerrainGenerator.js';
|
import { TerrainGenerator } from './TerrainGenerator.js';
|
||||||
import { VegetationSystem } from './VegetationSystem.js';
|
import { VegetationSystem } from './VegetationSystem.js';
|
||||||
|
import { DEFAULT_SCENE_PARAMS } from './weatherPresets.js';
|
||||||
|
|
||||||
const RAIN_AUDIO_URL = '/audio/rain-calming.mp3';
|
const RAIN_AUDIO_URL = '/audio/rain-calming.mp3';
|
||||||
const THUNDER_AUDIO_URL = '/audio/thunder-distant.mp3';
|
const THUNDER_AUDIO_URL = '/audio/thunder-distant.mp3';
|
||||||
@@ -53,36 +54,7 @@ export class OceanScene {
|
|||||||
this.thunderAudioIndex = 0;
|
this.thunderAudioIndex = 0;
|
||||||
this.scheduledThunder = [];
|
this.scheduledThunder = [];
|
||||||
|
|
||||||
this.params = {
|
this.params = { ...DEFAULT_SCENE_PARAMS };
|
||||||
elevation: 2,
|
|
||||||
azimuth: 180,
|
|
||||||
exposure: 0.1,
|
|
||||||
turbidity: 10,
|
|
||||||
rayleigh: 2,
|
|
||||||
bloomStrength: 0.1,
|
|
||||||
bloomRadius: 0,
|
|
||||||
bloomThreshold: 0,
|
|
||||||
cloudCoverage: 0.4,
|
|
||||||
cloudDensity: 0.5,
|
|
||||||
cloudElevation: 0.5,
|
|
||||||
fogDensity: 0.42,
|
|
||||||
fogHeight: 0.32,
|
|
||||||
fogRange: 0.55,
|
|
||||||
rainEnabled: false,
|
|
||||||
rainScreenIntensity: 0.41,
|
|
||||||
rainVeilIntensity: 1.15,
|
|
||||||
rainDropSize: 1.0,
|
|
||||||
rainSpeed: 1.0,
|
|
||||||
rainAudioEnabled: true,
|
|
||||||
rainAudioVolume: 0.35,
|
|
||||||
snowEnabled: false,
|
|
||||||
snowIntensity: 0.65,
|
|
||||||
snowSpeed: 0.85,
|
|
||||||
lightningEnabled: true,
|
|
||||||
lightningIntensity: 0.75,
|
|
||||||
mieCoefficient: 0.005,
|
|
||||||
mieDirectionalG: 0.8
|
|
||||||
};
|
|
||||||
|
|
||||||
this.clock = new THREE.Clock();
|
this.clock = new THREE.Clock();
|
||||||
this.lightningFlash = 0;
|
this.lightningFlash = 0;
|
||||||
@@ -1321,6 +1293,36 @@ export class OceanScene {
|
|||||||
this.params.lightningIntensity = value;
|
this.params.lightningIntensity = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyParams(nextParams = {}) {
|
||||||
|
const mergedParams = { ...DEFAULT_SCENE_PARAMS, ...nextParams };
|
||||||
|
|
||||||
|
this.setSunElevation(mergedParams.elevation);
|
||||||
|
this.setSunAzimuth(mergedParams.azimuth);
|
||||||
|
this.setExposure(mergedParams.exposure);
|
||||||
|
this.setTurbidity(mergedParams.turbidity);
|
||||||
|
this.setRayleigh(mergedParams.rayleigh);
|
||||||
|
this.setBloomStrength(mergedParams.bloomStrength);
|
||||||
|
this.setBloomRadius(mergedParams.bloomRadius);
|
||||||
|
this.setCloudCoverage(mergedParams.cloudCoverage);
|
||||||
|
this.setCloudDensity(mergedParams.cloudDensity);
|
||||||
|
this.setCloudElevation(mergedParams.cloudElevation);
|
||||||
|
this.setFogDensity(mergedParams.fogDensity);
|
||||||
|
this.setFogHeight(mergedParams.fogHeight);
|
||||||
|
this.setFogRange(mergedParams.fogRange);
|
||||||
|
this.setRainScreenIntensity(mergedParams.rainScreenIntensity);
|
||||||
|
this.setRainVeilIntensity(mergedParams.rainVeilIntensity);
|
||||||
|
this.setRainDropSize(mergedParams.rainDropSize);
|
||||||
|
this.setRainSpeed(mergedParams.rainSpeed);
|
||||||
|
this.setRainAudioVolume(mergedParams.rainAudioVolume);
|
||||||
|
this.setRainAudioEnabled(mergedParams.rainAudioEnabled);
|
||||||
|
this.setSnowIntensity(mergedParams.snowIntensity);
|
||||||
|
this.setSnowSpeed(mergedParams.snowSpeed);
|
||||||
|
this.setSnowEnabled(mergedParams.snowEnabled);
|
||||||
|
this.setLightningIntensity(mergedParams.lightningIntensity);
|
||||||
|
this.setLightningEnabled(mergedParams.lightningEnabled);
|
||||||
|
this.setRainEnabled(mergedParams.rainEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
scheduleNextLightning(time) {
|
scheduleNextLightning(time) {
|
||||||
const rainActivity = Math.max(this.params.rainVeilIntensity, this.params.rainScreenIntensity);
|
const rainActivity = Math.max(this.params.rainVeilIntensity, this.params.rainScreenIntensity);
|
||||||
const densityBias = THREE.MathUtils.clamp(rainActivity / 1.5, 0, 1);
|
const densityBias = THREE.MathUtils.clamp(rainActivity / 1.5, 0, 1);
|
||||||
|
|||||||
80
src/main.js
80
src/main.js
@@ -1,5 +1,6 @@
|
|||||||
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
|
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
|
||||||
import { OceanScene } from './OceanScene.js';
|
import { OceanScene } from './OceanScene.js';
|
||||||
|
import { WEATHER_PRESETS } from './weatherPresets.js';
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const container = document.getElementById('container');
|
const container = document.getElementById('container');
|
||||||
@@ -37,6 +38,11 @@ function setupControls(oceanScene) {
|
|||||||
gui.domElement.style.zIndex = '120';
|
gui.domElement.style.zIndex = '120';
|
||||||
|
|
||||||
const params = oceanScene.params;
|
const params = oceanScene.params;
|
||||||
|
const controllers = [];
|
||||||
|
const presetState = { 当前天气: 'default' };
|
||||||
|
const presetOptions = Object.fromEntries(
|
||||||
|
Object.entries(WEATHER_PRESETS).map(([key, preset]) => [preset.label, key])
|
||||||
|
);
|
||||||
const presetKeys = [
|
const presetKeys = [
|
||||||
'elevation',
|
'elevation',
|
||||||
'azimuth',
|
'azimuth',
|
||||||
@@ -119,44 +125,68 @@ function setupControls(oceanScene) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const markPresetCustom = () => {
|
||||||
|
if (presetState.当前天气 !== 'custom') {
|
||||||
|
presetState.当前天气 = 'custom';
|
||||||
|
presetController.updateDisplay();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const refreshControllers = () => {
|
||||||
|
controllers.forEach((controller) => controller.updateDisplay());
|
||||||
|
};
|
||||||
|
const bindController = (controller, applyValue) => {
|
||||||
|
controllers.push(controller);
|
||||||
|
controller.onChange((value) => {
|
||||||
|
applyValue(value);
|
||||||
|
markPresetCustom();
|
||||||
|
});
|
||||||
|
return controller;
|
||||||
|
};
|
||||||
|
|
||||||
|
const presetController = gui.add(presetState, '当前天气', { ...presetOptions, 自定义: 'custom' }).name('天气预设');
|
||||||
|
presetController.onChange((presetKey) => {
|
||||||
|
if (presetKey === 'custom') return;
|
||||||
|
oceanScene.applyParams(WEATHER_PRESETS[presetKey].params);
|
||||||
|
refreshControllers();
|
||||||
|
});
|
||||||
gui.add(exportActions, '导出预设');
|
gui.add(exportActions, '导出预设');
|
||||||
|
|
||||||
const skyFolder = gui.addFolder('天空');
|
const skyFolder = gui.addFolder('天空');
|
||||||
skyFolder.add(params, 'elevation', 0, 90, 0.1).name('太阳高度').onChange((value) => oceanScene.setSunElevation(value));
|
bindController(skyFolder.add(params, 'elevation', 0, 90, 0.1).name('太阳高度'), (value) => oceanScene.setSunElevation(value));
|
||||||
skyFolder.add(params, 'azimuth', -180, 180, 0.1).name('太阳方位').onChange((value) => oceanScene.setSunAzimuth(value));
|
bindController(skyFolder.add(params, 'azimuth', -180, 180, 0.1).name('太阳方位'), (value) => oceanScene.setSunAzimuth(value));
|
||||||
skyFolder.add(params, 'exposure', 0, 1, 0.01).name('曝光度').onChange((value) => oceanScene.setExposure(value));
|
bindController(skyFolder.add(params, 'exposure', 0, 1, 0.01).name('曝光度'), (value) => oceanScene.setExposure(value));
|
||||||
skyFolder.add(params, 'turbidity', 1, 20, 0.1).name('浑浊度').onChange((value) => oceanScene.setTurbidity(value));
|
bindController(skyFolder.add(params, 'turbidity', 1, 20, 0.1).name('浑浊度'), (value) => oceanScene.setTurbidity(value));
|
||||||
skyFolder.add(params, 'rayleigh', 0, 4, 0.01).name('瑞利散射').onChange((value) => oceanScene.setRayleigh(value));
|
bindController(skyFolder.add(params, 'rayleigh', 0, 4, 0.01).name('瑞利散射'), (value) => oceanScene.setRayleigh(value));
|
||||||
|
|
||||||
const bloomFolder = gui.addFolder('泛光');
|
const bloomFolder = gui.addFolder('泛光');
|
||||||
bloomFolder.add(params, 'bloomStrength', 0, 1, 0.01).name('强度').onChange((value) => oceanScene.setBloomStrength(value));
|
bindController(bloomFolder.add(params, 'bloomStrength', 0, 1, 0.01).name('强度'), (value) => oceanScene.setBloomStrength(value));
|
||||||
bloomFolder.add(params, 'bloomRadius', 0, 3, 0.01).name('扩散').onChange((value) => oceanScene.setBloomRadius(value));
|
bindController(bloomFolder.add(params, 'bloomRadius', 0, 3, 0.01).name('扩散'), (value) => oceanScene.setBloomRadius(value));
|
||||||
|
|
||||||
const cloudFolder = gui.addFolder('云层');
|
const cloudFolder = gui.addFolder('云层');
|
||||||
cloudFolder.add(params, 'cloudCoverage', 0, 1, 0.01).name('覆盖度').onChange((value) => oceanScene.setCloudCoverage(value));
|
bindController(cloudFolder.add(params, 'cloudCoverage', 0, 1, 0.01).name('覆盖度'), (value) => oceanScene.setCloudCoverage(value));
|
||||||
cloudFolder.add(params, 'cloudDensity', 0, 1, 0.01).name('密度').onChange((value) => oceanScene.setCloudDensity(value));
|
bindController(cloudFolder.add(params, 'cloudDensity', 0, 1, 0.01).name('密度'), (value) => oceanScene.setCloudDensity(value));
|
||||||
cloudFolder.add(params, 'cloudElevation', 0, 1, 0.01).name('高度').onChange((value) => oceanScene.setCloudElevation(value));
|
bindController(cloudFolder.add(params, 'cloudElevation', 0, 1, 0.01).name('高度'), (value) => oceanScene.setCloudElevation(value));
|
||||||
|
|
||||||
const fogFolder = gui.addFolder('雾气');
|
const fogFolder = gui.addFolder('雾气');
|
||||||
fogFolder.add(params, 'fogDensity', 0, 1, 0.01).name('浓度').onChange((value) => oceanScene.setFogDensity(value));
|
bindController(fogFolder.add(params, 'fogDensity', 0, 1, 0.01).name('浓度'), (value) => oceanScene.setFogDensity(value));
|
||||||
fogFolder.add(params, 'fogHeight', 0, 1, 0.01).name('高度').onChange((value) => oceanScene.setFogHeight(value));
|
bindController(fogFolder.add(params, 'fogHeight', 0, 1, 0.01).name('高度'), (value) => oceanScene.setFogHeight(value));
|
||||||
fogFolder.add(params, 'fogRange', 0, 1, 0.01).name('范围').onChange((value) => oceanScene.setFogRange(value));
|
bindController(fogFolder.add(params, 'fogRange', 0, 1, 0.01).name('范围'), (value) => oceanScene.setFogRange(value));
|
||||||
|
|
||||||
const rainFolder = gui.addFolder('雨效');
|
const rainFolder = gui.addFolder('雨效');
|
||||||
rainFolder.add(params, 'rainEnabled').name('启用雨效').onChange((value) => oceanScene.setRainEnabled(value));
|
bindController(rainFolder.add(params, 'rainEnabled').name('启用雨效'), (value) => oceanScene.setRainEnabled(value));
|
||||||
rainFolder.add(params, 'rainScreenIntensity', 0, 1.5, 0.01).name('屏幕雨滴').onChange((value) => oceanScene.setRainScreenIntensity(value));
|
bindController(rainFolder.add(params, 'rainScreenIntensity', 0, 1.5, 0.01).name('屏幕雨滴'), (value) => oceanScene.setRainScreenIntensity(value));
|
||||||
rainFolder.add(params, 'rainVeilIntensity', 0, 1.5, 0.01).name('雨线强度').onChange((value) => oceanScene.setRainVeilIntensity(value));
|
bindController(rainFolder.add(params, 'rainVeilIntensity', 0.5, 2.5, 0.01).name('雨线强度'), (value) => oceanScene.setRainVeilIntensity(value));
|
||||||
rainFolder.add(params, 'rainDropSize', 0.4, 1.8, 0.01).name('雨滴尺寸').onChange((value) => oceanScene.setRainDropSize(value));
|
bindController(rainFolder.add(params, 'rainDropSize', 0.4, 1.8, 0.01).name('雨滴尺寸'), (value) => oceanScene.setRainDropSize(value));
|
||||||
rainFolder.add(params, 'rainSpeed', 0.2, 2.5, 0.01).name('速度').onChange((value) => oceanScene.setRainSpeed(value));
|
bindController(rainFolder.add(params, 'rainSpeed', 0.2, 2.5, 0.01).name('速度'), (value) => oceanScene.setRainSpeed(value));
|
||||||
rainFolder.add(params, 'rainAudioEnabled').name('启用雨声').onChange((value) => oceanScene.setRainAudioEnabled(value));
|
bindController(rainFolder.add(params, 'rainAudioEnabled').name('启用雨声'), (value) => oceanScene.setRainAudioEnabled(value));
|
||||||
rainFolder.add(params, 'rainAudioVolume', 0, 1, 0.01).name('雨声音量').onChange((value) => oceanScene.setRainAudioVolume(value));
|
bindController(rainFolder.add(params, 'rainAudioVolume', 0, 1, 0.01).name('雨声音量'), (value) => oceanScene.setRainAudioVolume(value));
|
||||||
rainFolder.add(params, 'lightningEnabled').name('启用雷闪').onChange((value) => oceanScene.setLightningEnabled(value));
|
bindController(rainFolder.add(params, 'lightningEnabled').name('启用雷闪'), (value) => oceanScene.setLightningEnabled(value));
|
||||||
rainFolder.add(params, 'lightningIntensity', 0, 1.5, 0.01).name('雷闪强度').onChange((value) => oceanScene.setLightningIntensity(value));
|
bindController(rainFolder.add(params, 'lightningIntensity', 0, 1.5, 0.01).name('雷闪强度'), (value) => oceanScene.setLightningIntensity(value));
|
||||||
|
|
||||||
const snowFolder = gui.addFolder('雪效');
|
const snowFolder = gui.addFolder('雪效');
|
||||||
snowFolder.add(params, 'snowEnabled').name('启用降雪').onChange((value) => oceanScene.setSnowEnabled(value));
|
bindController(snowFolder.add(params, 'snowEnabled').name('启用降雪'), (value) => oceanScene.setSnowEnabled(value));
|
||||||
snowFolder.add(params, 'snowIntensity', 0, 1.5, 0.01).name('雪量').onChange((value) => oceanScene.setSnowIntensity(value));
|
bindController(snowFolder.add(params, 'snowIntensity', 0, 1.5, 0.01).name('雪量'), (value) => oceanScene.setSnowIntensity(value));
|
||||||
snowFolder.add(params, 'snowSpeed', 0.2, 2.2, 0.01).name('速度').onChange((value) => oceanScene.setSnowSpeed(value));
|
bindController(snowFolder.add(params, 'snowSpeed', 0.2, 2.2, 0.01).name('速度'), (value) => oceanScene.setSnowSpeed(value));
|
||||||
|
|
||||||
gui.close();
|
gui.close();
|
||||||
}
|
}
|
||||||
|
|||||||
139
src/weatherPresets.js
Normal file
139
src/weatherPresets.js
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
export const DEFAULT_SCENE_PARAMS = {
|
||||||
|
elevation: 2,
|
||||||
|
azimuth: 180,
|
||||||
|
exposure: 0.1,
|
||||||
|
turbidity: 10,
|
||||||
|
rayleigh: 2,
|
||||||
|
bloomStrength: 0.1,
|
||||||
|
bloomRadius: 0,
|
||||||
|
bloomThreshold: 0,
|
||||||
|
cloudCoverage: 0.4,
|
||||||
|
cloudDensity: 0.5,
|
||||||
|
cloudElevation: 0.5,
|
||||||
|
fogDensity: 0.42,
|
||||||
|
fogHeight: 0.32,
|
||||||
|
fogRange: 0.55,
|
||||||
|
rainEnabled: false,
|
||||||
|
rainScreenIntensity: 0.41,
|
||||||
|
rainVeilIntensity: 1.15,
|
||||||
|
rainDropSize: 1.0,
|
||||||
|
rainSpeed: 1.0,
|
||||||
|
rainAudioEnabled: true,
|
||||||
|
rainAudioVolume: 0.35,
|
||||||
|
snowEnabled: false,
|
||||||
|
snowIntensity: 0.65,
|
||||||
|
snowSpeed: 0.85,
|
||||||
|
lightningEnabled: true,
|
||||||
|
lightningIntensity: 0.75,
|
||||||
|
mieCoefficient: 0.005,
|
||||||
|
mieDirectionalG: 0.8
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WEATHER_PRESETS = {
|
||||||
|
default: {
|
||||||
|
label: '默认',
|
||||||
|
params: {
|
||||||
|
...DEFAULT_SCENE_PARAMS
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clear: {
|
||||||
|
label: '日出',
|
||||||
|
params: {
|
||||||
|
...DEFAULT_SCENE_PARAMS,
|
||||||
|
"elevation": 0,
|
||||||
|
"azimuth": 0,
|
||||||
|
"exposure": 0.61,
|
||||||
|
"turbidity": 1,
|
||||||
|
"rayleigh": 3.21,
|
||||||
|
"bloomStrength": 0.24,
|
||||||
|
"bloomRadius": 0.42,
|
||||||
|
"cloudCoverage": 0.4,
|
||||||
|
"cloudDensity": 0.18,
|
||||||
|
"cloudElevation": 0.98,
|
||||||
|
"fogDensity": 0,
|
||||||
|
"fogHeight": 1,
|
||||||
|
"fogRange": 0.02,
|
||||||
|
"rainEnabled": false,
|
||||||
|
"rainScreenIntensity": 0.41,
|
||||||
|
"rainVeilIntensity": 1.15,
|
||||||
|
"rainDropSize": 1,
|
||||||
|
"rainSpeed": 1,
|
||||||
|
"rainAudioEnabled": true,
|
||||||
|
"rainAudioVolume": 0.35,
|
||||||
|
"snowEnabled": false,
|
||||||
|
"snowIntensity": 0.65,
|
||||||
|
"snowSpeed": 0.85,
|
||||||
|
"lightningEnabled": true,
|
||||||
|
"lightningIntensity": 0.75
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rainy: {
|
||||||
|
label: '下雨',
|
||||||
|
params: {
|
||||||
|
...DEFAULT_SCENE_PARAMS,
|
||||||
|
exposure: 0.08,
|
||||||
|
bloomStrength: 0.16,
|
||||||
|
bloomRadius: 0.24,
|
||||||
|
cloudCoverage: 0.78,
|
||||||
|
cloudDensity: 0.82,
|
||||||
|
cloudElevation: 0.42,
|
||||||
|
fogDensity: 0.58,
|
||||||
|
fogHeight: 0.36,
|
||||||
|
fogRange: 0.72,
|
||||||
|
rainEnabled: true,
|
||||||
|
rainScreenIntensity: 0.38,
|
||||||
|
rainVeilIntensity: 1.25,
|
||||||
|
rainDropSize: 0.46,
|
||||||
|
rainSpeed: 1.18,
|
||||||
|
rainAudioEnabled: true,
|
||||||
|
rainAudioVolume: 0.35,
|
||||||
|
lightningEnabled: true,
|
||||||
|
lightningIntensity: 0.75,
|
||||||
|
snowEnabled: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
storm: {
|
||||||
|
label: '暴雨雷暴',
|
||||||
|
params: {
|
||||||
|
...DEFAULT_SCENE_PARAMS,
|
||||||
|
exposure: 0.065,
|
||||||
|
bloomStrength: 0.22,
|
||||||
|
bloomRadius: 0.35,
|
||||||
|
cloudCoverage: 0.92,
|
||||||
|
cloudDensity: 0.94,
|
||||||
|
cloudElevation: 0.36,
|
||||||
|
fogDensity: 0.7,
|
||||||
|
fogHeight: 0.42,
|
||||||
|
fogRange: 0.82,
|
||||||
|
rainEnabled: true,
|
||||||
|
rainScreenIntensity: 0.72,
|
||||||
|
rainVeilIntensity: 1.35,
|
||||||
|
rainDropSize: 1.14,
|
||||||
|
rainSpeed: 1.34,
|
||||||
|
rainAudioEnabled: true,
|
||||||
|
rainAudioVolume: 0.42,
|
||||||
|
lightningEnabled: true,
|
||||||
|
lightningIntensity: 1.0,
|
||||||
|
snowEnabled: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
snow: {
|
||||||
|
label: '降雪',
|
||||||
|
params: {
|
||||||
|
...DEFAULT_SCENE_PARAMS,
|
||||||
|
exposure: 0.11,
|
||||||
|
bloomStrength: 0.08,
|
||||||
|
cloudCoverage: 0.72,
|
||||||
|
cloudDensity: 0.7,
|
||||||
|
fogDensity: 0.52,
|
||||||
|
fogHeight: 0.4,
|
||||||
|
fogRange: 0.68,
|
||||||
|
rainEnabled: false,
|
||||||
|
lightningEnabled: false,
|
||||||
|
snowEnabled: true,
|
||||||
|
snowIntensity: 1.1,
|
||||||
|
snowSpeed: 1.2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user