闪电优化

This commit is contained in:
2026-03-26 12:55:20 +08:00
parent 7a509d0398
commit 0acbc916a8

View File

@@ -27,6 +27,7 @@ export class OceanScene {
this.sunLight = null; this.sunLight = null;
this.vegetationFillLight = null; this.vegetationFillLight = null;
this.lightningLight = null; this.lightningLight = null;
this.lightningCloudGlow = null;
this.composer = null; this.composer = null;
this.bloomPass = null; this.bloomPass = null;
this.rainPass = null; this.rainPass = null;
@@ -68,8 +69,10 @@ export class OceanScene {
this.frameCount = 0; this.frameCount = 0;
this.lastTime = performance.now(); this.lastTime = performance.now();
this.lightningFlash = 0; this.lightningFlash = 0;
this.lightningLocalFlash = 0;
this.lightningBurstEnd = 0; this.lightningBurstEnd = 0;
this.nextLightningAt = 0; this.nextLightningAt = 0;
this.lightningPulseSchedule = [];
} }
async init() { async init() {
@@ -443,11 +446,32 @@ export class OceanScene {
}); });
this.scene.add(this.cloudGroup); this.scene.add(this.cloudGroup);
this.initLightningCloudGlow();
this.setCloudElevation(this.params.cloudElevation); this.setCloudElevation(this.params.cloudElevation);
this.setCloudCoverage(this.params.cloudCoverage); this.setCloudCoverage(this.params.cloudCoverage);
this.updateClouds(); this.updateClouds();
} }
initLightningCloudGlow() {
const glowTexture = this.createLightningGlowTexture();
const material = new THREE.SpriteMaterial({
map: glowTexture,
color: 0xddeeff,
transparent: true,
opacity: 0,
depthWrite: false,
depthTest: false,
fog: false,
blending: THREE.AdditiveBlending
});
this.lightningCloudGlow = new THREE.Sprite(material);
this.lightningCloudGlow.scale.set(900, 900, 1);
this.lightningCloudGlow.position.set(-420, 210, -760);
this.lightningCloudGlow.visible = false;
this.scene.add(this.lightningCloudGlow);
}
addCloudDomeLayer(texture, config) { addCloudDomeLayer(texture, config) {
const layerTexture = texture.clone(); const layerTexture = texture.clone();
layerTexture.wrapS = THREE.RepeatWrapping; layerTexture.wrapS = THREE.RepeatWrapping;
@@ -576,6 +600,27 @@ export class OceanScene {
return texture; return texture;
} }
createLightningGlowTexture() {
const canvas = document.createElement('canvas');
canvas.width = 256;
canvas.height = 256;
const context = canvas.getContext('2d');
const gradient = context.createRadialGradient(128, 128, 0, 128, 128, 128);
gradient.addColorStop(0, 'rgba(255,255,255,0.95)');
gradient.addColorStop(0.18, 'rgba(220,236,255,0.85)');
gradient.addColorStop(0.42, 'rgba(180,205,255,0.35)');
gradient.addColorStop(0.72, 'rgba(120,155,255,0.08)');
gradient.addColorStop(1, 'rgba(120,155,255,0)');
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
const texture = new THREE.CanvasTexture(canvas);
texture.colorSpace = THREE.SRGBColorSpace;
texture.needsUpdate = true;
return texture;
}
createFogTexture() { createFogTexture() {
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
canvas.width = 512; canvas.width = 512;
@@ -1034,6 +1079,37 @@ export class OceanScene {
this.nextLightningAt = time + delay; this.nextLightningAt = time + delay;
} }
startLightningBurst(time) {
const pulseCountRoll = Math.random();
const pulseCount = pulseCountRoll > 0.8 ? 3 : pulseCountRoll > 0.45 ? 2 : 1;
this.lightningPulseSchedule = [];
let pulseTime = time;
for (let i = 0; i < pulseCount; i++) {
const duration = 0.05 + Math.random() * 0.07;
const amplitude = this.params.lightningIntensity * (1.0 - i * 0.14) * (0.85 + Math.random() * 0.35);
this.lightningPulseSchedule.push({
time: pulseTime,
duration,
amplitude
});
pulseTime += 0.06 + Math.random() * 0.12;
}
this.lightningBurstEnd = pulseTime + 0.12;
const flashX = THREE.MathUtils.randFloat(-1600, 1600);
const flashY = THREE.MathUtils.randFloat(120, 340);
const flashZ = THREE.MathUtils.randFloat(-1800, -420);
this.lightningLight.position.set(flashX * 0.22, flashY, flashZ * 0.08);
if (this.lightningCloudGlow) {
this.lightningCloudGlow.position.set(flashX, flashY, flashZ);
const size = THREE.MathUtils.randFloat(720, 1480);
this.lightningCloudGlow.scale.set(size, size * THREE.MathUtils.randFloat(0.72, 1.08), 1);
}
}
updateLightning(time) { updateLightning(time) {
if (!this.params.lightningEnabled) return; if (!this.params.lightningEnabled) return;
@@ -1042,36 +1118,46 @@ export class OceanScene {
} }
if (time >= this.nextLightningAt && time >= this.lightningBurstEnd) { if (time >= this.nextLightningAt && time >= this.lightningBurstEnd) {
const burstLength = 0.18 + Math.random() * 0.16; this.startLightningBurst(time);
this.lightningBurstEnd = time + burstLength;
this.lightningLight.position.set(
THREE.MathUtils.randFloat(-220, 220),
THREE.MathUtils.randFloat(140, 260),
THREE.MathUtils.randFloat(-120, 120)
);
this.scheduleNextLightning(time); this.scheduleNextLightning(time);
} }
if (time < this.lightningBurstEnd) { let flash = 0;
const burstProgress = 1.0 - (this.lightningBurstEnd - time) / Math.max(this.lightningBurstEnd - (this.lightningBurstEnd - 0.34), 0.0001); let localFlash = 0;
const pulseA = Math.max(0, Math.sin((time + 0.13) * 37.0)); for (const pulse of this.lightningPulseSchedule) {
const pulseB = Math.max(0, Math.sin((time + 0.04) * 83.0)); const dt = time - pulse.time;
const envelope = Math.exp(-burstProgress * 5.5); if (dt < -0.001 || dt > pulse.duration * 2.8) continue;
const flash = (pulseA * 0.75 + pulseB * 0.45 + 0.25) * envelope * this.params.lightningIntensity;
this.lightningFlash = Math.max(this.lightningFlash * 0.72, flash); const attack = Math.exp(-Math.pow((dt - pulse.duration * 0.12) / Math.max(pulse.duration * 0.32, 0.001), 2.0));
const decay = Math.exp(-Math.max(dt, 0.0) / Math.max(pulse.duration * 1.45, 0.001));
const pulseFlash = pulse.amplitude * attack * decay;
flash += pulseFlash;
localFlash += pulseFlash * 1.35;
}
if (flash > 0.001) {
this.lightningFlash = Math.max(this.lightningFlash * 0.7, flash);
this.lightningLocalFlash = Math.max(this.lightningLocalFlash * 0.62, localFlash);
} else { } else {
this.lightningFlash *= 0.82; this.lightningFlash *= 0.82;
if (this.lightningFlash < 0.002) this.lightningFlash = 0; if (this.lightningFlash < 0.002) this.lightningFlash = 0;
this.lightningLocalFlash *= 0.74;
if (this.lightningLocalFlash < 0.002) this.lightningLocalFlash = 0;
} }
this.applyLightningState(this.lightningFlash); this.applyLightningState(this.lightningFlash, this.lightningLocalFlash);
} }
applyLightningState(flash) { applyLightningState(flash, localFlash = 0) {
if (this.lightningLight) { if (this.lightningLight) {
this.lightningLight.intensity = flash * 5.5; this.lightningLight.intensity = flash * 5.5;
} }
if (this.lightningCloudGlow) {
this.lightningCloudGlow.visible = localFlash > 0.002;
this.lightningCloudGlow.material.opacity = THREE.MathUtils.clamp(localFlash * 0.95, 0, 0.95);
}
if (this.renderer) { if (this.renderer) {
this.renderer.toneMappingExposure = this.params.exposure * (1.0 + flash * 1.6); this.renderer.toneMappingExposure = this.params.exposure * (1.0 + flash * 1.6);
} }
@@ -1088,7 +1174,7 @@ export class OceanScene {
const warmCloud = new THREE.Color(0xdab188); const warmCloud = new THREE.Color(0xdab188);
const dayCloud = new THREE.Color(0xd1dbe6); const dayCloud = new THREE.Color(0xd1dbe6);
const cloudColor = warmCloud.lerp(dayCloud, sunMix); const cloudColor = warmCloud.lerp(dayCloud, sunMix);
const lightningMix = THREE.MathUtils.clamp(this.lightningFlash * 0.85, 0, 1); const lightningMix = THREE.MathUtils.clamp(this.lightningFlash * 0.32, 0, 1);
cloudColor.lerp(new THREE.Color(0xe9f3ff), lightningMix); cloudColor.lerp(new THREE.Color(0xe9f3ff), lightningMix);
for (const layer of this.cloudLayers) { for (const layer of this.cloudLayers) {
@@ -1104,7 +1190,7 @@ export class OceanScene {
updateFog() { updateFog() {
const { sunMix, fogColor, horizonColor, skyBaseColor, skyBlendColor } = this.getAtmosphereColors(); const { sunMix, fogColor, horizonColor, skyBaseColor, skyBlendColor } = this.getAtmosphereColors();
const fogDensity = THREE.MathUtils.lerp(0.00015, 0.0018, this.params.fogDensity); const fogDensity = THREE.MathUtils.lerp(0.00015, 0.0018, this.params.fogDensity);
const lightningMix = THREE.MathUtils.clamp(this.lightningFlash * 0.75, 0, 1); const lightningMix = THREE.MathUtils.clamp(this.lightningFlash * 0.42, 0, 1);
fogColor.lerp(new THREE.Color(0xdbe8f5), lightningMix); fogColor.lerp(new THREE.Color(0xdbe8f5), lightningMix);
horizonColor.lerp(new THREE.Color(0xe5eef9), lightningMix); horizonColor.lerp(new THREE.Color(0xe5eef9), lightningMix);
skyBlendColor.lerp(new THREE.Color(0xdbe7f3), lightningMix); skyBlendColor.lerp(new THREE.Color(0xdbe7f3), lightningMix);