zincjs 3.0.0 → 3.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/README.md +27 -22
- package/build/zinc.js +2 -2
- package/build/zinc.js.map +1 -1
- package/package.json +4 -1
- package/src/controls.js +1332 -1241
- package/src/geometryCSG.js +111 -115
- package/src/glyphsetCSG.js +51 -55
- package/src/loaders/GLTFToZincJSLoader.js +31 -33
- package/src/loaders/JSONLoader.js +339 -449
- package/src/loaders/OBJLoader.js +654 -851
- package/src/loaders/STLLoader.js +271 -329
- package/src/loaders/niftiReader.js +90 -59
- package/src/loaders/primitivesLoader.js +55 -52
- package/src/minimap.js +63 -43
- package/src/primitives/geometry.js +40 -44
- package/src/primitives/glyph.js +16 -19
- package/src/primitives/glyphset.js +229 -185
- package/src/primitives/label.js +29 -31
- package/src/primitives/lines.js +20 -20
- package/src/primitives/lines2.js +33 -39
- package/src/primitives/lod.js +43 -43
- package/src/primitives/marker.js +31 -32
- package/src/primitives/markerCluster.js +32 -35
- package/src/primitives/pointset.js +86 -83
- package/src/primitives/texturePrimitive.js +9 -10
- package/src/primitives/textureSlides.js +84 -97
- package/src/primitives/textureVolume.js +46 -49
- package/src/primitives/tubeLines.js +108 -108
- package/src/primitives/zincObject.js +176 -184
- package/src/region.js +145 -155
- package/src/renderRequests.js +3 -3
- package/src/renderer.js +635 -620
- package/src/scene.js +479 -419
- package/src/sceneExporter.js +22 -17
- package/src/sceneLoader.js +542 -296
- package/src/shaders/rgbVolumeRender.js +11 -18
- package/src/shaders/textureArray.js +5 -12
- package/src/shaders/textureSlide.js +10 -17
- package/src/shaders/volumeRender.js +11 -18
- package/src/shaders/volumeRender_old.js +11 -18
- package/src/shaders/volumeTexture.js +7 -14
- package/src/textSprite.js +23 -19
- package/src/texture/texture.js +14 -15
- package/src/texture/textureArray.js +14 -16
- package/src/three/InstancedPoints.js +2 -9
- package/src/three/Loader.js +334 -315
- package/src/three/line/Line.js +165 -215
- package/src/three/line/LineSegments.js +40 -55
- package/src/three/line/LineSegments2.js +322 -366
- package/src/three/line/LineSegmentsGeometry.js +239 -280
- package/src/three-js-csg.js +260 -252
- package/src/tsl/glyphRenderMaterial.js +12 -3
- package/src/tsl/glyphTransform.js +51 -29
- package/src/tsl/textureSlides.js +23 -24
- package/src/utilities.js +309 -371
- package/src/videoHandler.js +76 -83
- package/src/workers/geometryCSG.worker.js +33 -36
- package/src/workers/geometryCSGInternal.js +39 -44
- package/src/zinc.js +4 -7
- package/vite.config.js +7 -7
package/src/controls.js
CHANGED
|
@@ -9,16 +9,16 @@ import * as THREE from 'three/webgpu';
|
|
|
9
9
|
*/
|
|
10
10
|
const Viewport = function () {
|
|
11
11
|
/** @property {Number} */
|
|
12
|
-
|
|
12
|
+
this.nearPlane = 0.168248;
|
|
13
13
|
/** @property {Number} */
|
|
14
|
-
|
|
14
|
+
this.farPlane = 6.82906;
|
|
15
15
|
/**@property {Array} */
|
|
16
|
-
|
|
16
|
+
this.eyePosition = [0.5, -2.86496, 0.5];
|
|
17
17
|
/** @property {Array} */
|
|
18
|
-
|
|
18
|
+
this.targetPosition = [0.5, 0.5, 0.5];
|
|
19
19
|
/** @property {Array} */
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
this.upVector = [0.0, 0.0, 1.0];
|
|
21
|
+
const _this = this;
|
|
22
22
|
|
|
23
23
|
this.setFromObject = ({ nearPlane, farPlane, eyePosition, targetPosition, upVector }) => {
|
|
24
24
|
_this.nearPlane = nearPlane;
|
|
@@ -26,7 +26,7 @@ const Viewport = function () {
|
|
|
26
26
|
_this.eyePosition = eyePosition;
|
|
27
27
|
_this.targetPosition = targetPosition;
|
|
28
28
|
_this.upVector = upVector;
|
|
29
|
-
}
|
|
29
|
+
};
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
/**
|
|
@@ -36,61 +36,91 @@ const Viewport = function () {
|
|
|
36
36
|
* @author Alan Wu
|
|
37
37
|
* @return {CameraControls}
|
|
38
38
|
*/
|
|
39
|
-
const CameraControls = function (
|
|
40
|
-
|
|
39
|
+
const CameraControls = function (object, domElement, renderer, scene) {
|
|
40
|
+
const MODE = {
|
|
41
|
+
NONE: -1,
|
|
42
|
+
DEFAULT: 0,
|
|
43
|
+
PATH: 1,
|
|
44
|
+
SMOOTH_CAMERA_TRANSITION: 2,
|
|
45
|
+
AUTO_TUMBLE: 3,
|
|
46
|
+
ROTATE_TRANSITION: 4,
|
|
47
|
+
MINIMAP: 5,
|
|
48
|
+
SYNC_CONTROL: 6,
|
|
49
|
+
};
|
|
41
50
|
/**
|
|
42
51
|
* Actions states.
|
|
43
52
|
* Available states are NONE, ROTATE, ZOOM, PAN, TOUCH_ROTATE, TOUCH_ZOOM, TOUCH_PAN and SCROLL.
|
|
44
53
|
* @property {Object}
|
|
45
54
|
*/
|
|
46
|
-
|
|
55
|
+
const STATE = {
|
|
56
|
+
NONE: -1,
|
|
57
|
+
ROTATE: 0,
|
|
58
|
+
ZOOM: 1,
|
|
59
|
+
PAN: 2,
|
|
60
|
+
TOUCH_ROTATE: 3,
|
|
61
|
+
TOUCH_ZOOM: 4,
|
|
62
|
+
TOUCH_PAN: 5,
|
|
63
|
+
SCROLL: 6,
|
|
64
|
+
KEYBOARD_ZOOM: 7,
|
|
65
|
+
KEYBOARD_ROTATE: 8,
|
|
66
|
+
KEYBOARD_PAN: 9,
|
|
67
|
+
};
|
|
47
68
|
const ROTATE_DIRECTION = { NONE: -1, FREE: 1, HORIZONTAL: 2, VERTICAL: 3 };
|
|
48
|
-
|
|
69
|
+
const KEYBOARD = {
|
|
70
|
+
ARROWLEFT: 37,
|
|
71
|
+
ARROWUP: 38,
|
|
72
|
+
ARROWRIGHT: 39,
|
|
73
|
+
ARROWDOWN: 40,
|
|
74
|
+
NUMPADADD: 107,
|
|
75
|
+
NUMPADSUBTRACT: 109,
|
|
76
|
+
EQUAL: 187,
|
|
77
|
+
MINUS: 189,
|
|
78
|
+
};
|
|
49
79
|
/**
|
|
50
80
|
* Available click actions are MAIN, AUXILIARY and SECONARY.
|
|
51
81
|
* @property {Object}
|
|
52
82
|
*/
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
83
|
+
const CLICK_ACTION = {};
|
|
84
|
+
CLICK_ACTION.MAIN = STATE.ROTATE;
|
|
85
|
+
CLICK_ACTION.AUXILIARY = STATE.ZOOM;
|
|
86
|
+
CLICK_ACTION.SECONDARY = STATE.PAN;
|
|
87
|
+
this.cameraObject = object;
|
|
88
|
+
this.domElement = domElement !== undefined ? domElement : document;
|
|
89
|
+
this.renderer = renderer;
|
|
90
|
+
this.scene = scene;
|
|
91
|
+
this.tumble_rate = 1.5;
|
|
92
|
+
this.pointer_x = 0;
|
|
93
|
+
this.pointer_y = 0;
|
|
94
|
+
this.pointer_x_start = 0;
|
|
95
|
+
this.pointer_y_start = 0;
|
|
96
|
+
this.previous_pointer_x = 0;
|
|
97
|
+
this.previous_pointer_y = 0;
|
|
98
|
+
this.near_plane_fly_debt = 0.0;
|
|
99
|
+
this.touchZoomDistanceStart = 0;
|
|
100
|
+
this.touchZoomDistanceEnd = 0;
|
|
101
|
+
this.directionalLight = 0;
|
|
102
|
+
this.zoomRate = 50;
|
|
103
|
+
this.rotateRate = 50;
|
|
104
|
+
this.panRate = 100;
|
|
105
|
+
this.pixelHeight = 1;
|
|
106
|
+
let duration = 6000;
|
|
77
107
|
let enabled = true;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
108
|
+
let inbuildTime = 0;
|
|
109
|
+
let cameraPath = undefined;
|
|
110
|
+
let numberOfCameraPoint = undefined;
|
|
111
|
+
let updateLightWithPathFlag = false;
|
|
112
|
+
let playRate = 500;
|
|
113
|
+
let deviceOrientationControl = undefined;
|
|
114
|
+
let defaultViewport = 'default';
|
|
115
|
+
let currentMode = MODE.DEFAULT;
|
|
116
|
+
let smoothCameraTransitionObject = undefined;
|
|
117
|
+
let rotateCameraTransitionObject = undefined;
|
|
118
|
+
let cameraAutoTumbleObject = undefined;
|
|
119
|
+
let zoomSize = 0;
|
|
90
120
|
let rotateMode = ROTATE_DIRECTION.FREE;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
121
|
+
this._state = STATE.NONE;
|
|
122
|
+
let zincRayCaster = undefined;
|
|
123
|
+
this.targetTouchId = -1;
|
|
94
124
|
let rect = undefined;
|
|
95
125
|
const _a = new THREE.Vector3();
|
|
96
126
|
const _b = new THREE.Vector3();
|
|
@@ -106,17 +136,17 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
106
136
|
let ndcControl = undefined;
|
|
107
137
|
let maxDist = 0;
|
|
108
138
|
const viewports = {
|
|
109
|
-
|
|
139
|
+
default: new Viewport(),
|
|
110
140
|
};
|
|
111
141
|
viewports.default.nearPlane = 0.1;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
142
|
+
viewports.default.farPlane = 2000;
|
|
143
|
+
viewports.default.eyePosition = [0, 0, 0];
|
|
144
|
+
viewports.default.targetPosition = [0, 0, -1.0];
|
|
145
|
+
viewports.default.upVector = [0.0, 1.0, 0.0];
|
|
116
146
|
|
|
117
147
|
//Add the target property
|
|
118
|
-
|
|
119
|
-
|
|
148
|
+
if (this.cameraObject.target === undefined)
|
|
149
|
+
this.cameraObject.target = new THREE.Vector3(...viewports.default.targetPosition);
|
|
120
150
|
|
|
121
151
|
//Calculate the max distanc allowed, it is the longer
|
|
122
152
|
//of 6 times the radius of the current scene and
|
|
@@ -131,11 +161,11 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
131
161
|
if (this.cameraObject) {
|
|
132
162
|
currentDist = this.cameraObject.position.distanceTo(sceneSphere.center);
|
|
133
163
|
}
|
|
134
|
-
maxDist = currentDist > maxDist ? currentDist * 1.5: maxDist;
|
|
164
|
+
maxDist = currentDist > maxDist ? currentDist * 1.5 : maxDist;
|
|
135
165
|
} else {
|
|
136
166
|
maxDist = 0;
|
|
137
167
|
}
|
|
138
|
-
}
|
|
168
|
+
};
|
|
139
169
|
|
|
140
170
|
const updateNearAndFarPlane = (travalDist) => {
|
|
141
171
|
const ratio = 0.001;
|
|
@@ -173,7 +203,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
173
203
|
}
|
|
174
204
|
}
|
|
175
205
|
*/
|
|
176
|
-
}
|
|
206
|
+
};
|
|
177
207
|
|
|
178
208
|
/**
|
|
179
209
|
* Add a viewport to the list of available named viewports.
|
|
@@ -182,9 +212,8 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
182
212
|
* @param {Viewport} viewportName - Viewport to be added
|
|
183
213
|
*/
|
|
184
214
|
this.addViewport = (viewportName, viewport) => {
|
|
185
|
-
if (viewportName && viewport)
|
|
186
|
-
|
|
187
|
-
}
|
|
215
|
+
if (viewportName && viewport) viewports[viewportName] = viewport;
|
|
216
|
+
};
|
|
188
217
|
|
|
189
218
|
/**
|
|
190
219
|
* Set the default viewport for this {@link CameraControls}.
|
|
@@ -193,13 +222,13 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
193
222
|
*
|
|
194
223
|
* @return {Boolean} true if set successfully, false otherwise.
|
|
195
224
|
*/
|
|
196
|
-
this.setDefaultViewport = defaultName => {
|
|
197
|
-
|
|
225
|
+
this.setDefaultViewport = (defaultName) => {
|
|
226
|
+
if (defaultName && defaultName in viewports) {
|
|
198
227
|
defaultViewport = defaultName;
|
|
199
228
|
return true;
|
|
200
229
|
}
|
|
201
|
-
return false
|
|
202
|
-
|
|
230
|
+
return false;
|
|
231
|
+
};
|
|
203
232
|
|
|
204
233
|
/**
|
|
205
234
|
* Get the name of the default viewport.
|
|
@@ -208,8 +237,8 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
208
237
|
* @return {String}
|
|
209
238
|
*/
|
|
210
239
|
this.getDefaultViewport = () => {
|
|
211
|
-
|
|
212
|
-
|
|
240
|
+
return defaultViewport;
|
|
241
|
+
};
|
|
213
242
|
|
|
214
243
|
/**
|
|
215
244
|
* Get the viewport with the provied name stored in this object.
|
|
@@ -217,9 +246,9 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
217
246
|
*
|
|
218
247
|
* @return {Viewport}
|
|
219
248
|
*/
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
249
|
+
this.getViewportOfName = (name) => {
|
|
250
|
+
return viewports[name];
|
|
251
|
+
};
|
|
223
252
|
|
|
224
253
|
/**
|
|
225
254
|
* Set the viewport with a name if it is found in the list.
|
|
@@ -227,13 +256,13 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
227
256
|
*
|
|
228
257
|
* @return {Boolean} if viewport is found and set, otherwise false.
|
|
229
258
|
*/
|
|
230
|
-
this.setCurrentViewport = name => {
|
|
259
|
+
this.setCurrentViewport = (name) => {
|
|
231
260
|
if (name in viewports) {
|
|
232
|
-
this.setCurrentCameraSettings(viewports[name])
|
|
261
|
+
this.setCurrentCameraSettings(viewports[name]);
|
|
233
262
|
return true;
|
|
234
263
|
}
|
|
235
264
|
return false;
|
|
236
|
-
|
|
265
|
+
};
|
|
237
266
|
|
|
238
267
|
/**
|
|
239
268
|
* Set the direction of rotation allowed with this control.
|
|
@@ -241,51 +270,49 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
241
270
|
* @param {String} mode - available options are none, horizontal,
|
|
242
271
|
* vertical and free.
|
|
243
272
|
*/
|
|
244
|
-
this.setRotationMode = mode => {
|
|
273
|
+
this.setRotationMode = (mode) => {
|
|
245
274
|
switch (mode) {
|
|
246
|
-
case
|
|
275
|
+
case 'none':
|
|
247
276
|
rotateMode = ROTATE_DIRECTION.NONE;
|
|
248
277
|
break;
|
|
249
|
-
case
|
|
278
|
+
case 'horizontal':
|
|
250
279
|
rotateMode = ROTATE_DIRECTION.HORIZONTAL;
|
|
251
280
|
break;
|
|
252
|
-
case
|
|
281
|
+
case 'vertical':
|
|
253
282
|
rotateMode = ROTATE_DIRECTION.VERTICAL;
|
|
254
283
|
break;
|
|
255
|
-
case
|
|
284
|
+
case 'free':
|
|
256
285
|
default:
|
|
257
286
|
rotateMode = ROTATE_DIRECTION.FREE;
|
|
258
287
|
}
|
|
259
|
-
}
|
|
288
|
+
};
|
|
260
289
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
rect = undefined;
|
|
290
|
+
this.onResize = () => {
|
|
291
|
+
hasUpdated = true;
|
|
292
|
+
if (rect) rect = undefined;
|
|
265
293
|
if (ndcControl)
|
|
266
|
-
ndcControl.setCurrentCameraSettings(this.cameraObject,
|
|
267
|
-
|
|
268
|
-
}
|
|
294
|
+
ndcControl.setCurrentCameraSettings(this.cameraObject, viewports[defaultViewport]);
|
|
295
|
+
};
|
|
269
296
|
|
|
270
|
-
|
|
271
|
-
|
|
297
|
+
this.getVisibleHeightAtZDepth = (depth) => {
|
|
298
|
+
// compensate for cameras not positioned at z=0
|
|
272
299
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
300
|
+
const cameraOffset = this.cameraObject.position.distanceTo(this.cameraObject.target);
|
|
301
|
+
if (depth < cameraOffset) depth -= cameraOffset;
|
|
302
|
+
else depth += cameraOffset;
|
|
276
303
|
|
|
277
|
-
|
|
278
|
-
|
|
304
|
+
// vertical fov in radians
|
|
305
|
+
const vFOV = (this.cameraObject.fov * Math.PI) / 180;
|
|
279
306
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
307
|
+
// Math.abs to ensure the result is always positive
|
|
308
|
+
return 2 * Math.tan(vFOV / 2) * Math.abs(depth);
|
|
309
|
+
};
|
|
283
310
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
311
|
+
this.calculateHeightPerPixelAtZeroDepth = (wHeight) => {
|
|
312
|
+
const height = this.getVisibleHeightAtZDepth(0);
|
|
313
|
+
this.pixelHeight = height / wHeight;
|
|
314
|
+
return this.pixelHeight;
|
|
315
|
+
};
|
|
289
316
|
|
|
290
317
|
/**
|
|
291
318
|
* Get normalised coordinates from windows coordinates.
|
|
@@ -304,7 +331,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
304
331
|
const out_x = ((x - rect.left) / rect.width) * 2 - 1;
|
|
305
332
|
const out_y = -((y - rect.top) / rect.height) * 2 + 1;
|
|
306
333
|
return position.set(out_x, out_y);
|
|
307
|
-
}
|
|
334
|
+
};
|
|
308
335
|
|
|
309
336
|
/**
|
|
310
337
|
* Get the relative windows coordinates from normalised coordiantes.
|
|
@@ -320,10 +347,10 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
320
347
|
this.getRelativeCoordsFromNDC = (x, y, positionIn) => {
|
|
321
348
|
updateRect(false);
|
|
322
349
|
const position = positionIn ? positionIn : new THREE.Vector2();
|
|
323
|
-
position.x = (x + 1) * rect.width / 2.0;
|
|
324
|
-
position.y = (1 - y) * rect.height / 2.0;
|
|
350
|
+
position.x = ((x + 1) * rect.width) / 2.0;
|
|
351
|
+
position.y = ((1 - y) * rect.height) / 2.0;
|
|
325
352
|
return position;
|
|
326
|
-
}
|
|
353
|
+
};
|
|
327
354
|
|
|
328
355
|
/**
|
|
329
356
|
* Map a mouse click to the specified action.
|
|
@@ -331,184 +358,193 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
331
358
|
* @param {String} buttonName - please see {@link CLICK_ACTION}
|
|
332
359
|
* @param {String} actionName - please see {@link STATE}
|
|
333
360
|
*/
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
361
|
+
this.setMouseButtonAction = (buttonName, actionName) => {
|
|
362
|
+
CLICK_ACTION[buttonName] = STATE[actionName];
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
*
|
|
367
|
+
* @param {HTML} element
|
|
368
|
+
* @param {Number} index
|
|
369
|
+
*/
|
|
370
|
+
const setCanvasTabindex = (element, index) => {
|
|
371
|
+
if (element instanceof HTMLCanvasElement) element.tabIndex = index;
|
|
372
|
+
};
|
|
347
373
|
|
|
348
374
|
//Make sure the camera does not travel beyond limit
|
|
349
375
|
const checkTravelDistance = () => {
|
|
350
376
|
if (maxDist > 0) {
|
|
351
377
|
const newDist = _tempEye.distanceTo(sceneSphere.center);
|
|
352
|
-
return (
|
|
353
|
-
this.cameraObject.position.distanceTo(sceneSphere.center) > newDist
|
|
378
|
+
return (
|
|
379
|
+
maxDist > newDist || this.cameraObject.position.distanceTo(sceneSphere.center) > newDist
|
|
380
|
+
);
|
|
354
381
|
}
|
|
355
382
|
return true;
|
|
356
|
-
}
|
|
383
|
+
};
|
|
357
384
|
|
|
358
|
-
const translateViewport = translation => {
|
|
359
|
-
|
|
385
|
+
const translateViewport = (translation) => {
|
|
386
|
+
hasUpdated = true;
|
|
360
387
|
_tempEye.copy(this.cameraObject.position).add(translation);
|
|
361
388
|
if (checkTravelDistance()) {
|
|
362
389
|
this.cameraObject.target.add(translation);
|
|
363
390
|
this.cameraObject.position.add(translation);
|
|
364
391
|
this.updateDirectionalLight();
|
|
365
392
|
}
|
|
366
|
-
}
|
|
393
|
+
};
|
|
367
394
|
|
|
368
|
-
|
|
395
|
+
const onDocumentMouseDown = (event) => {
|
|
369
396
|
updateRect(false);
|
|
370
397
|
// Check if mouse event hapens inside the minimap
|
|
371
398
|
let minimapCoordinates = undefined;
|
|
372
399
|
if (currentMode === MODE.DEFAULT)
|
|
373
|
-
minimapCoordinates = this.scene.getNormalisedMinimapCoordinates(
|
|
374
|
-
this.renderer, event);
|
|
400
|
+
minimapCoordinates = this.scene.getNormalisedMinimapCoordinates(this.renderer, event);
|
|
375
401
|
if (!minimapCoordinates) {
|
|
376
402
|
if (event.button == 0) {
|
|
377
|
-
if (event.ctrlKey)
|
|
378
|
-
|
|
379
|
-
else
|
|
380
|
-
this._state = CLICK_ACTION.SECONDARY;
|
|
381
|
-
else
|
|
382
|
-
this._state = CLICK_ACTION.MAIN;
|
|
403
|
+
if (event.ctrlKey) this._state = CLICK_ACTION.AUXILIARY;
|
|
404
|
+
else if (event.shiftKey) this._state = CLICK_ACTION.SECONDARY;
|
|
405
|
+
else this._state = CLICK_ACTION.MAIN;
|
|
383
406
|
} else if (event.button == 1) {
|
|
384
407
|
event.preventDefault();
|
|
385
408
|
this._state = CLICK_ACTION.AUXILIARY;
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
409
|
+
} else if (event.button == 2) {
|
|
410
|
+
this._state = CLICK_ACTION.SECONDARY;
|
|
411
|
+
}
|
|
390
412
|
this.pointer_x = event.clientX - rect.left;
|
|
391
413
|
this.pointer_y = event.clientY - rect.top;
|
|
392
414
|
this.pointer_x_start = this.pointer_x;
|
|
393
415
|
this.pointer_y_start = this.pointer_y;
|
|
394
416
|
this.previous_pointer_x = this.pointer_x;
|
|
395
|
-
this.previous_pointer_y= this.pointer_y;
|
|
417
|
+
this.previous_pointer_y = this.pointer_y;
|
|
396
418
|
} else {
|
|
397
419
|
currentMode = MODE.MINIMAP;
|
|
398
420
|
let translation = this.scene.getMinimapDiffFromNormalised(
|
|
399
|
-
minimapCoordinates.x,
|
|
421
|
+
minimapCoordinates.x,
|
|
422
|
+
minimapCoordinates.y,
|
|
423
|
+
);
|
|
400
424
|
translateViewport(translation);
|
|
401
425
|
}
|
|
402
|
-
}
|
|
426
|
+
};
|
|
403
427
|
|
|
404
|
-
|
|
428
|
+
const onDocumentMouseMove = (event) => {
|
|
405
429
|
updateRect(false);
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
430
|
+
if (rect) {
|
|
431
|
+
this.pointer_x = event.clientX - rect.left;
|
|
432
|
+
this.pointer_y = event.clientY - rect.top;
|
|
433
|
+
if (currentMode === MODE.MINIMAP) {
|
|
434
|
+
let minimapCoordinates = this.scene.getNormalisedMinimapCoordinates(this.renderer, event);
|
|
435
|
+
if (minimapCoordinates) {
|
|
436
|
+
let translation = this.scene.getMinimapDiffFromNormalised(
|
|
437
|
+
minimapCoordinates.x,
|
|
438
|
+
minimapCoordinates.y,
|
|
439
|
+
);
|
|
440
|
+
translateViewport(translation);
|
|
441
|
+
}
|
|
442
|
+
} else {
|
|
443
|
+
if (this._state === STATE.NONE && zincRayCaster !== undefined) {
|
|
444
|
+
zincRayCaster.move(this, event.clientX, event.clientY, this.renderer);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
const onDocumentMouseUp = (event) => {
|
|
425
451
|
this._state = STATE.NONE;
|
|
426
|
-
if (currentMode == MODE.MINIMAP)
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
452
|
+
if (currentMode == MODE.MINIMAP) currentMode = MODE.DEFAULT;
|
|
453
|
+
if (zincRayCaster !== undefined) {
|
|
454
|
+
if (
|
|
455
|
+
this.pointer_x_start == event.clientX - rect.left &&
|
|
456
|
+
this.pointer_y_start == event.clientY - rect.top
|
|
457
|
+
) {
|
|
458
|
+
zincRayCaster.pick(this, event.clientX, event.clientY, this.renderer);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
const onDocumentMouseLeave = (event) => {
|
|
464
|
+
this._state = STATE.NONE;
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
const onDocumentTouchStart = (event) => {
|
|
440
468
|
updateRect(false);
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
469
|
+
const len = event.touches.length;
|
|
470
|
+
if (len == 1) {
|
|
471
|
+
this._state = STATE.TOUCH_ROTATE;
|
|
472
|
+
this.pointer_x = event.touches[0].clientX - rect?.left;
|
|
473
|
+
this.pointer_y = event.touches[0].clientY - rect?.top;
|
|
474
|
+
this.pointer_x_start = this.pointer_x;
|
|
475
|
+
this.pointer_y_start = this.pointer_y;
|
|
476
|
+
this.previous_pointer_x = this.pointer_x;
|
|
477
|
+
this.previous_pointer_y = this.pointer_y;
|
|
478
|
+
} else if (len == 2) {
|
|
479
|
+
this._state = STATE.TOUCH_ZOOM;
|
|
480
|
+
const dx = event.touches[0].clientX - event.touches[1].clientX;
|
|
481
|
+
const dy = event.touches[0].clientY - event.touches[1].clientY;
|
|
482
|
+
this.touchZoomDistanceEnd = this.touchZoomDistanceStart = Math.sqrt(dx * dx + dy * dy);
|
|
483
|
+
} else if (len == 3) {
|
|
484
|
+
this._state = STATE.TOUCH_PAN;
|
|
485
|
+
this.targetTouchId = event.touches[0].identifier;
|
|
486
|
+
this.pointer_x = event.touches[0].clientX - rect?.left;
|
|
487
|
+
this.pointer_y = event.touches[0].clientY - rect?.top;
|
|
488
|
+
this.previous_pointer_x = this.pointer_x;
|
|
489
|
+
this.previous_pointer_y = this.pointer_y;
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
const onDocumentTouchMove = (event) => {
|
|
494
|
+
event.preventDefault();
|
|
495
|
+
event.stopPropagation();
|
|
496
|
+
const len = event.touches.length;
|
|
497
|
+
if (len == 1) {
|
|
498
|
+
this.pointer_x = event.touches[0].clientX - rect.left;
|
|
499
|
+
this.pointer_y = event.touches[0].clientY - rect.top;
|
|
500
|
+
} else if (len == 2) {
|
|
501
|
+
if (this._state === STATE.TOUCH_ZOOM) {
|
|
502
|
+
const dx = event.touches[0].clientX - event.touches[1].clientX;
|
|
503
|
+
const dy = event.touches[0].clientY - event.touches[1].clientY;
|
|
504
|
+
this.touchZoomDistanceEnd = Math.sqrt(dx * dx + dy * dy);
|
|
505
|
+
}
|
|
506
|
+
} else if (len == 3) {
|
|
507
|
+
if (this._state === STATE.TOUCH_PAN) {
|
|
508
|
+
for (let i = 0; i < 3; i++) {
|
|
509
|
+
if (event.touches[i].identifier == this.targetTouchId) {
|
|
510
|
+
this.pointer_x = event.touches[0].clientX - rect.left;
|
|
511
|
+
this.pointer_y = event.touches[0].clientY - rect.top;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
const onDocumentTouchEnd = (event) => {
|
|
519
|
+
const previousState = this._state;
|
|
520
|
+
this.touchZoomDistanceStart = this.touchZoomDistanceEnd = 0;
|
|
521
|
+
this.targetTouchId = -1;
|
|
522
|
+
this._state = STATE.NONE;
|
|
523
|
+
//A single finger tap, the lifted touch is in changedTouches
|
|
524
|
+
if (
|
|
525
|
+
previousState === STATE.TOUCH_ROTATE &&
|
|
526
|
+
event.touches.length === 0 &&
|
|
527
|
+
event.changedTouches &&
|
|
528
|
+
event.changedTouches.length === 1 &&
|
|
529
|
+
rect
|
|
530
|
+
) {
|
|
531
|
+
if (zincRayCaster !== undefined) {
|
|
532
|
+
const touch = event.changedTouches[0];
|
|
533
|
+
if (
|
|
534
|
+
this.pointer_x_start == touch.clientX - rect.left &&
|
|
535
|
+
this.pointer_y_start == touch.clientY - rect.top
|
|
536
|
+
) {
|
|
537
|
+
zincRayCaster.pick(this, touch.clientX, touch.clientY, this.renderer);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
};
|
|
506
542
|
|
|
507
543
|
const onDocumentEnter = () => {
|
|
508
|
-
|
|
509
|
-
|
|
544
|
+
updateRect(true);
|
|
545
|
+
};
|
|
510
546
|
|
|
511
|
-
const updateRect = forced => {
|
|
547
|
+
const updateRect = (forced) => {
|
|
512
548
|
//Use intersectionObserver to reset the rect for ray tracing.
|
|
513
549
|
if (forced || rect === undefined) {
|
|
514
550
|
const observer = new IntersectionObserver((entries) => {
|
|
@@ -520,146 +556,146 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
520
556
|
|
|
521
557
|
observer.observe(this.domElement);
|
|
522
558
|
}
|
|
523
|
-
}
|
|
559
|
+
};
|
|
524
560
|
|
|
525
|
-
|
|
561
|
+
const onDocumentWheelEvent = (event) => {
|
|
526
562
|
updateRect(false);
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
const distance = this.cameraObject.position.distanceTo(this.cameraObject.target);
|
|
605
|
-
let fact = 0.0;
|
|
606
|
-
if ((this.cameraObject.far > this.cameraObject.near) && (distance >= this.cameraObject.near) &&
|
|
607
|
-
(distance <= this.cameraObject.far))
|
|
608
|
-
{
|
|
609
|
-
fact = (distance-this.cameraObject.near)/(this.cameraObject.far-this.cameraObject.near);
|
|
563
|
+
this._state = STATE.SCROLL;
|
|
564
|
+
let changes = 0;
|
|
565
|
+
if (event.deltaY > 0) changes = this.zoomRate;
|
|
566
|
+
else if (event.deltaY < 0) changes = this.zoomRate * -1;
|
|
567
|
+
zoomSize = zoomSize + changes;
|
|
568
|
+
event.preventDefault();
|
|
569
|
+
event.stopImmediatePropagation();
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
const onDocumentKeydownEvent = (event) => {
|
|
573
|
+
updateRect(false);
|
|
574
|
+
let changes = 0;
|
|
575
|
+
if (
|
|
576
|
+
event.keyCode === KEYBOARD.EQUAL ||
|
|
577
|
+
event.keyCode === KEYBOARD.MINUS ||
|
|
578
|
+
event.keyCode === KEYBOARD.NUMPADADD ||
|
|
579
|
+
event.keyCode === KEYBOARD.NUMPADSUBTRACT
|
|
580
|
+
) {
|
|
581
|
+
this._state = STATE.KEYBOARD_ZOOM;
|
|
582
|
+
let unit = 1;
|
|
583
|
+
if (event.shiftKey) {
|
|
584
|
+
unit = unit * 2;
|
|
585
|
+
}
|
|
586
|
+
if (event.keyCode === KEYBOARD.EQUAL || event.keyCode === KEYBOARD.NUMPADADD) {
|
|
587
|
+
changes = this.zoomRate * unit * -1;
|
|
588
|
+
} else if (event.keyCode === KEYBOARD.MINUS || event.keyCode === KEYBOARD.NUMPADSUBTRACT) {
|
|
589
|
+
changes = this.zoomRate * unit;
|
|
590
|
+
}
|
|
591
|
+
zoomSize = zoomSize + changes;
|
|
592
|
+
} else if (
|
|
593
|
+
event.keyCode === KEYBOARD.ARROWLEFT ||
|
|
594
|
+
event.keyCode === KEYBOARD.ARROWUP ||
|
|
595
|
+
event.keyCode === KEYBOARD.ARROWRIGHT ||
|
|
596
|
+
event.keyCode === KEYBOARD.ARROWDOWN
|
|
597
|
+
) {
|
|
598
|
+
if (event.shiftKey) {
|
|
599
|
+
this._state = STATE.KEYBOARD_ROTATE;
|
|
600
|
+
this.pointer_x_start = this.pointer_x;
|
|
601
|
+
this.pointer_y_start = this.pointer_y;
|
|
602
|
+
changes = this.rotateRate;
|
|
603
|
+
} else {
|
|
604
|
+
this._state = STATE.KEYBOARD_PAN;
|
|
605
|
+
changes = this.panRate;
|
|
606
|
+
}
|
|
607
|
+
this.previous_pointer_x = this.pointer_x;
|
|
608
|
+
this.previous_pointer_y = this.pointer_y;
|
|
609
|
+
if (event.keyCode === KEYBOARD.ARROWLEFT) {
|
|
610
|
+
this.pointer_x = this.pointer_x - changes;
|
|
611
|
+
} else if (event.keyCode === KEYBOARD.ARROWUP) {
|
|
612
|
+
this.pointer_y = this.pointer_y - changes;
|
|
613
|
+
} else if (event.keyCode === KEYBOARD.ARROWRIGHT) {
|
|
614
|
+
this.pointer_x = this.pointer_x + changes;
|
|
615
|
+
} else if (event.keyCode === KEYBOARD.ARROWDOWN) {
|
|
616
|
+
this.pointer_y = this.pointer_y + changes;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
if (Object.values(KEYBOARD).includes(event.keyCode)) {
|
|
620
|
+
event.preventDefault();
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
const onDocumentKeyupEvent = (event) => {
|
|
625
|
+
this._state = STATE.NONE;
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
const translate = () => {
|
|
629
|
+
if (typeof this.cameraObject !== 'undefined') {
|
|
630
|
+
const height = rect.height;
|
|
631
|
+
const distance = this.cameraObject.position.distanceTo(this.cameraObject.target);
|
|
632
|
+
let fact = 0.0;
|
|
633
|
+
if (
|
|
634
|
+
this.cameraObject.far > this.cameraObject.near &&
|
|
635
|
+
distance >= this.cameraObject.near &&
|
|
636
|
+
distance <= this.cameraObject.far
|
|
637
|
+
) {
|
|
638
|
+
fact =
|
|
639
|
+
(distance - this.cameraObject.near) / (this.cameraObject.far - this.cameraObject.near);
|
|
610
640
|
}
|
|
611
641
|
//_b == old_near, _c = old_far, _new_b = new_near, _new_c = new_far
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
642
|
+
_b.set(this.previous_pointer_x, height - this.previous_pointer_y, 0.0);
|
|
643
|
+
_c.set(this.previous_pointer_x, height - this.previous_pointer_y, 1.0);
|
|
644
|
+
_new_b.set(this.pointer_x, height - this.pointer_y, 0.0);
|
|
645
|
+
_new_c.set(this.pointer_x, height - this.pointer_y, 1.0);
|
|
646
|
+
_b.unproject(this.cameraObject);
|
|
647
|
+
_c.unproject(this.cameraObject);
|
|
648
|
+
_new_b.unproject(this.cameraObject);
|
|
649
|
+
_new_c.unproject(this.cameraObject);
|
|
620
650
|
const translate_rate = -0.002;
|
|
621
|
-
_new_b.sub(_b).multiplyScalar(1.0-fact);
|
|
651
|
+
_new_b.sub(_b).multiplyScalar(1.0 - fact);
|
|
622
652
|
_new_c.sub(_c).multiplyScalar(fact);
|
|
623
653
|
_new_b.add(_new_c).multiplyScalar(translate_rate);
|
|
624
654
|
translateViewport(_new_b);
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
655
|
+
}
|
|
656
|
+
this.previous_pointer_x = this.pointer_x;
|
|
657
|
+
this.previous_pointer_y = this.pointer_y;
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
this.getVectorsFromRotateAboutLookAtPoints = (axis, angle) => {
|
|
661
|
+
axis.normalize();
|
|
662
|
+
_v.copy(this.cameraObject.position).sub(this.cameraObject.target);
|
|
663
|
+
_rel_eye.copy(_v);
|
|
664
|
+
_v.normalize();
|
|
665
|
+
if (0.8 < Math.abs(_v.dot(axis))) {
|
|
666
|
+
_v.copy(this.cameraObject.up);
|
|
667
|
+
}
|
|
668
|
+
_b.crossVectors(axis, _v).normalize();
|
|
669
|
+
_c.crossVectors(axis, _b);
|
|
670
|
+
const rel_eyea = axis.dot(_rel_eye);
|
|
671
|
+
const rel_eyeb = _b.dot(_rel_eye);
|
|
672
|
+
const rel_eyec = _c.dot(_rel_eye);
|
|
673
|
+
const upa = axis.dot(this.cameraObject.up);
|
|
674
|
+
const upb = _b.dot(this.cameraObject.up);
|
|
675
|
+
const upc = _c.dot(this.cameraObject.up);
|
|
676
|
+
const cos_angle = Math.cos(angle);
|
|
677
|
+
const sin_angle = Math.sin(angle);
|
|
678
|
+
_new_b.set(
|
|
679
|
+
cos_angle * _b.x + sin_angle * _c.x,
|
|
680
|
+
cos_angle * _b.y + sin_angle * _c.y,
|
|
681
|
+
cos_angle * _b.z + sin_angle * _c.z,
|
|
682
|
+
);
|
|
683
|
+
_new_c.set(
|
|
684
|
+
cos_angle * _c.x - sin_angle * _b.x,
|
|
685
|
+
cos_angle * _c.y - sin_angle * _b.y,
|
|
686
|
+
cos_angle * _c.z - sin_angle * _b.z,
|
|
687
|
+
);
|
|
688
|
+
_v.copy(this.cameraObject.target);
|
|
689
|
+
_v.x = _v.x + axis.x * rel_eyea + _new_b.x * rel_eyeb + _new_c.x * rel_eyec;
|
|
690
|
+
_v.y = _v.y + axis.y * rel_eyea + _new_b.y * rel_eyeb + _new_c.y * rel_eyec;
|
|
691
|
+
_v.z = _v.z + axis.z * rel_eyea + _new_b.z * rel_eyeb + _new_c.z * rel_eyec;
|
|
692
|
+
_a.set(
|
|
693
|
+
axis.x * upa + _new_b.x * upb + _new_c.x * upc,
|
|
694
|
+
axis.y * upa + _new_b.y * upb + _new_c.y * upc,
|
|
695
|
+
axis.z * upa + _new_b.z * upb + _new_c.z * upc,
|
|
696
|
+
);
|
|
697
|
+
return { position: _v, up: _a };
|
|
698
|
+
};
|
|
663
699
|
|
|
664
700
|
/**
|
|
665
701
|
* Rotate around the axis with the amount specified by angle.
|
|
@@ -667,188 +703,196 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
667
703
|
* @param {THREE.Vector3} axis - The rotational axis.
|
|
668
704
|
* @param {Number} Angle - Specify how much the camera shoudl rotate by.
|
|
669
705
|
*/
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if (rotateMode === ROTATE_DIRECTION.FREE ||
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
if (
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
const tangent_dist = Math.sqrt(delta_x*delta_x + delta_y*delta_y);
|
|
695
|
-
if (tangent_dist > 0)
|
|
696
|
-
{
|
|
697
|
-
const dx=-delta_y*1.0/tangent_dist;
|
|
698
|
-
const dy=delta_x*1.0/tangent_dist;
|
|
706
|
+
this.rotateAboutLookAtpoint = (axis, angle) => {
|
|
707
|
+
hasUpdated = true;
|
|
708
|
+
const returned_values = this.getVectorsFromRotateAboutLookAtPoints(axis, angle);
|
|
709
|
+
this.cameraObject.position.copy(returned_values.position);
|
|
710
|
+
this.updateDirectionalLight();
|
|
711
|
+
this.cameraObject.up.copy(returned_values.up);
|
|
712
|
+
};
|
|
713
|
+
|
|
714
|
+
const tumble = () => {
|
|
715
|
+
if (typeof this.cameraObject !== 'undefined') {
|
|
716
|
+
const width = rect?.width;
|
|
717
|
+
const height = rect?.height;
|
|
718
|
+
if (0 < width && 0 < height) {
|
|
719
|
+
const radius = 0.25 * (width + height);
|
|
720
|
+
let delta_x = 0;
|
|
721
|
+
let delta_y = 0;
|
|
722
|
+
if (rotateMode === ROTATE_DIRECTION.FREE || rotateMode === ROTATE_DIRECTION.HORIZONTAL)
|
|
723
|
+
delta_x = this.pointer_x - this.previous_pointer_x;
|
|
724
|
+
if (rotateMode === ROTATE_DIRECTION.FREE || rotateMode === ROTATE_DIRECTION.VERTICAL)
|
|
725
|
+
delta_y = this.previous_pointer_y - this.pointer_y;
|
|
726
|
+
const tangent_dist = Math.sqrt(delta_x * delta_x + delta_y * delta_y);
|
|
727
|
+
if (tangent_dist > 0) {
|
|
728
|
+
const dx = (-delta_y * 1.0) / tangent_dist;
|
|
729
|
+
const dy = (delta_x * 1.0) / tangent_dist;
|
|
699
730
|
let d = 0;
|
|
700
731
|
// Do not allow rotation on other direction around the origin if rotateMode is not free
|
|
701
732
|
if (rotateMode === ROTATE_DIRECTION.FREE) {
|
|
702
|
-
let d=
|
|
703
|
-
|
|
733
|
+
let d =
|
|
734
|
+
dx * (this.pointer_x - 0.5 * (width - 1)) +
|
|
735
|
+
dy * (0.5 * (height - 1) - this.pointer_y);
|
|
736
|
+
if (d > radius) {
|
|
704
737
|
d = radius;
|
|
705
|
-
}
|
|
706
|
-
else {
|
|
738
|
+
} else {
|
|
707
739
|
if (d < -radius) {
|
|
708
740
|
d = -radius;
|
|
709
741
|
}
|
|
710
742
|
}
|
|
711
743
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
744
|
+
const phi = Math.acos(d / radius) - 0.5 * Math.PI;
|
|
745
|
+
const angle = (this.tumble_rate * tangent_dist) / radius;
|
|
746
|
+
_a.copy(this.cameraObject.position).sub(this.cameraObject.target).normalize();
|
|
747
|
+
_b.copy(this.cameraObject.up).normalize();
|
|
716
748
|
_c.copy(_b).cross(_a).normalize().multiplyScalar(dx);
|
|
717
749
|
_b.multiplyScalar(dy);
|
|
718
750
|
_axis.addVectors(_c, _b).multiplyScalar(Math.cos(phi));
|
|
719
751
|
_a.multiplyScalar(Math.sin(phi));
|
|
720
752
|
_axis.add(_a);
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
this.changeZoomByScrollRateUnit = unit => {
|
|
753
|
+
this.rotateAboutLookAtpoint(_axis, -angle);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
this.previous_pointer_x = this.pointer_x;
|
|
758
|
+
this.previous_pointer_y = this.pointer_y;
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
const calculateZoomDelta = () => {
|
|
762
|
+
let delta = 0;
|
|
763
|
+
if (this._state === STATE.ZOOM) {
|
|
764
|
+
delta = this.previous_pointer_y - this.pointer_y;
|
|
765
|
+
} else if (this._state === STATE.SCROLL || this._state === STATE.KEYBOARD_ZOOM) {
|
|
766
|
+
delta = zoomSize;
|
|
767
|
+
} else {
|
|
768
|
+
delta = -1.0 * (this.touchZoomDistanceEnd - this.touchZoomDistanceStart);
|
|
769
|
+
this.touchZoomDistanceStart = this.touchZoomDistanceEnd;
|
|
770
|
+
}
|
|
771
|
+
return delta;
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
this.changeZoomByScrollRateUnit = (unit) => {
|
|
744
775
|
const delta_y = unit * this.zoomRate;
|
|
745
776
|
this.changeZoomByValue(delta_y);
|
|
746
|
-
}
|
|
777
|
+
};
|
|
747
778
|
|
|
748
|
-
this.changeZoomByValue = delta_y => {
|
|
749
|
-
|
|
750
|
-
{
|
|
779
|
+
this.changeZoomByValue = (delta_y) => {
|
|
780
|
+
if (typeof this.cameraObject !== 'undefined') {
|
|
751
781
|
const height = rect.height;
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
782
|
+
const a = _v.copy(this.cameraObject.position);
|
|
783
|
+
a.sub(this.cameraObject.target);
|
|
784
|
+
const dist = a.length();
|
|
785
|
+
const dy = (1.5 * delta_y) / height;
|
|
756
786
|
const travalDist = dist * dy;
|
|
757
|
-
|
|
758
|
-
|
|
787
|
+
if (dist + travalDist > 0.01) {
|
|
788
|
+
a.normalize();
|
|
759
789
|
_tempEye.copy(this.cameraObject.position);
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
790
|
+
_tempEye.x += a.x * travalDist;
|
|
791
|
+
_tempEye.y += a.y * travalDist;
|
|
792
|
+
_tempEye.z += a.z * travalDist;
|
|
763
793
|
if (checkTravelDistance()) {
|
|
764
794
|
this.cameraObject.position.copy(_tempEye);
|
|
765
795
|
this.updateDirectionalLight();
|
|
766
796
|
updateNearAndFarPlane(travalDist);
|
|
767
797
|
hasUpdated = true;
|
|
768
798
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
};
|
|
772
802
|
|
|
773
|
-
|
|
803
|
+
const flyZoom = () => {
|
|
774
804
|
const delta_y = calculateZoomDelta();
|
|
775
805
|
this.changeZoomByValue(delta_y);
|
|
776
806
|
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
807
|
+
if (this._state === STATE.ZOOM) {
|
|
808
|
+
this.previous_pointer_x = this.pointer_x;
|
|
809
|
+
this.previous_pointer_y = this.pointer_y;
|
|
810
|
+
}
|
|
811
|
+
if (this._state === STATE.SCROLL || this._state === STATE.KEYBOARD_ZOOM) {
|
|
812
|
+
zoomSize = 0;
|
|
783
813
|
this._state = STATE.NONE;
|
|
784
|
-
|
|
785
|
-
|
|
814
|
+
}
|
|
815
|
+
};
|
|
786
816
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
817
|
+
this.setDirectionalLight = (directionalLightIn) => {
|
|
818
|
+
this.directionalLight = directionalLightIn;
|
|
819
|
+
};
|
|
790
820
|
|
|
791
821
|
/**
|
|
792
822
|
* Force an update to the position of the directional light.
|
|
793
823
|
*/
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
824
|
+
this.updateDirectionalLight = () => {
|
|
825
|
+
hasUpdated = true;
|
|
826
|
+
if (this.directionalLight != 0) {
|
|
827
|
+
this.directionalLight.position.set(
|
|
828
|
+
this.cameraObject.position.x,
|
|
829
|
+
this.cameraObject.position.y,
|
|
830
|
+
this.cameraObject.position.z,
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
|
|
835
|
+
/**
|
|
804
836
|
* Enable the camera control.
|
|
805
837
|
*/
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
838
|
+
this.enable = function () {
|
|
839
|
+
enabled = true;
|
|
840
|
+
if (this.domElement && this.domElement.addEventListener) {
|
|
841
|
+
setCanvasTabindex(this.domElement, 0);
|
|
842
|
+
this.domElement.addEventListener('mousedown', onDocumentMouseDown, false);
|
|
843
|
+
this.domElement.addEventListener('mousemove', onDocumentMouseMove, false);
|
|
844
|
+
this.domElement.addEventListener('mouseup', onDocumentMouseUp, false);
|
|
845
|
+
this.domElement.addEventListener('mouseleave', onDocumentMouseLeave, false);
|
|
846
|
+
this.domElement.addEventListener('touchstart', onDocumentTouchStart, false);
|
|
847
|
+
this.domElement.addEventListener('touchmove', onDocumentTouchMove, false);
|
|
848
|
+
this.domElement.addEventListener('touchend', onDocumentTouchEnd, false);
|
|
849
|
+
this.domElement.addEventListener('wheel', onDocumentWheelEvent, false);
|
|
850
|
+
this.domElement.addEventListener('mouseenter', onDocumentEnter, false);
|
|
851
|
+
this.domElement.addEventListener(
|
|
852
|
+
'contextmenu',
|
|
853
|
+
(event) => {
|
|
854
|
+
event.preventDefault();
|
|
855
|
+
},
|
|
856
|
+
false,
|
|
857
|
+
);
|
|
858
|
+
this.domElement.addEventListener('keydown', onDocumentKeydownEvent, false);
|
|
859
|
+
this.domElement.addEventListener('keyup', onDocumentKeyupEvent, false);
|
|
860
|
+
}
|
|
861
|
+
};
|
|
824
862
|
|
|
825
863
|
/**
|
|
826
864
|
* Disable the camera control.
|
|
827
865
|
*/
|
|
828
|
-
|
|
829
|
-
|
|
866
|
+
this.disable = function () {
|
|
867
|
+
enabled = false;
|
|
830
868
|
this._state = STATE.NONE;
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
869
|
+
if (this.domElement && this.domElement.removeEventListener) {
|
|
870
|
+
this.domElement.removeEventListener('mousedown', onDocumentMouseDown, false);
|
|
871
|
+
this.domElement.removeEventListener('mousemove', onDocumentMouseMove, false);
|
|
872
|
+
this.domElement.removeEventListener('mouseup', onDocumentMouseUp, false);
|
|
873
|
+
this.domElement.removeEventListener('mouseleave', onDocumentMouseLeave, false);
|
|
874
|
+
this.domElement.removeEventListener('touchstart', onDocumentTouchStart, false);
|
|
875
|
+
this.domElement.removeEventListener('touchmove', onDocumentTouchMove, false);
|
|
876
|
+
this.domElement.removeEventListener('touchend', onDocumentTouchEnd, false);
|
|
877
|
+
this.domElement.removeEventListener('wheel', onDocumentWheelEvent, false);
|
|
878
|
+
this.domElement.removeEventListener('mouseenter', onDocumentEnter, false);
|
|
879
|
+
this.domElement.removeEventListener(
|
|
880
|
+
'contextmenu',
|
|
881
|
+
(event) => {
|
|
882
|
+
event.preventDefault();
|
|
883
|
+
},
|
|
884
|
+
false,
|
|
885
|
+
);
|
|
886
|
+
this.domElement.removeEventListener('keydown', onDocumentKeydownEvent, false);
|
|
887
|
+
this.domElement.removeEventListener('keyup', onDocumentKeyupEvent, false);
|
|
888
|
+
setCanvasTabindex(this.domElement, -1);
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
|
|
892
|
+
this.loadPath = (pathData) => {
|
|
893
|
+
cameraPath = pathData.CameraPath;
|
|
894
|
+
numberOfCameraPoint = pathData.NumberOfPoints;
|
|
895
|
+
};
|
|
852
896
|
|
|
853
897
|
/**
|
|
854
898
|
* This is an experimental feature. It loads a path - point to point which
|
|
@@ -857,39 +901,36 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
857
901
|
* @param {String} path_url - The path.
|
|
858
902
|
* @param {requestCallback} finishCallback - The callback once the path is load.
|
|
859
903
|
*/
|
|
860
|
-
|
|
904
|
+
this.loadPathURL = (path_url, finishCallback) => {
|
|
861
905
|
const requestURL = path_url;
|
|
862
906
|
fetch(requestURL)
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
}
|
|
907
|
+
.then((response) => {
|
|
908
|
+
if (!response.ok) {
|
|
909
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
910
|
+
}
|
|
911
|
+
return response.json();
|
|
912
|
+
})
|
|
913
|
+
.then((pathData) => {
|
|
914
|
+
this.loadPath(pathData);
|
|
915
|
+
if (finishCallback !== undefined && typeof finishCallback === 'function') {
|
|
916
|
+
finishCallback();
|
|
917
|
+
}
|
|
918
|
+
})
|
|
919
|
+
.catch((error) => {
|
|
920
|
+
console.error(`Failed to load path asset from: ${requestURL}`, error);
|
|
921
|
+
});
|
|
922
|
+
};
|
|
880
923
|
|
|
881
924
|
/**
|
|
882
925
|
* Set the duration for the camera to travel along the path.
|
|
883
926
|
*
|
|
884
927
|
* @param {Number} durationIn - the duration for the path.
|
|
885
928
|
*/
|
|
886
|
-
|
|
929
|
+
this.setPathDuration = (durationIn) => {
|
|
887
930
|
duration = durationIn;
|
|
888
|
-
if (smoothCameraTransitionObject)
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
rotateCameraTransitionObject.setDuration(duration);
|
|
892
|
-
}
|
|
931
|
+
if (smoothCameraTransitionObject) smoothCameraTransitionObject.setDuration(duration);
|
|
932
|
+
if (rotateCameraTransitionObject) rotateCameraTransitionObject.setDuration(duration);
|
|
933
|
+
};
|
|
893
934
|
|
|
894
935
|
/**
|
|
895
936
|
* Get the playRate - this determines how fast it takes to
|
|
@@ -897,9 +938,9 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
897
938
|
*
|
|
898
939
|
* @return {Number}
|
|
899
940
|
*/
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
941
|
+
this.getPlayRate = () => {
|
|
942
|
+
return playRate;
|
|
943
|
+
};
|
|
903
944
|
|
|
904
945
|
/**
|
|
905
946
|
* Set the playRate - this determines how fast it takes to
|
|
@@ -907,9 +948,9 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
907
948
|
*
|
|
908
949
|
* @param {Number} playRateIn - The play rate speed.
|
|
909
950
|
*/
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
951
|
+
this.setPlayRate = (playRateIn) => {
|
|
952
|
+
playRate = playRateIn;
|
|
953
|
+
};
|
|
913
954
|
|
|
914
955
|
/**
|
|
915
956
|
* Update the internal timer by the set amount, this can
|
|
@@ -918,21 +959,20 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
918
959
|
* @param {Number} delta - The amount of time to increment
|
|
919
960
|
* the time by.
|
|
920
961
|
*/
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
};
|
|
962
|
+
const updateTime = (delta) => {
|
|
963
|
+
let targetTime = inbuildTime + delta;
|
|
964
|
+
if (targetTime > duration) targetTime = targetTime - duration;
|
|
965
|
+
inbuildTime = targetTime;
|
|
966
|
+
};
|
|
927
967
|
|
|
928
968
|
/**
|
|
929
969
|
* Get the current inbuild time,
|
|
930
970
|
*
|
|
931
971
|
* @return {Number}
|
|
932
972
|
*/
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
973
|
+
this.getTime = () => {
|
|
974
|
+
return inbuildTime;
|
|
975
|
+
};
|
|
936
976
|
|
|
937
977
|
/**
|
|
938
978
|
* Set the current inbuild time,
|
|
@@ -940,14 +980,11 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
940
980
|
* @param {Number} timeIn - this will be used as the current time,
|
|
941
981
|
* it should be between the range of zero and the set duration.
|
|
942
982
|
*/
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
else
|
|
949
|
-
inbuildTime = timeIn;
|
|
950
|
-
}
|
|
983
|
+
this.setTime = (timeIn) => {
|
|
984
|
+
if (timeIn > duration) inbuildTime = duration;
|
|
985
|
+
else if (timeIn < 0.0) inbuildTime = 0.0;
|
|
986
|
+
else inbuildTime = timeIn;
|
|
987
|
+
};
|
|
951
988
|
|
|
952
989
|
/**
|
|
953
990
|
* Get the number of frame which is determine by number of points
|
|
@@ -955,9 +992,9 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
955
992
|
*
|
|
956
993
|
* @return {Number}
|
|
957
994
|
*/
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
995
|
+
this.getNumberOfTimeFrame = () => {
|
|
996
|
+
return numberOfCameraPoint;
|
|
997
|
+
};
|
|
961
998
|
|
|
962
999
|
/**
|
|
963
1000
|
* Get the current time frame and it will return three values in
|
|
@@ -965,191 +1002,219 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
965
1002
|
*
|
|
966
1003
|
* @return {Array} - bottom frame, top frame and the proportion.
|
|
967
1004
|
*/
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1005
|
+
this.getCurrentTimeFrame = () => {
|
|
1006
|
+
if (numberOfCameraPoint > 2) {
|
|
1007
|
+
const current_time = (inbuildTime / duration) * (numberOfCameraPoint - 1);
|
|
1008
|
+
const bottom_frame = Math.floor(current_time);
|
|
1009
|
+
const proportion = 1 - (current_time - bottom_frame);
|
|
1010
|
+
const top_frame = Math.ceil(current_time);
|
|
1011
|
+
if (bottom_frame == top_frame) {
|
|
1012
|
+
if (bottom_frame == numberOfCameraPoint - 1) {
|
|
1013
|
+
return [bottom_frame - 1, top_frame, 0];
|
|
1014
|
+
} else {
|
|
1015
|
+
return [bottom_frame, top_frame + 1, 1.0];
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
return [bottom_frame, top_frame, proportion];
|
|
1019
|
+
} else if (numberOfCameraPoint == 1) {
|
|
1020
|
+
return [0, 0, 0];
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
return undefined;
|
|
1024
|
+
};
|
|
988
1025
|
|
|
989
1026
|
/**
|
|
990
1027
|
* Set the current time frame.
|
|
991
1028
|
*
|
|
992
1029
|
* @param {Number} targetTimeFrame - bottom frame, top frame and the proportion.
|
|
993
1030
|
*/
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1031
|
+
this.setCurrentTimeFrame = (targetTimeFrame) => {
|
|
1032
|
+
hasUpdated = true;
|
|
1033
|
+
if (numberOfCameraPoint > 2) {
|
|
1034
|
+
inbuildTime = (duration * targetTimeFrame) / (numberOfCameraPoint - 1);
|
|
1035
|
+
if (inbuildTime < 0.0) inbuildTime = 0.0;
|
|
1036
|
+
if (inbuildTime > duration) inbuildTime = duration;
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
1004
1039
|
|
|
1005
1040
|
/**
|
|
1006
1041
|
* Update the progress on the path by the specified amount - delta.
|
|
1007
1042
|
*
|
|
1008
1043
|
* @param {Number} delta - The amount of time to increment
|
|
1009
1044
|
*/
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1045
|
+
const updatePath = (delta) => {
|
|
1046
|
+
if (currentMode === MODE.PATH) {
|
|
1047
|
+
updateTime(delta);
|
|
1048
|
+
if (cameraPath) {
|
|
1049
|
+
const time_frame = this.getCurrentTimeFrame();
|
|
1050
|
+
const bottom_frame = time_frame[0];
|
|
1051
|
+
const top_frame = time_frame[1];
|
|
1052
|
+
const proportion = time_frame[2];
|
|
1053
|
+
const bottom = bottom_frame * 3;
|
|
1054
|
+
const top = top_frame * 3;
|
|
1055
|
+
const x = proportion * cameraPath[bottom] + (1.0 - proportion) * cameraPath[top];
|
|
1056
|
+
const y = proportion * cameraPath[bottom + 1] + (1.0 - proportion) * cameraPath[top + 1];
|
|
1057
|
+
const z = proportion * cameraPath[bottom + 2] + (1.0 - proportion) * cameraPath[top + 2];
|
|
1058
|
+
this.cameraObject.position.set(x, y, z);
|
|
1059
|
+
this.cameraObject.target.set(cameraPath[top], cameraPath[top + 1], cameraPath[top + 2]);
|
|
1060
|
+
if (deviceOrientationControl) this.cameraObject.lookAt(this.cameraObject.target);
|
|
1061
|
+
if (updateLightWithPathFlag) {
|
|
1062
|
+
this.directionalLight.position.set(x, y, z);
|
|
1063
|
+
this.directionalLight.target.position.set(
|
|
1064
|
+
cameraPath[top],
|
|
1065
|
+
cameraPath[top + 1],
|
|
1066
|
+
cameraPath[top + 2],
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1035
1072
|
|
|
1036
1073
|
/**
|
|
1037
1074
|
* Force recalculation of the current path.
|
|
1038
1075
|
*/
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1076
|
+
this.calculatePathNow = () => {
|
|
1077
|
+
hasUpdated = true;
|
|
1078
|
+
updatePath(0.0);
|
|
1079
|
+
};
|
|
1043
1080
|
|
|
1044
1081
|
// handle synchronised control based on information in the idc
|
|
1045
1082
|
const handleSyncControl = () => {
|
|
1046
|
-
if (
|
|
1083
|
+
if (
|
|
1084
|
+
this._state === STATE.ROTATE ||
|
|
1085
|
+
this._state === STATE.TOUCH_ROTATE ||
|
|
1086
|
+
this._state === STATE.KEYBOARD_ROTATE
|
|
1087
|
+
) {
|
|
1047
1088
|
//rotateion does not trigger callback
|
|
1048
1089
|
tumble();
|
|
1049
|
-
} else if (
|
|
1090
|
+
} else if (
|
|
1091
|
+
this._state === STATE.PAN ||
|
|
1092
|
+
this._state === STATE.TOUCH_PAN ||
|
|
1093
|
+
this._state === STATE.KEYBOARD_PAN
|
|
1094
|
+
) {
|
|
1050
1095
|
translate();
|
|
1051
1096
|
ndcControl.triggerCallback();
|
|
1052
|
-
} else if (
|
|
1097
|
+
} else if (
|
|
1098
|
+
this._state === STATE.ZOOM ||
|
|
1099
|
+
this._state === STATE.TOUCH_ZOOM ||
|
|
1100
|
+
this._state === STATE.SCROLL ||
|
|
1101
|
+
this._state === STATE.KEYBOARD_ZOOM
|
|
1102
|
+
) {
|
|
1053
1103
|
ndcControl.zoom(calculateZoomDelta());
|
|
1054
1104
|
this.previous_pointer_x = this.pointer_x;
|
|
1055
1105
|
this.previous_pointer_y = this.pointer_y;
|
|
1056
|
-
if (
|
|
1106
|
+
if (this._state === STATE.SCROLL || this._state === STATE.KEYBOARD_ZOOM) {
|
|
1057
1107
|
this._state = STATE.NONE;
|
|
1058
1108
|
}
|
|
1059
1109
|
zoomSize = 0;
|
|
1060
1110
|
ndcControl.triggerCallback();
|
|
1061
1111
|
}
|
|
1062
|
-
}
|
|
1112
|
+
};
|
|
1063
1113
|
|
|
1064
1114
|
/**
|
|
1065
1115
|
* Update all controls related changes - including calculation of the viewport.
|
|
1066
1116
|
*
|
|
1067
1117
|
* @param {Number} timeChanged - Time eclipse since last called.
|
|
1068
1118
|
*/
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1119
|
+
this.update = (timeChanged) => {
|
|
1120
|
+
const delta = timeChanged * playRate;
|
|
1121
|
+
let controlEnabled = enabled;
|
|
1122
|
+
let updated = true;
|
|
1123
|
+
if (currentMode === MODE.PATH) {
|
|
1124
|
+
updatePath(delta);
|
|
1125
|
+
} else if (currentMode === MODE.SMOOTH_CAMERA_TRANSITION && smoothCameraTransitionObject) {
|
|
1126
|
+
smoothCameraTransitionObject.update(delta);
|
|
1127
|
+
if (smoothCameraTransitionObject.isTransitionCompleted()) {
|
|
1128
|
+
smoothCameraTransitionObject = undefined;
|
|
1129
|
+
currentMode = MODE.DEFAULT;
|
|
1130
|
+
}
|
|
1131
|
+
controlEnabled = false;
|
|
1132
|
+
} else if (currentMode === MODE.ROTATE_TRANSITION && rotateCameraTransitionObject) {
|
|
1133
|
+
rotateCameraTransitionObject.update(delta);
|
|
1134
|
+
if (rotateCameraTransitionObject.isTransitionCompleted()) {
|
|
1135
|
+
rotateCameraTransitionObject = undefined;
|
|
1136
|
+
currentMode = MODE.DEFAULT;
|
|
1137
|
+
}
|
|
1138
|
+
controlEnabled = false;
|
|
1139
|
+
} else if (currentMode === MODE.AUTO_TUMBLE && cameraAutoTumbleObject) {
|
|
1140
|
+
cameraAutoTumbleObject.update(delta);
|
|
1141
|
+
} else if (currentMode === MODE.SYNC_CONTROL && ndcControl) {
|
|
1092
1142
|
handleSyncControl();
|
|
1093
1143
|
controlEnabled = false;
|
|
1094
1144
|
} else {
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1145
|
+
updated = false;
|
|
1146
|
+
}
|
|
1147
|
+
if (controlEnabled) {
|
|
1148
|
+
if (this._state !== STATE.NONE) {
|
|
1149
|
+
updated = true;
|
|
1150
|
+
}
|
|
1151
|
+
if (
|
|
1152
|
+
this._state === STATE.ROTATE ||
|
|
1153
|
+
this._state === STATE.TOUCH_ROTATE ||
|
|
1154
|
+
this._state === STATE.KEYBOARD_ROTATE
|
|
1155
|
+
) {
|
|
1156
|
+
tumble();
|
|
1157
|
+
} else if (
|
|
1158
|
+
this._state === STATE.PAN ||
|
|
1159
|
+
this._state === STATE.TOUCH_PAN ||
|
|
1160
|
+
this._state === STATE.KEYBOARD_PAN
|
|
1161
|
+
) {
|
|
1162
|
+
translate();
|
|
1163
|
+
} else if (
|
|
1164
|
+
this._state === STATE.ZOOM ||
|
|
1165
|
+
this._state === STATE.TOUCH_ZOOM ||
|
|
1166
|
+
this._state === STATE.SCROLL ||
|
|
1167
|
+
this._state === STATE.KEYBOARD_ZOOM
|
|
1168
|
+
) {
|
|
1169
|
+
flyZoom();
|
|
1170
|
+
}
|
|
1171
|
+
if (this._state !== STATE.NONE) {
|
|
1172
|
+
if (
|
|
1173
|
+
currentMode === MODE.AUTO_TUMBLE &&
|
|
1174
|
+
cameraAutoTumbleObject &&
|
|
1175
|
+
cameraAutoTumbleObject.stopOnCameraInput
|
|
1176
|
+
) {
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
if (this._state === STATE.SCROLL) this._state = STATE.NONE;
|
|
1180
|
+
}
|
|
1181
|
+
if (deviceOrientationControl) {
|
|
1182
|
+
updated = true;
|
|
1183
|
+
deviceOrientationControl.update();
|
|
1184
|
+
//this.directionalLight.target.position.set(this.cameraObject.target.x,
|
|
1185
|
+
// this.cameraObject.target.y, this.cameraObject.target.z);
|
|
1186
|
+
} else {
|
|
1187
|
+
this.cameraObject.lookAt(this.cameraObject.target);
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
updated = updated || hasUpdated;
|
|
1191
|
+
hasUpdated = false;
|
|
1192
|
+
|
|
1193
|
+
return updated;
|
|
1194
|
+
};
|
|
1130
1195
|
|
|
1131
1196
|
/**
|
|
1132
1197
|
* Switch to path mode and begin traveling through the camera path.
|
|
1133
1198
|
*/
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1199
|
+
this.playPath = () => {
|
|
1200
|
+
currentMode = MODE.PATH;
|
|
1201
|
+
};
|
|
1137
1202
|
|
|
1138
1203
|
/**
|
|
1139
1204
|
* Stop playing path and switch back to normal control.
|
|
1140
1205
|
*/
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1206
|
+
this.stopPath = () => {
|
|
1207
|
+
currentMode = MODE.DEFAULT;
|
|
1208
|
+
};
|
|
1144
1209
|
|
|
1145
1210
|
/**
|
|
1146
1211
|
* Check rather the control is currently in path mode.
|
|
1147
1212
|
*
|
|
1148
1213
|
* @return {Boolean}
|
|
1149
1214
|
*/
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1215
|
+
this.isPlayingPath = () => {
|
|
1216
|
+
return currentMode === MODE.PATH;
|
|
1217
|
+
};
|
|
1153
1218
|
|
|
1154
1219
|
/**
|
|
1155
1220
|
* Enable directional light update as the camera
|
|
@@ -1157,79 +1222,91 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1157
1222
|
*
|
|
1158
1223
|
* @param {Boolean} flag
|
|
1159
1224
|
*/
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1225
|
+
this.enableDirectionalLightUpdateWithPath = (flag) => {
|
|
1226
|
+
updateLightWithPathFlag = flag;
|
|
1227
|
+
};
|
|
1163
1228
|
|
|
1164
1229
|
/**
|
|
1165
1230
|
* Enable rotation using the devices's accelerometer.
|
|
1166
1231
|
*/
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1232
|
+
this.enableDeviceOrientation = () => {
|
|
1233
|
+
if (!deviceOrientationControl)
|
|
1234
|
+
deviceOrientationControl = new ModifiedDeviceOrientationControls(this.cameraObject);
|
|
1235
|
+
};
|
|
1171
1236
|
|
|
1172
1237
|
/**
|
|
1173
1238
|
* Disable rotation using the devices's accelerometer.
|
|
1174
1239
|
*/
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1240
|
+
this.disableDeviceOrientation = () => {
|
|
1241
|
+
if (deviceOrientationControl) {
|
|
1242
|
+
deviceOrientationControl.dispose();
|
|
1243
|
+
deviceOrientationControl = undefined;
|
|
1244
|
+
}
|
|
1245
|
+
};
|
|
1181
1246
|
|
|
1182
1247
|
/**
|
|
1183
1248
|
* Check rather device orientation based on accelerometer is on.
|
|
1184
1249
|
*/
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1250
|
+
this.isDeviceOrientationEnabled = () => {
|
|
1251
|
+
if (deviceOrientationControl) {
|
|
1252
|
+
return true;
|
|
1253
|
+
}
|
|
1254
|
+
return false;
|
|
1255
|
+
};
|
|
1191
1256
|
|
|
1192
1257
|
/**
|
|
1193
1258
|
* Reset the viewport settings to the one provided by default viewport.
|
|
1194
1259
|
*/
|
|
1195
|
-
|
|
1196
|
-
|
|
1260
|
+
this.resetView = () => {
|
|
1261
|
+
hasUpdated = true;
|
|
1197
1262
|
const viewport = viewports[defaultViewport];
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
viewport.eyePosition[
|
|
1202
|
-
|
|
1203
|
-
viewport.
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1263
|
+
this.cameraObject.near = viewport.nearPlane;
|
|
1264
|
+
this.cameraObject.far = viewport.farPlane;
|
|
1265
|
+
this.cameraObject.position.set(
|
|
1266
|
+
viewport.eyePosition[0],
|
|
1267
|
+
viewport.eyePosition[1],
|
|
1268
|
+
viewport.eyePosition[2],
|
|
1269
|
+
);
|
|
1270
|
+
this.cameraObject.target.set(
|
|
1271
|
+
viewport.targetPosition[0],
|
|
1272
|
+
viewport.targetPosition[1],
|
|
1273
|
+
viewport.targetPosition[2],
|
|
1274
|
+
);
|
|
1275
|
+
this.cameraObject.up.set(viewport.upVector[0], viewport.upVector[1], viewport.upVector[2]);
|
|
1276
|
+
this.cameraObject.updateProjectionMatrix();
|
|
1277
|
+
this.updateDirectionalLight();
|
|
1278
|
+
};
|
|
1209
1279
|
|
|
1210
1280
|
/**
|
|
1211
1281
|
* Set the current camera settings with the provided viewport.
|
|
1212
1282
|
*
|
|
1213
1283
|
* @param {Viewport} newViewport - viewport settings.
|
|
1214
1284
|
*/
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1285
|
+
this.setCurrentCameraSettings = (newViewport) => {
|
|
1286
|
+
if (newViewport.nearPlane) this.cameraObject.near = newViewport.nearPlane;
|
|
1287
|
+
if (newViewport.farPlane) this.cameraObject.far = newViewport.farPlane;
|
|
1288
|
+
if (newViewport.eyePosition)
|
|
1289
|
+
this.cameraObject.position.set(
|
|
1290
|
+
newViewport.eyePosition[0],
|
|
1291
|
+
newViewport.eyePosition[1],
|
|
1292
|
+
newViewport.eyePosition[2],
|
|
1293
|
+
);
|
|
1294
|
+
if (newViewport.targetPosition)
|
|
1295
|
+
this.cameraObject.target.set(
|
|
1296
|
+
newViewport.targetPosition[0],
|
|
1297
|
+
newViewport.targetPosition[1],
|
|
1298
|
+
newViewport.targetPosition[2],
|
|
1299
|
+
);
|
|
1300
|
+
if (newViewport.upVector)
|
|
1301
|
+
this.cameraObject.up.set(
|
|
1302
|
+
newViewport.upVector[0],
|
|
1303
|
+
newViewport.upVector[1],
|
|
1304
|
+
newViewport.upVector[2],
|
|
1305
|
+
);
|
|
1306
|
+
this.cameraObject.updateProjectionMatrix();
|
|
1307
|
+
this.updateDirectionalLight();
|
|
1308
|
+
hasUpdated = true;
|
|
1309
|
+
};
|
|
1233
1310
|
|
|
1234
1311
|
/**
|
|
1235
1312
|
* Get the viewport based on centre, radius, view_angle and clip distance.
|
|
@@ -1243,83 +1320,95 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1243
1320
|
*
|
|
1244
1321
|
* @return {Viewport}
|
|
1245
1322
|
*/
|
|
1246
|
-
|
|
1323
|
+
this.getViewportFromCentreAndRadius = (
|
|
1324
|
+
centreX,
|
|
1325
|
+
centreY,
|
|
1326
|
+
centreZ,
|
|
1327
|
+
radius,
|
|
1328
|
+
view_angle,
|
|
1329
|
+
clip_distance,
|
|
1330
|
+
) => {
|
|
1247
1331
|
_a.copy(this.cameraObject.position);
|
|
1248
1332
|
_a.sub(this.cameraObject.target);
|
|
1249
1333
|
_a.normalize();
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
/**
|
|
1334
|
+
/* look at the centre of the sphere */
|
|
1335
|
+
const localTargetPosition = [centreX, centreY, centreZ];
|
|
1336
|
+
/* shift the eye position to achieve the desired view_angle */
|
|
1337
|
+
const eye_distance = radius / Math.tan((view_angle * Math.PI) / 360.0);
|
|
1338
|
+
const localEyePosition = [
|
|
1339
|
+
centreX + _a.x * eye_distance,
|
|
1340
|
+
centreY + _a.y * eye_distance,
|
|
1341
|
+
centreZ + _a.z * eye_distance,
|
|
1342
|
+
];
|
|
1343
|
+
const localFarPlane = eye_distance + clip_distance;
|
|
1344
|
+
let localNearPlane = 0.0;
|
|
1345
|
+
const nearClippingFactor = 0.95;
|
|
1346
|
+
if (clip_distance > nearClippingFactor * eye_distance) {
|
|
1347
|
+
localNearPlane = (1.0 - nearClippingFactor) * eye_distance;
|
|
1348
|
+
} else {
|
|
1349
|
+
localNearPlane = eye_distance - clip_distance;
|
|
1350
|
+
}
|
|
1351
|
+
const newViewport = new Viewport();
|
|
1352
|
+
newViewport.nearPlane = localNearPlane;
|
|
1353
|
+
newViewport.farPlane = localFarPlane;
|
|
1354
|
+
newViewport.eyePosition = localEyePosition;
|
|
1355
|
+
newViewport.targetPosition = localTargetPosition;
|
|
1356
|
+
newViewport.upVector = [this.cameraObject.up.x, this.cameraObject.up.y, this.cameraObject.up.z];
|
|
1357
|
+
|
|
1358
|
+
return newViewport;
|
|
1359
|
+
};
|
|
1360
|
+
|
|
1361
|
+
/**
|
|
1279
1362
|
* Get the viewport for the boudning box
|
|
1280
1363
|
*
|
|
1281
1364
|
* @param {Number} boundingBox - y coordinate of the centre.
|
|
1282
1365
|
* @return {Viewport}
|
|
1283
1366
|
*/
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1367
|
+
this.getViewportFromBoundingBox = (boundingBox, radiusScale) => {
|
|
1368
|
+
const radius = (boundingBox.min.distanceTo(boundingBox.max) / 2.0) * radiusScale;
|
|
1369
|
+
const centreX = (boundingBox.min.x + boundingBox.max.x) / 2.0;
|
|
1370
|
+
const centreY = (boundingBox.min.y + boundingBox.max.y) / 2.0;
|
|
1371
|
+
const centreZ = (boundingBox.min.z + boundingBox.max.z) / 2.0;
|
|
1372
|
+
const clip_factor = 4.0;
|
|
1373
|
+
const viewport = this.getViewportFromCentreAndRadius(
|
|
1374
|
+
centreX,
|
|
1375
|
+
centreY,
|
|
1376
|
+
centreZ,
|
|
1377
|
+
radius,
|
|
1378
|
+
40,
|
|
1379
|
+
radius * clip_factor,
|
|
1380
|
+
);
|
|
1381
|
+
return viewport;
|
|
1382
|
+
};
|
|
1294
1383
|
|
|
1295
1384
|
/**
|
|
1296
1385
|
* Get the current camera viewport.
|
|
1297
1386
|
*
|
|
1298
1387
|
* @return {Viewport}
|
|
1299
1388
|
*/
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1389
|
+
this.getCurrentViewport = () => {
|
|
1390
|
+
const currentViewport = new Viewport();
|
|
1391
|
+
currentViewport.nearPlane = this.cameraObject.near;
|
|
1392
|
+
currentViewport.farPlane = this.cameraObject.far;
|
|
1393
|
+
currentViewport.eyePosition[0] = this.cameraObject.position.x;
|
|
1394
|
+
currentViewport.eyePosition[1] = this.cameraObject.position.y;
|
|
1395
|
+
currentViewport.eyePosition[2] = this.cameraObject.position.z;
|
|
1396
|
+
currentViewport.targetPosition[0] = this.cameraObject.target.x;
|
|
1397
|
+
currentViewport.targetPosition[1] = this.cameraObject.target.y;
|
|
1398
|
+
currentViewport.targetPosition[2] = this.cameraObject.target.z;
|
|
1399
|
+
currentViewport.upVector[0] = this.cameraObject.up.x;
|
|
1400
|
+
currentViewport.upVector[1] = this.cameraObject.up.y;
|
|
1401
|
+
currentViewport.upVector[2] = this.cameraObject.up.z;
|
|
1402
|
+
return currentViewport;
|
|
1403
|
+
};
|
|
1404
|
+
|
|
1405
|
+
this.getDefaultEyePosition = () => {
|
|
1406
|
+
return eyePosition;
|
|
1407
|
+
};
|
|
1408
|
+
|
|
1409
|
+
this.getDefaultTargetPosition = () => {
|
|
1410
|
+
return targetPosition;
|
|
1411
|
+
};
|
|
1323
1412
|
|
|
1324
1413
|
/**
|
|
1325
1414
|
* Setup a smooth transition object which transition the camera from one
|
|
@@ -1332,11 +1421,15 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1332
1421
|
* @param {Viewport} endingViewport - the viewport ti end the transistion with.
|
|
1333
1422
|
* @param {Number} durationIn - duration of the smooth transition.
|
|
1334
1423
|
*/
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1424
|
+
this.cameraTransition = (startingViewport, endingViewport, durationIn) => {
|
|
1425
|
+
if (rotateCameraTransitionObject == undefined)
|
|
1426
|
+
smoothCameraTransitionObject = new SmoothCameraTransition(
|
|
1427
|
+
startingViewport,
|
|
1428
|
+
endingViewport,
|
|
1429
|
+
this,
|
|
1430
|
+
durationIn,
|
|
1431
|
+
);
|
|
1432
|
+
};
|
|
1340
1433
|
|
|
1341
1434
|
/**
|
|
1342
1435
|
* Setup a rotate camera transition object which rotate the
|
|
@@ -1350,48 +1443,44 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1350
1443
|
* @param {Number} angle - the viewport ti end the transistion with.
|
|
1351
1444
|
* @param {Number} duration - duration of the smooth transition.
|
|
1352
1445
|
*/
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
}
|
|
1446
|
+
this.rotateCameraTransition = (axis, angle, duration) => {
|
|
1447
|
+
if (smoothCameraTransitionObject == undefined)
|
|
1448
|
+
rotateCameraTransitionObject = new RotateCameraTransition(axis, angle, this, duration);
|
|
1449
|
+
};
|
|
1358
1450
|
|
|
1359
1451
|
/**
|
|
1360
1452
|
* Enable camera transition, {@link rotateCameraTransition} amd
|
|
1361
1453
|
* {@link cameraTransition} must be called before camera transition can
|
|
1362
1454
|
* be enabled.
|
|
1363
1455
|
*/
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
currentMode = MODE.ROTATE_TRANSITION;
|
|
1369
|
-
}
|
|
1456
|
+
this.enableCameraTransition = () => {
|
|
1457
|
+
if (smoothCameraTransitionObject) currentMode = MODE.SMOOTH_CAMERA_TRANSITION;
|
|
1458
|
+
if (rotateCameraTransitionObject) currentMode = MODE.ROTATE_TRANSITION;
|
|
1459
|
+
};
|
|
1370
1460
|
|
|
1371
1461
|
/**
|
|
1372
1462
|
* Pause the camera transition.
|
|
1373
1463
|
*/
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1464
|
+
this.pauseCameraTransition = () => {
|
|
1465
|
+
currentMode = MODE.DEFAULT;
|
|
1466
|
+
};
|
|
1377
1467
|
|
|
1378
1468
|
/**
|
|
1379
1469
|
* Stop the camera transition and remove camera transition
|
|
1380
1470
|
* and rotate camera transition.
|
|
1381
1471
|
*/
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1472
|
+
this.stopCameraTransition = () => {
|
|
1473
|
+
currentMode = MODE.DEFAULT;
|
|
1474
|
+
smoothCameraTransitionObject = undefined;
|
|
1475
|
+
rotateCameraTransitionObject = undefined;
|
|
1476
|
+
};
|
|
1387
1477
|
|
|
1388
1478
|
/**
|
|
1389
1479
|
* Check if camera transition is active.
|
|
1390
1480
|
*/
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
}
|
|
1481
|
+
this.isTransitioningCamera = () => {
|
|
1482
|
+
return currentMode === MODE.SMOOTH_CAMERA_TRANSITION || currentMode === MODE.ROTATE_TRANSITION;
|
|
1483
|
+
};
|
|
1395
1484
|
|
|
1396
1485
|
/**
|
|
1397
1486
|
* Setup auto tumble object of the camera which will rotate the camera
|
|
@@ -1404,41 +1493,45 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1404
1493
|
* @param {Boolean} stopOnCameraInputIn - Disable the tumbling once the user
|
|
1405
1494
|
* start interacting with the scene.
|
|
1406
1495
|
*/
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1496
|
+
this.autoTumble = (tumbleDirectionIn, tumbleRateIn, stopOnCameraInputIn) => {
|
|
1497
|
+
cameraAutoTumbleObject = new CameraAutoTumble(
|
|
1498
|
+
tumbleDirectionIn,
|
|
1499
|
+
tumbleRateIn,
|
|
1500
|
+
stopOnCameraInputIn,
|
|
1501
|
+
this,
|
|
1502
|
+
);
|
|
1503
|
+
};
|
|
1410
1504
|
|
|
1411
1505
|
/**
|
|
1412
1506
|
* Enable autotumble.
|
|
1413
1507
|
*/
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1508
|
+
this.enableAutoTumble = () => {
|
|
1509
|
+
currentMode = MODE.AUTO_TUMBLE;
|
|
1510
|
+
};
|
|
1417
1511
|
|
|
1418
1512
|
/**
|
|
1419
1513
|
* Disable the autotumble.
|
|
1420
1514
|
*/
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1515
|
+
this.stopAutoTumble = () => {
|
|
1516
|
+
currentMode = MODE.DEFAULT;
|
|
1517
|
+
cameraAutoTumbleObject = undefined;
|
|
1518
|
+
};
|
|
1425
1519
|
|
|
1426
1520
|
/**
|
|
1427
1521
|
* Update the autotumble object.
|
|
1428
1522
|
*/
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
}
|
|
1523
|
+
this.updateAutoTumble = () => {
|
|
1524
|
+
if (cameraAutoTumbleObject) cameraAutoTumbleObject.requireUpdate = true;
|
|
1525
|
+
};
|
|
1433
1526
|
|
|
1434
1527
|
/**
|
|
1435
1528
|
* Check rather autotumble is active.
|
|
1436
1529
|
*
|
|
1437
1530
|
* @return {Boolean}
|
|
1438
1531
|
*/
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1532
|
+
this.isAutoTumble = () => {
|
|
1533
|
+
return currentMode === MODE.AUTO_TUMBLE;
|
|
1534
|
+
};
|
|
1442
1535
|
|
|
1443
1536
|
/**
|
|
1444
1537
|
* Create an internal raycaster object and enable it for picking.
|
|
@@ -1451,8 +1544,14 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1451
1544
|
*/
|
|
1452
1545
|
this.enableRaycaster = (sceneIn, callbackFunctionIn, hoverCallbackFunctionIn) => {
|
|
1453
1546
|
if (zincRayCaster == undefined)
|
|
1454
|
-
zincRayCaster = new RayCaster(
|
|
1455
|
-
|
|
1547
|
+
zincRayCaster = new RayCaster(
|
|
1548
|
+
sceneIn,
|
|
1549
|
+
this.scene,
|
|
1550
|
+
callbackFunctionIn,
|
|
1551
|
+
hoverCallbackFunctionIn,
|
|
1552
|
+
this.renderer,
|
|
1553
|
+
);
|
|
1554
|
+
};
|
|
1456
1555
|
|
|
1457
1556
|
/**
|
|
1458
1557
|
* Disable raycaster and remove the internal ray caster object.
|
|
@@ -1460,7 +1559,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1460
1559
|
this.disableRaycaster = () => {
|
|
1461
1560
|
zincRayCaster.disable();
|
|
1462
1561
|
zincRayCaster = undefined;
|
|
1463
|
-
}
|
|
1562
|
+
};
|
|
1464
1563
|
|
|
1465
1564
|
/**
|
|
1466
1565
|
* Check rather the camera is in syncControl mode.
|
|
@@ -1469,19 +1568,17 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1469
1568
|
*/
|
|
1470
1569
|
this.isSyncControl = () => {
|
|
1471
1570
|
return currentMpde === MODE.SYNC_CONTROL;
|
|
1472
|
-
}
|
|
1571
|
+
};
|
|
1473
1572
|
|
|
1474
1573
|
/**
|
|
1475
1574
|
* Enable syncControl.
|
|
1476
1575
|
*/
|
|
1477
1576
|
this.enableSyncControl = () => {
|
|
1478
1577
|
currentMode = MODE.SYNC_CONTROL;
|
|
1479
|
-
if (!ndcControl)
|
|
1480
|
-
|
|
1481
|
-
ndcControl.setCurrentCameraSettings(this.cameraObject,
|
|
1482
|
-
viewports[defaultViewport]);
|
|
1578
|
+
if (!ndcControl) ndcControl = new NDCCameraControl();
|
|
1579
|
+
ndcControl.setCurrentCameraSettings(this.cameraObject, viewports[defaultViewport]);
|
|
1483
1580
|
return ndcControl;
|
|
1484
|
-
}
|
|
1581
|
+
};
|
|
1485
1582
|
|
|
1486
1583
|
/**
|
|
1487
1584
|
* Disable syncControl.
|
|
@@ -1490,73 +1587,78 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1490
1587
|
currentMode = MODE.DEFAULT;
|
|
1491
1588
|
this.cameraObject.zoom = 1;
|
|
1492
1589
|
this.cameraObject.updateProjectionMatrix();
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
this.enable();
|
|
1590
|
+
};
|
|
1496
1591
|
|
|
1592
|
+
this.enable();
|
|
1497
1593
|
};
|
|
1498
1594
|
|
|
1499
|
-
const SmoothCameraTransition = function(
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1595
|
+
const SmoothCameraTransition = function (
|
|
1596
|
+
startingViewport,
|
|
1597
|
+
endingViewport,
|
|
1598
|
+
targetCameraIn,
|
|
1599
|
+
durationIn,
|
|
1600
|
+
) {
|
|
1601
|
+
const startingEyePosition = startingViewport.eyePosition;
|
|
1602
|
+
const startingTargetPosition = startingViewport.targetPosition;
|
|
1603
|
+
const endingEyePosition = endingViewport.eyePosition;
|
|
1604
|
+
const endingTargetPosition = endingViewport.targetPosition;
|
|
1605
|
+
const targetCamera = targetCameraIn;
|
|
1606
|
+
let duration = durationIn;
|
|
1607
|
+
let inbuildTime = 0;
|
|
1608
|
+
const enabled = true;
|
|
1609
|
+
const updateLightWithPathFlag = true;
|
|
1610
|
+
let completed = false;
|
|
1611
|
+
targetCamera.near = Math.min(startingViewport.nearPlane, endingViewport.nearPlane);
|
|
1612
|
+
targetCamera.far = Math.max(startingViewport.farPlane, endingViewport.farPlane);
|
|
1613
|
+
targetCamera.cameraObject.up.set(
|
|
1614
|
+
endingViewport.upVector[0],
|
|
1615
|
+
endingViewport.upVector[1],
|
|
1616
|
+
endingViewport.upVector[2],
|
|
1617
|
+
);
|
|
1618
|
+
|
|
1619
|
+
this.setDuration = (newDuration) => {
|
|
1516
1620
|
duration = newDuration;
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
const updateTime = delta => {
|
|
1520
|
-
let targetTime = inbuildTime + delta;
|
|
1521
|
-
if (targetTime > duration)
|
|
1522
|
-
targetTime = duration;
|
|
1523
|
-
inbuildTime = targetTime;
|
|
1524
|
-
};
|
|
1525
|
-
|
|
1526
|
-
const updateCameraSettings = () => {
|
|
1527
|
-
const ratio = inbuildTime / duration;
|
|
1528
|
-
const start = 1.0 - ratio;
|
|
1529
|
-
targetCamera.cameraObject.position.set(
|
|
1530
|
-
startingEyePosition[0] * start + endingEyePosition[0] * ratio,
|
|
1531
|
-
startingEyePosition[1] * start + endingEyePosition[1] * ratio,
|
|
1532
|
-
startingEyePosition[2] * start + endingEyePosition[2] * ratio);
|
|
1533
|
-
targetCamera.cameraObject.target.set(
|
|
1534
|
-
startingTargetPosition[0] * start + endingTargetPosition[0] * ratio,
|
|
1535
|
-
startingTargetPosition[1] * start + endingTargetPosition[1] * ratio,
|
|
1536
|
-
startingTargetPosition[2] * start + endingTargetPosition[2] * ratio);
|
|
1537
|
-
};
|
|
1538
|
-
|
|
1539
|
-
this.update = delta => {
|
|
1621
|
+
};
|
|
1540
1622
|
|
|
1541
|
-
|
|
1623
|
+
const updateTime = (delta) => {
|
|
1624
|
+
let targetTime = inbuildTime + delta;
|
|
1625
|
+
if (targetTime > duration) targetTime = duration;
|
|
1626
|
+
inbuildTime = targetTime;
|
|
1627
|
+
};
|
|
1542
1628
|
|
|
1543
|
-
|
|
1629
|
+
const updateCameraSettings = () => {
|
|
1630
|
+
const ratio = inbuildTime / duration;
|
|
1631
|
+
const start = 1.0 - ratio;
|
|
1632
|
+
targetCamera.cameraObject.position.set(
|
|
1633
|
+
startingEyePosition[0] * start + endingEyePosition[0] * ratio,
|
|
1634
|
+
startingEyePosition[1] * start + endingEyePosition[1] * ratio,
|
|
1635
|
+
startingEyePosition[2] * start + endingEyePosition[2] * ratio,
|
|
1636
|
+
);
|
|
1637
|
+
targetCamera.cameraObject.target.set(
|
|
1638
|
+
startingTargetPosition[0] * start + endingTargetPosition[0] * ratio,
|
|
1639
|
+
startingTargetPosition[1] * start + endingTargetPosition[1] * ratio,
|
|
1640
|
+
startingTargetPosition[2] * start + endingTargetPosition[2] * ratio,
|
|
1641
|
+
);
|
|
1642
|
+
};
|
|
1544
1643
|
|
|
1545
|
-
|
|
1644
|
+
this.update = (delta) => {
|
|
1645
|
+
if (this.enabled === false) return;
|
|
1546
1646
|
|
|
1547
|
-
|
|
1548
|
-
completed = true;
|
|
1549
|
-
}
|
|
1647
|
+
updateTime(delta);
|
|
1550
1648
|
|
|
1551
|
-
|
|
1649
|
+
updateCameraSettings();
|
|
1552
1650
|
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1651
|
+
if (inbuildTime == duration) {
|
|
1652
|
+
completed = true;
|
|
1653
|
+
}
|
|
1654
|
+
};
|
|
1556
1655
|
|
|
1656
|
+
this.isTransitionCompleted = () => {
|
|
1657
|
+
return completed;
|
|
1658
|
+
};
|
|
1557
1659
|
};
|
|
1558
1660
|
|
|
1559
|
-
const RotateCameraTransition = function(axisIn, angleIn, targetCameraIn, durationIn) {
|
|
1661
|
+
const RotateCameraTransition = function (axisIn, angleIn, targetCameraIn, durationIn) {
|
|
1560
1662
|
const axis = axisIn;
|
|
1561
1663
|
const angle = angleIn;
|
|
1562
1664
|
const targetCamera = targetCameraIn;
|
|
@@ -1566,15 +1668,14 @@ const RotateCameraTransition = function(axisIn, angleIn, targetCameraIn, duratio
|
|
|
1566
1668
|
const ratio = inbuildTime / duration;
|
|
1567
1669
|
let completed = false;
|
|
1568
1670
|
|
|
1569
|
-
this.setDuration = newDuration => {
|
|
1671
|
+
this.setDuration = (newDuration) => {
|
|
1570
1672
|
duration = newDuration;
|
|
1571
|
-
}
|
|
1673
|
+
};
|
|
1572
1674
|
|
|
1573
|
-
const updateCameraSettings = delta => {
|
|
1675
|
+
const updateCameraSettings = (delta) => {
|
|
1574
1676
|
const previousTime = inbuildTime;
|
|
1575
1677
|
let targetTime = inbuildTime + delta;
|
|
1576
|
-
if (targetTime > duration)
|
|
1577
|
-
targetTime = duration;
|
|
1678
|
+
if (targetTime > duration) targetTime = duration;
|
|
1578
1679
|
inbuildTime = targetTime;
|
|
1579
1680
|
const actualDelta = inbuildTime - previousTime;
|
|
1580
1681
|
const ratio = actualDelta / duration;
|
|
@@ -1582,52 +1683,56 @@ const RotateCameraTransition = function(axisIn, angleIn, targetCameraIn, duratio
|
|
|
1582
1683
|
targetCamera.rotateAboutLookAtpoint(axis, alpha);
|
|
1583
1684
|
};
|
|
1584
1685
|
|
|
1585
|
-
this.update = delta => {
|
|
1586
|
-
|
|
1587
|
-
if ( this.enabled === false ) return;
|
|
1686
|
+
this.update = (delta) => {
|
|
1687
|
+
if (this.enabled === false) return;
|
|
1588
1688
|
|
|
1589
1689
|
updateCameraSettings(delta);
|
|
1590
1690
|
|
|
1591
1691
|
if (inbuildTime == duration) {
|
|
1592
1692
|
completed = true;
|
|
1593
1693
|
}
|
|
1594
|
-
|
|
1595
|
-
}
|
|
1694
|
+
};
|
|
1596
1695
|
|
|
1597
1696
|
this.isTransitionCompleted = () => {
|
|
1598
1697
|
return completed;
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1698
|
+
};
|
|
1699
|
+
};
|
|
1601
1700
|
|
|
1602
|
-
const RayCaster = function (
|
|
1701
|
+
const RayCaster = function (
|
|
1702
|
+
sceneIn,
|
|
1703
|
+
hostSceneIn,
|
|
1704
|
+
callbackFunctionIn,
|
|
1705
|
+
hoverCallbackFunctionIn,
|
|
1706
|
+
rendererIn,
|
|
1707
|
+
) {
|
|
1603
1708
|
const scene = sceneIn;
|
|
1604
1709
|
const hostScene = hostSceneIn;
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1710
|
+
const renderer = rendererIn;
|
|
1711
|
+
const callbackFunction = callbackFunctionIn;
|
|
1712
|
+
const hoverCallbackFunction = hoverCallbackFunctionIn;
|
|
1713
|
+
let enabled = true;
|
|
1714
|
+
const raycaster = new THREE.Raycaster();
|
|
1715
|
+
raycaster.params.Line.threshold = 0.1;
|
|
1716
|
+
raycaster.params.Points.threshold = 1;
|
|
1612
1717
|
const mouse = new THREE.Vector2();
|
|
1613
1718
|
let awaiting = false;
|
|
1614
1719
|
let lastHoveredDate = new Date();
|
|
1615
1720
|
let lastHoveredEmpty = false;
|
|
1616
1721
|
let timeDiff = 0;
|
|
1617
1722
|
let pickedObjects = new Array();
|
|
1618
|
-
let lastPosition = { zincCamera: undefined, x: -1
|
|
1723
|
+
let lastPosition = { zincCamera: undefined, x: -1, y: -1 };
|
|
1619
1724
|
let hoverFrameRequested = false;
|
|
1620
|
-
|
|
1725
|
+
let pickableObjects = undefined;
|
|
1621
1726
|
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1727
|
+
this.enable = () => {
|
|
1728
|
+
enabled = true;
|
|
1729
|
+
};
|
|
1625
1730
|
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1731
|
+
this.disable = () => {
|
|
1732
|
+
enabled = false;
|
|
1733
|
+
};
|
|
1629
1734
|
|
|
1630
|
-
|
|
1735
|
+
this.getIntersectsObject = (zincCamera) => {
|
|
1631
1736
|
if (hostScene !== scene) {
|
|
1632
1737
|
//Only the world matrices need to be up to date for raycasting
|
|
1633
1738
|
scene.getThreeJSScene().updateMatrixWorld();
|
|
@@ -1635,52 +1740,56 @@ const RayCaster = function (sceneIn, hostSceneIn, callbackFunctionIn, hoverCallb
|
|
|
1635
1740
|
let objects = pickableObjects ? pickableObjects : scene.getPickableThreeJSObjects();
|
|
1636
1741
|
//Reset pickedObjects array
|
|
1637
1742
|
pickedObjects.length = 0;
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1743
|
+
return raycaster.intersectObjects(objects, true, pickedObjects);
|
|
1744
|
+
};
|
|
1745
|
+
|
|
1746
|
+
this.setPickableObjects = (zincObjects) => {
|
|
1747
|
+
if (zincObjects === undefined) {
|
|
1748
|
+
pickableObjects = undefined;
|
|
1749
|
+
} else {
|
|
1750
|
+
pickableObjects = [];
|
|
1751
|
+
zincObjects.forEach((zincObject) => {
|
|
1752
|
+
if (zincObject.getGroup() && zincObject.getGroup().visible) {
|
|
1753
|
+
pickableObjects.push(zincObject.getGroup());
|
|
1754
|
+
}
|
|
1755
|
+
});
|
|
1756
|
+
}
|
|
1757
|
+
};
|
|
1758
|
+
|
|
1759
|
+
this.getIntersectsObjectWithOrigin = (zincCamera, origin, direction) => {
|
|
1760
|
+
raycaster.set(origin, direction);
|
|
1761
|
+
return this.getIntersectsObject(zincCamera);
|
|
1762
|
+
};
|
|
1763
|
+
|
|
1764
|
+
this.getIntersectsObjectWithCamera = (zincCamera, x, y) => {
|
|
1660
1765
|
zincCamera.getNDCFromDocumentCoords(x, y, mouse);
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1766
|
+
raycaster.setFromCamera(mouse, zincCamera.cameraObject);
|
|
1767
|
+
return this.getIntersectsObject(zincCamera);
|
|
1768
|
+
};
|
|
1769
|
+
|
|
1770
|
+
this.pick = (zincCamera, x, y) => {
|
|
1771
|
+
if (enabled && renderer && scene && zincCamera && callbackFunction) {
|
|
1772
|
+
this.getIntersectsObjectWithCamera(zincCamera, x, y);
|
|
1773
|
+
const length = pickedObjects.length;
|
|
1774
|
+
for (let i = 0; i < length; i++) {
|
|
1775
|
+
let zincObject = pickedObjects[i].object ? pickedObjects[i].object.userData : undefined;
|
|
1776
|
+
if (
|
|
1777
|
+
zincObject &&
|
|
1778
|
+
zincObject.isMarkerCluster &&
|
|
1779
|
+
zincObject.visible &&
|
|
1780
|
+
zincObject.clusterIsVisible(pickedObjects[i].object.clusterIndex)
|
|
1781
|
+
) {
|
|
1782
|
+
//Can zoom into cluster
|
|
1783
|
+
if (zincObject.zoomToCluster(pickedObjects[i].object.clusterIndex)) {
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
callbackFunction(pickedObjects, x, y);
|
|
1789
|
+
//The callback may have changed what is displayed
|
|
1790
|
+
hostScene?.invalidate?.();
|
|
1791
|
+
}
|
|
1792
|
+
};
|
|
1684
1793
|
|
|
1685
1794
|
let hovered = (zincCamera, x, y) => {
|
|
1686
1795
|
if (enabled && renderer && scene && zincCamera && hoverCallbackFunction) {
|
|
@@ -1688,8 +1797,7 @@ const RayCaster = function (sceneIn, hostSceneIn, callbackFunctionIn, hoverCallb
|
|
|
1688
1797
|
lastHoveredDate.setTime(Date.now());
|
|
1689
1798
|
if (pickedObjects.length === 0) {
|
|
1690
1799
|
//skip hovered callback if the previous one is empty
|
|
1691
|
-
if (lastHoveredEmpty)
|
|
1692
|
-
return
|
|
1800
|
+
if (lastHoveredEmpty) return;
|
|
1693
1801
|
lastHoveredEmpty = true;
|
|
1694
1802
|
} else {
|
|
1695
1803
|
lastHoveredEmpty = false;
|
|
@@ -1698,9 +1806,9 @@ const RayCaster = function (sceneIn, hostSceneIn, callbackFunctionIn, hoverCallb
|
|
|
1698
1806
|
//The callback may have changed what is displayed
|
|
1699
1807
|
hostScene?.invalidate?.();
|
|
1700
1808
|
}
|
|
1701
|
-
}
|
|
1809
|
+
};
|
|
1702
1810
|
|
|
1703
|
-
|
|
1811
|
+
this.move = (zincCamera, x, y) => {
|
|
1704
1812
|
if (enabled && renderer && scene && zincCamera && hoverCallbackFunction) {
|
|
1705
1813
|
lastPosition.zincCamera = zincCamera;
|
|
1706
1814
|
lastPosition.x = x;
|
|
@@ -1729,162 +1837,157 @@ const RayCaster = function (sceneIn, hostSceneIn, callbackFunctionIn, hoverCallb
|
|
|
1729
1837
|
}
|
|
1730
1838
|
}
|
|
1731
1839
|
}
|
|
1732
|
-
}
|
|
1840
|
+
};
|
|
1733
1841
|
|
|
1734
1842
|
let awaitMove = (lastPosition) => {
|
|
1735
|
-
return function() {
|
|
1843
|
+
return function () {
|
|
1736
1844
|
awaiting = false;
|
|
1737
1845
|
hovered(lastPosition.zincCamera, lastPosition.x, lastPosition.y);
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1846
|
+
};
|
|
1847
|
+
};
|
|
1740
1848
|
};
|
|
1741
1849
|
|
|
1742
|
-
const CameraAutoTumble = function (
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1850
|
+
const CameraAutoTumble = function (
|
|
1851
|
+
tumbleDirectionIn,
|
|
1852
|
+
tumbleRateIn,
|
|
1853
|
+
stopOnCameraInputIn,
|
|
1854
|
+
targetCameraIn,
|
|
1855
|
+
) {
|
|
1856
|
+
const tumbleAxis = new THREE.Vector3();
|
|
1857
|
+
const angle = -tumbleRateIn;
|
|
1858
|
+
const targetCamera = targetCameraIn;
|
|
1859
|
+
const enabled = true;
|
|
1860
|
+
const updateLightWithPathFlag = true;
|
|
1861
|
+
const tumbleDirection = tumbleDirectionIn;
|
|
1862
|
+
this.stopOnCameraInput = stopOnCameraInputIn;
|
|
1750
1863
|
this.requireUpdate = true;
|
|
1751
1864
|
const b = new THREE.Vector3();
|
|
1752
1865
|
const c = new THREE.Vector3();
|
|
1753
1866
|
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
b.copy(targetCamera.cameraObject.up).normalize();
|
|
1867
|
+
const computeTumbleAxisAngle = (tumbleDirection) => {
|
|
1868
|
+
const tangent_dist = Math.sqrt(
|
|
1869
|
+
tumbleDirection[0] * tumbleDirection[0] + tumbleDirection[1] * tumbleDirection[1],
|
|
1870
|
+
);
|
|
1871
|
+
const width = Math.abs(tumbleDirection[0]) * 4.0;
|
|
1872
|
+
const height = Math.abs(tumbleDirection[1]) * 4.0;
|
|
1873
|
+
const radius = 0.25 * (width + height);
|
|
1874
|
+
const dx = -tumbleDirection[1] / tangent_dist;
|
|
1875
|
+
const dy = tumbleDirection[0] / tangent_dist;
|
|
1876
|
+
let d = dx * tumbleDirection[0] + dy * -tumbleDirection[1];
|
|
1877
|
+
|
|
1878
|
+
if (d > radius) {
|
|
1879
|
+
d = radius;
|
|
1880
|
+
} else {
|
|
1881
|
+
if (d < -radius) {
|
|
1882
|
+
d = -radius;
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
const phi = Math.acos(d / radius) - 0.5 * Math.PI;
|
|
1887
|
+
/* get axis to rotate about */
|
|
1888
|
+
tumbleAxis
|
|
1889
|
+
.copy(targetCamera.cameraObject.position)
|
|
1890
|
+
.sub(targetCamera.cameraObject.target)
|
|
1891
|
+
.normalize();
|
|
1892
|
+
b.copy(targetCamera.cameraObject.up).normalize();
|
|
1781
1893
|
c.crossVectors(b, tumbleAxis).normalize().multiplyScalar(dx);
|
|
1782
1894
|
b.multiplyScalar(dy);
|
|
1783
1895
|
b.add(c).multiplyScalar(Math.cos(phi));
|
|
1784
1896
|
tumbleAxis.multiplyScalar(Math.sin(phi)).add(b);
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
this.update = delta => {
|
|
1788
|
-
|
|
1789
|
-
if ( this.enabled === false ) return;
|
|
1790
|
-
|
|
1791
|
-
if (this.requireUpdate) {
|
|
1792
|
-
computeTumbleAxisAngle(tumbleDirection);
|
|
1793
|
-
this.requireUpdate = false;
|
|
1794
|
-
}
|
|
1795
|
-
targetCamera.rotateAboutLookAtpoint(tumbleAxis, angle * delta/1000);
|
|
1897
|
+
};
|
|
1796
1898
|
|
|
1797
|
-
|
|
1899
|
+
this.update = (delta) => {
|
|
1900
|
+
if (this.enabled === false) return;
|
|
1798
1901
|
|
|
1902
|
+
if (this.requireUpdate) {
|
|
1903
|
+
computeTumbleAxisAngle(tumbleDirection);
|
|
1904
|
+
this.requireUpdate = false;
|
|
1905
|
+
}
|
|
1906
|
+
targetCamera.rotateAboutLookAtpoint(tumbleAxis, (angle * delta) / 1000);
|
|
1907
|
+
};
|
|
1799
1908
|
};
|
|
1800
1909
|
|
|
1801
1910
|
/**
|
|
1802
1911
|
* @author mrdoob / http://mrdoob.com/
|
|
1803
1912
|
*/
|
|
1804
1913
|
const StereoCameraZoomFixed = function () {
|
|
1914
|
+
this.type = 'StereoCamera';
|
|
1805
1915
|
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
this.aspect = 1;
|
|
1809
|
-
|
|
1810
|
-
this.cameraL = new THREE.PerspectiveCamera();
|
|
1811
|
-
this.cameraL.layers.enable( 1 );
|
|
1812
|
-
this.cameraL.matrixAutoUpdate = false;
|
|
1916
|
+
this.aspect = 1;
|
|
1813
1917
|
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1918
|
+
this.cameraL = new THREE.PerspectiveCamera();
|
|
1919
|
+
this.cameraL.layers.enable(1);
|
|
1920
|
+
this.cameraL.matrixAutoUpdate = false;
|
|
1817
1921
|
|
|
1922
|
+
this.cameraR = new THREE.PerspectiveCamera();
|
|
1923
|
+
this.cameraR.layers.enable(2);
|
|
1924
|
+
this.cameraR.matrixAutoUpdate = false;
|
|
1818
1925
|
};
|
|
1819
1926
|
|
|
1820
|
-
Object.assign(
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
let focus, fov, aspect, near, far, zoom;
|
|
1927
|
+
Object.assign(StereoCameraZoomFixed.prototype, {
|
|
1928
|
+
update: (() => {
|
|
1929
|
+
let focus, fov, aspect, near, far, zoom;
|
|
1825
1930
|
|
|
1826
|
-
|
|
1827
|
-
|
|
1931
|
+
const eyeRight = new THREE.Matrix4();
|
|
1932
|
+
const eyeLeft = new THREE.Matrix4();
|
|
1828
1933
|
|
|
1829
|
-
|
|
1934
|
+
return function update(camera) {
|
|
1935
|
+
const needsUpdate =
|
|
1936
|
+
focus !== camera.focus ||
|
|
1937
|
+
fov !== camera.fov ||
|
|
1938
|
+
aspect !== camera.aspect * this.aspect ||
|
|
1939
|
+
near !== camera.near ||
|
|
1940
|
+
far !== camera.far ||
|
|
1941
|
+
zoom !== camera.zoom;
|
|
1830
1942
|
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1943
|
+
if (needsUpdate) {
|
|
1944
|
+
focus = camera.focus;
|
|
1945
|
+
fov = camera.fov;
|
|
1946
|
+
aspect = camera.aspect * this.aspect;
|
|
1947
|
+
near = camera.near;
|
|
1948
|
+
far = camera.far;
|
|
1949
|
+
zoom = camera.zoom;
|
|
1834
1950
|
|
|
1835
|
-
|
|
1951
|
+
// Off-axis stereoscopic effect based on
|
|
1952
|
+
// http://paulbourke.net/stereographics/stereorender/
|
|
1836
1953
|
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
zoom = camera.zoom;
|
|
1954
|
+
const projectionMatrix = camera.projectionMatrix.clone();
|
|
1955
|
+
const eyeSep = 0.064 / 2;
|
|
1956
|
+
const eyeSepOnProjection = (eyeSep * near) / focus;
|
|
1957
|
+
const ymax = (near * Math.tan(THREE.MathUtils.DEG2RAD * fov * 0.5)) / camera.zoom;
|
|
1958
|
+
let xmin, xmax;
|
|
1843
1959
|
|
|
1844
|
-
|
|
1845
|
-
// http://paulbourke.net/stereographics/stereorender/
|
|
1960
|
+
// translate xOffset
|
|
1846
1961
|
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
const eyeSepOnProjection = eyeSep * near / focus;
|
|
1850
|
-
const ymax = near * Math.tan( THREE.MathUtils.DEG2RAD * fov * 0.5 ) / camera.zoom;
|
|
1851
|
-
let xmin, xmax;
|
|
1962
|
+
eyeLeft.elements[12] = -eyeSep;
|
|
1963
|
+
eyeRight.elements[12] = eyeSep;
|
|
1852
1964
|
|
|
1853
|
-
|
|
1965
|
+
// for left eye
|
|
1854
1966
|
|
|
1855
|
-
|
|
1856
|
-
|
|
1967
|
+
xmin = -ymax * aspect + eyeSepOnProjection;
|
|
1968
|
+
xmax = ymax * aspect + eyeSepOnProjection;
|
|
1857
1969
|
|
|
1858
|
-
|
|
1970
|
+
projectionMatrix.elements[0] = (2 * near) / (xmax - xmin);
|
|
1971
|
+
projectionMatrix.elements[8] = (xmax + xmin) / (xmax - xmin);
|
|
1859
1972
|
|
|
1860
|
-
|
|
1861
|
-
xmax = ymax * aspect + eyeSepOnProjection;
|
|
1973
|
+
this.cameraL.projectionMatrix.copy(projectionMatrix);
|
|
1862
1974
|
|
|
1863
|
-
|
|
1864
|
-
projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
|
|
1975
|
+
// for right eye
|
|
1865
1976
|
|
|
1866
|
-
|
|
1977
|
+
xmin = -ymax * aspect - eyeSepOnProjection;
|
|
1978
|
+
xmax = ymax * aspect - eyeSepOnProjection;
|
|
1867
1979
|
|
|
1868
|
-
|
|
1980
|
+
projectionMatrix.elements[0] = (2 * near) / (xmax - xmin);
|
|
1981
|
+
projectionMatrix.elements[8] = (xmax + xmin) / (xmax - xmin);
|
|
1869
1982
|
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );
|
|
1874
|
-
projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
|
|
1875
|
-
|
|
1876
|
-
this.cameraR.projectionMatrix.copy( projectionMatrix );
|
|
1877
|
-
|
|
1878
|
-
}
|
|
1879
|
-
|
|
1880
|
-
this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft );
|
|
1881
|
-
this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight );
|
|
1882
|
-
|
|
1883
|
-
};
|
|
1884
|
-
|
|
1885
|
-
})()
|
|
1983
|
+
this.cameraR.projectionMatrix.copy(projectionMatrix);
|
|
1984
|
+
}
|
|
1886
1985
|
|
|
1887
|
-
|
|
1986
|
+
this.cameraL.matrixWorld.copy(camera.matrixWorld).multiply(eyeLeft);
|
|
1987
|
+
this.cameraR.matrixWorld.copy(camera.matrixWorld).multiply(eyeRight);
|
|
1988
|
+
};
|
|
1989
|
+
})(),
|
|
1990
|
+
});
|
|
1888
1991
|
|
|
1889
1992
|
/** the following StereoEffect is written by third party */
|
|
1890
1993
|
/**
|
|
@@ -1892,46 +1995,39 @@ Object.assign( StereoCameraZoomFixed.prototype, {
|
|
|
1892
1995
|
* @authod mrdoob / http://mrdoob.com/
|
|
1893
1996
|
* @authod arodic / http://aleksandarrodic.com/
|
|
1894
1997
|
* @authod fonserbc / http://fonserbc.github.io/
|
|
1895
|
-
*/
|
|
1896
|
-
const StereoEffect = function (
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
_stereo.aspect = 0.5;
|
|
1900
|
-
|
|
1901
|
-
this.setSize = (width, height) => {
|
|
1902
|
-
|
|
1903
|
-
renderer.setSize( width, height );
|
|
1904
|
-
|
|
1905
|
-
};
|
|
1906
|
-
|
|
1907
|
-
this.render = (scene, camera) => {
|
|
1908
|
-
|
|
1909
|
-
scene.updateMatrixWorld();
|
|
1998
|
+
*/
|
|
1999
|
+
const StereoEffect = function (renderer) {
|
|
2000
|
+
const _stereo = new StereoCameraZoomFixed();
|
|
2001
|
+
_stereo.aspect = 0.5;
|
|
1910
2002
|
|
|
1911
|
-
|
|
2003
|
+
this.setSize = (width, height) => {
|
|
2004
|
+
renderer.setSize(width, height);
|
|
2005
|
+
};
|
|
1912
2006
|
|
|
1913
|
-
|
|
2007
|
+
this.render = (scene, camera) => {
|
|
2008
|
+
scene.updateMatrixWorld();
|
|
1914
2009
|
|
|
1915
|
-
|
|
2010
|
+
if (camera.parent === null) camera.updateMatrixWorld();
|
|
1916
2011
|
|
|
1917
|
-
|
|
1918
|
-
renderer.clear();
|
|
2012
|
+
_stereo.update(camera);
|
|
1919
2013
|
|
|
1920
|
-
|
|
1921
|
-
renderer.setViewport( 0, 0, size.width / 2, size.height );
|
|
1922
|
-
renderer.render( scene, _stereo.cameraL );
|
|
2014
|
+
const size = renderer.getSize();
|
|
1923
2015
|
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
renderer.render( scene, _stereo.cameraR );
|
|
2016
|
+
renderer.setScissorTest(true);
|
|
2017
|
+
renderer.clear();
|
|
1927
2018
|
|
|
1928
|
-
|
|
2019
|
+
renderer.setScissor(0, 0, size.width / 2, size.height);
|
|
2020
|
+
renderer.setViewport(0, 0, size.width / 2, size.height);
|
|
2021
|
+
renderer.render(scene, _stereo.cameraL);
|
|
1929
2022
|
|
|
1930
|
-
|
|
2023
|
+
renderer.setScissor(size.width / 2, 0, size.width / 2, size.height);
|
|
2024
|
+
renderer.setViewport(size.width / 2, 0, size.width / 2, size.height);
|
|
2025
|
+
renderer.render(scene, _stereo.cameraR);
|
|
1931
2026
|
|
|
2027
|
+
renderer.setScissorTest(false);
|
|
2028
|
+
};
|
|
1932
2029
|
};
|
|
1933
2030
|
|
|
1934
|
-
|
|
1935
2031
|
/**
|
|
1936
2032
|
* @author richt / http://richt.me
|
|
1937
2033
|
* @author WestLangley / http://github.com/WestLangley
|
|
@@ -1939,113 +2035,102 @@ const StereoEffect = function ( renderer ) {
|
|
|
1939
2035
|
* W3C Device Orientation control (http://w3c.github.io/deviceorientation/spec-source-orientation.html)
|
|
1940
2036
|
*/
|
|
1941
2037
|
|
|
1942
|
-
const ModifiedDeviceOrientationControls = function (
|
|
1943
|
-
|
|
1944
|
-
const scope = this;
|
|
1945
|
-
|
|
1946
|
-
this.object = object;
|
|
1947
|
-
this.object.rotation.reorder( "YXZ" );
|
|
1948
|
-
|
|
1949
|
-
this.enabled = true;
|
|
1950
|
-
|
|
1951
|
-
this.deviceOrientation = {};
|
|
1952
|
-
this.screenOrientation = 0;
|
|
1953
|
-
|
|
1954
|
-
const onDeviceOrientationChangeEvent = event => {
|
|
1955
|
-
|
|
1956
|
-
scope.deviceOrientation = event;
|
|
1957
|
-
|
|
1958
|
-
};
|
|
1959
|
-
|
|
1960
|
-
const onScreenOrientationChangeEvent = () => {
|
|
1961
|
-
if (typeof(window) !== 'undefined')
|
|
1962
|
-
scope.screenOrientation = window.orientation || 0;
|
|
1963
|
-
|
|
1964
|
-
};
|
|
1965
|
-
|
|
1966
|
-
// The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''
|
|
1967
|
-
|
|
1968
|
-
const setObjectQuaternion = (() => {
|
|
1969
|
-
|
|
1970
|
-
const zee = new THREE.Vector3( 0, 0, 1 );
|
|
1971
|
-
|
|
1972
|
-
const euler = new THREE.Euler();
|
|
1973
|
-
|
|
1974
|
-
const q0 = new THREE.Quaternion();
|
|
2038
|
+
const ModifiedDeviceOrientationControls = function (object) {
|
|
2039
|
+
const scope = this;
|
|
1975
2040
|
|
|
1976
|
-
|
|
2041
|
+
this.object = object;
|
|
2042
|
+
this.object.rotation.reorder('YXZ');
|
|
1977
2043
|
|
|
1978
|
-
|
|
2044
|
+
this.enabled = true;
|
|
1979
2045
|
|
|
1980
|
-
|
|
2046
|
+
this.deviceOrientation = {};
|
|
2047
|
+
this.screenOrientation = 0;
|
|
1981
2048
|
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
euler.set( beta, alpha, - gamma, 'YXZ' ); // 'ZXY' for the device, but 'YXZ' for us
|
|
1987
|
-
|
|
1988
|
-
quaternion.setFromEuler( euler ); // orient the device
|
|
1989
|
-
|
|
1990
|
-
quaternion.multiply( q1 ); // camera looks out the back of the device, not the top
|
|
2049
|
+
const onDeviceOrientationChangeEvent = (event) => {
|
|
2050
|
+
scope.deviceOrientation = event;
|
|
2051
|
+
};
|
|
1991
2052
|
|
|
1992
|
-
|
|
2053
|
+
const onScreenOrientationChangeEvent = () => {
|
|
2054
|
+
if (typeof window !== 'undefined') scope.screenOrientation = window.orientation || 0;
|
|
2055
|
+
};
|
|
1993
2056
|
|
|
1994
|
-
|
|
2057
|
+
// The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''
|
|
1995
2058
|
|
|
1996
|
-
|
|
2059
|
+
const setObjectQuaternion = (() => {
|
|
2060
|
+
const zee = new THREE.Vector3(0, 0, 1);
|
|
1997
2061
|
|
|
1998
|
-
|
|
2062
|
+
const euler = new THREE.Euler();
|
|
1999
2063
|
|
|
2000
|
-
|
|
2064
|
+
const q0 = new THREE.Quaternion();
|
|
2001
2065
|
|
|
2002
|
-
|
|
2066
|
+
const q1 = new THREE.Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)); // - PI/2 around the x-axis
|
|
2003
2067
|
|
|
2004
|
-
|
|
2068
|
+
const vector = new THREE.Vector3();
|
|
2005
2069
|
|
|
2006
|
-
|
|
2007
|
-
if (typeof(window) !== 'undefined') {
|
|
2008
|
-
window.addEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
|
|
2009
|
-
window.addEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
|
|
2010
|
-
}
|
|
2011
|
-
scope.enabled = true;
|
|
2070
|
+
const quaternion = new THREE.Quaternion();
|
|
2012
2071
|
|
|
2013
|
-
|
|
2072
|
+
return (cameraObject, alpha, beta, gamma, orient) => {
|
|
2073
|
+
vector.subVectors(cameraObject.target, cameraObject.position);
|
|
2014
2074
|
|
|
2015
|
-
|
|
2016
|
-
if (typeof(window) !== 'undefined') {
|
|
2017
|
-
window.removeEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
|
|
2018
|
-
window.removeEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
|
|
2019
|
-
}
|
|
2020
|
-
scope.enabled = false;
|
|
2075
|
+
euler.set(beta, alpha, -gamma, 'YXZ'); // 'ZXY' for the device, but 'YXZ' for us
|
|
2021
2076
|
|
|
2022
|
-
|
|
2077
|
+
quaternion.setFromEuler(euler); // orient the device
|
|
2023
2078
|
|
|
2024
|
-
|
|
2079
|
+
quaternion.multiply(q1); // camera looks out the back of the device, not the top
|
|
2025
2080
|
|
|
2026
|
-
|
|
2081
|
+
quaternion.multiply(q0.setFromAxisAngle(zee, -orient)); // adjust for screen orientation
|
|
2027
2082
|
|
|
2028
|
-
|
|
2029
|
-
const beta = scope.deviceOrientation.beta ? THREE.MathUtils.degToRad( scope.deviceOrientation.beta ) : 0; // X'
|
|
2030
|
-
const gamma = scope.deviceOrientation.gamma ? THREE.MathUtils.degToRad( scope.deviceOrientation.gamma ) : 0; // Y''
|
|
2031
|
-
const orient = scope.screenOrientation ? THREE.MathUtils.degToRad( scope.screenOrientation ) : 0; // O
|
|
2083
|
+
vector.applyQuaternion(quaternion);
|
|
2032
2084
|
|
|
2033
|
-
|
|
2085
|
+
vector.addVectors(cameraObject.position, vector);
|
|
2034
2086
|
|
|
2035
|
-
|
|
2087
|
+
cameraObject.lookAt(vector);
|
|
2088
|
+
};
|
|
2089
|
+
})();
|
|
2036
2090
|
|
|
2037
|
-
|
|
2091
|
+
this.connect = () => {
|
|
2092
|
+
onScreenOrientationChangeEvent(); // run once on load
|
|
2093
|
+
if (typeof window !== 'undefined') {
|
|
2094
|
+
window.addEventListener('orientationchange', onScreenOrientationChangeEvent, false);
|
|
2095
|
+
window.addEventListener('deviceorientation', onDeviceOrientationChangeEvent, false);
|
|
2096
|
+
}
|
|
2097
|
+
scope.enabled = true;
|
|
2098
|
+
};
|
|
2038
2099
|
|
|
2039
|
-
|
|
2100
|
+
this.disconnect = () => {
|
|
2101
|
+
if (typeof window !== 'undefined') {
|
|
2102
|
+
window.removeEventListener('orientationchange', onScreenOrientationChangeEvent, false);
|
|
2103
|
+
window.removeEventListener('deviceorientation', onDeviceOrientationChangeEvent, false);
|
|
2104
|
+
}
|
|
2105
|
+
scope.enabled = false;
|
|
2106
|
+
};
|
|
2040
2107
|
|
|
2041
|
-
|
|
2108
|
+
this.update = () => {
|
|
2109
|
+
if (scope.enabled === false) return;
|
|
2110
|
+
|
|
2111
|
+
const alpha = scope.deviceOrientation.alpha
|
|
2112
|
+
? THREE.MathUtils.degToRad(scope.deviceOrientation.alpha)
|
|
2113
|
+
: 0; // Z
|
|
2114
|
+
const beta = scope.deviceOrientation.beta
|
|
2115
|
+
? THREE.MathUtils.degToRad(scope.deviceOrientation.beta)
|
|
2116
|
+
: 0; // X'
|
|
2117
|
+
const gamma = scope.deviceOrientation.gamma
|
|
2118
|
+
? THREE.MathUtils.degToRad(scope.deviceOrientation.gamma)
|
|
2119
|
+
: 0; // Y''
|
|
2120
|
+
const orient = scope.screenOrientation ? THREE.MathUtils.degToRad(scope.screenOrientation) : 0; // O
|
|
2121
|
+
|
|
2122
|
+
setObjectQuaternion(scope.object, alpha, beta, gamma, orient);
|
|
2123
|
+
};
|
|
2042
2124
|
|
|
2043
|
-
|
|
2125
|
+
this.dispose = function () {
|
|
2126
|
+
this.disconnect();
|
|
2127
|
+
};
|
|
2044
2128
|
|
|
2129
|
+
this.connect();
|
|
2045
2130
|
};
|
|
2046
2131
|
|
|
2047
2132
|
const NDCCameraControl = function () {
|
|
2048
|
-
|
|
2133
|
+
let camera = undefined;
|
|
2049
2134
|
let targetCamera = undefined;
|
|
2050
2135
|
let defaultViewport = undefined;
|
|
2051
2136
|
const position = new THREE.Vector3();
|
|
@@ -2054,52 +2139,60 @@ const NDCCameraControl = function () {
|
|
|
2054
2139
|
const v2 = new THREE.Vector3();
|
|
2055
2140
|
let eventCallback = undefined;
|
|
2056
2141
|
|
|
2057
|
-
this.setCurrentCameraSettings = (cameraIn, defaultViewportIn)
|
|
2142
|
+
this.setCurrentCameraSettings = (cameraIn, defaultViewportIn) => {
|
|
2058
2143
|
this.near_plane_fly_debt == 0.0;
|
|
2059
2144
|
camera = cameraIn.clone();
|
|
2060
2145
|
targetCamera = cameraIn;
|
|
2061
2146
|
defaultViewport = defaultViewportIn;
|
|
2062
2147
|
camera.near = defaultViewport.nearPlane;
|
|
2063
|
-
if (defaultViewport.farPlane)
|
|
2064
|
-
camera.far = defaultViewport.farPlane;
|
|
2148
|
+
if (defaultViewport.farPlane) camera.far = defaultViewport.farPlane;
|
|
2065
2149
|
if (defaultViewport.eyePosition)
|
|
2066
|
-
camera.position.set(
|
|
2067
|
-
defaultViewport.eyePosition[
|
|
2150
|
+
camera.position.set(
|
|
2151
|
+
defaultViewport.eyePosition[0],
|
|
2152
|
+
defaultViewport.eyePosition[1],
|
|
2153
|
+
defaultViewport.eyePosition[2],
|
|
2154
|
+
);
|
|
2068
2155
|
if (defaultViewport.upVector)
|
|
2069
|
-
camera.up.set(
|
|
2070
|
-
defaultViewport.upVector[
|
|
2156
|
+
camera.up.set(
|
|
2157
|
+
defaultViewport.upVector[0],
|
|
2158
|
+
defaultViewport.upVector[1],
|
|
2159
|
+
defaultViewport.upVector[2],
|
|
2160
|
+
);
|
|
2071
2161
|
if (defaultViewport.targetPosition) {
|
|
2072
|
-
camera.target = new THREE.Vector3(
|
|
2073
|
-
defaultViewport.targetPosition[
|
|
2162
|
+
camera.target = new THREE.Vector3(
|
|
2163
|
+
defaultViewport.targetPosition[0],
|
|
2164
|
+
defaultViewport.targetPosition[1],
|
|
2165
|
+
defaultViewport.targetPosition[2],
|
|
2166
|
+
);
|
|
2074
2167
|
camera.lookAt(camera.target);
|
|
2075
2168
|
}
|
|
2076
2169
|
camera.updateProjectionMatrix();
|
|
2077
2170
|
position.copy(camera.position).project(camera);
|
|
2078
2171
|
target.copy(camera.target).project(camera);
|
|
2079
|
-
}
|
|
2172
|
+
};
|
|
2080
2173
|
|
|
2081
2174
|
this.getCurrentPosition = () => {
|
|
2082
2175
|
target.copy(targetCamera.target).project(camera);
|
|
2083
2176
|
return [target.x, target.y];
|
|
2084
|
-
}
|
|
2177
|
+
};
|
|
2085
2178
|
|
|
2086
|
-
this.zoom = delta => {
|
|
2179
|
+
this.zoom = (delta) => {
|
|
2087
2180
|
let scaledDelta = delta * 0.002;
|
|
2088
2181
|
let zoom = Math.max(targetCamera.zoom - scaledDelta, 1.0);
|
|
2089
2182
|
targetCamera.zoom = zoom;
|
|
2090
2183
|
targetCamera.updateProjectionMatrix();
|
|
2091
|
-
}
|
|
2184
|
+
};
|
|
2092
2185
|
|
|
2093
2186
|
this.zoomToBox = (box, zoom) => {
|
|
2094
2187
|
box.getCenter(v1);
|
|
2095
2188
|
v1.project(camera);
|
|
2096
2189
|
this.setCenterZoom([v1.x, v1.y], zoom);
|
|
2097
|
-
}
|
|
2190
|
+
};
|
|
2098
2191
|
|
|
2099
2192
|
//return top left and size
|
|
2100
2193
|
this.getPanZoom = () => {
|
|
2101
|
-
return {target: this.getCurrentPosition(), zoom: targetCamera.zoom };
|
|
2102
|
-
}
|
|
2194
|
+
return { target: this.getCurrentPosition(), zoom: targetCamera.zoom };
|
|
2195
|
+
};
|
|
2103
2196
|
|
|
2104
2197
|
this.setCenterZoom = (center, zoom) => {
|
|
2105
2198
|
v1.set(center[0], center[1], target.z).unproject(camera);
|
|
@@ -2109,17 +2202,15 @@ const NDCCameraControl = function () {
|
|
|
2109
2202
|
targetCamera.position.add(v2);
|
|
2110
2203
|
targetCamera.zoom = zoom;
|
|
2111
2204
|
targetCamera.updateProjectionMatrix();
|
|
2112
|
-
}
|
|
2205
|
+
};
|
|
2113
2206
|
|
|
2114
2207
|
this.setEventCallback = (callback) => {
|
|
2115
|
-
if (callback === undefined ||
|
|
2116
|
-
|
|
2117
|
-
}
|
|
2208
|
+
if (callback === undefined || typeof callback == 'function') eventCallback = callback;
|
|
2209
|
+
};
|
|
2118
2210
|
|
|
2119
2211
|
this.triggerCallback = () => {
|
|
2120
|
-
if (eventCallback !== undefined &&
|
|
2121
|
-
|
|
2122
|
-
}
|
|
2212
|
+
if (eventCallback !== undefined && typeof eventCallback == 'function') eventCallback();
|
|
2213
|
+
};
|
|
2123
2214
|
};
|
|
2124
2215
|
|
|
2125
2216
|
export {
|
|
@@ -2130,5 +2221,5 @@ export {
|
|
|
2130
2221
|
RayCaster,
|
|
2131
2222
|
CameraAutoTumble,
|
|
2132
2223
|
StereoEffect,
|
|
2133
|
-
NDCCameraControl
|
|
2134
|
-
}
|
|
2224
|
+
NDCCameraControl,
|
|
2225
|
+
};
|