CesiumGS / cesium

An open-source JavaScript library for world-class 3D globes and maps :earth_americas:
https://cesium.com/cesiumjs/
Apache License 2.0
12.94k stars 3.49k forks source link

Camera moveStart and moveEnd events don't work when camera is very close to the ground #4753

Open hpinkos opened 7 years ago

hpinkos commented 7 years ago

Reported on the forum: https://groups.google.com/forum/?hl=en#!topic/cesium-dev/SwoFMPNm5_g

This is particularly noticeable in 2D

var viewer = new Cesium.Viewer('cesiumContainer', {
    sceneMode: Cesium.SceneMode.SCENE2D
});

var camera = viewer.camera;
camera.moveStart.addEventListener(function() {
    console.log('start');
});
camera.moveEnd.addEventListener(function() {
    console.log('end');
});
  1. Zoom in all the way (you should see start/end print out to the console)
  2. Use the scroll wheel to zoom out one click at a time (start/end don't print out to the console until you're zoomed out a bit)

It looks like we are using EPSILON6, which is not significant enough when the camera is very close to the ground: https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Scene/Scene.js#L2349

The camera changed event does a much better job because it takes the camera height into consideration: https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Scene/Camera.js#L336

hpinkos commented 7 years ago

@bagnell is there a reason the camera.moveStart and camera.moveEnd events are raised in Scene and camera.changed is raised in Camera? It seems like these should use the same logic

DannyLebel commented 6 years ago

To add to the description of this issue. The same behavior is even more obvious with camera.changed event. In fact, the event is not triggered at all when the camera is below the ellipsoid. This is very clearly noticeable when using a terrain provider since it is possible to navigate under the level of the ellipsoid. And to be more specific, this issue occurs with the zoom and the translation navigation but not with the rotation.

Steps to reproduce

  1. Copy the example code in Sandcastle and execute it.
  2. Select the STK World Terrain Meshes in the imagery provider dropdown. (the camera is located at a position near the surface of the ellipsoid)
  3. Rotate the camera with middle click and cross the surface of the ellipsoid multiple times.
  4. Notice that the height is printed whether positive or negative.
  5. Now, zoom in and out so that the camera crosses the surface of the ellipsoid.
  6. Notice that the height is only printed when positive and never negative.
  7. Place the camera so that it is at a negative height.
  8. Move the camera with left click.
  9. Notice that the height is never printed out since the camera is below the ellipsoid.

Expected Behavrior

The moveStart, moveEnd and changed events are triggered whether the camera is above or below the ellipsoid. (In our use cases we navigate near the surface of the terrain and very often under the ellipsoid.)

Example code

var viewer = new Cesium.Viewer('cesiumContainer');

var camera = viewer.camera;

camera.position = new Cesium.Cartesian3(1408166.1338912349, -4136627.945644175, 4630485.211009045);

camera.percentageChanged = 0.001;
camera.changed.addEventListener(
    function()
                               {
    var height = Cesium.Cartographic.fromCartesian(camera.position).height;
    console.log(height);
}.bind(camera));
hpinkos commented 6 years ago

Thanks for expanding on this @DannyLebel!

hpinkos commented 6 years ago

This event is almost never triggered when navigating an indoor 3D tileset. camera.changed has the same problem.