From ff62c1ed1fcbc1fb8cae3a956b243024e182b1d0 Mon Sep 17 00:00:00 2001 From: Zoran Kokeza Date: Fri, 27 Mar 2026 00:55:39 +0100 Subject: [PATCH 1/4] Re-add terrain and atmosphere splitting --- CHANGES.md | 1 + packages/engine/Source/Scene/Globe.js | 11 ++ .../Source/Scene/GlobeSurfaceShaderSet.js | 112 +++++++++++------- .../Source/Scene/GlobeSurfaceTileProvider.js | 7 ++ packages/engine/Source/Scene/SkyAtmosphere.js | 25 +++- packages/engine/Source/Shaders/GlobeFS.glsl | 13 ++ .../Source/Shaders/SkyAtmosphereFS.glsl | 13 ++ 7 files changed, 136 insertions(+), 46 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 44bb08df1a30..07073defba24 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,7 @@ - Added `token`, `mapServerData`, and `parameters` properties to `ArcGisMapServerImageryProvider.ConstructorOptions`. - Added `Ion.defaultTokenMessage` to customize the credit message shown on the map when using default Ion token. +- Added split terrain feature. ## 1.139.1 - 2026-03-05 diff --git a/packages/engine/Source/Scene/Globe.js b/packages/engine/Source/Scene/Globe.js index 65fc101d926d..414a2da68f93 100644 --- a/packages/engine/Source/Scene/Globe.js +++ b/packages/engine/Source/Scene/Globe.js @@ -27,6 +27,7 @@ import ImageryLayerCollection from "./ImageryLayerCollection.js"; import QuadtreePrimitive from "./QuadtreePrimitive.js"; import SceneMode from "./SceneMode.js"; import ShadowMode from "./ShadowMode.js"; +import SplitDirection from "./SplitDirection.js"; import CesiumMath from "../Core/Math.js"; /** @@ -370,6 +371,15 @@ function Globe(ellipsoid) { * @default 0.3 */ this.vertexShadowDarkness = 0.3; + + /** + * The {@link SplitDirection} to apply, showing the terrain only on + * the left or right of the splitter control. + * + * @type {SplitDirection} + * @default {@link SplitDirection.NONE} + */ + this.splitDirection = SplitDirection.NONE; } Object.defineProperties(Globe.prototype, { @@ -1055,6 +1065,7 @@ Globe.prototype.beginFrame = function (frameState) { tileProvider.undergroundColorAlphaByDistance = this._undergroundColorAlphaByDistance; tileProvider.lambertDiffuseMultiplier = this.lambertDiffuseMultiplier; + tileProvider.splitDirection = this.splitDirection; surface.beginFrame(frameState); } diff --git a/packages/engine/Source/Scene/GlobeSurfaceShaderSet.js b/packages/engine/Source/Scene/GlobeSurfaceShaderSet.js index 23668fbf8ea9..eb3c3285e3c6 100644 --- a/packages/engine/Source/Scene/GlobeSurfaceShaderSet.js +++ b/packages/engine/Source/Scene/GlobeSurfaceShaderSet.js @@ -8,13 +8,15 @@ import SceneMode from "./SceneMode.js"; function GlobeSurfaceShader( numberOfDayTextures, flags, + flags2, material, shaderProgram, clippingShaderState, - clippingPolygonShaderState, + clippingPolygonShaderState ) { this.numberOfDayTextures = numberOfDayTextures; this.flags = flags; + this.flags2 = flags2; this.material = material; this.shaderProgram = shaderProgram; this.clippingShaderState = clippingShaderState; @@ -134,6 +136,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { const hasExaggeration = options.hasExaggeration; const showUndergroundColor = options.showUndergroundColor; const translucent = options.translucent; + const splitTerrain = options.splitTerrain; let quantization = 0; let quantizationDefine = ""; @@ -165,39 +168,40 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { // Flags beyond bit 31 use arithmetic to avoid silent wrap-around // (x << 32 === x << 0 in JavaScript). const flags = - ((sceneMode | - (applyBrightness << 2) | - (applyContrast << 3) | - (applyHue << 4) | - (applySaturation << 5) | - (applyGamma << 6) | - (applyAlpha << 7) | - (hasWaterMask << 8) | - (showReflectiveOcean << 9) | - (showOceanWaves << 10) | - (enableLighting << 11) | - (dynamicAtmosphereLighting << 12) | - (dynamicAtmosphereLightingFromSun << 13) | - (showGroundAtmosphere << 14) | - (perFragmentGroundAtmosphere << 15) | - (hasVertexNormals << 16) | - (useWebMercatorProjection << 17) | - (enableFog << 18) | - (quantization << 19) | - (applySplit << 20) | - (enableClippingPlanes << 21) | - (enableClippingPolygons << 22) | - (cartographicLimitRectangleFlag << 23) | - (imageryCutoutFlag << 24) | - (colorCorrect << 25) | - (highlightFillTile << 26) | - (colorToAlpha << 27) | - (hasGeodeticSurfaceNormals << 28) | - (hasExaggeration << 29) | - (showUndergroundColor << 30) | - (translucent << 31)) >>> - 0) + - (applyDayNightAlpha ? 0x100000000 : 0); + sceneMode | + (applyBrightness << 2) | + (applyContrast << 3) | + (applyHue << 4) | + (applySaturation << 5) | + (applyGamma << 6) | + (applyAlpha << 7) | + (hasWaterMask << 8) | + (showReflectiveOcean << 9) | + (showOceanWaves << 10) | + (enableLighting << 11) | + (dynamicAtmosphereLighting << 12) | + (dynamicAtmosphereLightingFromSun << 13) | + (showGroundAtmosphere << 14) | + (perFragmentGroundAtmosphere << 15) | + (hasVertexNormals << 16) | + (useWebMercatorProjection << 17) | + (enableFog << 18) | + (quantization << 19) | + (applySplit << 20) | + (enableClippingPlanes << 21) | + (enableClippingPolygons << 22) | + (cartographicLimitRectangleFlag << 23) | + (imageryCutoutFlag << 24) | + (colorCorrect << 25) | + (highlightFillTile << 26) | + (colorToAlpha << 27) | + (hasGeodeticSurfaceNormals << 28) | + (hasExaggeration << 29) | + (showUndergroundColor << 30) | + (translucent << 31); + + // More bit flags that don't fit in the first `flag` + const flags2 = applyDayNightAlpha | (splitTerrain << 2); let currentClippingShaderState = 0; if (defined(clippingPlanes) && clippingPlanes.length > 0) { @@ -218,6 +222,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { defined(surfaceShader) && surfaceShader.numberOfDayTextures === numberOfDayTextures && surfaceShader.flags === flags && + surfaceShader.flags2 === flags2 && surfaceShader.material === this.material && surfaceShader.clippingShaderState === currentClippingShaderState && surfaceShader.clippingPolygonShaderState === @@ -232,7 +237,12 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { shadersByFlags = this._shadersByTexturesFlags[numberOfDayTextures] = []; } - surfaceShader = shadersByFlags[flags]; + let shadersByFlags2 = shadersByFlags[flags]; + if (!defined(shadersByFlags2)) { + shadersByFlags2 = shadersByFlags[flags2] = []; + } + + surfaceShader = shadersByFlags2[flags2]; if ( !defined(surfaceShader) || surfaceShader.material !== this.material || @@ -247,7 +257,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { // Need to go before GlobeFS if (currentClippingShaderState !== 0) { fs.sources.unshift( - getClippingFunction(clippingPlanes, frameState.context), + getClippingFunction(clippingPlanes, frameState.context) ); } @@ -261,7 +271,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { fs.defines.push( `TEXTURE_UNITS ${numberOfDayTextures}`, cartographicLimitRectangleDefine, - imageryCutoutDefine, + imageryCutoutDefine ); if (applyBrightness) { @@ -359,10 +369,10 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { } fs.defines.push( - `CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}`, + `CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}` ); vs.defines.push( - `CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}`, + `CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}` ); } @@ -382,6 +392,10 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { vs.defines.push("EXAGGERATION"); } + if (splitTerrain) { + fs.defines.push("SPLIT_TERRAIN"); + } + let computeDayColor = "\ vec4 computeDayColor(vec4 initialColor, vec3 textureCoordinates, float nightBlend)\n\ @@ -447,14 +461,17 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { attributeLocations: terrainEncoding.getAttributeLocations(), }); - surfaceShader = shadersByFlags[flags] = new GlobeSurfaceShader( + surfaceShader = new GlobeSurfaceShader( numberOfDayTextures, flags, + flags2, this.material, shader, currentClippingShaderState, - currentClippingPolygonsShaderState, + currentClippingPolygonsShaderState ); + + shadersByFlags2[flags2] = surfaceShader; } surfaceTile.surfaceShader = surfaceShader; @@ -462,7 +479,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { }; GlobeSurfaceShaderSet.prototype.destroy = function () { - let flags; + let flags, flags2; let shader; const shadersByTexturesFlags = this._shadersByTexturesFlags; @@ -475,9 +492,14 @@ GlobeSurfaceShaderSet.prototype.destroy = function () { for (flags in shadersByFlags) { if (shadersByFlags.hasOwnProperty(flags)) { - shader = shadersByFlags[flags]; - if (defined(shader)) { - shader.shaderProgram.destroy(); + const shadersByFlags2 = shadersByFlags[flags]; + for (flags2 in shadersByFlags2) { + if (shadersByFlags2.hasOwnProperty(flags2)) { + shader = shadersByFlags2[flags2]; + if (defined(shader)) { + shader.shaderProgram.destroy(); + } + } } } } diff --git a/packages/engine/Source/Scene/GlobeSurfaceTileProvider.js b/packages/engine/Source/Scene/GlobeSurfaceTileProvider.js index cb53223ec999..ade5a2ef7e07 100644 --- a/packages/engine/Source/Scene/GlobeSurfaceTileProvider.js +++ b/packages/engine/Source/Scene/GlobeSurfaceTileProvider.js @@ -47,6 +47,7 @@ import Primitive from "./Primitive.js"; import QuadtreeTileLoadState from "./QuadtreeTileLoadState.js"; import SceneMode from "./SceneMode.js"; import ShadowMode from "./ShadowMode.js"; +import SplitDirection from "./SplitDirection.js"; import TerrainFillMesh from "./TerrainFillMesh.js"; import TerrainState from "./TerrainState.js"; import TileBoundingRegion from "./TileBoundingRegion.js"; @@ -91,6 +92,7 @@ function GlobeSurfaceTileProvider(options) { this.showGroundAtmosphere = false; this.shadows = ShadowMode.RECEIVE_ONLY; this.vertexShadowDarkness = 0.3; + this.splitDirection = SplitDirection.NONE; /** * The color to use to highlight terrain fill tiles. If undefined, fill tiles are not @@ -1859,6 +1861,9 @@ function createTileUniformMap(frameState, globeSurfaceTileProvider) { u_vertexShadowDarkness: function () { return this.properties.vertexShadowDarkness; }, + u_terrainSplitDirection: function () { + return globeSurfaceTileProvider.splitDirection; + }, // make a separate object so that changes to the properties are seen on // derived commands that combine another uniform map with this one. @@ -2361,6 +2366,8 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) { surfaceShaderSetOptions.clippedByBoundaries = surfaceTile.clippedByBoundaries; surfaceShaderSetOptions.hasGeodeticSurfaceNormals = hasGeodeticSurfaceNormals; surfaceShaderSetOptions.hasExaggeration = hasExaggeration; + surfaceShaderSetOptions.splitTerrain = + tileProvider.splitDirection !== SplitDirection.NONE; const tileImageryCollection = surfaceTile.imagery; let imageryIndex = 0; diff --git a/packages/engine/Source/Scene/SkyAtmosphere.js b/packages/engine/Source/Scene/SkyAtmosphere.js index 9863027c96c8..c01b8066e8fd 100644 --- a/packages/engine/Source/Scene/SkyAtmosphere.js +++ b/packages/engine/Source/Scene/SkyAtmosphere.js @@ -21,6 +21,7 @@ import Axis from "./Axis.js"; import BlendingState from "./BlendingState.js"; import CullFace from "./CullFace.js"; import SceneMode from "./SceneMode.js"; +import SplitDirection from "./SplitDirection.js"; /** * An atmosphere drawn around the limb of the provided ellipsoid. Based on @@ -153,6 +154,16 @@ function SkyAtmosphere(ellipsoid) { */ this.brightnessShift = 0.0; + /** + * The {@link SplitDirection} to apply, showing the atmosphere only on + * the left or right of the splitter control. + * + * @type {SplitDirection} + * @default {@link SplitDirection.NONE} + */ + this.splitDirection = SplitDirection.NONE; + this._splitDirection = undefined; + this._hueSaturationBrightness = new Cartesian3(); // outer radius, inner radius, dynamic atmosphere color flag @@ -197,6 +208,9 @@ function SkyAtmosphere(ellipsoid) { u_atmosphereMieAnisotropy: function () { return that.atmosphereMieAnisotropy; }, + u_splitDirection: function () { + return that.splitDirection; + }, }; } @@ -298,8 +312,13 @@ SkyAtmosphere.prototype.update = function (frameState, globe) { }); } + // Note that the splitDirection flag requires _two_ bits. + const splitDirectionFlag = + this.splitDirection === 0 ? 0 : this.splitDirection < 0.0 ? 1 : 2; + const flags = - colorCorrect | (perFragmentAtmosphere << 2) | (translucent << 3); + colorCorrect | (perFragmentAtmosphere << 2) | (translucent << 3) || + splitDirectionFlag << 4; if (flags !== this._flags) { this._flags = flags; @@ -318,6 +337,10 @@ SkyAtmosphere.prototype.update = function (frameState, globe) { defines.push("GLOBE_TRANSLUCENT"); } + if (this.splitDirection !== SplitDirection.NONE) { + defines.push("SPLIT_ATMOSPHERE"); + } + const vs = new ShaderSource({ defines: defines, sources: [AtmosphereCommon, SkyAtmosphereCommon, SkyAtmosphereVS], diff --git a/packages/engine/Source/Shaders/GlobeFS.glsl b/packages/engine/Source/Shaders/GlobeFS.glsl index 81b394de7ae3..b5f2a53be4fa 100644 --- a/packages/engine/Source/Shaders/GlobeFS.glsl +++ b/packages/engine/Source/Shaders/GlobeFS.glsl @@ -83,6 +83,10 @@ in vec2 v_clippingPosition; flat in int v_regionIndex; #endif +#ifdef SPLIT_TERRAIN +uniform float u_terrainSplitDirection; +#endif + #if defined(GROUND_ATMOSPHERE) || defined(FOG) && defined(DYNAMIC_ATMOSPHERE_LIGHTING) && (defined(ENABLE_VERTEX_LIGHTING) || defined(ENABLE_DAYNIGHT_SHADING)) uniform float u_minimumBrightness; #endif @@ -337,6 +341,15 @@ void main() } #endif +#ifdef SPLIT_TERRAIN + float splitPosition = czm_splitPosition; + if (u_terrainSplitDirection < 0.0 && gl_FragCoord.x > splitPosition) { + discard; + } else if (u_terrainSplitDirection > 0.0 && gl_FragCoord.x < splitPosition) { + discard; + } +#endif + #ifdef ENABLE_CLIPPING_PLANES float clipDistance = clip(gl_FragCoord, u_clippingPlanes, u_clippingPlanesMatrix); #endif diff --git a/packages/engine/Source/Shaders/SkyAtmosphereFS.glsl b/packages/engine/Source/Shaders/SkyAtmosphereFS.glsl index 06a3f630c327..82a689e5bc7d 100644 --- a/packages/engine/Source/Shaders/SkyAtmosphereFS.glsl +++ b/packages/engine/Source/Shaders/SkyAtmosphereFS.glsl @@ -2,6 +2,10 @@ in vec3 v_outerPositionWC; uniform vec3 u_hsbShift; +#ifdef SPLIT_ATMOSPHERE +uniform float u_splitDirection; +#endif + #ifndef PER_FRAGMENT_ATMOSPHERE in vec3 v_mieColor; in vec3 v_rayleighColor; @@ -11,6 +15,15 @@ in float v_translucent; void main (void) { + #ifdef SPLIT_ATMOSPHERE + float splitPosition = czm_splitPosition; + if (u_splitDirection < 0.0 && gl_FragCoord.x > splitPosition) { + discard; + } else if (u_splitDirection > 0.0 && gl_FragCoord.x < splitPosition) { + discard; + } + #endif + float lightEnum = u_radiiAndDynamicAtmosphereColor.z; vec3 lightDirection = czm_getDynamicAtmosphereLightDirection(v_outerPositionWC, lightEnum); From da12e19003359acfa433ad394b9460f6900bef30 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 27 Mar 2026 16:03:09 +1100 Subject: [PATCH 2/4] Update terrain splitter code in surface shader set. (#104) --- .../Source/Scene/GlobeSurfaceShaderSet.js | 108 ++++++++---------- 1 file changed, 46 insertions(+), 62 deletions(-) diff --git a/packages/engine/Source/Scene/GlobeSurfaceShaderSet.js b/packages/engine/Source/Scene/GlobeSurfaceShaderSet.js index eb3c3285e3c6..cf9bbd7cdf5f 100644 --- a/packages/engine/Source/Scene/GlobeSurfaceShaderSet.js +++ b/packages/engine/Source/Scene/GlobeSurfaceShaderSet.js @@ -8,15 +8,13 @@ import SceneMode from "./SceneMode.js"; function GlobeSurfaceShader( numberOfDayTextures, flags, - flags2, material, shaderProgram, clippingShaderState, - clippingPolygonShaderState + clippingPolygonShaderState, ) { this.numberOfDayTextures = numberOfDayTextures; this.flags = flags; - this.flags2 = flags2; this.material = material; this.shaderProgram = shaderProgram; this.clippingShaderState = clippingShaderState; @@ -168,40 +166,40 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { // Flags beyond bit 31 use arithmetic to avoid silent wrap-around // (x << 32 === x << 0 in JavaScript). const flags = - sceneMode | - (applyBrightness << 2) | - (applyContrast << 3) | - (applyHue << 4) | - (applySaturation << 5) | - (applyGamma << 6) | - (applyAlpha << 7) | - (hasWaterMask << 8) | - (showReflectiveOcean << 9) | - (showOceanWaves << 10) | - (enableLighting << 11) | - (dynamicAtmosphereLighting << 12) | - (dynamicAtmosphereLightingFromSun << 13) | - (showGroundAtmosphere << 14) | - (perFragmentGroundAtmosphere << 15) | - (hasVertexNormals << 16) | - (useWebMercatorProjection << 17) | - (enableFog << 18) | - (quantization << 19) | - (applySplit << 20) | - (enableClippingPlanes << 21) | - (enableClippingPolygons << 22) | - (cartographicLimitRectangleFlag << 23) | - (imageryCutoutFlag << 24) | - (colorCorrect << 25) | - (highlightFillTile << 26) | - (colorToAlpha << 27) | - (hasGeodeticSurfaceNormals << 28) | - (hasExaggeration << 29) | - (showUndergroundColor << 30) | - (translucent << 31); - - // More bit flags that don't fit in the first `flag` - const flags2 = applyDayNightAlpha | (splitTerrain << 2); + ((sceneMode | + (applyBrightness << 2) | + (applyContrast << 3) | + (applyHue << 4) | + (applySaturation << 5) | + (applyGamma << 6) | + (applyAlpha << 7) | + (hasWaterMask << 8) | + (showReflectiveOcean << 9) | + (showOceanWaves << 10) | + (enableLighting << 11) | + (dynamicAtmosphereLighting << 12) | + (dynamicAtmosphereLightingFromSun << 13) | + (showGroundAtmosphere << 14) | + (perFragmentGroundAtmosphere << 15) | + (hasVertexNormals << 16) | + (useWebMercatorProjection << 17) | + (enableFog << 18) | + (quantization << 19) | + (applySplit << 20) | + (enableClippingPlanes << 21) | + (enableClippingPolygons << 22) | + (cartographicLimitRectangleFlag << 23) | + (imageryCutoutFlag << 24) | + (colorCorrect << 25) | + (highlightFillTile << 26) | + (colorToAlpha << 27) | + (hasGeodeticSurfaceNormals << 28) | + (hasExaggeration << 29) | + (showUndergroundColor << 30) | + (translucent << 31)) >>> + 0) + + (applyDayNightAlpha ? 0x100000000 : 0) + + (splitTerrain ? 0x1000000000 : 0); let currentClippingShaderState = 0; if (defined(clippingPlanes) && clippingPlanes.length > 0) { @@ -222,7 +220,6 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { defined(surfaceShader) && surfaceShader.numberOfDayTextures === numberOfDayTextures && surfaceShader.flags === flags && - surfaceShader.flags2 === flags2 && surfaceShader.material === this.material && surfaceShader.clippingShaderState === currentClippingShaderState && surfaceShader.clippingPolygonShaderState === @@ -237,12 +234,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { shadersByFlags = this._shadersByTexturesFlags[numberOfDayTextures] = []; } - let shadersByFlags2 = shadersByFlags[flags]; - if (!defined(shadersByFlags2)) { - shadersByFlags2 = shadersByFlags[flags2] = []; - } - - surfaceShader = shadersByFlags2[flags2]; + surfaceShader = shadersByFlags[flags]; if ( !defined(surfaceShader) || surfaceShader.material !== this.material || @@ -257,7 +249,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { // Need to go before GlobeFS if (currentClippingShaderState !== 0) { fs.sources.unshift( - getClippingFunction(clippingPlanes, frameState.context) + getClippingFunction(clippingPlanes, frameState.context), ); } @@ -271,7 +263,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { fs.defines.push( `TEXTURE_UNITS ${numberOfDayTextures}`, cartographicLimitRectangleDefine, - imageryCutoutDefine + imageryCutoutDefine, ); if (applyBrightness) { @@ -369,10 +361,10 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { } fs.defines.push( - `CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}` + `CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}`, ); vs.defines.push( - `CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}` + `CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}`, ); } @@ -461,17 +453,14 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { attributeLocations: terrainEncoding.getAttributeLocations(), }); - surfaceShader = new GlobeSurfaceShader( + surfaceShader = shadersByFlags[flags] = new GlobeSurfaceShader( numberOfDayTextures, flags, - flags2, this.material, shader, currentClippingShaderState, - currentClippingPolygonsShaderState + currentClippingPolygonsShaderState, ); - - shadersByFlags2[flags2] = surfaceShader; } surfaceTile.surfaceShader = surfaceShader; @@ -479,7 +468,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { }; GlobeSurfaceShaderSet.prototype.destroy = function () { - let flags, flags2; + let flags; let shader; const shadersByTexturesFlags = this._shadersByTexturesFlags; @@ -492,14 +481,9 @@ GlobeSurfaceShaderSet.prototype.destroy = function () { for (flags in shadersByFlags) { if (shadersByFlags.hasOwnProperty(flags)) { - const shadersByFlags2 = shadersByFlags[flags]; - for (flags2 in shadersByFlags2) { - if (shadersByFlags2.hasOwnProperty(flags2)) { - shader = shadersByFlags2[flags2]; - if (defined(shader)) { - shader.shaderProgram.destroy(); - } - } + shader = shadersByFlags[flags]; + if (defined(shader)) { + shader.shaderProgram.destroy(); } } } From 977493659ed23cb20f912adb8950ed307b688cb3 Mon Sep 17 00:00:00 2001 From: Zoran Kokeza Date: Fri, 27 Mar 2026 09:03:01 +0100 Subject: [PATCH 3/4] use bit 33 for splitTerrain --- packages/engine/Source/Scene/GlobeSurfaceShaderSet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/Source/Scene/GlobeSurfaceShaderSet.js b/packages/engine/Source/Scene/GlobeSurfaceShaderSet.js index cf9bbd7cdf5f..5f7cf9c26bbd 100644 --- a/packages/engine/Source/Scene/GlobeSurfaceShaderSet.js +++ b/packages/engine/Source/Scene/GlobeSurfaceShaderSet.js @@ -199,7 +199,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { (translucent << 31)) >>> 0) + (applyDayNightAlpha ? 0x100000000 : 0) + - (splitTerrain ? 0x1000000000 : 0); + (splitTerrain ? 0x200000000 : 0); let currentClippingShaderState = 0; if (defined(clippingPlanes) && clippingPlanes.length > 0) { From 8eb1c39d2298bcd9d70e10234ab1313504cfe269 Mon Sep 17 00:00:00 2001 From: Zoran Kokeza Date: Fri, 27 Mar 2026 09:35:16 +0100 Subject: [PATCH 4/4] use bitwise operator --- packages/engine/Source/Scene/SkyAtmosphere.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/engine/Source/Scene/SkyAtmosphere.js b/packages/engine/Source/Scene/SkyAtmosphere.js index c01b8066e8fd..eeec775944e6 100644 --- a/packages/engine/Source/Scene/SkyAtmosphere.js +++ b/packages/engine/Source/Scene/SkyAtmosphere.js @@ -317,8 +317,10 @@ SkyAtmosphere.prototype.update = function (frameState, globe) { this.splitDirection === 0 ? 0 : this.splitDirection < 0.0 ? 1 : 2; const flags = - colorCorrect | (perFragmentAtmosphere << 2) | (translucent << 3) || - splitDirectionFlag << 4; + colorCorrect | + (perFragmentAtmosphere << 2) | + (translucent << 3) | + (splitDirectionFlag << 4); if (flags !== this._flags) { this._flags = flags;