How to get the altitude of 3D models directly under the given coordinates

Objective

With 3D models (terrain and tileset) loaded into scene, we would like to obtain the altitude of the 3D model directly under the given coordinates.
The altitude to be acquired should be as accurate as possible, and should be invariant regardless of the camera position, etc.

What we tried, Part 1

First, we tried viewer.scene.sampleHeightMostDetailed.
We were able to get the altitude of the intersection with the terrain or tileset directly under the given coordinates.
However, we found that changing the camera position, zoom level, etc. returned different altitudes.
(I thought that perhaps the level of detail was changed, and thus the coordinate information in the scene was also changed.)

The behavior differs depending on whether the object directly below the scene is a terrain or a tileset.

If a terrain was directly under the given coordinate, the following values were returned depending on the camera position.
29.37 (when close)
-22979.007 (when far away)
undefined (when the earth is so far away that it cannot be seen)

If a tileset was directly under the given coordinate, the coordinate values returned were almost the same regardless of the camera position, although they shifted by several tens of centimeters.

What we tried, Part 2

Next, we tried Cesium.sampleTerrainMostDetailed(terrainProvider, positions).
It always returned a constant altitude, regardless of camera position or zoom level.
However, we found that this method only returns the altitude of the terrain and does not include the altitude of the tileset.

With the above in mind, I would like to know the best way to achieve my objective.

Hi there,

Would you mind providing a Sandcastle code example? viewer.scene.sampleHeightMostDetailed involved a pick, which can be affected by at what point in the render lifecycle the function is called.

Hi Gabby_Getz

Thank you for your reply.

I am sending you the sandcastle code example.
(If there are any usage mistakes, please let me know)

viewer.scene.sampleHeightMostDetailed involved a pick, which can be affected by at what point in the render lifecycle the function is called.

We want to get accurate altitude information no matter where on the planet the user is looking.
Maybe viewer.scene.sampleHeightMostDetailed is not appropriate for our use case.

For terrain, Cesium.sampleTerrainMostDetailed(terrainProvider, positions) is getting the right value.
A similar function for tileset would solve the problem, but I could not find it in the cesium source code or documentation.

Ah, I see the conflicting values that are occurring in scene.sampleHeightMostDetailed. This example shows the use case the function was originally designed around, and I’m not sure the drastic camera changes are fully accounted for.

We would like to obtain the altitude of the 3D model directly under the given coordinates. The altitude to be acquired should be as accurate as possible, and should be invariant regardless of the camera position, etc.

Could you provide a bit more detail about what these values are being used for? That may help narrow down any possible solutions.

I’m not sure the drastic camera changes are fully accounted for.

We feel that we are probably going beyond the expected use as well.

Could you provide a bit more detail about what these values are being used for?

I am interested in graphing the altitude on the ground directly under two points in the sky.
The graphing can be done by dividing the distance between the two given points into N equal parts and obtaining the ground altitude at each interior point.

Initially, I called synchronous sampleHeight N times in one animation loop.
However, since sampleHeight takes a certain amount of time, the screen froze when N became large.

To solve this problem, we made the following tuning

  • Use asynchronous sampleHeightMostDetailed
  • Limit the number of sampleHeightMostDetailed to be executed in one animation loop

As a result, the screen freeze problem has been resolved.
However, this implementation may cause the user to perform unintended camera operations during the course of updating the ground elevation of all interior points.
The resulting altitude is less reliable.

How is the current situation? If this part is not resolved, we will not be able to achieve our goal. We are very troubled. Any advice you can give me would be greatly appreciated.

Hi @tomohiko.hishinuma,

I understand the use case of graphing altitudes along a line between two points, however, I’m still not sure how the animation loop factors in. Does this graph need to be constantly updated based on the camera position?

We’ve seen a similar use case where we needed to have a widget that showed the current world position under the user’s mouse. Getting the most accurate position was asynchronous, but the user needed some immediate feedback in the UI. We chose to show an estimate of the position in the UI until the user stopped moving their mouse, at which point we could wait for the asynchronous operation to complete before showing the more accurate result.

Thanks,
Gabby

@Gabby_Getz

Thank you for your reply.

My explanation was not enough, so there may have been a misunderstanding.
I will try to explain it again, so please take a moment to check again.

Does this graph need to be constantly updated according to the camera position?

This graph needs to be constantly updated “independently” of the camera position.

Screen freeze issue.

When two points in space are specified by a user operation, the ground altitude directly below the line segment connecting the two points is determined.
Normally, we would like to update the graph immediately at that moment, but this process is very heavy and causes the UI to freeze.

As I told you in a previous message as follows.

Initially, I called synchronous sampleHeight N times in one animation loop.
However, since sampleHeight takes a certain amount of time, the screen froze when N became large.

Limit the number of times “synchronous sampleHeight” can be executed in one animation loop

The UI freezes seemed to be caused by updating all interior points in one animation loop.
Our idea was to split the N endpoints and limit the number of “synchronous sampleHeight” calls in one animation loop.

This part corresponds to the following part of the previous message.
(I wrote “sampleHeightMostDetailed”, but please interpret it as “synchronous sampleHeight”.)

Limit the number of sampleHeightMostDetailed to be executed in one animation loop

For example, if we call “synchronous sampleHeight” 5 times per animation loop, it means that we can update all N interior points in N/5 animation loops.
In this way, the cost per animation loop would be reduced and freezes would be avoided as the process would be returned to the system.
This plan worked, and we were able to avoid screen freezes while updating the graphs.

However, a problem arose with this specification.
The user could freely move the camera while updating the graph.
This caused the “synchronous sampleHeight” result to change during the graph update.
This is problematic because the altitude above ground should be constant regardless of the camera position.

Application of sampleHeightMostDetailed

So far, we have used the “synchronous sampleHeight” method.
We thought, “Maybe the problem is that we are using a synchronous function.”
So we tried the asynchronous version of sampleHeightMostDetailed as well.

As we told you in a previous message as follows.

Use asynchronous sampleHeightMostDetailed

We decided to limit the execution to one animation loop, basically the same as “synchronous sampleHeight”.
However, considering that this is an asynchronous function, we added a process that waits for additional execution when the function executed in the previous animation loop is in the “running” status.
As a result, the same problem as with “synchronous sampleHeight” occurred.

This is the current situation.

As I mentioned in my first message,
For only terrain, Cesium.sampleTerrainMostDetailed(terrainProvider, positions) will solve the problem.

The problem is that we have a system with Terrain + tileset.
If we want to get the altitude information including tileset information, we would use sampleHeightMostDetailed,
However, due to the aforementioned problem, it cannot be used.

I expected a function like Cesium.sampleTilesetMostDetailed(tileset, positions), but I could not find it in the CesiumJS documentation or source code.

Thanks. I did track down where I think the issue with sampleHeight and sampleHeightMostDetailed is originating – scene.pickPosition returns incorrect position · Issue #4368 · CesiumGS/cesium · GitHub. Please keep an eye on that issue, as we will update with any progress there.

For sampleHeight, you may be able to workaround the issue by using Scene.afterRender instead of requestAnimationFrame and making a call to pick before sampleHeight. I’s tricky to apply a workaround for sampleHeightMostDetailed as the actual picking is deferred until all needed 3D Tiles data is loaded, so there is less control over when the pick function is executed.