Skip to content

Commit

Permalink
Merge pull request #7035 from AnalyticalGraphicsInc/force-traversal-e…
Browse files Browse the repository at this point in the history
…xternal

External tileset traversal fix
  • Loading branch information
ggetz authored Sep 14, 2018
2 parents f9d05bc + ab8c895 commit 32c7098
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 49 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Change Log
* Added `OpenCageGeocoderService`, which provides geocoding via [OpenCage](https://opencagedata.com/). [#7015](https://github.com/AnalyticalGraphicsInc/cesium/pull/7015)

##### Fixes :wrench:
* Fixed an issue in the 3D Tiles traversal where external tilesets would not always traverse to their root tile. [#7035](https://github.com/AnalyticalGraphicsInc/cesium/pull/7035)
* Fixed an issue in the 3D Tiles traversal where empty tiles would be selected instead of their nearest loaded ancestors. [#7011](https://github.com/AnalyticalGraphicsInc/cesium/pull/7011)
* Fixed bug where credits weren't displaying correctly if more than one viewer was initialized [#6965](expect(https://github.com/AnalyticalGraphicsInc/cesium/issues/6965)

Expand Down
45 changes: 28 additions & 17 deletions Source/Scene/Cesium3DTilesetTraversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ define([
return tile._distanceToCamera;
}
var parent = tile.parent;
var useParentScreenSpaceError = defined(parent) && (!skipLevelOfDetail(tileset) || (tile._screenSpaceError === 0.0));
var useParentScreenSpaceError = defined(parent) && (!skipLevelOfDetail(tileset) || (tile._screenSpaceError === 0.0) || parent.hasTilesetContent);
var screenSpaceError = useParentScreenSpaceError ? parent._screenSpaceError : tile._screenSpaceError;
var rootScreenSpaceError = tileset.root._screenSpaceError;
return rootScreenSpaceError - screenSpaceError; // Map higher SSE to lower values (e.g. root tile is highest priority)
Expand Down Expand Up @@ -298,16 +298,25 @@ define([
return anyVisible;
}

function meetsScreenSpaceErrorEarly(tileset, tile, frameState) {
var parent = tile.parent;
if (!defined(parent) || parent.hasTilesetContent || (parent.refine !== Cesium3DTileRefine.ADD)) {
return false;
}

// Use parent's geometric error with child's box to see if the tile already meet the SSE
var sse = getScreenSpaceError(tileset, parent.geometricError, tile, frameState);
return sse <= tileset._maximumScreenSpaceError;
}

function updateTileVisibility(tileset, tile, frameState) {
updateVisibility(tileset, tile, frameState);

if (!isVisible(tile)) {
return;
}

// Use parent's geometric error with child's box to see if the tile already meet the SSE
var parent = tile.parent;
if (defined(parent) && (parent.refine === Cesium3DTileRefine.ADD) && getScreenSpaceError(tileset, parent.geometricError, tile, frameState) <= tileset._maximumScreenSpaceError) {
if (meetsScreenSpaceErrorEarly(tileset, tile, frameState)) {
tile._visible = false;
return;
}
Expand Down Expand Up @@ -438,6 +447,18 @@ define([
return tile._screenSpaceError > baseScreenSpaceError;
}

function canTraverse(tileset, tile) {
if (tile.children.length === 0) {
return false;
}
if (tile.hasTilesetContent) {
// Traverse external tileset to visit its root tile
// Don't traverse if the subtree is expired because it will be destroyed
return !tile.contentExpired;
}
return tile._screenSpaceError > tileset._maximumScreenSpaceError;
}

function executeTraversal(tileset, root, baseScreenSpaceError, maximumScreenSpaceError, frameState) {
// Depth-first traversal that traverses all visible tiles and marks tiles for selection.
// If skipLevelOfDetail is off then a tile does not refine until all children are loaded.
Expand All @@ -455,19 +476,11 @@ define([
var baseTraversal = inBaseTraversal(tileset, tile, baseScreenSpaceError);
var add = tile.refine === Cesium3DTileRefine.ADD;
var replace = tile.refine === Cesium3DTileRefine.REPLACE;
var children = tile.children;
var childrenLength = children.length;
var parent = tile.parent;
var parentRefines = !defined(parent) || parent._refines;
var traverse = (childrenLength > 0) && (tile._screenSpaceError > maximumScreenSpaceError);
var refines = false;

if (tile.hasTilesetContent && tile.contentExpired) {
// Don't traverse expired subtree because it will be destroyed
traverse = false;
}

if (traverse) {
if (canTraverse(tileset, tile)) {
refines = updateAndPushChildren(tileset, tile, stack, frameState) && parentRefines;
}

Expand Down Expand Up @@ -514,7 +527,6 @@ define([
function executeEmptyTraversal(tileset, root, frameState) {
// Depth-first traversal that checks if all nearest descendants with content are loaded. Ignores visibility.
var allDescendantsLoaded = true;
var maximumScreenSpaceError = tileset._maximumScreenSpaceError;
var stack = emptyTraversal.stack;
stack.push(root);

Expand All @@ -526,7 +538,7 @@ define([
var childrenLength = children.length;

// Only traverse if the tile is empty - traversal stop at descendants with content
var traverse = hasEmptyContent(tile) && (childrenLength > 0) && (tile._screenSpaceError > maximumScreenSpaceError);
var traverse = hasEmptyContent(tile) && canTraverse(tileset, tile);

// Traversal stops but the tile does not have content yet.
// There will be holes if the parent tries to refine to its children, so don't refine.
Expand Down Expand Up @@ -573,7 +585,6 @@ define([
* selected tiles must be no deeper than 15. This is still very unlikely.
*/
function traverseAndSelect(tileset, root, frameState) {
var maximumScreenSpaceError = tileset._maximumScreenSpaceError;
var stack = selectionTraversal.stack;
var ancestorStack = selectionTraversal.ancestorStack;
var lastAncestor;
Expand Down Expand Up @@ -606,7 +617,7 @@ define([
var shouldSelect = tile._shouldSelect;
var children = tile.children;
var childrenLength = children.length;
var traverse = (childrenLength > 0) && (tile._screenSpaceError > maximumScreenSpaceError);
var traverse = canTraverse(tileset, tile);

if (shouldSelect) {
if (add) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
88
]
},
"geometricError": 240,
"geometricError": 70,
"refine": "ADD",
"content": {
"uri": "tileset2.json"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
20
]
},
"geometricError": 70,
"geometricError": 0,
"content": {
"uri": "tileset3/tileset3.json"
}
Expand Down
70 changes: 40 additions & 30 deletions Specs/Scene/Cesium3DTilesetSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -854,11 +854,15 @@ defineSuite([
});
});

function findTileByUrl(tiles, url) {
function findTileByUri(tiles, uri) {
var length = tiles.length;
for (var i = 0; i < length; ++i) {
if (tiles[i].content._resource.url.indexOf(url) >= 0) {
return tiles[i];
var tile = tiles[i];
var contentHeader = tile._header.content;
if (defined(contentHeader)) {
if (contentHeader.uri.indexOf(uri) >= 0) {
return tile;
}
}
}
return undefined;
Expand All @@ -877,10 +881,10 @@ defineSuite([
scene.renderForSpecs();

var root = tileset.root;
var llTile = findTileByUrl(root.children, 'll.b3dm');
var lrTile = findTileByUrl(root.children, 'lr.b3dm');
var urTile = findTileByUrl(root.children, 'ur.b3dm');
var ulTile = findTileByUrl(root.children, 'ul.b3dm');
var llTile = findTileByUri(root.children, 'll.b3dm');
var lrTile = findTileByUri(root.children, 'lr.b3dm');
var urTile = findTileByUri(root.children, 'ur.b3dm');
var ulTile = findTileByUri(root.children, 'ul.b3dm');

var selectedTiles = tileset._selectedTiles;
expect(selectedTiles[0]).toBe(root);
Expand Down Expand Up @@ -1079,8 +1083,7 @@ defineSuite([
//
return Cesium3DTilesTester.loadTileset(scene, tilesetReplacement1Url).then(function(tileset) {
tileset.root.geometricError = 90;
viewRootOnly();
scene.camera.zoomIn(20);
setZoom(80);
scene.renderForSpecs();

var statistics = tileset._statistics;
Expand Down Expand Up @@ -1364,6 +1367,15 @@ defineSuite([
});
});

it('always visits external tileset root', function() {
viewRootOnly();
return Cesium3DTilesTester.loadTileset(scene, tilesetOfTilesetsUrl).then(function(tileset) {
var statistics = tileset._statistics;
expect(statistics.visited).toEqual(2); // Visits external tileset tile, and external tileset root
expect(statistics.numberOfCommands).toEqual(1); // Renders external tileset root
});
});

it('set tile color', function() {
return Cesium3DTilesTester.loadTileset(scene, noBatchIdsUrl).then(function(tileset) {
// Get initial color
Expand Down Expand Up @@ -2765,29 +2777,27 @@ defineSuite([
});

it('immediatelyLoadDesiredLevelOfDetail', function() {
viewBottomLeft();
var tileset = scene.primitives.add(new Cesium3DTileset({
url : tilesetOfTilesetsUrl,
viewNothing();
return Cesium3DTilesTester.loadTileset(scene, tilesetUrl, {
immediatelyLoadDesiredLevelOfDetail : true
}));
return Cesium3DTilesTester.waitForReady(scene, tileset).then(function(tileset) {
scene.renderForSpecs();
return tileset.root.contentReadyPromise.then(function() {
tileset.root.refine = Cesium3DTileRefine.REPLACE;
tileset.root.children[0].refine = Cesium3DTileRefine.REPLACE;
tileset._allTilesAdditive = false;
}).then(function(tileset) {
var root = tileset.root;
var child = findTileByUri(root.children, 'll.b3dm');
tileset.root.refine = Cesium3DTileRefine.REPLACE;
tileset._allTilesAdditive = false;
viewBottomLeft();
return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function(tileset) {
expect(isSelected(tileset, child));
expect(!isSelected(tileset, root));
expect(root.contentUnloaded).toBe(true);
// Renders child while parent loads
viewRootOnly();
scene.renderForSpecs();
expect(isSelected(tileset, child));
expect(!isSelected(tileset, root));
return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function(tileset) {
var statistics = tileset._statistics;
expect(statistics.numberOfTilesWithContentReady).toBe(1);
// Renders child while parent loads
viewRootOnly();
scene.renderForSpecs();
expect(isSelected(tileset, tileset.root.children[0]));
expect(!isSelected(tileset, tileset.root));
return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function(tileset) {
expect(!isSelected(tileset, tileset.root.children[0]));
expect(isSelected(tileset, tileset.root));
});
expect(!isSelected(tileset, child));
expect(isSelected(tileset, root));
});
});
});
Expand Down

0 comments on commit 32c7098

Please sign in to comment.