-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Refactor Tileset Traversal #5254
Conversation
…avoid double loading
33cc46b
to
a9786fb
Compare
Source/Scene/Cesium3DTile.js
Outdated
@@ -338,6 +339,10 @@ define([ | |||
this._selectionDepth = 0; | |||
this._lastFinalResolution = undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer used.
Source/Scene/Cesium3DTileset.js
Outdated
if (b.distanceToCamera === 0 && a.distanceToCamera === 0) { | ||
return b._centerZDepth - a._centerZDepth; | ||
function sortForLoad(a, b) { | ||
var diff = a.distanceToCamera - b.distanceToCamera; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename to distanceDifference
and screenSpaceErrorDifference
Source/Scene/Cesium3DTileset.js
Outdated
@@ -124,6 +126,7 @@ define([ | |||
* @param {Boolean} [options.debugShowGeometricError=false] For debugging only. When true, draws labels to indicate the geometric error of each tile | |||
* @param {ShadowMode} [options.shadows=ShadowMode.ENABLED] Determines whether the tileset casts or receives shadows from each light source. | |||
* @param {Boolean} [options.skipLODs=true] Determines if level-of-detail skipping optimization should be used. | |||
* @param {Number} [options.baseScreenSpaceError=1024] The screen-space error that must be reached before skipping LODs | |||
* @param {Number} [options.skipSSEFactor=10] Multiplier defining the minimum screen space error to skip when loading tiles. Used in conjuction with skipLevels to determine which tiles to load. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While we're doing the other renamings, this could be skipScreenSpaceErrorFactor
.
|
||
//>>includeStart('debug', pragmas.debug); | ||
Check.typeOf.number.greaterThanOrEquals('baseScreenSpaceError', baseScreenSpaceError, this.tileset._maximumScreenSpaceError); | ||
//>>includeEnd('debug'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be checked in Cesium3DTileset
somewhere, or always just clamped.
|
||
if (defined(stack.trim)) { | ||
stack.trim(maxLength); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When would stack.trim
be undefined?
Also this comment still applies right?
// on the next frame, we will likely need an array about the same size
Could be worth adding back.
child.selected = true; | ||
child._finalResolution = true; | ||
child._selectedFrame = frameState.frameNumber; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here.
if (tile.hasTilesetContent) { | ||
if (!tile.contentReady) { | ||
return emptyArray; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as before, is this check needed? Plus the situation where this actually returns the empty array is somewhat low, since tile.hasTilesetContent
will be false until the content has been loaded.
} | ||
|
||
var childrenVisibility = updateChildren(tileset, tile, this.frameState); | ||
var showAdditive = tile.refine === Cesium3DTileRefine.ADD && tile._screenSpaceError > maximumScreenSpaceError; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment about the SSE check being redundant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's needed if tile.hasTilesetContent === true
@@ -263,6 +267,7 @@ define([ | |||
this.show = defaultValue(options.show, true); | |||
|
|||
this._maximumScreenSpaceError = defaultValue(options.maximumScreenSpaceError, 16); | |||
this._baseScreenSpaceError = defaultValue(options.baseScreenSpaceError, 1024); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm getting a crash when changing the the maximum sse in the inspector with skipLODs
as false.
var length = leaves.length; | ||
for (var i = 0; i < length; ++i) { | ||
tileset._desiredTiles.push(leaves.get(i)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When skipLODs
is false, should the bivariateVisibilityTest
ever be on? I am seeing some cases where it is.
After testing the old performance/ behavior is still there which is good, minus the low-lod geometry blips that happened sometimes. I like the way the traversal code is organized now. |
The new code doesn't use the child union optimization. Is that intentional? |
777c3b9
to
2b858d6
Compare
@lilleyse Updated based on comments.
Whoops. Just an old thing
Accidentally removed. Added back.
Fixed. The one with maximum screen space error isn't always true. We need the check if |
c2ca6ff
to
50ec7c8
Compare
@austinEng have you ran a few JavaScript profiles to make sure this didn't introduce any high CPU or memory usage? |
There's a few CI test failures: https://travis-ci.org/AnalyticalGraphicsInc/cesium/builds/228357786 |
@lilleyse Updated. Spent a lot of time trying to solve what seemed to be bugs in the traversal. This turned out to be problems with translucency. Translucent commands were being put in the @pjcozzi Performance and memory usage is about the same. |
8099a04
to
b8ccf80
Compare
b8ccf80
to
80806ea
Compare
}; | ||
|
||
function baseUpdateAndCheckChildren(tileset, tile, baseScreenSpaceError, frameState) { | ||
if (tile.hasTilesetContent) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still don't think this block is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're right, but I think we should then add to the condition below
tile._screenSpaceError <= baseScreenSpaceError && !tile.hasTilesetContent
so that the base traversal doesn't stop at the root of external tilesets
// stop traversal when we've attained the desired level of error | ||
if (tile._screenSpaceError <= baseScreenSpaceError) { | ||
// When skipping LODs, require an existing base level of content first | ||
updateChildren(tileset, tile, frameState); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't completely see why the children are updated here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leafHandler
checks if at least one child is visible for the children union bound optimization
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, leave a comment about that.
} | ||
|
||
InternalBaseTraversal.prototype.execute = function(root) { | ||
this.allLoaded = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be defined in the class.
BaseTraversal.prototype.visitStart = function(tile) { | ||
if (tile._lastVisitedFrame !== this.frameState.frameNumber) { | ||
visitTile(this.tileset, tile, this.frameState, this.outOfCore); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This last visited check is pretty much the same throughout, why not put back in visitTile
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also this goes to the second point, are visitStart
and visitEnd
needed? If InternalBaseTraversal.prototype.visitStart
is changed based on other comments, visitStart
would be the same throughout. The code in visitEnd
can be incorporated in visit
along with my comment right above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
visitStart
getChildren
- if no children,
leafHandler
visitEnd
sometimes the leaf handler checks tile._lastVisitedFrame !== this.frameState.frameNumber
so we don't add tiles twice
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For that case it can stay, but do you think the others can be simplified?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never mind, I see now. Maybe a short isVisited
helper would be cleaner.
} | ||
} | ||
|
||
function touch(tileset, tile, outOfCore) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be a touchedFrame
? Some things will be touched twice - first in getChildren
and then visitTile
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth adding this? The other flags are important because they prevent tiles from getting put onto a list twice, but this just moves the tile in the doubly linked list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well it's a bit like the sse check.
} | ||
if (!tile.contentReady) { | ||
this.allLoaded = false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since shouldVisit()
will return false for any tile with renderable content, this code would not got reached for those tiles. This would create a situation allLoaded
is true even if one of its descendants with renderable content is not ready.
…s when multiple final tiles have different selection depths
@lilleyse Updated |
Thanks @austinEng, the recent updates look good. |
Cesium3DTilesetTraversal.js
baseScreenSpaceError
which defines the screen space error which must be met before LOD skipping startsexecute
,visit
,getChildren
,shouldVisit
, andleafHandler
._requestedFrame
and_lastVisitedFrame
have been added toCesium3DTile
_ancestorWithContent
and_ancestorWithLoadedContent
during the top-down traversal. It is no longer necessary to do a bottom-up traversal._sse
has been renamed to_screenSpaceError
skipLODs = false
now just setsbaseScreenSpaceError
to_maximumScreenSpaceError
and runs a base traversal._hasMixedContent
flag so that the stencil test is only applied when necessary. Previously, it would always set_hasMixedContent
totrue
if we had to go up the tree to select a tile. It is more correct to do this only when_selectionDepth > 0
which implies a selected tile has a selected ancestor. Tests have been updated to account for this.