From b864fa803728f46df5f57d53b082511cde3a8f8a Mon Sep 17 00:00:00 2001 From: Victor Ripplinger Date: Tue, 26 May 2026 15:21:22 +0200 Subject: [PATCH 1/2] fix(rendering): add SunLightLayer only if explicitly enabled in options --- examples/3dtiles_loader.html | 3 ++- examples/demo/src/Views/View3D.ts | 1 + examples/mars.html | 1 + examples/view_3d_map.html | 1 + examples/view_3d_mns_map.html | 1 + .../Main/src/Core/Prefab/Globe/SkyManager.ts | 8 +++++--- packages/Main/src/Core/Prefab/GlobeView.js | 20 +++++++++++++++---- packages/Main/test/unit/globeview.js | 1 + 8 files changed, 28 insertions(+), 8 deletions(-) diff --git a/examples/3dtiles_loader.html b/examples/3dtiles_loader.html index 56ae5b01f1..e19c75f24b 100644 --- a/examples/3dtiles_loader.html +++ b/examples/3dtiles_loader.html @@ -81,7 +81,7 @@ const isEmbedded = window.self !== window.top; window.gui = new dat.GUI(); - + // ---- Create a GlobeView ---- @@ -97,6 +97,7 @@ // Create a GlobeView const view = new GlobeView(viewerDiv, placement, { realisticLighting: true, + withSunLightLayer: true, shadows: true, controls: { minDistance: 100, diff --git a/examples/demo/src/Views/View3D.ts b/examples/demo/src/Views/View3D.ts index 88b7fdb964..47050394a3 100644 --- a/examples/demo/src/Views/View3D.ts +++ b/examples/demo/src/Views/View3D.ts @@ -30,6 +30,7 @@ class View3D extends View { placement, { realisticLighting: true, + withSunLightLayer: true, }, ); diff --git a/examples/mars.html b/examples/mars.html index e2a19df57c..9524073dbb 100644 --- a/examples/mars.html +++ b/examples/mars.html @@ -62,6 +62,7 @@ scaleDepth: 0.38, }, realisticLighting: true, + withSunLightLayer: true, }); setupLoadingScreen(viewerDiv, view); diff --git a/examples/view_3d_map.html b/examples/view_3d_map.html index 5a5b99544c..b818e8a5fb 100644 --- a/examples/view_3d_map.html +++ b/examples/view_3d_map.html @@ -50,6 +50,7 @@ // Create a GlobeView const view = new itowns.GlobeView(viewerDiv, placement, { realisticLighting: true, + withSunLightLayer: true, }); // Setup loading screen and debug menu diff --git a/examples/view_3d_mns_map.html b/examples/view_3d_mns_map.html index aaae1fe583..98818011f2 100644 --- a/examples/view_3d_mns_map.html +++ b/examples/view_3d_mns_map.html @@ -57,6 +57,7 @@ // Create a GlobeView const view = new itowns.GlobeView(viewerDiv, placement, { realisticLighting: true, + withSunLightLayer: true, }); // Setup loading screen and debug menu diff --git a/packages/Main/src/Core/Prefab/Globe/SkyManager.ts b/packages/Main/src/Core/Prefab/Globe/SkyManager.ts index 08a0d850de..92daf374b1 100644 --- a/packages/Main/src/Core/Prefab/Globe/SkyManager.ts +++ b/packages/Main/src/Core/Prefab/Globe/SkyManager.ts @@ -93,7 +93,8 @@ class SkyManager { const camera = this.view.camera3D as THREE.PerspectiveCamera | THREE.OrthographicCamera; if (!this.enabled) { return; } - const sunDirection = this.view.sunLightLayer.sunDirection; + // sunLightLayer necessarily exists if SkyManager was created. + const sunDirection = this.view.sunLightLayer!.sunDirection; const moonDirection = new THREE.Vector3(); getMoonDirectionECEF(this.view.date, moonDirection); @@ -137,8 +138,9 @@ class SkyManager { } private _setState(on: boolean) { - // Realistic rendering requires a dimmer sunlight - this.view.sunLightLayer.sunLight.intensity *= on ? 0.1 : 10; + // Realistic rendering requires a dimmer sunlight. + // sunLightLayer necessarily exists if SkyManager was created. + this.view.sunLightLayer!.sunLight.intensity *= on ? 0.1 : 10; this.sky.visible = on; this.skyLight.visible = on; this.effectPass.enabled = on; diff --git a/packages/Main/src/Core/Prefab/GlobeView.js b/packages/Main/src/Core/Prefab/GlobeView.js index 6f0734b466..7642bf392e 100644 --- a/packages/Main/src/Core/Prefab/GlobeView.js +++ b/packages/Main/src/Core/Prefab/GlobeView.js @@ -84,9 +84,13 @@ class GlobeView extends View { * The maximum view distance is this factor times the camera's altitude (above sea level). * @param {number} [options.fogSpread=0.5] - Proportion of the visible depth range that contains fog. * Between 0 and 1. + * @param {boolean} [options.withSunLightLayer=false] - Create and add a SunLightLayer. + * If true, it can later be switched by setting this.sunLightLayer.visible to true/false. + * If false, it will be impossible to enable it later on. * @param {boolean} [options.realisticLighting=false] - Enable realistic lighting. * If true, it can later be switched by setting this.skyManager.enabled to true/false. * If false, it will be impossible to enable it later on. + * Can only be enabled if withSunLightLayer was also enabled. * @param {boolean} [options.shadows=false] - Enable shadow map rendering. Can be toggled * later via `this.shadows`. */ @@ -164,13 +168,20 @@ class GlobeView extends View { } this.date = new Date(); // now + const withSunLightLayer = options.withSunLightLayer === true; // Sunlight and shadow layer - this.sunLightLayer = new SunLightLayer(this); - this.addLayer(this.sunLightLayer); + if (withSunLightLayer) { + this.sunLightLayer = new SunLightLayer(this); + this.addLayer(this.sunLightLayer); + } if (options.realisticLighting === true) { - this.skyManager = new SkyManager(this); + if (withSunLightLayer) { + this.skyManager = new SkyManager(this); + } else { + console.error('Realistic lighting cannot be enabled without sunlight layer option'); + } } this.renderer.shadowMap.enabled = true; @@ -229,10 +240,11 @@ class GlobeView extends View { * @type {boolean} */ get shadows() { - return this.sunLightLayer.castShadow; + return this.sunLightLayer?.castShadow ?? false; } set shadows(value) { + if (!this.sunLightLayer) { return; } if (this.sunLightLayer.castShadow == value) { return; } this.sunLightLayer.castShadow = value; this.notifyChange(this.camera3D); diff --git a/packages/Main/test/unit/globeview.js b/packages/Main/test/unit/globeview.js index fcb890b0e7..1d1ff10d98 100644 --- a/packages/Main/test/unit/globeview.js +++ b/packages/Main/test/unit/globeview.js @@ -17,6 +17,7 @@ describe('GlobeView', function () { const viewer = new GlobeView(renderer.domElement, placement, { renderer, realisticLighting: true, + withSunLightLayer: true, }); const pickedPosition = new THREE.Vector3(); pickedPosition.copy(viewer.camera.position()); From 85f401668e3f8d4e3d33136360caa8e52754eaf0 Mon Sep 17 00:00:00 2001 From: Victor Ripplinger Date: Tue, 26 May 2026 16:04:00 +0200 Subject: [PATCH 2/2] fix: remove forbidden `!` assertions --- packages/Main/src/Core/Prefab/Globe/SkyManager.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/Main/src/Core/Prefab/Globe/SkyManager.ts b/packages/Main/src/Core/Prefab/Globe/SkyManager.ts index 92daf374b1..a2eeb3c6ff 100644 --- a/packages/Main/src/Core/Prefab/Globe/SkyManager.ts +++ b/packages/Main/src/Core/Prefab/Globe/SkyManager.ts @@ -94,7 +94,8 @@ class SkyManager { if (!this.enabled) { return; } // sunLightLayer necessarily exists if SkyManager was created. - const sunDirection = this.view.sunLightLayer!.sunDirection; + if (!this.view.sunLightLayer) { return; } + const sunDirection = this.view.sunLightLayer.sunDirection; const moonDirection = new THREE.Vector3(); getMoonDirectionECEF(this.view.date, moonDirection); @@ -140,7 +141,8 @@ class SkyManager { private _setState(on: boolean) { // Realistic rendering requires a dimmer sunlight. // sunLightLayer necessarily exists if SkyManager was created. - this.view.sunLightLayer!.sunLight.intensity *= on ? 0.1 : 10; + if (!this.view.sunLightLayer) { return; } + this.view.sunLightLayer.sunLight.intensity *= on ? 0.1 : 10; this.sky.visible = on; this.skyLight.visible = on; this.effectPass.enabled = on;