沙沙的雨声

This commit is contained in:
2026-03-26 13:01:17 +08:00
parent 0acbc916a8
commit c8dfb03362
4 changed files with 57 additions and 0 deletions

View File

@@ -335,6 +335,17 @@
<div class="control-value" id="rain-speed-value">1.00</div>
</div>
</div>
<div class="control-toggle" style="margin-top: 8px;">
<label for="rain-audio-enabled">启用雨声</label>
<input type="checkbox" id="rain-audio-enabled">
</div>
<div class="control-grid">
<div class="control-group full-width">
<label>雨声音量</label>
<input type="range" id="rain-audio-volume" min="0" max="1" value="0.35" step="0.01">
<div class="control-value" id="rain-audio-volume-value">0.35</div>
</div>
</div>
</div>
<div class="control-section">

Binary file not shown.

View File

@@ -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) {

View File

@@ -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));
}