From efc2aa09d00aed95c46ccca54ac0a5cf45742ca9 Mon Sep 17 00:00:00 2001 From: Florian Rival Date: Wed, 30 Sep 2026 20:41:37 +0200 Subject: [PATCH] Update 3D lights shadows and fogs when the world scale changes (#9169) --- Extensions/3D/DirectionalLight.ts | 13 +++++++++--- Extensions/3D/ExponentialFog.ts | 24 ++++++++++++++-------- Extensions/3D/LinearFog.ts | 34 ++++++++++++++++++++----------- 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/Extensions/3D/DirectionalLight.ts b/Extensions/3D/DirectionalLight.ts index 8a70617310..d612d8eedd 100644 --- a/Extensions/3D/DirectionalLight.ts +++ b/Extensions/3D/DirectionalLight.ts @@ -30,6 +30,7 @@ namespace gdjs { private _light: THREE.DirectionalLight; private _shadowMapDirty = true; private _shadowCameraDirty = true; + private _shadowCameraInverseWorldScale: float = 0; private _shadowCameraHelper: THREE.CameraHelper | null; constructor() { @@ -47,12 +48,16 @@ namespace gdjs { } private _updateShadowCamera(scene: gdjs.RuntimeScene): void { - if (!this._shadowCameraDirty) { + const inverseWorldScale = scene.getRenderer3DInverseWorldScale(); + // The world scale can be changed in the editor. + if ( + !this._shadowCameraDirty && + this._shadowCameraInverseWorldScale === inverseWorldScale + ) { return; } this._shadowCameraDirty = false; - - const inverseWorldScale = scene.getRenderer3DInverseWorldScale(); + this._shadowCameraInverseWorldScale = inverseWorldScale; const frustumSize = this._frustumSize * inverseWorldScale; this._light.shadow.camera.near = 1 * inverseWorldScale; @@ -62,6 +67,8 @@ namespace gdjs { this._light.shadow.camera.left = -frustumSize / 2; this._light.shadow.camera.top = frustumSize / 2; this._light.shadow.camera.bottom = -frustumSize / 2; + // Three.js only updates it when the shadow map is created. + this._light.shadow.camera.updateProjectionMatrix(); } private _updateShadowMapSize(): void { diff --git a/Extensions/3D/ExponentialFog.ts b/Extensions/3D/ExponentialFog.ts index cf3d65f255..aa1083ed2c 100644 --- a/Extensions/3D/ExponentialFog.ts +++ b/Extensions/3D/ExponentialFog.ts @@ -15,6 +15,9 @@ namespace gdjs { } return new (class implements gdjs.PixiFiltersTools.Filter { fog: THREE.FogExp2; + // In scene units: the fog is converted to the Three.js world units + // before each rendering, as the world scale can change in the editor. + private _density: float = 0.0012; constructor() { this.fog = new THREE.FogExp2(0xffffff); @@ -56,19 +59,23 @@ namespace gdjs { scene.fog = null; return true; } - updatePreRender(target: gdjs.EffectsTarget): any {} - updateDoubleParameter(parameterName: string, value: number): void { + updatePreRender(target: gdjs.EffectsTarget): any { + this._updateFogDensity(); + } + private _updateFogDensity(): void { const scene = target.getRuntimeScene().getScene(); const worldScale = scene.getRenderer3DWorldScale(); + this.fog.density = this._density * worldScale; + } + updateDoubleParameter(parameterName: string, value: number): void { if (parameterName === 'density') { - this.fog.density = value * worldScale; + this._density = value; + this._updateFogDensity(); } } getDoubleParameter(parameterName: string): number { - const scene = target.getRuntimeScene().getScene(); - const inverseWorldScale = scene.getRenderer3DInverseWorldScale(); if (parameterName === 'density') { - return this.fog.density * inverseWorldScale; + return this._density; } return 0; } @@ -93,14 +100,15 @@ namespace gdjs { updateBooleanParameter(parameterName: string, value: boolean): void {} getNetworkSyncData(): ExponentialFogFilterNetworkSyncData { return { - d: this.fog.density, + d: this._density, c: this.fog.color.getHex(), }; } updateFromNetworkSyncData( syncData: ExponentialFogFilterNetworkSyncData ): void { - this.fog.density = syncData.d; + this._density = syncData.d; + this._updateFogDensity(); this.fog.color.setHex(syncData.c); } })(); diff --git a/Extensions/3D/LinearFog.ts b/Extensions/3D/LinearFog.ts index 2e23875afa..58840790d2 100644 --- a/Extensions/3D/LinearFog.ts +++ b/Extensions/3D/LinearFog.ts @@ -16,6 +16,10 @@ namespace gdjs { } return new (class implements gdjs.PixiFiltersTools.Filter { fog: THREE.Fog; + // In scene units: the fog is converted to the Three.js world units + // before each rendering, as the world scale can change in the editor. + private _near: float = 200; + private _far: float = 2000; constructor() { this.fog = new THREE.Fog(0xffffff); @@ -57,23 +61,28 @@ namespace gdjs { scene.fog = null; return true; } - updatePreRender(target: gdjs.EffectsTarget): any {} - updateDoubleParameter(parameterName: string, value: number): void { + updatePreRender(target: gdjs.EffectsTarget): any { + this._updateFogDistances(); + } + private _updateFogDistances(): void { const scene = target.getRuntimeScene().getScene(); const inverseWorldScale = scene.getRenderer3DInverseWorldScale(); + this.fog.near = this._near * inverseWorldScale; + this.fog.far = this._far * inverseWorldScale; + } + updateDoubleParameter(parameterName: string, value: number): void { if (parameterName === 'near') { - this.fog.near = value * inverseWorldScale; + this._near = value; } else if (parameterName === 'far') { - this.fog.far = value * inverseWorldScale; + this._far = value; } + this._updateFogDistances(); } getDoubleParameter(parameterName: string): number { - const scene = target.getRuntimeScene().getScene(); - const worldScale = scene.getRenderer3DWorldScale(); if (parameterName === 'near') { - return this.fog.near * worldScale; + return this._near; } else if (parameterName === 'far') { - return this.fog.far * worldScale; + return this._far; } return 0; } @@ -98,16 +107,17 @@ namespace gdjs { updateBooleanParameter(parameterName: string, value: boolean): void {} getNetworkSyncData(): LinearFogFilterNetworkSyncData { return { - n: this.fog.near, - f: this.fog.far, + n: this._near, + f: this._far, c: this.fog.color.getHex(), }; } updateFromNetworkSyncData( data: LinearFogFilterNetworkSyncData ): void { - this.fog.near = data.n; - this.fog.far = data.f; + this._near = data.n; + this._far = data.f; + this._updateFogDistances(); this.fog.color.setHex(data.c); } })();