Skip to content

Commit

Permalink
Merge pull request #7774 from loshjawrence/staging-3dtiles-streaming-…
Browse files Browse the repository at this point in the history
…optimizations

3DTiles streaming optimizations
  • Loading branch information
lilleyse authored Apr 26, 2019
2 parents 9d2aef3 + 7e6c20f commit ab441f2
Show file tree
Hide file tree
Showing 28 changed files with 2,153 additions and 583 deletions.
211 changes: 211 additions & 0 deletions Apps/Sandcastle/gallery/development/3D Tiles Performance Testing.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
<!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="Measure 3D Tiles streaming and rendering performance.">
<meta name="cesium-sandcastle-labels" content="Development">
<title>Streaming Performance Testing</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
/*
This Sandcastle makes it easy to test streaming performance for 3D Tiles & terrain. `startTest()` will begin a
camera tour, and end once both the tileset has finish resolving in the final view.
It is better to host locally with throttling and disabled cache (f12, networktab).
You can add more flights to destinationFunctions to change the tour or make it longer.
The heatmapTileProperty will colorize the tile property in a heatmap. Booleans should set a reference min/max of -1,1 to help with coloring.
*/
var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;
var camera = scene.camera;
var globe = scene.globe;
var statistics = Cesium.RequestScheduler.statistics;
var Cartesian3 = Cesium.Cartesian3;

var tourTime = 0;
var tourLoads = 0;
var destinationFunctions = [];
var lastTotalLoaded = 0;
var flightDuration = 8.0;
var doTour = true;
var currentDestination = 0;

var referenceMinimum = new Cesium.JulianDate();
var referenceMaximum = new Cesium.JulianDate();
var heatmapTileProperty = '_foveatedFactor';

var tileset = new Cesium.Cesium3DTileset({
url: Cesium.IonResource.fromAssetId(5741),
debugHeatmapTilePropertyName: heatmapTileProperty
});

function updateReferenceMinMax() {
if (heatmapTileProperty === '_loadTimestamp') {
Cesium.JulianDate.now(referenceMinimum);
var viewLoadTime = 10;
Cesium.JulianDate.addSeconds(referenceMinimum, viewLoadTime, referenceMaximum);
tileset._heatmap.setReferenceMinimumMaximum(referenceMinimum, referenceMaximum, heatmapTileProperty);
} else if (heatmapTileProperty === '_priorityDeferred') {
tileset._heatmap.setReferenceMinimumMaximum(-1, 1, heatmapTileProperty);
}
}

viewer.scene.primitives.add(tileset);

destinationFunctions[0] = function(){
tourTime = 0;
updateReferenceMinMax();
camera.flyTo({
destination : new Cartesian3(1333596.036282181, -4655169.681831507, 4137566.3043841794),
orientation : {
direction : new Cartesian3(0.16082862107778806, 0.8832766751525227, 0.4404048929947557),
up : new Cartesian3(0.27688172689171486, -0.4686726309748134, 0.8388578391411791)
},
duration : 0,
easingFunction: Cesium.EasingFunction.LINEAR_NONE
});
startTimer();
};

destinationFunctions[1] = function(){
updateReferenceMinMax();
camera.flyTo({
destination : new Cartesian3(1334667.3697728787, -4654198.808294234, 4137970.3278586734),
orientation : {
direction : new Cartesian3(-0.27073345520322445, 0.8195770495850765, 0.504972133911511),
up : new Cartesian3(0.12792976837875633, -0.48927851021971713, 0.8626937543530335)
},
duration : flightDuration,
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
maximumHeight : 100
});
startTimer();
};

destinationFunctions[2] = function(){
updateReferenceMinMax();
camera.flyTo({
destination : new Cartesian3(1334615.6546409938, -4653003.089826743, 4139331.5003454844),
orientation : {
direction : new Cartesian3(-0.2708199805903497, 0.8196978379289465, 0.5047296232713642),
up : new Cartesian3(0.12789117766285887, -0.48903793608573193, 0.8628358730054139)
},
duration : flightDuration,
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
maximumHeight : 100
});
startTimer();
};

destinationFunctions[3] = function(){
console.log('Total Loads and Time (ignoring first view and flight time): ' + tourLoads + ', ' + tourTime);
};

viewer.scene.debugShowFramesPerSecond = true;

