沙沙的雨声
This commit is contained in:
@@ -9,6 +9,8 @@ import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
|
||||
import { TerrainGenerator } from './TerrainGenerator.js';
|
||||
import { VegetationSystem } from './VegetationSystem.js';
|
||||
|
||||
const RAIN_AUDIO_URL = '/audio/rain-calming.mp3';
|
||||
|
||||
export class OceanScene {
|
||||
constructor(container) {
|
||||
this.container = container;
|
||||
@@ -38,6 +40,7 @@ export class OceanScene {
|
||||
this.fogLayers = [];
|
||||
this.horizonFog = null;
|
||||
this.skyHazeBand = null;
|
||||
this.rainAudio = null;
|
||||
|
||||
this.params = {
|
||||
elevation: 2,
|
||||
@@ -59,6 +62,8 @@ export class OceanScene {
|
||||
rainVeilIntensity: 1.15,
|
||||
rainDropSize: 1.0,
|
||||
rainSpeed: 1.0,
|
||||
rainAudioEnabled: false,
|
||||
rainAudioVolume: 0.35,
|
||||
lightningEnabled: false,
|
||||
lightningIntensity: 0.75,
|
||||
mieCoefficient: 0.005,
|
||||
@@ -82,6 +87,7 @@ export class OceanScene {
|
||||
this.initControls();
|
||||
this.initLighting();
|
||||
this.initPostProcessing();
|
||||
this.initAudio();
|
||||
await this.initSky();
|
||||
this.initClouds();
|
||||
this.initFog();
|
||||
@@ -180,6 +186,14 @@ export class OceanScene {
|
||||
this.composer.addPass(this.rainPass);
|
||||
}
|
||||
|
||||
initAudio() {
|
||||
this.rainAudio = new Audio(RAIN_AUDIO_URL);
|
||||
this.rainAudio.loop = true;
|
||||
this.rainAudio.preload = 'auto';
|
||||
this.rainAudio.volume = this.params.rainAudioVolume;
|
||||
this.rainAudio.crossOrigin = 'anonymous';
|
||||
}
|
||||
|
||||
createRainShader() {
|
||||
return {
|
||||
uniforms: {
|
||||
@@ -1028,6 +1042,7 @@ export class OceanScene {
|
||||
if (this.rainPass) {
|
||||
this.rainPass.enabled = value;
|
||||
}
|
||||
this.updateRainAudioState();
|
||||
}
|
||||
|
||||
setRainScreenIntensity(value) {
|
||||
@@ -1058,6 +1073,35 @@ export class OceanScene {
|
||||
}
|
||||
}
|
||||
|
||||
setRainAudioEnabled(value) {
|
||||
this.params.rainAudioEnabled = value;
|
||||
this.updateRainAudioState();
|
||||
}
|
||||
|
||||
setRainAudioVolume(value) {
|
||||
this.params.rainAudioVolume = value;
|
||||
if (this.rainAudio) {
|
||||
this.rainAudio.volume = value;
|
||||
}
|
||||
this.updateRainAudioState();
|
||||
}
|
||||
|
||||
updateRainAudioState() {
|
||||
if (!this.rainAudio) return;
|
||||
|
||||
const shouldPlay = this.params.rainEnabled && this.params.rainAudioEnabled && this.params.rainAudioVolume > 0.001;
|
||||
if (shouldPlay) {
|
||||
this.rainAudio.volume = this.params.rainAudioVolume;
|
||||
const playPromise = this.rainAudio.play();
|
||||
if (playPromise?.catch) {
|
||||
playPromise.catch(() => {});
|
||||
}
|
||||
} else {
|
||||
this.rainAudio.pause();
|
||||
this.rainAudio.currentTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
setLightningEnabled(value) {
|
||||
this.params.lightningEnabled = value;
|
||||
if (!value) {
|
||||
|
||||
@@ -68,8 +68,10 @@ function setupControls(oceanScene) {
|
||||
bindSlider('rain-veil-intensity', (value) => value.toFixed(2), (value) => oceanScene.setRainVeilIntensity(value));
|
||||
bindSlider('rain-drop-size', (value) => value.toFixed(2), (value) => oceanScene.setRainDropSize(value));
|
||||
bindSlider('rain-speed', (value) => value.toFixed(2), (value) => oceanScene.setRainSpeed(value));
|
||||
bindSlider('rain-audio-volume', (value) => value.toFixed(2), (value) => oceanScene.setRainAudioVolume(value));
|
||||
bindSlider('lightning-intensity', (value) => value.toFixed(2), (value) => oceanScene.setLightningIntensity(value));
|
||||
bindCheckbox('rain-enabled', (value) => oceanScene.setRainEnabled(value));
|
||||
bindCheckbox('rain-audio-enabled', (value) => oceanScene.setRainAudioEnabled(value));
|
||||
bindCheckbox('lightning-enabled', (value) => oceanScene.setLightningEnabled(value));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user