From a8bde9ab06d6426c3891768361c6955e8580ab65 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 11:03:46 +0900 Subject: [PATCH 01/15] Update wheel logic --- src/three/controls/EnvironmentControls.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/three/controls/EnvironmentControls.js b/src/three/controls/EnvironmentControls.js index 957eb007..4ce0ea37 100644 --- a/src/three/controls/EnvironmentControls.js +++ b/src/three/controls/EnvironmentControls.js @@ -378,6 +378,14 @@ export class EnvironmentControls extends EventDispatcher { e.preventDefault(); + const { pointerTracker } = this; + pointerTracker.setHoverEvent( e ); + if ( ! pointerTracker.updatePointer( e ) ) { + + return; + + } + this.dispatchEvent( _startEvent ); let delta; From 0c4392faab6c82113ea04062771389e375512aaa Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 11:03:56 +0900 Subject: [PATCH 02/15] Add raycast from mouse position --- src/three/controls/EnvironmentControls.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/three/controls/EnvironmentControls.js b/src/three/controls/EnvironmentControls.js index 4ce0ea37..3d175f72 100644 --- a/src/three/controls/EnvironmentControls.js +++ b/src/three/controls/EnvironmentControls.js @@ -949,6 +949,19 @@ export class EnvironmentControls extends EventDispatcher { } + _raycastAtMousePosition( coords, raycaster ) { + + const camera = this.camera; + const ray = raycaster.ray; + ray.origin.setFromMatrixPosition( camera.matrixWorld ); + ray.origin.set( coords.x, coords.y, - 1 ).unproject( camera ); + ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( ray.origin ).normalize(); + raycaster.camera = camera; + + return this._raycast( raycaster ); + + } + _raycast( raycaster ) { const { scene, useFallbackPlane, fallbackPlane } = this; From 0e58e74593de32ae6314c5728904938d2a08e735 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 11:06:53 +0900 Subject: [PATCH 03/15] Use raycast function --- src/three/controls/EnvironmentControls.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/three/controls/EnvironmentControls.js b/src/three/controls/EnvironmentControls.js index 3d175f72..6dfc03bc 100644 --- a/src/three/controls/EnvironmentControls.js +++ b/src/three/controls/EnvironmentControls.js @@ -222,8 +222,7 @@ export class EnvironmentControls extends EventDispatcher { mouseToCoords( _pointer.x, _pointer.y, domElement, _pointer ); // find the hit point - raycaster.setFromCamera( _pointer, camera ); - const hit = this._raycast( raycaster ); + const hit = this._raycastAtMousePosition( _pointer, raycaster ); if ( hit ) { // if two fingers, right click, or shift click are being used then we trigger @@ -951,6 +950,7 @@ export class EnvironmentControls extends EventDispatcher { _raycastAtMousePosition( coords, raycaster ) { + // position the ray for the raycaster at the near clip plane const camera = this.camera; const ray = raycaster.ray; ray.origin.setFromMatrixPosition( camera.matrixWorld ); From 84468085115ae401f411bcc4e603f881e41edf36 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 11:11:42 +0900 Subject: [PATCH 04/15] Share some common vectors for actions --- src/three/controls/EnvironmentControls.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/three/controls/EnvironmentControls.js b/src/three/controls/EnvironmentControls.js index 6dfc03bc..ffeb1ade 100644 --- a/src/three/controls/EnvironmentControls.js +++ b/src/three/controls/EnvironmentControls.js @@ -93,16 +93,19 @@ export class EnvironmentControls extends EventDispatcher { this.needsUpdate = false; this.actionHeightOffset = 0; + this.pivotPoint = new Vector3(); + this.pivotDirection = new Vector3(); + this.dragPointSet = false; - this.dragPoint = new Vector3(); + this.dragPoint = this.pivotPoint; this.rotationPointSet = false; - this.rotationPoint = new Vector3(); + this.rotationPoint = this.pivotPoint; this.zoomDirectionSet = false; this.zoomPointSet = false; - this.zoomDirection = new Vector3(); - this.zoomPoint = new Vector3(); + this.zoomDirection = this.pivotDirection; + this.zoomPoint = this.pivotPoint; this.zoomDelta = 0; this.pivotMesh = new PivotPointMesh(); From a2a936d07dea36c2bc48d7575df339520cd8d47e Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 11:16:24 +0900 Subject: [PATCH 05/15] Undo zoom direction change --- src/three/controls/EnvironmentControls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/three/controls/EnvironmentControls.js b/src/three/controls/EnvironmentControls.js index ffeb1ade..f459195d 100644 --- a/src/three/controls/EnvironmentControls.js +++ b/src/three/controls/EnvironmentControls.js @@ -104,7 +104,7 @@ export class EnvironmentControls extends EventDispatcher { this.zoomDirectionSet = false; this.zoomPointSet = false; - this.zoomDirection = this.pivotDirection; + this.zoomDirection = new Vector3(); this.zoomPoint = this.pivotPoint; this.zoomDelta = 0; From 9a33163a11da40afa1023a72a1e04eefa7a3121b Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 11:18:22 +0900 Subject: [PATCH 06/15] Use common fields for rotation and drag --- src/three/controls/EnvironmentControls.js | 43 ++++++++++------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/src/three/controls/EnvironmentControls.js b/src/three/controls/EnvironmentControls.js index f459195d..d16ae00d 100644 --- a/src/three/controls/EnvironmentControls.js +++ b/src/three/controls/EnvironmentControls.js @@ -93,14 +93,9 @@ export class EnvironmentControls extends EventDispatcher { this.needsUpdate = false; this.actionHeightOffset = 0; + // pivot point for drag and rotation + this.pivotPointSet = false; this.pivotPoint = new Vector3(); - this.pivotDirection = new Vector3(); - - this.dragPointSet = false; - this.dragPoint = this.pivotPoint; - - this.rotationPointSet = false; - this.rotationPoint = this.pivotPoint; this.zoomDirectionSet = false; this.zoomPointSet = false; @@ -237,8 +232,8 @@ export class EnvironmentControls extends EventDispatcher { ) { this.setState( ROTATE ); - this.rotationPoint.copy( hit.point ); - this.rotationPointSet = true; + this.pivotPoint.copy( hit.point ); + this.pivotPointSet = true; this.pivotMesh.position.copy( hit.point ); this.pivotMesh.updateMatrixWorld(); @@ -250,8 +245,8 @@ export class EnvironmentControls extends EventDispatcher { if ( raycaster.ray.direction.dot( up ) < 0 ) { this.setState( DRAG ); - this.dragPoint.copy( hit.point ); - this.dragPointSet = true; + this.pivotPoint.copy( hit.point ); + this.pivotPointSet = true; this.pivotMesh.position.copy( hit.point ); this.pivotMesh.updateMatrixWorld(); @@ -484,8 +479,8 @@ export class EnvironmentControls extends EventDispatcher { this.state = NONE; this.pinchState = NONE; - this.dragPointSet = false; - this.rotationPointSet = false; + this.pivotPointSet = false; + this.pivotPointSet = false; this.scene.remove( this.pivotMesh ); this.pivotMesh.visible = true; this.actionHeightOffset = 0; @@ -522,7 +517,7 @@ export class EnvironmentControls extends EventDispatcher { const { camera, cameraRadius, - dragPoint, + pivotPoint, up, state, pinchState, @@ -583,7 +578,7 @@ export class EnvironmentControls extends EventDispatcher { const { actionHeightOffset } = this; camera.position.addScaledVector( up, - actionHeightOffset ); - dragPoint.addScaledVector( up, - actionHeightOffset ); + pivotPoint.addScaledVector( up, - actionHeightOffset ); // adjust the height if ( hit ) { @@ -603,7 +598,7 @@ export class EnvironmentControls extends EventDispatcher { const delta = cameraRadius - dist; camera.position.addScaledVector( up, delta ); - dragPoint.addScaledVector( up, delta ); + pivotPoint.addScaledVector( up, delta ); this.actionHeightOffset = delta; } @@ -778,7 +773,7 @@ export class EnvironmentControls extends EventDispatcher { const { raycaster, camera, - dragPoint, + pivotPoint, up, pointerTracker, domElement, @@ -788,7 +783,7 @@ export class EnvironmentControls extends EventDispatcher { pointerTracker.getCenterPoint( _pointer ); mouseToCoords( _pointer.x, _pointer.y, domElement, _pointer ); - _plane.setFromNormalAndCoplanarPoint( up, dragPoint ); + _plane.setFromNormalAndCoplanarPoint( up, pivotPoint ); raycaster.setFromCamera( _pointer, camera ); // prevent the drag distance from getting too severe by limiting the drag point @@ -815,7 +810,7 @@ export class EnvironmentControls extends EventDispatcher { // if we drag to a point that's near the edge of the earth then we want to prevent it // from wrapping around and causing unexpected rotations - this.getUpDirection( dragPoint, _localUp ); + this.getUpDirection( pivotPoint, _localUp ); if ( - raycaster.ray.direction.dot( _localUp ) < DRAG_UP_THRESHOLD ) { const angle = Math.acos( DRAG_UP_THRESHOLD ); @@ -834,7 +829,7 @@ export class EnvironmentControls extends EventDispatcher { // find the point on the plane that we should drag to if ( raycaster.ray.intersectPlane( _plane, _vec ) ) { - _delta.subVectors( dragPoint, _vec ); + _delta.subVectors( pivotPoint, _vec ); this.camera.position.add( _delta ); this.camera.updateMatrixWorld(); @@ -846,7 +841,7 @@ export class EnvironmentControls extends EventDispatcher { const { camera, - rotationPoint, + pivotPoint, minAltitude, maxAltitude, up, @@ -868,7 +863,7 @@ export class EnvironmentControls extends EventDispatcher { .transformDirection( camera.matrixWorld ) .multiplyScalar( - 1 ); - this.getUpDirection( rotationPoint, _localUp ); + this.getUpDirection( pivotPoint, _localUp ); // get the signed angle relative to the top down view _vec.crossVectors( up, _forward ).normalize(); @@ -892,14 +887,14 @@ export class EnvironmentControls extends EventDispatcher { // rotate around the up axis _quaternion.setFromAxisAngle( _localUp, azimuth ); - makeRotateAroundPoint( rotationPoint, _quaternion, _rotMatrix ); + makeRotateAroundPoint( pivotPoint, _quaternion, _rotMatrix ); camera.matrixWorld.premultiply( _rotMatrix ); // get a rotation axis for altitude and rotate _rotationAxis.set( - 1, 0, 0 ).transformDirection( camera.matrixWorld ); _quaternion.setFromAxisAngle( _rotationAxis, altitude ); - makeRotateAroundPoint( rotationPoint, _quaternion, _rotMatrix ); + makeRotateAroundPoint( pivotPoint, _quaternion, _rotMatrix ); camera.matrixWorld.premultiply( _rotMatrix ); // update the transform members From b6756799645c9dd44a5260114401818298c60105 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 11:23:33 +0900 Subject: [PATCH 07/15] Add stand in function --- src/three/controls/EnvironmentControls.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/three/controls/EnvironmentControls.js b/src/three/controls/EnvironmentControls.js index d16ae00d..3b760d1e 100644 --- a/src/three/controls/EnvironmentControls.js +++ b/src/three/controls/EnvironmentControls.js @@ -455,6 +455,15 @@ export class EnvironmentControls extends EventDispatcher { } + getLastInteractionPoint( target ) { + + // TODO: Ensure are handling the last zoom point if possible + // TODO: Return null (or get center point?) if it can't be provided + + return target.copy( this.pivotPoint ); + + } + detach() { this.domElement = null; From eaafe48cc044935aeaf84bbf68c95dec07c13491 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 11:55:51 +0900 Subject: [PATCH 08/15] Fixes --- src/three/controls/EnvironmentControls.js | 8 ++------ src/three/controls/GlobeControls.js | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/three/controls/EnvironmentControls.js b/src/three/controls/EnvironmentControls.js index 3b760d1e..9e4b7fd7 100644 --- a/src/three/controls/EnvironmentControls.js +++ b/src/three/controls/EnvironmentControls.js @@ -100,7 +100,7 @@ export class EnvironmentControls extends EventDispatcher { this.zoomDirectionSet = false; this.zoomPointSet = false; this.zoomDirection = new Vector3(); - this.zoomPoint = this.pivotPoint; + this.zoomPoint = new Vector3(); this.zoomDelta = 0; this.pivotMesh = new PivotPointMesh(); @@ -377,11 +377,7 @@ export class EnvironmentControls extends EventDispatcher { const { pointerTracker } = this; pointerTracker.setHoverEvent( e ); - if ( ! pointerTracker.updatePointer( e ) ) { - - return; - - } + pointerTracker.updatePointer( e ); this.dispatchEvent( _startEvent ); diff --git a/src/three/controls/GlobeControls.js b/src/three/controls/GlobeControls.js index e50524c0..8ebaccd6 100644 --- a/src/three/controls/GlobeControls.js +++ b/src/three/controls/GlobeControls.js @@ -222,7 +222,7 @@ export class GlobeControls extends EnvironmentControls { rotationSpeed, camera, pivotMesh, - dragPoint, + pivotPoint, tilesGroup, } = this; From d279b7730ba801b05d30822c98803636f8990c0a Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 12:13:34 +0900 Subject: [PATCH 09/15] Fix zoom scale --- src/three/controls/GlobeControls.js | 37 +++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/three/controls/GlobeControls.js b/src/three/controls/GlobeControls.js index 8ebaccd6..11555e6f 100644 --- a/src/three/controls/GlobeControls.js +++ b/src/three/controls/GlobeControls.js @@ -12,6 +12,7 @@ const _invMatrix = new Matrix4(); const _rotMatrix = new Matrix4(); const _pos = new Vector3(); const _vec = new Vector3(); +const _vec2 = new Vector3(); const _center = new Vector3(); const _up = new Vector3(); const _forward = new Vector3(); @@ -80,6 +81,28 @@ export class GlobeControls extends EnvironmentControls { } + getClosestPointOnSurface( target ) { + + const { ellipsoid, camera, tilesGroup } = this; + + _invMatrix + .copy( tilesGroup.matrixWorld ) + .invert(); + + // get camera position in local frame + target + .setFromMatrixPosition( camera.matrixWorld ) + .applyMatrix4( _invMatrix ); + + // get point on surface + ellipsoid + .getPositionToSurfacePoint( target, target ) + .applyMatrix4( tilesGroup.matrixWorld ); + + return target; + + } + // get the vector to the center of the provided globe getVectorToCenter( target ) { @@ -233,7 +256,7 @@ export class GlobeControls extends EnvironmentControls { pointerTracker.getPreviousCenterPoint( _prevPointer ); _deltaPointer .subVectors( _pointer, _prevPointer ) - .multiplyScalar( camera.position.distanceTo( dragPoint ) * 1e-10 / devicePixelRatio ); + .multiplyScalar( camera.position.distanceTo( pivotPoint ) * 1e-9 / devicePixelRatio ); const azimuth = - _deltaPointer.x * rotationSpeed; const altitude = - _deltaPointer.y * rotationSpeed; @@ -280,8 +303,8 @@ export class GlobeControls extends EnvironmentControls { _updateZoom() { - const scale = this.zoomDelta; - if ( this.getDistanceToCenter() < GLOBE_TRANSITION_THRESHOLD || scale > 0 ) { + const zoomDelta = this.zoomDelta; + if ( this.getDistanceToCenter() < GLOBE_TRANSITION_THRESHOLD || zoomDelta > 0 ) { super._updateZoom(); @@ -292,9 +315,13 @@ export class GlobeControls extends EnvironmentControls { this._tiltTowardsCenter( MathUtils.lerp( 1, 0.8, alpha ) ); this._alignCameraUpToNorth( MathUtils.lerp( 1, 0.9, alpha ) ); + // get the distance to the surface of the sphere and compute teh zoom scale + const dist = this.getClosestPointOnSurface( _vec ).distanceTo( this.camera.position ); + const scale = zoomDelta * dist * this.zoomSpeed * 0.0025; + // zoom out directly from the globe center - this.getVectorToCenter( _vec ); - this.camera.position.addScaledVector( _vec, scale * 0.0025 ); + this.getVectorToCenter( _vec ).normalize(); + this.camera.position.addScaledVector( _vec, scale ); this.camera.updateMatrixWorld(); this.zoomDelta = 0; From ae0a6166831e5fab96e1fbc303e3e95defadd2a6 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 12:31:56 +0900 Subject: [PATCH 10/15] Remove unused field --- src/three/controls/EnvironmentControls.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/three/controls/EnvironmentControls.js b/src/three/controls/EnvironmentControls.js index 9e4b7fd7..8886b53b 100644 --- a/src/three/controls/EnvironmentControls.js +++ b/src/three/controls/EnvironmentControls.js @@ -94,7 +94,6 @@ export class EnvironmentControls extends EventDispatcher { this.actionHeightOffset = 0; // pivot point for drag and rotation - this.pivotPointSet = false; this.pivotPoint = new Vector3(); this.zoomDirectionSet = false; @@ -184,7 +183,6 @@ export class EnvironmentControls extends EventDispatcher { e.preventDefault(); const { - camera, raycaster, domElement, up, @@ -233,7 +231,6 @@ export class EnvironmentControls extends EventDispatcher { this.setState( ROTATE ); this.pivotPoint.copy( hit.point ); - this.pivotPointSet = true; this.pivotMesh.position.copy( hit.point ); this.pivotMesh.updateMatrixWorld(); @@ -246,7 +243,6 @@ export class EnvironmentControls extends EventDispatcher { this.setState( DRAG ); this.pivotPoint.copy( hit.point ); - this.pivotPointSet = true; this.pivotMesh.position.copy( hit.point ); this.pivotMesh.updateMatrixWorld(); @@ -484,8 +480,6 @@ export class EnvironmentControls extends EventDispatcher { this.state = NONE; this.pinchState = NONE; - this.pivotPointSet = false; - this.pivotPointSet = false; this.scene.remove( this.pivotMesh ); this.pivotMesh.visible = true; this.actionHeightOffset = 0; From 2b31cab3284c13cdbb58f847c5f99b40040b63e3 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 12:41:22 +0900 Subject: [PATCH 11/15] Fix speed --- src/three/controls/GlobeControls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/three/controls/GlobeControls.js b/src/three/controls/GlobeControls.js index 11555e6f..15c06588 100644 --- a/src/three/controls/GlobeControls.js +++ b/src/three/controls/GlobeControls.js @@ -256,7 +256,7 @@ export class GlobeControls extends EnvironmentControls { pointerTracker.getPreviousCenterPoint( _prevPointer ); _deltaPointer .subVectors( _pointer, _prevPointer ) - .multiplyScalar( camera.position.distanceTo( pivotPoint ) * 1e-9 / devicePixelRatio ); + .multiplyScalar( camera.position.distanceTo( pivotPoint ) * 5 * 1e-10 / devicePixelRatio ); const azimuth = - _deltaPointer.x * rotationSpeed; const altitude = - _deltaPointer.y * rotationSpeed; From 3224da711ac6b50732dfe6de07bb0920765052a7 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 21:05:21 +0900 Subject: [PATCH 12/15] Controls updates --- src/three/controls/GlobeControls.js | 56 ++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/src/three/controls/GlobeControls.js b/src/three/controls/GlobeControls.js index 15c06588..0eb395ad 100644 --- a/src/three/controls/GlobeControls.js +++ b/src/three/controls/GlobeControls.js @@ -164,8 +164,9 @@ export class GlobeControls extends EnvironmentControls { } // if we're outside the transition threshold then we toggle some reorientation behavior - // when adjusting the up frame while moving hte camera - if ( distanceToCenter > GLOBE_TRANSITION_THRESHOLD ) { + // when adjusting the up frame + // whether controls are based on a far distance from the camera while moving hte camera + if ( ! this._isDistantControls() ) { if ( this.state !== NONE && this._dragMode !== 1 && this._rotationMode !== 1 ) { @@ -230,7 +231,8 @@ export class GlobeControls extends EnvironmentControls { _updatePosition( ...args ) { - if ( this._dragMode === 1 || this.getDistanceToCenter() < GLOBE_TRANSITION_THRESHOLD ) { + // whether controls are based on a far distance from the camera + if ( this._dragMode === 1 || this._isDistantControls() ) { this._dragMode = 1; @@ -287,7 +289,8 @@ export class GlobeControls extends EnvironmentControls { // disable rotation once we're outside the control transition _updateRotation( ...args ) { - if ( this._rotationMode === 1 || this.getDistanceToCenter() < GLOBE_TRANSITION_THRESHOLD ) { + // whether controls are based on a far distance from the camera + if ( this._rotationMode === 1 || this._isDistantControls() ) { this._rotationMode = 1; super._updateRotation( ...args ); @@ -303,11 +306,24 @@ export class GlobeControls extends EnvironmentControls { _updateZoom() { - const zoomDelta = this.zoomDelta; - if ( this.getDistanceToCenter() < GLOBE_TRANSITION_THRESHOLD || zoomDelta > 0 ) { + const { zoomDelta, camera, zoomSpeed } = this; + + // whether controls are based on a far distance from the camera + if ( this._isDistantControls() || zoomDelta > 0 ) { super._updateZoom(); + } else if ( camera.isOrthographicCamera ) { + + // zoom the camera + const normalizedDelta = Math.pow( 0.95, Math.abs( zoomDelta * 0.05 ) ); + const scaleFactor = zoomDelta > 0 ? 1 / Math.abs( normalizedDelta ) : normalizedDelta; + + camera.zoom = camera.zoom * scaleFactor * zoomSpeed; + camera.updateProjectionMatrix(); + + this.zoomDelta = 0; + } else { // orient the camera to focus on the earth during the zoom @@ -316,8 +332,8 @@ export class GlobeControls extends EnvironmentControls { this._alignCameraUpToNorth( MathUtils.lerp( 1, 0.9, alpha ) ); // get the distance to the surface of the sphere and compute teh zoom scale - const dist = this.getClosestPointOnSurface( _vec ).distanceTo( this.camera.position ); - const scale = zoomDelta * dist * this.zoomSpeed * 0.0025; + const dist = this.getClosestPointOnSurface( _vec ).distanceTo( camera.position ); + const scale = zoomDelta * dist * zoomSpeed * 0.0025; // zoom out directly from the globe center this.getVectorToCenter( _vec ).normalize(); @@ -379,4 +395,28 @@ export class GlobeControls extends EnvironmentControls { } + // whether controls are based on a far distance from the camera + _isDistantControls() { + + const { camera, ellipsoid } = this; + const maxRadius = Math.max( ...ellipsoid.radius ); + + let isFullyInView = false; + if ( camera.isOrthographicCamera ) { + + const maxView = Math.min( camera.right - camera.left, camera.top - camera.bottom ) / camera.zoom; + isFullyInView = maxRadius > maxView; + + console.log( maxRadius, maxView ); + + } else { + + isFullyInView = this.getDistanceToCenter() < GLOBE_TRANSITION_THRESHOLD; + + } + + return isFullyInView; + + } + } From 1398caff21d05a6e5e18605290ea36094f8fe8d5 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 26 Apr 2024 21:35:17 +0900 Subject: [PATCH 13/15] Handle zooming --- src/three/controls/GlobeControls.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/three/controls/GlobeControls.js b/src/three/controls/GlobeControls.js index 0eb395ad..69d65ae4 100644 --- a/src/three/controls/GlobeControls.js +++ b/src/three/controls/GlobeControls.js @@ -318,10 +318,16 @@ export class GlobeControls extends EnvironmentControls { // zoom the camera const normalizedDelta = Math.pow( 0.95, Math.abs( zoomDelta * 0.05 ) ); const scaleFactor = zoomDelta > 0 ? 1 / Math.abs( normalizedDelta ) : normalizedDelta; + const maxDiameter = 2.0 * Math.max( ...this.ellipsoid.radius ); + const minZoom = Math.min( camera.right - camera.left, camera.top - camera.bottom ) / maxDiameter; - camera.zoom = camera.zoom * scaleFactor * zoomSpeed; + camera.zoom = Math.max( 0.75 * minZoom, camera.zoom * scaleFactor * zoomSpeed ); camera.updateProjectionMatrix(); + const alpha = MathUtils.mapLinear( camera.zoom, minZoom, minZoom * 0.75, 0, 1 ); + this._tiltTowardsCenter( MathUtils.lerp( 1, 0.8, alpha ) ); + this._alignCameraUpToNorth( MathUtils.lerp( 1, 0.9, alpha ) ); + this.zoomDelta = 0; } else { @@ -399,15 +405,13 @@ export class GlobeControls extends EnvironmentControls { _isDistantControls() { const { camera, ellipsoid } = this; - const maxRadius = Math.max( ...ellipsoid.radius ); + const maxDiameter = 2.0 * Math.max( ...ellipsoid.radius ); let isFullyInView = false; if ( camera.isOrthographicCamera ) { const maxView = Math.min( camera.right - camera.left, camera.top - camera.bottom ) / camera.zoom; - isFullyInView = maxRadius > maxView; - - console.log( maxRadius, maxView ); + isFullyInView = maxDiameter > maxView; } else { From 5e6ca44ce47f2cde7757871cbbd1e3c4a06f87d1 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sat, 27 Apr 2024 10:36:29 +0900 Subject: [PATCH 14/15] Updates --- src/three/controls/EnvironmentControls.js | 73 ++++++++++++----------- src/three/controls/GlobeControls.js | 65 +++++++++++--------- 2 files changed, 74 insertions(+), 64 deletions(-) diff --git a/src/three/controls/EnvironmentControls.js b/src/three/controls/EnvironmentControls.js index 8886b53b..adeaea41 100644 --- a/src/three/controls/EnvironmentControls.js +++ b/src/three/controls/EnvironmentControls.js @@ -641,6 +641,7 @@ export class EnvironmentControls extends EventDispatcher { } + // addjust the orthographic camera zoom if ( camera.isOrthographicCamera ) { // get the mouse position before zoom @@ -662,52 +663,55 @@ export class EnvironmentControls extends EventDispatcher { camera.position.sub( _mouseAfter ).add( _mouseBefore ); camera.updateMatrixWorld(); - } else { + } - // initialize the zoom direction - mouseToCoords( _pointer.x, _pointer.y, domElement, _pointer ); - raycaster.setFromCamera( _pointer, camera ); - zoomDirection.copy( raycaster.ray.direction ).normalize(); - this.zoomDirectionSet = true; + // Adjust zoom position + // Needed for orthographic camera, as well, to avoid floating point error when + // shifting the camera position to keep the world under the mouse cursor + // ie due to the local "up" vector used for the camera orientation - // track the zoom direction we're going to use - const finalZoomDirection = _vec.copy( zoomDirection ); + // initialize the zoom direction + mouseToCoords( _pointer.x, _pointer.y, domElement, _pointer ); + raycaster.setFromCamera( _pointer, camera ); + zoomDirection.copy( raycaster.ray.direction ).normalize(); + this.zoomDirectionSet = true; - // always update the zoom target point in case the tiles are changing - if ( this._updateZoomPoint() ) { + // track the zoom direction we're going to use + const finalZoomDirection = _vec.copy( zoomDirection ); - const dist = zoomPoint.distanceTo( camera.position ); + // always update the zoom target point in case the tiles are changing + if ( this._updateZoomPoint() ) { - // scale the distance based on how far there is to move - if ( scale < 0 ) { + const dist = zoomPoint.distanceTo( camera.position ); - const remainingDistance = Math.min( 0, dist - maxDistance ); - scale = scale * dist * zoomSpeed * 0.0025; - scale = Math.max( scale, remainingDistance ); + // scale the distance based on how far there is to move + if ( scale < 0 ) { - } else { + const remainingDistance = Math.min( 0, dist - maxDistance ); + scale = scale * dist * zoomSpeed * 0.0025; + scale = Math.max( scale, remainingDistance ); - const remainingDistance = Math.max( 0, dist - minDistance ); - scale = scale * ( dist - minDistance ) * zoomSpeed * 0.0025; - scale = Math.min( scale, remainingDistance ); + } else { - } + const remainingDistance = Math.max( 0, dist - minDistance ); + scale = scale * ( dist - minDistance ) * zoomSpeed * 0.0025; + scale = Math.min( scale, remainingDistance ); - camera.position.addScaledVector( zoomDirection, scale ); - camera.updateMatrixWorld(); + } - } else { + camera.position.addScaledVector( zoomDirection, scale ); + camera.updateMatrixWorld(); - // if we're zooming into nothing then use the distance from the ground to scale movement - const hit = this._getPointBelowCamera(); - if ( hit ) { + } else { - const dist = hit.distance; - finalZoomDirection.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); - camera.position.addScaledVector( finalZoomDirection, scale * dist * 0.01 ); - camera.updateMatrixWorld(); + // if we're zooming into nothing then use the distance from the ground to scale movement + const hit = this._getPointBelowCamera(); + if ( hit ) { - } + const dist = hit.distance; + finalZoomDirection.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); + camera.position.addScaledVector( finalZoomDirection, scale * dist * 0.01 ); + camera.updateMatrixWorld(); } @@ -843,7 +847,6 @@ export class EnvironmentControls extends EventDispatcher { pivotPoint, minAltitude, maxAltitude, - up, pointerTracker, rotationSpeed, } = this; @@ -865,10 +868,10 @@ export class EnvironmentControls extends EventDispatcher { this.getUpDirection( pivotPoint, _localUp ); // get the signed angle relative to the top down view - _vec.crossVectors( up, _forward ).normalize(); + _vec.crossVectors( _localUp, _forward ).normalize(); _right.set( 1, 0, 0 ).transformDirection( camera.matrixWorld ).normalize(); const sign = Math.sign( _vec.dot( _right ) ); - const angle = sign * up.angleTo( _forward ); + const angle = sign * _localUp.angleTo( _forward ); // clamp the rotation to be within the provided limits // clamp to 0 here, as well, so we don't "pop" to the the value range diff --git a/src/three/controls/GlobeControls.js b/src/three/controls/GlobeControls.js index 69d65ae4..22becade 100644 --- a/src/three/controls/GlobeControls.js +++ b/src/three/controls/GlobeControls.js @@ -12,7 +12,6 @@ const _invMatrix = new Matrix4(); const _rotMatrix = new Matrix4(); const _pos = new Vector3(); const _vec = new Vector3(); -const _vec2 = new Vector3(); const _center = new Vector3(); const _up = new Vector3(); const _forward = new Vector3(); @@ -166,7 +165,7 @@ export class GlobeControls extends EnvironmentControls { // if we're outside the transition threshold then we toggle some reorientation behavior // when adjusting the up frame // whether controls are based on a far distance from the camera while moving hte camera - if ( ! this._isDistantControls() ) { + if ( ! this._isNearControls() ) { if ( this.state !== NONE && this._dragMode !== 1 && this._rotationMode !== 1 ) { @@ -217,13 +216,13 @@ export class GlobeControls extends EnvironmentControls { } // animate the frame to align to an up direction - setFrame( ...args ) { + _setFrame( ...args ) { - super.setFrame( ...args ); + super._setFrame( ...args ); - if ( this.getDistanceToCenter() < GLOBE_TRANSITION_THRESHOLD ) { + if ( this._isNearControls() ) { - this._alignCameraUp( this.up ); + this._alignCameraUp( this.up, 1 ); } @@ -232,7 +231,7 @@ export class GlobeControls extends EnvironmentControls { _updatePosition( ...args ) { // whether controls are based on a far distance from the camera - if ( this._dragMode === 1 || this._isDistantControls() ) { + if ( this._dragMode === 1 || this._isNearControls() ) { this._dragMode = 1; @@ -290,7 +289,7 @@ export class GlobeControls extends EnvironmentControls { _updateRotation( ...args ) { // whether controls are based on a far distance from the camera - if ( this._rotationMode === 1 || this._isDistantControls() ) { + if ( this._rotationMode === 1 || this._isNearControls() ) { this._rotationMode = 1; super._updateRotation( ...args ); @@ -306,36 +305,44 @@ export class GlobeControls extends EnvironmentControls { _updateZoom() { + window.CONTROLS = this; const { zoomDelta, camera, zoomSpeed } = this; // whether controls are based on a far distance from the camera - if ( this._isDistantControls() || zoomDelta > 0 ) { + if ( this._isNearControls() || zoomDelta > 0 ) { super._updateZoom(); - } else if ( camera.isOrthographicCamera ) { + } else { - // zoom the camera - const normalizedDelta = Math.pow( 0.95, Math.abs( zoomDelta * 0.05 ) ); - const scaleFactor = zoomDelta > 0 ? 1 / Math.abs( normalizedDelta ) : normalizedDelta; - const maxDiameter = 2.0 * Math.max( ...this.ellipsoid.radius ); - const minZoom = Math.min( camera.right - camera.left, camera.top - camera.bottom ) / maxDiameter; + if ( camera.isOrthographicCamera ) { - camera.zoom = Math.max( 0.75 * minZoom, camera.zoom * scaleFactor * zoomSpeed ); - camera.updateProjectionMatrix(); + // zoom the camera + const normalizedDelta = Math.pow( 0.95, Math.abs( zoomDelta * 0.05 ) ); + const scaleFactor = zoomDelta > 0 ? 1 / Math.abs( normalizedDelta ) : normalizedDelta; + const maxDiameter = 2.0 * Math.max( ...this.ellipsoid.radius ); + const minZoom = Math.min( camera.right - camera.left, camera.top - camera.bottom ) / maxDiameter; - const alpha = MathUtils.mapLinear( camera.zoom, minZoom, minZoom * 0.75, 0, 1 ); - this._tiltTowardsCenter( MathUtils.lerp( 1, 0.8, alpha ) ); - this._alignCameraUpToNorth( MathUtils.lerp( 1, 0.9, alpha ) ); + camera.zoom = Math.max( 0.75 * minZoom, camera.zoom * scaleFactor * zoomSpeed ); + camera.updateProjectionMatrix(); - this.zoomDelta = 0; + let alpha = MathUtils.mapLinear( camera.zoom, minZoom * 1.25, minZoom * 0.75, 0, 1 ); + alpha = MathUtils.clamp( alpha, 0, 1 ); + this._tiltTowardsCenter( MathUtils.lerp( 1, 0.8, alpha ) ); + this._alignCameraUpToNorth( MathUtils.lerp( 1, 0.9, alpha ) ); - } else { + // this.zoomDelta = 0; + + } + + if ( camera.isPerspectiveCamera ) { - // orient the camera to focus on the earth during the zoom - const alpha = MathUtils.mapLinear( this.getDistanceToCenter(), GLOBE_TRANSITION_THRESHOLD, MAX_GLOBE_DISTANCE, 0, 1 ); - this._tiltTowardsCenter( MathUtils.lerp( 1, 0.8, alpha ) ); - this._alignCameraUpToNorth( MathUtils.lerp( 1, 0.9, alpha ) ); + // orient the camera to focus on the earth during the zoom + const alpha = MathUtils.mapLinear( this.getDistanceToCenter(), GLOBE_TRANSITION_THRESHOLD, MAX_GLOBE_DISTANCE, 0, 1 ); + this._tiltTowardsCenter( MathUtils.lerp( 1, 0.8, alpha ) ); + this._alignCameraUpToNorth( MathUtils.lerp( 1, 0.9, alpha ) ); + + } // get the distance to the surface of the sphere and compute teh zoom scale const dist = this.getClosestPointOnSurface( _vec ).distanceTo( camera.position ); @@ -402,16 +409,16 @@ export class GlobeControls extends EnvironmentControls { } // whether controls are based on a far distance from the camera - _isDistantControls() { + _isNearControls() { const { camera, ellipsoid } = this; const maxDiameter = 2.0 * Math.max( ...ellipsoid.radius ); let isFullyInView = false; - if ( camera.isOrthographicCamera ) { + if ( camera.isOrthographicCamera && false ) { const maxView = Math.min( camera.right - camera.left, camera.top - camera.bottom ) / camera.zoom; - isFullyInView = maxDiameter > maxView; + isFullyInView = 0.5 * maxDiameter > maxView; } else { From 89c839932adf74895464f4a943ad1a5f2c8547f4 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sat, 27 Apr 2024 15:06:21 +0900 Subject: [PATCH 15/15] Updates --- src/three/controls/GlobeControls.js | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/three/controls/GlobeControls.js b/src/three/controls/GlobeControls.js index 22becade..1c22bbfd 100644 --- a/src/three/controls/GlobeControls.js +++ b/src/three/controls/GlobeControls.js @@ -202,6 +202,19 @@ export class GlobeControls extends EnvironmentControls { const horizonDistance = ellipsoid.calculateHorizonDistance( _latLon.lat, elevation ); camera.far = horizonDistance + 0.1; + + + if ( camera.isOrthographicCamera ) { + + _invMatrix.copy( camera.matrixWorld ).invert(); + + const v = new Vector3().setFromMatrixPosition( this.tilesGroup.matrixWorld ).applyMatrix4( _invMatrix ); + + camera.near = - Math.max( ...this.ellipsoid.radius ); + camera.far = - v.z; + + } + camera.updateProjectionMatrix(); } @@ -327,9 +340,13 @@ export class GlobeControls extends EnvironmentControls { camera.updateProjectionMatrix(); let alpha = MathUtils.mapLinear( camera.zoom, minZoom * 1.25, minZoom * 0.75, 0, 1 ); - alpha = MathUtils.clamp( alpha, 0, 1 ); - this._tiltTowardsCenter( MathUtils.lerp( 1, 0.8, alpha ) ); - this._alignCameraUpToNorth( MathUtils.lerp( 1, 0.9, alpha ) ); + if ( alpha > 0 ) { + + alpha = MathUtils.clamp( alpha, 0, 1 ); + this._tiltTowardsCenter( MathUtils.lerp( 1, 0.8, alpha ) ); + this._alignCameraUpToNorth( MathUtils.lerp( 1, 0.9, alpha ) ); + + } // this.zoomDelta = 0; @@ -415,7 +432,7 @@ export class GlobeControls extends EnvironmentControls { const maxDiameter = 2.0 * Math.max( ...ellipsoid.radius ); let isFullyInView = false; - if ( camera.isOrthographicCamera && false ) { + if ( camera.isOrthographicCamera ) { const maxView = Math.min( camera.right - camera.left, camera.top - camera.bottom ) / camera.zoom; isFullyInView = 0.5 * maxDiameter > maxView;