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

how to get ground point? #174

Closed
kfarr opened this issue Jul 3, 2024 · 9 comments
Closed

how to get ground point? #174

kfarr opened this issue Jul 3, 2024 · 9 comments

Comments

@kfarr
Copy link
Contributor

kfarr commented Jul 3, 2024

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: 3DStreet/3dstreet#655

Possible solutions that we could use help with:

  • is there an easy way to translate "elevation" from google elevation service to height of this library?
  • is there another way to "clamp to ground" or otherwise place elements at the ground as fetched via 3d tiles?
  • I noticed a "draping" demo --> this sounds conceptually similar but unclear how to leverage that logic for this use case
@Avnerus
Copy link
Collaborator

Avnerus commented Jul 3, 2024

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
Copy link
Contributor Author

kfarr commented Jul 3, 2024

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: #97

@Avnerus
Copy link
Collaborator

Avnerus commented Jul 4, 2024

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
Copy link
Contributor Author

kfarr commented Jul 4, 2024

@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
Copy link
Collaborator

Avnerus commented Jul 4, 2024

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
Copy link
Contributor Author

kfarr commented Jul 6, 2024

We now have a basic working solution 3DStreet/aframe-loader-3dtiles-component@f59bedf

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

tileset-height1-1080p.mov

video2

tileset-height2-1080p.mov

@Avnerus
Copy link
Collaborator

Avnerus commented Jul 7, 2024

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

@kfarr
Copy link
Contributor Author

kfarr commented Jul 7, 2024

@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:

  • use the initial google elevation service API response as a "hint" of the correct elevation value + 1000meters above for initial height camera / raycaster relative to tiles, so that our raycaster and camera can get reasonable LOD above the tiles for intersection
  • put a spinner / loader state on top of three.js canvas while we're controlling the camera position and performing raycasting operation for up to 10 seconds
  • offer ability for user to accept, manually change or retry the calibration since it may very likely return incorrect answer due to (1) issue above
  • cache the 'height' value for the long/lat so that this process does not need to be repeated after setting initial scene location

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

@kfarr
Copy link
Contributor Author

kfarr commented Aug 14, 2024

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 3DStreet/3dstreet#720 it seems to work with ~1m accuracy.

@kfarr kfarr closed this as completed Aug 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants