闪电优化
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user