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 geographic limit rectangle #6987

Merged
merged 6 commits into from
Sep 10, 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
88 changes: 88 additions & 0 deletions Apps/Sandcastle/gallery/Geographic Limit Rectangle.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<!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="Use Viewer to start building new applications or easily embed Cesium into existing applications.">
<meta name="cesium-sandcastle-labels" content="Showcases">
<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">
if(typeof require === 'function') {
require.config({
baseUrl : '../../../Source',
waitSeconds : 120
});
}
</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"></div>
<script id="cesium_sandcastle_script">
function startup(Cesium) {
'use strict';
//Sandcastle_Begin
var viewer = new Cesium.Viewer('cesiumContainer', {
terrainProvider: Cesium.createWorldTerrain()
});

// Tropics of Cancer and Capricorn
var coffeeBeltRectangle = Cesium.Rectangle.fromDegrees(-180, -23.43687, 180, 23.43687);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Append .0 when the intention is floating point.

Throughout.


viewer.scene.globe.geographicLimitRectangle = coffeeBeltRectangle;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be called "cartographicLimitRectangle" given Cesium's Cartographic type? Same question for this filename and throughout.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or just limitRectangle, cullRectangle, or whatever language is consistent with the rest of Cesium?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's go with cartographicLimitRectangle.

viewer.scene.skyAtmosphere.show = false;

// Add rectangles to show bounds
var rectangles = [];

for (var i = 0; i < 10; i++) {
rectangles.push(viewer.entities.add({
name : 'EPSG 2093 bounds',
rectangle : {
coordinates : coffeeBeltRectangle,
material : Cesium.Color.WHITE.withAlpha(0.0),
height : i * 5000.0,
outline : true,
outlineWidth : 4.0,
outlineColor : Cesium.Color.WHITE
}
}));
}

Sandcastle.addToolbarButton('Show/Hide Bounds', function() {
var rectanglesLength = rectangles.length;
for (var i = 0; i < rectanglesLength; i++) {
var rectangleEntity = rectangles[i];
rectangleEntity.show = !rectangleEntity.show;
}
});

var limited = true;
Sandcastle.addToolbarButton('enable/disable limiter', function() {
if (limited) {
viewer.scene.globe.geographicLimitRectangle = Cesium.Rectangle.MAX_VALUE;
limited = false;
} else {
viewer.scene.globe.geographicLimitRectangle = coffeeBeltRectangle;
limited = true;
}
});

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

### 1.50 - 2018-10-01

##### Additions :tada:
* Added `geographicLimitRectangle` to `Globe`. Use this to limit terrain and imagery to a specific `Rectangle` area. [#6987](https://github.com/AnalyticalGraphicsInc/cesium/pull/6987)

### 1.49 - 2018-09-04

##### Breaking Changes :mega:
Expand Down
8 changes: 8 additions & 0 deletions Source/Scene/Globe.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,14 @@ define([
this._surface.tileProvider.clippingPlanes = value;
}
},
geographicLimitRectangle : {
get : function() {
return this._surface.tileProvider.geographicLimitRectangle;
},
set : function(value) {
this._surface.tileProvider.geographicLimitRectangle = value;
}
},
/**
* The normal map to use for rendering waves in the ocean. Setting this property will
* only have an effect if the configured terrain provider includes a water mask.
Expand Down
14 changes: 11 additions & 3 deletions Source/Scene/GlobeSurfaceShaderSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ define([
return useWebMercatorProjection ? get2DYPositionFractionMercatorProjection : get2DYPositionFractionGeographicProjection;
}

GlobeSurfaceShaderSet.prototype.getShaderProgram = function(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, showReflectiveOcean, showOceanWaves, enableLighting, hasVertexNormals, useWebMercatorProjection, enableFog, enableClippingPlanes, clippingPlanes) {
GlobeSurfaceShaderSet.prototype.getShaderProgram = function(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, showReflectiveOcean, showOceanWaves, enableLighting, hasVertexNormals, useWebMercatorProjection, enableFog, enableClippingPlanes, clippingPlanes, clippedByBoundaries) {
var quantization = 0;
var quantizationDefine = '';

Expand All @@ -84,6 +84,13 @@ define([
vertexLogDepthDefine = 'DISABLE_GL_POSITION_LOG_DEPTH';
}

var geographicLimitRectangleFlag = 0;
var geographicLimitRectangleDefine = '';
if (clippedByBoundaries) {//} && frameState.mode !== SceneMode.SCENE3D) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented out code.

geographicLimitRectangleFlag = 1;
geographicLimitRectangleDefine = 'TILE_LIMIT_RECTANGLE';
}

var sceneMode = frameState.mode;
var flags = sceneMode |
(applyBrightness << 2) |
Expand All @@ -101,7 +108,8 @@ define([
(quantization << 14) |
(applySplit << 15) |
(enableClippingPlanes << 16) |
(vertexLogDepth << 17);
(vertexLogDepth << 17) |
(geographicLimitRectangleFlag << 18);

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

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

if (applyBrightness) {
fs.defines.push('APPLY_BRIGHTNESS');
Expand Down
2 changes: 2 additions & 0 deletions Source/Scene/GlobeSurfaceTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ define([

this.surfaceShader = undefined;
this.isClipped = true;

this.clippedByBoundaries = false;
}

defineProperties(GlobeSurfaceTile.prototype, {
Expand Down
62 changes: 60 additions & 2 deletions Source/Scene/GlobeSurfaceTileProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ define([
'../Core/Cartesian2',
'../Core/Cartesian3',
'../Core/Cartesian4',
'../Core/Cartographic',
'../Core/Color',
'../Core/ColorGeometryInstanceAttribute',
'../Core/combine',
Expand Down Expand Up @@ -50,6 +51,7 @@ define([
Cartesian2,
Cartesian3,
Cartesian4,
Cartographic,
Color,
ColorGeometryInstanceAttribute,
combine,
Expand Down Expand Up @@ -168,6 +170,13 @@ define([
* @private
*/
this._clippingPlanes = undefined;

/**
* A property specifying a {@link Rectangle} used to selectively prevent tiles outside a region from loading.
* For limiting terrain in scenes that use custom projections or Proj4JS projections that cause overlapping tiles.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove the line about custom projections since this would likely get merged before support is added for them and that is not the only use case.

Prevents tiles from loading and also clips tiles on the boundary?

* @type {Rectangle}
*/
this.geographicLimitRectangle = Rectangle.clone(Rectangle.MAX_VALUE);
}

defineProperties(GlobeSurfaceTileProvider.prototype, {
Expand Down Expand Up @@ -509,6 +518,24 @@ define([
};

var boundingSphereScratch = new BoundingSphere();
var rectangleIntersectionScratch = new Rectangle();
var splitGeographicLimitRectangleScratch = new Rectangle();
var rectangleCenterScratch = new Cartographic();

// geographicLimitRectangle may span the IDL, but tiles never will.
function clipRectangleAntimeridian(tileRectangle, geographicLimitRectangle) {
if (geographicLimitRectangle.west < geographicLimitRectangle.east) {
return geographicLimitRectangle;
}
var splitRectangle = Rectangle.clone(geographicLimitRectangle, splitGeographicLimitRectangleScratch);
var tileCenter = Rectangle.center(tileRectangle, rectangleCenterScratch);
if (tileCenter.longitude > 0.0) {
splitRectangle.east = CesiumMath.PI;
} else {
splitRectangle.west = -CesiumMath.PI;
}
return splitRectangle;
}

/**
* Determines the visibility of a given tile. The tile may be fully visible, partially visible, or not
Expand Down Expand Up @@ -536,6 +563,17 @@ define([
var cullingVolume = frameState.cullingVolume;
var boundingVolume = defaultValue(surfaceTile.orientedBoundingBox, surfaceTile.boundingSphere3D);

// Check if the tile is outside the limit area in cartographic space
surfaceTile.clippedByBoundaries = false;
var clippedGeographicLimitRectangle = clipRectangleAntimeridian(tile.rectangle, this.geographicLimitRectangle);
var areaLimitIntersection = Rectangle.simpleIntersection(clippedGeographicLimitRectangle, tile.rectangle, rectangleIntersectionScratch);
if (!defined(areaLimitIntersection)) {
return Visibility.NONE;
}
if (!Rectangle.equals(areaLimitIntersection, tile.rectangle)) {
surfaceTile.clippedByBoundaries = true;
}

if (frameState.mode !== SceneMode.SCENE3D) {
boundingVolume = boundingSphereScratch;
BoundingSphere.fromRectangleWithHeights2D(tile.rectangle, frameState.mapProjection, surfaceTile.minimumHeight, surfaceTile.maximumHeight, boundingVolume);
Expand Down Expand Up @@ -580,6 +618,7 @@ define([
var modifiedModelViewScratch = new Matrix4();
var modifiedModelViewProjectionScratch = new Matrix4();
var tileRectangleScratch = new Cartesian4();
var localizedGeographicLimitRectangleScratch = new Cartesian4();
var rtcScratch = new Cartesian3();
var centerEyeScratch = new Cartesian3();
var southwestScratch = new Cartesian3();
Expand Down Expand Up @@ -921,6 +960,9 @@ define([
}
return frameState.context.defaultTexture;
},
u_geographicLimitRectangle : function() {
return this.properties.localizedGeographicLimitRectangle;
},
u_clippingPlanesMatrix : function() {
var clippingPlanes = globeSurfaceTileProvider._clippingPlanes;
return defined(clippingPlanes) ? Matrix4.multiply(frameState.context.uniformState.view, clippingPlanes.modelMatrix, scratchClippingPlaneMatrix) : Matrix4.IDENTITY;
Expand Down Expand Up @@ -969,7 +1011,9 @@ define([
minMaxHeight : new Cartesian2(),
scaleAndBias : new Matrix4(),
clippingPlanesEdgeColor : Color.clone(Color.WHITE),
clippingPlanesEdgeWidth : 0.0
clippingPlanesEdgeWidth : 0.0,

localizedGeographicLimitRectangle : new Cartesian4()
}
};

Expand Down Expand Up @@ -1255,6 +1299,20 @@ define([
uniformMapProperties.southMercatorYAndOneOverHeight.x = southMercatorY;
uniformMapProperties.southMercatorYAndOneOverHeight.y = oneOverMercatorHeight;

// Convert tile limiter rectangle from cartographic to texture space using the tileRectangle.
var localizedGeographicLimitRectangle = localizedGeographicLimitRectangleScratch;
var geographicLimitRectangle = clipRectangleAntimeridian(tile.rectangle, tileProvider.geographicLimitRectangle);

var cartographicTileRectangle = tile.rectangle;
var inverseTileWidth = 1.0 / cartographicTileRectangle.width;
var inverseTileHeight = 1.0 / cartographicTileRectangle.height;
localizedGeographicLimitRectangle.x = (geographicLimitRectangle.west - cartographicTileRectangle.west) * inverseTileWidth;
localizedGeographicLimitRectangle.y = (geographicLimitRectangle.south - cartographicTileRectangle.south) * inverseTileHeight;
localizedGeographicLimitRectangle.z = (geographicLimitRectangle.east - cartographicTileRectangle.west) * inverseTileWidth;
localizedGeographicLimitRectangle.w = (geographicLimitRectangle.north - cartographicTileRectangle.south) * inverseTileHeight;

Cartesian4.clone(localizedGeographicLimitRectangle, uniformMapProperties.localizedGeographicLimitRectangle);

// For performance, use fog in the shader only when the tile is in fog.
var applyFog = enableFog && CesiumMath.fog(tile._distance, frameState.fog.density) > CesiumMath.EPSILON3;

Expand Down Expand Up @@ -1357,7 +1415,7 @@ define([
uniformMap = combine(uniformMap, tileProvider.uniformMap);
}

command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog, clippingPlanesEnabled, clippingPlanes);
command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog, clippingPlanesEnabled, clippingPlanes, surfaceTile.clippedByBoundaries);
command.castShadows = castShadows;
command.receiveShadows = receiveShadows;
command.renderState = renderState;
Expand Down
13 changes: 13 additions & 0 deletions Source/Shaders/GlobeFS.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ uniform sampler2D u_oceanNormalMap;
uniform vec2 u_lightingFadeDistance;
#endif

#ifdef TILE_LIMIT_RECTANGLE
uniform vec4 u_geographicLimitRectangle;
#endif

#ifdef ENABLE_CLIPPING_PLANES
uniform sampler2D u_clippingPlanes;
uniform mat4 u_clippingPlanesMatrix;
Expand Down Expand Up @@ -155,6 +159,15 @@ vec4 computeWaterColor(vec3 positionEyeCoordinates, vec2 textureCoordinates, mat

void main()
{

#ifdef TILE_LIMIT_RECTANGLE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to add a fast reject case to the vertex shader so that if the entire tile is outside the region, the vertex is moved beyond the camera like we do for billboards, etc.?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be necessary, the limiter is tied into tileset visibility computation. Tiles completely outside bounds won't get drawn and tiles completely inside bounds won't receive shader modification.

if (v_textureCoordinates.x < u_geographicLimitRectangle.x || u_geographicLimitRectangle.z < v_textureCoordinates.x ||
v_textureCoordinates.y < u_geographicLimitRectangle.y || u_geographicLimitRectangle.w < v_textureCoordinates.y)
{
discard;
}
#endif

#ifdef ENABLE_CLIPPING_PLANES
float clipDistance = clip(gl_FragCoord, u_clippingPlanes, u_clippingPlanesMatrix);
#endif
Expand Down
Loading