delayed changes to height

I am using the Camera.setView API to specify a position (including height), heading, pitch and roll. For example:

viewer.camera.setView({
    positionCartographic: Cesium.Cartographic.fromDegrees(-71.304006, -33.378611, 0),
    heading: Cesium.Math.toRadians(41.5725784302),
    pitch: 0,
    roll: 0
});

What I'm seeing is that immediately after this call, if I check the camera position height via:

viewer.scene.globe.ellipsoid.cartesianToCartographic(viewer.camera.position).height

this value is 0. However, if I wait several seconds after the setView call (with no further changes or user interaction), the height is reported as 512.8532641851385. At that point I can then call viewer.camera.setView, again specifying a height of 0, which results in the height actually being set to 365.16182601730156.

What I actually see in the browser window is, initially, the camera is clearly well above ground level. After the second call to viewer.camera.setView, however, the camera is either at ground level or at least reasonably close to it.

The above numbers are using a terrain server. I see the same delayed-height-change behavior without the terrain server, though the numbers are much lower.

This leads to several questions:

1. What is causing the delayed height shift? Is it due to trying to change height, pitch and roll all at the same time? Or is it due to a delay in retrieving terrain data?

2. How can I perform another action (changing the height) after #1 (whatever it is) has completed?

3. I'd like to confirm - I'm guessing I can only get as low as 365 is because that is what the terrain server is reporting as the elevation for this point?

  1. No, you can change the position, heading pitch and roll at the same. Yes, it is related to the terrain. We do collision detection between the camera and the terrain to prevent the camera from going below the terrain. When you set the camera height to zero, the next render frame the collision detection is performed and the current terrain height is at 512 so it moves the camera above it. The higher resolution terrain is being loaded so the next time you set the height it gets moved back up to 365.

  2. The terrain LOD is based on the camera position. Currently, there is no way to set the camera from a global view to the terrain height because we won’t know what terrain to load until the camera moves closer. You can look at the code for the Monster Milktruck which displays a loading screen until the terrain is fully loaded in an area. It checks if the terrain is at the highest resolution, moves the camera close if not, repeats. Its not a great solution, but its the only way I was able to do it until there is a better method

  3. The terrain height for that location is around 363 but we push the camera a little above the terrain.

Thank you - that example was very helpful. I am now able to set the height correctly.

However, although I was able to adapt your example to make mine work, I'm still a little unclear on a few parts of how this is working.

1. Why with each camera.setView call are we increasing height by 1? I understand why we're increasing the level value, but why height as well?

2. Once we've reached the maximum level, there's another sort of loop where, as the scene renders, it looks like we're waiting until the "pickedHeight" is reasonably close to the terrain height at the specified location. My question here is - what is the distinction between the "pickedHeight" (from viewer.scene.globe.getHeight) vs. the height as retrieved from the terrain server? And how does this vary as each frame is rendered?

3. I found that at the end of all this, even though Cesium is reporting that the camera height now matches the terrain height, I'm still seeing the browser show the original (too high) height. I need to make one final call to camera.setView to make it render properly. Why is this last call necessary?