Skip to content

Commit 742e171

Browse files
committed
Re-add terrain and atmosphere splitting
1 parent b406ad5 commit 742e171

7 files changed

Lines changed: 136 additions & 46 deletions

File tree

‎CHANGES.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Added `token`, `mapServerData`, and `parameters` properties to `ArcGisMapServerImageryProvider.ConstructorOptions`.
66
- Added `Ion.defaultTokenMessage` to customize the credit message shown on the map when using default Ion token.
7+
- Added split terrain feature.
78

89
## 1.139.1 - 2026-03-05
910

‎packages/engine/Source/Scene/Globe.js‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import ImageryLayerCollection from "./ImageryLayerCollection.js";
2727
import QuadtreePrimitive from "./QuadtreePrimitive.js";
2828
import SceneMode from "./SceneMode.js";
2929
import ShadowMode from "./ShadowMode.js";
30+
import SplitDirection from "./SplitDirection.js";
3031
import CesiumMath from "../Core/Math.js";
3132

3233
/**
@@ -370,6 +371,15 @@ function Globe(ellipsoid) {
370371
* @default 0.3
371372
*/
372373
this.vertexShadowDarkness = 0.3;
374+
375+
/**
376+
* The {@link SplitDirection} to apply, showing the terrain only on
377+
* the left or right of the splitter control.
378+
*
379+
* @type {SplitDirection}
380+
* @default {@link SplitDirection.NONE}
381+
*/
382+
this.splitDirection = SplitDirection.NONE;
373383
}
374384

