-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
3D Tiles Traversal cleanup #6390
Conversation
e49d8c2
to
a0d5c5c
Compare
23e71dc
to
2705996
Compare
After too long.. updated. |
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.
Looks a lot cleaner overall! Looks like adding new functionality like other tile priority function will be straightforward.
|
||
if (getScreenSpaceError(tileset, tileset._geometricError, root, frameState) <= maximumScreenSpaceError) { | ||
// The SSE of not rendering the tree is small enough that the tree does not need to be rendered | ||
// The SSE of not rendering the tree is small enough that the tree does not need to be rendered |
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 comment isn't super clear - The root tile doesn't meet the SSE requirement, therefore the tree does not need to be rendered
?
function isVisibleAndMeetsSSE(tileset, tile, frameState) { | ||
/** | ||
* Traverse the tree and check if their selected frame is the current frame. If so, add it to a selection queue. | ||
* Furthermore, this is a preorder traversal so children tiles are selected before ancestor tiles. |
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.
Furthermore
* no deeper than 255. It is very, very unlikely this will cause a problem. | ||
* | ||
* NOTE: when the scene has inverted classification enabled, the stencil buffer will be masked to 4 bits. So, the | ||
* selected tiles must be no deeper than 15. This is still very unlikely. |
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.
Can we check the selection depth at this point and throw an error if either of these cases arise? Since it's so unlikely to happen, it won't immediately be apparent what is happening.
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.
Throwing an error is probably too extreme since the tileset can still render there just may be artifacts.
Source/Scene/Cesium3DTile.js
Outdated
color = Color.GREEN; | ||
} else { | ||
color = Color.RED; | ||
} |
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.
A little picky, but since red usually means "bad" and green usually mean "good" or "go", I would mark the colors something like so:
!finalResolution
-> Yellow
empty
-> gray
hasContentBoundingVolume
-> green
otherwise -> blue
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 ended up going with:
!finalResolution
-> yellow
empty
-> gray
boundingVolume
-> white
contentBoundingVolume
-> blue (the code for drawing content bounding volumes is further down)
I like white
as the "base" color because it's really neutral.
Source/Scene/Cesium3DTile.js
Outdated
@@ -253,14 +253,16 @@ define([ | |||
this.hasTilesetContent = false; | |||
|
|||
/** | |||
* The corresponding node in the cache replacement list. | |||
* The corresponding node in the cache. |
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 would briefly mention what the cache is used for here.
Source/Scene/Cesium3DTile.js
Outdated
@@ -458,13 +456,13 @@ define([ | |||
*/ | |||
contentAvailable : { | |||
get : function() { | |||
return this.contentReady || (defined(this._expiredContent) && this._contentState !== Cesium3DTileContentState.FAILED); | |||
return (this.contentReady && this.hasRenderableContent) || (defined(this._expiredContent) && this._contentState !== Cesium3DTileContentState.FAILED); |
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.
Shouldn't contentReady
determine if the content is renderable? Would it make more sence to make sure it's non-empty and also if the content is ready?
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.
Overall, it seems like there is a mix of setting variables like hasRenderableContent
explicitly, along with using states like this._contentState === Cesium3DTileContentState.READY
. hadRenderableContent
can be a getter that checks the state, but I think we should only be setting one or the other.
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.
Yes this was confusing, I removed this.hasRenderableContent
and instead check hasEmptyContent
or hasTilesetContent
as needed.
var add = tile.refine === Cesium3DTileRefine.ADD; | ||
if (add) { | ||
return tile._distanceToCamera; | ||
} else if (replace) { |
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.
Do we want to return some priority as a default, or leave the priority 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.
Also you don't need the else if
because of the early return above.
if (hasEmptyContent(tile)) { | ||
// Add empty tile just to show its debug bounding volume | ||
addEmptyTile(tileset, tile, frameState); | ||
loadTile(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.
Why are we loading an empty tile? Won't it just return from the loadTile
function?
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.
hasEmptyContent
is a catch-all for anything that has Empty3DTileContent
or Tileset3DTileContent
. The load is needed for the Tileset3DTileContent
case to load the external tileset. I left a comment to clarify.
|
||
tile._childrenVisibility = flag; | ||
function executeEmptyTraversal(tileset, root, frameState) { | ||
// Depth-first traversal that checks if all nearest descendants with content are loaded. Ignores visibility. |
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 believe you mentioned you'd like to combine this function with the normal traversal function if possible. Taking a look at both, I would say they are fine being separate as the logic would get too complex.
lastAncestor = tile; | ||
if (!traverse) { | ||
selectTile(tileset, tile, frameState); | ||
tile._finalResolution = 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.
So _finalResolution
is a tile marked for rendering at the end of this round of traversal, correct? I think we should call this _selectedForRender
or something a little more specific (as it is used externally to this class for debug code).
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.
_selectedForRender
is a bit too broad, _finalResolution
says a tile is rendered AND none of its descendants are rendered. I wonder if there's a better name specifically for that condition...
But that's where the !finalResolution -> yellow
comes in, it indicates a tile and its descendant are rendering simultaneously and the tile is not entirely "resolved".
I did clean up some of the _finalResolution
code though so that _finalResolution = false
is set in one place instead of _finalResolution = true
being set everywhere.
@ggetz Updated |
@ggetz bump - we should merge this sooner than later so it has time to sit in master. |
Sorry for the delay @lilleyse! Code looks good to me, the only thing I see is that http://cesium-dev.s3-website-us-east-1.amazonaws.com/cesium/traversal-cleanup/Apps/Sandcastle/index.html?src=3D%20Tiles%20Terrain%20Classification.html&label=3D%20Tiles takes a significantly longer time to load the tileset then it did previously. Is that a consequence of something in this PR? |
I believe it is an unrelated bug - #6908. |
@lilleyse Yep, that fixed it! Thanks for all the work here! |
This is mainly a cleanup of the 3D Tiles traversal code. The base traversal and skip traversal are now one code path which should make it easier to understand and maintain. The fundamentals haven't changed.
Besides cleanup some of the fixes are
Includes changes from these PRs which should be merged before this:
#6240#6247#6364#6391Part of #6243To do