闪电优化
This commit is contained in:
@@ -27,6 +27,7 @@ export class OceanScene {
|
||||
this.sunLight = null;
|
||||
this.vegetationFillLight = null;
|
||||
this.lightningLight = null;
|
||||
this.lightningCloudGlow = null;
|
||||
this.composer = null;
|
||||
this.bloomPass = null;
|
||||
this.rainPass = null;
|
||||
@@ -68,8 +69,10 @@ export class OceanScene {
|
||||
this.frameCount = 0;
|
||||
this.lastTime = performance.now();
|
||||
this.lightningFlash = 0;
|
||||
this.lightningLocalFlash = 0;
|
||||
this.lightningBurstEnd = 0;
|
||||
this.nextLightningAt = 0;
|
||||
this.lightningPulseSchedule = [];
|
||||
}
|
||||
|
||||
async init() {
|
||||
@@ -443,11 +446,32 @@ export class OceanScene {
|
||||
});
|
||||
|
||||
this.scene.add(this.cloudGroup);
|
||||
this.initLightningCloudGlow();
|
||||
this.setCloudElevation(this.params.cloudElevation);
|
||||
this.setCloudCoverage(this.params.cloudCoverage);
|
||||
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) {
|
||||
const layerTexture = texture.clone();
|
||||
layerTexture.wrapS = THREE.RepeatWrapping;
|
||||
@@ -576,6 +600,27 @@ export class OceanScene {
|
||||
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() {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 512;
|
||||
@@ -1034,6 +1079,37 @@ export class OceanScene {
|
||||
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) {
|
||||
if (!this.params.lightningEnabled) return;
|
||||
|
||||
@@ -1042,36 +1118,46 @@ export class OceanScene {
|
||||
}
|
||||
|
||||
if (time >= this.nextLightningAt && time >= this.lightningBurstEnd) {
|
||||
const burstLength = 0.18 + Math.random() * 0.16;
|
||||
this.lightningBurstEnd = time + burstLength;
|
||||
this.lightningLight.position.set(
|
||||
THREE.MathUtils.randFloat(-220, 220),
|
||||
THREE.MathUtils.randFloat(140, 260),
|
||||
THREE.MathUtils.randFloat(-120, 120)
|
||||
);
|
||||
this.startLightningBurst(time);
|
||||
this.scheduleNextLightning(time);
|
||||
}
|
||||
|
||||
if (time < this.lightningBurstEnd) {
|
||||
const burstProgress = 1.0 - (this.lightningBurstEnd - time) / Math.max(this.lightningBurstEnd - (this.lightningBurstEnd - 0.34), 0.0001);
|
||||
const pulseA = Math.max(0, Math.sin((time + 0.13) * 37.0));
|
||||
const pulseB = Math.max(0, Math.sin((time + 0.04) * 83.0));
|
||||
const envelope = Math.exp(-burstProgress * 5.5);
|
||||
const flash = (pulseA * 0.75 + pulseB * 0.45 + 0.25) * envelope * this.params.lightningIntensity;
|
||||
this.lightningFlash = Math.max(this.lightningFlash * 0.72, flash);
|
||||
let flash = 0;
|
||||
let localFlash = 0;
|
||||
for (const pulse of this.lightningPulseSchedule) {
|
||||
const dt = time - pulse.time;
|
||||
if (dt < -0.001 || dt > pulse.duration * 2.8) continue;
|
||||
|
||||
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 {
|
||||
this.lightningFlash *= 0.82;
|
||||
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) {
|
||||
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) {
|
||||
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 dayCloud = new THREE.Color(0xd1dbe6);
|
||||
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);
|
||||
|
||||
for (const layer of this.cloudLayers) {
|
||||
@@ -1104,7 +1190,7 @@ export class OceanScene {
|
||||
updateFog() {
|
||||
const { sunMix, fogColor, horizonColor, skyBaseColor, skyBlendColor } = this.getAtmosphereColors();
|
||||
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);
|
||||
horizonColor.lerp(new THREE.Color(0xe5eef9), lightningMix);
|
||||
skyBlendColor.lerp(new THREE.Color(0xdbe7f3), lightningMix);
|
||||
|
||||
Reference in New Issue
Block a user