375385
Object.defineProperties(Globe.prototype, {
@@ -1055,6 +1065,7 @@ Globe.prototype.beginFrame = function (frameState) {
10551065
tileProvider.undergroundColorAlphaByDistance =
10561066
this._undergroundColorAlphaByDistance;
10571067
tileProvider.lambertDiffuseMultiplier = this.lambertDiffuseMultiplier;
1068+
tileProvider.splitDirection = this.splitDirection;
10581069

10591070
surface.beginFrame(frameState);
10601071
}

‎packages/engine/Source/Scene/GlobeSurfaceShaderSet.js‎

Lines changed: 67 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import SceneMode from "./SceneMode.js";
88
function GlobeSurfaceShader(
99
numberOfDayTextures,
1010
flags,
11+
flags2,
1112
material,
1213
shaderProgram,
1314
clippingShaderState,
14-
clippingPolygonShaderState,
15+
clippingPolygonShaderState
1516
) {
1617
this.numberOfDayTextures = numberOfDayTextures;
1718
this.flags = flags;
19+
this.flags2 = flags2;
1820
this.material = material;
1921
this.shaderProgram = shaderProgram;
2022
this.clippingShaderState = clippingShaderState;
@@ -134,6 +136,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
134136
const hasExaggeration = options.hasExaggeration;
135137
const showUndergroundColor = options.showUndergroundColor;
136138
const translucent = options.translucent;
139+
const splitTerrain = options.splitTerrain;
137140

138141
let quantization = 0;
139142
let quantizationDefine = "";
@@ -165,39 +168,40 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
165168
// Flags beyond bit 31 use arithmetic to avoid silent wrap-around
166169
// (x << 32 === x << 0 in JavaScript).
167170
const flags =
168-
((sceneMode |
169-
(applyBrightness << 2) |
170-
(applyContrast << 3) |
171-
(applyHue << 4) |
172-
(applySaturation << 5) |
173-
(applyGamma << 6) |
174-
(applyAlpha << 7) |
175-
(hasWaterMask << 8) |
176-
(showReflectiveOcean << 9) |
177-
(showOceanWaves << 10) |
178-
(enableLighting << 11) |
179-
(dynamicAtmosphereLighting << 12) |
180-
(dynamicAtmosphereLightingFromSun << 13) |
181-
(showGroundAtmosphere << 14) |
182-
(perFragmentGroundAtmosphere << 15) |
183-
(hasVertexNormals << 16) |
184-
(useWebMercatorProjection << 17) |
185-
(enableFog << 18) |
186-
(quantization << 19) |
187-
(applySplit << 20) |
188-
(enableClippingPlanes << 21) |
189-
(enableClippingPolygons << 22) |
190-
(cartographicLimitRectangleFlag << 23) |
191-
(imageryCutoutFlag << 24) |
192-
(colorCorrect << 25) |
193-
(highlightFillTile << 26) |
194-
(colorToAlpha << 27) |
195-
(hasGeodeticSurfaceNormals << 28) |
196-
(hasExaggeration << 29) |
197-
(showUndergroundColor << 30) |
198-
(translucent << 31)) >>>
199-
0) +
200-
(applyDayNightAlpha ? 0x100000000 : 0);
171+
sceneMode |
172+
(applyBrightness << 2) |
173+
(applyContrast << 3) |
174+
(applyHue << 4) |
175+
(applySaturation << 5) |
176+
(applyGamma << 6) |
177+
(applyAlpha << 7) |
178+
(hasWaterMask << 8) |
179+
(showReflectiveOcean << 9) |
180+
(showOceanWaves << 10) |
181+
(enableLighting << 11) |
182+
(dynamicAtmosphereLighting << 12) |
183+
(dynamicAtmosphereLightingFromSun << 13) |
184+
(showGroundAtmosphere << 14) |
185+
(perFragmentGroundAtmosphere << 15) |
186+
(hasVertexNormals << 16) |
187+
(useWebMercatorProjection << 17) |
188+
(enableFog << 18) |
189+
(quantization << 19) |
190+
(applySplit << 20) |
191+
(enableClippingPlanes << 21) |
192+
(enableClippingPolygons << 22) |
193+
(cartographicLimitRectangleFlag << 23) |
194+
(imageryCutoutFlag << 24) |
195+
(colorCorrect << 25) |
196+
(highlightFillTile << 26) |
197+
(colorToAlpha << 27) |
198+
(hasGeodeticSurfaceNormals << 28) |
199+
(hasExaggeration << 29) |
200+
(showUndergroundColor << 30) |
201+
(translucent << 31);
202+
203+
// More bit flags that don't fit in the first `flag`
204+
const flags2 = applyDayNightAlpha | (splitTerrain << 2);
201205

202206
let currentClippingShaderState = 0;
203207
if (defined(clippingPlanes) && clippingPlanes.length > 0) {
@@ -218,6 +222,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
218222
defined(surfaceShader) &&
219223
surfaceShader.numberOfDayTextures === numberOfDayTextures &&
220224
surfaceShader.flags === flags &&
225+
surfaceShader.flags2 === flags2 &&
221226
surfaceShader.material === this.material &&
222227
surfaceShader.clippingShaderState === currentClippingShaderState &&
223228
surfaceShader.clippingPolygonShaderState ===
@@ -232,7 +237,12 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
232237
shadersByFlags = this._shadersByTexturesFlags[numberOfDayTextures] = [];
233238
}
234239

235-
surfaceShader = shadersByFlags[flags];
240+
let shadersByFlags2 = shadersByFlags[flags];
241+
if (!defined(shadersByFlags2)) {
242+
shadersByFlags2 = shadersByFlags[flags2] = [];
243+
}
244+
245+
surfaceShader = shadersByFlags2[flags2];
236246
if (
237247
!defined(surfaceShader) ||
238248
surfaceShader.material !== this.material ||
@@ -247,7 +257,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
247257
// Need to go before GlobeFS
248258
if (currentClippingShaderState !== 0) {
249259
fs.sources.unshift(
250-
getClippingFunction(clippingPlanes, frameState.context),
260+
getClippingFunction(clippingPlanes, frameState.context)
251261
);
252262
}
253263

@@ -261,7 +271,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
261271
fs.defines.push(
262272
`TEXTURE_UNITS ${numberOfDayTextures}`,
263273
cartographicLimitRectangleDefine,
264-
imageryCutoutDefine,
274+
imageryCutoutDefine
265275
);
266276

267277
if (applyBrightness) {
@@ -359,10 +369,10 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
359369
}
360370

361371
fs.defines.push(
362-
`CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}`,
372+
`CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}`
363373
);
364374
vs.defines.push(
365-
`CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}`,
375+
`CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}`
366376
);
367377
}
368378

@@ -382,6 +392,10 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
382392
vs.defines.push("EXAGGERATION");
383393
}
384394

395+
if (splitTerrain) {
396+
fs.defines.push("SPLIT_TERRAIN");
397+
}
398+
385399
let computeDayColor =
386400
"\
387401
vec4 computeDayColor(vec4 initialColor, vec3 textureCoordinates, float nightBlend)\n\
@@ -447,22 +461,25 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
447461
attributeLocations: terrainEncoding.getAttributeLocations(),
448462
});
449463