Sandcastle.addToolbarButton('Start Test', function() {
currentDestination = 0;
tourLoads = 0;
tourTime = 0;
doTour = true;
lastTotalLoaded = 0;
destinationFunctions[0]();
});

Sandcastle.addToolbarButton('View 0', function() {
destinationFunctions[0]();
});

Sandcastle.addToolbarButton('View 1', function() {
destinationFunctions[1]();
});

Sandcastle.addToolbarButton('View 2', function() {
destinationFunctions[2]();
});

function startTimer() {
var timerStart = window.performance.now();
var timerListener = function() {
if (camera._currentFlight !== undefined) {
tileset.allTilesLoaded.removeEventListener(timerListener);
camera.moveEnd.addEventListener(timerListener);
return;
} else if (!tileset._tilesLoaded) {
return;
}
var timerEnd = window.performance.now();
var duration = (timerEnd - timerStart) / 1000.0;
var totalLoaded = tileset._statistics.numberOfLoadedTilesTotal;
duration -= currentDestination === 0 ? 0 : flightDuration;
var flightLoads = totalLoaded - lastTotalLoaded;
console.log('view ' + currentDestination + ' flight loads, final view time: ' + flightLoads + ', ' + duration);
lastTotalLoaded = totalLoaded;
tourTime += currentDestination === 0 ? 0 : duration;
tourLoads += currentDestination === 0 ? 0 : flightLoads;
if (doTour && currentDestination < destinationFunctions.length - 1) {
destinationFunctions[++currentDestination]();
}
tileset.allTilesLoaded.removeEventListener(timerListener);
camera.moveEnd.removeEventListener(timerListener);
};
window.setTimeout(function() {
tileset.allTilesLoaded.addEventListener(timerListener);
}, 50);
}

// Add code for flyto
Sandcastle.addToolbarButton('get cam', function() {
console.log('requested params for current camera view');
var position = camera.position;
var direction = camera.direction;
var up = camera.up;

console.log('\n\
Sandcastle.addToolbarButton(VIEW, function() {\n\
camera.flyTo({\n\
destination : new Cartesian3(' + position.x + ', ' + position.y + ', ' + position.z + '),\n\
orientation : {\n\
direction : new Cartesian3(' + direction.x + ', ' + direction.y + ', ' + direction.z + '),\n\
up : new Cartesian3(' + up.x + ', ' + up.y + ', ' + up.z + '),\n\
},\n\
duration : flightDuration,\n\
easingFunction: Cesium.EasingFunction.LINEAR_NONE,\n\
});\n\
timeAll();\n\
});');
});//Sandcastle_End
Sandcastle.finishedLoading();
}
if (typeof Cesium !== "undefined") {
startup(Cesium);
} else if (typeof require === "function") {
require(["Cesium"], startup);
}
</script>
</body>
</html>
14 changes: 14 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,25 @@ Change Log
### 1.57 - 2019-05-01

