3dtiles-inspector 0.2.11 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +1 -1
- package/dist/inspector-assets/viewer/app.js +1743 -8426
- package/package.json +3 -4
- package/src/server/viewerHtml.js +53 -14
- package/src/viewer/app.js +2 -0
- package/src/viewer/dom/elements.js +1 -0
- package/src/viewer/dom/events.js +3 -1
- package/src/viewer/dom/viewerToggles.js +18 -2
- package/src/viewer/scene/cameraController.js +153 -206
- package/src/viewer/scene/globeController.js +3 -2
- package/src/viewer/scene/tiles.js +9 -3
|
@@ -11,10 +11,8 @@ import {
|
|
|
11
11
|
Vector2,
|
|
12
12
|
Vector3,
|
|
13
13
|
} from 'three';
|
|
14
|
+
import { Ellipsoid } from '3d-tiles-renderer';
|
|
14
15
|
|
|
15
|
-
const createUninitializedCallback = (name) => () => {
|
|
16
|
-
console.warn(`${name} was called before initialization.`);
|
|
17
|
-
};
|
|
18
16
|
const CAMERA_CENTER_MODE_DISTANCE = 3000000;
|
|
19
17
|
const CAMERA_CENTER_MODE_DISTANCE_SQ = CAMERA_CENTER_MODE_DISTANCE ** 2;
|
|
20
18
|
|
|
@@ -347,16 +345,14 @@ const _vec5 = new Vector3();
|
|
|
347
345
|
const _vec6 = new Vector3();
|
|
348
346
|
const _axis = new Vector3();
|
|
349
347
|
const _localUp = new Vector3();
|
|
348
|
+
const _positionUp = new Vector3();
|
|
350
349
|
const _localRight = new Vector3();
|
|
351
|
-
const _localForward = new Vector3();
|
|
352
350
|
const _rotMatrix = new Matrix4();
|
|
353
|
-
const _invMatrix = new Matrix4();
|
|
354
351
|
const _quaternion = new Quaternion();
|
|
352
|
+
const _rollRotation = new Quaternion();
|
|
355
353
|
const _plane = new Plane();
|
|
356
354
|
const _ray = new Ray();
|
|
357
|
-
const
|
|
358
|
-
const _fixedPointSurface = new Vector3();
|
|
359
|
-
const _fixedPointNormal = new Vector3();
|
|
355
|
+
const _dragEllipsoid = new Ellipsoid(1, 1, 1);
|
|
360
356
|
class CameraController extends EventDispatcher {
|
|
361
357
|
enableDamping;
|
|
362
358
|
dampingFactor;
|
|
@@ -376,8 +372,6 @@ class CameraController extends EventDispatcher {
|
|
|
376
372
|
#rotateInertia;
|
|
377
373
|
#dragInertia;
|
|
378
374
|
#dragAnchorPoint;
|
|
379
|
-
#dragStartPosition;
|
|
380
|
-
#dragStartQuaternion;
|
|
381
375
|
#dragPlaneNormal;
|
|
382
376
|
#inertiaValue;
|
|
383
377
|
#enabled;
|
|
@@ -385,22 +379,6 @@ class CameraController extends EventDispatcher {
|
|
|
385
379
|
#ellipsoidMaxRadius;
|
|
386
380
|
#lastTime;
|
|
387
381
|
#hit;
|
|
388
|
-
#contextMenuEvent = createUninitializedCallback(
|
|
389
|
-
'CameraController.#contextMenuEvent',
|
|
390
|
-
);
|
|
391
|
-
#pointerDownEvent = createUninitializedCallback(
|
|
392
|
-
'CameraController.#pointerDownEvent',
|
|
393
|
-
);
|
|
394
|
-
#pointerMoveEvent = createUninitializedCallback(
|
|
395
|
-
'CameraController.#pointerMoveEvent',
|
|
396
|
-
);
|
|
397
|
-
#pointerUpEvent = createUninitializedCallback(
|
|
398
|
-
'CameraController.#pointerUpEvent',
|
|
399
|
-
);
|
|
400
|
-
#wheelEvent = createUninitializedCallback('CameraController.#wheelEvent');
|
|
401
|
-
#pointerEnterEvent = createUninitializedCallback(
|
|
402
|
-
'CameraController.#pointerEnterEvent',
|
|
403
|
-
);
|
|
404
382
|
#pointerDownFilter;
|
|
405
383
|
#zoomTimeout;
|
|
406
384
|
constructor(renderer, scene, camera, options = {}) {
|
|
@@ -428,8 +406,6 @@ class CameraController extends EventDispatcher {
|
|
|
428
406
|
this.#rotateInertia = new Vector2();
|
|
429
407
|
this.#dragInertia = new Vector3();
|
|
430
408
|
this.#dragAnchorPoint = new Vector3();
|
|
431
|
-
this.#dragStartPosition = new Vector3();
|
|
432
|
-
this.#dragStartQuaternion = new Quaternion();
|
|
433
409
|
this.#dragPlaneNormal = new Vector3();
|
|
434
410
|
this.#inertiaValue = 0;
|
|
435
411
|
this.#enabled = false;
|
|
@@ -452,12 +428,6 @@ class CameraController extends EventDispatcher {
|
|
|
452
428
|
this.#enabled = v;
|
|
453
429
|
this.#resetState();
|
|
454
430
|
this.#pointerTracker.reset();
|
|
455
|
-
if (!this.enabled) {
|
|
456
|
-
this.#dragInertia.set(0, 0, 0);
|
|
457
|
-
this.#rotateInertia.set(0, 0);
|
|
458
|
-
this.#zoomInertia = 0;
|
|
459
|
-
this.#inertiaValue = 0;
|
|
460
|
-
}
|
|
461
431
|
this.dispatchEvent(UPDATE_EVENT);
|
|
462
432
|
this.dispatchEvent(FINISH_EVENT);
|
|
463
433
|
}
|
|
@@ -492,8 +462,6 @@ class CameraController extends EventDispatcher {
|
|
|
492
462
|
this.#rotateInertia.set(0, 0);
|
|
493
463
|
this.#dragInertia.set(0, 0, 0);
|
|
494
464
|
this.#dragAnchorPoint.set(0, 0, 0);
|
|
495
|
-
this.#dragStartPosition.set(0, 0, 0);
|
|
496
|
-
this.#dragStartQuaternion.identity();
|
|
497
465
|
this.#dragPlaneNormal.set(0, 0, 0);
|
|
498
466
|
this.#zoomInertia = 0;
|
|
499
467
|
this.#hit = null;
|
|
@@ -519,12 +487,6 @@ class CameraController extends EventDispatcher {
|
|
|
519
487
|
this.#domElement.style.touchAction = 'none';
|
|
520
488
|
this.#pivotMesh.raycast = () => {};
|
|
521
489
|
this.#scene.add(this.#pivotMesh);
|
|
522
|
-
this.#contextMenuEvent = this.#contextMenu.bind(this);
|
|
523
|
-
this.#pointerDownEvent = this.#pointerDown.bind(this);
|
|
524
|
-
this.#pointerMoveEvent = this.#pointerMove.bind(this);
|
|
525
|
-
this.#pointerUpEvent = this.#pointerUp.bind(this);
|
|
526
|
-
this.#wheelEvent = this.#wheel.bind(this);
|
|
527
|
-
this.#pointerEnterEvent = this.#pointerEnter.bind(this);
|
|
528
490
|
this.#bindEvents();
|
|
529
491
|
this.#enabled = true;
|
|
530
492
|
}
|
|
@@ -565,23 +527,32 @@ class CameraController extends EventDispatcher {
|
|
|
565
527
|
if (!_pointer1.equals(_pointer2) && this.#hit && this.#hit.distance > 0) {
|
|
566
528
|
mouseToCoords(_pointer1.x, _pointer1.y, this.#domElement, _pointer1);
|
|
567
529
|
mouseToCoords(_pointer2.x, _pointer2.y, this.#domElement, _pointer2);
|
|
568
|
-
this.#
|
|
569
|
-
if (
|
|
530
|
+
const shouldDragModified = this.#shouldDragModified();
|
|
531
|
+
if (shouldDragModified) {
|
|
532
|
+
if (this.#modifiedDrag(_pointer1)) {
|
|
533
|
+
this.#inertiaValue = 1;
|
|
534
|
+
this.#rotateInertia.set(0, 0);
|
|
535
|
+
this.#zoomInertia = 0;
|
|
536
|
+
this.#finalizeCamera();
|
|
537
|
+
} else {
|
|
538
|
+
this.#setState(IDLE);
|
|
539
|
+
}
|
|
540
|
+
this.dispatchEvent(UPDATE_EVENT);
|
|
541
|
+
} else if (
|
|
570
542
|
this.#intersectDragPlane(_pointer1, _vec1) &&
|
|
571
543
|
this.#intersectDragPlane(_pointer2, _vec2)
|
|
572
544
|
) {
|
|
573
545
|
_vec.subVectors(_vec1, this.#dragAnchorPoint);
|
|
574
546
|
_vec5.subVectors(_vec1, _vec2);
|
|
575
|
-
|
|
576
|
-
this.#modifiedDrag(_vec);
|
|
577
|
-
} else {
|
|
578
|
-
this.#camera.position.sub(_vec);
|
|
579
|
-
}
|
|
547
|
+
this.#camera.position.sub(_vec);
|
|
580
548
|
this.#dragInertia.copy(_vec5);
|
|
581
549
|
this.#inertiaValue = 1;
|
|
582
550
|
this.#rotateInertia.set(0, 0);
|
|
583
551
|
this.#zoomInertia = 0;
|
|
584
552
|
this.#finalizeCamera();
|
|
553
|
+
if (!shouldDragModified && this.#shouldDragModified()) {
|
|
554
|
+
this.#initializeDragAnchor();
|
|
555
|
+
}
|
|
585
556
|
this.dispatchEvent(UPDATE_EVENT);
|
|
586
557
|
}
|
|
587
558
|
}
|
|
@@ -592,15 +563,24 @@ class CameraController extends EventDispatcher {
|
|
|
592
563
|
this.#rotate(_pointer);
|
|
593
564
|
this.#finalizeCamera();
|
|
594
565
|
} else if (this.#dragInertia.lengthSq() > 0 && this.#inertiaValue > 0) {
|
|
595
|
-
|
|
566
|
+
const shouldDragModified = this.#shouldDragModified();
|
|
567
|
+
if (shouldDragModified) {
|
|
596
568
|
_vec.copy(this.#dragInertia).multiplyScalar(this.#inertiaValue);
|
|
597
|
-
|
|
569
|
+
const angle = _vec.length();
|
|
570
|
+
if (angle > THRESHOLD) {
|
|
571
|
+
_axis.copy(_vec).multiplyScalar(1 / angle);
|
|
572
|
+
_quaternion.setFromAxisAngle(_axis, angle);
|
|
573
|
+
this.#applyCameraRotationAroundOrigin(_quaternion);
|
|
574
|
+
}
|
|
598
575
|
this.#finalizeCamera();
|
|
599
576
|
} else {
|
|
600
577
|
_vec.copy(this.#dragInertia).multiplyScalar(this.#inertiaValue);
|
|
601
578
|
this.#camera.position.sub(_vec);
|
|
602
579
|
this.#finalizeCamera();
|
|
603
580
|
}
|
|
581
|
+
if (!shouldDragModified && this.#shouldDragModified()) {
|
|
582
|
+
this.#initializeDragAnchor();
|
|
583
|
+
}
|
|
604
584
|
}
|
|
605
585
|
if (
|
|
606
586
|
(this.#rotateInertia.lengthSq() === 0 &&
|
|
@@ -643,6 +623,8 @@ class CameraController extends EventDispatcher {
|
|
|
643
623
|
this.#zoomDelta = delta * 4000;
|
|
644
624
|
}
|
|
645
625
|
if (this.#zoomDelta !== 0) {
|
|
626
|
+
this.#rotateInertia.set(0, 0);
|
|
627
|
+
this.#dragInertia.set(0, 0, 0);
|
|
646
628
|
if (this.#zoomTimeout !== null) {
|
|
647
629
|
clearTimeout(this.#zoomTimeout);
|
|
648
630
|
this.#zoomTimeout = null;
|
|
@@ -705,15 +687,12 @@ class CameraController extends EventDispatcher {
|
|
|
705
687
|
clearTimeout(this.#zoomTimeout);
|
|
706
688
|
this.#zoomTimeout = null;
|
|
707
689
|
}
|
|
708
|
-
this.#domElement.removeEventListener('contextmenu', this.#
|
|
709
|
-
this.#domElement.removeEventListener('pointerdown', this.#
|
|
710
|
-
this.#domElement.removeEventListener('pointermove', this.#
|
|
711
|
-
this.#domElement.removeEventListener('pointerup', this.#
|
|
712
|
-
this.#domElement.removeEventListener('wheel', this.#
|
|
713
|
-
this.#domElement.removeEventListener(
|
|
714
|
-
'pointerenter',
|
|
715
|
-
this.#pointerEnterEvent,
|
|
716
|
-
);
|
|
690
|
+
this.#domElement.removeEventListener('contextmenu', this.#contextMenu);
|
|
691
|
+
this.#domElement.removeEventListener('pointerdown', this.#pointerDown);
|
|
692
|
+
this.#domElement.removeEventListener('pointermove', this.#pointerMove);
|
|
693
|
+
this.#domElement.removeEventListener('pointerup', this.#pointerUp);
|
|
694
|
+
this.#domElement.removeEventListener('wheel', this.#wheel);
|
|
695
|
+
this.#domElement.removeEventListener('pointerenter', this.#pointerEnter);
|
|
717
696
|
this.#pivotMesh.removeFromParent();
|
|
718
697
|
this.#pivotMesh.dispose();
|
|
719
698
|
this.#domElement.style.touchAction = '';
|
|
@@ -721,12 +700,12 @@ class CameraController extends EventDispatcher {
|
|
|
721
700
|
this.#ellipsoid = null;
|
|
722
701
|
}
|
|
723
702
|
#bindEvents() {
|
|
724
|
-
this.#domElement.addEventListener('contextmenu', this.#
|
|
725
|
-
this.#domElement.addEventListener('pointerdown', this.#
|
|
726
|
-
this.#domElement.addEventListener('pointermove', this.#
|
|
727
|
-
this.#domElement.addEventListener('pointerup', this.#
|
|
728
|
-
this.#domElement.addEventListener('wheel', this.#
|
|
729
|
-
this.#domElement.addEventListener('pointerenter', this.#
|
|
703
|
+
this.#domElement.addEventListener('contextmenu', this.#contextMenu);
|
|
704
|
+
this.#domElement.addEventListener('pointerdown', this.#pointerDown);
|
|
705
|
+
this.#domElement.addEventListener('pointermove', this.#pointerMove);
|
|
706
|
+
this.#domElement.addEventListener('pointerup', this.#pointerUp);
|
|
707
|
+
this.#domElement.addEventListener('wheel', this.#wheel);
|
|
708
|
+
this.#domElement.addEventListener('pointerenter', this.#pointerEnter);
|
|
730
709
|
}
|
|
731
710
|
#contextMenu = (e) => {
|
|
732
711
|
e.preventDefault();
|
|
@@ -870,29 +849,27 @@ class CameraController extends EventDispatcher {
|
|
|
870
849
|
}
|
|
871
850
|
};
|
|
872
851
|
#finalizeCamera() {
|
|
873
|
-
|
|
874
|
-
|
|
852
|
+
const fixedPoint =
|
|
853
|
+
this.#hit && this.#hit.distance > 0 ? this.#hit.point : undefined;
|
|
854
|
+
this.#limitCameraDistance(fixedPoint);
|
|
855
|
+
if (fixedPoint && !this.#isCameraCenterMode()) {
|
|
856
|
+
this.#keepCameraUp(fixedPoint);
|
|
857
|
+
} else {
|
|
858
|
+
this.#keepCameraUp();
|
|
859
|
+
}
|
|
875
860
|
this.#camera.updateMatrixWorld();
|
|
876
861
|
}
|
|
877
|
-
#
|
|
878
|
-
this.#
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
_right.crossVectors(_forward, _worldZ);
|
|
884
|
-
}
|
|
885
|
-
if (_right.lengthSq() <= THRESHOLD * THRESHOLD) {
|
|
886
|
-
return;
|
|
862
|
+
#getPositionUpDirection(position, target) {
|
|
863
|
+
if (this.#ellipsoid) {
|
|
864
|
+
this.#ellipsoid.getPositionToNormal(position, target);
|
|
865
|
+
if (target.lengthSq() > THRESHOLD * THRESHOLD) {
|
|
866
|
+
return target;
|
|
867
|
+
}
|
|
887
868
|
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
_right.negate();
|
|
869
|
+
if (position.lengthSq() > THRESHOLD * THRESHOLD) {
|
|
870
|
+
return target.copy(position).normalize();
|
|
891
871
|
}
|
|
892
|
-
|
|
893
|
-
_vec2.copy(_forward).negate();
|
|
894
|
-
_rotMatrix.makeBasis(_right, _localUp, _vec2);
|
|
895
|
-
this.#camera.quaternion.setFromRotationMatrix(_rotMatrix);
|
|
872
|
+
return target.copy(_worldZ);
|
|
896
873
|
}
|
|
897
874
|
#rotateNearAnchor(rotateVec) {
|
|
898
875
|
if (!this.#hit) {
|
|
@@ -982,9 +959,9 @@ class CameraController extends EventDispatcher {
|
|
|
982
959
|
this.#camera.getWorldDirection(_forward);
|
|
983
960
|
_up.copy(this.#camera.up).transformDirection(this.#camera.matrixWorld);
|
|
984
961
|
_right.crossVectors(_forward, _up).normalize();
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
const cameraVerticalAngle = Math.PI - _forward.angleTo(
|
|
962
|
+
this.#getPositionUpDirection(this.#hit.point, _localUp);
|
|
963
|
+
this.#getPositionUpDirection(this.#camera.position, _positionUp);
|
|
964
|
+
const cameraVerticalAngle = Math.PI - _forward.angleTo(_positionUp);
|
|
988
965
|
const maxVerticalAngle = Math.PI - THRESHOLD;
|
|
989
966
|
const minVerticalAngle = THRESHOLD;
|
|
990
967
|
let verticalAngle = Math.min(
|
|
@@ -1025,16 +1002,9 @@ class CameraController extends EventDispatcher {
|
|
|
1025
1002
|
return;
|
|
1026
1003
|
}
|
|
1027
1004
|
this.#dragAnchorPoint.copy(this.#hit.point);
|
|
1028
|
-
this.#dragStartPosition.copy(this.#camera.position);
|
|
1029
|
-
this.#dragStartQuaternion.copy(this.#camera.quaternion);
|
|
1030
|
-
this.#camera.getWorldDirection(this.#dragPlaneNormal);
|
|
1031
|
-
}
|
|
1032
|
-
#restoreDragStartCamera() {
|
|
1033
|
-
this.#camera.position.copy(this.#dragStartPosition);
|
|
1034
|
-
this.#camera.quaternion.copy(this.#dragStartQuaternion);
|
|
1035
|
-
this.#camera.updateMatrixWorld();
|
|
1036
1005
|
}
|
|
1037
1006
|
#intersectDragPlane(pointer, target) {
|
|
1007
|
+
this.#camera.getWorldDirection(this.#dragPlaneNormal);
|
|
1038
1008
|
_plane.setFromNormalAndCoplanarPoint(
|
|
1039
1009
|
this.#dragPlaneNormal,
|
|
1040
1010
|
this.#dragAnchorPoint,
|
|
@@ -1042,111 +1012,66 @@ class CameraController extends EventDispatcher {
|
|
|
1042
1012
|
setRaycasterFromCamera(this.#raycaster, pointer, this.#camera);
|
|
1043
1013
|
return this.#raycaster.ray.intersectPlane(_plane, target) !== null;
|
|
1044
1014
|
}
|
|
1045
|
-
#modifiedDrag(
|
|
1046
|
-
if (!this.#hit || this.#hit.distance <= 0) {
|
|
1015
|
+
#modifiedDrag(pointer) {
|
|
1016
|
+
if (!this.#hit || this.#hit.distance <= 0 || this.#hit.virtual) {
|
|
1017
|
+
return false;
|
|
1018
|
+
}
|
|
1019
|
+
const radius = this.#dragAnchorPoint.length();
|
|
1020
|
+
if (radius <= THRESHOLD) {
|
|
1021
|
+
return false;
|
|
1022
|
+
}
|
|
1023
|
+
_dragEllipsoid.radius.setScalar(radius);
|
|
1024
|
+
setRaycasterFromCamera(this.#raycaster, pointer, this.#camera);
|
|
1025
|
+
if (!_dragEllipsoid.intersectRay(this.#raycaster.ray, _vec1)) {
|
|
1026
|
+
return false;
|
|
1027
|
+
}
|
|
1028
|
+
_vec2.copy(_vec1).normalize();
|
|
1029
|
+
if (this.#raycaster.ray.direction.dot(_vec2) > 0) {
|
|
1030
|
+
return false;
|
|
1031
|
+
}
|
|
1032
|
+
_vec1.normalize();
|
|
1033
|
+
_vec2.copy(this.#dragAnchorPoint).normalize();
|
|
1034
|
+
_quaternion.setFromUnitVectors(_vec1, _vec2);
|
|
1035
|
+
this.#setModifiedDragInertia(_quaternion);
|
|
1036
|
+
this.#applyCameraRotationAroundOrigin(_quaternion);
|
|
1037
|
+
return true;
|
|
1038
|
+
}
|
|
1039
|
+
#setModifiedDragInertia(rotation) {
|
|
1040
|
+
_axis.set(rotation.x, rotation.y, rotation.z);
|
|
1041
|
+
if (rotation.w < 0) {
|
|
1042
|
+
_axis.negate();
|
|
1043
|
+
}
|
|
1044
|
+
const axisLength = _axis.length();
|
|
1045
|
+
if (axisLength <= THRESHOLD) {
|
|
1046
|
+
this.#dragInertia.set(0, 0, 0);
|
|
1047
1047
|
return;
|
|
1048
1048
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
const length = this.#hit.point.length();
|
|
1055
|
-
let verticalAngle =
|
|
1056
|
-
Math.atan2(_vec2.length(), length) * Math.sign(_vec2.dot(_up));
|
|
1057
|
-
let horizontalAngle =
|
|
1058
|
-
-Math.atan2(_vec1.length(), length) * Math.sign(_vec1.dot(_right));
|
|
1059
|
-
this.#camera.getWorldDirection(_vec4).negate();
|
|
1060
|
-
const angle = _vec4.angleTo(this.#camera.position);
|
|
1061
|
-
const cos = Math.cos(angle);
|
|
1062
|
-
verticalAngle /= cos;
|
|
1063
|
-
horizontalAngle /= cos;
|
|
1064
|
-
// Rotate around the right axis
|
|
1065
|
-
_quaternion.setFromAxisAngle(_right, verticalAngle);
|
|
1066
|
-
makeRotateAroundPoint(_vec3.set(0, 0, 0), _quaternion, _rotMatrix);
|
|
1067
|
-
this.#camera.matrixWorld.premultiply(_rotMatrix);
|
|
1068
|
-
// Rotate around the up axis
|
|
1069
|
-
_quaternion.setFromAxisAngle(_up, horizontalAngle);
|
|
1070
|
-
makeRotateAroundPoint(_vec3.set(0, 0, 0), _quaternion, _rotMatrix);
|
|
1049
|
+
const angle = 2 * Math.atan2(axisLength, Math.abs(rotation.w));
|
|
1050
|
+
this.#dragInertia.copy(_axis).multiplyScalar(angle / axisLength);
|
|
1051
|
+
}
|
|
1052
|
+
#applyCameraRotationAroundOrigin(rotation) {
|
|
1053
|
+
makeRotateAroundPoint(_vec3.set(0, 0, 0), rotation, _rotMatrix);
|
|
1071
1054
|
this.#camera.matrixWorld.premultiply(_rotMatrix);
|
|
1072
|
-
// Explicitly set the quaternion before decomposing
|
|
1073
1055
|
this.#camera.matrixWorld.decompose(
|
|
1074
1056
|
this.#camera.position,
|
|
1075
1057
|
this.#camera.quaternion,
|
|
1076
1058
|
_vec3,
|
|
1077
1059
|
);
|
|
1078
1060
|
}
|
|
1079
|
-
#
|
|
1080
|
-
this.#
|
|
1081
|
-
|
|
1082
|
-
_vec1.copy(fixedPoint).applyMatrix4(_invMatrix);
|
|
1083
|
-
let clampToGlobeHorizon = false;
|
|
1084
|
-
if (this.#ellipsoid && !this.#isCameraCenterMode()) {
|
|
1085
|
-
const surfacePoint = this.#ellipsoid.getPositionToSurfacePoint(
|
|
1086
|
-
fixedPoint,
|
|
1087
|
-
_fixedPointSurface,
|
|
1088
|
-
);
|
|
1089
|
-
if (surfacePoint) {
|
|
1090
|
-
this.#ellipsoid.getPositionToNormal(
|
|
1091
|
-
_fixedPointSurface,
|
|
1092
|
-
_fixedPointNormal,
|
|
1093
|
-
);
|
|
1094
|
-
clampToGlobeHorizon =
|
|
1095
|
-
_fixedPointNormal.lengthSq() > THRESHOLD * THRESHOLD;
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
this.#keepCameraUp();
|
|
1099
|
-
this.#camera.updateMatrixWorld();
|
|
1100
|
-
_vec2.copy(_vec1).applyMatrix4(this.#camera.matrixWorld);
|
|
1101
|
-
_vec3.subVectors(fixedPoint, _vec2);
|
|
1102
|
-
if (clampToGlobeHorizon) {
|
|
1103
|
-
_vec4.copy(this.#camera.position).add(_vec3);
|
|
1104
|
-
const candidateClearance = _vec5
|
|
1105
|
-
.subVectors(_vec4, _fixedPointSurface)
|
|
1106
|
-
.dot(_fixedPointNormal);
|
|
1107
|
-
|
|
1108
|
-
if (candidateClearance < 0) {
|
|
1109
|
-
return;
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
this.#camera.position.add(_vec3);
|
|
1113
|
-
}
|
|
1114
|
-
#getZoomOutMetrics(source, baseScale = 1) {
|
|
1115
|
-
const metrics = _zoomOutMetrics;
|
|
1116
|
-
const minScale = 0;
|
|
1117
|
-
metrics.distanceScale = baseScale;
|
|
1118
|
-
if (!this.#ellipsoid || this.#isCameraCenterMode()) {
|
|
1119
|
-
return metrics;
|
|
1061
|
+
#getZoomDistanceScale(zoomAmount, source) {
|
|
1062
|
+
if (zoomAmount >= 0 || !this.#ellipsoid || this.#isCameraCenterMode()) {
|
|
1063
|
+
return 1;
|
|
1120
1064
|
}
|
|
1121
1065
|
const taperStartRadius = this.#ellipsoidMaxRadius * 1.5;
|
|
1122
1066
|
const maxRadius = this.#ellipsoidMaxRadius * 2;
|
|
1123
1067
|
const currentDistance = source.length();
|
|
1124
|
-
if (currentDistance
|
|
1125
|
-
|
|
1126
|
-
metrics.distanceScale = minScale;
|
|
1127
|
-
} else {
|
|
1128
|
-
const factor =
|
|
1129
|
-
(maxRadius - currentDistance) / (maxRadius - taperStartRadius);
|
|
1130
|
-
metrics.distanceScale = minScale + (baseScale - minScale) * factor;
|
|
1131
|
-
}
|
|
1068
|
+
if (currentDistance <= taperStartRadius) {
|
|
1069
|
+
return 1;
|
|
1132
1070
|
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
#getScaledZoomTarget(hit, zoomFactor, source, distanceScale, target) {
|
|
1136
|
-
target
|
|
1137
|
-
.copy(source)
|
|
1138
|
-
.sub(hit.point)
|
|
1139
|
-
.multiplyScalar(1 + (zoomFactor - 1) * distanceScale)
|
|
1140
|
-
.add(hit.point);
|
|
1141
|
-
}
|
|
1142
|
-
#getZoomPosition(hit, zoomAmount, zoomFactor, target) {
|
|
1143
|
-
const source = _vec4.copy(this.#camera.position);
|
|
1144
|
-
let distanceScale = 1;
|
|
1145
|
-
if (zoomAmount < 0 && this.#ellipsoid && !this.#isCameraCenterMode()) {
|
|
1146
|
-
const metrics = this.#getZoomOutMetrics(source);
|
|
1147
|
-
distanceScale = metrics.distanceScale;
|
|
1071
|
+
if (currentDistance >= maxRadius) {
|
|
1072
|
+
return 0;
|
|
1148
1073
|
}
|
|
1149
|
-
|
|
1074
|
+
return (maxRadius - currentDistance) / (maxRadius - taperStartRadius);
|
|
1150
1075
|
}
|
|
1151
1076
|
#applyZoom(zoomAmount) {
|
|
1152
1077
|
const hit = this.#hit;
|
|
@@ -1171,12 +1096,18 @@ class CameraController extends EventDispatcher {
|
|
|
1171
1096
|
this.#camera.zoom /= zoomFactor;
|
|
1172
1097
|
this.#camera.updateProjectionMatrix();
|
|
1173
1098
|
}
|
|
1174
|
-
|
|
1099
|
+
const source = _vec4.copy(this.#camera.position);
|
|
1100
|
+
const distanceScale = this.#getZoomDistanceScale(zoomAmount, source);
|
|
1101
|
+
this.#camera.position
|
|
1102
|
+
.copy(source)
|
|
1103
|
+
.sub(hit.point)
|
|
1104
|
+
.multiplyScalar(1 + (zoomFactor - 1) * distanceScale)
|
|
1105
|
+
.add(hit.point);
|
|
1175
1106
|
this.#limitCameraDistance(hit.point);
|
|
1176
1107
|
if (this.#isCameraCenterMode()) {
|
|
1177
1108
|
this.#camera.updateMatrixWorld();
|
|
1178
1109
|
} else {
|
|
1179
|
-
this.#
|
|
1110
|
+
this.#keepCameraUp(hit.point);
|
|
1180
1111
|
}
|
|
1181
1112
|
this.#camera.updateMatrixWorld();
|
|
1182
1113
|
if (this.state === DRAG) {
|
|
@@ -1239,46 +1170,64 @@ class CameraController extends EventDispatcher {
|
|
|
1239
1170
|
return (
|
|
1240
1171
|
!!this.#ellipsoid &&
|
|
1241
1172
|
!this.#isCameraCenterMode() &&
|
|
1242
|
-
this.#camera.position.length() >= this.#ellipsoidMaxRadius
|
|
1173
|
+
this.#camera.position.length() >= this.#ellipsoidMaxRadius * 1.05
|
|
1243
1174
|
);
|
|
1244
1175
|
}
|
|
1245
|
-
#
|
|
1246
|
-
|
|
1247
|
-
const cameraPositionLength = _vec6.length();
|
|
1248
|
-
if (cameraPositionLength < CAMERA_CENTER_MODE_DISTANCE) {
|
|
1249
|
-
this.#alignCameraRightToXYPlane();
|
|
1250
|
-
return;
|
|
1251
|
-
}
|
|
1252
|
-
_localForward.copy(this.#camera.position).normalize();
|
|
1176
|
+
#alignCameraRoll(referenceUp) {
|
|
1177
|
+
_rollRotation.identity();
|
|
1253
1178
|
this.#camera.getWorldDirection(_forward);
|
|
1254
1179
|
_up.copy(this.#camera.up).transformDirection(this.#camera.matrixWorld);
|
|
1255
1180
|
_right.crossVectors(_forward, _up).normalize();
|
|
1256
|
-
_localRight.crossVectors(_up,
|
|
1181
|
+
_localRight.crossVectors(_up, referenceUp);
|
|
1257
1182
|
if (_localRight.dot(_right) < 0) {
|
|
1258
1183
|
_localRight.negate();
|
|
1259
1184
|
}
|
|
1260
1185
|
_quaternion.setFromUnitVectors(_right, _localRight);
|
|
1261
1186
|
this.#camera.quaternion.premultiply(_quaternion);
|
|
1262
|
-
|
|
1187
|
+
_rollRotation.premultiply(_quaternion);
|
|
1263
1188
|
this.#camera.getWorldDirection(_forward);
|
|
1264
1189
|
_up.copy(this.#camera.up).transformDirection(this.#camera.matrixWorld);
|
|
1265
1190
|
_right.crossVectors(_forward, _up).normalize();
|
|
1266
|
-
_localUp.crossVectors(_forward,
|
|
1191
|
+
_localUp.crossVectors(_forward, referenceUp);
|
|
1267
1192
|
if (_localUp.dot(_right) < 0) {
|
|
1268
|
-
const forwardAngle = _forward.angleTo(
|
|
1193
|
+
const forwardAngle = _forward.angleTo(referenceUp);
|
|
1269
1194
|
if (forwardAngle < Math.PI / 2) {
|
|
1270
|
-
_axis.crossVectors(_forward,
|
|
1195
|
+
_axis.crossVectors(_forward, referenceUp).normalize();
|
|
1271
1196
|
_quaternion.setFromAxisAngle(_axis, forwardAngle);
|
|
1272
1197
|
this.#camera.quaternion.premultiply(_quaternion);
|
|
1198
|
+
_rollRotation.premultiply(_quaternion);
|
|
1273
1199
|
} else {
|
|
1274
1200
|
_axis
|
|
1275
|
-
.crossVectors(_forward, _vec4.copy(
|
|
1201
|
+
.crossVectors(_forward, _vec4.copy(referenceUp).negate())
|
|
1276
1202
|
.normalize();
|
|
1277
1203
|
const negatedAngle = _forward.angleTo(_vec4);
|
|
1278
1204
|
_quaternion.setFromAxisAngle(_axis, negatedAngle);
|
|
1279
1205
|
this.#camera.quaternion.premultiply(_quaternion);
|
|
1206
|
+
_rollRotation.premultiply(_quaternion);
|
|
1280
1207
|
}
|
|
1281
1208
|
}
|
|
1209
|
+
return _rollRotation;
|
|
1210
|
+
}
|
|
1211
|
+
#canApplyCameraRollAroundAnchor(anchorPoint) {
|
|
1212
|
+
return (
|
|
1213
|
+
anchorPoint.dot(_vec3.subVectors(this.#camera.position, anchorPoint)) >= 0
|
|
1214
|
+
);
|
|
1215
|
+
}
|
|
1216
|
+
#keepCameraUp(anchorPoint) {
|
|
1217
|
+
// Near the ellipsoid centre the surface normal is unstable, so fall back to
|
|
1218
|
+
// the world up direction.
|
|
1219
|
+
if (this.#isCameraCenterMode()) {
|
|
1220
|
+
this.#alignCameraRoll(_worldZ);
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
this.#getPositionUpDirection(this.#camera.position, _positionUp);
|
|
1224
|
+
const rollRotation = this.#alignCameraRoll(_positionUp);
|
|
1225
|
+
if (anchorPoint && this.#canApplyCameraRollAroundAnchor(anchorPoint)) {
|
|
1226
|
+
this.#camera.position
|
|
1227
|
+
.sub(anchorPoint)
|
|
1228
|
+
.applyQuaternion(rollRotation)
|
|
1229
|
+
.add(anchorPoint);
|
|
1230
|
+
}
|
|
1282
1231
|
}
|
|
1283
1232
|
#normalRaycastClosest(raycaster, objects) {
|
|
1284
1233
|
const targets = Array.isArray(objects) ? objects : [objects];
|
|
@@ -1300,12 +1249,10 @@ class CameraController extends EventDispatcher {
|
|
|
1300
1249
|
const result = this.#isCameraCenterMode()
|
|
1301
1250
|
? undefined
|
|
1302
1251
|
: this.#ellipsoid?.intersectRay(raycaster.ray, _vec6);
|
|
1303
|
-
this.#ellipsoid?.getPositionToNormal(_vec6, _vec5);
|
|
1304
|
-
const distance = _vec6.distanceTo(this.#camera.position);
|
|
1305
1252
|
if (result) {
|
|
1306
1253
|
return {
|
|
1307
1254
|
point: _vec6.clone(),
|
|
1308
|
-
distance:
|
|
1255
|
+
distance: _vec6.distanceTo(this.#camera.position),
|
|
1309
1256
|
onGlobe: true,
|
|
1310
1257
|
};
|
|
1311
1258
|
}
|
|
@@ -11,11 +11,12 @@ export function createGlobeController({
|
|
|
11
11
|
renderer,
|
|
12
12
|
}) {
|
|
13
13
|
let tiles = null;
|
|
14
|
-
let terrainEnabled =
|
|
14
|
+
let terrainEnabled = false;
|
|
15
15
|
|
|
16
|
-
function setTerrainEnabled(enabled) {
|
|
16
|
+
function setTerrainEnabled(enabled, { cesiumIonToken = '' } = {}) {
|
|
17
17
|
const globeTileOptions = {
|
|
18
18
|
camera,
|
|
19
|
+
cesiumIonToken,
|
|
19
20
|
preprocessURL: normalizeLocalResourceUrl,
|
|
20
21
|
renderer,
|
|
21
22
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Ion } from 'cesium';
|
|
2
1
|
import { TilesRenderer } from '3d-tiles-renderer';
|
|
3
2
|
import { ImplicitTilingPlugin } from '3d-tiles-renderer/src/core/plugins/ImplicitTilingPlugin.js';
|
|
4
3
|
import { CesiumIonAuthPlugin } from '3d-tiles-renderer/src/three/plugins/CesiumIonAuthPlugin.js';
|
|
@@ -22,7 +21,6 @@ const SATELLITE_IMAGERY = {
|
|
|
22
21
|
levels: 18,
|
|
23
22
|
};
|
|
24
23
|
const CESIUM_ION_TERRAIN = {
|
|
25
|
-
apiToken: Ion.defaultAccessToken,
|
|
26
24
|
assetId: 1,
|
|
27
25
|
};
|
|
28
26
|
|
|
@@ -73,13 +71,21 @@ export function createImageryGlobeTiles(options) {
|
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
export function createTerrainGlobeTiles(options) {
|
|
74
|
+
const apiToken =
|
|
75
|
+
typeof options.cesiumIonToken === 'string'
|
|
76
|
+
? options.cesiumIonToken.trim()
|
|
77
|
+
: '';
|
|
78
|
+
if (!apiToken) {
|
|
79
|
+
throw new Error('Cesium ion token is required to enable terrain.');
|
|
80
|
+
}
|
|
81
|
+
|
|
76
82
|
const next = new TilesRenderer();
|
|
77
83
|
const satelliteOverlay = createSatelliteOverlay(options.preprocessURL);
|
|
78
84
|
next.downloadQueue.maxJobs = 8;
|
|
79
85
|
next.parseQueue.maxJobs = 2;
|
|
80
86
|
next.registerPlugin(
|
|
81
87
|
new CesiumIonAuthPlugin({
|
|
82
|
-
apiToken
|
|
88
|
+
apiToken,
|
|
83
89
|
assetId: String(CESIUM_ION_TERRAIN.assetId),
|
|
84
90
|
autoRefreshToken: true,
|
|
85
91
|
assetTypeHandler: (type, tilesRenderer) => {
|