450-
surfaceShader = shadersByFlags[flags] = new GlobeSurfaceShader(
464+
surfaceShader = new GlobeSurfaceShader(
451465
numberOfDayTextures,
452466
flags,
467+
flags2,
453468
this.material,
454469
shader,
455470
currentClippingShaderState,
456-
currentClippingPolygonsShaderState,
471+
currentClippingPolygonsShaderState
457472
);
473+
474+
shadersByFlags2[flags2] = surfaceShader;
458475
}
459476

460477
surfaceTile.surfaceShader = surfaceShader;
461478
return surfaceShader.shaderProgram;
462479
};
463480

464481
GlobeSurfaceShaderSet.prototype.destroy = function () {
465-
let flags;
482+
let flags, flags2;
466483
let shader;
467484

468485
const shadersByTexturesFlags = this._shadersByTexturesFlags;
@@ -475,9 +492,14 @@ GlobeSurfaceShaderSet.prototype.destroy = function () {
475492

476493
for (flags in shadersByFlags) {
477494
if (shadersByFlags.hasOwnProperty(flags)) {
478-
shader = shadersByFlags[flags];
479-
if (defined(shader)) {
480-
shader.shaderProgram.destroy();
495+
const shadersByFlags2 = shadersByFlags[flags];
496+
for (flags2 in shadersByFlags2) {
497+
if (shadersByFlags2.hasOwnProperty(flags2)) {
498+
shader = shadersByFlags2[flags2];
499+
if (defined(shader)) {
500+
shader.shaderProgram.destroy();
501+
}
502+
}
481503
}
482504
}
483505
}

‎packages/engine/Source/Scene/GlobeSurfaceTileProvider.js‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import Primitive from "./Primitive.js";
4747
import QuadtreeTileLoadState from "./QuadtreeTileLoadState.js";
4848
import SceneMode from "./SceneMode.js";
4949
import ShadowMode from "./ShadowMode.js";
50+
import SplitDirection from "./SplitDirection.js";
5051
import TerrainFillMesh from "./TerrainFillMesh.js";
5152
import TerrainState from "./TerrainState.js";
5253
import TileBoundingRegion from "./TileBoundingRegion.js";
@@ -91,6 +92,7 @@ function GlobeSurfaceTileProvider(options) {
9192
this.showGroundAtmosphere = false;
9293
this.shadows = ShadowMode.RECEIVE_ONLY;
9394
this.vertexShadowDarkness = 0.3;
95+
this.splitDirection = SplitDirection.NONE;
9496

9597
/**
9698
* The color to use to highlight terrain fill tiles. If undefined, fill tiles are not
@@ -1859,6 +1861,9 @@ function createTileUniformMap(frameState, globeSurfaceTileProvider) {
18591861
u_vertexShadowDarkness: function () {
18601862
return this.properties.vertexShadowDarkness;
18611863
},
1864+
u_terrainSplitDirection: function () {
1865+
return globeSurfaceTileProvider.splitDirection;
1866+
},
18621867

18631868
// make a separate object so that changes to the properties are seen on
18641869
// derived commands that combine another uniform map with this one.
@@ -2361,6 +2366,8 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) {
23612366
surfaceShaderSetOptions.clippedByBoundaries = surfaceTile.clippedByBoundaries;
23622367
surfaceShaderSetOptions.hasGeodeticSurfaceNormals = hasGeodeticSurfaceNormals;
23632368
surfaceShaderSetOptions.hasExaggeration = hasExaggeration;
2369+
surfaceShaderSetOptions.splitTerrain =
2370+
tileProvider.splitDirection !== SplitDirection.NONE;
23642371

23652372
const tileImageryCollection = surfaceTile.imagery;
23662373
let imageryIndex = 0;

‎packages/engine/Source/Scene/SkyAtmosphere.js‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import Axis from "./Axis.js";
2121
import BlendingState from "./BlendingState.js";
2222
import CullFace from "./CullFace.js";
2323
import SceneMode from "./SceneMode.js";
24+
import SplitDirection from "./SplitDirection.js";
2425

2526
/**
2627
* An atmosphere drawn around the limb of the provided ellipsoid. Based on
@@ -153,6 +154,16 @@ function SkyAtmosphere(ellipsoid) {
153154
*/
154155
this.brightnessShift = 0.0;
155156

157+
/**
158+
* The {@link SplitDirection} to apply, showing the atmosphere only on
159+
* the left or right of the splitter control.
160+
*
161+
* @type {SplitDirection}
162+
* @default {@link SplitDirection.NONE}
163+
*/
164+
this.splitDirection = SplitDirection.NONE;
165+
this._splitDirection = undefined;
166+
156167
this._hueSaturationBrightness = new Cartesian3();
157168

158169
// outer radius, inner radius, dynamic atmosphere color flag
@@ -197,6 +208,9 @@ function SkyAtmosphere(ellipsoid) {
197208
u_atmosphereMieAnisotropy: function () {
198209
return that.atmosphereMieAnisotropy;
199210
},
211+
u_splitDirection: function () {
212+
return that.splitDirection;
213+
},
200214
};
201215
}
202216

@@ -298,8 +312,13 @@ SkyAtmosphere.prototype.update = function (frameState, globe) {
298312
});
299313
}
300314

315+
// Note that the splitDirection flag requires _two_ bits.
316+
const splitDirectionFlag =
317+
this.splitDirection === 0 ? 0 : this.splitDirection < 0.0 ? 1 : 2;
318+
301319
const flags =
302-
colorCorrect | (perFragmentAtmosphere << 2) | (translucent << 3);
320+
colorCorrect | (perFragmentAtmosphere << 2) | (translucent << 3) ||
321+
splitDirectionFlag << 4;
303322

304323
if (flags !== this._flags) {
305324
this._flags = flags;
@@ -318,6 +337,10 @@ SkyAtmosphere.prototype.update = function (frameState, globe) {
318337
defines.push("GLOBE_TRANSLUCENT");
319338
}
320339

340+
if (this.splitDirection !== SplitDirection.NONE) {
341+
defines.push("SPLIT_ATMOSPHERE");
342+
}
343+
321344
const vs = new ShaderSource({
322345
defines: defines,
323346
sources: [AtmosphereCommon, SkyAtmosphereCommon, SkyAtmosphereVS],

‎packages/engine/Source/Shaders/GlobeFS.glsl‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ in vec2 v_clippingPosition;
8383
flat in int v_regionIndex;
8484
#endif
8585

86+
#ifdef SPLIT_TERRAIN
87+
uniform float u_terrainSplitDirection;
88+
#endif
89+
8690
#if defined(GROUND_ATMOSPHERE) || defined(FOG) && defined(DYNAMIC_ATMOSPHERE_LIGHTING) && (defined(ENABLE_VERTEX_LIGHTING) || defined(ENABLE_DAYNIGHT_SHADING))
8791
uniform float u_minimumBrightness;
8892
#endif
@@ -337,6 +341,15 @@ void main()
337341
}
338342
#endif
339343

344+
#ifdef SPLIT_TERRAIN
345+
float splitPosition = czm_splitPosition;
346+
if (u_terrainSplitDirection < 0.0 && gl_FragCoord.x > splitPosition) {
347+
discard;
348+
} else if (u_terrainSplitDirection > 0.0 && gl_FragCoord.x < splitPosition) {
349+
discard;
350+
}
351+
#endif
352+
340353
#ifdef ENABLE_CLIPPING_PLANES
341354
float clipDistance = clip(gl_FragCoord, u_clippingPlanes, u_clippingPlanesMatrix);
342355
#endif

‎packages/engine/Source/Shaders/SkyAtmosphereFS.glsl‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ in vec3 v_outerPositionWC;
22

33
uniform vec3 u_hsbShift;
44

5+
#ifdef SPLIT_ATMOSPHERE
6+
uniform float u_splitDirection;
7+
#endif
8+
59
#ifndef PER_FRAGMENT_ATMOSPHERE
610
in vec3 v_mieColor;
711
in vec3 v_rayleighColor;
@@ -11,6 +15,15 @@ in float v_translucent;
1115

1216
void main (void)
1317
{
18+
#ifdef SPLIT_ATMOSPHERE
19+
float splitPosition = czm_splitPosition;
20+
if (u_splitDirection < 0.0 && gl_FragCoord.x > splitPosition) {
21+
discard;
22+
} else if (u_splitDirection > 0.0 && gl_FragCoord.x < splitPosition) {
23+
discard;
24+
}
25+
#endif
26+
1427
float lightEnum = u_radiiAndDynamicAtmosphereColor.z;
1528
vec3 lightDirection = czm_getDynamicAtmosphereLightDirection(v_outerPositionWC, lightEnum);
1629

0 commit comments

Comments
 (0)