优化雷

This commit is contained in:
2026-03-26 13:12:50 +08:00
parent 299d9d4d82
commit c1f2d0ed2b
2 changed files with 86 additions and 21 deletions

View File

@@ -337,7 +337,7 @@
</div> </div>
<div class="control-toggle" style="margin-top: 8px;"> <div class="control-toggle" style="margin-top: 8px;">
<label for="rain-audio-enabled">启用雨声</label> <label for="rain-audio-enabled">启用雨声</label>
<input type="checkbox" id="rain-audio-enabled"> <input type="checkbox" id="rain-audio-enabled" checked>
</div> </div>
<div class="control-grid"> <div class="control-grid">
<div class="control-group full-width"> <div class="control-group full-width">
@@ -352,7 +352,7 @@
<div class="control-section-title">雷闪</div> <div class="control-section-title">雷闪</div>
<div class="control-toggle"> <div class="control-toggle">
<label for="lightning-enabled">启用雷闪</label> <label for="lightning-enabled">启用雷闪</label>
<input type="checkbox" id="lightning-enabled"> <input type="checkbox" id="lightning-enabled" checked>
</div> </div>
<div class="control-grid"> <div class="control-grid">
<div class="control-group full-width"> <div class="control-group full-width">

View File

@@ -41,7 +41,11 @@ export class OceanScene {
this.fogLayers = []; this.fogLayers = [];
this.horizonFog = null; this.horizonFog = null;
this.skyHazeBand = null; this.skyHazeBand = null;
this.rainAudio = null; this.rainAudioPool = [];
this.rainAudioActiveIndex = 0;
this.rainAudioIsPlaying = false;
this.rainAudioCrossfading = false;
this.rainAudioCrossfadeDuration = 1.6;
this.thunderAudioPool = []; this.thunderAudioPool = [];
this.thunderAudioIndex = 0; this.thunderAudioIndex = 0;
this.scheduledThunder = []; this.scheduledThunder = [];
@@ -66,9 +70,9 @@ export class OceanScene {
rainVeilIntensity: 1.15, rainVeilIntensity: 1.15,
rainDropSize: 1.0, rainDropSize: 1.0,
rainSpeed: 1.0, rainSpeed: 1.0,
rainAudioEnabled: false, rainAudioEnabled: true,
rainAudioVolume: 0.35, rainAudioVolume: 0.35,
lightningEnabled: false, lightningEnabled: true,
lightningIntensity: 0.75, lightningIntensity: 0.75,
mieCoefficient: 0.005, mieCoefficient: 0.005,
mieDirectionalG: 0.8 mieDirectionalG: 0.8
@@ -191,11 +195,14 @@ export class OceanScene {
} }
initAudio() { initAudio() {
this.rainAudio = new Audio(RAIN_AUDIO_URL); this.rainAudioPool = Array.from({ length: 2 }, () => {
this.rainAudio.loop = true; const audio = new Audio(RAIN_AUDIO_URL);
this.rainAudio.preload = 'auto'; audio.loop = false;
this.rainAudio.volume = this.params.rainAudioVolume; audio.preload = 'auto';
this.rainAudio.crossOrigin = 'anonymous'; audio.volume = 0;
audio.crossOrigin = 'anonymous';
return audio;
});
this.thunderAudioPool = Array.from({ length: 3 }, () => { this.thunderAudioPool = Array.from({ length: 3 }, () => {
const audio = new Audio(THUNDER_AUDIO_URL); const audio = new Audio(THUNDER_AUDIO_URL);
@@ -1054,6 +1061,16 @@ export class OceanScene {
this.rainPass.enabled = value; this.rainPass.enabled = value;
} }
this.updateRainAudioState(); this.updateRainAudioState();
if (!value) {
this.lightningFlash = 0;
this.lightningLocalFlash = 0;
this.lightningBurstEnd = 0;
this.nextLightningAt = 0;
this.lightningPulseSchedule = [];
this.scheduledThunder = [];
this.applyLightningState(0);
this.stopThunderAudio();
}
} }
setRainScreenIntensity(value) { setRainScreenIntensity(value) {
@@ -1091,25 +1108,72 @@ export class OceanScene {
setRainAudioVolume(value) { setRainAudioVolume(value) {
this.params.rainAudioVolume = value; this.params.rainAudioVolume = value;
if (this.rainAudio) {
this.rainAudio.volume = value;
}
this.updateRainAudioState(); this.updateRainAudioState();
} }
updateRainAudioState() { updateRainAudioState() {
if (!this.rainAudio) return; if (this.rainAudioPool.length === 0) return;
const shouldPlay = this.params.rainEnabled && this.params.rainAudioEnabled && this.params.rainAudioVolume > 0.001; const shouldPlay = this.params.rainEnabled && this.params.rainAudioEnabled && this.params.rainAudioVolume > 0.001;
if (shouldPlay) { if (shouldPlay) {
this.rainAudio.volume = this.params.rainAudioVolume; if (!this.rainAudioIsPlaying) {
const playPromise = this.rainAudio.play(); const active = this.rainAudioPool[this.rainAudioActiveIndex];
active.currentTime = 0;
active.volume = this.params.rainAudioVolume;
const playPromise = active.play();
if (playPromise?.catch) { if (playPromise?.catch) {
playPromise.catch(() => {}); playPromise.catch(() => {});
} }
this.rainAudioIsPlaying = true;
this.rainAudioCrossfading = false;
}
} else { } else {
this.rainAudio.pause(); for (const audio of this.rainAudioPool) {
this.rainAudio.currentTime = 0; audio.pause();
audio.currentTime = 0;
audio.volume = 0;
}
this.rainAudioIsPlaying = false;
this.rainAudioCrossfading = false;
}
}
updateRainAudioLoop() {
if (!this.rainAudioIsPlaying || this.rainAudioPool.length < 2) return;
const active = this.rainAudioPool[this.rainAudioActiveIndex];
const next = this.rainAudioPool[(this.rainAudioActiveIndex + 1) % this.rainAudioPool.length];
const duration = Number.isFinite(active.duration) ? active.duration : 0;
if (duration <= 0) {
active.volume = this.params.rainAudioVolume;
return;
}
const timeLeft = duration - active.currentTime;
if (!this.rainAudioCrossfading && timeLeft <= this.rainAudioCrossfadeDuration) {
next.currentTime = 0;
next.volume = 0;
const playPromise = next.play();
if (playPromise?.catch) {
playPromise.catch(() => {});
}
this.rainAudioCrossfading = true;
}
if (this.rainAudioCrossfading) {
const progress = THREE.MathUtils.clamp(1.0 - timeLeft / this.rainAudioCrossfadeDuration, 0, 1);
active.volume = this.params.rainAudioVolume * (1.0 - progress);
next.volume = this.params.rainAudioVolume * progress;
if (progress >= 0.999 || active.ended) {
active.pause();
active.currentTime = 0;
active.volume = 0;
this.rainAudioActiveIndex = (this.rainAudioActiveIndex + 1) % this.rainAudioPool.length;
this.rainAudioCrossfading = false;
}
} else {
active.volume = this.params.rainAudioVolume;
} }
} }
@@ -1193,7 +1257,7 @@ export class OceanScene {
} }
playThunder(volume, playbackRate) { playThunder(volume, playbackRate) {
if (!this.params.lightningEnabled || this.thunderAudioPool.length === 0) return; if (!this.params.rainEnabled || !this.params.lightningEnabled || this.thunderAudioPool.length === 0) return;
const audio = this.thunderAudioPool[this.thunderAudioIndex % this.thunderAudioPool.length]; const audio = this.thunderAudioPool[this.thunderAudioIndex % this.thunderAudioPool.length];
this.thunderAudioIndex += 1; this.thunderAudioIndex += 1;
@@ -1208,7 +1272,7 @@ export class OceanScene {
} }
updateThunder(time) { updateThunder(time) {
if (!this.params.lightningEnabled || this.scheduledThunder.length === 0) return; if (!this.params.rainEnabled || !this.params.lightningEnabled || this.scheduledThunder.length === 0) return;
const pending = []; const pending = [];
for (const thunder of this.scheduledThunder) { for (const thunder of this.scheduledThunder) {
@@ -1222,7 +1286,7 @@ export class OceanScene {
} }
updateLightning(time) { updateLightning(time) {
if (!this.params.lightningEnabled) return; if (!this.params.rainEnabled || !this.params.lightningEnabled) return;
if (this.nextLightningAt === 0) { if (this.nextLightningAt === 0) {
this.scheduleNextLightning(time); this.scheduleNextLightning(time);
@@ -1361,6 +1425,7 @@ export class OceanScene {
const time = this.clock.getElapsedTime(); const time = this.clock.getElapsedTime();
this.updateLightning(time); this.updateLightning(time);
this.updateThunder(time); this.updateThunder(time);
this.updateRainAudioLoop();
if (this.water) { if (this.water) {
this.water.material.uniforms['time'].value += 1.0 / 60.0; this.water.material.uniforms['time'].value += 1.0 / 60.0;