easy-three-utils 0.0.1
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/package.json +12 -0
- package/src/common/index.ts +24 -0
- package/src/common/useLine2.ts +87 -0
- package/src/common/useLoader.ts +184 -0
- package/src/common/useLocationCalculator.ts +145 -0
- package/src/common/useMark.ts +42 -0
- package/src/common/useTween.ts +86 -0
- package/src/core/basic/camera.ts +28 -0
- package/src/core/basic/clock.ts +11 -0
- package/src/core/basic/control.ts +32 -0
- package/src/core/basic/index.ts +35 -0
- package/src/core/basic/labelRenderer.ts +26 -0
- package/src/core/basic/light.ts +63 -0
- package/src/core/basic/renderer.ts +37 -0
- package/src/core/basic/scene.ts +11 -0
- package/src/core/basic/stats.ts +16 -0
- package/src/core/event.ts +74 -0
- package/src/core/index.ts +11 -0
- package/src/core/main.ts +389 -0
- package/src/draco/README.md +32 -0
- package/src/draco/draco_decoder.js +34 -0
- package/src/draco/draco_decoder.wasm +0 -0
- package/src/draco/draco_encoder.js +33 -0
- package/src/draco/draco_wasm_wrapper.js +117 -0
- package/src/draco/gltf/draco_decoder.js +33 -0
- package/src/draco/gltf/draco_decoder.wasm +0 -0
- package/src/draco/gltf/draco_encoder.js +33 -0
- package/src/draco/gltf/draco_wasm_wrapper.js +116 -0
- package/src/tileRenderer/base/Tile.d.ts +50 -0
- package/src/tileRenderer/base/TileBase.d.ts +76 -0
- package/src/tileRenderer/base/TileInternal.d.ts +36 -0
- package/src/tileRenderer/base/TilesRendererBase.d.ts +35 -0
- package/src/tileRenderer/base/TilesRendererBase.js +847 -0
- package/src/tileRenderer/base/Tileset.d.ts +66 -0
- package/src/tileRenderer/base/constants.d.ts +6 -0
- package/src/tileRenderer/base/constants.js +16 -0
- package/src/tileRenderer/base/loaders/B3DMLoaderBase.d.ts +18 -0
- package/src/tileRenderer/base/loaders/B3DMLoaderBase.js +85 -0
- package/src/tileRenderer/base/loaders/CMPTLoaderBase.d.ts +22 -0
- package/src/tileRenderer/base/loaders/CMPTLoaderBase.js +61 -0
- package/src/tileRenderer/base/loaders/I3DMLoaderBase.d.ts +21 -0
- package/src/tileRenderer/base/loaders/I3DMLoaderBase.js +130 -0
- package/src/tileRenderer/base/loaders/LoaderBase.d.ts +10 -0
- package/src/tileRenderer/base/loaders/LoaderBase.js +73 -0
- package/src/tileRenderer/base/loaders/PNTSLoaderBase.d.ts +17 -0
- package/src/tileRenderer/base/loaders/PNTSLoaderBase.js +82 -0
- package/src/tileRenderer/base/plugins/ImplicitTilingPlugin.js +12 -0
- package/src/tileRenderer/base/traverseFunctions.js +468 -0
- package/src/tileRenderer/gltf.js +144 -0
- package/src/tileRenderer/index.d.ts +41 -0
- package/src/tileRenderer/index.js +44 -0
- package/src/tileRenderer/plugins/README.md +578 -0
- package/src/tileRenderer/plugins/base/ImplicitTilingPlugin.d.ts +2 -0
- package/src/tileRenderer/plugins/base/ImplicitTilingPlugin.js +84 -0
- package/src/tileRenderer/plugins/base/SUBTREELoader.js +876 -0
- package/src/tileRenderer/plugins/index.d.ts +17 -0
- package/src/tileRenderer/plugins/index.js +17 -0
- package/src/tileRenderer/plugins/three/CesiumIonAuthPlugin.d.ts +9 -0
- package/src/tileRenderer/plugins/three/CesiumIonAuthPlugin.js +175 -0
- package/src/tileRenderer/plugins/three/DebugTilesPlugin.d.ts +29 -0
- package/src/tileRenderer/plugins/three/DebugTilesPlugin.js +677 -0
- package/src/tileRenderer/plugins/three/GLTFExtensionsPlugin.d.ts +18 -0
- package/src/tileRenderer/plugins/three/GLTFExtensionsPlugin.js +86 -0
- package/src/tileRenderer/plugins/three/GoogleAttributionsManager.js +62 -0
- package/src/tileRenderer/plugins/three/GoogleCloudAuthPlugin.d.ts +5 -0
- package/src/tileRenderer/plugins/three/GoogleCloudAuthPlugin.js +200 -0
- package/src/tileRenderer/plugins/three/ReorientationPlugin.d.ts +12 -0
- package/src/tileRenderer/plugins/three/ReorientationPlugin.js +136 -0
- package/src/tileRenderer/plugins/three/TileCompressionPlugin.d.ts +18 -0
- package/src/tileRenderer/plugins/three/TileCompressionPlugin.js +223 -0
- package/src/tileRenderer/plugins/three/UpdateOnChangePlugin.d.ts +5 -0
- package/src/tileRenderer/plugins/three/UpdateOnChangePlugin.js +87 -0
- package/src/tileRenderer/plugins/three/fade/FadeManager.js +370 -0
- package/src/tileRenderer/plugins/three/fade/TilesFadePlugin.d.ts +9 -0
- package/src/tileRenderer/plugins/three/fade/TilesFadePlugin.js +318 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFCesiumRTCExtension.d.ts +5 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFCesiumRTCExtension.js +27 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFMeshFeaturesExtension.d.ts +30 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFMeshFeaturesExtension.js +76 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFStructuralMetadataExtension.d.ts +49 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFStructuralMetadataExtension.js +147 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/ClassProperty.js +149 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/MeshFeatures.js +215 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyAttributeAccessor.js +107 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertySetAccessor.js +45 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyTableAccessor.js +209 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyTextureAccessor.js +244 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/StructuralMetadata.js +202 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/math/Matrix2.js +55 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/utilities/ClassPropertyHelpers.js +495 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/utilities/TexCoordUtilities.js +72 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/utilities/TextureReadUtility.js +154 -0
- package/src/tileRenderer/plugins/three/objects/EllipsoidRegionHelper.js +186 -0
- package/src/tileRenderer/plugins/three/objects/SphereHelper.js +55 -0
- package/src/tileRenderer/r3f/README.md +238 -0
- package/src/tileRenderer/r3f/components/CameraControls.jsx +132 -0
- package/src/tileRenderer/r3f/components/CameraTransition.jsx +177 -0
- package/src/tileRenderer/r3f/components/CanvasDOMOverlay.jsx +54 -0
- package/src/tileRenderer/r3f/components/CompassGizmo.jsx +260 -0
- package/src/tileRenderer/r3f/components/TilesAttributionOverlay.jsx +110 -0
- package/src/tileRenderer/r3f/components/TilesRenderer.jsx +239 -0
- package/src/tileRenderer/r3f/index.jsx +6 -0
- package/src/tileRenderer/r3f/utilities/useForceUpdate.jsx +8 -0
- package/src/tileRenderer/r3f/utilities/useObjectDep.jsx +59 -0
- package/src/tileRenderer/r3f/utilities/useOptions.jsx +143 -0
- package/src/tileRenderer/three/DebugTilesRenderer.d.ts +28 -0
- package/src/tileRenderer/three/DebugTilesRenderer.js +58 -0
- package/src/tileRenderer/three/TilesGroup.d.ts +9 -0
- package/src/tileRenderer/three/TilesGroup.js +91 -0
- package/src/tileRenderer/three/TilesRenderer.d.ts +37 -0
- package/src/tileRenderer/three/TilesRenderer.js +1049 -0
- package/src/tileRenderer/three/controls/CameraTransitionManager.js +305 -0
- package/src/tileRenderer/three/controls/EnvironmentControls.js +1295 -0
- package/src/tileRenderer/three/controls/GlobeControls.js +684 -0
- package/src/tileRenderer/three/controls/PivotPointMesh.js +104 -0
- package/src/tileRenderer/three/controls/PointerTracker.js +257 -0
- package/src/tileRenderer/three/controls/utils.js +113 -0
- package/src/tileRenderer/three/loaders/B3DMLoader.d.ts +26 -0
- package/src/tileRenderer/three/loaders/B3DMLoader.js +85 -0
- package/src/tileRenderer/three/loaders/CMPTLoader.d.ts +19 -0
- package/src/tileRenderer/three/loaders/CMPTLoader.js +97 -0
- package/src/tileRenderer/three/loaders/GLTFExtensionLoader.d.ts +11 -0
- package/src/tileRenderer/three/loaders/GLTFExtensionLoader.js +68 -0
- package/src/tileRenderer/three/loaders/I3DMLoader.d.ts +26 -0
- package/src/tileRenderer/three/loaders/I3DMLoader.js +256 -0
- package/src/tileRenderer/three/loaders/PNTSLoader.d.ts +25 -0
- package/src/tileRenderer/three/loaders/PNTSLoader.js +202 -0
- package/src/tileRenderer/three/loaders/gltf/GLTFCesiumRTCExtension.js +12 -0
- package/src/tileRenderer/three/loaders/gltf/GLTFMeshFeaturesExtension.js +12 -0
- package/src/tileRenderer/three/loaders/gltf/GLTFStructuralMetadataExtension.js +12 -0
- package/src/tileRenderer/three/math/Ellipsoid.d.ts +31 -0
- package/src/tileRenderer/three/math/Ellipsoid.js +337 -0
- package/src/tileRenderer/three/math/EllipsoidRegion.d.ts +23 -0
- package/src/tileRenderer/three/math/EllipsoidRegion.js +178 -0
- package/src/tileRenderer/three/math/ExtendedFrustum.js +65 -0
- package/src/tileRenderer/three/math/GeoConstants.d.ts +4 -0
- package/src/tileRenderer/three/math/GeoConstants.js +5 -0
- package/src/tileRenderer/three/math/GeoUtils.d.ts +9 -0
- package/src/tileRenderer/three/math/GeoUtils.js +106 -0
- package/src/tileRenderer/three/math/OBB.js +179 -0
- package/src/tileRenderer/three/math/TileBoundingVolume.js +272 -0
- package/src/tileRenderer/three/plugins/CesiumIonAuthPlugin.js +12 -0
- package/src/tileRenderer/three/plugins/DebugTilesPlugin.js +26 -0
- package/src/tileRenderer/three/plugins/GoogleCloudAuthPlugin.js +12 -0
- package/src/tileRenderer/three/raycastTraverse.js +178 -0
- package/src/tileRenderer/three/renderers/CesiumIonTilesRenderer.d.ts +14 -0
- package/src/tileRenderer/three/renderers/CesiumIonTilesRenderer.js +21 -0
- package/src/tileRenderer/three/renderers/GoogleTilesRenderer.d.ts +43 -0
- package/src/tileRenderer/three/renderers/GoogleTilesRenderer.js +48 -0
- package/src/tileRenderer/three/utilities.js +54 -0
- package/src/tileRenderer/utilities/BatchTable.d.ts +24 -0
- package/src/tileRenderer/utilities/BatchTable.js +82 -0
- package/src/tileRenderer/utilities/BatchTableHierarchyExtension.js +127 -0
- package/src/tileRenderer/utilities/FeatureTable.d.ts +30 -0
- package/src/tileRenderer/utilities/FeatureTable.js +159 -0
- package/src/tileRenderer/utilities/LRUCache.d.ts +8 -0
- package/src/tileRenderer/utilities/LRUCache.js +385 -0
- package/src/tileRenderer/utilities/PriorityQueue.d.ts +16 -0
- package/src/tileRenderer/utilities/PriorityQueue.js +137 -0
- package/src/tileRenderer/utilities/arrayToString.js +7 -0
- package/src/tileRenderer/utilities/readMagicBytes.js +29 -0
- package/src/tileRenderer/utilities/rgb565torgb.js +22 -0
- package/src/tileRenderer/utilities/urlExtension.js +34 -0
- package/tsconfig.json +42 -0
- package/tsconfig.node.json +11 -0
- package/typings/three.d.ts +27 -0
|
@@ -0,0 +1,1295 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Matrix4,
|
|
3
|
+
Quaternion,
|
|
4
|
+
Vector2,
|
|
5
|
+
Vector3,
|
|
6
|
+
Raycaster,
|
|
7
|
+
Plane,
|
|
8
|
+
EventDispatcher,
|
|
9
|
+
MathUtils,
|
|
10
|
+
Clock,
|
|
11
|
+
} from 'three';
|
|
12
|
+
import { PivotPointMesh } from './PivotPointMesh.js';
|
|
13
|
+
import { PointerTracker } from './PointerTracker.js';
|
|
14
|
+
import { mouseToCoords, makeRotateAroundPoint, setRaycasterFromCamera } from './utils.js';
|
|
15
|
+
|
|
16
|
+
export const NONE = 0;
|
|
17
|
+
export const DRAG = 1;
|
|
18
|
+
export const ROTATE = 2;
|
|
19
|
+
export const ZOOM = 3;
|
|
20
|
+
export const WAITING = 4;
|
|
21
|
+
|
|
22
|
+
const DRAG_PLANE_THRESHOLD = 0.05;
|
|
23
|
+
const DRAG_UP_THRESHOLD = 0.025;
|
|
24
|
+
const ROT_MOMENTUM_THRESHOLD = 1e-4;
|
|
25
|
+
const POS_MOMENTUM_THRESHOLD = 1e-2;
|
|
26
|
+
|
|
27
|
+
const _rotMatrix = new Matrix4();
|
|
28
|
+
const _delta = new Vector3();
|
|
29
|
+
const _vec = new Vector3();
|
|
30
|
+
const _forward = new Vector3();
|
|
31
|
+
const _right = new Vector3();
|
|
32
|
+
const _rotationAxis = new Vector3();
|
|
33
|
+
const _quaternion = new Quaternion();
|
|
34
|
+
const _plane = new Plane();
|
|
35
|
+
const _localUp = new Vector3();
|
|
36
|
+
const _mouseBefore = new Vector3();
|
|
37
|
+
const _mouseAfter = new Vector3();
|
|
38
|
+
const _identityQuat = new Quaternion();
|
|
39
|
+
|
|
40
|
+
const _zoomPointPointer = new Vector2();
|
|
41
|
+
const _pointer = new Vector2();
|
|
42
|
+
const _prevPointer = new Vector2();
|
|
43
|
+
const _deltaPointer = new Vector2();
|
|
44
|
+
const _centerPoint = new Vector2();
|
|
45
|
+
const _startCenterPoint = new Vector2();
|
|
46
|
+
|
|
47
|
+
const _changeEvent = { type: 'change' };
|
|
48
|
+
const _startEvent = { type: 'start' };
|
|
49
|
+
const _endEvent = { type: 'end' };
|
|
50
|
+
|
|
51
|
+
export class EnvironmentControls extends EventDispatcher {
|
|
52
|
+
|
|
53
|
+
get enabled() {
|
|
54
|
+
|
|
55
|
+
return this._enabled;
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
set enabled( v ) {
|
|
60
|
+
|
|
61
|
+
if ( v !== this.enabled ) {
|
|
62
|
+
|
|
63
|
+
this._enabled = v;
|
|
64
|
+
this.resetState();
|
|
65
|
+
this.pointerTracker.reset();
|
|
66
|
+
|
|
67
|
+
if ( ! this.enabled ) {
|
|
68
|
+
|
|
69
|
+
this.dragInertia.set( 0, 0, 0 );
|
|
70
|
+
this.rotationInertia.set( 0, 0 );
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
constructor( scene = null, camera = null, domElement = null, tilesRenderer = null ) {
|
|
79
|
+
|
|
80
|
+
super();
|
|
81
|
+
|
|
82
|
+
this.isEnvironmentControls = true;
|
|
83
|
+
|
|
84
|
+
this.domElement = null;
|
|
85
|
+
this.camera = null;
|
|
86
|
+
this.scene = null;
|
|
87
|
+
this.tilesRenderer = null;
|
|
88
|
+
|
|
89
|
+
// settings
|
|
90
|
+
this._enabled = true;
|
|
91
|
+
this.cameraRadius = 5;
|
|
92
|
+
this.rotationSpeed = 1;
|
|
93
|
+
this.minAltitude = 0;
|
|
94
|
+
this.maxAltitude = 0.45 * Math.PI;
|
|
95
|
+
this.minDistance = 10;
|
|
96
|
+
this.maxDistance = Infinity;
|
|
97
|
+
this.minZoom = 0;
|
|
98
|
+
this.maxZoom = Infinity;
|
|
99
|
+
this.zoomSpeed = 1;
|
|
100
|
+
this.adjustHeight = true;
|
|
101
|
+
this.enableDamping = false;
|
|
102
|
+
this.dampingFactor = 0.15;
|
|
103
|
+
|
|
104
|
+
// settings for GlobeControls
|
|
105
|
+
this.reorientOnDrag = true;
|
|
106
|
+
this.scaleZoomOrientationAtEdges = false;
|
|
107
|
+
|
|
108
|
+
// internal state
|
|
109
|
+
this.state = NONE;
|
|
110
|
+
this.pointerTracker = new PointerTracker();
|
|
111
|
+
this.needsUpdate = false;
|
|
112
|
+
this.actionHeightOffset = 0;
|
|
113
|
+
|
|
114
|
+
this.pivotPoint = new Vector3();
|
|
115
|
+
|
|
116
|
+
this.zoomDirectionSet = false;
|
|
117
|
+
this.zoomPointSet = false;
|
|
118
|
+
this.zoomDirection = new Vector3();
|
|
119
|
+
this.zoomPoint = new Vector3();
|
|
120
|
+
this.zoomDelta = 0;
|
|
121
|
+
|
|
122
|
+
this.rotationInertia = new Vector2();
|
|
123
|
+
this.dragInertia = new Vector3();
|
|
124
|
+
|
|
125
|
+
this.pivotMesh = new PivotPointMesh();
|
|
126
|
+
this.pivotMesh.raycast = () => {};
|
|
127
|
+
this.pivotMesh.scale.setScalar( 0.25 );
|
|
128
|
+
|
|
129
|
+
this.raycaster = new Raycaster();
|
|
130
|
+
this.raycaster.firstHitOnly = true;
|
|
131
|
+
|
|
132
|
+
this.up = new Vector3( 0, 1, 0 );
|
|
133
|
+
this.clock = new Clock();
|
|
134
|
+
|
|
135
|
+
this.fallbackPlane = new Plane( new Vector3( 0, 1, 0 ), 0 );
|
|
136
|
+
this.useFallbackPlane = true;
|
|
137
|
+
|
|
138
|
+
this._detachCallback = null;
|
|
139
|
+
this._upInitialized = false;
|
|
140
|
+
this._lastUsedState = NONE;
|
|
141
|
+
this._zoomPointWasSet = false;
|
|
142
|
+
|
|
143
|
+
// always update the zoom target point in case the tiles are changing
|
|
144
|
+
this._tilesOnChangeCallback = () => this.zoomPointSet = false;
|
|
145
|
+
|
|
146
|
+
// init
|
|
147
|
+
if ( domElement ) this.attach( domElement );
|
|
148
|
+
if ( camera ) this.setCamera( camera );
|
|
149
|
+
if ( scene ) this.setScene( scene );
|
|
150
|
+
if ( tilesRenderer ) this.setTilesRenderer( tilesRenderer );
|
|
151
|
+
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
setScene( scene ) {
|
|
155
|
+
|
|
156
|
+
this.scene = scene;
|
|
157
|
+
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
setCamera( camera ) {
|
|
161
|
+
|
|
162
|
+
this.camera = camera;
|
|
163
|
+
this._upInitialized = false;
|
|
164
|
+
this.zoomDirectionSet = false;
|
|
165
|
+
this.zoomPointSet = false;
|
|
166
|
+
this.needsUpdate = true;
|
|
167
|
+
this.raycaster.camera = camera;
|
|
168
|
+
this.resetState();
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
setTilesRenderer( tilesRenderer ) {
|
|
173
|
+
|
|
174
|
+
// TODO: what if a scene has multiple tile sets?
|
|
175
|
+
if ( this.tilesRenderer ) {
|
|
176
|
+
|
|
177
|
+
this.tilesRenderer.removeEventListener( 'tile-visibility-change', this._tilesOnChangeCallback );
|
|
178
|
+
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
this.tilesRenderer = tilesRenderer;
|
|
182
|
+
if ( this.tilesRenderer !== null ) {
|
|
183
|
+
|
|
184
|
+
this.tilesRenderer.addEventListener( 'tile-visibility-change', this._tilesOnChangeCallback );
|
|
185
|
+
|
|
186
|
+
if ( this.scene === null ) {
|
|
187
|
+
|
|
188
|
+
this.setScene( this.tilesRenderer.group );
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
attach( domElement ) {
|
|
197
|
+
|
|
198
|
+
if ( this.domElement ) {
|
|
199
|
+
|
|
200
|
+
throw new Error( 'EnvironmentControls: Controls already attached to element' );
|
|
201
|
+
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// set the touch action to none so the browser does not
|
|
205
|
+
// drag the page to refresh or scroll
|
|
206
|
+
this.domElement = domElement;
|
|
207
|
+
this.pointerTracker.domElement = domElement;
|
|
208
|
+
domElement.style.touchAction = 'none';
|
|
209
|
+
|
|
210
|
+
let shiftClicked = false;
|
|
211
|
+
|
|
212
|
+
const contextMenuCallback = e => {
|
|
213
|
+
|
|
214
|
+
e.preventDefault();
|
|
215
|
+
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const keydownCallback = e => {
|
|
219
|
+
|
|
220
|
+
if ( e.key === 'Shift' ) {
|
|
221
|
+
|
|
222
|
+
shiftClicked = true;
|
|
223
|
+
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const keyupCallback = e => {
|
|
229
|
+
|
|
230
|
+
if ( e.key === 'Shift' ) {
|
|
231
|
+
|
|
232
|
+
shiftClicked = false;
|
|
233
|
+
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const pointerdownCallback = e => {
|
|
239
|
+
|
|
240
|
+
e.preventDefault();
|
|
241
|
+
|
|
242
|
+
const {
|
|
243
|
+
camera,
|
|
244
|
+
raycaster,
|
|
245
|
+
domElement,
|
|
246
|
+
up,
|
|
247
|
+
pivotMesh,
|
|
248
|
+
pointerTracker,
|
|
249
|
+
} = this;
|
|
250
|
+
|
|
251
|
+
// init the pointer
|
|
252
|
+
pointerTracker.addPointer( e );
|
|
253
|
+
this.needsUpdate = true;
|
|
254
|
+
|
|
255
|
+
// handle cases where we need to capture the pointer or
|
|
256
|
+
// reset state when we have too many pointers
|
|
257
|
+
if ( pointerTracker.isPointerTouch() ) {
|
|
258
|
+
|
|
259
|
+
pivotMesh.visible = false;
|
|
260
|
+
|
|
261
|
+
if ( pointerTracker.getPointerCount() === 0 ) {
|
|
262
|
+
|
|
263
|
+
domElement.setPointerCapture( e.pointerId );
|
|
264
|
+
|
|
265
|
+
} else if ( pointerTracker.getPointerCount() > 2 ) {
|
|
266
|
+
|
|
267
|
+
this.resetState();
|
|
268
|
+
return;
|
|
269
|
+
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// the "pointer" for zooming and rotating should be based on the center point
|
|
275
|
+
pointerTracker.getCenterPoint( _pointer );
|
|
276
|
+
mouseToCoords( _pointer.x, _pointer.y, domElement, _pointer );
|
|
277
|
+
setRaycasterFromCamera( raycaster, _pointer, camera );
|
|
278
|
+
|
|
279
|
+
// prevent the drag distance from getting too severe by limiting the drag point
|
|
280
|
+
// to a reasonable angle and reasonable distance with the drag plane
|
|
281
|
+
const dot = Math.abs( raycaster.ray.direction.dot( up ) );
|
|
282
|
+
if ( dot < DRAG_PLANE_THRESHOLD || dot < DRAG_UP_THRESHOLD ) {
|
|
283
|
+
|
|
284
|
+
return;
|
|
285
|
+
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// find the hit point
|
|
289
|
+
const hit = this._raycast( raycaster );
|
|
290
|
+
if ( hit ) {
|
|
291
|
+
|
|
292
|
+
// if two fingers, right click, or shift click are being used then we trigger
|
|
293
|
+
// a rotation action to begin
|
|
294
|
+
if (
|
|
295
|
+
pointerTracker.getPointerCount() === 2 ||
|
|
296
|
+
pointerTracker.isRightClicked() ||
|
|
297
|
+
pointerTracker.isLeftClicked() && shiftClicked
|
|
298
|
+
) {
|
|
299
|
+
|
|
300
|
+
this.setState( pointerTracker.isPointerTouch() ? WAITING : ROTATE );
|
|
301
|
+
|
|
302
|
+
this.pivotPoint.copy( hit.point );
|
|
303
|
+
this.pivotMesh.position.copy( hit.point );
|
|
304
|
+
this.pivotMesh.updateMatrixWorld();
|
|
305
|
+
this.scene.add( this.pivotMesh );
|
|
306
|
+
|
|
307
|
+
} else if ( pointerTracker.isLeftClicked() ) {
|
|
308
|
+
|
|
309
|
+
// if the clicked point is coming from below the plane then don't perform the drag
|
|
310
|
+
this.setState( DRAG );
|
|
311
|
+
this.pivotPoint.copy( hit.point );
|
|
312
|
+
|
|
313
|
+
this.pivotMesh.position.copy( hit.point );
|
|
314
|
+
this.pivotMesh.updateMatrixWorld();
|
|
315
|
+
this.scene.add( this.pivotMesh );
|
|
316
|
+
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
let _pointerMoveQueued = false;
|
|
324
|
+
const pointermoveCallback = e => {
|
|
325
|
+
|
|
326
|
+
e.preventDefault();
|
|
327
|
+
|
|
328
|
+
// whenever the pointer moves we need to re-derive the zoom direction and point
|
|
329
|
+
this.zoomDirectionSet = false;
|
|
330
|
+
this.zoomPointSet = false;
|
|
331
|
+
|
|
332
|
+
if ( this.state !== NONE ) {
|
|
333
|
+
|
|
334
|
+
this.needsUpdate = true;
|
|
335
|
+
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const { pointerTracker } = this;
|
|
339
|
+
pointerTracker.setHoverEvent( e );
|
|
340
|
+
if ( ! pointerTracker.updatePointer( e ) ) {
|
|
341
|
+
|
|
342
|
+
return;
|
|
343
|
+
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if ( pointerTracker.isPointerTouch() && pointerTracker.getPointerCount() === 2 ) {
|
|
347
|
+
|
|
348
|
+
// We queue this event to ensure that all pointers have been updated
|
|
349
|
+
if ( ! _pointerMoveQueued ) {
|
|
350
|
+
|
|
351
|
+
_pointerMoveQueued = true;
|
|
352
|
+
queueMicrotask( () => {
|
|
353
|
+
|
|
354
|
+
_pointerMoveQueued = false;
|
|
355
|
+
|
|
356
|
+
// adjust the pointer position to be the center point
|
|
357
|
+
pointerTracker.getCenterPoint( _centerPoint );
|
|
358
|
+
|
|
359
|
+
// detect zoom transition
|
|
360
|
+
const startDist = pointerTracker.getStartTouchPointerDistance();
|
|
361
|
+
const pointerDist = pointerTracker.getTouchPointerDistance();
|
|
362
|
+
const separateDelta = pointerDist - startDist;
|
|
363
|
+
if ( this.state === NONE || this.state === WAITING ) {
|
|
364
|
+
|
|
365
|
+
// check which direction was moved in first - if the pointers are pinching then
|
|
366
|
+
// it's a zoom. But if they move in parallel it's a rotation
|
|
367
|
+
pointerTracker.getCenterPoint( _centerPoint );
|
|
368
|
+
pointerTracker.getStartCenterPoint( _startCenterPoint );
|
|
369
|
+
|
|
370
|
+
// adjust the drag requirement by the dpr
|
|
371
|
+
const dragThreshold = 2.0 * window.devicePixelRatio;
|
|
372
|
+
const parallelDelta = _centerPoint.distanceTo( _startCenterPoint );
|
|
373
|
+
if ( Math.abs( separateDelta ) > dragThreshold || parallelDelta > dragThreshold ) {
|
|
374
|
+
|
|
375
|
+
if ( Math.abs( separateDelta ) > parallelDelta ) {
|
|
376
|
+
|
|
377
|
+
this.setState( ZOOM );
|
|
378
|
+
this.zoomDirectionSet = false;
|
|
379
|
+
|
|
380
|
+
} else {
|
|
381
|
+
|
|
382
|
+
this.setState( ROTATE );
|
|
383
|
+
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if ( this.state === ZOOM ) {
|
|
391
|
+
|
|
392
|
+
const previousDist = pointerTracker.getPreviousTouchPointerDistance();
|
|
393
|
+
this.zoomDelta += pointerDist - previousDist;
|
|
394
|
+
|
|
395
|
+
} else if ( this.state === ROTATE ) {
|
|
396
|
+
|
|
397
|
+
this.pivotMesh.visible = this.enabled;
|
|
398
|
+
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
} );
|
|
402
|
+
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// TODO: we have the potential to fire change multiple times per frame - should we debounce?
|
|
408
|
+
this.dispatchEvent( _changeEvent );
|
|
409
|
+
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
const pointerupCallback = e => {
|
|
413
|
+
|
|
414
|
+
const { pointerTracker } = this;
|
|
415
|
+
|
|
416
|
+
pointerTracker.deletePointer( e );
|
|
417
|
+
|
|
418
|
+
if (
|
|
419
|
+
pointerTracker.getPointerType() === 'touch' &&
|
|
420
|
+
pointerTracker.getPointerCount() === 0
|
|
421
|
+
) {
|
|
422
|
+
|
|
423
|
+
domElement.releasePointerCapture( e.pointerId );
|
|
424
|
+
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
this.resetState();
|
|
428
|
+
this.needsUpdate = true;
|
|
429
|
+
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
const wheelCallback = e => {
|
|
433
|
+
|
|
434
|
+
e.preventDefault();
|
|
435
|
+
|
|
436
|
+
const { pointerTracker } = this;
|
|
437
|
+
pointerTracker.setHoverEvent( e );
|
|
438
|
+
pointerTracker.updatePointer( e );
|
|
439
|
+
|
|
440
|
+
// TODO: do we need events here?
|
|
441
|
+
this.dispatchEvent( _startEvent );
|
|
442
|
+
|
|
443
|
+
let delta;
|
|
444
|
+
switch ( e.deltaMode ) {
|
|
445
|
+
|
|
446
|
+
case 2: // Pages
|
|
447
|
+
delta = e.deltaY * 100;
|
|
448
|
+
break;
|
|
449
|
+
case 1: // Lines
|
|
450
|
+
delta = e.deltaY * 16;
|
|
451
|
+
break;
|
|
452
|
+
case 0: // Pixels
|
|
453
|
+
delta = e.deltaY;
|
|
454
|
+
break;
|
|
455
|
+
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// use LOG to scale the scroll delta and hopefully normalize them across platforms
|
|
459
|
+
const deltaSign = Math.sign( delta );
|
|
460
|
+
const normalizedDelta = Math.log( Math.abs( delta ) + 1 );
|
|
461
|
+
this.zoomDelta -= 3 * deltaSign * normalizedDelta;
|
|
462
|
+
this.needsUpdate = true;
|
|
463
|
+
|
|
464
|
+
this._lastUsedState = ZOOM;
|
|
465
|
+
this.dispatchEvent( _endEvent );
|
|
466
|
+
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
const pointerenterCallback = e => {
|
|
470
|
+
|
|
471
|
+
const { pointerTracker } = this;
|
|
472
|
+
|
|
473
|
+
shiftClicked = false;
|
|
474
|
+
|
|
475
|
+
if ( e.buttons !== pointerTracker.getPointerButtons() ) {
|
|
476
|
+
|
|
477
|
+
pointerTracker.deletePointer( e );
|
|
478
|
+
this.resetState();
|
|
479
|
+
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
domElement.addEventListener( 'contextmenu', contextMenuCallback );
|
|
485
|
+
domElement.addEventListener( 'keydown', keydownCallback );
|
|
486
|
+
domElement.addEventListener( 'keyup', keyupCallback );
|
|
487
|
+
domElement.addEventListener( 'pointerdown', pointerdownCallback );
|
|
488
|
+
domElement.addEventListener( 'pointermove', pointermoveCallback );
|
|
489
|
+
domElement.addEventListener( 'pointerup', pointerupCallback );
|
|
490
|
+
domElement.addEventListener( 'wheel', wheelCallback, { passive: false } );
|
|
491
|
+
domElement.addEventListener( 'pointerenter', pointerenterCallback );
|
|
492
|
+
|
|
493
|
+
this._detachCallback = () => {
|
|
494
|
+
|
|
495
|
+
domElement.removeEventListener( 'contextmenu', contextMenuCallback );
|
|
496
|
+
domElement.removeEventListener( 'keydown', keydownCallback );
|
|
497
|
+
domElement.removeEventListener( 'keyup', keyupCallback );
|
|
498
|
+
domElement.removeEventListener( 'pointerdown', pointerdownCallback );
|
|
499
|
+
domElement.removeEventListener( 'pointermove', pointermoveCallback );
|
|
500
|
+
domElement.removeEventListener( 'pointerup', pointerupCallback );
|
|
501
|
+
domElement.removeEventListener( 'wheel', wheelCallback );
|
|
502
|
+
domElement.removeEventListener( 'pointerenter', pointerenterCallback );
|
|
503
|
+
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// override-able functions for retrieving the up direction at a point
|
|
509
|
+
getUpDirection( point, target ) {
|
|
510
|
+
|
|
511
|
+
target.copy( this.up );
|
|
512
|
+
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
getCameraUpDirection( target ) {
|
|
516
|
+
|
|
517
|
+
this.getUpDirection( this.camera.position, target );
|
|
518
|
+
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// returns the active / last used pivot point for the scene
|
|
522
|
+
getPivotPoint( target ) {
|
|
523
|
+
|
|
524
|
+
if ( this._lastUsedState === ZOOM ) {
|
|
525
|
+
|
|
526
|
+
if ( this._zoomPointWasSet ) {
|
|
527
|
+
|
|
528
|
+
target.copy( this.zoomPoint );
|
|
529
|
+
return target;
|
|
530
|
+
|
|
531
|
+
} else {
|
|
532
|
+
|
|
533
|
+
return null;
|
|
534
|
+
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
} else if ( this._lastUsedState === ROTATE || this._lastUsedState === DRAG ) {
|
|
538
|
+
|
|
539
|
+
target.copy( this.pivotPoint );
|
|
540
|
+
return target;
|
|
541
|
+
|
|
542
|
+
} else {
|
|
543
|
+
|
|
544
|
+
return null;
|
|
545
|
+
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
detach() {
|
|
551
|
+
|
|
552
|
+
this.domElement = null;
|
|
553
|
+
|
|
554
|
+
if ( this._detachCallback ) {
|
|
555
|
+
|
|
556
|
+
this._detachCallback();
|
|
557
|
+
this._detachCallback = null;
|
|
558
|
+
this.pointerTracker.reset();
|
|
559
|
+
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
resetState() {
|
|
565
|
+
|
|
566
|
+
if ( this.state !== NONE ) {
|
|
567
|
+
|
|
568
|
+
this.dispatchEvent( _endEvent );
|
|
569
|
+
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
this.state = NONE;
|
|
573
|
+
this.pivotMesh.removeFromParent();
|
|
574
|
+
this.pivotMesh.visible = this.enabled;
|
|
575
|
+
this.actionHeightOffset = 0;
|
|
576
|
+
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
setState( state = this.state, fireEvent = true ) {
|
|
580
|
+
|
|
581
|
+
if ( this.state === state ) {
|
|
582
|
+
|
|
583
|
+
return;
|
|
584
|
+
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if ( this.state === NONE && fireEvent ) {
|
|
588
|
+
|
|
589
|
+
this.dispatchEvent( _startEvent );
|
|
590
|
+
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
this.pivotMesh.visible = this.enabled;
|
|
594
|
+
this.dragInertia.set( 0, 0, 0 );
|
|
595
|
+
this.rotationInertia.set( 0, 0 );
|
|
596
|
+
this.state = state;
|
|
597
|
+
|
|
598
|
+
if ( state !== NONE && state !== WAITING ) {
|
|
599
|
+
|
|
600
|
+
this._lastUsedState = state;
|
|
601
|
+
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
update( deltaTime = Math.min( this.clock.getDelta(), 64 / 1000 ) ) {
|
|
607
|
+
|
|
608
|
+
if ( ! this.enabled || ! this.camera || deltaTime === 0 ) {
|
|
609
|
+
|
|
610
|
+
return;
|
|
611
|
+
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
const {
|
|
615
|
+
camera,
|
|
616
|
+
cameraRadius,
|
|
617
|
+
pivotPoint,
|
|
618
|
+
up,
|
|
619
|
+
state,
|
|
620
|
+
adjustHeight,
|
|
621
|
+
} = this;
|
|
622
|
+
|
|
623
|
+
camera.updateMatrixWorld();
|
|
624
|
+
|
|
625
|
+
// set the "up" vector immediately so it's available in the following functions
|
|
626
|
+
this.getCameraUpDirection( _localUp );
|
|
627
|
+
if ( ! this._upInitialized ) {
|
|
628
|
+
|
|
629
|
+
this._upInitialized = true;
|
|
630
|
+
this.up.copy( _localUp );
|
|
631
|
+
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// update the actions
|
|
635
|
+
const inertiaNeedsUpdate = this._inertiaNeedsUpdate();
|
|
636
|
+
if ( this.needsUpdate || inertiaNeedsUpdate ) {
|
|
637
|
+
|
|
638
|
+
const zoomDelta = this.zoomDelta;
|
|
639
|
+
if ( state === ZOOM || zoomDelta !== 0 ) {
|
|
640
|
+
|
|
641
|
+
this._updateZoom();
|
|
642
|
+
|
|
643
|
+
this.rotationInertia.set( 0, 0 );
|
|
644
|
+
this.dragInertia.set( 0, 0, 0 );
|
|
645
|
+
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
this._updatePosition( deltaTime );
|
|
649
|
+
this._updateRotation( deltaTime );
|
|
650
|
+
|
|
651
|
+
if ( state !== NONE || zoomDelta !== 0 || inertiaNeedsUpdate ) {
|
|
652
|
+
|
|
653
|
+
this.dispatchEvent( _changeEvent );
|
|
654
|
+
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
this.needsUpdate = false;
|
|
658
|
+
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
if ( inertiaNeedsUpdate ) {
|
|
662
|
+
|
|
663
|
+
this._updateInertiaDamping( deltaTime );
|
|
664
|
+
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// update the up direction based on where the camera moved to
|
|
668
|
+
// if using an orthographic camera then rotate around drag pivot
|
|
669
|
+
// reuse the "hit" information since it can be slow to perform multiple hits
|
|
670
|
+
const hit = camera.isOrthographicCamera ? null : adjustHeight && this._getPointBelowCamera() || null;
|
|
671
|
+
const rotationPoint = camera.isOrthographicCamera ? pivotPoint : hit && hit.point || null;
|
|
672
|
+
this.getCameraUpDirection( _localUp );
|
|
673
|
+
this._setFrame( _localUp, rotationPoint );
|
|
674
|
+
|
|
675
|
+
// when dragging the camera and drag point may be moved
|
|
676
|
+
// to accommodate terrain so we try to move it back down
|
|
677
|
+
// to the original point.
|
|
678
|
+
if ( ( this.state === DRAG || this.state === ROTATE ) && this.actionHeightOffset !== 0 ) {
|
|
679
|
+
|
|
680
|
+
const { actionHeightOffset } = this;
|
|
681
|
+
camera.position.addScaledVector( up, - actionHeightOffset );
|
|
682
|
+
pivotPoint.addScaledVector( up, - actionHeightOffset );
|
|
683
|
+
|
|
684
|
+
// adjust the height
|
|
685
|
+
if ( hit ) {
|
|
686
|
+
|
|
687
|
+
hit.distance -= actionHeightOffset;
|
|
688
|
+
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
this.actionHeightOffset = 0;
|
|
694
|
+
|
|
695
|
+
if ( hit ) {
|
|
696
|
+
|
|
697
|
+
const dist = hit.distance;
|
|
698
|
+
if ( dist < cameraRadius ) {
|
|
699
|
+
|
|
700
|
+
const delta = cameraRadius - dist;
|
|
701
|
+
camera.position.addScaledVector( up, delta );
|
|
702
|
+
pivotPoint.addScaledVector( up, delta );
|
|
703
|
+
this.actionHeightOffset = delta;
|
|
704
|
+
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
this.pointerTracker.updateFrame();
|
|
710
|
+
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// updates the camera to position it based on the constraints of the controls
|
|
714
|
+
adjustCamera( camera ) {
|
|
715
|
+
|
|
716
|
+
const { adjustHeight, cameraRadius } = this;
|
|
717
|
+
if ( camera.isPerspectiveCamera ) {
|
|
718
|
+
|
|
719
|
+
// adjust the camera height
|
|
720
|
+
this.getUpDirection( camera.position, _localUp );
|
|
721
|
+
const hit = adjustHeight && this._getPointBelowCamera( camera.position, _localUp ) || null;
|
|
722
|
+
if ( hit ) {
|
|
723
|
+
|
|
724
|
+
const dist = hit.distance;
|
|
725
|
+
if ( dist < cameraRadius ) {
|
|
726
|
+
|
|
727
|
+
camera.position.addScaledVector( _localUp, cameraRadius - dist );
|
|
728
|
+
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
dispose() {
|
|
738
|
+
|
|
739
|
+
this.detach();
|
|
740
|
+
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// private
|
|
744
|
+
_updateInertiaDamping( deltaTime ) {
|
|
745
|
+
|
|
746
|
+
// update the damping of momentum variables
|
|
747
|
+
const {
|
|
748
|
+
rotationInertia,
|
|
749
|
+
dragInertia,
|
|
750
|
+
enableDamping,
|
|
751
|
+
dampingFactor,
|
|
752
|
+
} = this;
|
|
753
|
+
|
|
754
|
+
// Based on Freya Holmer's frame-rate independent lerp function
|
|
755
|
+
const factor = Math.pow( 2, - deltaTime / dampingFactor );
|
|
756
|
+
|
|
757
|
+
// scale the residual motion
|
|
758
|
+
rotationInertia.multiplyScalar( factor );
|
|
759
|
+
if ( rotationInertia.lengthSq() < ROT_MOMENTUM_THRESHOLD || ! enableDamping ) {
|
|
760
|
+
|
|
761
|
+
rotationInertia.set( 0, 0 );
|
|
762
|
+
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
dragInertia.multiplyScalar( factor );
|
|
766
|
+
if ( dragInertia.lengthSq() < POS_MOMENTUM_THRESHOLD || ! enableDamping ) {
|
|
767
|
+
|
|
768
|
+
dragInertia.set( 0, 0, 0 );
|
|
769
|
+
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
_inertiaNeedsUpdate() {
|
|
775
|
+
|
|
776
|
+
const { rotationInertia, dragInertia } = this;
|
|
777
|
+
return rotationInertia.lengthSq() !== 0 || dragInertia.lengthSq() !== 0;
|
|
778
|
+
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
_updateZoom() {
|
|
782
|
+
|
|
783
|
+
const {
|
|
784
|
+
zoomPoint,
|
|
785
|
+
zoomDirection,
|
|
786
|
+
camera,
|
|
787
|
+
minDistance,
|
|
788
|
+
maxDistance,
|
|
789
|
+
pointerTracker,
|
|
790
|
+
domElement,
|
|
791
|
+
minZoom,
|
|
792
|
+
maxZoom,
|
|
793
|
+
zoomSpeed,
|
|
794
|
+
} = this;
|
|
795
|
+
|
|
796
|
+
let scale = this.zoomDelta;
|
|
797
|
+
this.zoomDelta = 0;
|
|
798
|
+
|
|
799
|
+
// get the latest hover / touch point
|
|
800
|
+
if ( ! pointerTracker.getLatestPoint( _pointer ) ) {
|
|
801
|
+
|
|
802
|
+
return;
|
|
803
|
+
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if ( camera.isOrthographicCamera ) {
|
|
807
|
+
|
|
808
|
+
// update the zoom direction
|
|
809
|
+
this._updateZoomDirection();
|
|
810
|
+
|
|
811
|
+
// zoom straight into the globe if we haven't hit anything
|
|
812
|
+
const zoomIntoPoint = this.zoomPointSet || this._updateZoomPoint();
|
|
813
|
+
|
|
814
|
+
// get the mouse position before zoom
|
|
815
|
+
_mouseBefore.unproject( camera );
|
|
816
|
+
|
|
817
|
+
// zoom the camera
|
|
818
|
+
const normalizedDelta = Math.pow( 0.95, Math.abs( scale * 0.05 ) );
|
|
819
|
+
let scaleFactor = scale > 0 ? 1 / Math.abs( normalizedDelta ) : normalizedDelta;
|
|
820
|
+
scaleFactor *= zoomSpeed;
|
|
821
|
+
|
|
822
|
+
if ( scaleFactor > 1 ) {
|
|
823
|
+
|
|
824
|
+
if ( maxZoom < camera.zoom * scaleFactor ) {
|
|
825
|
+
|
|
826
|
+
scaleFactor = 1;
|
|
827
|
+
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
} else {
|
|
831
|
+
|
|
832
|
+
if ( minZoom > camera.zoom * scaleFactor ) {
|
|
833
|
+
|
|
834
|
+
scaleFactor = 1;
|
|
835
|
+
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
camera.zoom *= scaleFactor;
|
|
841
|
+
camera.updateProjectionMatrix();
|
|
842
|
+
|
|
843
|
+
// adjust the surface point to be in the same position if the globe is hovered over
|
|
844
|
+
if ( zoomIntoPoint ) {
|
|
845
|
+
|
|
846
|
+
// get the mouse position after zoom
|
|
847
|
+
mouseToCoords( _pointer.x, _pointer.y, domElement, _mouseAfter );
|
|
848
|
+
_mouseAfter.unproject( camera );
|
|
849
|
+
|
|
850
|
+
// shift the camera on the near plane so the mouse is in the same spot
|
|
851
|
+
camera.position.sub( _mouseAfter ).add( _mouseBefore );
|
|
852
|
+
camera.updateMatrixWorld();
|
|
853
|
+
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// TODO: the user can currently zoom into the sky and hide the globe.
|
|
857
|
+
// Consider forcing the camera to zoom into the closest horizon point
|
|
858
|
+
|
|
859
|
+
} else {
|
|
860
|
+
|
|
861
|
+
// initialize the zoom direction
|
|
862
|
+
this._updateZoomDirection();
|
|
863
|
+
|
|
864
|
+
// track the zoom direction we're going to use
|
|
865
|
+
const finalZoomDirection = _vec.copy( zoomDirection );
|
|
866
|
+
|
|
867
|
+
if ( this.zoomPointSet || this._updateZoomPoint() ) {
|
|
868
|
+
|
|
869
|
+
const dist = zoomPoint.distanceTo( camera.position );
|
|
870
|
+
|
|
871
|
+
// scale the distance based on how far there is to move
|
|
872
|
+
if ( scale < 0 ) {
|
|
873
|
+
|
|
874
|
+
const remainingDistance = Math.min( 0, dist - maxDistance );
|
|
875
|
+
scale = scale * dist * zoomSpeed * 0.0025;
|
|
876
|
+
scale = Math.max( scale, remainingDistance );
|
|
877
|
+
|
|
878
|
+
} else {
|
|
879
|
+
|
|
880
|
+
const remainingDistance = Math.max( 0, dist - minDistance );
|
|
881
|
+
scale = scale * Math.max( dist - minDistance, 0 ) * zoomSpeed * 0.0025;
|
|
882
|
+
scale = Math.min( scale, remainingDistance );
|
|
883
|
+
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
camera.position.addScaledVector( zoomDirection, scale );
|
|
887
|
+
camera.updateMatrixWorld();
|
|
888
|
+
|
|
889
|
+
} else {
|
|
890
|
+
|
|
891
|
+
// if we're zooming into nothing then use the distance from the ground to scale movement
|
|
892
|
+
const hit = this._getPointBelowCamera();
|
|
893
|
+
if ( hit ) {
|
|
894
|
+
|
|
895
|
+
const dist = hit.distance;
|
|
896
|
+
finalZoomDirection.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
|
|
897
|
+
camera.position.addScaledVector( finalZoomDirection, scale * dist * 0.01 );
|
|
898
|
+
camera.updateMatrixWorld();
|
|
899
|
+
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
_updateZoomDirection() {
|
|
909
|
+
|
|
910
|
+
if ( this.zoomDirectionSet ) {
|
|
911
|
+
|
|
912
|
+
return;
|
|
913
|
+
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
const { domElement, raycaster, camera, zoomDirection, pointerTracker } = this;
|
|
917
|
+
pointerTracker.getLatestPoint( _pointer );
|
|
918
|
+
mouseToCoords( _pointer.x, _pointer.y, domElement, _mouseBefore );
|
|
919
|
+
setRaycasterFromCamera( raycaster, _mouseBefore, camera );
|
|
920
|
+
zoomDirection.copy( raycaster.ray.direction ).normalize();
|
|
921
|
+
this.zoomDirectionSet = true;
|
|
922
|
+
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// update the point being zoomed in to based on the zoom direction
|
|
926
|
+
_updateZoomPoint() {
|
|
927
|
+
|
|
928
|
+
const {
|
|
929
|
+
camera,
|
|
930
|
+
zoomDirectionSet,
|
|
931
|
+
zoomDirection,
|
|
932
|
+
raycaster,
|
|
933
|
+
zoomPoint,
|
|
934
|
+
pointerTracker,
|
|
935
|
+
domElement,
|
|
936
|
+
} = this;
|
|
937
|
+
|
|
938
|
+
this._zoomPointWasSet = false;
|
|
939
|
+
|
|
940
|
+
if ( ! zoomDirectionSet ) {
|
|
941
|
+
|
|
942
|
+
return false;
|
|
943
|
+
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// If using an orthographic camera we have to account for the mouse position when picking the point
|
|
947
|
+
if ( camera.isOrthographicCamera && pointerTracker.getLatestPoint( _zoomPointPointer ) ) {
|
|
948
|
+
|
|
949
|
+
mouseToCoords( _zoomPointPointer.x, _zoomPointPointer.y, domElement, _zoomPointPointer );
|
|
950
|
+
setRaycasterFromCamera( raycaster, _zoomPointPointer, camera );
|
|
951
|
+
|
|
952
|
+
} else {
|
|
953
|
+
|
|
954
|
+
raycaster.ray.origin.copy( camera.position );
|
|
955
|
+
raycaster.ray.direction.copy( zoomDirection );
|
|
956
|
+
raycaster.near = 0;
|
|
957
|
+
raycaster.far = Infinity;
|
|
958
|
+
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// get the hit point
|
|
962
|
+
const hit = this._raycast( raycaster );
|
|
963
|
+
if ( hit ) {
|
|
964
|
+
|
|
965
|
+
zoomPoint.copy( hit.point );
|
|
966
|
+
this.zoomPointSet = true;
|
|
967
|
+
this._zoomPointWasSet = true;
|
|
968
|
+
return true;
|
|
969
|
+
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
return false;
|
|
973
|
+
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// returns the point below the camera
|
|
977
|
+
_getPointBelowCamera( point = this.camera.position, up = this.up ) {
|
|
978
|
+
|
|
979
|
+
const { raycaster } = this;
|
|
980
|
+
raycaster.ray.direction.copy( up ).multiplyScalar( - 1 );
|
|
981
|
+
raycaster.ray.origin.copy( point ).addScaledVector( up, 1e5 );
|
|
982
|
+
raycaster.near = 0;
|
|
983
|
+
raycaster.far = Infinity;
|
|
984
|
+
|
|
985
|
+
const hit = this._raycast( raycaster );
|
|
986
|
+
if ( hit ) {
|
|
987
|
+
|
|
988
|
+
hit.distance -= 1e5;
|
|
989
|
+
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
return hit;
|
|
993
|
+
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// update the drag action
|
|
997
|
+
_updatePosition( deltaTime ) {
|
|
998
|
+
|
|
999
|
+
const {
|
|
1000
|
+
raycaster,
|
|
1001
|
+
camera,
|
|
1002
|
+
pivotPoint,
|
|
1003
|
+
up,
|
|
1004
|
+
pointerTracker,
|
|
1005
|
+
domElement,
|
|
1006
|
+
state,
|
|
1007
|
+
dragInertia,
|
|
1008
|
+
enableDamping,
|
|
1009
|
+
} = this;
|
|
1010
|
+
|
|
1011
|
+
if ( state === DRAG ) {
|
|
1012
|
+
|
|
1013
|
+
// get the pointer and plane
|
|
1014
|
+
pointerTracker.getCenterPoint( _pointer );
|
|
1015
|
+
mouseToCoords( _pointer.x, _pointer.y, domElement, _pointer );
|
|
1016
|
+
|
|
1017
|
+
_plane.setFromNormalAndCoplanarPoint( up, pivotPoint );
|
|
1018
|
+
setRaycasterFromCamera( raycaster, _pointer, camera );
|
|
1019
|
+
|
|
1020
|
+
// prevent the drag distance from getting too severe by limiting the drag point
|
|
1021
|
+
// to a reasonable angle with the drag plane
|
|
1022
|
+
if ( Math.abs( raycaster.ray.direction.dot( up ) ) < DRAG_PLANE_THRESHOLD ) {
|
|
1023
|
+
|
|
1024
|
+
// rotate the pointer direction down to the correct angle for horizontal dragging
|
|
1025
|
+
const angle = Math.acos( DRAG_PLANE_THRESHOLD );
|
|
1026
|
+
|
|
1027
|
+
_rotationAxis
|
|
1028
|
+
.crossVectors( raycaster.ray.direction, up )
|
|
1029
|
+
.normalize();
|
|
1030
|
+
|
|
1031
|
+
raycaster.ray.direction
|
|
1032
|
+
.copy( up )
|
|
1033
|
+
.applyAxisAngle( _rotationAxis, angle )
|
|
1034
|
+
.multiplyScalar( - 1 );
|
|
1035
|
+
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// TODO: dragging causes the camera to rise because we're getting "pushed" up by lower resolution tiles and
|
|
1039
|
+
// don't lower back down. We should maintain a target height above tiles where possible
|
|
1040
|
+
// prevent the drag from inverting
|
|
1041
|
+
|
|
1042
|
+
// if we drag to a point that's near the edge of the earth then we want to prevent it
|
|
1043
|
+
// from wrapping around and causing unexpected rotations
|
|
1044
|
+
this.getUpDirection( pivotPoint, _localUp );
|
|
1045
|
+
if ( Math.abs( raycaster.ray.direction.dot( _localUp ) ) < DRAG_UP_THRESHOLD ) {
|
|
1046
|
+
|
|
1047
|
+
const angle = Math.acos( DRAG_UP_THRESHOLD );
|
|
1048
|
+
|
|
1049
|
+
_rotationAxis
|
|
1050
|
+
.crossVectors( raycaster.ray.direction, _localUp )
|
|
1051
|
+
.normalize();
|
|
1052
|
+
|
|
1053
|
+
raycaster.ray.direction
|
|
1054
|
+
.copy( _localUp )
|
|
1055
|
+
.applyAxisAngle( _rotationAxis, angle )
|
|
1056
|
+
.multiplyScalar( - 1 );
|
|
1057
|
+
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// find the point on the plane that we should drag to
|
|
1061
|
+
if ( raycaster.ray.intersectPlane( _plane, _vec ) ) {
|
|
1062
|
+
|
|
1063
|
+
_delta.subVectors( pivotPoint, _vec );
|
|
1064
|
+
camera.position.add( _delta );
|
|
1065
|
+
camera.updateMatrixWorld();
|
|
1066
|
+
|
|
1067
|
+
// update the drag inertia
|
|
1068
|
+
_delta.multiplyScalar( 1 / deltaTime );
|
|
1069
|
+
if ( pointerTracker.getMoveDistance() / deltaTime < 2 * window.devicePixelRatio ) {
|
|
1070
|
+
|
|
1071
|
+
dragInertia.lerp( _delta, 0.5 );
|
|
1072
|
+
|
|
1073
|
+
} else {
|
|
1074
|
+
|
|
1075
|
+
dragInertia.copy( _delta );
|
|
1076
|
+
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
} else if ( enableDamping ) {
|
|
1082
|
+
|
|
1083
|
+
camera.position.addScaledVector( dragInertia, deltaTime );
|
|
1084
|
+
camera.updateMatrixWorld();
|
|
1085
|
+
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
_updateRotation( deltaTime ) {
|
|
1091
|
+
|
|
1092
|
+
const {
|
|
1093
|
+
pivotPoint,
|
|
1094
|
+
pointerTracker,
|
|
1095
|
+
domElement,
|
|
1096
|
+
state,
|
|
1097
|
+
rotationInertia,
|
|
1098
|
+
enableDamping,
|
|
1099
|
+
} = this;
|
|
1100
|
+
|
|
1101
|
+
if ( state === ROTATE ) {
|
|
1102
|
+
|
|
1103
|
+
// get the rotation motion and divide out the container height to normalize for element size
|
|
1104
|
+
pointerTracker.getCenterPoint( _pointer );
|
|
1105
|
+
pointerTracker.getPreviousCenterPoint( _prevPointer );
|
|
1106
|
+
_deltaPointer.subVectors( _pointer, _prevPointer ).multiplyScalar( 2 * Math.PI / domElement.clientHeight );
|
|
1107
|
+
|
|
1108
|
+
this._applyRotation( _deltaPointer.x, _deltaPointer.y, pivotPoint );
|
|
1109
|
+
|
|
1110
|
+
// update rotation inertia
|
|
1111
|
+
_deltaPointer.multiplyScalar( 1 / deltaTime );
|
|
1112
|
+
if ( pointerTracker.getMoveDistance() / deltaTime < 2 * window.devicePixelRatio ) {
|
|
1113
|
+
|
|
1114
|
+
rotationInertia.lerp( _deltaPointer, 0.5 );
|
|
1115
|
+
|
|
1116
|
+
} else {
|
|
1117
|
+
|
|
1118
|
+
rotationInertia.copy( _deltaPointer );
|
|
1119
|
+
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
} else if ( enableDamping ) {
|
|
1123
|
+
|
|
1124
|
+
this._applyRotation( rotationInertia.x * deltaTime, rotationInertia.y * deltaTime, pivotPoint );
|
|
1125
|
+
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
_applyRotation( x, y, pivotPoint ) {
|
|
1131
|
+
|
|
1132
|
+
if ( x === 0 && y === 0 ) {
|
|
1133
|
+
|
|
1134
|
+
return;
|
|
1135
|
+
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
const {
|
|
1139
|
+
camera,
|
|
1140
|
+
minAltitude,
|
|
1141
|
+
maxAltitude,
|
|
1142
|
+
rotationSpeed,
|
|
1143
|
+
} = this;
|
|
1144
|
+
|
|
1145
|
+
const azimuth = - x * rotationSpeed;
|
|
1146
|
+
let altitude = y * rotationSpeed;
|
|
1147
|
+
|
|
1148
|
+
// calculate current angles and clamp
|
|
1149
|
+
_forward.set( 0, 0, 1 ).transformDirection( camera.matrixWorld );
|
|
1150
|
+
|
|
1151
|
+
this.getUpDirection( pivotPoint, _localUp );
|
|
1152
|
+
|
|
1153
|
+
// get the signed angle relative to the top down view
|
|
1154
|
+
_vec.crossVectors( _localUp, _forward ).normalize();
|
|
1155
|
+
_right.set( 1, 0, 0 ).transformDirection( camera.matrixWorld ).normalize();
|
|
1156
|
+
const sign = Math.sign( _vec.dot( _right ) );
|
|
1157
|
+
const angle = sign * _localUp.angleTo( _forward );
|
|
1158
|
+
|
|
1159
|
+
// clamp the rotation to be within the provided limits
|
|
1160
|
+
// clamp to 0 here, as well, so we don't "pop" to the the value range
|
|
1161
|
+
if ( altitude > 0 ) {
|
|
1162
|
+
|
|
1163
|
+
altitude = Math.min( angle - minAltitude - 1e-2, altitude );
|
|
1164
|
+
altitude = Math.max( 0, altitude );
|
|
1165
|
+
|
|
1166
|
+
} else {
|
|
1167
|
+
|
|
1168
|
+
altitude = Math.max( angle - maxAltitude, altitude );
|
|
1169
|
+
altitude = Math.min( 0, altitude );
|
|
1170
|
+
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
// rotate around the up axis
|
|
1174
|
+
_quaternion.setFromAxisAngle( _localUp, azimuth );
|
|
1175
|
+
makeRotateAroundPoint( pivotPoint, _quaternion, _rotMatrix );
|
|
1176
|
+
camera.matrixWorld.premultiply( _rotMatrix );
|
|
1177
|
+
|
|
1178
|
+
// get a rotation axis for altitude and rotate
|
|
1179
|
+
_rotationAxis.set( - 1, 0, 0 ).transformDirection( camera.matrixWorld );
|
|
1180
|
+
|
|
1181
|
+
_quaternion.setFromAxisAngle( _rotationAxis, altitude );
|
|
1182
|
+
makeRotateAroundPoint( pivotPoint, _quaternion, _rotMatrix );
|
|
1183
|
+
camera.matrixWorld.premultiply( _rotMatrix );
|
|
1184
|
+
|
|
1185
|
+
// update the transform members
|
|
1186
|
+
camera.matrixWorld.decompose( camera.position, camera.quaternion, _vec );
|
|
1187
|
+
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
// sets the "up" axis for the current surface of the tile set
|
|
1191
|
+
_setFrame( newUp, pivot ) {
|
|
1192
|
+
|
|
1193
|
+
const {
|
|
1194
|
+
up,
|
|
1195
|
+
camera,
|
|
1196
|
+
state,
|
|
1197
|
+
zoomPoint,
|
|
1198
|
+
zoomDirectionSet,
|
|
1199
|
+
zoomPointSet,
|
|
1200
|
+
reorientOnDrag,
|
|
1201
|
+
scaleZoomOrientationAtEdges,
|
|
1202
|
+
} = this;
|
|
1203
|
+
|
|
1204
|
+
camera.updateMatrixWorld();
|
|
1205
|
+
|
|
1206
|
+
// get the amount needed to rotate
|
|
1207
|
+
_quaternion.setFromUnitVectors( up, newUp );
|
|
1208
|
+
|
|
1209
|
+
// If we're zooming then reorient around the zoom point
|
|
1210
|
+
const action = state;
|
|
1211
|
+
if ( zoomDirectionSet && ( zoomPointSet || this._updateZoomPoint() ) ) {
|
|
1212
|
+
|
|
1213
|
+
this.getUpDirection( zoomPoint, _vec );
|
|
1214
|
+
|
|
1215
|
+
if ( scaleZoomOrientationAtEdges ) {
|
|
1216
|
+
|
|
1217
|
+
let amt = Math.max( _vec.dot( up ) - 0.6, 0 ) / 0.4;
|
|
1218
|
+
amt = MathUtils.mapLinear( amt, 0, 0.5, 0, 1 );
|
|
1219
|
+
amt = Math.min( amt, 1 );
|
|
1220
|
+
|
|
1221
|
+
// scale the value if we're using an orthographic camera so
|
|
1222
|
+
// GlobeControls works correctly
|
|
1223
|
+
if ( camera.isOrthographicCamera ) {
|
|
1224
|
+
|
|
1225
|
+
amt *= 0.1;
|
|
1226
|
+
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
_quaternion.slerp( _identityQuat, 1.0 - amt );
|
|
1230
|
+
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// rotates the camera position around the point being zoomed in to
|
|
1234
|
+
makeRotateAroundPoint( zoomPoint, _quaternion, _rotMatrix );
|
|
1235
|
+
camera.matrixWorld.premultiply( _rotMatrix );
|
|
1236
|
+
camera.matrixWorld.decompose( camera.position, camera.quaternion, _vec );
|
|
1237
|
+
|
|
1238
|
+
// recompute the zoom direction after updating rotation to align with frame
|
|
1239
|
+
this.zoomDirectionSet = false;
|
|
1240
|
+
this._updateZoomDirection();
|
|
1241
|
+
|
|
1242
|
+
} else if ( action === DRAG && reorientOnDrag ) {
|
|
1243
|
+
|
|
1244
|
+
// If we're dragging then reorient around the drag point
|
|
1245
|
+
|
|
1246
|
+
// NOTE: We used to derive the pivot point here by getting the point below the camera
|
|
1247
|
+
// but decided to pass it in via "update" to avoid multiple ray casts
|
|
1248
|
+
|
|
1249
|
+
if ( pivot ) {
|
|
1250
|
+
|
|
1251
|
+
// perform a simple realignment by rotating the camera around the pivot
|
|
1252
|
+
makeRotateAroundPoint( pivot, _quaternion, _rotMatrix );
|
|
1253
|
+
camera.matrixWorld.premultiply( _rotMatrix );
|
|
1254
|
+
camera.matrixWorld.decompose( camera.position, camera.quaternion, _vec );
|
|
1255
|
+
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
up.copy( newUp );
|
|
1261
|
+
camera.updateMatrixWorld();
|
|
1262
|
+
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
_raycast( raycaster ) {
|
|
1266
|
+
|
|
1267
|
+
const { scene, useFallbackPlane, fallbackPlane } = this;
|
|
1268
|
+
const result = raycaster.intersectObject( scene )[ 0 ] || null;
|
|
1269
|
+
if ( result ) {
|
|
1270
|
+
|
|
1271
|
+
return result;
|
|
1272
|
+
|
|
1273
|
+
} else if ( useFallbackPlane ) {
|
|
1274
|
+
|
|
1275
|
+
// if we don't hit any geometry then try to intersect the fallback
|
|
1276
|
+
// plane so the camera can still be manipulated
|
|
1277
|
+
const plane = fallbackPlane;
|
|
1278
|
+
if ( raycaster.ray.intersectPlane( plane, _vec ) ) {
|
|
1279
|
+
|
|
1280
|
+
const planeHit = {
|
|
1281
|
+
point: _vec.clone(),
|
|
1282
|
+
distance: raycaster.ray.origin.distanceTo( _vec ),
|
|
1283
|
+
};
|
|
1284
|
+
|
|
1285
|
+
return planeHit;
|
|
1286
|
+
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
return null;
|
|
1292
|
+
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
}
|