From f401d277b83b799c5c1ae8533574cf76b50b8ffa Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 11 Jul 2016 17:05:06 -0400 Subject: [PATCH 1/6] Disable camera input before a flight and do not reenable until the terrain has finished loading for the area. --- Source/Scene/Camera.js | 82 +++++++++++++++++++++ Source/Scene/CameraFlightPath.js | 13 +++- Source/Scene/Scene.js | 5 +- Source/Scene/ScreenSpaceCameraController.js | 73 +----------------- 4 files changed, 97 insertions(+), 76 deletions(-) diff --git a/Source/Scene/Camera.js b/Source/Scene/Camera.js index 0a1629fb0213..066b8c018f88 100644 --- a/Source/Scene/Camera.js +++ b/Source/Scene/Camera.js @@ -219,6 +219,7 @@ define([ this._projection = projection; this._maxCoord = projection.project(new Cartographic(Math.PI, CesiumMath.PI_OVER_TWO)); this._max2Dfrustum = undefined; + this._suspendTerrainAdjustment = false; // set default view rectangleCameraPosition3D(this, Camera.DEFAULT_VIEW_RECTANGLE, this.position, true); @@ -338,6 +339,75 @@ define([ } }; + var scratchAdjustHeightCartographic = new Cartographic(); + + Camera.prototype._adjustHeightForTerrain = function() { + var scene = this._scene; + + // TODO: deprecate and move to camera + var enableCollisionDetection = scene.screenSpaceCameraController.enableCollisionDetection; + var minimumCollisionTerrainHeight = scene.screenSpaceCameraController.minimumCollisionTerrainHeight; + var minimumZoomDistance = scene.screenSpaceCameraController.minimumZoomDistance; + + if (this._suspendTerrainAdjustment || !enableCollisionDetection) { + return; + } + + var mode = this._mode; + var globe = scene.globe; + + if (!defined(globe) || mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) { + return; + } + + var ellipsoid = globe.ellipsoid; + var projection = scene.mapProjection; + + var transform; + var mag; + if (!Matrix4.equals(this.transform, Matrix4.IDENTITY)) { + transform = Matrix4.clone(this.transform); + mag = Cartesian3.magnitude(this.position); + this._setTransform(Matrix4.IDENTITY); + } + + var cartographic = scratchAdjustHeightCartographic; + if (mode === SceneMode.SCENE3D) { + ellipsoid.cartesianToCartographic(this.position, cartographic); + } else { + projection.unproject(this.position, cartographic); + } + + var heightUpdated = false; + if (cartographic.height < minimumCollisionTerrainHeight) { + var height = globe.getHeight(cartographic); + if (defined(height)) { + height += minimumZoomDistance; + if (cartographic.height < height) { + cartographic.height = height; + if (mode === SceneMode.SCENE3D) { + ellipsoid.cartographicToCartesian(cartographic, this.position); + } else { + projection.project(cartographic, this.position); + } + heightUpdated = true; + } + } + } + + if (defined(transform)) { + this._setTransform(transform); + if (heightUpdated) { + Cartesian3.normalize(this.position, this.position); + Cartesian3.negate(this.position, this.direction); + Cartesian3.multiplyByScalar(this.position, Math.max(mag, minimumZoomDistance), this.position); + Cartesian3.normalize(this.direction, this.direction); + Cartesian3.cross(this.direction, this.up, this.right); + Cartesian3.cross(this.right, this.direction, this.up); + } + } + }; + function convertTransformForColumbusView(camera) { Transforms.basisTo2D(camera._projection, camera._transform, camera._actualTransform); } @@ -854,6 +924,14 @@ define([ if (this._mode === SceneMode.SCENE2D) { clampMove2D(this, this.position); } + + var globe = this._scene.globe; + var globeFinishedUpdating = !defined(globe) || (globe._surface.tileProvider.ready && !defined(globe._surface._tileLoadQueue.head) && globe._surface._debug.tilesWaitingForChildren === 0); + if (this._suspendTerrainAdjustment) { + this._scene.screenSpaceCameraController.enableInputs = globeFinishedUpdating; + this._suspendTerrainAdjustment = !globeFinishedUpdating; + } + this._adjustHeightForTerrain(); }; var setTransformPosition = new Cartesian3(); @@ -1082,6 +1160,8 @@ define([ var pitch = defaultValue(orientation.pitch, -CesiumMath.PI_OVER_TWO); var roll = defaultValue(orientation.roll, 0.0); + this._suspendTerrainAdjustment = true; + if (mode === SceneMode.SCENE3D) { setView3D(this, destination, heading, pitch, roll); } else if (mode === SceneMode.SCENE2D) { @@ -2542,6 +2622,7 @@ define([ destination = this.getRectangleCameraCoordinates(destination, scratchFlyToDestination); } + /* var sscc = this._scene.screenSpaceCameraController; if (defined(sscc) || mode === SceneMode.SCENE2D) { @@ -2574,6 +2655,7 @@ define([ destination = ellipsoid.cartographicToCartesian(destinationCartographic, scratchFlyToDestination); } } + */ newOptions.destination = destination; newOptions.heading = orientation.heading; diff --git a/Source/Scene/CameraFlightPath.js b/Source/Scene/CameraFlightPath.js index 4b7b28df3e94..9cfba86206f3 100644 --- a/Source/Scene/CameraFlightPath.js +++ b/Source/Scene/CameraFlightPath.js @@ -151,9 +151,11 @@ define([ var startRoll = adjustAngleForLERP(camera.roll, roll); var destCart = ellipsoid.cartesianToCartographic(destination, scratchEndCart); + /* if (destCart.height <= 0.0) { destCart.height = startCart.height; } + */ startCart.longitude = CesiumMath.zeroToTwoPi(startCart.longitude); destCart.longitude = CesiumMath.zeroToTwoPi(destCart.longitude); @@ -291,11 +293,14 @@ define([ var pitch = defaultValue(options.pitch, -CesiumMath.PI_OVER_TWO); var roll = defaultValue(options.roll, 0.0); - var controller = scene.screenSpaceCameraController; - controller.enableInputs = false; + //var controller = scene.screenSpaceCameraController; + //controller.enableInputs = false; - var complete = wrapCallback(controller, options.complete); - var cancel = wrapCallback(controller, options.cancel); + //var complete = wrapCallback(controller, options.complete); + //var cancel = wrapCallback(controller, options.cancel); + + var complete = options.complete; + var cancel = options.cancel; var frustum = camera.frustum; diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js index fcfd53fc76d5..0f47731b8191 100644 --- a/Source/Scene/Scene.js +++ b/Source/Scene/Scene.js @@ -2303,13 +2303,14 @@ define([ } this._tweens.update(); - this._camera.update(this._mode); - this._camera._updateCameraChanged(); this._screenSpaceCameraController.update(); if (defined(this._deviceOrientationCameraController)) { this._deviceOrientationCameraController.update(); } + + this._camera.update(this._mode); + this._camera._updateCameraChanged(); }; var scratchEyeTranslation = new Cartesian3(); diff --git a/Source/Scene/ScreenSpaceCameraController.js b/Source/Scene/ScreenSpaceCameraController.js index 23af144ee69d..02a98707494e 100644 --- a/Source/Scene/ScreenSpaceCameraController.js +++ b/Source/Scene/ScreenSpaceCameraController.js @@ -991,7 +991,6 @@ define([ } function rotateCVOnTerrain(controller, startPosition, movement) { - var ellipsoid = controller._ellipsoid; var scene = controller._scene; var camera = scene.camera; @@ -1046,7 +1045,7 @@ define([ var verticalCenter = IntersectionTests.rayPlane(ray, plane, rotateCVVerticalCenter); var projection = camera._projection; - ellipsoid = projection.ellipsoid; + var ellipsoid = projection.ellipsoid; Cartesian3.fromElements(center.y, center.z, center.x, center); var cart = projection.unproject(center, rotateCVCart); @@ -1122,7 +1121,7 @@ define([ controller._rotateRateRangeAdjustment = radius; var originalPosition = Cartesian3.clone(camera.positionWC, rotateCVCartesian3); - adjustHeightForTerrain(controller); + camera._adjustHeightForTerrain(); if (!Cartesian3.equals(camera.positionWC, originalPosition)) { camera._setTransform(verticalTransform); @@ -1753,7 +1752,7 @@ define([ controller._rotateRateRangeAdjustment = radius; var originalPosition = Cartesian3.clone(camera.positionWC, tilt3DCartesian3); - adjustHeightForTerrain(controller); + camera._adjustHeightForTerrain(); if (!Cartesian3.equals(camera.positionWC, originalPosition)) { camera._setTransform(verticalTransform); @@ -1866,70 +1865,6 @@ define([ reactToInput(controller, controller.enableLook, controller.lookEventTypes, look3D); } - var scratchAdjustHeightCartographic = new Cartographic(); - - function adjustHeightForTerrain(controller) { - if (!controller.enableCollisionDetection) { - return; - } - - var scene = controller._scene; - var mode = scene.mode; - var globe = scene.globe; - - if (!defined(globe) || mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) { - return; - } - - var camera = scene.camera; - var ellipsoid = globe.ellipsoid; - var projection = scene.mapProjection; - - var transform; - var mag; - if (!Matrix4.equals(camera.transform, Matrix4.IDENTITY)) { - transform = Matrix4.clone(camera.transform); - mag = Cartesian3.magnitude(camera.position); - camera._setTransform(Matrix4.IDENTITY); - } - - var cartographic = scratchAdjustHeightCartographic; - if (mode === SceneMode.SCENE3D) { - ellipsoid.cartesianToCartographic(camera.position, cartographic); - } else { - projection.unproject(camera.position, cartographic); - } - - var heightUpdated = false; - if (cartographic.height < controller._minimumCollisionTerrainHeight) { - var height = globe.getHeight(cartographic); - if (defined(height)) { - height += controller.minimumZoomDistance; - if (cartographic.height < height) { - cartographic.height = height; - if (mode === SceneMode.SCENE3D) { - ellipsoid.cartographicToCartesian(cartographic, camera.position); - } else { - projection.project(cartographic, camera.position); - } - heightUpdated = true; - } - } - } - - if (defined(transform)) { - camera._setTransform(transform); - if (heightUpdated) { - Cartesian3.normalize(camera.position, camera.position); - Cartesian3.negate(camera.position, camera.direction); - Cartesian3.multiplyByScalar(camera.position, Math.max(mag, controller.minimumZoomDistance), camera.position); - Cartesian3.normalize(camera.direction, camera.direction); - Cartesian3.cross(camera.direction, camera.up, camera.right); - Cartesian3.cross(camera.right, camera.direction, camera.up); - } - } - } - /** * @private */ @@ -1962,8 +1897,6 @@ define([ update3D(this); } - adjustHeightForTerrain(this); - this._aggregator.reset(); }; From 291c96c73edb50f5831e9d8e29c07019c286a1d2 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Thu, 14 Jul 2016 16:02:41 -0400 Subject: [PATCH 2/6] Re-enable input after camera flight not terrain load completion. --- Source/Scene/Camera.js | 1 - Source/Scene/CameraFlightPath.js | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Source/Scene/Camera.js b/Source/Scene/Camera.js index 066b8c018f88..ffca211d41be 100644 --- a/Source/Scene/Camera.js +++ b/Source/Scene/Camera.js @@ -928,7 +928,6 @@ define([ var globe = this._scene.globe; var globeFinishedUpdating = !defined(globe) || (globe._surface.tileProvider.ready && !defined(globe._surface._tileLoadQueue.head) && globe._surface._debug.tilesWaitingForChildren === 0); if (this._suspendTerrainAdjustment) { - this._scene.screenSpaceCameraController.enableInputs = globeFinishedUpdating; this._suspendTerrainAdjustment = !globeFinishedUpdating; } this._adjustHeightForTerrain(); diff --git a/Source/Scene/CameraFlightPath.js b/Source/Scene/CameraFlightPath.js index 9cfba86206f3..7f7529454d50 100644 --- a/Source/Scene/CameraFlightPath.js +++ b/Source/Scene/CameraFlightPath.js @@ -293,14 +293,14 @@ define([ var pitch = defaultValue(options.pitch, -CesiumMath.PI_OVER_TWO); var roll = defaultValue(options.roll, 0.0); - //var controller = scene.screenSpaceCameraController; - //controller.enableInputs = false; + var controller = scene.screenSpaceCameraController; + controller.enableInputs = false; - //var complete = wrapCallback(controller, options.complete); - //var cancel = wrapCallback(controller, options.cancel); + var complete = wrapCallback(controller, options.complete); + var cancel = wrapCallback(controller, options.cancel); - var complete = options.complete; - var cancel = options.cancel; + //var complete = options.complete; + //var cancel = options.cancel; var frustum = camera.frustum; From e3d243e258b8438954fa7dc57dc70d5e155daea6 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 1 Aug 2016 13:39:30 -0400 Subject: [PATCH 3/6] Remove commented code and use scratch variables. --- Source/Scene/Camera.js | 48 +++++--------------------------- Source/Scene/CameraFlightPath.js | 9 ------ 2 files changed, 7 insertions(+), 50 deletions(-) diff --git a/Source/Scene/Camera.js b/Source/Scene/Camera.js index ffca211d41be..67f8494c4c48 100644 --- a/Source/Scene/Camera.js +++ b/Source/Scene/Camera.js @@ -339,15 +339,17 @@ define([ } }; + var scratchAdjustHeightTransform = new Matrix4(); var scratchAdjustHeightCartographic = new Cartographic(); Camera.prototype._adjustHeightForTerrain = function() { var scene = this._scene; - // TODO: deprecate and move to camera - var enableCollisionDetection = scene.screenSpaceCameraController.enableCollisionDetection; - var minimumCollisionTerrainHeight = scene.screenSpaceCameraController.minimumCollisionTerrainHeight; - var minimumZoomDistance = scene.screenSpaceCameraController.minimumZoomDistance; + // Should these be moved to the camera? + var screenSpaceCameraController = scene.screenSpaceCameraController; + var enableCollisionDetection = screenSpaceCameraController.enableCollisionDetection; + var minimumCollisionTerrainHeight = screenSpaceCameraController.minimumCollisionTerrainHeight; + var minimumZoomDistance = screenSpaceCameraController.minimumZoomDistance; if (this._suspendTerrainAdjustment || !enableCollisionDetection) { return; @@ -366,7 +368,7 @@ define([ var transform; var mag; if (!Matrix4.equals(this.transform, Matrix4.IDENTITY)) { - transform = Matrix4.clone(this.transform); + transform = Matrix4.clone(this.transform, scratchAdjustHeightTransform); mag = Cartesian3.magnitude(this.position); this._setTransform(Matrix4.IDENTITY); } @@ -2521,7 +2523,6 @@ define([ }; var scratchFlyToDestination = new Cartesian3(); - var scratchFlyToCarto = new Cartographic(); var newOptions = { destination : undefined, heading : undefined, @@ -2621,41 +2622,6 @@ define([ destination = this.getRectangleCameraCoordinates(destination, scratchFlyToDestination); } - /* - var sscc = this._scene.screenSpaceCameraController; - - if (defined(sscc) || mode === SceneMode.SCENE2D) { - var ellipsoid = this._scene.mapProjection.ellipsoid; - var destinationCartographic = ellipsoid.cartesianToCartographic(destination, scratchFlyToCarto); - var height = destinationCartographic.height; - - // Make sure camera doesn't zoom outside set limits - if (defined(sscc)) { - //The computed height for rectangle in 2D/CV is stored in the 'z' component of Cartesian3 - if (mode !== SceneMode.SCENE3D && isRectangle) { - destination.z = CesiumMath.clamp(destination.z, sscc.minimumZoomDistance, sscc.maximumZoomDistance); - } else { - destinationCartographic.height = CesiumMath.clamp(destinationCartographic.height, sscc.minimumZoomDistance, sscc.maximumZoomDistance); - } - } - - // The max height in 2D might be lower than the max height for sscc. - if (mode === SceneMode.SCENE2D) { - var maxHeight = ellipsoid.maximumRadius * Math.PI * 2.0; - if (isRectangle) { - destination.z = Math.min(destination.z, maxHeight); - } else { - destinationCartographic.height = Math.min(destinationCartographic.height, maxHeight); - } - } - - //Only change if we clamped the height - if (destinationCartographic.height !== height) { - destination = ellipsoid.cartographicToCartesian(destinationCartographic, scratchFlyToDestination); - } - } - */ - newOptions.destination = destination; newOptions.heading = orientation.heading; newOptions.pitch = orientation.pitch; diff --git a/Source/Scene/CameraFlightPath.js b/Source/Scene/CameraFlightPath.js index 7f7529454d50..3aacb634f9b1 100644 --- a/Source/Scene/CameraFlightPath.js +++ b/Source/Scene/CameraFlightPath.js @@ -151,12 +151,6 @@ define([ var startRoll = adjustAngleForLERP(camera.roll, roll); var destCart = ellipsoid.cartesianToCartographic(destination, scratchEndCart); - /* - if (destCart.height <= 0.0) { - destCart.height = startCart.height; - } - */ - startCart.longitude = CesiumMath.zeroToTwoPi(startCart.longitude); destCart.longitude = CesiumMath.zeroToTwoPi(destCart.longitude); @@ -299,9 +293,6 @@ define([ var complete = wrapCallback(controller, options.complete); var cancel = wrapCallback(controller, options.cancel); - //var complete = options.complete; - //var cancel = options.cancel; - var frustum = camera.frustum; var empty = scene.mode === SceneMode.SCENE2D; From d3164f4884286a5d411ed6e66b8a87a9dfeb2bdf Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 1 Aug 2016 14:07:23 -0400 Subject: [PATCH 4/6] Update tests. --- Specs/Scene/ModelSpec.js | 10 +++++++++- Specs/Scene/ScreenSpaceCameraControllerSpec.js | 13 +++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Specs/Scene/ModelSpec.js b/Specs/Scene/ModelSpec.js index 8756b4e7773f..30148d615ea1 100644 --- a/Specs/Scene/ModelSpec.js +++ b/Specs/Scene/ModelSpec.js @@ -1834,7 +1834,15 @@ defineSuite([ getHeight : function() { return 0.0; }, - _surface : {}, + _surface : { + tileProvider : { + ready : true + }, + _tileLoadQueue : {}, + _debug : { + tilesWaitingForChildren : 0 + } + }, destroy : function() {} }; diff --git a/Specs/Scene/ScreenSpaceCameraControllerSpec.js b/Specs/Scene/ScreenSpaceCameraControllerSpec.js index 015875efd384..0bb6a625bbda 100644 --- a/Specs/Scene/ScreenSpaceCameraControllerSpec.js +++ b/Specs/Scene/ScreenSpaceCameraControllerSpec.js @@ -57,6 +57,7 @@ defineSuite([ this.globe = undefined; this.mapProjection = new GeographicProjection(ellipsoid); this.terrainExaggeration = 1.0; + this.screenSpaceCameraController = undefined; } function MockGlobe(ellipsoid) { @@ -64,6 +65,15 @@ defineSuite([ this.getHeight = function(cartographic) { return 0.0; }; + this._surface = { + tileProvider : { + ready : true + }, + _tileLoadQueue : {}, + _debug : { + tilesWaitingForChildren : 0 + } + }; } beforeAll(function() { canvas = createCanvas(1024, 768); @@ -86,6 +96,9 @@ defineSuite([ scene = new MockScene(canvas, camera, Ellipsoid.WGS84); controller = new ScreenSpaceCameraController(scene); + + scene.screenSpaceCameraController = controller; + camera._scene = scene; }); afterEach(function() { From f057cf140bc7c9493fc165213e3e5d010bff8b61 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 1 Aug 2016 14:14:32 -0400 Subject: [PATCH 5/6] Update CHANGES.md. --- CHANGES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index c917c1fe4be4..a05e65951e28 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,10 @@ Change Log ========== +### 1.25 - 2016-09-01 + +* Camera flights now disable collision with the terrain until all of the terrain in the area has finished loading. This prevents the camera from being moved to be above lower resolution terrain when flying to a position close to higher resolution terrain. [#4075](https://github.com/AnalyticalGraphicsInc/cesium/issues/4075) + ### 1.24 - 2016-08-01 * Added support in CZML for expressing `BillboardGraphics.alignedAxis` as the velocity vector of an entity, using `velocityReference` syntax. From 7c324c6ae682c75a87f9c93c93935ff0e2c57a2d Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 2 Aug 2016 15:11:34 -0400 Subject: [PATCH 6/6] Remove code comment. --- Source/Scene/Camera.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/Scene/Camera.js b/Source/Scene/Camera.js index 67f8494c4c48..ac0e65bffedc 100644 --- a/Source/Scene/Camera.js +++ b/Source/Scene/Camera.js @@ -345,7 +345,6 @@ define([ Camera.prototype._adjustHeightForTerrain = function() { var scene = this._scene; - // Should these be moved to the camera? var screenSpaceCameraController = scene.screenSpaceCameraController; var enableCollisionDetection = screenSpaceCameraController.enableCollisionDetection; var minimumCollisionTerrainHeight = screenSpaceCameraController.minimumCollisionTerrainHeight;