Skip to content

Commit 93b4615

Browse files
authored
Merge pull request #7056 from AnalyticalGraphicsInc/imageryCutoutRectangle
Add the ability to cut out a Rectangle from ImageryLayers
2 parents 5d16b8b + 96eafbe commit 93b4615

8 files changed

+271
-19
lines changed
+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
7+
<meta name="description" content="Demonstration of imagery layers with rectangular cutouts.">
8+
<meta name="cesium-sandcastle-labels" content="Tutorials">
9+
<title>Cesium Demo</title>
10+
<script type="text/javascript" src="../Sandcastle-header.js"></script>
11+
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.20/require.js"></script>
12+
<script type="text/javascript">
13+
require.config({
14+
baseUrl : '../../../Source',
15+
waitSeconds : 60
16+
});
17+
</script>
18+
</head>
19+
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
20+
<style>
21+
@import url(../templates/bucket.css);
22+
</style>
23+
<div id="cesiumContainer" class="fullSize"></div>
24+
<div id="loadingOverlay"><h1>Loading...</h1></div>
25+
<div id="toolbar">
26+
<table class="infoPanel">
27+
<tbody>
28+
<tr>
29+
<td>Click on the Cesium display to start.</td>
30+
</tr>
31+
<tr>
32+
<td>w/s - move cutout north/south</td>
33+
</tr>
34+
<tr>
35+
<td>a/d - move cutout west/east</td>
36+
</tr>
37+
</tbody>
38+
</table>
39+
</div>
40+
<script id="cesium_sandcastle_script">
41+
function startup(Cesium) {
42+
'use strict';
43+
//Sandcastle_Begin
44+
var viewer = new Cesium.Viewer('cesiumContainer', {
45+
imageryProvider : Cesium.createTileMapServiceImageryProvider({
46+
url : Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')
47+
}),
48+
baseLayerPicker : false
49+
});
50+
51+
var canvas = viewer.canvas;
52+
canvas.setAttribute('tabindex', '0'); // needed to put focus on the canvas
53+
canvas.onclick = function() {
54+
canvas.focus();
55+
};
56+
57+
var scene = viewer.scene;
58+
59+
var defaultImageryLayerCutout = Cesium.Rectangle.fromDegrees(-90, 20, -70, 40);
60+
61+
// Cut a rectangle out of the base layer
62+
var layers = viewer.imageryLayers;
63+
var imageryBaseLayer = layers.get(0);
64+
65+
imageryBaseLayer.cutoutRectangle = defaultImageryLayerCutout;
66+
67+
// Fit a SingleTileImageryProvider inside the cutout on the lowest layer
68+
layers.addImageryProvider(new Cesium.SingleTileImageryProvider({
69+
url : '../images/Cesium_Logo_overlay.png',
70+
rectangle : defaultImageryLayerCutout
71+
}));
72+
73+
// Add an Earth at Night layer and a "traveling" cutout
74+
var earthAtNight = layers.addImageryProvider(new Cesium.IonImageryProvider({ assetId: 3812 }));
75+
earthAtNight.cutoutRectangle = Cesium.Rectangle.fromDegrees(-100, 10, -60, 50);
76+
earthAtNight.alpha = 0.9;
77+
78+
// "traveling" code
79+
var flags = {
80+
moveEast : false,
81+
moveWest : false,
82+
moveNorth : false,
83+
moveSouth : false
84+
};
85+
86+
function getFlagForKeyCode(keyCode) {
87+
switch (keyCode) {
88+
case 'W'.charCodeAt(0):
89+
return 'moveNorth';
90+
case 'S'.charCodeAt(0):
91+
return 'moveSouth';
92+
case 'D'.charCodeAt(0):
93+
return 'moveEast';
94+
case 'A'.charCodeAt(0):
95+
return 'moveWest';
96+
default:
97+
return undefined;
98+
}
99+
}
100+
101+
document.addEventListener('keydown', function(e) {
102+
var flagName = getFlagForKeyCode(e.keyCode);
103+
if (typeof flagName !== 'undefined') {
104+
flags[flagName] = true;
105+
}
106+
}, false);
107+
108+
document.addEventListener('keyup', function(e) {
109+
var flagName = getFlagForKeyCode(e.keyCode);
110+
if (typeof flagName !== 'undefined') {
111+
flags[flagName] = false;
112+
}
113+
}, false);
114+
115+
var moveIncrement = 0.05;
116+
viewer.clock.onTick.addEventListener(function(clock) {
117+
var travelingRectangle = earthAtNight.cutoutRectangle;
118+
if (flags.moveNorth && travelingRectangle.north + moveIncrement < Cesium.Math.PI_OVER_TWO) {
119+
travelingRectangle.north += moveIncrement;
120+
travelingRectangle.south += moveIncrement;
121+
}
122+
if (flags.moveSouth && travelingRectangle.south - moveIncrement > -Cesium.Math.PI_OVER_TWO) {
123+
travelingRectangle.north -= moveIncrement;
124+
travelingRectangle.south -= moveIncrement;
125+
}
126+
if (flags.moveEast) {
127+
travelingRectangle.east += moveIncrement;
128+
travelingRectangle.west += moveIncrement;
129+
}
130+
if (flags.moveWest) {
131+
travelingRectangle.east -= moveIncrement;
132+
travelingRectangle.west -= moveIncrement;
133+
}
134+
travelingRectangle.east = wrapLongitude(travelingRectangle.east);
135+
travelingRectangle.west = wrapLongitude(travelingRectangle.west);
136+
});
137+
138+
function wrapLongitude(value) {
139+
if (value < -Cesium.Math.PI) {
140+
return value + Cesium.Math.TWO_PI;
141+
}
142+
if (value > Cesium.Math.PI) {
143+
return value - Cesium.Math.TWO_PI;
144+
}
145+
return value;
146+
}
147+
148+
//Sandcastle_End
149+
Sandcastle.finishedLoading();
150+
}
151+
if (typeof Cesium !== 'undefined') {
152+
startup(Cesium);
153+
} else if (typeof require === 'function') {
154+
require(['Cesium'], startup);
155+
}
156+
</script>
157+
</body>
158+
</html>
11 KB
Loading

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Change Log
55

