Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to cut out a Rectangle from ImageryLayers #7056

Merged
merged 5 commits into from
Oct 11, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions Apps/Sandcastle/gallery/Imagery Cutout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="description" content="Demonstration of imagery layers with rectangular cutouts.">
<meta name="cesium-sandcastle-labels" content="Tutorials">
<title>Cesium Demo</title>
<script type="text/javascript" src="../Sandcastle-header.js"></script>
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.20/require.js"></script>
<script type="text/javascript">
require.config({
baseUrl : '../../../Source',
waitSeconds : 60
});
</script>
</head>
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
<style>
@import url(../templates/bucket.css);
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar">
<table class="infoPanel">
<tbody>
<tr>
<td>Click on the Cesium display to start.</td>
</tr>
<tr>
<td>w/s - move cutout north/south</td>
</tr>
<tr>
<td>a/d - move cutout west/east</td>
</tr>
</tbody>
</table>
</div>
<script id="cesium_sandcastle_script">
function startup(Cesium) {
'use strict';
//Sandcastle_Begin
var viewer = new Cesium.Viewer('cesiumContainer', {
imageryProvider : Cesium.createTileMapServiceImageryProvider({
url : Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')
}),
baseLayerPicker : false
});

var canvas = viewer.canvas;
canvas.setAttribute('tabindex', '0'); // needed to put focus on the canvas
canvas.onclick = function() {
canvas.focus();
};

var scene = viewer.scene;

var defaultImageryLayerCutout = Cesium.Rectangle.fromDegrees(-90, 20, -70, 40);

// Cut a rectangle out of the base layer
var layers = viewer.imageryLayers;
var imageryBaseLayer = layers.get(0);

imageryBaseLayer.cutoutRectangle = defaultImageryLayerCutout;

// Fit a SingleTileImageryProvider inside the cutout on the lowest layer
layers.addImageryProvider(new Cesium.SingleTileImageryProvider({
url : '../images/Cesium_Logo_overlay.png',
rectangle : defaultImageryLayerCutout
}));

// Add an Earth at Night layer and a "traveling" cutout
var earthAtNight = layers.addImageryProvider(new Cesium.IonImageryProvider({ assetId: 3812 }));
earthAtNight.cutoutRectangle = Cesium.Rectangle.fromDegrees(-100, 10, -60, 50);
earthAtNight.alpha = 0.9;

// "traveling" code
var flags = {
moveEast : false,
moveWest : false,
moveNorth : false,
moveSouth : false
};

function getFlagForKeyCode(keyCode) {
switch (keyCode) {
case 'W'.charCodeAt(0):
return 'moveNorth';
case 'S'.charCodeAt(0):
return 'moveSouth';
case 'D'.charCodeAt(0):
return 'moveEast';
case 'A'.charCodeAt(0):
return 'moveWest';
default:
return undefined;
}
}

document.addEventListener('keydown', function(e) {
var flagName = getFlagForKeyCode(e.keyCode);
if (typeof flagName !== 'undefined') {
flags[flagName] = true;
}
}, false);

document.addEventListener('keyup', function(e) {
var flagName = getFlagForKeyCode(e.keyCode);
if (typeof flagName !== 'undefined') {
flags[flagName] = false;
}
}, false);

var moveIncrement = 0.05;
viewer.clock.onTick.addEventListener(function(clock) {
var travelingRectangle = earthAtNight.cutoutRectangle;
if (flags.moveNorth && travelingRectangle.north + moveIncrement < Cesium.Math.PI_OVER_TWO) {
travelingRectangle.north += moveIncrement;
travelingRectangle.south += moveIncrement;
}
if (flags.moveSouth && travelingRectangle.south - moveIncrement > -Cesium.Math.PI_OVER_TWO) {
travelingRectangle.north -= moveIncrement;
travelingRectangle.south -= moveIncrement;
}
if (flags.moveEast) {
travelingRectangle.east += moveIncrement;
travelingRectangle.west += moveIncrement;
}
if (flags.moveWest) {
travelingRectangle.east -= moveIncrement;
travelingRectangle.west -= moveIncrement;
}
travelingRectangle.east = wrapLongitude(travelingRectangle.east);
travelingRectangle.west = wrapLongitude(travelingRectangle.west);
});

function wrapLongitude(value) {
if (value < -Cesium.Math.PI) {
return value + Cesium.Math.TWO_PI;
}
if (value > Cesium.Math.PI) {
return value - Cesium.Math.TWO_PI;
}
return value;
}

//Sandcastle_End
Sandcastle.finishedLoading();
}
if (typeof Cesium !== 'undefined') {
startup(Cesium);
} else if (typeof require === 'function') {
require(['Cesium'], startup);
}
</script>
</body>
</html>
Binary file added Apps/Sandcastle/gallery/Imagery Cutout.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Change Log

