nytimes / three-loader-3dtiles

This is a Three.js loader module for handling OGC 3D Tiles, created by Cesium. It currently supports the two main formats, Batched 3D Model (b3dm) - based on glTF Point cloud.
Other
454 stars 64 forks source link

how to get ground point? #174

Closed kfarr closed 1 month ago

kfarr commented 3 months ago

We are encountering a challenge of helping users initialize google 3d tiles at the correct elevation.

We get elevation from this service from google which appears to be relative to mean sea level, and not actual elevation: https://developers.google.com/maps/documentation/javascript/reference/elevation#ElevationResult

We cannot get this elevation value to match reliably with height from this library as their relationships seems to vary across different longitudes and latitudes.

More details: https://github.com/3DStreet/3dstreet/issues/655

Possible solutions that we could use help with:

Avnerus commented 3 months ago

Hi Kieran!

I have also noticed an offset in my tests, but where I was looking it was 50. Initial intuition is that this might be due to the difference between "Geoids" (see here ). It seems that Google Earth uses the EGM96 Geoid and that you should be able to convert the heights with Math.GL - the math library used by this library.. The (perhaps more simple) solution used in most cases is to just raycast from the camera to find the ground level at a specific point. The "draping" demo uses a more sophisticated shader, but it's needed only to drape a complex object to the terrain.

Sorry that we will not be able to allocate time to research this further, at least in the coming month, but PRs are welcome if you find a solution!

kfarr commented 3 months ago

We did a first attempt for raycasting method. We were able to get the (a-frame managed) raycaster to successfully intersect with other object3d's on the scene, however it does not appear to emit an intersected event for 3d tiles rendered from this library. Are there any examples you're aware of for successful THREE.Raycaster intersection against 3d tiles?

Here is a quick video of the attempt showing raycaster events for a box geometry but not the 3dtiles: https://github.com/nytimes/three-loader-3dtiles/assets/470477/a98ed4ad-2b32-4796-93c5-88d4dfee0ea2

Here is a link to the WIP raycaster demo that does not work yet... https://3dstreet.github.io/aframe-loader-3dtiles-component/examples/google-tiles-raycaster/

related: https://github.com/nytimes/three-loader-3dtiles/issues/97

Avnerus commented 3 months ago

I did run raycasting on the tileset before but I don't have any public example right now. It does seem like they figured it out in #97, though. I took a quick look on how A-Frame does raycasting and it might be that it is unable to handle the deep hierarchy of the tileset. I would suggest trying a raw Three.js approach as in #97.

kfarr commented 3 months ago

@Avnerus you're 100% correct, I dove deep into that last night and will need to adjust the default a-frame raycaster component behavior to collide with the tiles, but it seems feasible. Therefore a PR it will likely be an a-frame loader specific but happy to share

Avnerus commented 3 months ago

Hi, great! Feel free to close this issue if you feel it's resolved. I am also still interested if this can be solved by selecting a height with Geoid conversion, for example with this tool.

kfarr commented 2 months ago

We now have a basic working solution https://github.com/3DStreet/aframe-loader-3dtiles-component/commit/f59bedf7d9af5efe1ebbad3dc03f4089723cfb96

This uses a raycaster with the camera pointing down above the ground and waits a few seconds for the scene to load. It's brittle but it works as a first version.

video1

https://github.com/nytimes/three-loader-3dtiles/assets/470477/b026dce8-dfd0-42ec-a772-2277bef57823

video2

https://github.com/nytimes/three-loader-3dtiles/assets/470477/ba42056e-49eb-4158-9d8d-3f290b951409

Avnerus commented 2 months ago

Looks great! Maybe this could be integrated to the a-frame component?

kfarr commented 2 months ago

@Avnerus yes we are already adding to our forked a-frame loader repo which still has MIT license and you are always welcome to merge back to your org (it's all here) but I hesitate to suggest anyone else use this as it's not reliable due to lack of control or awareness of state of target tile loading (1) and requires taking control of the camera (2)

(1) Right now we just wait x seconds until to assume the target center tile at origin is loaded at its highest LOD quality level. But often this fails due to internet connection speeds and will often trigger raycast at a low LOD which will result in incorrect ground location. I noticed in another thread there is a contentPostProcess but it's not clear how to target that better, such as listening for tile covering a specific origin point (0,0,0) or its state of loading level of detail in order to trigger a raycast for ground point. (Separate but related, sometimes tiles just don't load without any error message or any other indication, there is a general "invisibility" to the state of tiles that makes me uncomfortable but I don't know of any other easy solution for now.)

(2) We also have to "take over" the camera during this ground raycasting so that we are aiming the camera at 0,0,0 from above (but not too far above or it's too low LOD!) therefore ensuring that the tiles are being loaded in the origin. In theory this could be fixed by assigning an inactive camera to the tiles to use as its frustum instead of the visible one, but that's another three.js side quest that I don't have time for.

For our app we are planning on following UX flow to "paste over" these issues:

Would love any suggestions on how to better handle (1). I'm okay with accepting the reality of (2) for now.

kfarr commented 1 month ago

I'm going to close this thread. Here were the 2 solutions we found

First we tried using the raycaster method with a proof of concept demo, but this was unreliable because the value changes depending on camera position and tile loading state

We ended up creating a cloud function to find geoid height for given long/lat and then calculate ellipsoidal height which is needed by google 3d tiles "height" property to achieve 0 elevation at 0 0 0 scene origin https://github.com/3DStreet/3dstreet/pull/720 it seems to work with ~1m accuracy.