##### Additions :tada:
* Improved 3D Tiles streaming performance, resulting in ~67% camera tour load time reduction, ~44% camera tour load count reduction. And for general camera movement, ~20% load time reduction with ~27% tile load count reduction. Tile load priority changed to focus on loading tiles in the center of the screen first. Added the following tileset optimizations, which unless stated otherwise are enabled by default. [#7774](https://github.com/AnalyticalGraphicsInc/cesium/pull/7774)
* Added `Cesium3DTileset.cullRequestsWhileMoving` option to ignore requests for tiles that will likely be out-of-view due to the camera's movement when they come back from the server.
* Added `Cesium3DTileset.cullRequestsWhileMovingMultiplier` option to act as a multiplier when used in culling requests while moving. Larger is more aggressive culling, smaller less aggressive culling.
* Added `Cesium3DTileset.preloadFlightDestinations` option to preload tiles at the camera's flight destination while the camera is in flight.
* Added `Cesium3DTileset.preferLeaves` option to prefer loading of leaves. Good for additive refinement point clouds. Set to `false` by default.
* Added `Cesium3DTileset.progressiveResolutionHeightFraction` option to load tiles at a smaller resolution first. This can help get a quick layer of tiles down while full resolution tiles continue to load.
* Added `Cesium3DTileset.foveatedScreenSpaceError` option to prioritize loading tiles in the center of the screen.
* Added `Cesium3DTileset.foveatedConeSize` option to control the cone size that determines which tiles are deferred for loading. Tiles outside the cone are potentially deferred.
* Added `Cesium3DTileset.foveatedMinimumScreenSpaceErrorRelaxation` option to control the starting screen space error relaxation for tiles outside the foveated cone.
* Added `Cesium3DTileset.foveatedInterpolationCallback` option to control how screen space error threshold is interpolated for tiles outside the foveated cone.
* Added `Cesium3DTileset.foveatedTimeDelay` option to control how long in seconds to wait after the camera stops moving before deferred tiles start loading in.
* Added new parameter to `PolylineGlowMaterial` called `taperPower`, that works similar to the existing `glowPower` parameter, to taper the back of the line away. [#7626](https://github.com/AnalyticalGraphicsInc/cesium/pull/7626)
* Added `Cesium3DTileset.preloadWhenHidden` tileset option to preload tiles when `tileset.show` is false. Loads tiles as if the tileset is visible but does not render them. [#7774](https://github.com/AnalyticalGraphicsInc/cesium/pull/7774)
* Added support for the `KHR_texture_transform` glTF extension. [#7549](https://github.com/AnalyticalGraphicsInc/cesium/pull/7549)
* Added functions to remove samples from `SampledProperty` and `SampledPositionProperty`. [#7723](https://github.com/AnalyticalGraphicsInc/cesium/pull/7723)
* Added support for color-to-alpha with a threshold on imagery layers. [#7727](https://github.com/AnalyticalGraphicsInc/cesium/pull/7727)
* Add CZML processing for `heightReference` and `extrudedHeightReference` for geoemtry types that support it.
* `CesiumMath.toSNorm` documentation changed to reflect the function's implementation. [#7774](https://github.com/AnalyticalGraphicsInc/cesium/pull/7774)
* Added `CesiumMath.normalize` to convert a scalar value in an arbitrary range to a scalar in the range [0.0, 1.0]. [#7774](https://github.com/AnalyticalGraphicsInc/cesium/pull/7774)

##### Fixes :wrench:
* Fixed an error where `clampToHeightMostDetailed` or `sampleHeightMostDetailed` would crash if entities were created when the promise resolved. [#7690](https://github.com/AnalyticalGraphicsInc/cesium/pull/7690)
Expand Down
36 changes: 24 additions & 12 deletions Source/Core/Math.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,29 +227,41 @@ define([
};

/**
* Converts a scalar value in the range [-1.0, 1.0] to a SNORM in the range [0, rangeMax]
* Converts a scalar value in the range [-1.0, 1.0] to a SNORM in the range [0, rangeMaximum]
* @param {Number} value The scalar value in the range [-1.0, 1.0]
* @param {Number} [rangeMax=255] The maximum value in the mapped range, 255 by default.
* @returns {Number} A SNORM value, where 0 maps to -1.0 and rangeMax maps to 1.0.
* @param {Number} [rangeMaximum=255] The maximum value in the mapped range, 255 by default.
* @returns {Number} A SNORM value, where 0 maps to -1.0 and rangeMaximum maps to 1.0.
*
* @see CesiumMath.fromSNorm
*/
CesiumMath.toSNorm = function(value, rangeMax) {
rangeMax = defaultValue(rangeMax, 255);
return Math.round((CesiumMath.clamp(value, -1.0, 1.0) * 0.5 + 0.5) * rangeMax);
CesiumMath.toSNorm = function(value, rangeMaximum) {
rangeMaximum = defaultValue(rangeMaximum, 255);
return Math.round((CesiumMath.clamp(value, -1.0, 1.0) * 0.5 + 0.5) * rangeMaximum);
};

/**
* Converts a SNORM value in the range [0, rangeMax] to a scalar in the range [-1.0, 1.0].
* @param {Number} value SNORM value in the range [0, 255]
* @param {Number} [rangeMax=255] The maximum value in the SNORM range, 255 by default.
* Converts a SNORM value in the range [0, rangeMaximum] to a scalar in the range [-1.0, 1.0].
* @param {Number} value SNORM value in the range [0, rangeMaximum]
* @param {Number} [rangeMaximum=255] The maximum value in the SNORM range, 255 by default.
* @returns {Number} Scalar in the range [-1.0, 1.0].
*
* @see CesiumMath.toSNorm
*/
CesiumMath.fromSNorm = function(value, rangeMax) {
rangeMax = defaultValue(rangeMax, 255);
return CesiumMath.clamp(value, 0.0, rangeMax) / rangeMax * 2.0 - 1.0;
CesiumMath.fromSNorm = function(value, rangeMaximum) {
rangeMaximum = defaultValue(rangeMaximum, 255);
return CesiumMath.clamp(value, 0.0, rangeMaximum) / rangeMaximum * 2.0 - 1.0;
};

/**
* Converts a scalar value in the range [rangeMinimum, rangeMaximum] to a scalar in the range [0.0, 1.0]
* @param {Number} value The scalar value in the range [rangeMinimum, rangeMaximum]
* @param {Number} rangeMinimum The minimum value in the mapped range.
* @param {Number} rangeMaximum The maximum value in the mapped range.
* @returns {Number} A scalar value, where rangeMinimum maps to 0.0 and rangeMaximum maps to 1.0.
*/
CesiumMath.normalize = function(value, rangeMinimum, rangeMaximum) {
rangeMaximum = Math.max(rangeMaximum - rangeMinimum, 0.0);
return rangeMaximum === 0.0 ? 0.0 : CesiumMath.clamp((value - rangeMinimum) / rangeMaximum, 0.0, 1.0);
};

/**
Expand Down
46 changes: 24 additions & 22 deletions Source/Core/RequestScheduler.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ define([
numberOfCancelledRequests : 0,
numberOfCancelledActiveRequests : 0,
numberOfFailedRequests : 0,
numberOfActiveRequestsEver : 0
numberOfActiveRequestsEver : 0,
lastNumberOfActiveRequests : 0
};

var priorityHeapLength = 20;
Expand Down Expand Up @@ -373,34 +374,34 @@ define([
return issueRequest(request);
};

function clearStatistics() {
statistics.numberOfAttemptedRequests = 0;
statistics.numberOfCancelledRequests = 0;
statistics.numberOfCancelledActiveRequests = 0;
}

function updateStatistics() {
if (!RequestScheduler.debugShowStatistics) {
return;
}

if (statistics.numberOfAttemptedRequests > 0) {
console.log('Number of attempted requests: ' + statistics.numberOfAttemptedRequests);
}
if (statistics.numberOfActiveRequests > 0) {
console.log('Number of active requests: ' + statistics.numberOfActiveRequests);
}
if (statistics.numberOfCancelledRequests > 0) {
console.log('Number of cancelled requests: ' + statistics.numberOfCancelledRequests);
}
if (statistics.numberOfCancelledActiveRequests > 0) {
console.log('Number of cancelled active requests: ' + statistics.numberOfCancelledActiveRequests);
}
if (statistics.numberOfFailedRequests > 0) {
console.log('Number of failed requests: ' + statistics.numberOfFailedRequests);
if (statistics.numberOfActiveRequests === 0 && statistics.lastNumberOfActiveRequests > 0) {
if (statistics.numberOfAttemptedRequests > 0) {
console.log('Number of attempted requests: ' + statistics.numberOfAttemptedRequests);
statistics.numberOfAttemptedRequests = 0;
}

if (statistics.numberOfCancelledRequests > 0) {
console.log('Number of cancelled requests: ' + statistics.numberOfCancelledRequests);
statistics.numberOfCancelledRequests = 0;
}

if (statistics.numberOfCancelledActiveRequests > 0) {
console.log('Number of cancelled active requests: ' + statistics.numberOfCancelledActiveRequests);
statistics.numberOfCancelledActiveRequests = 0;
}

if (statistics.numberOfFailedRequests > 0) {
console.log('Number of failed requests: ' + statistics.numberOfFailedRequests);
statistics.numberOfFailedRequests = 0;
}
}

clearStatistics();
statistics.lastNumberOfActiveRequests = statistics.numberOfActiveRequests;
}

/**
Expand All @@ -427,6 +428,7 @@ define([
statistics.numberOfCancelledActiveRequests = 0;
statistics.numberOfFailedRequests = 0;
statistics.numberOfActiveRequestsEver = 0;
statistics.lastNumberOfActiveRequests = 0;
};

/**
Expand Down
Loading

0 comments on commit ab441f2

Please sign in to comment.