##### Additions :tada:
* Added WMS-T (time) support in WebMapServiceImageryProvider [#2581](https://github.com/AnalyticalGraphicsInc/cesium/issues/2581)
* 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)

### 1.50 - 2018-10-01

Expand Down
61 changes: 44 additions & 17 deletions Source/Scene/GlobeSurfaceShaderSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ define([
var enableClippingPlanes = options.enableClippingPlanes;
var clippingPlanes = options.clippingPlanes;
var clippedByBoundaries = options.clippedByBoundaries;
var hasImageryLayerCutout = options.hasImageryLayerCutout;

var quantization = 0;
var quantizationDefine = '';
Expand All @@ -113,6 +114,13 @@ define([
cartographicLimitRectangleDefine = 'TILE_LIMIT_RECTANGLE';
}

var imageryCutoutFlag = 0;
var imageryCutoutDefine = '';
if (hasImageryLayerCutout) {
imageryCutoutFlag = 1;
imageryCutoutDefine = 'APPLY_IMAGERY_CUTOUT';
}

var sceneMode = frameState.mode;
var flags = sceneMode |
(applyBrightness << 2) |
Expand All @@ -133,7 +141,8 @@ define([
(applySplit << 17) |
(enableClippingPlanes << 18) |
(vertexLogDepth << 19) |
(cartographicLimitRectangleFlag << 20);
(cartographicLimitRectangleFlag << 20) |
(imageryCutoutFlag << 21);

var currentClippingShaderState = 0;
if (defined(clippingPlanes)) {
Expand Down Expand Up @@ -166,7 +175,7 @@ define([
}

vs.defines.push(quantizationDefine, vertexLogDepthDefine);
fs.defines.push('TEXTURE_UNITS ' + numberOfDayTextures, cartographicLimitRectangleDefine);
fs.defines.push('TEXTURE_UNITS ' + numberOfDayTextures, cartographicLimitRectangleDefine, imageryCutoutDefine);

if (applyBrightness) {
fs.defines.push('APPLY_BRIGHTNESS');
Expand Down Expand Up @@ -233,22 +242,40 @@ define([
{\n\
vec4 color = initialColor;\n';

if (hasImageryLayerCutout) {
computeDayColor += '\
vec4 cutoutAndColorResult;\n\
bool texelUnclipped;\n';
}

for (var i = 0; i < numberOfDayTextures; ++i) {
computeDayColor += '\
color = sampleAndBlend(\n\
color,\n\
u_dayTextures[' + i + '],\n\
u_dayTextureUseWebMercatorT[' + i + '] ? textureCoordinates.xz : textureCoordinates.xy,\n\
u_dayTextureTexCoordsRectangle[' + i + '],\n\
u_dayTextureTranslationAndScale[' + i + '],\n\
' + (applyAlpha ? 'u_dayTextureAlpha[' + i + ']' : '1.0') + ',\n\
' + (applyBrightness ? 'u_dayTextureBrightness[' + i + ']' : '0.0') + ',\n\
' + (applyContrast ? 'u_dayTextureContrast[' + i + ']' : '0.0') + ',\n\
' + (applyHue ? 'u_dayTextureHue[' + i + ']' : '0.0') + ',\n\
' + (applySaturation ? 'u_dayTextureSaturation[' + i + ']' : '0.0') + ',\n\
' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + ',\n\
' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + '\n\
);\n';
if (hasImageryLayerCutout) {
computeDayColor += '\
cutoutAndColorResult = u_dayTextureCutoutRectangles[' + i + '];\n\
texelUnclipped = v_textureCoordinates.x < cutoutAndColorResult.x || cutoutAndColorResult.z < v_textureCoordinates.x || v_textureCoordinates.y < cutoutAndColorResult.y || cutoutAndColorResult.w < v_textureCoordinates.y;\n\
cutoutAndColorResult = sampleAndBlend(\n';
} else {
computeDayColor += '\
color = sampleAndBlend(\n';
}
computeDayColor += '\
color,\n\
u_dayTextures[' + i + '],\n\
u_dayTextureUseWebMercatorT[' + i + '] ? textureCoordinates.xz : textureCoordinates.xy,\n\
u_dayTextureTexCoordsRectangle[' + i + '],\n\
u_dayTextureTranslationAndScale[' + i + '],\n\
' + (applyAlpha ? 'u_dayTextureAlpha[' + i + ']' : '1.0') + ',\n\
' + (applyBrightness ? 'u_dayTextureBrightness[' + i + ']' : '0.0') + ',\n\
' + (applyContrast ? 'u_dayTextureContrast[' + i + ']' : '0.0') + ',\n\
' + (applyHue ? 'u_dayTextureHue[' + i + ']' : '0.0') + ',\n\
' + (applySaturation ? 'u_dayTextureSaturation[' + i + ']' : '0.0') + ',\n\
' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + ',\n\
' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + '\n\
);\n';
if (hasImageryLayerCutout) {
computeDayColor += '\
color = czm_branchFreeTernary(texelUnclipped, cutoutAndColorResult, color);\n';
}
}

computeDayColor += '\
Expand Down
27 changes: 26 additions & 1 deletion Source/Scene/GlobeSurfaceTileProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,9 @@ define([
u_dayTextureSplit : function() {
return this.properties.dayTextureSplit;
},
u_dayTextureCutoutRectangles : function() {
return this.properties.dayTextureCutoutRectangles;
},
u_clippingPlanes : function() {
var clippingPlanes = globeSurfaceTileProvider._clippingPlanes;
if (defined(clippingPlanes) && defined(clippingPlanes.texture)) {
Expand Down Expand Up @@ -1004,6 +1007,7 @@ define([
dayTextureSaturation : [],
dayTextureOneOverGamma : [],
dayTextureSplit : [],
dayTextureCutoutRectangles : [],
dayIntensity : 0.0,

southAndNorthLatitude : new Cartesian2(),
Expand Down Expand Up @@ -1161,7 +1165,8 @@ define([
enableFog : undefined,
enableClippingPlanes : undefined,
clippingPlanes : undefined,
clippedByBoundaries : undefined
clippedByBoundaries : undefined,
hasImageryLayerCutout : undefined
};

function addDrawCommandsForTile(tileProvider, tile, frameState) {
Expand Down Expand Up @@ -1382,6 +1387,7 @@ define([
var applyGamma = false;
var applyAlpha = false;
var applySplit = false;
var applyCutout = false;

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

// Update cutout rectangle
var dayTextureCutoutRectangle = uniformMapProperties.dayTextureCutoutRectangles[numberOfDayTextures];
if (!defined(dayTextureCutoutRectangle)) {
dayTextureCutoutRectangle = uniformMapProperties.dayTextureCutoutRectangles[numberOfDayTextures] = new Cartesian4();
}

Cartesian4.clone(Cartesian4.ZERO, dayTextureCutoutRectangle);
if (defined(imageryLayer.cutoutRectangle)) {
var cutoutRectangle = clipRectangleAntimeridian(cartographicTileRectangle, imageryLayer.cutoutRectangle);
var intersection = Rectangle.simpleIntersection(cutoutRectangle, cartographicTileRectangle, rectangleIntersectionScratch);
applyCutout = defined(intersection) || applyCutout;

dayTextureCutoutRectangle.x = (cutoutRectangle.west - cartographicTileRectangle.west) * inverseTileWidth;
dayTextureCutoutRectangle.y = (cutoutRectangle.south - cartographicTileRectangle.south) * inverseTileHeight;
dayTextureCutoutRectangle.z = (cutoutRectangle.east - cartographicTileRectangle.west) * inverseTileWidth;
dayTextureCutoutRectangle.w = (cutoutRectangle.north - cartographicTileRectangle.south) * inverseTileHeight;
}

if (defined(imagery.credits)) {
var credits = imagery.credits;
for (var creditIndex = 0, creditLength = credits.length; creditIndex < creditLength; ++creditIndex) {
Expand Down Expand Up @@ -1485,6 +1509,7 @@ define([
surfaceShaderSetOptions.enableFog = applyFog;
surfaceShaderSetOptions.enableClippingPlanes = clippingPlanesEnabled;
surfaceShaderSetOptions.clippingPlanes = clippingPlanes;
surfaceShaderSetOptions.hasImageryLayerCutout = applyCutout;

command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(surfaceShaderSetOptions);
command.castShadows = castShadows;
Expand Down
8 changes: 8 additions & 0 deletions Source/Scene/ImageryLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ define([
* or undefined to show it at all levels. Level zero is the least-detailed level.
* @param {Number} [options.maximumTerrainLevel] The maximum terrain level-of-detail at which to show this imagery layer,
* or undefined to show it at all levels. Level zero is the least-detailed level.
* @param {Rectangle} [options.cutoutRectangle] Cartographic rectangle for cutting out a portion of this ImageryLayer.
*/
function ImageryLayer(imageryProvider, options) {
this._imageryProvider = imageryProvider;
Expand Down Expand Up @@ -279,6 +280,13 @@ define([
this._requestImageError = undefined;

this._reprojectComputeCommands = [];

/**
* Rectangle cutout in this layer of imagery.
*
* @type {Rectangle}
*/
this.cutoutRectangle = options.cutoutRectangle;
}

defineProperties(ImageryLayer.prototype, {
Expand Down
4 changes: 4 additions & 0 deletions Source/Shaders/GlobeFS.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ uniform float u_dayTextureSaturation[TEXTURE_UNITS];
uniform float u_dayTextureOneOverGamma[TEXTURE_UNITS];
#endif

#ifdef APPLY_IMAGERY_CUTOUT
uniform vec4 u_dayTextureCutoutRectangles[TEXTURE_UNITS];
#endif

uniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS];
#endif

Expand Down
Loading