66
##### Additions :tada:
77
* Added WMS-T (time) support in WebMapServiceImageryProvider [#2581](https://github.com/AnalyticalGraphicsInc/cesium/issues/2581)
8+
* Added `cutoutRectangle` to `ImageryLayer`, which allows cutting out rectangular areas in imagery layers to reveal underlying imagery. [#7056](https://github.com/AnalyticalGraphicsInc/cesium/pull/7056)
89

910
### 1.50 - 2018-10-01
1011

Source/Scene/GlobeSurfaceShaderSet.js

+44-17
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ define([
8888
var enableClippingPlanes = options.enableClippingPlanes;
8989
var clippingPlanes = options.clippingPlanes;
9090
var clippedByBoundaries = options.clippedByBoundaries;
91+
var hasImageryLayerCutout = options.hasImageryLayerCutout;
9192

9293
var quantization = 0;
9394
var quantizationDefine = '';
@@ -113,6 +114,13 @@ define([
113114
cartographicLimitRectangleDefine = 'TILE_LIMIT_RECTANGLE';
114115
}
115116

117+
var imageryCutoutFlag = 0;
118+
var imageryCutoutDefine = '';
119+
if (hasImageryLayerCutout) {
120+
imageryCutoutFlag = 1;
121+
imageryCutoutDefine = 'APPLY_IMAGERY_CUTOUT';
122+
}
123+
116124
var sceneMode = frameState.mode;
117125
var flags = sceneMode |
118126
(applyBrightness << 2) |
@@ -133,7 +141,8 @@ define([
133141
(applySplit << 17) |
134142
(enableClippingPlanes << 18) |
135143
(vertexLogDepth << 19) |
136-
(cartographicLimitRectangleFlag << 20);
144+
(cartographicLimitRectangleFlag << 20) |
145+
(imageryCutoutFlag << 21);
137146

138147
var currentClippingShaderState = 0;
139148
if (defined(clippingPlanes)) {
@@ -166,7 +175,7 @@ define([
166175
}
167176

168177
vs.defines.push(quantizationDefine, vertexLogDepthDefine);
169-
fs.defines.push('TEXTURE_UNITS ' + numberOfDayTextures, cartographicLimitRectangleDefine);
178+
fs.defines.push('TEXTURE_UNITS ' + numberOfDayTextures, cartographicLimitRectangleDefine, imageryCutoutDefine);
170179

171180
if (applyBrightness) {
172181
fs.defines.push('APPLY_BRIGHTNESS');
@@ -233,22 +242,40 @@ define([
233242
{\n\
234243
vec4 color = initialColor;\n';
235244

245+
if (hasImageryLayerCutout) {
246+
computeDayColor += '\
247+
vec4 cutoutAndColorResult;\n\
248+
bool texelUnclipped;\n';
249+
}
250+
236251
for (var i = 0; i < numberOfDayTextures; ++i) {
237-
computeDayColor += '\
238-
color = sampleAndBlend(\n\
239-
color,\n\
240-
u_dayTextures[' + i + '],\n\
241-
u_dayTextureUseWebMercatorT[' + i + '] ? textureCoordinates.xz : textureCoordinates.xy,\n\
242-
u_dayTextureTexCoordsRectangle[' + i + '],\n\
243-
u_dayTextureTranslationAndScale[' + i + '],\n\
244-
' + (applyAlpha ? 'u_dayTextureAlpha[' + i + ']' : '1.0') + ',\n\
245-
' + (applyBrightness ? 'u_dayTextureBrightness[' + i + ']' : '0.0') + ',\n\
246-
' + (applyContrast ? 'u_dayTextureContrast[' + i + ']' : '0.0') + ',\n\
247-
' + (applyHue ? 'u_dayTextureHue[' + i + ']' : '0.0') + ',\n\
248-
' + (applySaturation ? 'u_dayTextureSaturation[' + i + ']' : '0.0') + ',\n\
249-
' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + ',\n\
250-
' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + '\n\
251-
);\n';
252+
if (hasImageryLayerCutout) {
253+
computeDayColor += '\
254+
cutoutAndColorResult = u_dayTextureCutoutRectangles[' + i + '];\n\
255+
texelUnclipped = v_textureCoordinates.x < cutoutAndColorResult.x || cutoutAndColorResult.z < v_textureCoordinates.x || v_textureCoordinates.y < cutoutAndColorResult.y || cutoutAndColorResult.w < v_textureCoordinates.y;\n\
256+
cutoutAndColorResult = sampleAndBlend(\n';
257+
} else {
258+
computeDayColor += '\
259+
color = sampleAndBlend(\n';
260+
}
261+
computeDayColor += '\
262+
color,\n\
263+
u_dayTextures[' + i + '],\n\
264+
u_dayTextureUseWebMercatorT[' + i + '] ? textureCoordinates.xz : textureCoordinates.xy,\n\
265+
u_dayTextureTexCoordsRectangle[' + i + '],\n\
266+
u_dayTextureTranslationAndScale[' + i + '],\n\
267+
' + (applyAlpha ? 'u_dayTextureAlpha[' + i + ']' : '1.0') + ',\n\
268+
' + (applyBrightness ? 'u_dayTextureBrightness[' + i + ']' : '0.0') + ',\n\
269+
' + (applyContrast ? 'u_dayTextureContrast[' + i + ']' : '0.0') + ',\n\
270+
' + (applyHue ? 'u_dayTextureHue[' + i + ']' : '0.0') + ',\n\
271+
' + (applySaturation ? 'u_dayTextureSaturation[' + i + ']' : '0.0') + ',\n\
272+
' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + ',\n\
273+
' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + '\n\
274+
);\n';
275+
if (hasImageryLayerCutout) {
276+
computeDayColor += '\
277+
color = czm_branchFreeTernary(texelUnclipped, cutoutAndColorResult, color);\n';
278+
}
252279
}
253280

254281
computeDayColor += '\

Source/Scene/GlobeSurfaceTileProvider.js

+26-1
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,9 @@ define([
955955
u_dayTextureSplit : function() {
956956
return this.properties.dayTextureSplit;
957957
},
958+
u_dayTextureCutoutRectangles : function() {
959+
return this.properties.dayTextureCutoutRectangles;
960+
},
958961
u_clippingPlanes : function() {
959962
var clippingPlanes = globeSurfaceTileProvider._clippingPlanes;
960963
if (defined(clippingPlanes) && defined(clippingPlanes.texture)) {
@@ -1004,6 +1007,7 @@ define([
10041007
dayTextureSaturation : [],
10051008
dayTextureOneOverGamma : [],
10061009
dayTextureSplit : [],
1010+
dayTextureCutoutRectangles : [],
10071011
dayIntensity : 0.0,
10081012

10091013
southAndNorthLatitude : new Cartesian2(),
@@ -1161,7 +1165,8 @@ define([
11611165
enableFog : undefined,
11621166
enableClippingPlanes : undefined,
11631167
clippingPlanes : undefined,
1164-
clippedByBoundaries : undefined
1168+
clippedByBoundaries : undefined,
1169+
hasImageryLayerCutout : undefined
11651170
};
11661171

11671172
function addDrawCommandsForTile(tileProvider, tile, frameState) {
@@ -1382,6 +1387,7 @@ define([
13821387
var applyGamma = false;
13831388
var applyAlpha = false;
13841389
var applySplit = false;
1390+
var applyCutout = false;
13851391

13861392
while (numberOfDayTextures < maxTextures && imageryIndex < imageryLen) {
13871393
var tileImagery = tileImageryCollection[imageryIndex];
@@ -1442,6 +1448,24 @@ define([
14421448
uniformMapProperties.dayTextureSplit[numberOfDayTextures] = imageryLayer.splitDirection;
14431449
applySplit = applySplit || uniformMapProperties.dayTextureSplit[numberOfDayTextures] !== 0.0;
14441450

1451+
// Update cutout rectangle
1452+
var dayTextureCutoutRectangle = uniformMapProperties.dayTextureCutoutRectangles[numberOfDayTextures];
1453+
if (!defined(dayTextureCutoutRectangle)) {
1454+
dayTextureCutoutRectangle = uniformMapProperties.dayTextureCutoutRectangles[numberOfDayTextures] = new Cartesian4();
1455+
}
1456+
1457+
Cartesian4.clone(Cartesian4.ZERO, dayTextureCutoutRectangle);
1458+
if (defined(imageryLayer.cutoutRectangle)) {
1459+
var cutoutRectangle = clipRectangleAntimeridian(cartographicTileRectangle, imageryLayer.cutoutRectangle);
1460+
var intersection = Rectangle.simpleIntersection(cutoutRectangle, cartographicTileRectangle, rectangleIntersectionScratch);
1461+
applyCutout = defined(intersection) || applyCutout;
1462+
1463+
dayTextureCutoutRectangle.x = (cutoutRectangle.west - cartographicTileRectangle.west) * inverseTileWidth;
1464+
dayTextureCutoutRectangle.y = (cutoutRectangle.south - cartographicTileRectangle.south) * inverseTileHeight;
1465+
dayTextureCutoutRectangle.z = (cutoutRectangle.east - cartographicTileRectangle.west) * inverseTileWidth;
1466+
dayTextureCutoutRectangle.w = (cutoutRectangle.north - cartographicTileRectangle.south) * inverseTileHeight;
1467+
}
1468+
14451469
if (defined(imagery.credits)) {
14461470
var credits = imagery.credits;
14471471
for (var creditIndex = 0, creditLength = credits.length; creditIndex < creditLength; ++creditIndex) {
@@ -1485,6 +1509,7 @@ define([
14851509
surfaceShaderSetOptions.enableFog = applyFog;
14861510
surfaceShaderSetOptions.enableClippingPlanes = clippingPlanesEnabled;
14871511
surfaceShaderSetOptions.clippingPlanes = clippingPlanes;
1512+
surfaceShaderSetOptions.hasImageryLayerCutout = applyCutout;
14881513

14891514
command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(surfaceShaderSetOptions);
14901515
command.castShadows = castShadows;

Source/Scene/ImageryLayer.js

+8
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ define([
157157
* or undefined to show it at all levels. Level zero is the least-detailed level.
158158
* @param {Number} [options.maximumTerrainLevel] The maximum terrain level-of-detail at which to show this imagery layer,
159159
* or undefined to show it at all levels. Level zero is the least-detailed level.
160+
* @param {Rectangle} [options.cutoutRectangle] Cartographic rectangle for cutting out a portion of this ImageryLayer.
160161
*/
161162
function ImageryLayer(imageryProvider, options) {
162163
this._imageryProvider = imageryProvider;
@@ -279,6 +280,13 @@ define([
279280
this._requestImageError = undefined;
280281

281282
this._reprojectComputeCommands = [];
283+
284+
/**
285+
* Rectangle cutout in this layer of imagery.
286+
*
287+
* @type {Rectangle}
288+
*/
289+
this.cutoutRectangle = options.cutoutRectangle;
282290
}
283291

284292
defineProperties(ImageryLayer.prototype, {

Source/Shaders/GlobeFS.glsl

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ uniform float u_dayTextureSaturation[TEXTURE_UNITS];
3333
uniform float u_dayTextureOneOverGamma[TEXTURE_UNITS];
3434
#endif
3535

36+
#ifdef APPLY_IMAGERY_CUTOUT
37+
uniform vec4 u_dayTextureCutoutRectangles[TEXTURE_UNITS];
38+
#endif
39+
3640
uniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS];
3741
#endif
3842

0 commit comments

Comments
 (0)