threepipe icon indicating copy to clipboard operation
threepipe copied to clipboard

Importer/Loader Plugin for OGC 3D-Tiles

Open jo-chemla opened this issue 9 months ago • 3 comments

Hi, first of all congrats on this impressive framework! Very detailed docs and API, as well as very interesting live-examples and reusable components.

Following a comment by @gkjohnson, maintainer of NASA-AMMOS/3DTilesRendererJS on another topic, I wanted to open that thread to explore the possibility to create an Importer/Loader Plugin meant to read OGC 3D-Tiles within ThreePipe. As a quick summary, OGC 3D Tiles datasets are hierarchical tilesets that load geometry + textures interactively, in a recursive manner, depending on the camera position within the scene, a set of settings, and geometricError of the nodes projected onto the screen - basically what's used by Google to stream 3D Photorealistic cities, see their live demo and API doc.

This plugin would probably work similarly to @threepipe/plugins-extra-importers (based on threejs loaders, see implementation, extending BaseImporterPlugin) or @threepipe/plugin-gaussian-splatting (which looks more like, and eventually land within extra-importer-plugins.

I'm not entirely sure how to write such a plugin, and how much of it would be glue-code to the 3DTilesRendererJS library, especially given the fact that the renderer has to also update/render. One would probably have to import the 3DTilesRendererJS renderer and when loading the plugin create a renderer and provide it with the tileset uri. Subsequent steps, after 3d-tiles integration, could be including Controls and plugins from 3DTilesRendererJS as well.

Would you have any recommendation to start? Thanks!

jo-chemla avatar Apr 15 '25 16:04 jo-chemla

Hello, I had a quick look it seems interesting. Have been seeing a lot about it on twitter but didn't get a chance to get into it yet. Hooking the update from its renderer shouldn't be a lot of problem. But since it requires a minimum three.js version of r166, might have to see if it uses any new API extensively and adding support for that. I'll try a POC this week.

repalash avatar Apr 22 '25 06:04 repalash

I see that the project is using a custom, modified version of three.js. Is this something that's required for a model viewer? Or can some of these changes be upstreamed to three.js? The tiles renderer should generally work with some older versions of three.js but was bumped to r166 to take advantage of some of the newer BatchedMesh features.

Let me know if you need any help or instructions on how getting it working!

gkjohnson avatar Apr 28 '25 20:04 gkjohnson

Hey @gkjohnson, thanks for the great library, its nicely written, and for the mention of 3dviewer and threepipe. I am able to get it working with the basic renderer and it seems to work well. As well as loading individual file formats b3dm, cmpt, i3dm and pnts, so they would work with quicklook model viewer. Will release a version in a few days along with some basic UI configuration.

For three.js version, just had to copy Matrix2, and there are 2 versions of GLTFLoader in the build, otherwise it all works. (haven't tried your plugins yet). The fork I have includes changes for performance improvements, some fixes, some changes to enable additional features and patches for browser bugs, old devices, etc that three.js don't want to support. Many of those I plan to contribute upstream but would require some planning and a lot of time, but it shouldn't matter for this.

Image

A few questions I had related to the package, feel free to answer whenever available -

  • The JSON file used for tileset looks very generic, is there a json-schema / any way to identify the type of the file when someone loads an arbitrary json file. Would checking the extension of root->content->uri be b3dm okay? Maybe something could be added to the asset key like type or generator. Also is there a special extension/mime-type thought of or registered for the format?
  • The file loader classes as well as the renderer loads files using a custom interface which is different from threejs. Seems its done to able able to use extend to other engines. I saw in some places that headers and credentials are copied, but the loading routine is not followed like other loaders, specifically using the FileLoader(with it's cache) and calling itemStart, itemEnd, itemError. So, any plans to add that? I have currently wrapped your loaders in a three.js style Loader, just using the parse function, and it works. If you plan to change the implementation, it can be used directly.
  • The update method in the TilesRenderer is expected to be called every frame or only camera change/update? Like do we need to call when lighting updates or frame re-render for SSAA, sub-render for Reflectors/shadow maps etc or only on camera frustum change. There is also a frameCount variable, do we need to reset it sometime?
  • The loadRootTileSet method seems to be called from update, assuming to automatically load when required. But because of that, and it being in the super class, there is now a requirement of setting a camera to even start loading the first tile. Can this be changed to check for load before the camera check or provide a function for "preload".
  • Renderer adds and removes children to the group on every frame and sets the visibility, is it possible to ensure one object/tile is always in the group after load/preload so that the three.js Group/Object3D returns the correct bounding box(and raycast) always(for other plugins, functionality, external code). Since there is already frustum culling inside three.js renderer it won't render it anyway.
  • Continuing on the last point, is it possible to prevent changing the object node hierarchy of the scene. I have some plugins that updates lighting, trigger baking, update scene bvh, other data and some plugins for UI that shows the complete nested hierarchy. They subscribe to add/remove events of the objects, and if it happens every time camera moves, that could be a problem.
  • For cleanup, the dispose method calls dispose on the three.js objects. Is it written as a way to clear the GPU resources and it is possible to reuse the TilesRenderer and Group inside it again by adding it to a Scene, or once called dispose we cannot use it. Asking since removeFromParent is called on the group.
  • There are 3 gltf extensions used in the project - CESIUM_RTC, EXT_structural_metadata, EXT_mesh_features. Are you aware of any GLTFExporter plugins for these that are available?
  • You mentioned in the other thread that never tried the 3dviewer.xyz app, any specific reason for that?
  • For the model in your index.html demo, what is the License for it(and other files in the repo)? Also is it the Lunar surface or Mars?
  • The cmpt example doesn't have a demo source file, as a result the example doesn't load. Not a question, just a report. Here's a test file I found - https://raw.githubusercontent.com/CesiumGS/3d-tiles-tools/main/specs/data/contentTypes/content.cmpt

I think thats all. Please don't assume any of the above are feature requests for changes in your API, there are ways around most of them.

repalash avatar May 01 '25 20:05 repalash

The JSON file used for tileset looks very generic, is there a json-schema / any way to identify the type of the file when someone loads an arbitrary json file.

This is a good question - there are no custom extensions for the format but there are schema files available here. If we need anything more we can try asking a question at the 3d tiles repo.

the loading routine is not followed like other loaders, specifically using the FileLoader(with it's cache) and calling itemStart, itemEnd, itemError.

Support for itemStart, itemEnd, and itemError can be added (I'll make an issue for it). But whats your use case for FileLoader and the three.js cache? The Cache specifically has always seemed lack luster and error prone to me. It doesn't account for header data in the cache key and it will blindly save as much data as you load via FileLoader, which in this case can be tens or more gigabytes. It's better, imo, to rely on the browser cache for the type of simple caching being done here, otherwise you'll likely see a massive amount of memory eaten from the cached data.

edit: Actually, can you let me know your use case for itemStart, etc, as well?

The update method in the TilesRenderer is expected to be called every frame or only camera change/update? Like do we need to call when lighting updates or frame re-render for SSAA, sub-render for Reflectors/shadow maps etc or only on camera frustum change. There is also a frameCount variable, do we need to reset it sometime?

If you use the UpdateOnChangePlugin (looks like I need to write some docs for it), then even if you call "update" every frame it will only run when needed. If you want to support on-demand rendering (only render when needed) then you can listen for specific set of events indicating an update and rerender need to be performed (see https://github.com/NASA-AMMOS/3DTilesRendererJS/pull/1100). I'm still trying to simplify this and there's a bug currently which I'm going to try to address in the next release (see https://github.com/NASA-AMMOS/3DTilesRendererJS/pull/1081).

Note that the other two plugins you should use are the GLTFExtensionsPlugin with Draco, KTX2, and MeshOpt support. And the ImplicitTilingPlugin for adding implicit tiling support.

because of that, and it being in the super class, there is now a requirement of setting a camera to even start loading the first tile. Can this be changed to check for load before the camera check

I think we can do this. What's your use case?

is it possible to ensure one object/tile is always in the group after load/preload so that the three.js Group/Object3D returns the correct bounding box(and raycast) always(for other plugins, functionality, external code). Since there is already frustum culling inside three.js renderer it won't render it anyway.

Can you explain the need for this? Frustum culling, matrix updating, default raycasting behavior, etc is all disabled by default since it can be handled more optimally internally given the nature of the tile set hierarchy. We could expose boundingSphere or boundingBox on the TilesRenderer.group object if that's needed (similar to three.js' SkinnedMesh).

is it possible to prevent changing the object node hierarchy of the scene.

This I don't think can be done. Every movement of the camera will trigger new model loads into the scene and nodes need to be deleted when unloaded. Already-loaded nodes are added and removed from the scene to prevent three.js from traversing them on render. Otherwise there could be thousands (or tens of thousands) of nodes in the hierarchy in some cases.

Is it written as a way to clear the GPU resources and it is possible to reuse the TilesRenderer and Group inside it again by adding it to a Scene, or once called dispose we cannot use it.

Once a TilesRenderer has been disposed it should not be reused. If you need to load a new tileset URL you should create a new TilesRenderer.

CESIUM_RTC, EXT_structural_metadata, EXT_mesh_features. Are you aware of any GLTFExporter plugins for these that are available?

Not as far as I know.

For the model in your index.html demo, what is the License for it(and other files in the repo)? Also is it the Lunar surface or Mars?

Tbh I don't recall the history of that file 😅 I believe it was a data set generated from some dig site near LA if I recall correctly. It's probably worth adjusting the main demo to use a different file since I don't have a good story for this one. The sample Mars data can be used with this use policy.


You mentioned in the other thread that never tried the 3dviewer.xyz app, any specific reason for that?

I had recalled seeing it on twitter a long time ago but never downloaded it at the time. Beyond that, a lot of my work recently has involved 3d tiles, which hasn't been supported, and glTF, which I've typically used Don's viewer for and allows me to perform more analysis which I typically need for my work (calculating triangle counts, inspecting materials, toggling geometry, etc) via the command line.

Thinking more generally (assuming you're asking more about how to make installation more appealing / useful) - I'm usually hesitant to download apps from online or Github outside of widely known organizations. I usually look through the source a bit before doing so. There are, of course, security concerns but also the need to manually keep it up to date and wondering whether it can be cleanly uninstalled without leaving settings unmodified, etc. Some of these are admittedly left over worries and frustrations from having dealt with Windows applications for decades that leave cruft on disk when you realize you don't need it or conflict with other tools. Adding it to something like the Apple App store may help alleviate some of these concerns but I don't know if there's a cost with that?


Let me know if that answers what you need for getting this integrated! Happy to help with anything else.

gkjohnson avatar May 03 '25 23:05 gkjohnson

Hey so the basic integration is working, you can try it here - https://dev.threepipe.org/examples/tweakpane-editor/?m=https://raw.githubusercontent.com/NASA-AMMOS/3DTilesRendererJS/c7a9a7f7607e8759d16c26fb83815ad1cd1fd865/example/data/tileset.json&ext=tileset And other examples for the individual threepipe plugins - https://dev.threepipe.org/examples/?q=tile#3d-tiles-renderer/

You can have a look at the implementation here - https://github.com/repalash/threepipe/tree/739ebae861d7c80253bf53c48d812da347af6da4/plugins/3d-tiles-renderer/src

I will add support for GlobeControls and play around a bit with materials, lighting, and post-processing as well soon. Support for BatchedMesh will have to wait till the three.js upgrade is done.

Its mostly working pretty well, there are some small issues -

  • There are some seams between the tiles. You can see it a bit in the above link but more in the globe demo with full scale earth. Any idea why this is? Maybe some precision issue? I don't see it in the demos in 3d-tiles-renderer package.
Image
  • In the examples when I zoom in and out, it doesn't show the bigger tile back, and keeps showing the small ones, you can try it here - https://dev.threepipe.org/examples/?q=tile#slippy-map-tiles/
Image

Do I need some plugin like UnloadTiles, or is there some or mistake I am doing like scaling down the model?

  • Some examples don't load automatically(they don't trigger the change event). I guess it's related to the issue you mentioned, but its not only on the demos that require auth, but in DeepZoomImage example as well.

Answering questions from above -

But whats your use case for FileLoader and the three.js cache?

FileLoader also supports onProgress event which is used to show download progress bar/percentage in the UI. For the three.js Cache, in threepipe its overridden to use the browser cache storage or a custom storage provided by the user(or use the memory cache if useful for the application). This is done through FileLoader as all three.js examples loaders already support it and its a consistent way to inject this.

can you let me know your use case for itemStart, etc, as well?

Its useful to show the loading screen/progress bar. In the editor, there is a plugin that shows this data either as an overlay or in a small panel. It can be configured to show just a spinner when a load is in progress or the full list of assets that are being downloaded. It can be done using the events you provide as well in TilesRenderer, instead of itemStart, etc. But with that we get it automatically.

UpdateOnChangePlugin works, I am using that and calling the update before every render.

there's a bug currently which I'm going to try to address in the next release

I think I see that as well here - https://dev.threepipe.org/examples/?q=#ogc-tiles-google-maps/ The globe doesn't render initially till you move the mouse, I guess its the same issue?

Can this be changed to check for load before the camera check, I think we can do this. What's your use case?

To preload the file before adding it to the scene(which has the camera). This is useful in apps where we preload the next scene before unloading the first.

We could expose boundingSphere or boundingBox on the TilesRenderer.group object if that's needed (similar to three.js' SkinnedMesh).

Yeah I ended up doing the same here after creating the group - https://github.com/repalash/threepipe/blob/739ebae861d7c80253bf53c48d812da347af6da4/plugins/3d-tiles-renderer/src/TilesRendererPlugin.ts#L246-L260 With this, the autoScale, autoCenter on load and other features, actions from UI work. It can also be added inside the library. Raycast works normally, no issues there.

you should use are the GLTFExtensionsPlugin with Draco, KTX2, and MeshOpt support

I added support for the extra extensions separately using the AssetManager in threepipe. Draco, KTX2, MeshOpt should work by default since it takes the GLTFLoader from the loading manager which has the other loaders set.

Adding it to something like the Apple App store may help alleviate some of these concerns but I don't know if there's a cost with that?

Thanks for the tips about the app. I plan to display more info about the model and provide some mini editor-like controls, soon. Publishing it on the App Store is also to be done, the cost is the same as notarizing/signing which I am already paying, but the only problem is that it cannot be automated and require regular manual work.

I agree to the security concerns you have, I wouldn't either. To try to counter some and gain a user, the app is notarized by Apple, and it has app sandbox flag set in Info.plist, which are the requirement for App Store submission. I generally use this as an indicator to see if I should open an app(assuming its attractive enough to check it). And it prompts for new version updates. No auto-updates though because of the app sandbox flag.


Btw, I saw that the three-gpu-pathtracer was fixed last year, I somehow missed the update. I will recover and add the plugins of that as well to threepipe. Thanks for the great work there as well. Its a nice addition for rendering apps, now that there are nice open source denoisers available as well.

repalash avatar May 06 '25 18:05 repalash

There are some seams between the tiles. You can see it a bit in the above link but more in the globe demo with full scale earth. Any idea why this is? Maybe some precision issue? I don't see it in the demos in 3d-tiles-renderer package.

These looks like two different issues:

  • The globe demo is due to precision issues from the scale of the data set. The GlobeControls used in the demos in the repo adjusts the camera near and far plane to encapsulate the globe model such that there are no noticeable artifacts and the model isn't clipped. Using three.js' logarithmic depth buffer or reverse depth buffer would work, too, but these have performance and code ergonomic implications.
  • The gray data set has no tile "skirts" so these kinds of seams are inevitable but I think they are particularly noticeable in your screenshot because it looks like antialiasing is disabled.

In the examples when I zoom in and out, it doesn't show the bigger tile back, and keeps showing the small ones, you can try it here - https://dev.threepipe.org/examples/?q=tile#slippy-map-tiles/

~From poking around the group object logged it looks like the model is scaled significantly which is likely affecting the screen space error calculation. I'll have to dig into this and figure out what the expected behavior should be. Scaling the model isn't done much and hasn't been tested extensively so it may be best to think of that as "unsupported" at the moment (though it should be).~

It actually looks like have accounted for scale so I'm not exactly sure what's going on, yet. Something seems to be affecting the error calculations though I'm not sure what, atm.

Some examples don't load automatically(they don't trigger the change event).

This should be addressed in the v0.4.9 release.

FileLoader also supports onProgress event which is used to show download progress bar/percentage in the UI.

You can check out some of the "load-content" events, etc which broadcast when a tile has finished downloading. Coupled with TilesRenderer.loadProgress you could probably broadcast your own events of this form. This doesn't include any byte-download progress, though. You can see a demo with a loading bar here. You'll notice that, depending on the data set, the bar can jump back and forth as new subtrees are loaded and the renderer "realizes" that more tiles actually need to be loaded.

I'll have to think about the events, though. Ergonomically fetch is a lot easier to deal with and this kind of use case feels like it has limited broad utility. For handling the individual file loaders you could fetch the file with FileLoader yourself and then pass the buffer to each parse function:

new FileLoader( manager )
    /* ... assign settings */
    .loadAsync( url )
    .then( res => res.arraybuffer() )
    .then( buffer => new B3DMLoader().parse( buffer ) );

To preload the file before adding it to the scene(which has the camera). This is useful in apps where we preload the next scene before unloading the first.

I got this added in the latest release.

Btw, I saw that the three-gpu-pathtracer was fixed last year, I somehow missed the update.

Yeah maintaining that project has turned into a bit of fighting a Hydra 😅 The number of browser issues popping up I've had to report and try to work around has been bit exhausting. Unfortunately I don't know how much energy I have to keep doing that for WebGL - hopefully WebGPU makes these kinds of projects more viable with compute.

gkjohnson avatar May 07 '25 21:05 gkjohnson

In the examples when I zoom in and out, it doesn't show the bigger tile back, and keeps showing the small ones, you can try it here - https://dev.threepipe.org/examples/?q=tile#slippy-map-tiles/

It looks like the TilesGroup.matrixWorldInverse field is not being updated and therefore becoming out of sync with TilesGroup.matrixWorld, causing some issues with error calculations. Are you manually calculating world matrices instead of using the updateMatrixWorld function? TilesGroup uses a custom updateMatrixWorld to prevent unnecessary matrix update calls and to precompute an inverse matrix.

edit - it looks like the custom updateMatrixWorld function is running but the matrixWorld value is already computed to use the scaled value so it doesn't trigger child or dependent matrix updates. Perhaps your manually precomputing the matrixWorld field somewhere causing this? If so the fix for now would be to not do this and I'll have to think about whether or not it makes sense (and how) to account for this kind of case.

gkjohnson avatar May 07 '25 22:05 gkjohnson

adjusts the camera near and far plane to encapsulate the globe model

Ah thanks, there is built in auto near-far in threepipe for this that I disabled here for some reason. That should also fix it.

For handling the individual file loaders you could fetch the file with FileLoader yourself and then pass the buffer to each parse function

Yes, that's what I did, works well.

I got this added in the latest release.

Thanks

it looks like the custom updateMatrixWorld function is running but the matrixWorld value is already computed to use the scaled value so it doesn't trigger child or dependent matrix updates. Perhaps your manually precomputing the matrixWorld field somewhere causing this

Thanks for looking into this. Without any other plugin, I don't think anything is being done with matrixWorld by default. Not sure if I understand correctly but trying, do you mean the matrix is updated after I scale the model, but before the children are added in the TilesGroup, and because of this the child matrices are incorrect? But for this I assume you would have something to invalidate the needs update check for the parent matrix or set the matrices when loading the models correctly?

For scaling the model, it happens automatically based on the bounds after I receive the load-tile-set event with root tile - https://github.com/repalash/threepipe/blob/e581362ab8eeef0754d1e87d83ec5d98e717ffe7/plugins/3d-tiles-renderer/src/TilesRendererPlugin.ts#L262-L272

Maybe there is a race condition somewhere?

repalash avatar May 07 '25 23:05 repalash

Okay so, reseting the matrix whenever any child is added fixed it.

const tadd = group.add
group.add = (child: Object3D)=>{
    tadd.call(group, child)
    group.matrixWorld.identity()
    return group
}

group is the TilesGroup.

Quickly checking the code, I don't see anyplace its invalidating the difference check in TilesGroup here. Can you point me to how the matrix world are initially set after loading the individual tiles, i'll figure out the rest.

Also the force doesn't get used in updateMatrixWorld -> isDifferent check, and doesn't get passed to children, is that intentional?

repalash avatar May 07 '25 23:05 repalash

So it looks like the matrixWorld is updated separately from custom updateMatrixWorld( force ) function when the (separate) updateWorldMatrix( updateParents, updateChildren ) is called from Box3B.expandByObject (initially called during "refreshScene" after load) here. I'm generally not a fan of the dual matrix update functions but that's the API...

I'll have to think of how to account for that. But in the mean time you should be able to fix this by setting the matrixWorld back to an identity matrix just once after the scene is recentered, scaled, refreshed, etc here.

Can you point me to how the matrix world are initially set after loading the individual tiles, i'll figure out the rest.

Matrices for the tile meshes are updated whenever they are added to the scene. And any subsequent updates are handled by the isDifferent dirty check in TilesGroup.

Also the force doesn't get used in updateMatrixWorld -> isDifferent check, and doesn't get passed to children, is that intentional?

Passing force shouldn't really matter. The TilesRenderer assumes complete control over the child meshes transform updates which means matrixAutoUpdate will be set to true, calling updateMatrix, which will set matrixWorldNeedsUpdate = true resulting in the same effect as force anyway. Perhaps passing force as always true is more safe but it should be inconsequential.

gkjohnson avatar May 08 '25 00:05 gkjohnson

Oh yeah, missed updateWorldMatrix, thanks. I can reset the matrix in setDirty on transform change, which is called by other code on changes.

I think that should fix all issues from above.

BTW, what was the reason for another check for matrix change and not use matrixWorldNeedsUpdate like in three.js. I guess the assumption in the API is to call updateMatrix(which sets matrixWorldNeedsUpdate) only when something changes, is that not the case? or any other issue?

repalash avatar May 08 '25 00:05 repalash

I can reset the matrix in setDirty on transform change, which is called by other code on changes.

Hopefully this is just a temporary requirement - I've created https://github.com/NASA-AMMOS/3DTilesRendererJS/issues/1119 to address this in an upcoming release.

BTW, what was the reason for another check for matrix change and not use matrixWorldNeedsUpdate like in three.js

The 3d tiles use case is unique because it's known that none of the tiles can move (at least in the typical case) so there's no need to traverse and update matrices unless the root has changed. Most users also use three.js with default settings which means they're not manually setting matrixWorldNeedsUpdate when changing a transform so automatically detecting a change is more ergonomic and intuitive in the general case. This small diff check saves thousands of matrix operations in the typical case so it's more than worth it to make sure it's running no matter what the users preferred matrix update strategy is.

gkjohnson avatar May 08 '25 01:05 gkjohnson

Also

Ah thanks, there is built in auto near-far in threepipe for this that I disabled here for some reason. That should also fix it.

This may fix it. The extents of the globe are extremely large (+- ~6,380,000 m) and the known bounding volumes are boxes so the naively inferred bounds will be even larger. The GlobeControls strategy uses the tile set's Ellipsoid definition to more tightly set the near plane and sets the far plane to somewhere near the half way through the globe (w/ some margin in both cases) since we know the geometry on the back side of the globe will not be visible and doesn't need to be loaded.

Unfortunately there's no completely reliable way to determine if a tile set is a globe or not based on metadata but using something like the bounding box offset (eg is the position of the model roughly a planet-sized radius away from the center) or the size of the bounding box (eg is the bounding box the size of a planet) may be able to be used to infer whether globe controls should be used. But I haven't taken a dive into that, yet.

gkjohnson avatar May 08 '25 01:05 gkjohnson

This may fix it. The extents of the globe are extremely large...

Yeah so it didn't, since it's extremely large. It works when far away from the model, but as you said it needs a very tight fit like with ellipsoid and horizon and wouldn't work for simple bounds. Also, for some reason the bounds I am getting from getBoundingBox are much bigger than the globe itself. Will have some more look and create an issue if its from inside the renderer.

Added the EnvironmentControls and GlobeControls as plugins, they can be directly used in the framework without even tiles.

The integration is finally good enough for use, and published on npm as a new package.

The docs are here on basic usage - https://threepipe.org/package/plugin-3d-tiles-renderer.html

To load a tileset in the editor, the url and a extension of tileset can be added to the query params and it picks the loader automatically, try here - https://threepipe.org/examples/tweakpane-editor/?m=https://raw.githubusercontent.com/NASA-AMMOS/3DTilesRendererJS/c7a9a7f7607e8759d16c26fb83815ad1cd1fd865/example/data/tileset.json&ext=tileset

The controls(environment, globe) can be picked from the UI above by going to Viewer -> Scene -> Camera -> Controls, but it doesn't take the TilesRenderer instance, so globe won't work well in the editor. Also not sure how to handle multiple renderers per controls. So it has to be done manually in code like here - https://threepipe.org/examples/?q=tile#ogc-tiles-google-maps/ (pretty fun to play around)

Will soon also add these plugins to 3dviewer.xyz app.

Closing this issue for now, feel free to create new issues or PR about anything specific in this.

repalash avatar May 12 '25 21:05 repalash

Also, for some reason the bounds I am getting from getBoundingBox are much bigger than the globe itself.

The bounding boxes are derived from the root bounds which are oriented in this case. You can see the bounding boxes of all the tiles here which may give a sense for why they're so off.

Image

And here's one with the root AABB (yellow) derived from the root bounds:

Image

I'm not sure why Google's data set doesn't use "region" bounding volumes for its data but if it did then we'd likely have a better implicit bounding box the root. But that's a data problem and not anything the library can or should fix, imo 🤷

To load a tileset in the editor, the url and a extension of tileset can be added to the query params and it picks the loader automatically, try here - https://threepipe.org/examples/tweakpane-editor/?m=https://raw.githubusercontent.com/NASA-AMMOS/3DTilesRendererJS/c7a9a7f7607e8759d16c26fb83815ad1cd1fd865/example/data/tileset.json&ext=tileset

I see the user has to manually add ext=tileset to the URL to display the display the data. Did duck-typing the tileset json format not seem robust enough? Is this something we should raise with the 3d tiles spec?

The controls(environment, globe) can be picked from the UI above by going to Viewer -> Scene -> Camera -> Controls, but it doesn't take the TilesRenderer instance, so globe won't work well in the editor.

Great! In the editor when I select "environment" controls with your demo link above the camera seems to jump around a bit while dragging. Not sure if it's competing with some other camera behavior? I'm also working on removing the requirement that a TilesRenderer be passed to the controls. Then EnvironmentControls should just need the "scene" to operate for raycasting. And GlobeControls will need the ellipsoid and ellipsoid frame to be set.

Also not sure how to handle multiple renderers per controls. So it has to be done manually in code like here

I'm not seeing multiple tile sets in that link? Either way hopefully the above answers the question. Just adding the tile sets to the scene that is attached to the controls is enough to get it working with raycasting.

Will soon also add these plugins to 3dviewer.xyz app.

Amazing! Will it allow for dragging / dropping a folder with a tileset to load?


Also last thing I noticed -

It looks like the tile sets stop rendering too early. The tiles fade plugin broadcasts a needs-render indicating that another frame should be drawn (this was changed from force-rerender in a recent release - sorry if that broke things).

Image

Very nice work, as always! Excited to see this 😁 And happy to make any other issues relating to the above comments if you prefer.

gkjohnson avatar May 12 '25 23:05 gkjohnson