Skip to content

Commit 63b899d

Browse files
committed
Handle expiring subtrees
1 parent 5fb5f91 commit 63b899d

File tree

3 files changed

+63
-50
lines changed

3 files changed

+63
-50
lines changed

Source/Scene/Cesium3DTile.js

+22-30
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,6 @@ define([
120120
*/
121121
this.computedTransform = computedTransform;
122122

123-
this._transformDirty = true;
124-
125123
this._boundingVolume = this.createBoundingVolume(header.boundingVolume, computedTransform);
126124
this._boundingVolume2D = undefined;
127125

@@ -422,20 +420,6 @@ define([
422420
}
423421
},
424422

425-
/**
426-
* Whether the computedTransform has changed this frame.
427-
*
428-
* @memberof Cesium3DTile.prototype
429-
*
430-
* @type {Boolean}
431-
* @readonly
432-
*/
433-
transformDirty : {
434-
get : function() {
435-
return this._transformDirty;
436-
}
437-
},
438-
439423
/**
440424
* @readonly
441425
* @private
@@ -550,15 +534,20 @@ define([
550534

551535
var scratchJulianDate = new JulianDate();
552536

553-
function updateExpiration(tile) {
554-
if (defined(tile.expireDate) && tile.contentReady && !tile.hasEmptyContent) {
537+
/**
538+
* Update whether the tile has expired.
539+
*
540+
* @private
541+
*/
542+
Cesium3DTile.prototype.updateExpiration = function() {
543+
if (defined(this.expireDate) && this.contentReady && !this.hasEmptyContent) {
555544
var now = JulianDate.now(scratchJulianDate);
556-
if (JulianDate.lessThan(tile.expireDate, now)) {
557-
tile._contentState = Cesium3DTileContentState.EXPIRED;
558-
tile._expiredContent = tile._content;
545+
if (JulianDate.lessThan(this.expireDate, now)) {
546+
this._contentState = Cesium3DTileContentState.EXPIRED;
547+
this._expiredContent = this._content;
559548
}
560549
}
561-
}
550+
};
562551

563552
function updateExpireDate(tile) {
564553
if (defined(tile.expireDuration)) {
@@ -620,9 +609,9 @@ define([
620609

621610
promise.then(function(arrayBuffer) {
622611
if (that.isDestroyed()) {
623-
return when.reject('tileset is destroyed');
612+
// Tile is unloaded before the content finishes loading
613+
return when.reject('tile is destroyed');
624614
}
625-
626615
var uint8Array = new Uint8Array(arrayBuffer);
627616
var magic = getMagic(uint8Array);
628617
var contentFactory = Cesium3DTileContentFactory[magic];
@@ -642,6 +631,11 @@ define([
642631
that._contentReadyToProcessPromise.resolve(content);
643632

644633
content.readyPromise.then(function(content) {
634+
if (that.isDestroyed()) {
635+
// Tile is unloaded before the content finishes processing
636+
that._content.destroy();
637+
return when.reject('tile is destroyed');
638+
}
645639
updateExpireDate(that);
646640
that._contentState = Cesium3DTileContentState.READY;
647641
that._contentReadyPromise.resolve(content);
@@ -883,9 +877,8 @@ define([
883877
Cesium3DTile.prototype.updateTransform = function(parentTransform) {
884878
parentTransform = defaultValue(parentTransform, Matrix4.IDENTITY);
885879
var computedTransform = Matrix4.multiply(parentTransform, this.transform, scratchTransform);
886-
var transformDirty = !Matrix4.equals(computedTransform, this.computedTransform);
887-
if (transformDirty) {
888-
this._transformDirty = true;
880+
var transformChanged = !Matrix4.equals(computedTransform, this.computedTransform);
881+
if (transformChanged) {
889882
Matrix4.clone(computedTransform, this.computedTransform);
890883

891884
// Update the bounding volumes
@@ -969,9 +962,7 @@ define([
969962
*/
970963
Cesium3DTile.prototype.update = function(tileset, frameState) {
971964
applyDebugSettings(this, tileset, frameState);
972-
updateExpiration(this);
973965
updateContent(this, tileset, frameState);
974-
this._transformDirty = false;
975966
};
976967

977968
var scratchCommandList = [];
@@ -1005,8 +996,9 @@ define([
1005996
* @private
1006997
*/
1007998
Cesium3DTile.prototype.destroy = function() {
999+
// For the interval between new content being requested and downloaded, expiredContent === content, so don't destroy twice
10081000
this._content = this._content && this._content.destroy();
1009-
this._expiredContent = this._expiredContent && this._expiredContent.destroy();
1001+
this._expiredContent = this._expiredContent && !this._expiredContent.isDestroyed() && this._expiredContent.destroy();
10101002
this._debugBoundingVolume = this._debugBoundingVolume && this._debugBoundingVolume.destroy();
10111003
this._debugContentBoundingVolume = this._debugContentBoundingVolume && this._debugContentBoundingVolume.destroy();
10121004
this._debugViewerRequestVolume = this._debugViewerRequestVolume && this._debugViewerRequestVolume.destroy();

Source/Scene/Cesium3DTileset.js

+38-19
Original file line numberDiff line numberDiff line change
@@ -1222,23 +1222,25 @@ define([
12221222

12231223
///////////////////////////////////////////////////////////////////////////
12241224

1225-
function unloadSubtree(tileset, tile) {
1225+
function destroySubtree(tileset, tile) {
1226+
var root = tile;
12261227
var stats = tileset._statistics;
1227-
var stack = [];
1228+
var stack = scratchStack;
12281229
stack.push(tile);
12291230
while (stack.length > 0) {
12301231
tile = stack.pop();
1231-
unloadTile(tileset, tile);
12321232
var children = tile.children;
12331233
var length = children.length;
12341234
for (var i = 0; i < length; ++i) {
1235-
var child = children[i];
1235+
stack.push(children[i]);
1236+
}
1237+
if (tile !== root) {
1238+
unloadTileFromCache(tileset, tile);
1239+
tile.destroy();
12361240
--stats.numberTotal;
1237-
stack.push(child);
12381241
}
12391242
}
1240-
1241-
tile.children = [];
1243+
root.children = [];
12421244
}
12431245

12441246
function isVisible(visibilityPlaneMask) {
@@ -1263,8 +1265,13 @@ define([
12631265
return;
12641266
}
12651267

1266-
if (expired && tile.hasTilesetContent) {
1267-
unloadSubtree(tileset, tile);
1268+
if (expired) {
1269+
if (tile.hasRenderableContent) {
1270+
decrementPointAndFeatureLoadCounts(tileset, tile.content);
1271+
--tileset._statistics.numberContentReady;
1272+
} else if (tile.hasTilesetContent) {
1273+
destroySubtree(tileset, tile);
1274+
}
12681275
}
12691276

12701277
++stats.numberOfPendingRequests;
@@ -1591,6 +1598,7 @@ define([
15911598
tile._sse = getScreenSpaceError(tileset, tile.geometricError, tile, frameState);
15921599
tile.selected = false;
15931600
tile._finalResolution = false;
1601+
tile.updateExpiration();
15941602
touch(tileset, tile, outOfCore);
15951603
}
15961604

@@ -1623,7 +1631,12 @@ define([
16231631
var loadSiblings = tileset.loadSiblings;
16241632

16251633
if (tile.hasTilesetContent) {
1626-
updateAndPushChildren(tileset, tile, frameState, stack, loadSiblings, outOfCore);
1634+
if (tile.contentExpired) {
1635+
// Request new content and destroy subtree
1636+
loadTile(tile);
1637+
} else {
1638+
updateAndPushChildren(tileset, tile, frameState, stack, loadSiblings, outOfCore);
1639+
}
16271640
} else {
16281641
if (tile.refine === Cesium3DTileRefine.ADD) {
16291642
loadAndAddToQueue(tileset, tile, finalQueue);
@@ -1751,12 +1764,17 @@ define([
17511764
// Remove from processing queue
17521765
tileset._processingQueue.splice(index, 1);
17531766
--tileset._statistics.numberProcessing;
1767+
17541768
if (tile.hasRenderableContent) {
17551769
// RESEARCH_IDEA: ability to unload tiles (without content) for an
17561770
// external tileset when all the tiles are unloaded.
1757-
++tileset._statistics.numberContentReady;
17581771
incrementPointAndFeatureLoadCounts(tileset, tile.content);
1759-
tile.replacementNode = tileset._replacementList.add(tile);
1772+
++tileset._statistics.numberContentReady;
1773+
1774+
// Add to the tile cache. Previously expired tiles are already in the cache.
1775+
if (!defined(tile.replacementNode)) {
1776+
tile.replacementNode = tileset._replacementList.add(tile);
1777+
}
17601778
}
17611779
} else {
17621780
// Not in processing queue
@@ -1981,8 +1999,9 @@ define([
19811999
}
19822000
}
19832001

1984-
function unloadTile(tileset, tile) {
1985-
if (!tile.hasRenderableContent) {
2002+
function unloadTileFromCache(tileset, tile) {
2003+
var node = tile.replacementNode;
2004+
if (!defined(node)) {
19862005
return;
19872006
}
19882007

@@ -1991,13 +2010,12 @@ define([
19912010
var tileUnload = tileset.tileUnload;
19922011

19932012
tileUnload.raiseEvent(tile);
1994-
replacementList.remove(tile.replacementNode);
2013+
replacementList.remove(node);
19952014
decrementPointAndFeatureLoadCounts(tileset, tile.content);
19962015
--stats.numberContentReady;
1997-
tile.unloadContent();
19982016
}
19992017

2000-
function unloadTiles(tileset, frameState) {
2018+
function unloadTiles(tileset) {
20012019
var trimTiles = tileset._trimTiles;
20022020
tileset._trimTiles = false;
20032021

@@ -2013,7 +2031,8 @@ define([
20132031
while ((node !== sentinel) && ((replacementList.length > maximumNumberOfLoadedTiles) || trimTiles)) {
20142032
var tile = node.item;
20152033
node = node.next;
2016-
unloadTile(tileset, tile);
2034+
unloadTileFromCache(tileset, tile);
2035+
tile.unloadContent();
20172036
}
20182037
}
20192038

@@ -2100,7 +2119,7 @@ define([
21002119
updateTiles(this, frameState);
21012120

21022121
if (outOfCore) {
2103-
unloadTiles(this, frameState);
2122+
unloadTiles(this);
21042123
}
21052124

21062125
// Events are raised (added to the afterRender queue) here since promises

Source/Scene/PointCloud3DTileContent.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ define([
115115
this._quantizedVolumeScale = undefined;
116116
this._quantizedVolumeOffset = undefined;
117117

118+
this._modelMatrix = Matrix4.clone(Matrix4.IDENTITY);
118119
this._mode = undefined;
119120

120121
/**
@@ -1138,7 +1139,8 @@ define([
11381139
* Part of the {@link Cesium3DTileContent} interface.
11391140
*/
11401141
PointCloud3DTileContent.prototype.update = function(tileset, frameState) {
1141-
var updateModelMatrix = this._tile.transformDirty || this._mode !== frameState.mode;
1142+
var modelMatrixChanged = !Matrix4.equals(this._modelMatrix, this._tile.computedTransform);
1143+
var updateModelMatrix = modelMatrixChanged || this._mode !== frameState.mode;
11421144
this._mode = frameState.mode;
11431145

11441146
if (!defined(this._drawCommand)) {

0 commit comments

Comments
 (0)