Skip to content
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

Voxel API should conform to Cesium3DTileset interface #12297

Open
ggetz opened this issue Nov 8, 2024 · 6 comments
Open

Voxel API should conform to Cesium3DTileset interface #12297

ggetz opened this issue Nov 8, 2024 · 6 comments

Comments

@ggetz
Copy link
Contributor

ggetz commented Nov 8, 2024

Right now Cesium3DTilesVoxelProvider and other voxel classes are distinct from how other 3D tilesets are used in CesiumJS:

const provider = await Cesium.Cesium3DTilesVoxelProvider.fromUrl(
  "..."
);
const voxelPrimitive = viewer.scene.primitives.add(
  new Cesium.VoxelPrimitive({
    provider: provider,
  })
);

The goal is eventually to bring voxels into 3D Tiles as an extension. As such, we want to treat it in the API like like other 3D Tilesets, and be able to operate using familiar paradigms. Furthermore, the properties and functions associated with other 3D Tilesets should be available for voxel tilesets too, particularly:

  • the loading events, like allTilesLoaded, initialTilesLoaded, loadProgress, tileFailed, tileLoad, tileLoad, tilesLoaded, tileVisible, tileUnload.
  • statistics (for use in other parts of the API)

Where possible, we should also make sure the documentation is in good shape, and include inline examples where we can.

CC #11018
CC #11008

@lukemckinstry
Copy link
Contributor

lukemckinstry commented Jan 3, 2025

Question regarding the approach for reproducing the 3DTileset events for Voxels. Looking at the generated sample dataset we only have a single LOD at 0/0/0. Is this always the case now? Or is this due to the specifics on the source data and/or the specific tiler used?

└── Temperaturmodell-ellipsoid
    ├── subtrees
    │   └── 0
    │       └── 0
    │           └── 0
    │               └── 0.subtree
    ├── tilers-stats.json
    ├── tiles
    │   └── 0
    │       └── 0
    │           └── 0
    │               └── 0.voxel
    └── tileset.json

It seems like the 3DTileset event properties either operate on a per-tile or per-tileset basis. If VoxelPrimitive only uses info for a single LOD, does it make sense to only implement the per-tileset events and not the per-tile events?

  • Per-tile events: loadProgress, tileLoad, tileFailed, tileVisible, tileUnload - do not seem to have an equivalent in the current voxel setup.
  • Per-tileset events: allTilesLoaded makes sense to keep, and fire when the VoxelPrimitive has loaded (it could be a better description to call it primitiveLoaded, but allTilesLoaded keeps the API naming consistent). initialTilesLoaded seems to be redundant with allTilesLoaded for voxels and no necessary to implement separately.

@jjhembd
Copy link
Contributor

jjhembd commented Jan 6, 2025

@lukemckinstry I'm not quite sure what you're saying about the LODs. The folders are organized as tiles/LOD/x/y/z.voxel. LOD 0 is the level where the entire tileset bounding volume is spanned by one tile, so as you noticed, the x/y/z coordinates only take the value 0/0/0. The directories for higher LODs will show many more tiles.

For the per-tile events, one point for clarity: Individual tiles are handled very differently between Cesium3DTileset and VoxelPrimitive. I jotted down some quick observations below. This is a pretty rough overview, so don't hesitate to let me know which parts aren't clear.

Current state

Cesium3DTileset

A Cesium3DTileset keeps track of its tiles via 3 arrays:

  • _selectedTiles: the tiles selected as relevant to the current scene by Cesium3DTilesetTraversal. This list is re-computed every frame.
  • _requestedTiles: the tiles for which an HTTP request has been started. Also re-computed every frame.
  • _processingQueue: tiles for which the HTTP request completed successfully, but the data is still being processed and uploaded to the GPU. This list is filtered every frame, to avoid spending resources processing tiles which may have moved out of view in the current scene.

Each Cesium3DTile has a Cesium3DTileContentState to keep track of its status. It also has a priority property and an updatePriority method (called from Cesium3DTilesetTraversal) to make sure tile requests are sent off in the right order.

Every change to a tile in _requestedTiles or _processingQueue results in an update to the main Cesium3DTileset.prototype.statistics.

VoxelPrimitive

A VoxelPrimitive doesn't really have any idea of the tiles used to render the primitive. It delegates all of this to VoxelTraversal, which manages a tree of SpatialNodes, each of which can have several KeyframeNodes if the dataset is time-variant. This tree is updated in VoxelTraversal.prototype.update, which has some parallels with Cesium3DTilesetTraveral.selectTiles.

Requesting data is done from VoxelTraversal, via the VoxelProvider.prototype.requestData function, which is a single asynchronous function that does not resolve or report until the request is complete and some processing is done.

For an analogue to Cesium3DTileset statistics, you may want to look at printDebugInformation in VoxelTraversal. This performs a second traversal over the whole tree (in addition to the one that actually selects tiles for loading) and accumulates the number of KeyframeNodes in each KeyframeNode.LoadState. The results are then printed to the console.

Desired state

Ideally, each voxel tile should be a Cesium3DTile. Tile selection and loading should be done in the same way as they are for Cesium3DTileset--or better yet, VoxelPrimitive should be completely replaced by Cesium3DTileset.

One complication is that the SpatialNode / KeyframeNode architecture supports time-variant data. Switching to Cesium3DTileset would either drop support for time-variant voxels, or require modifications to Cesium3DTileset to incorporate time-variant data.

@jjhembd
Copy link
Contributor

jjhembd commented Jan 6, 2025

@lilleyse:

  • Have we already sketched out an architecture somewhere for time-variant 3D Tiles that are not voxels?
  • How much are time-variant voxels used? Would it make sense to switch to Cesium3DTileset for voxels now, and add back time dependence later?

@lukemckinstry
Copy link
Contributor

lukemckinstry commented Jan 8, 2025

A few follow ups

  1. The sample tiled voxel data I am working with only has LOD 0. The file tree I pasted above is from the sample data. One of my original questions was if having one LOD like this is always the case for voxels or if this data being single LOD is specific to the source data or tiler being used?
  • It would be helpful to test with voxel data with multiple LODs if possible.
  1. Looking at VoxelProvider.prototype.requestData, running on the same single LOD sample dataset. requestData returns successfully for the top level node level: 0 x,y,z: 0/0/0 but fails for all the child nodes. This makes sense since the data only contains LOD 0. My question is if we would want to raise the tileFailed event in this situation. If the setup is comparable in the 3DTiles traversal (recursively requesting child tiles until they are not present in the tileset) it seems we should follow that.

@ggetz
Copy link
Contributor Author

ggetz commented Jan 14, 2025

My question is if we would want to raise the tileFailed event in this situation. If the setup is comparable in the 3DTiles traversal (recursively requesting child tiles until they are not present in the tileset) it seems we should follow that.

@lukemckinstry We should mirror the behavior for implicit tilesets here. Do we have availability data? If so, let's try to use that to determine if the tile is available. Otherwise I believe implicit tilesets raise the tile failed event.

CC @jjhembd

@lukemckinstry
Copy link
Contributor

lukemckinstry commented Jan 14, 2025

It seems we do have availability data for voxels in the tileset.json. It would be helpful to know if it is a required field, is there a spec?
I do not see a reason to call requestData for voxel tiles when tileLevel > availableLevels. I think eliminating this extra level of calls to requestData may be the simplest solution to implement the tileFailed event.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants