@spiffcommerce/preview 3.6.2-rc.8 → 4.0.0
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/dist/index.esm.js +1576 -38
- package/dist/index.umd.js +1 -0
- package/package.json +4 -6
- package/dist/_tslib.esm.js +0 -33
- package/dist/animation.esm.js +0 -1364
- package/dist/assetCache.esm.js +0 -6
- package/dist/assetCache.esm2.js +0 -825
- package/dist/blurPostProcess.esm.js +0 -327
- package/dist/bumpVertex.esm.js +0 -497
- package/dist/compatibilityOptions.esm.js +0 -68
- package/dist/configuration.esm.js +0 -121
- package/dist/core.esm.js +0 -8135
- package/dist/dynamicTexture.esm.js +0 -105
- package/dist/dynamicTexture.esm2.js +0 -238
- package/dist/easing.esm.js +0 -130
- package/dist/effectFallbacks.esm.js +0 -378
- package/dist/engine.esm.js +0 -25504
- package/dist/glbLoaderExtensions.esm.js +0 -690
- package/dist/glowLayer.esm.js +0 -1621
- package/dist/glowLayerManager.esm.js +0 -50
- package/dist/guid.esm.js +0 -21
- package/dist/hdrFilteringFunctions.esm.js +0 -816
- package/dist/helperFunctions.esm.js +0 -5145
- package/dist/material.esm.js +0 -115
- package/dist/material.esm2.js +0 -5245
- package/dist/math.axis.esm.js +0 -35
- package/dist/math.color.esm.js +0 -1661
- package/dist/math.path.esm.js +0 -15
- package/dist/math.size.esm.js +0 -137
- package/dist/mesh.esm.js +0 -11170
- package/dist/modelContainer.esm.js +0 -1895
- package/dist/node.esm.js +0 -795
- package/dist/pbrBRDFFunctions.esm.js +0 -124
- package/dist/pbrMaterial.esm.js +8 -8739
- package/dist/productAnimations.esm.js +0 -182
- package/dist/productCamera.esm.js +0 -14
- package/dist/productCamera.esm2.js +0 -3870
- package/dist/renderConstants.esm.js +0 -116
- package/dist/renderingPipeline.esm.js +0 -18
- package/dist/renderingPipeline.esm2.js +1 -3594
- package/dist/sceneLoaderFlags.esm.js +0 -51
- package/dist/types.esm.js +0 -30
- package/dist/variants.esm.js +0 -16
- package/dist/variants.esm2.js +0 -3097
- package/dist/webRequest.esm.js +0 -7777
|
@@ -1,3870 +0,0 @@
|
|
|
1
|
-
import { O as Observable, V as Vector3, b as Vector2, M as Matrix, _ as __decorate, Q as Quaternion, T as TmpVectors, d as serializeAsVector3, s as serialize, c as serializeAsMeshReference, S as SerializationHelper, h as serializeAsVector2 } from './webRequest.esm.js';
|
|
2
|
-
import { N as Node } from './node.esm.js';
|
|
3
|
-
import { M as Mesh } from './mesh.esm.js';
|
|
4
|
-
import { l as PointerEventTypes, m as PrecisionDate, L as Logger, c as Tools, K as KeyboardEventTypes, n as EventConstants, P as Plane } from './engine.esm.js';
|
|
5
|
-
import { E as Epsilon, S as Scalar } from './math.color.esm.js';
|
|
6
|
-
import { B as BackEase, E as EasingFunction, a as ExponentialEase } from './easing.esm.js';
|
|
7
|
-
import { A as Animation } from './animation.esm.js';
|
|
8
|
-
import { C as Camera } from './material.esm2.js';
|
|
9
|
-
import { A as Axis } from './math.axis.esm.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* The autoRotation behavior (AutoRotationBehavior) is designed to create a smooth rotation of an ArcRotateCamera when there is no user interaction.
|
|
13
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors/cameraBehaviors#autorotation-behavior
|
|
14
|
-
*/
|
|
15
|
-
class AutoRotationBehavior {
|
|
16
|
-
constructor() {
|
|
17
|
-
this._zoomStopsAnimation = false;
|
|
18
|
-
this._idleRotationSpeed = 0.05;
|
|
19
|
-
this._idleRotationWaitTime = 2000;
|
|
20
|
-
this._idleRotationSpinupTime = 2000;
|
|
21
|
-
this.targetAlpha = null;
|
|
22
|
-
this._isPointerDown = false;
|
|
23
|
-
this._lastFrameTime = null;
|
|
24
|
-
this._lastInteractionTime = -Infinity;
|
|
25
|
-
this._cameraRotationSpeed = 0;
|
|
26
|
-
this._lastFrameRadius = 0;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Gets the name of the behavior.
|
|
30
|
-
*/
|
|
31
|
-
get name() {
|
|
32
|
-
return "AutoRotation";
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Sets the flag that indicates if user zooming should stop animation.
|
|
36
|
-
*/
|
|
37
|
-
set zoomStopsAnimation(flag) {
|
|
38
|
-
this._zoomStopsAnimation = flag;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Gets the flag that indicates if user zooming should stop animation.
|
|
42
|
-
*/
|
|
43
|
-
get zoomStopsAnimation() {
|
|
44
|
-
return this._zoomStopsAnimation;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Sets the default speed at which the camera rotates around the model.
|
|
48
|
-
*/
|
|
49
|
-
set idleRotationSpeed(speed) {
|
|
50
|
-
this._idleRotationSpeed = speed;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Gets the default speed at which the camera rotates around the model.
|
|
54
|
-
*/
|
|
55
|
-
get idleRotationSpeed() {
|
|
56
|
-
return this._idleRotationSpeed;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Sets the time (in milliseconds) to wait after user interaction before the camera starts rotating.
|
|
60
|
-
*/
|
|
61
|
-
set idleRotationWaitTime(time) {
|
|
62
|
-
this._idleRotationWaitTime = time;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Gets the time (milliseconds) to wait after user interaction before the camera starts rotating.
|
|
66
|
-
*/
|
|
67
|
-
get idleRotationWaitTime() {
|
|
68
|
-
return this._idleRotationWaitTime;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Sets the time (milliseconds) to take to spin up to the full idle rotation speed.
|
|
72
|
-
*/
|
|
73
|
-
set idleRotationSpinupTime(time) {
|
|
74
|
-
this._idleRotationSpinupTime = time;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Gets the time (milliseconds) to take to spin up to the full idle rotation speed.
|
|
78
|
-
*/
|
|
79
|
-
get idleRotationSpinupTime() {
|
|
80
|
-
return this._idleRotationSpinupTime;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Gets a value indicating if the camera is currently rotating because of this behavior
|
|
84
|
-
*/
|
|
85
|
-
get rotationInProgress() {
|
|
86
|
-
return Math.abs(this._cameraRotationSpeed) > 0;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Initializes the behavior.
|
|
90
|
-
*/
|
|
91
|
-
init() {
|
|
92
|
-
// Do nothing
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Attaches the behavior to its arc rotate camera.
|
|
96
|
-
* @param camera Defines the camera to attach the behavior to
|
|
97
|
-
*/
|
|
98
|
-
attach(camera) {
|
|
99
|
-
this._attachedCamera = camera;
|
|
100
|
-
const scene = this._attachedCamera.getScene();
|
|
101
|
-
this._onPrePointerObservableObserver = scene.onPrePointerObservable.add((pointerInfoPre) => {
|
|
102
|
-
if (pointerInfoPre.type === PointerEventTypes.POINTERDOWN) {
|
|
103
|
-
this._isPointerDown = true;
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (pointerInfoPre.type === PointerEventTypes.POINTERUP) {
|
|
107
|
-
this._isPointerDown = false;
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(() => {
|
|
111
|
-
if (this._reachTargetAlpha()) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
const now = PrecisionDate.Now;
|
|
115
|
-
let dt = 0;
|
|
116
|
-
if (this._lastFrameTime != null) {
|
|
117
|
-
dt = now - this._lastFrameTime;
|
|
118
|
-
}
|
|
119
|
-
this._lastFrameTime = now;
|
|
120
|
-
// Stop the animation if there is user interaction and the animation should stop for this interaction
|
|
121
|
-
this._applyUserInteraction();
|
|
122
|
-
const timeToRotation = now - this._lastInteractionTime - this._idleRotationWaitTime;
|
|
123
|
-
const scale = Math.max(Math.min(timeToRotation / this._idleRotationSpinupTime, 1), 0);
|
|
124
|
-
this._cameraRotationSpeed = this._idleRotationSpeed * scale;
|
|
125
|
-
// Step camera rotation by rotation speed
|
|
126
|
-
if (this._attachedCamera) {
|
|
127
|
-
this._attachedCamera.alpha -= this._cameraRotationSpeed * (dt / 1000);
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Detaches the behavior from its current arc rotate camera.
|
|
133
|
-
*/
|
|
134
|
-
detach() {
|
|
135
|
-
if (!this._attachedCamera) {
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
const scene = this._attachedCamera.getScene();
|
|
139
|
-
if (this._onPrePointerObservableObserver) {
|
|
140
|
-
scene.onPrePointerObservable.remove(this._onPrePointerObservableObserver);
|
|
141
|
-
}
|
|
142
|
-
this._attachedCamera.onAfterCheckInputsObservable.remove(this._onAfterCheckInputsObserver);
|
|
143
|
-
this._attachedCamera = null;
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Force-reset the last interaction time
|
|
147
|
-
* @param customTime an optional time that will be used instead of the current last interaction time. For example `Date.now()`
|
|
148
|
-
*/
|
|
149
|
-
resetLastInteractionTime(customTime) {
|
|
150
|
-
this._lastInteractionTime = customTime !== null && customTime !== void 0 ? customTime : PrecisionDate.Now;
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Returns true if camera alpha reaches the target alpha
|
|
154
|
-
* @returns true if camera alpha reaches the target alpha
|
|
155
|
-
*/
|
|
156
|
-
_reachTargetAlpha() {
|
|
157
|
-
if (this._attachedCamera && this.targetAlpha) {
|
|
158
|
-
return Math.abs(this._attachedCamera.alpha - this.targetAlpha) < Epsilon;
|
|
159
|
-
}
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Returns true if user is scrolling.
|
|
164
|
-
* @returns true if user is scrolling.
|
|
165
|
-
*/
|
|
166
|
-
_userIsZooming() {
|
|
167
|
-
if (!this._attachedCamera) {
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
return this._attachedCamera.inertialRadiusOffset !== 0;
|
|
171
|
-
}
|
|
172
|
-
_shouldAnimationStopForInteraction() {
|
|
173
|
-
if (!this._attachedCamera) {
|
|
174
|
-
return false;
|
|
175
|
-
}
|
|
176
|
-
let zoomHasHitLimit = false;
|
|
177
|
-
if (this._lastFrameRadius === this._attachedCamera.radius && this._attachedCamera.inertialRadiusOffset !== 0) {
|
|
178
|
-
zoomHasHitLimit = true;
|
|
179
|
-
}
|
|
180
|
-
// Update the record of previous radius - works as an approx. indicator of hitting radius limits
|
|
181
|
-
this._lastFrameRadius = this._attachedCamera.radius;
|
|
182
|
-
return this._zoomStopsAnimation ? zoomHasHitLimit : this._userIsZooming();
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Applies any current user interaction to the camera. Takes into account maximum alpha rotation.
|
|
186
|
-
*/
|
|
187
|
-
_applyUserInteraction() {
|
|
188
|
-
if (this._userIsMoving() && !this._shouldAnimationStopForInteraction()) {
|
|
189
|
-
this._lastInteractionTime = PrecisionDate.Now;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
// Tools
|
|
193
|
-
_userIsMoving() {
|
|
194
|
-
if (!this._attachedCamera) {
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
return (this._attachedCamera.inertialAlphaOffset !== 0 ||
|
|
198
|
-
this._attachedCamera.inertialBetaOffset !== 0 ||
|
|
199
|
-
this._attachedCamera.inertialRadiusOffset !== 0 ||
|
|
200
|
-
this._attachedCamera.inertialPanningX !== 0 ||
|
|
201
|
-
this._attachedCamera.inertialPanningY !== 0 ||
|
|
202
|
-
this._isPointerDown);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Add a bouncing effect to an ArcRotateCamera when reaching a specified minimum and maximum radius
|
|
208
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors/cameraBehaviors#bouncing-behavior
|
|
209
|
-
*/
|
|
210
|
-
class BouncingBehavior {
|
|
211
|
-
constructor() {
|
|
212
|
-
/**
|
|
213
|
-
* The duration of the animation, in milliseconds
|
|
214
|
-
*/
|
|
215
|
-
this.transitionDuration = 450;
|
|
216
|
-
/**
|
|
217
|
-
* Length of the distance animated by the transition when lower radius is reached
|
|
218
|
-
*/
|
|
219
|
-
this.lowerRadiusTransitionRange = 2;
|
|
220
|
-
/**
|
|
221
|
-
* Length of the distance animated by the transition when upper radius is reached
|
|
222
|
-
*/
|
|
223
|
-
this.upperRadiusTransitionRange = -2;
|
|
224
|
-
this._autoTransitionRange = false;
|
|
225
|
-
// Animations
|
|
226
|
-
this._radiusIsAnimating = false;
|
|
227
|
-
this._radiusBounceTransition = null;
|
|
228
|
-
this._animatables = new Array();
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Gets the name of the behavior.
|
|
232
|
-
*/
|
|
233
|
-
get name() {
|
|
234
|
-
return "Bouncing";
|
|
235
|
-
}
|
|
236
|
-
/**
|
|
237
|
-
* Gets a value indicating if the lowerRadiusTransitionRange and upperRadiusTransitionRange are defined automatically
|
|
238
|
-
*/
|
|
239
|
-
get autoTransitionRange() {
|
|
240
|
-
return this._autoTransitionRange;
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* Sets a value indicating if the lowerRadiusTransitionRange and upperRadiusTransitionRange are defined automatically
|
|
244
|
-
* Transition ranges will be set to 5% of the bounding box diagonal in world space
|
|
245
|
-
*/
|
|
246
|
-
set autoTransitionRange(value) {
|
|
247
|
-
if (this._autoTransitionRange === value) {
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
this._autoTransitionRange = value;
|
|
251
|
-
const camera = this._attachedCamera;
|
|
252
|
-
if (!camera) {
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
if (value) {
|
|
256
|
-
this._onMeshTargetChangedObserver = camera.onMeshTargetChangedObservable.add((mesh) => {
|
|
257
|
-
if (!mesh) {
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
mesh.computeWorldMatrix(true);
|
|
261
|
-
const diagonal = mesh.getBoundingInfo().diagonalLength;
|
|
262
|
-
this.lowerRadiusTransitionRange = diagonal * 0.05;
|
|
263
|
-
this.upperRadiusTransitionRange = diagonal * 0.05;
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
else if (this._onMeshTargetChangedObserver) {
|
|
267
|
-
camera.onMeshTargetChangedObservable.remove(this._onMeshTargetChangedObserver);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* Initializes the behavior.
|
|
272
|
-
*/
|
|
273
|
-
init() {
|
|
274
|
-
// Do nothing
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Attaches the behavior to its arc rotate camera.
|
|
278
|
-
* @param camera Defines the camera to attach the behavior to
|
|
279
|
-
*/
|
|
280
|
-
attach(camera) {
|
|
281
|
-
this._attachedCamera = camera;
|
|
282
|
-
this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(() => {
|
|
283
|
-
if (!this._attachedCamera) {
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
// Add the bounce animation to the lower radius limit
|
|
287
|
-
if (this._isRadiusAtLimit(this._attachedCamera.lowerRadiusLimit)) {
|
|
288
|
-
this._applyBoundRadiusAnimation(this.lowerRadiusTransitionRange);
|
|
289
|
-
}
|
|
290
|
-
// Add the bounce animation to the upper radius limit
|
|
291
|
-
if (this._isRadiusAtLimit(this._attachedCamera.upperRadiusLimit)) {
|
|
292
|
-
this._applyBoundRadiusAnimation(this.upperRadiusTransitionRange);
|
|
293
|
-
}
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Detaches the behavior from its current arc rotate camera.
|
|
298
|
-
*/
|
|
299
|
-
detach() {
|
|
300
|
-
if (!this._attachedCamera) {
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
if (this._onAfterCheckInputsObserver) {
|
|
304
|
-
this._attachedCamera.onAfterCheckInputsObservable.remove(this._onAfterCheckInputsObserver);
|
|
305
|
-
}
|
|
306
|
-
if (this._onMeshTargetChangedObserver) {
|
|
307
|
-
this._attachedCamera.onMeshTargetChangedObservable.remove(this._onMeshTargetChangedObserver);
|
|
308
|
-
}
|
|
309
|
-
this._attachedCamera = null;
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Checks if the camera radius is at the specified limit. Takes into account animation locks.
|
|
313
|
-
* @param radiusLimit The limit to check against.
|
|
314
|
-
* @returns Bool to indicate if at limit.
|
|
315
|
-
*/
|
|
316
|
-
_isRadiusAtLimit(radiusLimit) {
|
|
317
|
-
if (!this._attachedCamera) {
|
|
318
|
-
return false;
|
|
319
|
-
}
|
|
320
|
-
if (this._attachedCamera.radius === radiusLimit && !this._radiusIsAnimating) {
|
|
321
|
-
return true;
|
|
322
|
-
}
|
|
323
|
-
return false;
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* Applies an animation to the radius of the camera, extending by the radiusDelta.
|
|
327
|
-
* @param radiusDelta The delta by which to animate to. Can be negative.
|
|
328
|
-
*/
|
|
329
|
-
_applyBoundRadiusAnimation(radiusDelta) {
|
|
330
|
-
if (!this._attachedCamera) {
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
if (!this._radiusBounceTransition) {
|
|
334
|
-
BouncingBehavior.EasingFunction.setEasingMode(BouncingBehavior.EasingMode);
|
|
335
|
-
this._radiusBounceTransition = Animation.CreateAnimation("radius", Animation.ANIMATIONTYPE_FLOAT, 60, BouncingBehavior.EasingFunction);
|
|
336
|
-
}
|
|
337
|
-
// Prevent zoom until bounce has completed
|
|
338
|
-
this._cachedWheelPrecision = this._attachedCamera.wheelPrecision;
|
|
339
|
-
this._attachedCamera.wheelPrecision = Infinity;
|
|
340
|
-
this._attachedCamera.inertialRadiusOffset = 0;
|
|
341
|
-
// Animate to the radius limit
|
|
342
|
-
this.stopAllAnimations();
|
|
343
|
-
this._radiusIsAnimating = true;
|
|
344
|
-
const animatable = Animation.TransitionTo("radius", this._attachedCamera.radius + radiusDelta, this._attachedCamera, this._attachedCamera.getScene(), 60, this._radiusBounceTransition, this.transitionDuration, () => this._clearAnimationLocks());
|
|
345
|
-
if (animatable) {
|
|
346
|
-
this._animatables.push(animatable);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
/**
|
|
350
|
-
* Removes all animation locks. Allows new animations to be added to any of the camera properties.
|
|
351
|
-
*/
|
|
352
|
-
_clearAnimationLocks() {
|
|
353
|
-
this._radiusIsAnimating = false;
|
|
354
|
-
if (this._attachedCamera) {
|
|
355
|
-
this._attachedCamera.wheelPrecision = this._cachedWheelPrecision;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* Stops and removes all animations that have been applied to the camera
|
|
360
|
-
*/
|
|
361
|
-
stopAllAnimations() {
|
|
362
|
-
if (this._attachedCamera) {
|
|
363
|
-
this._attachedCamera.animations = [];
|
|
364
|
-
}
|
|
365
|
-
while (this._animatables.length) {
|
|
366
|
-
this._animatables[0].onAnimationEnd = null;
|
|
367
|
-
this._animatables[0].stop();
|
|
368
|
-
this._animatables.shift();
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* The easing function used by animations
|
|
374
|
-
*/
|
|
375
|
-
BouncingBehavior.EasingFunction = new BackEase(0.3);
|
|
376
|
-
/**
|
|
377
|
-
* The easing mode used by animations
|
|
378
|
-
*/
|
|
379
|
-
BouncingBehavior.EasingMode = EasingFunction.EASINGMODE_EASEOUT;
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* The framing behavior (FramingBehavior) is designed to automatically position an ArcRotateCamera when its target is set to a mesh. It is also useful if you want to prevent the camera to go under a virtual horizontal plane.
|
|
383
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors/cameraBehaviors#framing-behavior
|
|
384
|
-
*/
|
|
385
|
-
class FramingBehavior {
|
|
386
|
-
constructor() {
|
|
387
|
-
/**
|
|
388
|
-
* An event triggered when the animation to zoom on target mesh has ended
|
|
389
|
-
*/
|
|
390
|
-
this.onTargetFramingAnimationEndObservable = new Observable();
|
|
391
|
-
this._mode = FramingBehavior.FitFrustumSidesMode;
|
|
392
|
-
this._radiusScale = 1.0;
|
|
393
|
-
this._positionScale = 0.5;
|
|
394
|
-
this._defaultElevation = 0.3;
|
|
395
|
-
this._elevationReturnTime = 1500;
|
|
396
|
-
this._elevationReturnWaitTime = 1000;
|
|
397
|
-
this._zoomStopsAnimation = false;
|
|
398
|
-
this._framingTime = 1500;
|
|
399
|
-
/**
|
|
400
|
-
* Define if the behavior should automatically change the configured
|
|
401
|
-
* camera limits and sensibilities.
|
|
402
|
-
*/
|
|
403
|
-
this.autoCorrectCameraLimitsAndSensibility = true;
|
|
404
|
-
this._isPointerDown = false;
|
|
405
|
-
this._lastInteractionTime = -Infinity;
|
|
406
|
-
// Framing control
|
|
407
|
-
this._animatables = new Array();
|
|
408
|
-
this._betaIsAnimating = false;
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* Gets the name of the behavior.
|
|
412
|
-
*/
|
|
413
|
-
get name() {
|
|
414
|
-
return "Framing";
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Sets the current mode used by the behavior
|
|
418
|
-
*/
|
|
419
|
-
set mode(mode) {
|
|
420
|
-
this._mode = mode;
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
|
-
* Gets current mode used by the behavior.
|
|
424
|
-
*/
|
|
425
|
-
get mode() {
|
|
426
|
-
return this._mode;
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Sets the scale applied to the radius (1 by default)
|
|
430
|
-
*/
|
|
431
|
-
set radiusScale(radius) {
|
|
432
|
-
this._radiusScale = radius;
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* Gets the scale applied to the radius
|
|
436
|
-
*/
|
|
437
|
-
get radiusScale() {
|
|
438
|
-
return this._radiusScale;
|
|
439
|
-
}
|
|
440
|
-
/**
|
|
441
|
-
* Sets the scale to apply on Y axis to position camera focus. 0.5 by default which means the center of the bounding box.
|
|
442
|
-
*/
|
|
443
|
-
set positionScale(scale) {
|
|
444
|
-
this._positionScale = scale;
|
|
445
|
-
}
|
|
446
|
-
/**
|
|
447
|
-
* Gets the scale to apply on Y axis to position camera focus. 0.5 by default which means the center of the bounding box.
|
|
448
|
-
*/
|
|
449
|
-
get positionScale() {
|
|
450
|
-
return this._positionScale;
|
|
451
|
-
}
|
|
452
|
-
/**
|
|
453
|
-
* Sets the angle above/below the horizontal plane to return to when the return to default elevation idle
|
|
454
|
-
* behaviour is triggered, in radians.
|
|
455
|
-
*/
|
|
456
|
-
set defaultElevation(elevation) {
|
|
457
|
-
this._defaultElevation = elevation;
|
|
458
|
-
}
|
|
459
|
-
/**
|
|
460
|
-
* Gets the angle above/below the horizontal plane to return to when the return to default elevation idle
|
|
461
|
-
* behaviour is triggered, in radians.
|
|
462
|
-
*/
|
|
463
|
-
get defaultElevation() {
|
|
464
|
-
return this._defaultElevation;
|
|
465
|
-
}
|
|
466
|
-
/**
|
|
467
|
-
* Sets the time (in milliseconds) taken to return to the default beta position.
|
|
468
|
-
* Negative value indicates camera should not return to default.
|
|
469
|
-
*/
|
|
470
|
-
set elevationReturnTime(speed) {
|
|
471
|
-
this._elevationReturnTime = speed;
|
|
472
|
-
}
|
|
473
|
-
/**
|
|
474
|
-
* Gets the time (in milliseconds) taken to return to the default beta position.
|
|
475
|
-
* Negative value indicates camera should not return to default.
|
|
476
|
-
*/
|
|
477
|
-
get elevationReturnTime() {
|
|
478
|
-
return this._elevationReturnTime;
|
|
479
|
-
}
|
|
480
|
-
/**
|
|
481
|
-
* Sets the delay (in milliseconds) taken before the camera returns to the default beta position.
|
|
482
|
-
*/
|
|
483
|
-
set elevationReturnWaitTime(time) {
|
|
484
|
-
this._elevationReturnWaitTime = time;
|
|
485
|
-
}
|
|
486
|
-
/**
|
|
487
|
-
* Gets the delay (in milliseconds) taken before the camera returns to the default beta position.
|
|
488
|
-
*/
|
|
489
|
-
get elevationReturnWaitTime() {
|
|
490
|
-
return this._elevationReturnWaitTime;
|
|
491
|
-
}
|
|
492
|
-
/**
|
|
493
|
-
* Sets the flag that indicates if user zooming should stop animation.
|
|
494
|
-
*/
|
|
495
|
-
set zoomStopsAnimation(flag) {
|
|
496
|
-
this._zoomStopsAnimation = flag;
|
|
497
|
-
}
|
|
498
|
-
/**
|
|
499
|
-
* Gets the flag that indicates if user zooming should stop animation.
|
|
500
|
-
*/
|
|
501
|
-
get zoomStopsAnimation() {
|
|
502
|
-
return this._zoomStopsAnimation;
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* Sets the transition time when framing the mesh, in milliseconds
|
|
506
|
-
*/
|
|
507
|
-
set framingTime(time) {
|
|
508
|
-
this._framingTime = time;
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* Gets the transition time when framing the mesh, in milliseconds
|
|
512
|
-
*/
|
|
513
|
-
get framingTime() {
|
|
514
|
-
return this._framingTime;
|
|
515
|
-
}
|
|
516
|
-
/**
|
|
517
|
-
* Initializes the behavior.
|
|
518
|
-
*/
|
|
519
|
-
init() {
|
|
520
|
-
// Do nothing
|
|
521
|
-
}
|
|
522
|
-
/**
|
|
523
|
-
* Attaches the behavior to its arc rotate camera.
|
|
524
|
-
* @param camera Defines the camera to attach the behavior to
|
|
525
|
-
*/
|
|
526
|
-
attach(camera) {
|
|
527
|
-
this._attachedCamera = camera;
|
|
528
|
-
const scene = this._attachedCamera.getScene();
|
|
529
|
-
FramingBehavior.EasingFunction.setEasingMode(FramingBehavior.EasingMode);
|
|
530
|
-
this._onPrePointerObservableObserver = scene.onPrePointerObservable.add((pointerInfoPre) => {
|
|
531
|
-
if (pointerInfoPre.type === PointerEventTypes.POINTERDOWN) {
|
|
532
|
-
this._isPointerDown = true;
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
if (pointerInfoPre.type === PointerEventTypes.POINTERUP) {
|
|
536
|
-
this._isPointerDown = false;
|
|
537
|
-
}
|
|
538
|
-
});
|
|
539
|
-
this._onMeshTargetChangedObserver = camera.onMeshTargetChangedObservable.add((mesh) => {
|
|
540
|
-
if (mesh) {
|
|
541
|
-
this.zoomOnMesh(mesh, undefined, () => {
|
|
542
|
-
this.onTargetFramingAnimationEndObservable.notifyObservers();
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
});
|
|
546
|
-
this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(() => {
|
|
547
|
-
// Stop the animation if there is user interaction and the animation should stop for this interaction
|
|
548
|
-
this._applyUserInteraction();
|
|
549
|
-
// Maintain the camera above the ground. If the user pulls the camera beneath the ground plane, lift it
|
|
550
|
-
// back to the default position after a given timeout
|
|
551
|
-
this._maintainCameraAboveGround();
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
/**
|
|
555
|
-
* Detaches the behavior from its current arc rotate camera.
|
|
556
|
-
*/
|
|
557
|
-
detach() {
|
|
558
|
-
if (!this._attachedCamera) {
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
561
|
-
const scene = this._attachedCamera.getScene();
|
|
562
|
-
if (this._onPrePointerObservableObserver) {
|
|
563
|
-
scene.onPrePointerObservable.remove(this._onPrePointerObservableObserver);
|
|
564
|
-
}
|
|
565
|
-
if (this._onAfterCheckInputsObserver) {
|
|
566
|
-
this._attachedCamera.onAfterCheckInputsObservable.remove(this._onAfterCheckInputsObserver);
|
|
567
|
-
}
|
|
568
|
-
if (this._onMeshTargetChangedObserver) {
|
|
569
|
-
this._attachedCamera.onMeshTargetChangedObservable.remove(this._onMeshTargetChangedObserver);
|
|
570
|
-
}
|
|
571
|
-
this._attachedCamera = null;
|
|
572
|
-
}
|
|
573
|
-
/**
|
|
574
|
-
* Targets the given mesh and updates zoom level accordingly.
|
|
575
|
-
* @param mesh The mesh to target.
|
|
576
|
-
* @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
|
|
577
|
-
* @param onAnimationEnd Callback triggered at the end of the framing animation
|
|
578
|
-
*/
|
|
579
|
-
zoomOnMesh(mesh, focusOnOriginXZ = false, onAnimationEnd = null) {
|
|
580
|
-
mesh.computeWorldMatrix(true);
|
|
581
|
-
const boundingBox = mesh.getBoundingInfo().boundingBox;
|
|
582
|
-
this.zoomOnBoundingInfo(boundingBox.minimumWorld, boundingBox.maximumWorld, focusOnOriginXZ, onAnimationEnd);
|
|
583
|
-
}
|
|
584
|
-
/**
|
|
585
|
-
* Targets the given mesh with its children and updates zoom level accordingly.
|
|
586
|
-
* @param mesh The mesh to target.
|
|
587
|
-
* @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
|
|
588
|
-
* @param onAnimationEnd Callback triggered at the end of the framing animation
|
|
589
|
-
*/
|
|
590
|
-
zoomOnMeshHierarchy(mesh, focusOnOriginXZ = false, onAnimationEnd = null) {
|
|
591
|
-
mesh.computeWorldMatrix(true);
|
|
592
|
-
const boundingBox = mesh.getHierarchyBoundingVectors(true);
|
|
593
|
-
this.zoomOnBoundingInfo(boundingBox.min, boundingBox.max, focusOnOriginXZ, onAnimationEnd);
|
|
594
|
-
}
|
|
595
|
-
/**
|
|
596
|
-
* Targets the given meshes with their children and updates zoom level accordingly.
|
|
597
|
-
* @param meshes The mesh to target.
|
|
598
|
-
* @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
|
|
599
|
-
* @param onAnimationEnd Callback triggered at the end of the framing animation
|
|
600
|
-
*/
|
|
601
|
-
zoomOnMeshesHierarchy(meshes, focusOnOriginXZ = false, onAnimationEnd = null) {
|
|
602
|
-
const min = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
|
|
603
|
-
const max = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
|
|
604
|
-
for (let i = 0; i < meshes.length; i++) {
|
|
605
|
-
const boundingInfo = meshes[i].getHierarchyBoundingVectors(true);
|
|
606
|
-
Vector3.CheckExtends(boundingInfo.min, min, max);
|
|
607
|
-
Vector3.CheckExtends(boundingInfo.max, min, max);
|
|
608
|
-
}
|
|
609
|
-
this.zoomOnBoundingInfo(min, max, focusOnOriginXZ, onAnimationEnd);
|
|
610
|
-
}
|
|
611
|
-
/**
|
|
612
|
-
* Targets the bounding box info defined by its extends and updates zoom level accordingly.
|
|
613
|
-
* @param minimumWorld Determines the smaller position of the bounding box extend
|
|
614
|
-
* @param maximumWorld Determines the bigger position of the bounding box extend
|
|
615
|
-
* @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
|
|
616
|
-
* @param onAnimationEnd Callback triggered at the end of the framing animation
|
|
617
|
-
*/
|
|
618
|
-
zoomOnBoundingInfo(minimumWorld, maximumWorld, focusOnOriginXZ = false, onAnimationEnd = null) {
|
|
619
|
-
let zoomTarget;
|
|
620
|
-
if (!this._attachedCamera) {
|
|
621
|
-
return;
|
|
622
|
-
}
|
|
623
|
-
// Find target by interpolating from bottom of bounding box in world-space to top via framingPositionY
|
|
624
|
-
const bottom = minimumWorld.y;
|
|
625
|
-
const top = maximumWorld.y;
|
|
626
|
-
const zoomTargetY = bottom + (top - bottom) * this._positionScale;
|
|
627
|
-
const radiusWorld = maximumWorld.subtract(minimumWorld).scale(0.5);
|
|
628
|
-
if (focusOnOriginXZ) {
|
|
629
|
-
zoomTarget = new Vector3(0, zoomTargetY, 0);
|
|
630
|
-
}
|
|
631
|
-
else {
|
|
632
|
-
const centerWorld = minimumWorld.add(radiusWorld);
|
|
633
|
-
zoomTarget = new Vector3(centerWorld.x, zoomTargetY, centerWorld.z);
|
|
634
|
-
}
|
|
635
|
-
if (!this._vectorTransition) {
|
|
636
|
-
this._vectorTransition = Animation.CreateAnimation("target", Animation.ANIMATIONTYPE_VECTOR3, 60, FramingBehavior.EasingFunction);
|
|
637
|
-
}
|
|
638
|
-
this._betaIsAnimating = true;
|
|
639
|
-
let animatable = Animation.TransitionTo("target", zoomTarget, this._attachedCamera, this._attachedCamera.getScene(), 60, this._vectorTransition, this._framingTime);
|
|
640
|
-
if (animatable) {
|
|
641
|
-
this._animatables.push(animatable);
|
|
642
|
-
}
|
|
643
|
-
// sets the radius and lower radius bounds
|
|
644
|
-
// Small delta ensures camera is not always at lower zoom limit.
|
|
645
|
-
let radius = 0;
|
|
646
|
-
if (this._mode === FramingBehavior.FitFrustumSidesMode) {
|
|
647
|
-
const position = this._calculateLowerRadiusFromModelBoundingSphere(minimumWorld, maximumWorld);
|
|
648
|
-
if (this.autoCorrectCameraLimitsAndSensibility) {
|
|
649
|
-
this._attachedCamera.lowerRadiusLimit = radiusWorld.length() + this._attachedCamera.minZ;
|
|
650
|
-
}
|
|
651
|
-
radius = position;
|
|
652
|
-
}
|
|
653
|
-
else if (this._mode === FramingBehavior.IgnoreBoundsSizeMode) {
|
|
654
|
-
radius = this._calculateLowerRadiusFromModelBoundingSphere(minimumWorld, maximumWorld);
|
|
655
|
-
if (this.autoCorrectCameraLimitsAndSensibility && this._attachedCamera.lowerRadiusLimit === null) {
|
|
656
|
-
this._attachedCamera.lowerRadiusLimit = this._attachedCamera.minZ;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
// Set sensibilities
|
|
660
|
-
if (this.autoCorrectCameraLimitsAndSensibility) {
|
|
661
|
-
const extend = maximumWorld.subtract(minimumWorld).length();
|
|
662
|
-
this._attachedCamera.panningSensibility = 5000 / extend;
|
|
663
|
-
this._attachedCamera.wheelPrecision = 100 / radius;
|
|
664
|
-
}
|
|
665
|
-
// transition to new radius
|
|
666
|
-
if (!this._radiusTransition) {
|
|
667
|
-
this._radiusTransition = Animation.CreateAnimation("radius", Animation.ANIMATIONTYPE_FLOAT, 60, FramingBehavior.EasingFunction);
|
|
668
|
-
}
|
|
669
|
-
animatable = Animation.TransitionTo("radius", radius, this._attachedCamera, this._attachedCamera.getScene(), 60, this._radiusTransition, this._framingTime, () => {
|
|
670
|
-
this.stopAllAnimations();
|
|
671
|
-
if (onAnimationEnd) {
|
|
672
|
-
onAnimationEnd();
|
|
673
|
-
}
|
|
674
|
-
if (this._attachedCamera && this._attachedCamera.useInputToRestoreState) {
|
|
675
|
-
this._attachedCamera.storeState();
|
|
676
|
-
}
|
|
677
|
-
});
|
|
678
|
-
if (animatable) {
|
|
679
|
-
this._animatables.push(animatable);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
/**
|
|
683
|
-
* Calculates the lowest radius for the camera based on the bounding box of the mesh.
|
|
684
|
-
* @param minimumWorld
|
|
685
|
-
* @param maximumWorld
|
|
686
|
-
* @returns The minimum distance from the primary mesh's center point at which the camera must be kept in order
|
|
687
|
-
* to fully enclose the mesh in the viewing frustum.
|
|
688
|
-
*/
|
|
689
|
-
_calculateLowerRadiusFromModelBoundingSphere(minimumWorld, maximumWorld) {
|
|
690
|
-
const size = maximumWorld.subtract(minimumWorld);
|
|
691
|
-
const boxVectorGlobalDiagonal = size.length();
|
|
692
|
-
const frustumSlope = this._getFrustumSlope();
|
|
693
|
-
// Formula for setting distance
|
|
694
|
-
// (Good explanation: http://stackoverflow.com/questions/2866350/move-camera-to-fit-3d-scene)
|
|
695
|
-
const radiusWithoutFraming = boxVectorGlobalDiagonal * 0.5;
|
|
696
|
-
// Horizon distance
|
|
697
|
-
const radius = radiusWithoutFraming * this._radiusScale;
|
|
698
|
-
const distanceForHorizontalFrustum = radius * Math.sqrt(1.0 + 1.0 / (frustumSlope.x * frustumSlope.x));
|
|
699
|
-
const distanceForVerticalFrustum = radius * Math.sqrt(1.0 + 1.0 / (frustumSlope.y * frustumSlope.y));
|
|
700
|
-
let distance = Math.max(distanceForHorizontalFrustum, distanceForVerticalFrustum);
|
|
701
|
-
const camera = this._attachedCamera;
|
|
702
|
-
if (!camera) {
|
|
703
|
-
return 0;
|
|
704
|
-
}
|
|
705
|
-
if (camera.lowerRadiusLimit && this._mode === FramingBehavior.IgnoreBoundsSizeMode) {
|
|
706
|
-
// Don't exceed the requested limit
|
|
707
|
-
distance = distance < camera.lowerRadiusLimit ? camera.lowerRadiusLimit : distance;
|
|
708
|
-
}
|
|
709
|
-
// Don't exceed the upper radius limit
|
|
710
|
-
if (camera.upperRadiusLimit) {
|
|
711
|
-
distance = distance > camera.upperRadiusLimit ? camera.upperRadiusLimit : distance;
|
|
712
|
-
}
|
|
713
|
-
return distance;
|
|
714
|
-
}
|
|
715
|
-
/**
|
|
716
|
-
* Keeps the camera above the ground plane. If the user pulls the camera below the ground plane, the camera
|
|
717
|
-
* is automatically returned to its default position (expected to be above ground plane).
|
|
718
|
-
*/
|
|
719
|
-
_maintainCameraAboveGround() {
|
|
720
|
-
if (this._elevationReturnTime < 0) {
|
|
721
|
-
return;
|
|
722
|
-
}
|
|
723
|
-
const timeSinceInteraction = PrecisionDate.Now - this._lastInteractionTime;
|
|
724
|
-
const defaultBeta = Math.PI * 0.5 - this._defaultElevation;
|
|
725
|
-
const limitBeta = Math.PI * 0.5;
|
|
726
|
-
// Bring the camera back up if below the ground plane
|
|
727
|
-
if (this._attachedCamera && !this._betaIsAnimating && this._attachedCamera.beta > limitBeta && timeSinceInteraction >= this._elevationReturnWaitTime) {
|
|
728
|
-
this._betaIsAnimating = true;
|
|
729
|
-
//Transition to new position
|
|
730
|
-
this.stopAllAnimations();
|
|
731
|
-
if (!this._betaTransition) {
|
|
732
|
-
this._betaTransition = Animation.CreateAnimation("beta", Animation.ANIMATIONTYPE_FLOAT, 60, FramingBehavior.EasingFunction);
|
|
733
|
-
}
|
|
734
|
-
const animatabe = Animation.TransitionTo("beta", defaultBeta, this._attachedCamera, this._attachedCamera.getScene(), 60, this._betaTransition, this._elevationReturnTime, () => {
|
|
735
|
-
this._clearAnimationLocks();
|
|
736
|
-
this.stopAllAnimations();
|
|
737
|
-
});
|
|
738
|
-
if (animatabe) {
|
|
739
|
-
this._animatables.push(animatabe);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
/**
|
|
744
|
-
* Returns the frustum slope based on the canvas ratio and camera FOV
|
|
745
|
-
* @returns The frustum slope represented as a Vector2 with X and Y slopes
|
|
746
|
-
*/
|
|
747
|
-
_getFrustumSlope() {
|
|
748
|
-
// Calculate the viewport ratio
|
|
749
|
-
// Aspect Ratio is Height/Width.
|
|
750
|
-
const camera = this._attachedCamera;
|
|
751
|
-
if (!camera) {
|
|
752
|
-
return Vector2.Zero();
|
|
753
|
-
}
|
|
754
|
-
const engine = camera.getScene().getEngine();
|
|
755
|
-
const aspectRatio = engine.getAspectRatio(camera);
|
|
756
|
-
// Camera FOV is the vertical field of view (top-bottom) in radians.
|
|
757
|
-
// Slope of the frustum top/bottom planes in view space, relative to the forward vector.
|
|
758
|
-
const frustumSlopeY = Math.tan(camera.fov / 2);
|
|
759
|
-
// Slope of the frustum left/right planes in view space, relative to the forward vector.
|
|
760
|
-
// Provides the amount that one side (e.g. left) of the frustum gets wider for every unit
|
|
761
|
-
// along the forward vector.
|
|
762
|
-
const frustumSlopeX = frustumSlopeY * aspectRatio;
|
|
763
|
-
return new Vector2(frustumSlopeX, frustumSlopeY);
|
|
764
|
-
}
|
|
765
|
-
/**
|
|
766
|
-
* Removes all animation locks. Allows new animations to be added to any of the arcCamera properties.
|
|
767
|
-
*/
|
|
768
|
-
_clearAnimationLocks() {
|
|
769
|
-
this._betaIsAnimating = false;
|
|
770
|
-
}
|
|
771
|
-
/**
|
|
772
|
-
* Applies any current user interaction to the camera. Takes into account maximum alpha rotation.
|
|
773
|
-
*/
|
|
774
|
-
_applyUserInteraction() {
|
|
775
|
-
if (this.isUserIsMoving) {
|
|
776
|
-
this._lastInteractionTime = PrecisionDate.Now;
|
|
777
|
-
this.stopAllAnimations();
|
|
778
|
-
this._clearAnimationLocks();
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
/**
|
|
782
|
-
* Stops and removes all animations that have been applied to the camera
|
|
783
|
-
*/
|
|
784
|
-
stopAllAnimations() {
|
|
785
|
-
if (this._attachedCamera) {
|
|
786
|
-
this._attachedCamera.animations = [];
|
|
787
|
-
}
|
|
788
|
-
while (this._animatables.length) {
|
|
789
|
-
if (this._animatables[0]) {
|
|
790
|
-
this._animatables[0].onAnimationEnd = null;
|
|
791
|
-
this._animatables[0].stop();
|
|
792
|
-
}
|
|
793
|
-
this._animatables.shift();
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
/**
|
|
797
|
-
* Gets a value indicating if the user is moving the camera
|
|
798
|
-
*/
|
|
799
|
-
get isUserIsMoving() {
|
|
800
|
-
if (!this._attachedCamera) {
|
|
801
|
-
return false;
|
|
802
|
-
}
|
|
803
|
-
return (this._attachedCamera.inertialAlphaOffset !== 0 ||
|
|
804
|
-
this._attachedCamera.inertialBetaOffset !== 0 ||
|
|
805
|
-
this._attachedCamera.inertialRadiusOffset !== 0 ||
|
|
806
|
-
this._attachedCamera.inertialPanningX !== 0 ||
|
|
807
|
-
this._attachedCamera.inertialPanningY !== 0 ||
|
|
808
|
-
this._isPointerDown);
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
/**
|
|
812
|
-
* The easing function used by animations
|
|
813
|
-
*/
|
|
814
|
-
FramingBehavior.EasingFunction = new ExponentialEase();
|
|
815
|
-
/**
|
|
816
|
-
* The easing mode used by animations
|
|
817
|
-
*/
|
|
818
|
-
FramingBehavior.EasingMode = EasingFunction.EASINGMODE_EASEINOUT;
|
|
819
|
-
// Statics
|
|
820
|
-
/**
|
|
821
|
-
* The camera can move all the way towards the mesh.
|
|
822
|
-
*/
|
|
823
|
-
FramingBehavior.IgnoreBoundsSizeMode = 0;
|
|
824
|
-
/**
|
|
825
|
-
* The camera is not allowed to zoom closer to the mesh than the point at which the adjusted bounding sphere touches the frustum sides
|
|
826
|
-
*/
|
|
827
|
-
FramingBehavior.FitFrustumSidesMode = 1;
|
|
828
|
-
|
|
829
|
-
/**
|
|
830
|
-
* A target camera takes a mesh or position as a target and continues to look at it while it moves.
|
|
831
|
-
* This is the base of the follow, arc rotate cameras and Free camera
|
|
832
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras
|
|
833
|
-
*/
|
|
834
|
-
class TargetCamera extends Camera {
|
|
835
|
-
/**
|
|
836
|
-
* Instantiates a target camera that takes a mesh or position as a target and continues to look at it while it moves.
|
|
837
|
-
* This is the base of the follow, arc rotate cameras and Free camera
|
|
838
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras
|
|
839
|
-
* @param name Defines the name of the camera in the scene
|
|
840
|
-
* @param position Defines the start position of the camera in the scene
|
|
841
|
-
* @param scene Defines the scene the camera belongs to
|
|
842
|
-
* @param setActiveOnSceneIfNoneActive Defines whether the camera should be marked as active if not other active cameras have been defined
|
|
843
|
-
*/
|
|
844
|
-
constructor(name, position, scene, setActiveOnSceneIfNoneActive = true) {
|
|
845
|
-
super(name, position, scene, setActiveOnSceneIfNoneActive);
|
|
846
|
-
this._tmpUpVector = Vector3.Zero();
|
|
847
|
-
this._tmpTargetVector = Vector3.Zero();
|
|
848
|
-
/**
|
|
849
|
-
* Define the current direction the camera is moving to
|
|
850
|
-
*/
|
|
851
|
-
this.cameraDirection = new Vector3(0, 0, 0);
|
|
852
|
-
/**
|
|
853
|
-
* Define the current rotation the camera is rotating to
|
|
854
|
-
*/
|
|
855
|
-
this.cameraRotation = new Vector2(0, 0);
|
|
856
|
-
/** Gets or sets a boolean indicating that the scaling of the parent hierarchy will not be taken in account by the camera */
|
|
857
|
-
this.ignoreParentScaling = false;
|
|
858
|
-
/**
|
|
859
|
-
* When set, the up vector of the camera will be updated by the rotation of the camera
|
|
860
|
-
*/
|
|
861
|
-
this.updateUpVectorFromRotation = false;
|
|
862
|
-
this._tmpQuaternion = new Quaternion();
|
|
863
|
-
/**
|
|
864
|
-
* Define the current rotation of the camera
|
|
865
|
-
*/
|
|
866
|
-
this.rotation = new Vector3(0, 0, 0);
|
|
867
|
-
/**
|
|
868
|
-
* Define the current speed of the camera
|
|
869
|
-
*/
|
|
870
|
-
this.speed = 2.0;
|
|
871
|
-
/**
|
|
872
|
-
* Add constraint to the camera to prevent it to move freely in all directions and
|
|
873
|
-
* around all axis.
|
|
874
|
-
*/
|
|
875
|
-
this.noRotationConstraint = false;
|
|
876
|
-
/**
|
|
877
|
-
* Reverses mouselook direction to 'natural' panning as opposed to traditional direct
|
|
878
|
-
* panning
|
|
879
|
-
*/
|
|
880
|
-
this.invertRotation = false;
|
|
881
|
-
/**
|
|
882
|
-
* Speed multiplier for inverse camera panning
|
|
883
|
-
*/
|
|
884
|
-
this.inverseRotationSpeed = 0.2;
|
|
885
|
-
/**
|
|
886
|
-
* Define the current target of the camera as an object or a position.
|
|
887
|
-
* Please note that locking a target will disable panning.
|
|
888
|
-
*/
|
|
889
|
-
this.lockedTarget = null;
|
|
890
|
-
/** @internal */
|
|
891
|
-
this._currentTarget = Vector3.Zero();
|
|
892
|
-
/** @internal */
|
|
893
|
-
this._initialFocalDistance = 1;
|
|
894
|
-
/** @internal */
|
|
895
|
-
this._viewMatrix = Matrix.Zero();
|
|
896
|
-
/** @internal */
|
|
897
|
-
this._camMatrix = Matrix.Zero();
|
|
898
|
-
/** @internal */
|
|
899
|
-
this._cameraTransformMatrix = Matrix.Zero();
|
|
900
|
-
/** @internal */
|
|
901
|
-
this._cameraRotationMatrix = Matrix.Zero();
|
|
902
|
-
/** @internal */
|
|
903
|
-
this._referencePoint = new Vector3(0, 0, 1);
|
|
904
|
-
/** @internal */
|
|
905
|
-
this._transformedReferencePoint = Vector3.Zero();
|
|
906
|
-
this._deferredPositionUpdate = new Vector3();
|
|
907
|
-
this._deferredRotationQuaternionUpdate = new Quaternion();
|
|
908
|
-
this._deferredRotationUpdate = new Vector3();
|
|
909
|
-
this._deferredUpdated = false;
|
|
910
|
-
this._deferOnly = false;
|
|
911
|
-
this._defaultUp = Vector3.Up();
|
|
912
|
-
this._cachedRotationZ = 0;
|
|
913
|
-
this._cachedQuaternionRotationZ = 0;
|
|
914
|
-
}
|
|
915
|
-
/**
|
|
916
|
-
* Gets the position in front of the camera at a given distance.
|
|
917
|
-
* @param distance The distance from the camera we want the position to be
|
|
918
|
-
* @returns the position
|
|
919
|
-
*/
|
|
920
|
-
getFrontPosition(distance) {
|
|
921
|
-
this.getWorldMatrix();
|
|
922
|
-
const direction = this.getTarget().subtract(this.position);
|
|
923
|
-
direction.normalize();
|
|
924
|
-
direction.scaleInPlace(distance);
|
|
925
|
-
return this.globalPosition.add(direction);
|
|
926
|
-
}
|
|
927
|
-
/** @internal */
|
|
928
|
-
_getLockedTargetPosition() {
|
|
929
|
-
if (!this.lockedTarget) {
|
|
930
|
-
return null;
|
|
931
|
-
}
|
|
932
|
-
if (this.lockedTarget.absolutePosition) {
|
|
933
|
-
const lockedTarget = this.lockedTarget;
|
|
934
|
-
const m = lockedTarget.computeWorldMatrix();
|
|
935
|
-
// in some cases the absolute position resets externally, but doesn't update since the matrix is cached.
|
|
936
|
-
m.getTranslationToRef(lockedTarget.absolutePosition);
|
|
937
|
-
}
|
|
938
|
-
return this.lockedTarget.absolutePosition || this.lockedTarget;
|
|
939
|
-
}
|
|
940
|
-
/**
|
|
941
|
-
* Store current camera state of the camera (fov, position, rotation, etc..)
|
|
942
|
-
* @returns the camera
|
|
943
|
-
*/
|
|
944
|
-
storeState() {
|
|
945
|
-
this._storedPosition = this.position.clone();
|
|
946
|
-
this._storedRotation = this.rotation.clone();
|
|
947
|
-
if (this.rotationQuaternion) {
|
|
948
|
-
this._storedRotationQuaternion = this.rotationQuaternion.clone();
|
|
949
|
-
}
|
|
950
|
-
return super.storeState();
|
|
951
|
-
}
|
|
952
|
-
/**
|
|
953
|
-
* Restored camera state. You must call storeState() first
|
|
954
|
-
* @returns whether it was successful or not
|
|
955
|
-
* @internal
|
|
956
|
-
*/
|
|
957
|
-
_restoreStateValues() {
|
|
958
|
-
if (!super._restoreStateValues()) {
|
|
959
|
-
return false;
|
|
960
|
-
}
|
|
961
|
-
this.position = this._storedPosition.clone();
|
|
962
|
-
this.rotation = this._storedRotation.clone();
|
|
963
|
-
if (this.rotationQuaternion) {
|
|
964
|
-
this.rotationQuaternion = this._storedRotationQuaternion.clone();
|
|
965
|
-
}
|
|
966
|
-
this.cameraDirection.copyFromFloats(0, 0, 0);
|
|
967
|
-
this.cameraRotation.copyFromFloats(0, 0);
|
|
968
|
-
return true;
|
|
969
|
-
}
|
|
970
|
-
/** @internal */
|
|
971
|
-
_initCache() {
|
|
972
|
-
super._initCache();
|
|
973
|
-
this._cache.lockedTarget = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
|
|
974
|
-
this._cache.rotation = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
|
|
975
|
-
this._cache.rotationQuaternion = new Quaternion(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
|
|
976
|
-
}
|
|
977
|
-
/**
|
|
978
|
-
* @internal
|
|
979
|
-
*/
|
|
980
|
-
_updateCache(ignoreParentClass) {
|
|
981
|
-
if (!ignoreParentClass) {
|
|
982
|
-
super._updateCache();
|
|
983
|
-
}
|
|
984
|
-
const lockedTargetPosition = this._getLockedTargetPosition();
|
|
985
|
-
if (!lockedTargetPosition) {
|
|
986
|
-
this._cache.lockedTarget = null;
|
|
987
|
-
}
|
|
988
|
-
else {
|
|
989
|
-
if (!this._cache.lockedTarget) {
|
|
990
|
-
this._cache.lockedTarget = lockedTargetPosition.clone();
|
|
991
|
-
}
|
|
992
|
-
else {
|
|
993
|
-
this._cache.lockedTarget.copyFrom(lockedTargetPosition);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
this._cache.rotation.copyFrom(this.rotation);
|
|
997
|
-
if (this.rotationQuaternion) {
|
|
998
|
-
this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
// Synchronized
|
|
1002
|
-
/** @internal */
|
|
1003
|
-
_isSynchronizedViewMatrix() {
|
|
1004
|
-
if (!super._isSynchronizedViewMatrix()) {
|
|
1005
|
-
return false;
|
|
1006
|
-
}
|
|
1007
|
-
const lockedTargetPosition = this._getLockedTargetPosition();
|
|
1008
|
-
return ((this._cache.lockedTarget ? this._cache.lockedTarget.equals(lockedTargetPosition) : !lockedTargetPosition) &&
|
|
1009
|
-
(this.rotationQuaternion ? this.rotationQuaternion.equals(this._cache.rotationQuaternion) : this._cache.rotation.equals(this.rotation)));
|
|
1010
|
-
}
|
|
1011
|
-
// Methods
|
|
1012
|
-
/** @internal */
|
|
1013
|
-
_computeLocalCameraSpeed() {
|
|
1014
|
-
const engine = this.getEngine();
|
|
1015
|
-
return this.speed * Math.sqrt(engine.getDeltaTime() / (engine.getFps() * 100.0));
|
|
1016
|
-
}
|
|
1017
|
-
// Target
|
|
1018
|
-
/**
|
|
1019
|
-
* Defines the target the camera should look at.
|
|
1020
|
-
* @param target Defines the new target as a Vector
|
|
1021
|
-
*/
|
|
1022
|
-
setTarget(target) {
|
|
1023
|
-
this.upVector.normalize();
|
|
1024
|
-
this._initialFocalDistance = target.subtract(this.position).length();
|
|
1025
|
-
if (this.position.z === target.z) {
|
|
1026
|
-
this.position.z += Epsilon;
|
|
1027
|
-
}
|
|
1028
|
-
this._referencePoint.normalize().scaleInPlace(this._initialFocalDistance);
|
|
1029
|
-
Matrix.LookAtLHToRef(this.position, target, this._defaultUp, this._camMatrix);
|
|
1030
|
-
this._camMatrix.invert();
|
|
1031
|
-
this.rotation.x = Math.atan(this._camMatrix.m[6] / this._camMatrix.m[10]);
|
|
1032
|
-
const vDir = target.subtract(this.position);
|
|
1033
|
-
if (vDir.x >= 0.0) {
|
|
1034
|
-
this.rotation.y = -Math.atan(vDir.z / vDir.x) + Math.PI / 2.0;
|
|
1035
|
-
}
|
|
1036
|
-
else {
|
|
1037
|
-
this.rotation.y = -Math.atan(vDir.z / vDir.x) - Math.PI / 2.0;
|
|
1038
|
-
}
|
|
1039
|
-
this.rotation.z = 0;
|
|
1040
|
-
if (isNaN(this.rotation.x)) {
|
|
1041
|
-
this.rotation.x = 0;
|
|
1042
|
-
}
|
|
1043
|
-
if (isNaN(this.rotation.y)) {
|
|
1044
|
-
this.rotation.y = 0;
|
|
1045
|
-
}
|
|
1046
|
-
if (isNaN(this.rotation.z)) {
|
|
1047
|
-
this.rotation.z = 0;
|
|
1048
|
-
}
|
|
1049
|
-
if (this.rotationQuaternion) {
|
|
1050
|
-
Quaternion.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this.rotationQuaternion);
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
/**
|
|
1054
|
-
* Defines the target point of the camera.
|
|
1055
|
-
* The camera looks towards it form the radius distance.
|
|
1056
|
-
*/
|
|
1057
|
-
get target() {
|
|
1058
|
-
return this.getTarget();
|
|
1059
|
-
}
|
|
1060
|
-
set target(value) {
|
|
1061
|
-
this.setTarget(value);
|
|
1062
|
-
}
|
|
1063
|
-
/**
|
|
1064
|
-
* Return the current target position of the camera. This value is expressed in local space.
|
|
1065
|
-
* @returns the target position
|
|
1066
|
-
*/
|
|
1067
|
-
getTarget() {
|
|
1068
|
-
return this._currentTarget;
|
|
1069
|
-
}
|
|
1070
|
-
/** @internal */
|
|
1071
|
-
_decideIfNeedsToMove() {
|
|
1072
|
-
return Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
|
|
1073
|
-
}
|
|
1074
|
-
/** @internal */
|
|
1075
|
-
_updatePosition() {
|
|
1076
|
-
if (this.parent) {
|
|
1077
|
-
this.parent.getWorldMatrix().invertToRef(TmpVectors.Matrix[0]);
|
|
1078
|
-
Vector3.TransformNormalToRef(this.cameraDirection, TmpVectors.Matrix[0], TmpVectors.Vector3[0]);
|
|
1079
|
-
this._deferredPositionUpdate.addInPlace(TmpVectors.Vector3[0]);
|
|
1080
|
-
if (!this._deferOnly) {
|
|
1081
|
-
this.position.copyFrom(this._deferredPositionUpdate);
|
|
1082
|
-
}
|
|
1083
|
-
else {
|
|
1084
|
-
this._deferredUpdated = true;
|
|
1085
|
-
}
|
|
1086
|
-
return;
|
|
1087
|
-
}
|
|
1088
|
-
this._deferredPositionUpdate.addInPlace(this.cameraDirection);
|
|
1089
|
-
if (!this._deferOnly) {
|
|
1090
|
-
this.position.copyFrom(this._deferredPositionUpdate);
|
|
1091
|
-
}
|
|
1092
|
-
else {
|
|
1093
|
-
this._deferredUpdated = true;
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
/** @internal */
|
|
1097
|
-
_checkInputs() {
|
|
1098
|
-
const directionMultiplier = this.invertRotation ? -this.inverseRotationSpeed : 1.0;
|
|
1099
|
-
const needToMove = this._decideIfNeedsToMove();
|
|
1100
|
-
const needToRotate = this.cameraRotation.x || this.cameraRotation.y;
|
|
1101
|
-
this._deferredUpdated = false;
|
|
1102
|
-
this._deferredRotationUpdate.copyFrom(this.rotation);
|
|
1103
|
-
this._deferredPositionUpdate.copyFrom(this.position);
|
|
1104
|
-
if (this.rotationQuaternion) {
|
|
1105
|
-
this._deferredRotationQuaternionUpdate.copyFrom(this.rotationQuaternion);
|
|
1106
|
-
}
|
|
1107
|
-
// Move
|
|
1108
|
-
if (needToMove) {
|
|
1109
|
-
this._updatePosition();
|
|
1110
|
-
}
|
|
1111
|
-
// Rotate
|
|
1112
|
-
if (needToRotate) {
|
|
1113
|
-
//rotate, if quaternion is set and rotation was used
|
|
1114
|
-
if (this.rotationQuaternion) {
|
|
1115
|
-
this.rotationQuaternion.toEulerAnglesToRef(this._deferredRotationUpdate);
|
|
1116
|
-
}
|
|
1117
|
-
this._deferredRotationUpdate.x += this.cameraRotation.x * directionMultiplier;
|
|
1118
|
-
this._deferredRotationUpdate.y += this.cameraRotation.y * directionMultiplier;
|
|
1119
|
-
// Apply constraints
|
|
1120
|
-
if (!this.noRotationConstraint) {
|
|
1121
|
-
const limit = 1.570796;
|
|
1122
|
-
if (this._deferredRotationUpdate.x > limit) {
|
|
1123
|
-
this._deferredRotationUpdate.x = limit;
|
|
1124
|
-
}
|
|
1125
|
-
if (this._deferredRotationUpdate.x < -limit) {
|
|
1126
|
-
this._deferredRotationUpdate.x = -limit;
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
if (!this._deferOnly) {
|
|
1130
|
-
this.rotation.copyFrom(this._deferredRotationUpdate);
|
|
1131
|
-
}
|
|
1132
|
-
else {
|
|
1133
|
-
this._deferredUpdated = true;
|
|
1134
|
-
}
|
|
1135
|
-
//rotate, if quaternion is set and rotation was used
|
|
1136
|
-
if (this.rotationQuaternion) {
|
|
1137
|
-
const len = this._deferredRotationUpdate.lengthSquared();
|
|
1138
|
-
if (len) {
|
|
1139
|
-
Quaternion.RotationYawPitchRollToRef(this._deferredRotationUpdate.y, this._deferredRotationUpdate.x, this._deferredRotationUpdate.z, this._deferredRotationQuaternionUpdate);
|
|
1140
|
-
if (!this._deferOnly) {
|
|
1141
|
-
this.rotationQuaternion.copyFrom(this._deferredRotationQuaternionUpdate);
|
|
1142
|
-
}
|
|
1143
|
-
else {
|
|
1144
|
-
this._deferredUpdated = true;
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
// Inertia
|
|
1150
|
-
if (needToMove) {
|
|
1151
|
-
if (Math.abs(this.cameraDirection.x) < this.speed * Epsilon) {
|
|
1152
|
-
this.cameraDirection.x = 0;
|
|
1153
|
-
}
|
|
1154
|
-
if (Math.abs(this.cameraDirection.y) < this.speed * Epsilon) {
|
|
1155
|
-
this.cameraDirection.y = 0;
|
|
1156
|
-
}
|
|
1157
|
-
if (Math.abs(this.cameraDirection.z) < this.speed * Epsilon) {
|
|
1158
|
-
this.cameraDirection.z = 0;
|
|
1159
|
-
}
|
|
1160
|
-
this.cameraDirection.scaleInPlace(this.inertia);
|
|
1161
|
-
}
|
|
1162
|
-
if (needToRotate) {
|
|
1163
|
-
if (Math.abs(this.cameraRotation.x) < this.speed * Epsilon) {
|
|
1164
|
-
this.cameraRotation.x = 0;
|
|
1165
|
-
}
|
|
1166
|
-
if (Math.abs(this.cameraRotation.y) < this.speed * Epsilon) {
|
|
1167
|
-
this.cameraRotation.y = 0;
|
|
1168
|
-
}
|
|
1169
|
-
this.cameraRotation.scaleInPlace(this.inertia);
|
|
1170
|
-
}
|
|
1171
|
-
super._checkInputs();
|
|
1172
|
-
}
|
|
1173
|
-
_updateCameraRotationMatrix() {
|
|
1174
|
-
if (this.rotationQuaternion) {
|
|
1175
|
-
this.rotationQuaternion.toRotationMatrix(this._cameraRotationMatrix);
|
|
1176
|
-
}
|
|
1177
|
-
else {
|
|
1178
|
-
Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
|
|
1179
|
-
}
|
|
1180
|
-
}
|
|
1181
|
-
/**
|
|
1182
|
-
* Update the up vector to apply the rotation of the camera (So if you changed the camera rotation.z this will let you update the up vector as well)
|
|
1183
|
-
* @returns the current camera
|
|
1184
|
-
*/
|
|
1185
|
-
_rotateUpVectorWithCameraRotationMatrix() {
|
|
1186
|
-
Vector3.TransformNormalToRef(this._defaultUp, this._cameraRotationMatrix, this.upVector);
|
|
1187
|
-
return this;
|
|
1188
|
-
}
|
|
1189
|
-
/** @internal */
|
|
1190
|
-
_getViewMatrix() {
|
|
1191
|
-
if (this.lockedTarget) {
|
|
1192
|
-
this.setTarget(this._getLockedTargetPosition());
|
|
1193
|
-
}
|
|
1194
|
-
// Compute
|
|
1195
|
-
this._updateCameraRotationMatrix();
|
|
1196
|
-
// Apply the changed rotation to the upVector
|
|
1197
|
-
if (this.rotationQuaternion && this._cachedQuaternionRotationZ != this.rotationQuaternion.z) {
|
|
1198
|
-
this._rotateUpVectorWithCameraRotationMatrix();
|
|
1199
|
-
this._cachedQuaternionRotationZ = this.rotationQuaternion.z;
|
|
1200
|
-
}
|
|
1201
|
-
else if (this._cachedRotationZ !== this.rotation.z) {
|
|
1202
|
-
this._rotateUpVectorWithCameraRotationMatrix();
|
|
1203
|
-
this._cachedRotationZ = this.rotation.z;
|
|
1204
|
-
}
|
|
1205
|
-
Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
|
|
1206
|
-
// Computing target and final matrix
|
|
1207
|
-
this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
|
|
1208
|
-
if (this.updateUpVectorFromRotation) {
|
|
1209
|
-
if (this.rotationQuaternion) {
|
|
1210
|
-
Axis.Y.rotateByQuaternionToRef(this.rotationQuaternion, this.upVector);
|
|
1211
|
-
}
|
|
1212
|
-
else {
|
|
1213
|
-
Quaternion.FromEulerVectorToRef(this.rotation, this._tmpQuaternion);
|
|
1214
|
-
Axis.Y.rotateByQuaternionToRef(this._tmpQuaternion, this.upVector);
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
this._computeViewMatrix(this.position, this._currentTarget, this.upVector);
|
|
1218
|
-
return this._viewMatrix;
|
|
1219
|
-
}
|
|
1220
|
-
_computeViewMatrix(position, target, up) {
|
|
1221
|
-
if (this.ignoreParentScaling) {
|
|
1222
|
-
if (this.parent) {
|
|
1223
|
-
const parentWorldMatrix = this.parent.getWorldMatrix();
|
|
1224
|
-
Vector3.TransformCoordinatesToRef(position, parentWorldMatrix, this._globalPosition);
|
|
1225
|
-
Vector3.TransformCoordinatesToRef(target, parentWorldMatrix, this._tmpTargetVector);
|
|
1226
|
-
Vector3.TransformNormalToRef(up, parentWorldMatrix, this._tmpUpVector);
|
|
1227
|
-
this._markSyncedWithParent();
|
|
1228
|
-
}
|
|
1229
|
-
else {
|
|
1230
|
-
this._globalPosition.copyFrom(position);
|
|
1231
|
-
this._tmpTargetVector.copyFrom(target);
|
|
1232
|
-
this._tmpUpVector.copyFrom(up);
|
|
1233
|
-
}
|
|
1234
|
-
if (this.getScene().useRightHandedSystem) {
|
|
1235
|
-
Matrix.LookAtRHToRef(this._globalPosition, this._tmpTargetVector, this._tmpUpVector, this._viewMatrix);
|
|
1236
|
-
}
|
|
1237
|
-
else {
|
|
1238
|
-
Matrix.LookAtLHToRef(this._globalPosition, this._tmpTargetVector, this._tmpUpVector, this._viewMatrix);
|
|
1239
|
-
}
|
|
1240
|
-
return;
|
|
1241
|
-
}
|
|
1242
|
-
if (this.getScene().useRightHandedSystem) {
|
|
1243
|
-
Matrix.LookAtRHToRef(position, target, up, this._viewMatrix);
|
|
1244
|
-
}
|
|
1245
|
-
else {
|
|
1246
|
-
Matrix.LookAtLHToRef(position, target, up, this._viewMatrix);
|
|
1247
|
-
}
|
|
1248
|
-
if (this.parent) {
|
|
1249
|
-
const parentWorldMatrix = this.parent.getWorldMatrix();
|
|
1250
|
-
this._viewMatrix.invert();
|
|
1251
|
-
this._viewMatrix.multiplyToRef(parentWorldMatrix, this._viewMatrix);
|
|
1252
|
-
this._viewMatrix.getTranslationToRef(this._globalPosition);
|
|
1253
|
-
this._viewMatrix.invert();
|
|
1254
|
-
this._markSyncedWithParent();
|
|
1255
|
-
}
|
|
1256
|
-
else {
|
|
1257
|
-
this._globalPosition.copyFrom(position);
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
/**
|
|
1261
|
-
* @internal
|
|
1262
|
-
*/
|
|
1263
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1264
|
-
createRigCamera(name, cameraIndex) {
|
|
1265
|
-
if (this.cameraRigMode !== Camera.RIG_MODE_NONE) {
|
|
1266
|
-
const rigCamera = new TargetCamera(name, this.position.clone(), this.getScene());
|
|
1267
|
-
rigCamera.isRigCamera = true;
|
|
1268
|
-
rigCamera.rigParent = this;
|
|
1269
|
-
if (this.cameraRigMode === Camera.RIG_MODE_VR || this.cameraRigMode === Camera.RIG_MODE_WEBVR) {
|
|
1270
|
-
if (!this.rotationQuaternion) {
|
|
1271
|
-
this.rotationQuaternion = new Quaternion();
|
|
1272
|
-
}
|
|
1273
|
-
rigCamera._cameraRigParams = {};
|
|
1274
|
-
rigCamera.rotationQuaternion = new Quaternion();
|
|
1275
|
-
}
|
|
1276
|
-
rigCamera.mode = this.mode;
|
|
1277
|
-
rigCamera.orthoLeft = this.orthoLeft;
|
|
1278
|
-
rigCamera.orthoRight = this.orthoRight;
|
|
1279
|
-
rigCamera.orthoTop = this.orthoTop;
|
|
1280
|
-
rigCamera.orthoBottom = this.orthoBottom;
|
|
1281
|
-
return rigCamera;
|
|
1282
|
-
}
|
|
1283
|
-
return null;
|
|
1284
|
-
}
|
|
1285
|
-
/**
|
|
1286
|
-
* @internal
|
|
1287
|
-
*/
|
|
1288
|
-
_updateRigCameras() {
|
|
1289
|
-
const camLeft = this._rigCameras[0];
|
|
1290
|
-
const camRight = this._rigCameras[1];
|
|
1291
|
-
this.computeWorldMatrix();
|
|
1292
|
-
switch (this.cameraRigMode) {
|
|
1293
|
-
case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
|
|
1294
|
-
case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
|
|
1295
|
-
case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
|
|
1296
|
-
case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
|
|
1297
|
-
case Camera.RIG_MODE_STEREOSCOPIC_INTERLACED: {
|
|
1298
|
-
//provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
|
|
1299
|
-
const leftSign = this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED ? 1 : -1;
|
|
1300
|
-
const rightSign = this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED ? -1 : 1;
|
|
1301
|
-
this._getRigCamPositionAndTarget(this._cameraRigParams.stereoHalfAngle * leftSign, camLeft);
|
|
1302
|
-
this._getRigCamPositionAndTarget(this._cameraRigParams.stereoHalfAngle * rightSign, camRight);
|
|
1303
|
-
break;
|
|
1304
|
-
}
|
|
1305
|
-
case Camera.RIG_MODE_VR:
|
|
1306
|
-
if (camLeft.rotationQuaternion) {
|
|
1307
|
-
camLeft.rotationQuaternion.copyFrom(this.rotationQuaternion);
|
|
1308
|
-
camRight.rotationQuaternion.copyFrom(this.rotationQuaternion);
|
|
1309
|
-
}
|
|
1310
|
-
else {
|
|
1311
|
-
camLeft.rotation.copyFrom(this.rotation);
|
|
1312
|
-
camRight.rotation.copyFrom(this.rotation);
|
|
1313
|
-
}
|
|
1314
|
-
camLeft.position.copyFrom(this.position);
|
|
1315
|
-
camRight.position.copyFrom(this.position);
|
|
1316
|
-
break;
|
|
1317
|
-
}
|
|
1318
|
-
super._updateRigCameras();
|
|
1319
|
-
}
|
|
1320
|
-
_getRigCamPositionAndTarget(halfSpace, rigCamera) {
|
|
1321
|
-
const target = this.getTarget();
|
|
1322
|
-
target.subtractToRef(this.position, TargetCamera._TargetFocalPoint);
|
|
1323
|
-
TargetCamera._TargetFocalPoint.normalize().scaleInPlace(this._initialFocalDistance);
|
|
1324
|
-
const newFocalTarget = TargetCamera._TargetFocalPoint.addInPlace(this.position);
|
|
1325
|
-
Matrix.TranslationToRef(-newFocalTarget.x, -newFocalTarget.y, -newFocalTarget.z, TargetCamera._TargetTransformMatrix);
|
|
1326
|
-
TargetCamera._TargetTransformMatrix.multiplyToRef(Matrix.RotationAxis(rigCamera.upVector, halfSpace), TargetCamera._RigCamTransformMatrix);
|
|
1327
|
-
Matrix.TranslationToRef(newFocalTarget.x, newFocalTarget.y, newFocalTarget.z, TargetCamera._TargetTransformMatrix);
|
|
1328
|
-
TargetCamera._RigCamTransformMatrix.multiplyToRef(TargetCamera._TargetTransformMatrix, TargetCamera._RigCamTransformMatrix);
|
|
1329
|
-
Vector3.TransformCoordinatesToRef(this.position, TargetCamera._RigCamTransformMatrix, rigCamera.position);
|
|
1330
|
-
rigCamera.setTarget(newFocalTarget);
|
|
1331
|
-
}
|
|
1332
|
-
/**
|
|
1333
|
-
* Gets the current object class name.
|
|
1334
|
-
* @returns the class name
|
|
1335
|
-
*/
|
|
1336
|
-
getClassName() {
|
|
1337
|
-
return "TargetCamera";
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
TargetCamera._RigCamTransformMatrix = new Matrix();
|
|
1341
|
-
TargetCamera._TargetTransformMatrix = new Matrix();
|
|
1342
|
-
TargetCamera._TargetFocalPoint = new Vector3();
|
|
1343
|
-
__decorate([
|
|
1344
|
-
serializeAsVector3()
|
|
1345
|
-
], TargetCamera.prototype, "rotation", void 0);
|
|
1346
|
-
__decorate([
|
|
1347
|
-
serialize()
|
|
1348
|
-
], TargetCamera.prototype, "speed", void 0);
|
|
1349
|
-
__decorate([
|
|
1350
|
-
serializeAsMeshReference("lockedTargetId")
|
|
1351
|
-
], TargetCamera.prototype, "lockedTarget", void 0);
|
|
1352
|
-
|
|
1353
|
-
/**
|
|
1354
|
-
* @ignore
|
|
1355
|
-
* This is a list of all the different input types that are available in the application.
|
|
1356
|
-
* Fo instance: ArcRotateCameraGamepadInput...
|
|
1357
|
-
*/
|
|
1358
|
-
// eslint-disable-next-line no-var, @typescript-eslint/naming-convention
|
|
1359
|
-
var CameraInputTypes = {};
|
|
1360
|
-
/**
|
|
1361
|
-
* This represents the input manager used within a camera.
|
|
1362
|
-
* It helps dealing with all the different kind of input attached to a camera.
|
|
1363
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
|
|
1364
|
-
*/
|
|
1365
|
-
class CameraInputsManager {
|
|
1366
|
-
/**
|
|
1367
|
-
* Instantiate a new Camera Input Manager.
|
|
1368
|
-
* @param camera Defines the camera the input manager belongs to
|
|
1369
|
-
*/
|
|
1370
|
-
constructor(camera) {
|
|
1371
|
-
/**
|
|
1372
|
-
* Defines the dom element the camera is collecting inputs from.
|
|
1373
|
-
* This is null if the controls have not been attached.
|
|
1374
|
-
*/
|
|
1375
|
-
this.attachedToElement = false;
|
|
1376
|
-
this.attached = {};
|
|
1377
|
-
this.camera = camera;
|
|
1378
|
-
this.checkInputs = () => { };
|
|
1379
|
-
}
|
|
1380
|
-
/**
|
|
1381
|
-
* Add an input method to a camera
|
|
1382
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
|
|
1383
|
-
* @param input Camera input method
|
|
1384
|
-
*/
|
|
1385
|
-
add(input) {
|
|
1386
|
-
const type = input.getSimpleName();
|
|
1387
|
-
if (this.attached[type]) {
|
|
1388
|
-
Logger.Warn("camera input of type " + type + " already exists on camera");
|
|
1389
|
-
return;
|
|
1390
|
-
}
|
|
1391
|
-
this.attached[type] = input;
|
|
1392
|
-
input.camera = this.camera;
|
|
1393
|
-
// for checkInputs, we are dynamically creating a function
|
|
1394
|
-
// the goal is to avoid the performance penalty of looping for inputs in the render loop
|
|
1395
|
-
if (input.checkInputs) {
|
|
1396
|
-
this.checkInputs = this._addCheckInputs(input.checkInputs.bind(input));
|
|
1397
|
-
}
|
|
1398
|
-
if (this.attachedToElement) {
|
|
1399
|
-
input.attachControl(this.noPreventDefault);
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
/**
|
|
1403
|
-
* Remove a specific input method from a camera
|
|
1404
|
-
* example: camera.inputs.remove(camera.inputs.attached.mouse);
|
|
1405
|
-
* @param inputToRemove camera input method
|
|
1406
|
-
*/
|
|
1407
|
-
remove(inputToRemove) {
|
|
1408
|
-
for (const cam in this.attached) {
|
|
1409
|
-
const input = this.attached[cam];
|
|
1410
|
-
if (input === inputToRemove) {
|
|
1411
|
-
input.detachControl();
|
|
1412
|
-
input.camera = null;
|
|
1413
|
-
delete this.attached[cam];
|
|
1414
|
-
this.rebuildInputCheck();
|
|
1415
|
-
return;
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
|
-
/**
|
|
1420
|
-
* Remove a specific input type from a camera
|
|
1421
|
-
* example: camera.inputs.remove("ArcRotateCameraGamepadInput");
|
|
1422
|
-
* @param inputType the type of the input to remove
|
|
1423
|
-
*/
|
|
1424
|
-
removeByType(inputType) {
|
|
1425
|
-
for (const cam in this.attached) {
|
|
1426
|
-
const input = this.attached[cam];
|
|
1427
|
-
if (input.getClassName() === inputType) {
|
|
1428
|
-
input.detachControl();
|
|
1429
|
-
input.camera = null;
|
|
1430
|
-
delete this.attached[cam];
|
|
1431
|
-
this.rebuildInputCheck();
|
|
1432
|
-
}
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
_addCheckInputs(fn) {
|
|
1436
|
-
const current = this.checkInputs;
|
|
1437
|
-
return () => {
|
|
1438
|
-
current();
|
|
1439
|
-
fn();
|
|
1440
|
-
};
|
|
1441
|
-
}
|
|
1442
|
-
/**
|
|
1443
|
-
* Attach the input controls to the currently attached dom element to listen the events from.
|
|
1444
|
-
* @param input Defines the input to attach
|
|
1445
|
-
*/
|
|
1446
|
-
attachInput(input) {
|
|
1447
|
-
if (this.attachedToElement) {
|
|
1448
|
-
input.attachControl(this.noPreventDefault);
|
|
1449
|
-
}
|
|
1450
|
-
}
|
|
1451
|
-
/**
|
|
1452
|
-
* Attach the current manager inputs controls to a specific dom element to listen the events from.
|
|
1453
|
-
* @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
|
|
1454
|
-
*/
|
|
1455
|
-
attachElement(noPreventDefault = false) {
|
|
1456
|
-
if (this.attachedToElement) {
|
|
1457
|
-
return;
|
|
1458
|
-
}
|
|
1459
|
-
noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
|
|
1460
|
-
this.attachedToElement = true;
|
|
1461
|
-
this.noPreventDefault = noPreventDefault;
|
|
1462
|
-
for (const cam in this.attached) {
|
|
1463
|
-
this.attached[cam].attachControl(noPreventDefault);
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
/**
|
|
1467
|
-
* Detach the current manager inputs controls from a specific dom element.
|
|
1468
|
-
* @param disconnect Defines whether the input should be removed from the current list of attached inputs
|
|
1469
|
-
*/
|
|
1470
|
-
detachElement(disconnect = false) {
|
|
1471
|
-
for (const cam in this.attached) {
|
|
1472
|
-
this.attached[cam].detachControl();
|
|
1473
|
-
if (disconnect) {
|
|
1474
|
-
this.attached[cam].camera = null;
|
|
1475
|
-
}
|
|
1476
|
-
}
|
|
1477
|
-
this.attachedToElement = false;
|
|
1478
|
-
}
|
|
1479
|
-
/**
|
|
1480
|
-
* Rebuild the dynamic inputCheck function from the current list of
|
|
1481
|
-
* defined inputs in the manager.
|
|
1482
|
-
*/
|
|
1483
|
-
rebuildInputCheck() {
|
|
1484
|
-
this.checkInputs = () => { };
|
|
1485
|
-
for (const cam in this.attached) {
|
|
1486
|
-
const input = this.attached[cam];
|
|
1487
|
-
if (input.checkInputs) {
|
|
1488
|
-
this.checkInputs = this._addCheckInputs(input.checkInputs.bind(input));
|
|
1489
|
-
}
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
/**
|
|
1493
|
-
* Remove all attached input methods from a camera
|
|
1494
|
-
*/
|
|
1495
|
-
clear() {
|
|
1496
|
-
if (this.attachedToElement) {
|
|
1497
|
-
this.detachElement(true);
|
|
1498
|
-
}
|
|
1499
|
-
this.attached = {};
|
|
1500
|
-
this.attachedToElement = false;
|
|
1501
|
-
this.checkInputs = () => { };
|
|
1502
|
-
}
|
|
1503
|
-
/**
|
|
1504
|
-
* Serialize the current input manager attached to a camera.
|
|
1505
|
-
* This ensures than once parsed,
|
|
1506
|
-
* the input associated to the camera will be identical to the current ones
|
|
1507
|
-
* @param serializedCamera Defines the camera serialization JSON the input serialization should write to
|
|
1508
|
-
*/
|
|
1509
|
-
serialize(serializedCamera) {
|
|
1510
|
-
const inputs = {};
|
|
1511
|
-
for (const cam in this.attached) {
|
|
1512
|
-
const input = this.attached[cam];
|
|
1513
|
-
const res = SerializationHelper.Serialize(input);
|
|
1514
|
-
inputs[input.getClassName()] = res;
|
|
1515
|
-
}
|
|
1516
|
-
serializedCamera.inputsmgr = inputs;
|
|
1517
|
-
}
|
|
1518
|
-
/**
|
|
1519
|
-
* Parses an input manager serialized JSON to restore the previous list of inputs
|
|
1520
|
-
* and states associated to a camera.
|
|
1521
|
-
* @param parsedCamera Defines the JSON to parse
|
|
1522
|
-
*/
|
|
1523
|
-
parse(parsedCamera) {
|
|
1524
|
-
const parsedInputs = parsedCamera.inputsmgr;
|
|
1525
|
-
if (parsedInputs) {
|
|
1526
|
-
this.clear();
|
|
1527
|
-
for (const n in parsedInputs) {
|
|
1528
|
-
const construct = CameraInputTypes[n];
|
|
1529
|
-
if (construct) {
|
|
1530
|
-
const parsedinput = parsedInputs[n];
|
|
1531
|
-
const input = SerializationHelper.Parse(() => {
|
|
1532
|
-
return new construct();
|
|
1533
|
-
}, parsedinput, null);
|
|
1534
|
-
this.add(input);
|
|
1535
|
-
}
|
|
1536
|
-
}
|
|
1537
|
-
}
|
|
1538
|
-
else {
|
|
1539
|
-
//2016-03-08 this part is for managing backward compatibility
|
|
1540
|
-
for (const n in this.attached) {
|
|
1541
|
-
const construct = CameraInputTypes[this.attached[n].getClassName()];
|
|
1542
|
-
if (construct) {
|
|
1543
|
-
const input = SerializationHelper.Parse(() => {
|
|
1544
|
-
return new construct();
|
|
1545
|
-
}, parsedCamera, null);
|
|
1546
|
-
this.remove(this.attached[n]);
|
|
1547
|
-
this.add(input);
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
/**
|
|
1555
|
-
* Base class for Camera Pointer Inputs.
|
|
1556
|
-
* See FollowCameraPointersInput in src/Cameras/Inputs/followCameraPointersInput.ts
|
|
1557
|
-
* for example usage.
|
|
1558
|
-
*/
|
|
1559
|
-
class BaseCameraPointersInput {
|
|
1560
|
-
constructor() {
|
|
1561
|
-
this._currentActiveButton = -1;
|
|
1562
|
-
/**
|
|
1563
|
-
* Defines the buttons associated with the input to handle camera move.
|
|
1564
|
-
*/
|
|
1565
|
-
this.buttons = [0, 1, 2];
|
|
1566
|
-
}
|
|
1567
|
-
/**
|
|
1568
|
-
* Attach the input controls to a specific dom element to get the input from.
|
|
1569
|
-
* @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
|
|
1570
|
-
*/
|
|
1571
|
-
attachControl(noPreventDefault) {
|
|
1572
|
-
// eslint-disable-next-line prefer-rest-params
|
|
1573
|
-
noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
|
|
1574
|
-
const engine = this.camera.getEngine();
|
|
1575
|
-
const element = engine.getInputElement();
|
|
1576
|
-
let previousPinchSquaredDistance = 0;
|
|
1577
|
-
let previousMultiTouchPanPosition = null;
|
|
1578
|
-
this._pointA = null;
|
|
1579
|
-
this._pointB = null;
|
|
1580
|
-
this._altKey = false;
|
|
1581
|
-
this._ctrlKey = false;
|
|
1582
|
-
this._metaKey = false;
|
|
1583
|
-
this._shiftKey = false;
|
|
1584
|
-
this._buttonsPressed = 0;
|
|
1585
|
-
this._pointerInput = (p) => {
|
|
1586
|
-
var _a, _b;
|
|
1587
|
-
const evt = p.event;
|
|
1588
|
-
const isTouch = evt.pointerType === "touch";
|
|
1589
|
-
if (engine.isInVRExclusivePointerMode) {
|
|
1590
|
-
return;
|
|
1591
|
-
}
|
|
1592
|
-
if (p.type !== PointerEventTypes.POINTERMOVE && this.buttons.indexOf(evt.button) === -1) {
|
|
1593
|
-
return;
|
|
1594
|
-
}
|
|
1595
|
-
const srcElement = evt.target;
|
|
1596
|
-
this._altKey = evt.altKey;
|
|
1597
|
-
this._ctrlKey = evt.ctrlKey;
|
|
1598
|
-
this._metaKey = evt.metaKey;
|
|
1599
|
-
this._shiftKey = evt.shiftKey;
|
|
1600
|
-
this._buttonsPressed = evt.buttons;
|
|
1601
|
-
if (engine.isPointerLock) {
|
|
1602
|
-
const offsetX = evt.movementX;
|
|
1603
|
-
const offsetY = evt.movementY;
|
|
1604
|
-
this.onTouch(null, offsetX, offsetY);
|
|
1605
|
-
this._pointA = null;
|
|
1606
|
-
this._pointB = null;
|
|
1607
|
-
}
|
|
1608
|
-
else if (p.type !== PointerEventTypes.POINTERDOWN && isTouch && ((_a = this._pointA) === null || _a === void 0 ? void 0 : _a.pointerId) !== evt.pointerId && ((_b = this._pointB) === null || _b === void 0 ? void 0 : _b.pointerId) !== evt.pointerId) {
|
|
1609
|
-
return; // If we get a non-down event for a touch that we're not tracking, ignore it
|
|
1610
|
-
}
|
|
1611
|
-
else if (p.type === PointerEventTypes.POINTERDOWN && (this._currentActiveButton === -1 || isTouch)) {
|
|
1612
|
-
try {
|
|
1613
|
-
srcElement === null || srcElement === void 0 ? void 0 : srcElement.setPointerCapture(evt.pointerId);
|
|
1614
|
-
}
|
|
1615
|
-
catch (e) {
|
|
1616
|
-
//Nothing to do with the error. Execution will continue.
|
|
1617
|
-
}
|
|
1618
|
-
if (this._pointA === null) {
|
|
1619
|
-
this._pointA = {
|
|
1620
|
-
x: evt.clientX,
|
|
1621
|
-
y: evt.clientY,
|
|
1622
|
-
pointerId: evt.pointerId,
|
|
1623
|
-
type: evt.pointerType,
|
|
1624
|
-
};
|
|
1625
|
-
}
|
|
1626
|
-
else if (this._pointB === null) {
|
|
1627
|
-
this._pointB = {
|
|
1628
|
-
x: evt.clientX,
|
|
1629
|
-
y: evt.clientY,
|
|
1630
|
-
pointerId: evt.pointerId,
|
|
1631
|
-
type: evt.pointerType,
|
|
1632
|
-
};
|
|
1633
|
-
}
|
|
1634
|
-
else {
|
|
1635
|
-
return; // We are already tracking two pointers so ignore this one
|
|
1636
|
-
}
|
|
1637
|
-
if (this._currentActiveButton === -1 && !isTouch) {
|
|
1638
|
-
this._currentActiveButton = evt.button;
|
|
1639
|
-
}
|
|
1640
|
-
this.onButtonDown(evt);
|
|
1641
|
-
if (!noPreventDefault) {
|
|
1642
|
-
evt.preventDefault();
|
|
1643
|
-
element && element.focus();
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
|
-
else if (p.type === PointerEventTypes.POINTERDOUBLETAP) {
|
|
1647
|
-
this.onDoubleTap(evt.pointerType);
|
|
1648
|
-
}
|
|
1649
|
-
else if (p.type === PointerEventTypes.POINTERUP && (this._currentActiveButton === evt.button || isTouch)) {
|
|
1650
|
-
try {
|
|
1651
|
-
srcElement === null || srcElement === void 0 ? void 0 : srcElement.releasePointerCapture(evt.pointerId);
|
|
1652
|
-
}
|
|
1653
|
-
catch (e) {
|
|
1654
|
-
//Nothing to do with the error.
|
|
1655
|
-
}
|
|
1656
|
-
if (!isTouch) {
|
|
1657
|
-
this._pointB = null; // Mouse and pen are mono pointer
|
|
1658
|
-
}
|
|
1659
|
-
//would be better to use pointers.remove(evt.pointerId) for multitouch gestures,
|
|
1660
|
-
//but emptying completely pointers collection is required to fix a bug on iPhone :
|
|
1661
|
-
//when changing orientation while pinching camera,
|
|
1662
|
-
//one pointer stay pressed forever if we don't release all pointers
|
|
1663
|
-
//will be ok to put back pointers.remove(evt.pointerId); when iPhone bug corrected
|
|
1664
|
-
if (engine._badOS) {
|
|
1665
|
-
this._pointA = this._pointB = null;
|
|
1666
|
-
}
|
|
1667
|
-
else {
|
|
1668
|
-
//only remove the impacted pointer in case of multitouch allowing on most
|
|
1669
|
-
//platforms switching from rotate to zoom and pan seamlessly.
|
|
1670
|
-
if (this._pointB && this._pointA && this._pointA.pointerId == evt.pointerId) {
|
|
1671
|
-
this._pointA = this._pointB;
|
|
1672
|
-
this._pointB = null;
|
|
1673
|
-
}
|
|
1674
|
-
else if (this._pointA && this._pointB && this._pointB.pointerId == evt.pointerId) {
|
|
1675
|
-
this._pointB = null;
|
|
1676
|
-
}
|
|
1677
|
-
else {
|
|
1678
|
-
this._pointA = this._pointB = null;
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
if (previousPinchSquaredDistance !== 0 || previousMultiTouchPanPosition) {
|
|
1682
|
-
// Previous pinch data is populated but a button has been lifted
|
|
1683
|
-
// so pinch has ended.
|
|
1684
|
-
this.onMultiTouch(this._pointA, this._pointB, previousPinchSquaredDistance, 0, // pinchSquaredDistance
|
|
1685
|
-
previousMultiTouchPanPosition, null // multiTouchPanPosition
|
|
1686
|
-
);
|
|
1687
|
-
previousPinchSquaredDistance = 0;
|
|
1688
|
-
previousMultiTouchPanPosition = null;
|
|
1689
|
-
}
|
|
1690
|
-
this._currentActiveButton = -1;
|
|
1691
|
-
this.onButtonUp(evt);
|
|
1692
|
-
if (!noPreventDefault) {
|
|
1693
|
-
evt.preventDefault();
|
|
1694
|
-
}
|
|
1695
|
-
}
|
|
1696
|
-
else if (p.type === PointerEventTypes.POINTERMOVE) {
|
|
1697
|
-
if (!noPreventDefault) {
|
|
1698
|
-
evt.preventDefault();
|
|
1699
|
-
}
|
|
1700
|
-
// One button down
|
|
1701
|
-
if (this._pointA && this._pointB === null) {
|
|
1702
|
-
const offsetX = evt.clientX - this._pointA.x;
|
|
1703
|
-
const offsetY = evt.clientY - this._pointA.y;
|
|
1704
|
-
this.onTouch(this._pointA, offsetX, offsetY);
|
|
1705
|
-
this._pointA.x = evt.clientX;
|
|
1706
|
-
this._pointA.y = evt.clientY;
|
|
1707
|
-
}
|
|
1708
|
-
// Two buttons down: pinch
|
|
1709
|
-
else if (this._pointA && this._pointB) {
|
|
1710
|
-
const ed = this._pointA.pointerId === evt.pointerId ? this._pointA : this._pointB;
|
|
1711
|
-
ed.x = evt.clientX;
|
|
1712
|
-
ed.y = evt.clientY;
|
|
1713
|
-
const distX = this._pointA.x - this._pointB.x;
|
|
1714
|
-
const distY = this._pointA.y - this._pointB.y;
|
|
1715
|
-
const pinchSquaredDistance = distX * distX + distY * distY;
|
|
1716
|
-
const multiTouchPanPosition = {
|
|
1717
|
-
x: (this._pointA.x + this._pointB.x) / 2,
|
|
1718
|
-
y: (this._pointA.y + this._pointB.y) / 2,
|
|
1719
|
-
pointerId: evt.pointerId,
|
|
1720
|
-
type: p.type,
|
|
1721
|
-
};
|
|
1722
|
-
this.onMultiTouch(this._pointA, this._pointB, previousPinchSquaredDistance, pinchSquaredDistance, previousMultiTouchPanPosition, multiTouchPanPosition);
|
|
1723
|
-
previousMultiTouchPanPosition = multiTouchPanPosition;
|
|
1724
|
-
previousPinchSquaredDistance = pinchSquaredDistance;
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
};
|
|
1728
|
-
this._observer = this.camera
|
|
1729
|
-
.getScene()
|
|
1730
|
-
._inputManager._addCameraPointerObserver(this._pointerInput, PointerEventTypes.POINTERDOWN | PointerEventTypes.POINTERUP | PointerEventTypes.POINTERMOVE | PointerEventTypes.POINTERDOUBLETAP);
|
|
1731
|
-
this._onLostFocus = () => {
|
|
1732
|
-
this._pointA = this._pointB = null;
|
|
1733
|
-
previousPinchSquaredDistance = 0;
|
|
1734
|
-
previousMultiTouchPanPosition = null;
|
|
1735
|
-
this.onLostFocus();
|
|
1736
|
-
};
|
|
1737
|
-
this._contextMenuBind = this.onContextMenu.bind(this);
|
|
1738
|
-
element && element.addEventListener("contextmenu", this._contextMenuBind, false);
|
|
1739
|
-
const hostWindow = this.camera.getScene().getEngine().getHostWindow();
|
|
1740
|
-
if (hostWindow) {
|
|
1741
|
-
Tools.RegisterTopRootEvents(hostWindow, [{ name: "blur", handler: this._onLostFocus }]);
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
/**
|
|
1745
|
-
* Detach the current controls from the specified dom element.
|
|
1746
|
-
*/
|
|
1747
|
-
detachControl() {
|
|
1748
|
-
if (this._onLostFocus) {
|
|
1749
|
-
const hostWindow = this.camera.getScene().getEngine().getHostWindow();
|
|
1750
|
-
if (hostWindow) {
|
|
1751
|
-
Tools.UnregisterTopRootEvents(hostWindow, [{ name: "blur", handler: this._onLostFocus }]);
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
if (this._observer) {
|
|
1755
|
-
this.camera.getScene()._inputManager._removeCameraPointerObserver(this._observer);
|
|
1756
|
-
this._observer = null;
|
|
1757
|
-
if (this._contextMenuBind) {
|
|
1758
|
-
const inputElement = this.camera.getScene().getEngine().getInputElement();
|
|
1759
|
-
inputElement && inputElement.removeEventListener("contextmenu", this._contextMenuBind);
|
|
1760
|
-
}
|
|
1761
|
-
this._onLostFocus = null;
|
|
1762
|
-
}
|
|
1763
|
-
this._altKey = false;
|
|
1764
|
-
this._ctrlKey = false;
|
|
1765
|
-
this._metaKey = false;
|
|
1766
|
-
this._shiftKey = false;
|
|
1767
|
-
this._buttonsPressed = 0;
|
|
1768
|
-
this._currentActiveButton = -1;
|
|
1769
|
-
}
|
|
1770
|
-
/**
|
|
1771
|
-
* Gets the class name of the current input.
|
|
1772
|
-
* @returns the class name
|
|
1773
|
-
*/
|
|
1774
|
-
getClassName() {
|
|
1775
|
-
return "BaseCameraPointersInput";
|
|
1776
|
-
}
|
|
1777
|
-
/**
|
|
1778
|
-
* Get the friendly name associated with the input class.
|
|
1779
|
-
* @returns the input friendly name
|
|
1780
|
-
*/
|
|
1781
|
-
getSimpleName() {
|
|
1782
|
-
return "pointers";
|
|
1783
|
-
}
|
|
1784
|
-
/**
|
|
1785
|
-
* Called on pointer POINTERDOUBLETAP event.
|
|
1786
|
-
* Override this method to provide functionality on POINTERDOUBLETAP event.
|
|
1787
|
-
* @param type
|
|
1788
|
-
*/
|
|
1789
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1790
|
-
onDoubleTap(type) { }
|
|
1791
|
-
/**
|
|
1792
|
-
* Called on pointer POINTERMOVE event if only a single touch is active.
|
|
1793
|
-
* Override this method to provide functionality.
|
|
1794
|
-
* @param point
|
|
1795
|
-
* @param offsetX
|
|
1796
|
-
* @param offsetY
|
|
1797
|
-
*/
|
|
1798
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1799
|
-
onTouch(point, offsetX, offsetY) { }
|
|
1800
|
-
/**
|
|
1801
|
-
* Called on pointer POINTERMOVE event if multiple touches are active.
|
|
1802
|
-
* Override this method to provide functionality.
|
|
1803
|
-
* @param _pointA
|
|
1804
|
-
* @param _pointB
|
|
1805
|
-
* @param previousPinchSquaredDistance
|
|
1806
|
-
* @param pinchSquaredDistance
|
|
1807
|
-
* @param previousMultiTouchPanPosition
|
|
1808
|
-
* @param multiTouchPanPosition
|
|
1809
|
-
*/
|
|
1810
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1811
|
-
onMultiTouch(_pointA, _pointB, previousPinchSquaredDistance, pinchSquaredDistance, previousMultiTouchPanPosition, multiTouchPanPosition) { }
|
|
1812
|
-
/**
|
|
1813
|
-
* Called on JS contextmenu event.
|
|
1814
|
-
* Override this method to provide functionality.
|
|
1815
|
-
* @param evt
|
|
1816
|
-
*/
|
|
1817
|
-
onContextMenu(evt) {
|
|
1818
|
-
evt.preventDefault();
|
|
1819
|
-
}
|
|
1820
|
-
/**
|
|
1821
|
-
* Called each time a new POINTERDOWN event occurs. Ie, for each button
|
|
1822
|
-
* press.
|
|
1823
|
-
* Override this method to provide functionality.
|
|
1824
|
-
* @param evt
|
|
1825
|
-
*/
|
|
1826
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1827
|
-
onButtonDown(evt) { }
|
|
1828
|
-
/**
|
|
1829
|
-
* Called each time a new POINTERUP event occurs. Ie, for each button
|
|
1830
|
-
* release.
|
|
1831
|
-
* Override this method to provide functionality.
|
|
1832
|
-
* @param evt
|
|
1833
|
-
*/
|
|
1834
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1835
|
-
onButtonUp(evt) { }
|
|
1836
|
-
/**
|
|
1837
|
-
* Called when window becomes inactive.
|
|
1838
|
-
* Override this method to provide functionality.
|
|
1839
|
-
*/
|
|
1840
|
-
onLostFocus() { }
|
|
1841
|
-
}
|
|
1842
|
-
__decorate([
|
|
1843
|
-
serialize()
|
|
1844
|
-
], BaseCameraPointersInput.prototype, "buttons", void 0);
|
|
1845
|
-
|
|
1846
|
-
/**
|
|
1847
|
-
* Manage the pointers inputs to control an arc rotate camera.
|
|
1848
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
|
|
1849
|
-
*/
|
|
1850
|
-
class ArcRotateCameraPointersInput extends BaseCameraPointersInput {
|
|
1851
|
-
constructor() {
|
|
1852
|
-
super(...arguments);
|
|
1853
|
-
/**
|
|
1854
|
-
* Defines the buttons associated with the input to handle camera move.
|
|
1855
|
-
*/
|
|
1856
|
-
this.buttons = [0, 1, 2];
|
|
1857
|
-
/**
|
|
1858
|
-
* Defines the pointer angular sensibility along the X axis or how fast is
|
|
1859
|
-
* the camera rotating.
|
|
1860
|
-
*/
|
|
1861
|
-
this.angularSensibilityX = 1000.0;
|
|
1862
|
-
/**
|
|
1863
|
-
* Defines the pointer angular sensibility along the Y axis or how fast is
|
|
1864
|
-
* the camera rotating.
|
|
1865
|
-
*/
|
|
1866
|
-
this.angularSensibilityY = 1000.0;
|
|
1867
|
-
/**
|
|
1868
|
-
* Defines the pointer pinch precision or how fast is the camera zooming.
|
|
1869
|
-
*/
|
|
1870
|
-
this.pinchPrecision = 12.0;
|
|
1871
|
-
/**
|
|
1872
|
-
* pinchDeltaPercentage will be used instead of pinchPrecision if different
|
|
1873
|
-
* from 0.
|
|
1874
|
-
* It defines the percentage of current camera.radius to use as delta when
|
|
1875
|
-
* pinch zoom is used.
|
|
1876
|
-
*/
|
|
1877
|
-
this.pinchDeltaPercentage = 0;
|
|
1878
|
-
/**
|
|
1879
|
-
* When useNaturalPinchZoom is true, multi touch zoom will zoom in such
|
|
1880
|
-
* that any object in the plane at the camera's target point will scale
|
|
1881
|
-
* perfectly with finger motion.
|
|
1882
|
-
* Overrides pinchDeltaPercentage and pinchPrecision.
|
|
1883
|
-
*/
|
|
1884
|
-
this.useNaturalPinchZoom = false;
|
|
1885
|
-
/**
|
|
1886
|
-
* Defines whether zoom (2 fingers pinch) is enabled through multitouch
|
|
1887
|
-
*/
|
|
1888
|
-
this.pinchZoom = true;
|
|
1889
|
-
/**
|
|
1890
|
-
* Defines the pointer panning sensibility or how fast is the camera moving.
|
|
1891
|
-
*/
|
|
1892
|
-
this.panningSensibility = 1000.0;
|
|
1893
|
-
/**
|
|
1894
|
-
* Defines whether panning (2 fingers swipe) is enabled through multitouch.
|
|
1895
|
-
*/
|
|
1896
|
-
this.multiTouchPanning = true;
|
|
1897
|
-
/**
|
|
1898
|
-
* Defines whether panning is enabled for both pan (2 fingers swipe) and
|
|
1899
|
-
* zoom (pinch) through multitouch.
|
|
1900
|
-
*/
|
|
1901
|
-
this.multiTouchPanAndZoom = true;
|
|
1902
|
-
/**
|
|
1903
|
-
* Revers pinch action direction.
|
|
1904
|
-
*/
|
|
1905
|
-
this.pinchInwards = true;
|
|
1906
|
-
this._isPanClick = false;
|
|
1907
|
-
this._twoFingerActivityCount = 0;
|
|
1908
|
-
this._isPinching = false;
|
|
1909
|
-
}
|
|
1910
|
-
/**
|
|
1911
|
-
* Gets the class name of the current input.
|
|
1912
|
-
* @returns the class name
|
|
1913
|
-
*/
|
|
1914
|
-
getClassName() {
|
|
1915
|
-
return "ArcRotateCameraPointersInput";
|
|
1916
|
-
}
|
|
1917
|
-
/**
|
|
1918
|
-
* Move camera from multi touch panning positions.
|
|
1919
|
-
* @param previousMultiTouchPanPosition
|
|
1920
|
-
* @param multiTouchPanPosition
|
|
1921
|
-
*/
|
|
1922
|
-
_computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition) {
|
|
1923
|
-
if (this.panningSensibility !== 0 && previousMultiTouchPanPosition && multiTouchPanPosition) {
|
|
1924
|
-
const moveDeltaX = multiTouchPanPosition.x - previousMultiTouchPanPosition.x;
|
|
1925
|
-
const moveDeltaY = multiTouchPanPosition.y - previousMultiTouchPanPosition.y;
|
|
1926
|
-
this.camera.inertialPanningX += -moveDeltaX / this.panningSensibility;
|
|
1927
|
-
this.camera.inertialPanningY += moveDeltaY / this.panningSensibility;
|
|
1928
|
-
}
|
|
1929
|
-
}
|
|
1930
|
-
/**
|
|
1931
|
-
* Move camera from pinch zoom distances.
|
|
1932
|
-
* @param previousPinchSquaredDistance
|
|
1933
|
-
* @param pinchSquaredDistance
|
|
1934
|
-
*/
|
|
1935
|
-
_computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance) {
|
|
1936
|
-
const radius = this.camera.radius || ArcRotateCameraPointersInput.MinimumRadiusForPinch;
|
|
1937
|
-
if (this.useNaturalPinchZoom) {
|
|
1938
|
-
this.camera.radius = (radius * Math.sqrt(previousPinchSquaredDistance)) / Math.sqrt(pinchSquaredDistance);
|
|
1939
|
-
}
|
|
1940
|
-
else if (this.pinchDeltaPercentage) {
|
|
1941
|
-
this.camera.inertialRadiusOffset += (pinchSquaredDistance - previousPinchSquaredDistance) * 0.001 * radius * this.pinchDeltaPercentage;
|
|
1942
|
-
}
|
|
1943
|
-
else {
|
|
1944
|
-
this.camera.inertialRadiusOffset +=
|
|
1945
|
-
(pinchSquaredDistance - previousPinchSquaredDistance) /
|
|
1946
|
-
((this.pinchPrecision * (this.pinchInwards ? 1 : -1) * (this.angularSensibilityX + this.angularSensibilityY)) / 2);
|
|
1947
|
-
}
|
|
1948
|
-
}
|
|
1949
|
-
/**
|
|
1950
|
-
* Called on pointer POINTERMOVE event if only a single touch is active.
|
|
1951
|
-
* @param point
|
|
1952
|
-
* @param offsetX
|
|
1953
|
-
* @param offsetY
|
|
1954
|
-
*/
|
|
1955
|
-
onTouch(point, offsetX, offsetY) {
|
|
1956
|
-
if (this.panningSensibility !== 0 && ((this._ctrlKey && this.camera._useCtrlForPanning) || this._isPanClick)) {
|
|
1957
|
-
this.camera.inertialPanningX += -offsetX / this.panningSensibility;
|
|
1958
|
-
this.camera.inertialPanningY += offsetY / this.panningSensibility;
|
|
1959
|
-
}
|
|
1960
|
-
else {
|
|
1961
|
-
this.camera.inertialAlphaOffset -= offsetX / this.angularSensibilityX;
|
|
1962
|
-
this.camera.inertialBetaOffset -= offsetY / this.angularSensibilityY;
|
|
1963
|
-
}
|
|
1964
|
-
}
|
|
1965
|
-
/**
|
|
1966
|
-
* Called on pointer POINTERDOUBLETAP event.
|
|
1967
|
-
*/
|
|
1968
|
-
onDoubleTap() {
|
|
1969
|
-
if (this.camera.useInputToRestoreState) {
|
|
1970
|
-
this.camera.restoreState();
|
|
1971
|
-
}
|
|
1972
|
-
}
|
|
1973
|
-
/**
|
|
1974
|
-
* Called on pointer POINTERMOVE event if multiple touches are active.
|
|
1975
|
-
* @param pointA
|
|
1976
|
-
* @param pointB
|
|
1977
|
-
* @param previousPinchSquaredDistance
|
|
1978
|
-
* @param pinchSquaredDistance
|
|
1979
|
-
* @param previousMultiTouchPanPosition
|
|
1980
|
-
* @param multiTouchPanPosition
|
|
1981
|
-
*/
|
|
1982
|
-
onMultiTouch(pointA, pointB, previousPinchSquaredDistance, pinchSquaredDistance, previousMultiTouchPanPosition, multiTouchPanPosition) {
|
|
1983
|
-
if (previousPinchSquaredDistance === 0 && previousMultiTouchPanPosition === null) {
|
|
1984
|
-
// First time this method is called for new pinch.
|
|
1985
|
-
// Next time this is called there will be a
|
|
1986
|
-
// previousPinchSquaredDistance and pinchSquaredDistance to compare.
|
|
1987
|
-
return;
|
|
1988
|
-
}
|
|
1989
|
-
if (pinchSquaredDistance === 0 && multiTouchPanPosition === null) {
|
|
1990
|
-
// Last time this method is called at the end of a pinch.
|
|
1991
|
-
return;
|
|
1992
|
-
}
|
|
1993
|
-
// Zoom and panning enabled together
|
|
1994
|
-
if (this.multiTouchPanAndZoom) {
|
|
1995
|
-
this._computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance);
|
|
1996
|
-
this._computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition);
|
|
1997
|
-
// Zoom and panning enabled but only one at a time
|
|
1998
|
-
}
|
|
1999
|
-
else if (this.multiTouchPanning && this.pinchZoom) {
|
|
2000
|
-
this._twoFingerActivityCount++;
|
|
2001
|
-
if (this._isPinching ||
|
|
2002
|
-
(this._twoFingerActivityCount < 20 && Math.abs(Math.sqrt(pinchSquaredDistance) - Math.sqrt(previousPinchSquaredDistance)) > this.camera.pinchToPanMaxDistance)) {
|
|
2003
|
-
// Since pinch has not been active long, assume we intend to zoom.
|
|
2004
|
-
this._computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance);
|
|
2005
|
-
// Since we are pinching, remain pinching on next iteration.
|
|
2006
|
-
this._isPinching = true;
|
|
2007
|
-
}
|
|
2008
|
-
else {
|
|
2009
|
-
// Pause between pinch starting and moving implies not a zoom event. Pan instead.
|
|
2010
|
-
this._computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition);
|
|
2011
|
-
}
|
|
2012
|
-
// Panning enabled, zoom disabled
|
|
2013
|
-
}
|
|
2014
|
-
else if (this.multiTouchPanning) {
|
|
2015
|
-
this._computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition);
|
|
2016
|
-
// Zoom enabled, panning disabled
|
|
2017
|
-
}
|
|
2018
|
-
else if (this.pinchZoom) {
|
|
2019
|
-
this._computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance);
|
|
2020
|
-
}
|
|
2021
|
-
}
|
|
2022
|
-
/**
|
|
2023
|
-
* Called each time a new POINTERDOWN event occurs. Ie, for each button
|
|
2024
|
-
* press.
|
|
2025
|
-
* @param evt
|
|
2026
|
-
*/
|
|
2027
|
-
onButtonDown(evt) {
|
|
2028
|
-
this._isPanClick = evt.button === this.camera._panningMouseButton;
|
|
2029
|
-
}
|
|
2030
|
-
/**
|
|
2031
|
-
* Called each time a new POINTERUP event occurs. Ie, for each button
|
|
2032
|
-
* release.
|
|
2033
|
-
*/
|
|
2034
|
-
onButtonUp() {
|
|
2035
|
-
this._twoFingerActivityCount = 0;
|
|
2036
|
-
this._isPinching = false;
|
|
2037
|
-
}
|
|
2038
|
-
/**
|
|
2039
|
-
* Called when window becomes inactive.
|
|
2040
|
-
*/
|
|
2041
|
-
onLostFocus() {
|
|
2042
|
-
this._isPanClick = false;
|
|
2043
|
-
this._twoFingerActivityCount = 0;
|
|
2044
|
-
this._isPinching = false;
|
|
2045
|
-
}
|
|
2046
|
-
}
|
|
2047
|
-
/**
|
|
2048
|
-
* The minimum radius used for pinch, to avoid radius lock at 0
|
|
2049
|
-
*/
|
|
2050
|
-
ArcRotateCameraPointersInput.MinimumRadiusForPinch = 0.001;
|
|
2051
|
-
__decorate([
|
|
2052
|
-
serialize()
|
|
2053
|
-
], ArcRotateCameraPointersInput.prototype, "buttons", void 0);
|
|
2054
|
-
__decorate([
|
|
2055
|
-
serialize()
|
|
2056
|
-
], ArcRotateCameraPointersInput.prototype, "angularSensibilityX", void 0);
|
|
2057
|
-
__decorate([
|
|
2058
|
-
serialize()
|
|
2059
|
-
], ArcRotateCameraPointersInput.prototype, "angularSensibilityY", void 0);
|
|
2060
|
-
__decorate([
|
|
2061
|
-
serialize()
|
|
2062
|
-
], ArcRotateCameraPointersInput.prototype, "pinchPrecision", void 0);
|
|
2063
|
-
__decorate([
|
|
2064
|
-
serialize()
|
|
2065
|
-
], ArcRotateCameraPointersInput.prototype, "pinchDeltaPercentage", void 0);
|
|
2066
|
-
__decorate([
|
|
2067
|
-
serialize()
|
|
2068
|
-
], ArcRotateCameraPointersInput.prototype, "useNaturalPinchZoom", void 0);
|
|
2069
|
-
__decorate([
|
|
2070
|
-
serialize()
|
|
2071
|
-
], ArcRotateCameraPointersInput.prototype, "pinchZoom", void 0);
|
|
2072
|
-
__decorate([
|
|
2073
|
-
serialize()
|
|
2074
|
-
], ArcRotateCameraPointersInput.prototype, "panningSensibility", void 0);
|
|
2075
|
-
__decorate([
|
|
2076
|
-
serialize()
|
|
2077
|
-
], ArcRotateCameraPointersInput.prototype, "multiTouchPanning", void 0);
|
|
2078
|
-
__decorate([
|
|
2079
|
-
serialize()
|
|
2080
|
-
], ArcRotateCameraPointersInput.prototype, "multiTouchPanAndZoom", void 0);
|
|
2081
|
-
CameraInputTypes["ArcRotateCameraPointersInput"] = ArcRotateCameraPointersInput;
|
|
2082
|
-
|
|
2083
|
-
/**
|
|
2084
|
-
* Manage the keyboard inputs to control the movement of an arc rotate camera.
|
|
2085
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
|
|
2086
|
-
*/
|
|
2087
|
-
class ArcRotateCameraKeyboardMoveInput {
|
|
2088
|
-
constructor() {
|
|
2089
|
-
/**
|
|
2090
|
-
* Defines the list of key codes associated with the up action (increase alpha)
|
|
2091
|
-
*/
|
|
2092
|
-
this.keysUp = [38];
|
|
2093
|
-
/**
|
|
2094
|
-
* Defines the list of key codes associated with the down action (decrease alpha)
|
|
2095
|
-
*/
|
|
2096
|
-
this.keysDown = [40];
|
|
2097
|
-
/**
|
|
2098
|
-
* Defines the list of key codes associated with the left action (increase beta)
|
|
2099
|
-
*/
|
|
2100
|
-
this.keysLeft = [37];
|
|
2101
|
-
/**
|
|
2102
|
-
* Defines the list of key codes associated with the right action (decrease beta)
|
|
2103
|
-
*/
|
|
2104
|
-
this.keysRight = [39];
|
|
2105
|
-
/**
|
|
2106
|
-
* Defines the list of key codes associated with the reset action.
|
|
2107
|
-
* Those keys reset the camera to its last stored state (with the method camera.storeState())
|
|
2108
|
-
*/
|
|
2109
|
-
this.keysReset = [220];
|
|
2110
|
-
/**
|
|
2111
|
-
* Defines the panning sensibility of the inputs.
|
|
2112
|
-
* (How fast is the camera panning)
|
|
2113
|
-
*/
|
|
2114
|
-
this.panningSensibility = 50.0;
|
|
2115
|
-
/**
|
|
2116
|
-
* Defines the zooming sensibility of the inputs.
|
|
2117
|
-
* (How fast is the camera zooming)
|
|
2118
|
-
*/
|
|
2119
|
-
this.zoomingSensibility = 25.0;
|
|
2120
|
-
/**
|
|
2121
|
-
* Defines whether maintaining the alt key down switch the movement mode from
|
|
2122
|
-
* orientation to zoom.
|
|
2123
|
-
*/
|
|
2124
|
-
this.useAltToZoom = true;
|
|
2125
|
-
/**
|
|
2126
|
-
* Rotation speed of the camera
|
|
2127
|
-
*/
|
|
2128
|
-
this.angularSpeed = 0.01;
|
|
2129
|
-
this._keys = new Array();
|
|
2130
|
-
}
|
|
2131
|
-
/**
|
|
2132
|
-
* Attach the input controls to a specific dom element to get the input from.
|
|
2133
|
-
* @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
|
|
2134
|
-
*/
|
|
2135
|
-
attachControl(noPreventDefault) {
|
|
2136
|
-
// was there a second variable defined?
|
|
2137
|
-
// eslint-disable-next-line prefer-rest-params
|
|
2138
|
-
noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
|
|
2139
|
-
if (this._onCanvasBlurObserver) {
|
|
2140
|
-
return;
|
|
2141
|
-
}
|
|
2142
|
-
this._scene = this.camera.getScene();
|
|
2143
|
-
this._engine = this._scene.getEngine();
|
|
2144
|
-
this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(() => {
|
|
2145
|
-
this._keys.length = 0;
|
|
2146
|
-
});
|
|
2147
|
-
this._onKeyboardObserver = this._scene.onKeyboardObservable.add((info) => {
|
|
2148
|
-
const evt = info.event;
|
|
2149
|
-
if (!evt.metaKey) {
|
|
2150
|
-
if (info.type === KeyboardEventTypes.KEYDOWN) {
|
|
2151
|
-
this._ctrlPressed = evt.ctrlKey;
|
|
2152
|
-
this._altPressed = evt.altKey;
|
|
2153
|
-
if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
|
|
2154
|
-
this.keysDown.indexOf(evt.keyCode) !== -1 ||
|
|
2155
|
-
this.keysLeft.indexOf(evt.keyCode) !== -1 ||
|
|
2156
|
-
this.keysRight.indexOf(evt.keyCode) !== -1 ||
|
|
2157
|
-
this.keysReset.indexOf(evt.keyCode) !== -1) {
|
|
2158
|
-
const index = this._keys.indexOf(evt.keyCode);
|
|
2159
|
-
if (index === -1) {
|
|
2160
|
-
this._keys.push(evt.keyCode);
|
|
2161
|
-
}
|
|
2162
|
-
if (evt.preventDefault) {
|
|
2163
|
-
if (!noPreventDefault) {
|
|
2164
|
-
evt.preventDefault();
|
|
2165
|
-
}
|
|
2166
|
-
}
|
|
2167
|
-
}
|
|
2168
|
-
}
|
|
2169
|
-
else {
|
|
2170
|
-
if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
|
|
2171
|
-
this.keysDown.indexOf(evt.keyCode) !== -1 ||
|
|
2172
|
-
this.keysLeft.indexOf(evt.keyCode) !== -1 ||
|
|
2173
|
-
this.keysRight.indexOf(evt.keyCode) !== -1 ||
|
|
2174
|
-
this.keysReset.indexOf(evt.keyCode) !== -1) {
|
|
2175
|
-
const index = this._keys.indexOf(evt.keyCode);
|
|
2176
|
-
if (index >= 0) {
|
|
2177
|
-
this._keys.splice(index, 1);
|
|
2178
|
-
}
|
|
2179
|
-
if (evt.preventDefault) {
|
|
2180
|
-
if (!noPreventDefault) {
|
|
2181
|
-
evt.preventDefault();
|
|
2182
|
-
}
|
|
2183
|
-
}
|
|
2184
|
-
}
|
|
2185
|
-
}
|
|
2186
|
-
}
|
|
2187
|
-
});
|
|
2188
|
-
}
|
|
2189
|
-
/**
|
|
2190
|
-
* Detach the current controls from the specified dom element.
|
|
2191
|
-
*/
|
|
2192
|
-
detachControl() {
|
|
2193
|
-
if (this._scene) {
|
|
2194
|
-
if (this._onKeyboardObserver) {
|
|
2195
|
-
this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);
|
|
2196
|
-
}
|
|
2197
|
-
if (this._onCanvasBlurObserver) {
|
|
2198
|
-
this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
|
|
2199
|
-
}
|
|
2200
|
-
this._onKeyboardObserver = null;
|
|
2201
|
-
this._onCanvasBlurObserver = null;
|
|
2202
|
-
}
|
|
2203
|
-
this._keys.length = 0;
|
|
2204
|
-
}
|
|
2205
|
-
/**
|
|
2206
|
-
* Update the current camera state depending on the inputs that have been used this frame.
|
|
2207
|
-
* This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
|
|
2208
|
-
*/
|
|
2209
|
-
checkInputs() {
|
|
2210
|
-
if (this._onKeyboardObserver) {
|
|
2211
|
-
const camera = this.camera;
|
|
2212
|
-
for (let index = 0; index < this._keys.length; index++) {
|
|
2213
|
-
const keyCode = this._keys[index];
|
|
2214
|
-
if (this.keysLeft.indexOf(keyCode) !== -1) {
|
|
2215
|
-
if (this._ctrlPressed && this.camera._useCtrlForPanning) {
|
|
2216
|
-
camera.inertialPanningX -= 1 / this.panningSensibility;
|
|
2217
|
-
}
|
|
2218
|
-
else {
|
|
2219
|
-
camera.inertialAlphaOffset -= this.angularSpeed;
|
|
2220
|
-
}
|
|
2221
|
-
}
|
|
2222
|
-
else if (this.keysUp.indexOf(keyCode) !== -1) {
|
|
2223
|
-
if (this._ctrlPressed && this.camera._useCtrlForPanning) {
|
|
2224
|
-
camera.inertialPanningY += 1 / this.panningSensibility;
|
|
2225
|
-
}
|
|
2226
|
-
else if (this._altPressed && this.useAltToZoom) {
|
|
2227
|
-
camera.inertialRadiusOffset += 1 / this.zoomingSensibility;
|
|
2228
|
-
}
|
|
2229
|
-
else {
|
|
2230
|
-
camera.inertialBetaOffset -= this.angularSpeed;
|
|
2231
|
-
}
|
|
2232
|
-
}
|
|
2233
|
-
else if (this.keysRight.indexOf(keyCode) !== -1) {
|
|
2234
|
-
if (this._ctrlPressed && this.camera._useCtrlForPanning) {
|
|
2235
|
-
camera.inertialPanningX += 1 / this.panningSensibility;
|
|
2236
|
-
}
|
|
2237
|
-
else {
|
|
2238
|
-
camera.inertialAlphaOffset += this.angularSpeed;
|
|
2239
|
-
}
|
|
2240
|
-
}
|
|
2241
|
-
else if (this.keysDown.indexOf(keyCode) !== -1) {
|
|
2242
|
-
if (this._ctrlPressed && this.camera._useCtrlForPanning) {
|
|
2243
|
-
camera.inertialPanningY -= 1 / this.panningSensibility;
|
|
2244
|
-
}
|
|
2245
|
-
else if (this._altPressed && this.useAltToZoom) {
|
|
2246
|
-
camera.inertialRadiusOffset -= 1 / this.zoomingSensibility;
|
|
2247
|
-
}
|
|
2248
|
-
else {
|
|
2249
|
-
camera.inertialBetaOffset += this.angularSpeed;
|
|
2250
|
-
}
|
|
2251
|
-
}
|
|
2252
|
-
else if (this.keysReset.indexOf(keyCode) !== -1) {
|
|
2253
|
-
if (camera.useInputToRestoreState) {
|
|
2254
|
-
camera.restoreState();
|
|
2255
|
-
}
|
|
2256
|
-
}
|
|
2257
|
-
}
|
|
2258
|
-
}
|
|
2259
|
-
}
|
|
2260
|
-
/**
|
|
2261
|
-
* Gets the class name of the current input.
|
|
2262
|
-
* @returns the class name
|
|
2263
|
-
*/
|
|
2264
|
-
getClassName() {
|
|
2265
|
-
return "ArcRotateCameraKeyboardMoveInput";
|
|
2266
|
-
}
|
|
2267
|
-
/**
|
|
2268
|
-
* Get the friendly name associated with the input class.
|
|
2269
|
-
* @returns the input friendly name
|
|
2270
|
-
*/
|
|
2271
|
-
getSimpleName() {
|
|
2272
|
-
return "keyboard";
|
|
2273
|
-
}
|
|
2274
|
-
}
|
|
2275
|
-
__decorate([
|
|
2276
|
-
serialize()
|
|
2277
|
-
], ArcRotateCameraKeyboardMoveInput.prototype, "keysUp", void 0);
|
|
2278
|
-
__decorate([
|
|
2279
|
-
serialize()
|
|
2280
|
-
], ArcRotateCameraKeyboardMoveInput.prototype, "keysDown", void 0);
|
|
2281
|
-
__decorate([
|
|
2282
|
-
serialize()
|
|
2283
|
-
], ArcRotateCameraKeyboardMoveInput.prototype, "keysLeft", void 0);
|
|
2284
|
-
__decorate([
|
|
2285
|
-
serialize()
|
|
2286
|
-
], ArcRotateCameraKeyboardMoveInput.prototype, "keysRight", void 0);
|
|
2287
|
-
__decorate([
|
|
2288
|
-
serialize()
|
|
2289
|
-
], ArcRotateCameraKeyboardMoveInput.prototype, "keysReset", void 0);
|
|
2290
|
-
__decorate([
|
|
2291
|
-
serialize()
|
|
2292
|
-
], ArcRotateCameraKeyboardMoveInput.prototype, "panningSensibility", void 0);
|
|
2293
|
-
__decorate([
|
|
2294
|
-
serialize()
|
|
2295
|
-
], ArcRotateCameraKeyboardMoveInput.prototype, "zoomingSensibility", void 0);
|
|
2296
|
-
__decorate([
|
|
2297
|
-
serialize()
|
|
2298
|
-
], ArcRotateCameraKeyboardMoveInput.prototype, "useAltToZoom", void 0);
|
|
2299
|
-
__decorate([
|
|
2300
|
-
serialize()
|
|
2301
|
-
], ArcRotateCameraKeyboardMoveInput.prototype, "angularSpeed", void 0);
|
|
2302
|
-
CameraInputTypes["ArcRotateCameraKeyboardMoveInput"] = ArcRotateCameraKeyboardMoveInput;
|
|
2303
|
-
|
|
2304
|
-
/**
|
|
2305
|
-
* Firefox uses a different scheme to report scroll distances to other
|
|
2306
|
-
* browsers. Rather than use complicated methods to calculate the exact
|
|
2307
|
-
* multiple we need to apply, let's just cheat and use a constant.
|
|
2308
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/deltaMode
|
|
2309
|
-
* https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
|
|
2310
|
-
*/
|
|
2311
|
-
const ffMultiplier = 40;
|
|
2312
|
-
/**
|
|
2313
|
-
* Manage the mouse wheel inputs to control an arc rotate camera.
|
|
2314
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
|
|
2315
|
-
*/
|
|
2316
|
-
class ArcRotateCameraMouseWheelInput {
|
|
2317
|
-
constructor() {
|
|
2318
|
-
/**
|
|
2319
|
-
* Gets or Set the mouse wheel precision or how fast is the camera zooming.
|
|
2320
|
-
*/
|
|
2321
|
-
this.wheelPrecision = 3.0;
|
|
2322
|
-
/**
|
|
2323
|
-
* Gets or Set the boolean value that controls whether or not the mouse wheel
|
|
2324
|
-
* zooms to the location of the mouse pointer or not. The default is false.
|
|
2325
|
-
*/
|
|
2326
|
-
this.zoomToMouseLocation = false;
|
|
2327
|
-
/**
|
|
2328
|
-
* wheelDeltaPercentage will be used instead of wheelPrecision if different from 0.
|
|
2329
|
-
* It defines the percentage of current camera.radius to use as delta when wheel is used.
|
|
2330
|
-
*/
|
|
2331
|
-
this.wheelDeltaPercentage = 0;
|
|
2332
|
-
/**
|
|
2333
|
-
* If set, this function will be used to set the radius delta that will be added to the current camera radius
|
|
2334
|
-
*/
|
|
2335
|
-
this.customComputeDeltaFromMouseWheel = null;
|
|
2336
|
-
this._inertialPanning = Vector3.Zero();
|
|
2337
|
-
}
|
|
2338
|
-
_computeDeltaFromMouseWheelLegacyEvent(mouseWheelDelta, radius) {
|
|
2339
|
-
let delta = 0;
|
|
2340
|
-
const wheelDelta = mouseWheelDelta * 0.01 * this.wheelDeltaPercentage * radius;
|
|
2341
|
-
if (mouseWheelDelta > 0) {
|
|
2342
|
-
delta = wheelDelta / (1.0 + this.wheelDeltaPercentage);
|
|
2343
|
-
}
|
|
2344
|
-
else {
|
|
2345
|
-
delta = wheelDelta * (1.0 + this.wheelDeltaPercentage);
|
|
2346
|
-
}
|
|
2347
|
-
return delta;
|
|
2348
|
-
}
|
|
2349
|
-
/**
|
|
2350
|
-
* Attach the input controls to a specific dom element to get the input from.
|
|
2351
|
-
* @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
|
|
2352
|
-
*/
|
|
2353
|
-
attachControl(noPreventDefault) {
|
|
2354
|
-
noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
|
|
2355
|
-
this._wheel = (p) => {
|
|
2356
|
-
//sanity check - this should be a PointerWheel event.
|
|
2357
|
-
if (p.type !== PointerEventTypes.POINTERWHEEL) {
|
|
2358
|
-
return;
|
|
2359
|
-
}
|
|
2360
|
-
const event = p.event;
|
|
2361
|
-
let delta = 0;
|
|
2362
|
-
const platformScale = event.deltaMode === EventConstants.DOM_DELTA_LINE ? ffMultiplier : 1; // If this happens to be set to DOM_DELTA_LINE, adjust accordingly
|
|
2363
|
-
const wheelDelta = -(event.deltaY * platformScale);
|
|
2364
|
-
if (this.customComputeDeltaFromMouseWheel) {
|
|
2365
|
-
delta = this.customComputeDeltaFromMouseWheel(wheelDelta, this, event);
|
|
2366
|
-
}
|
|
2367
|
-
else {
|
|
2368
|
-
if (this.wheelDeltaPercentage) {
|
|
2369
|
-
delta = this._computeDeltaFromMouseWheelLegacyEvent(wheelDelta, this.camera.radius);
|
|
2370
|
-
// If zooming in, estimate the target radius and use that to compute the delta for inertia
|
|
2371
|
-
// this will stop multiple scroll events zooming in from adding too much inertia
|
|
2372
|
-
if (delta > 0) {
|
|
2373
|
-
let estimatedTargetRadius = this.camera.radius;
|
|
2374
|
-
let targetInertia = this.camera.inertialRadiusOffset + delta;
|
|
2375
|
-
for (let i = 0; i < 20 && Math.abs(targetInertia) > 0.001; i++) {
|
|
2376
|
-
estimatedTargetRadius -= targetInertia;
|
|
2377
|
-
targetInertia *= this.camera.inertia;
|
|
2378
|
-
}
|
|
2379
|
-
estimatedTargetRadius = Scalar.Clamp(estimatedTargetRadius, 0, Number.MAX_VALUE);
|
|
2380
|
-
delta = this._computeDeltaFromMouseWheelLegacyEvent(wheelDelta, estimatedTargetRadius);
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2383
|
-
else {
|
|
2384
|
-
delta = wheelDelta / (this.wheelPrecision * 40);
|
|
2385
|
-
}
|
|
2386
|
-
}
|
|
2387
|
-
if (delta) {
|
|
2388
|
-
if (this.zoomToMouseLocation) {
|
|
2389
|
-
// If we are zooming to the mouse location, then we need to get the hit plane at the start of the zoom gesture if it doesn't exist
|
|
2390
|
-
// The hit plane is normally calculated after the first motion and each time there's motion so if we don't do this first,
|
|
2391
|
-
// the first zoom will be to the center of the screen
|
|
2392
|
-
if (!this._hitPlane) {
|
|
2393
|
-
this._updateHitPlane();
|
|
2394
|
-
}
|
|
2395
|
-
this._zoomToMouse(delta);
|
|
2396
|
-
}
|
|
2397
|
-
else {
|
|
2398
|
-
this.camera.inertialRadiusOffset += delta;
|
|
2399
|
-
}
|
|
2400
|
-
}
|
|
2401
|
-
if (event.preventDefault) {
|
|
2402
|
-
if (!noPreventDefault) {
|
|
2403
|
-
event.preventDefault();
|
|
2404
|
-
}
|
|
2405
|
-
}
|
|
2406
|
-
};
|
|
2407
|
-
this._observer = this.camera.getScene()._inputManager._addCameraPointerObserver(this._wheel, PointerEventTypes.POINTERWHEEL);
|
|
2408
|
-
if (this.zoomToMouseLocation) {
|
|
2409
|
-
this._inertialPanning.setAll(0);
|
|
2410
|
-
}
|
|
2411
|
-
}
|
|
2412
|
-
/**
|
|
2413
|
-
* Detach the current controls from the specified dom element.
|
|
2414
|
-
*/
|
|
2415
|
-
detachControl() {
|
|
2416
|
-
if (this._observer) {
|
|
2417
|
-
this.camera.getScene()._inputManager._removeCameraPointerObserver(this._observer);
|
|
2418
|
-
this._observer = null;
|
|
2419
|
-
this._wheel = null;
|
|
2420
|
-
}
|
|
2421
|
-
}
|
|
2422
|
-
/**
|
|
2423
|
-
* Update the current camera state depending on the inputs that have been used this frame.
|
|
2424
|
-
* This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
|
|
2425
|
-
*/
|
|
2426
|
-
checkInputs() {
|
|
2427
|
-
if (!this.zoomToMouseLocation) {
|
|
2428
|
-
return;
|
|
2429
|
-
}
|
|
2430
|
-
const camera = this.camera;
|
|
2431
|
-
const motion = 0.0 + camera.inertialAlphaOffset + camera.inertialBetaOffset + camera.inertialRadiusOffset;
|
|
2432
|
-
if (motion) {
|
|
2433
|
-
// if zooming is still happening as a result of inertia, then we also need to update
|
|
2434
|
-
// the hit plane.
|
|
2435
|
-
this._updateHitPlane();
|
|
2436
|
-
// Note we cannot use arcRotateCamera.inertialPlanning here because arcRotateCamera panning
|
|
2437
|
-
// uses a different panningInertia which could cause this panning to get out of sync with
|
|
2438
|
-
// the zooming, and for this to work they must be exactly in sync.
|
|
2439
|
-
camera.target.addInPlace(this._inertialPanning);
|
|
2440
|
-
this._inertialPanning.scaleInPlace(camera.inertia);
|
|
2441
|
-
this._zeroIfClose(this._inertialPanning);
|
|
2442
|
-
}
|
|
2443
|
-
}
|
|
2444
|
-
/**
|
|
2445
|
-
* Gets the class name of the current input.
|
|
2446
|
-
* @returns the class name
|
|
2447
|
-
*/
|
|
2448
|
-
getClassName() {
|
|
2449
|
-
return "ArcRotateCameraMouseWheelInput";
|
|
2450
|
-
}
|
|
2451
|
-
/**
|
|
2452
|
-
* Get the friendly name associated with the input class.
|
|
2453
|
-
* @returns the input friendly name
|
|
2454
|
-
*/
|
|
2455
|
-
getSimpleName() {
|
|
2456
|
-
return "mousewheel";
|
|
2457
|
-
}
|
|
2458
|
-
_updateHitPlane() {
|
|
2459
|
-
const camera = this.camera;
|
|
2460
|
-
const direction = camera.target.subtract(camera.position);
|
|
2461
|
-
this._hitPlane = Plane.FromPositionAndNormal(camera.target, direction);
|
|
2462
|
-
}
|
|
2463
|
-
// Get position on the hit plane
|
|
2464
|
-
_getPosition() {
|
|
2465
|
-
var _a;
|
|
2466
|
-
const camera = this.camera;
|
|
2467
|
-
const scene = camera.getScene();
|
|
2468
|
-
// since the _hitPlane is always updated to be orthogonal to the camera position vector
|
|
2469
|
-
// we don't have to worry about this ray shooting off to infinity. This ray creates
|
|
2470
|
-
// a vector defining where we want to zoom to.
|
|
2471
|
-
const ray = scene.createPickingRay(scene.pointerX, scene.pointerY, Matrix.Identity(), camera, false);
|
|
2472
|
-
// Since the camera is the origin of the picking ray, we need to offset it by the camera's offset manually
|
|
2473
|
-
ray.origin.x -= camera.targetScreenOffset.x;
|
|
2474
|
-
ray.origin.y -= camera.targetScreenOffset.y;
|
|
2475
|
-
let distance = 0;
|
|
2476
|
-
if (this._hitPlane) {
|
|
2477
|
-
distance = (_a = ray.intersectsPlane(this._hitPlane)) !== null && _a !== void 0 ? _a : 0;
|
|
2478
|
-
}
|
|
2479
|
-
// not using this ray again, so modifying its vectors here is fine
|
|
2480
|
-
return ray.origin.addInPlace(ray.direction.scaleInPlace(distance));
|
|
2481
|
-
}
|
|
2482
|
-
_zoomToMouse(delta) {
|
|
2483
|
-
var _a, _b;
|
|
2484
|
-
const camera = this.camera;
|
|
2485
|
-
const inertiaComp = 1 - camera.inertia;
|
|
2486
|
-
if (camera.lowerRadiusLimit) {
|
|
2487
|
-
const lowerLimit = (_a = camera.lowerRadiusLimit) !== null && _a !== void 0 ? _a : 0;
|
|
2488
|
-
if (camera.radius - (camera.inertialRadiusOffset + delta) / inertiaComp < lowerLimit) {
|
|
2489
|
-
delta = (camera.radius - lowerLimit) * inertiaComp - camera.inertialRadiusOffset;
|
|
2490
|
-
}
|
|
2491
|
-
}
|
|
2492
|
-
if (camera.upperRadiusLimit) {
|
|
2493
|
-
const upperLimit = (_b = camera.upperRadiusLimit) !== null && _b !== void 0 ? _b : 0;
|
|
2494
|
-
if (camera.radius - (camera.inertialRadiusOffset + delta) / inertiaComp > upperLimit) {
|
|
2495
|
-
delta = (camera.radius - upperLimit) * inertiaComp - camera.inertialRadiusOffset;
|
|
2496
|
-
}
|
|
2497
|
-
}
|
|
2498
|
-
const zoomDistance = delta / inertiaComp;
|
|
2499
|
-
const ratio = zoomDistance / camera.radius;
|
|
2500
|
-
const vec = this._getPosition();
|
|
2501
|
-
// Now this vector tells us how much we also need to pan the camera
|
|
2502
|
-
// so the targeted mouse location becomes the center of zooming.
|
|
2503
|
-
const directionToZoomLocation = TmpVectors.Vector3[6];
|
|
2504
|
-
vec.subtractToRef(camera.target, directionToZoomLocation);
|
|
2505
|
-
directionToZoomLocation.scaleInPlace(ratio);
|
|
2506
|
-
directionToZoomLocation.scaleInPlace(inertiaComp);
|
|
2507
|
-
this._inertialPanning.addInPlace(directionToZoomLocation);
|
|
2508
|
-
camera.inertialRadiusOffset += delta;
|
|
2509
|
-
}
|
|
2510
|
-
// Sets x y or z of passed in vector to zero if less than Epsilon.
|
|
2511
|
-
_zeroIfClose(vec) {
|
|
2512
|
-
if (Math.abs(vec.x) < Epsilon) {
|
|
2513
|
-
vec.x = 0;
|
|
2514
|
-
}
|
|
2515
|
-
if (Math.abs(vec.y) < Epsilon) {
|
|
2516
|
-
vec.y = 0;
|
|
2517
|
-
}
|
|
2518
|
-
if (Math.abs(vec.z) < Epsilon) {
|
|
2519
|
-
vec.z = 0;
|
|
2520
|
-
}
|
|
2521
|
-
}
|
|
2522
|
-
}
|
|
2523
|
-
__decorate([
|
|
2524
|
-
serialize()
|
|
2525
|
-
], ArcRotateCameraMouseWheelInput.prototype, "wheelPrecision", void 0);
|
|
2526
|
-
__decorate([
|
|
2527
|
-
serialize()
|
|
2528
|
-
], ArcRotateCameraMouseWheelInput.prototype, "zoomToMouseLocation", void 0);
|
|
2529
|
-
__decorate([
|
|
2530
|
-
serialize()
|
|
2531
|
-
], ArcRotateCameraMouseWheelInput.prototype, "wheelDeltaPercentage", void 0);
|
|
2532
|
-
CameraInputTypes["ArcRotateCameraMouseWheelInput"] = ArcRotateCameraMouseWheelInput;
|
|
2533
|
-
|
|
2534
|
-
/**
|
|
2535
|
-
* Default Inputs manager for the ArcRotateCamera.
|
|
2536
|
-
* It groups all the default supported inputs for ease of use.
|
|
2537
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
|
|
2538
|
-
*/
|
|
2539
|
-
class ArcRotateCameraInputsManager extends CameraInputsManager {
|
|
2540
|
-
/**
|
|
2541
|
-
* Instantiates a new ArcRotateCameraInputsManager.
|
|
2542
|
-
* @param camera Defines the camera the inputs belong to
|
|
2543
|
-
*/
|
|
2544
|
-
constructor(camera) {
|
|
2545
|
-
super(camera);
|
|
2546
|
-
}
|
|
2547
|
-
/**
|
|
2548
|
-
* Add mouse wheel input support to the input manager.
|
|
2549
|
-
* @returns the current input manager
|
|
2550
|
-
*/
|
|
2551
|
-
addMouseWheel() {
|
|
2552
|
-
this.add(new ArcRotateCameraMouseWheelInput());
|
|
2553
|
-
return this;
|
|
2554
|
-
}
|
|
2555
|
-
/**
|
|
2556
|
-
* Add pointers input support to the input manager.
|
|
2557
|
-
* @returns the current input manager
|
|
2558
|
-
*/
|
|
2559
|
-
addPointers() {
|
|
2560
|
-
this.add(new ArcRotateCameraPointersInput());
|
|
2561
|
-
return this;
|
|
2562
|
-
}
|
|
2563
|
-
/**
|
|
2564
|
-
* Add keyboard input support to the input manager.
|
|
2565
|
-
* @returns the current input manager
|
|
2566
|
-
*/
|
|
2567
|
-
addKeyboard() {
|
|
2568
|
-
this.add(new ArcRotateCameraKeyboardMoveInput());
|
|
2569
|
-
return this;
|
|
2570
|
-
}
|
|
2571
|
-
}
|
|
2572
|
-
|
|
2573
|
-
Node.AddNodeConstructor("ArcRotateCamera", (name, scene) => {
|
|
2574
|
-
return () => new ArcRotateCamera(name, 0, 0, 1.0, Vector3.Zero(), scene);
|
|
2575
|
-
});
|
|
2576
|
-
/**
|
|
2577
|
-
* This represents an orbital type of camera.
|
|
2578
|
-
*
|
|
2579
|
-
* This camera always points towards a given target position and can be rotated around that target with the target as the centre of rotation. It can be controlled with cursors and mouse, or with touch events.
|
|
2580
|
-
* Think of this camera as one orbiting its target position, or more imaginatively as a spy satellite orbiting the earth. Its position relative to the target (earth) can be set by three parameters, alpha (radians) the longitudinal rotation, beta (radians) the latitudinal rotation and radius the distance from the target position.
|
|
2581
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/camera_introduction#arc-rotate-camera
|
|
2582
|
-
*/
|
|
2583
|
-
class ArcRotateCamera extends TargetCamera {
|
|
2584
|
-
/**
|
|
2585
|
-
* Defines the target point of the camera.
|
|
2586
|
-
* The camera looks towards it from the radius distance.
|
|
2587
|
-
*/
|
|
2588
|
-
get target() {
|
|
2589
|
-
return this._target;
|
|
2590
|
-
}
|
|
2591
|
-
set target(value) {
|
|
2592
|
-
this.setTarget(value);
|
|
2593
|
-
}
|
|
2594
|
-
/**
|
|
2595
|
-
* Defines the target mesh of the camera.
|
|
2596
|
-
* The camera looks towards it from the radius distance.
|
|
2597
|
-
* Please note that setting a target host will disable panning.
|
|
2598
|
-
*/
|
|
2599
|
-
get targetHost() {
|
|
2600
|
-
return this._targetHost;
|
|
2601
|
-
}
|
|
2602
|
-
set targetHost(value) {
|
|
2603
|
-
if (value) {
|
|
2604
|
-
this.setTarget(value);
|
|
2605
|
-
}
|
|
2606
|
-
}
|
|
2607
|
-
/**
|
|
2608
|
-
* Return the current target position of the camera. This value is expressed in local space.
|
|
2609
|
-
* @returns the target position
|
|
2610
|
-
*/
|
|
2611
|
-
getTarget() {
|
|
2612
|
-
return this.target;
|
|
2613
|
-
}
|
|
2614
|
-
/**
|
|
2615
|
-
* Define the current local position of the camera in the scene
|
|
2616
|
-
*/
|
|
2617
|
-
get position() {
|
|
2618
|
-
return this._position;
|
|
2619
|
-
}
|
|
2620
|
-
set position(newPosition) {
|
|
2621
|
-
this.setPosition(newPosition);
|
|
2622
|
-
}
|
|
2623
|
-
/**
|
|
2624
|
-
* The vector the camera should consider as up. (default is Vector3(0, 1, 0) as returned by Vector3.Up())
|
|
2625
|
-
* Setting this will copy the given vector to the camera's upVector, and set rotation matrices to and from Y up.
|
|
2626
|
-
* DO NOT set the up vector using copyFrom or copyFromFloats, as this bypasses setting the above matrices.
|
|
2627
|
-
*/
|
|
2628
|
-
set upVector(vec) {
|
|
2629
|
-
if (!this._upToYMatrix) {
|
|
2630
|
-
this._yToUpMatrix = new Matrix();
|
|
2631
|
-
this._upToYMatrix = new Matrix();
|
|
2632
|
-
this._upVector = Vector3.Zero();
|
|
2633
|
-
}
|
|
2634
|
-
vec.normalize();
|
|
2635
|
-
this._upVector.copyFrom(vec);
|
|
2636
|
-
this.setMatUp();
|
|
2637
|
-
}
|
|
2638
|
-
get upVector() {
|
|
2639
|
-
return this._upVector;
|
|
2640
|
-
}
|
|
2641
|
-
/**
|
|
2642
|
-
* Sets the Y-up to camera up-vector rotation matrix, and the up-vector to Y-up rotation matrix.
|
|
2643
|
-
*/
|
|
2644
|
-
setMatUp() {
|
|
2645
|
-
// from y-up to custom-up (used in _getViewMatrix)
|
|
2646
|
-
Matrix.RotationAlignToRef(Vector3.UpReadOnly, this._upVector, this._yToUpMatrix);
|
|
2647
|
-
// from custom-up to y-up (used in rebuildAnglesAndRadius)
|
|
2648
|
-
Matrix.RotationAlignToRef(this._upVector, Vector3.UpReadOnly, this._upToYMatrix);
|
|
2649
|
-
}
|
|
2650
|
-
//-- begin properties for backward compatibility for inputs
|
|
2651
|
-
/**
|
|
2652
|
-
* Gets or Set the pointer angular sensibility along the X axis or how fast is the camera rotating.
|
|
2653
|
-
*/
|
|
2654
|
-
get angularSensibilityX() {
|
|
2655
|
-
const pointers = this.inputs.attached["pointers"];
|
|
2656
|
-
if (pointers) {
|
|
2657
|
-
return pointers.angularSensibilityX;
|
|
2658
|
-
}
|
|
2659
|
-
return 0;
|
|
2660
|
-
}
|
|
2661
|
-
set angularSensibilityX(value) {
|
|
2662
|
-
const pointers = this.inputs.attached["pointers"];
|
|
2663
|
-
if (pointers) {
|
|
2664
|
-
pointers.angularSensibilityX = value;
|
|
2665
|
-
}
|
|
2666
|
-
}
|
|
2667
|
-
/**
|
|
2668
|
-
* Gets or Set the pointer angular sensibility along the Y axis or how fast is the camera rotating.
|
|
2669
|
-
*/
|
|
2670
|
-
get angularSensibilityY() {
|
|
2671
|
-
const pointers = this.inputs.attached["pointers"];
|
|
2672
|
-
if (pointers) {
|
|
2673
|
-
return pointers.angularSensibilityY;
|
|
2674
|
-
}
|
|
2675
|
-
return 0;
|
|
2676
|
-
}
|
|
2677
|
-
set angularSensibilityY(value) {
|
|
2678
|
-
const pointers = this.inputs.attached["pointers"];
|
|
2679
|
-
if (pointers) {
|
|
2680
|
-
pointers.angularSensibilityY = value;
|
|
2681
|
-
}
|
|
2682
|
-
}
|
|
2683
|
-
/**
|
|
2684
|
-
* Gets or Set the pointer pinch precision or how fast is the camera zooming.
|
|
2685
|
-
*/
|
|
2686
|
-
get pinchPrecision() {
|
|
2687
|
-
const pointers = this.inputs.attached["pointers"];
|
|
2688
|
-
if (pointers) {
|
|
2689
|
-
return pointers.pinchPrecision;
|
|
2690
|
-
}
|
|
2691
|
-
return 0;
|
|
2692
|
-
}
|
|
2693
|
-
set pinchPrecision(value) {
|
|
2694
|
-
const pointers = this.inputs.attached["pointers"];
|
|
2695
|
-
if (pointers) {
|
|
2696
|
-
pointers.pinchPrecision = value;
|
|
2697
|
-
}
|
|
2698
|
-
}
|
|
2699
|
-
/**
|
|
2700
|
-
* Gets or Set the pointer pinch delta percentage or how fast is the camera zooming.
|
|
2701
|
-
* It will be used instead of pinchDeltaPrecision if different from 0.
|
|
2702
|
-
* It defines the percentage of current camera.radius to use as delta when pinch zoom is used.
|
|
2703
|
-
*/
|
|
2704
|
-
get pinchDeltaPercentage() {
|
|
2705
|
-
const pointers = this.inputs.attached["pointers"];
|
|
2706
|
-
if (pointers) {
|
|
2707
|
-
return pointers.pinchDeltaPercentage;
|
|
2708
|
-
}
|
|
2709
|
-
return 0;
|
|
2710
|
-
}
|
|
2711
|
-
set pinchDeltaPercentage(value) {
|
|
2712
|
-
const pointers = this.inputs.attached["pointers"];
|
|
2713
|
-
if (pointers) {
|
|
2714
|
-
pointers.pinchDeltaPercentage = value;
|
|
2715
|
-
}
|
|
2716
|
-
}
|
|
2717
|
-
/**
|
|
2718
|
-
* Gets or Set the pointer use natural pinch zoom to override the pinch precision
|
|
2719
|
-
* and pinch delta percentage.
|
|
2720
|
-
* When useNaturalPinchZoom is true, multi touch zoom will zoom in such
|
|
2721
|
-
* that any object in the plane at the camera's target point will scale
|
|
2722
|
-
* perfectly with finger motion.
|
|
2723
|
-
*/
|
|
2724
|
-
get useNaturalPinchZoom() {
|
|
2725
|
-
const pointers = this.inputs.attached["pointers"];
|
|
2726
|
-
if (pointers) {
|
|
2727
|
-
return pointers.useNaturalPinchZoom;
|
|
2728
|
-
}
|
|
2729
|
-
return false;
|
|
2730
|
-
}
|
|
2731
|
-
set useNaturalPinchZoom(value) {
|
|
2732
|
-
const pointers = this.inputs.attached["pointers"];
|
|
2733
|
-
if (pointers) {
|
|
2734
|
-
pointers.useNaturalPinchZoom = value;
|
|
2735
|
-
}
|
|
2736
|
-
}
|
|
2737
|
-
/**
|
|
2738
|
-
* Gets or Set the pointer panning sensibility or how fast is the camera moving.
|
|
2739
|
-
*/
|
|
2740
|
-
get panningSensibility() {
|
|
2741
|
-
const pointers = this.inputs.attached["pointers"];
|
|
2742
|
-
if (pointers) {
|
|
2743
|
-
return pointers.panningSensibility;
|
|
2744
|
-
}
|
|
2745
|
-
return 0;
|
|
2746
|
-
}
|
|
2747
|
-
set panningSensibility(value) {
|
|
2748
|
-
const pointers = this.inputs.attached["pointers"];
|
|
2749
|
-
if (pointers) {
|
|
2750
|
-
pointers.panningSensibility = value;
|
|
2751
|
-
}
|
|
2752
|
-
}
|
|
2753
|
-
/**
|
|
2754
|
-
* Gets or Set the list of keyboard keys used to control beta angle in a positive direction.
|
|
2755
|
-
*/
|
|
2756
|
-
get keysUp() {
|
|
2757
|
-
const keyboard = this.inputs.attached["keyboard"];
|
|
2758
|
-
if (keyboard) {
|
|
2759
|
-
return keyboard.keysUp;
|
|
2760
|
-
}
|
|
2761
|
-
return [];
|
|
2762
|
-
}
|
|
2763
|
-
set keysUp(value) {
|
|
2764
|
-
const keyboard = this.inputs.attached["keyboard"];
|
|
2765
|
-
if (keyboard) {
|
|
2766
|
-
keyboard.keysUp = value;
|
|
2767
|
-
}
|
|
2768
|
-
}
|
|
2769
|
-
/**
|
|
2770
|
-
* Gets or Set the list of keyboard keys used to control beta angle in a negative direction.
|
|
2771
|
-
*/
|
|
2772
|
-
get keysDown() {
|
|
2773
|
-
const keyboard = this.inputs.attached["keyboard"];
|
|
2774
|
-
if (keyboard) {
|
|
2775
|
-
return keyboard.keysDown;
|
|
2776
|
-
}
|
|
2777
|
-
return [];
|
|
2778
|
-
}
|
|
2779
|
-
set keysDown(value) {
|
|
2780
|
-
const keyboard = this.inputs.attached["keyboard"];
|
|
2781
|
-
if (keyboard) {
|
|
2782
|
-
keyboard.keysDown = value;
|
|
2783
|
-
}
|
|
2784
|
-
}
|
|
2785
|
-
/**
|
|
2786
|
-
* Gets or Set the list of keyboard keys used to control alpha angle in a negative direction.
|
|
2787
|
-
*/
|
|
2788
|
-
get keysLeft() {
|
|
2789
|
-
const keyboard = this.inputs.attached["keyboard"];
|
|
2790
|
-
if (keyboard) {
|
|
2791
|
-
return keyboard.keysLeft;
|
|
2792
|
-
}
|
|
2793
|
-
return [];
|
|
2794
|
-
}
|
|
2795
|
-
set keysLeft(value) {
|
|
2796
|
-
const keyboard = this.inputs.attached["keyboard"];
|
|
2797
|
-
if (keyboard) {
|
|
2798
|
-
keyboard.keysLeft = value;
|
|
2799
|
-
}
|
|
2800
|
-
}
|
|
2801
|
-
/**
|
|
2802
|
-
* Gets or Set the list of keyboard keys used to control alpha angle in a positive direction.
|
|
2803
|
-
*/
|
|
2804
|
-
get keysRight() {
|
|
2805
|
-
const keyboard = this.inputs.attached["keyboard"];
|
|
2806
|
-
if (keyboard) {
|
|
2807
|
-
return keyboard.keysRight;
|
|
2808
|
-
}
|
|
2809
|
-
return [];
|
|
2810
|
-
}
|
|
2811
|
-
set keysRight(value) {
|
|
2812
|
-
const keyboard = this.inputs.attached["keyboard"];
|
|
2813
|
-
if (keyboard) {
|
|
2814
|
-
keyboard.keysRight = value;
|
|
2815
|
-
}
|
|
2816
|
-
}
|
|
2817
|
-
/**
|
|
2818
|
-
* Gets or Set the mouse wheel precision or how fast is the camera zooming.
|
|
2819
|
-
*/
|
|
2820
|
-
get wheelPrecision() {
|
|
2821
|
-
const mousewheel = this.inputs.attached["mousewheel"];
|
|
2822
|
-
if (mousewheel) {
|
|
2823
|
-
return mousewheel.wheelPrecision;
|
|
2824
|
-
}
|
|
2825
|
-
return 0;
|
|
2826
|
-
}
|
|
2827
|
-
set wheelPrecision(value) {
|
|
2828
|
-
const mousewheel = this.inputs.attached["mousewheel"];
|
|
2829
|
-
if (mousewheel) {
|
|
2830
|
-
mousewheel.wheelPrecision = value;
|
|
2831
|
-
}
|
|
2832
|
-
}
|
|
2833
|
-
/**
|
|
2834
|
-
* Gets or Set the boolean value that controls whether or not the mouse wheel
|
|
2835
|
-
* zooms to the location of the mouse pointer or not. The default is false.
|
|
2836
|
-
*/
|
|
2837
|
-
get zoomToMouseLocation() {
|
|
2838
|
-
const mousewheel = this.inputs.attached["mousewheel"];
|
|
2839
|
-
if (mousewheel) {
|
|
2840
|
-
return mousewheel.zoomToMouseLocation;
|
|
2841
|
-
}
|
|
2842
|
-
return false;
|
|
2843
|
-
}
|
|
2844
|
-
set zoomToMouseLocation(value) {
|
|
2845
|
-
const mousewheel = this.inputs.attached["mousewheel"];
|
|
2846
|
-
if (mousewheel) {
|
|
2847
|
-
mousewheel.zoomToMouseLocation = value;
|
|
2848
|
-
}
|
|
2849
|
-
}
|
|
2850
|
-
/**
|
|
2851
|
-
* Gets or Set the mouse wheel delta percentage or how fast is the camera zooming.
|
|
2852
|
-
* It will be used instead of pinchDeltaPrecision if different from 0.
|
|
2853
|
-
* It defines the percentage of current camera.radius to use as delta when pinch zoom is used.
|
|
2854
|
-
*/
|
|
2855
|
-
get wheelDeltaPercentage() {
|
|
2856
|
-
const mousewheel = this.inputs.attached["mousewheel"];
|
|
2857
|
-
if (mousewheel) {
|
|
2858
|
-
return mousewheel.wheelDeltaPercentage;
|
|
2859
|
-
}
|
|
2860
|
-
return 0;
|
|
2861
|
-
}
|
|
2862
|
-
set wheelDeltaPercentage(value) {
|
|
2863
|
-
const mousewheel = this.inputs.attached["mousewheel"];
|
|
2864
|
-
if (mousewheel) {
|
|
2865
|
-
mousewheel.wheelDeltaPercentage = value;
|
|
2866
|
-
}
|
|
2867
|
-
}
|
|
2868
|
-
/**
|
|
2869
|
-
* Gets the bouncing behavior of the camera if it has been enabled.
|
|
2870
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors/cameraBehaviors#bouncing-behavior
|
|
2871
|
-
*/
|
|
2872
|
-
get bouncingBehavior() {
|
|
2873
|
-
return this._bouncingBehavior;
|
|
2874
|
-
}
|
|
2875
|
-
/**
|
|
2876
|
-
* Defines if the bouncing behavior of the camera is enabled on the camera.
|
|
2877
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors/cameraBehaviors#bouncing-behavior
|
|
2878
|
-
*/
|
|
2879
|
-
get useBouncingBehavior() {
|
|
2880
|
-
return this._bouncingBehavior != null;
|
|
2881
|
-
}
|
|
2882
|
-
set useBouncingBehavior(value) {
|
|
2883
|
-
if (value === this.useBouncingBehavior) {
|
|
2884
|
-
return;
|
|
2885
|
-
}
|
|
2886
|
-
if (value) {
|
|
2887
|
-
this._bouncingBehavior = new BouncingBehavior();
|
|
2888
|
-
this.addBehavior(this._bouncingBehavior);
|
|
2889
|
-
}
|
|
2890
|
-
else if (this._bouncingBehavior) {
|
|
2891
|
-
this.removeBehavior(this._bouncingBehavior);
|
|
2892
|
-
this._bouncingBehavior = null;
|
|
2893
|
-
}
|
|
2894
|
-
}
|
|
2895
|
-
/**
|
|
2896
|
-
* Gets the framing behavior of the camera if it has been enabled.
|
|
2897
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors/cameraBehaviors#framing-behavior
|
|
2898
|
-
*/
|
|
2899
|
-
get framingBehavior() {
|
|
2900
|
-
return this._framingBehavior;
|
|
2901
|
-
}
|
|
2902
|
-
/**
|
|
2903
|
-
* Defines if the framing behavior of the camera is enabled on the camera.
|
|
2904
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors/cameraBehaviors#framing-behavior
|
|
2905
|
-
*/
|
|
2906
|
-
get useFramingBehavior() {
|
|
2907
|
-
return this._framingBehavior != null;
|
|
2908
|
-
}
|
|
2909
|
-
set useFramingBehavior(value) {
|
|
2910
|
-
if (value === this.useFramingBehavior) {
|
|
2911
|
-
return;
|
|
2912
|
-
}
|
|
2913
|
-
if (value) {
|
|
2914
|
-
this._framingBehavior = new FramingBehavior();
|
|
2915
|
-
this.addBehavior(this._framingBehavior);
|
|
2916
|
-
}
|
|
2917
|
-
else if (this._framingBehavior) {
|
|
2918
|
-
this.removeBehavior(this._framingBehavior);
|
|
2919
|
-
this._framingBehavior = null;
|
|
2920
|
-
}
|
|
2921
|
-
}
|
|
2922
|
-
/**
|
|
2923
|
-
* Gets the auto rotation behavior of the camera if it has been enabled.
|
|
2924
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors/cameraBehaviors#autorotation-behavior
|
|
2925
|
-
*/
|
|
2926
|
-
get autoRotationBehavior() {
|
|
2927
|
-
return this._autoRotationBehavior;
|
|
2928
|
-
}
|
|
2929
|
-
/**
|
|
2930
|
-
* Defines if the auto rotation behavior of the camera is enabled on the camera.
|
|
2931
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors/cameraBehaviors#autorotation-behavior
|
|
2932
|
-
*/
|
|
2933
|
-
get useAutoRotationBehavior() {
|
|
2934
|
-
return this._autoRotationBehavior != null;
|
|
2935
|
-
}
|
|
2936
|
-
set useAutoRotationBehavior(value) {
|
|
2937
|
-
if (value === this.useAutoRotationBehavior) {
|
|
2938
|
-
return;
|
|
2939
|
-
}
|
|
2940
|
-
if (value) {
|
|
2941
|
-
this._autoRotationBehavior = new AutoRotationBehavior();
|
|
2942
|
-
this.addBehavior(this._autoRotationBehavior);
|
|
2943
|
-
}
|
|
2944
|
-
else if (this._autoRotationBehavior) {
|
|
2945
|
-
this.removeBehavior(this._autoRotationBehavior);
|
|
2946
|
-
this._autoRotationBehavior = null;
|
|
2947
|
-
}
|
|
2948
|
-
}
|
|
2949
|
-
/**
|
|
2950
|
-
* Instantiates a new ArcRotateCamera in a given scene
|
|
2951
|
-
* @param name Defines the name of the camera
|
|
2952
|
-
* @param alpha Defines the camera rotation along the longitudinal axis
|
|
2953
|
-
* @param beta Defines the camera rotation along the latitudinal axis
|
|
2954
|
-
* @param radius Defines the camera distance from its target
|
|
2955
|
-
* @param target Defines the camera target
|
|
2956
|
-
* @param scene Defines the scene the camera belongs to
|
|
2957
|
-
* @param setActiveOnSceneIfNoneActive Defines whether the camera should be marked as active if not other active cameras have been defined
|
|
2958
|
-
*/
|
|
2959
|
-
constructor(name, alpha, beta, radius, target, scene, setActiveOnSceneIfNoneActive = true) {
|
|
2960
|
-
super(name, Vector3.Zero(), scene, setActiveOnSceneIfNoneActive);
|
|
2961
|
-
/**
|
|
2962
|
-
* Current inertia value on the longitudinal axis.
|
|
2963
|
-
* The bigger this number the longer it will take for the camera to stop.
|
|
2964
|
-
*/
|
|
2965
|
-
this.inertialAlphaOffset = 0;
|
|
2966
|
-
/**
|
|
2967
|
-
* Current inertia value on the latitudinal axis.
|
|
2968
|
-
* The bigger this number the longer it will take for the camera to stop.
|
|
2969
|
-
*/
|
|
2970
|
-
this.inertialBetaOffset = 0;
|
|
2971
|
-
/**
|
|
2972
|
-
* Current inertia value on the radius axis.
|
|
2973
|
-
* The bigger this number the longer it will take for the camera to stop.
|
|
2974
|
-
*/
|
|
2975
|
-
this.inertialRadiusOffset = 0;
|
|
2976
|
-
/**
|
|
2977
|
-
* Minimum allowed angle on the longitudinal axis.
|
|
2978
|
-
* This can help limiting how the Camera is able to move in the scene.
|
|
2979
|
-
*/
|
|
2980
|
-
this.lowerAlphaLimit = null;
|
|
2981
|
-
/**
|
|
2982
|
-
* Maximum allowed angle on the longitudinal axis.
|
|
2983
|
-
* This can help limiting how the Camera is able to move in the scene.
|
|
2984
|
-
*/
|
|
2985
|
-
this.upperAlphaLimit = null;
|
|
2986
|
-
/**
|
|
2987
|
-
* Minimum allowed angle on the latitudinal axis.
|
|
2988
|
-
* This can help limiting how the Camera is able to move in the scene.
|
|
2989
|
-
*/
|
|
2990
|
-
this.lowerBetaLimit = 0.01;
|
|
2991
|
-
/**
|
|
2992
|
-
* Maximum allowed angle on the latitudinal axis.
|
|
2993
|
-
* This can help limiting how the Camera is able to move in the scene.
|
|
2994
|
-
*/
|
|
2995
|
-
this.upperBetaLimit = Math.PI - 0.01;
|
|
2996
|
-
/**
|
|
2997
|
-
* Minimum allowed distance of the camera to the target (The camera can not get closer).
|
|
2998
|
-
* This can help limiting how the Camera is able to move in the scene.
|
|
2999
|
-
*/
|
|
3000
|
-
this.lowerRadiusLimit = null;
|
|
3001
|
-
/**
|
|
3002
|
-
* Maximum allowed distance of the camera to the target (The camera can not get further).
|
|
3003
|
-
* This can help limiting how the Camera is able to move in the scene.
|
|
3004
|
-
*/
|
|
3005
|
-
this.upperRadiusLimit = null;
|
|
3006
|
-
/**
|
|
3007
|
-
* Defines the current inertia value used during panning of the camera along the X axis.
|
|
3008
|
-
*/
|
|
3009
|
-
this.inertialPanningX = 0;
|
|
3010
|
-
/**
|
|
3011
|
-
* Defines the current inertia value used during panning of the camera along the Y axis.
|
|
3012
|
-
*/
|
|
3013
|
-
this.inertialPanningY = 0;
|
|
3014
|
-
/**
|
|
3015
|
-
* Defines the distance used to consider the camera in pan mode vs pinch/zoom.
|
|
3016
|
-
* Basically if your fingers moves away from more than this distance you will be considered
|
|
3017
|
-
* in pinch mode.
|
|
3018
|
-
*/
|
|
3019
|
-
this.pinchToPanMaxDistance = 20;
|
|
3020
|
-
/**
|
|
3021
|
-
* Defines the maximum distance the camera can pan.
|
|
3022
|
-
* This could help keeping the camera always in your scene.
|
|
3023
|
-
*/
|
|
3024
|
-
this.panningDistanceLimit = null;
|
|
3025
|
-
/**
|
|
3026
|
-
* Defines the target of the camera before panning.
|
|
3027
|
-
*/
|
|
3028
|
-
this.panningOriginTarget = Vector3.Zero();
|
|
3029
|
-
/**
|
|
3030
|
-
* Defines the value of the inertia used during panning.
|
|
3031
|
-
* 0 would mean stop inertia and one would mean no deceleration at all.
|
|
3032
|
-
*/
|
|
3033
|
-
this.panningInertia = 0.9;
|
|
3034
|
-
//-- end properties for backward compatibility for inputs
|
|
3035
|
-
/**
|
|
3036
|
-
* Defines how much the radius should be scaled while zooming on a particular mesh (through the zoomOn function)
|
|
3037
|
-
*/
|
|
3038
|
-
this.zoomOnFactor = 1;
|
|
3039
|
-
/**
|
|
3040
|
-
* Defines a screen offset for the camera position.
|
|
3041
|
-
*/
|
|
3042
|
-
this.targetScreenOffset = Vector2.Zero();
|
|
3043
|
-
/**
|
|
3044
|
-
* Allows the camera to be completely reversed.
|
|
3045
|
-
* If false the camera can not arrive upside down.
|
|
3046
|
-
*/
|
|
3047
|
-
this.allowUpsideDown = true;
|
|
3048
|
-
/**
|
|
3049
|
-
* Define if double tap/click is used to restore the previously saved state of the camera.
|
|
3050
|
-
*/
|
|
3051
|
-
this.useInputToRestoreState = true;
|
|
3052
|
-
/** @internal */
|
|
3053
|
-
this._viewMatrix = new Matrix();
|
|
3054
|
-
/**
|
|
3055
|
-
* Defines the allowed panning axis.
|
|
3056
|
-
*/
|
|
3057
|
-
this.panningAxis = new Vector3(1, 1, 0);
|
|
3058
|
-
this._transformedDirection = new Vector3();
|
|
3059
|
-
/**
|
|
3060
|
-
* Defines if camera will eliminate transform on y axis.
|
|
3061
|
-
*/
|
|
3062
|
-
this.mapPanning = false;
|
|
3063
|
-
/**
|
|
3064
|
-
* Observable triggered when the mesh target has been changed on the camera.
|
|
3065
|
-
*/
|
|
3066
|
-
this.onMeshTargetChangedObservable = new Observable();
|
|
3067
|
-
/**
|
|
3068
|
-
* Defines whether the camera should check collision with the objects oh the scene.
|
|
3069
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/camera_collisions#how-can-i-do-this-
|
|
3070
|
-
*/
|
|
3071
|
-
this.checkCollisions = false;
|
|
3072
|
-
/**
|
|
3073
|
-
* Defines the collision radius of the camera.
|
|
3074
|
-
* This simulates a sphere around the camera.
|
|
3075
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/camera_collisions#arcrotatecamera
|
|
3076
|
-
*/
|
|
3077
|
-
this.collisionRadius = new Vector3(0.5, 0.5, 0.5);
|
|
3078
|
-
this._previousPosition = Vector3.Zero();
|
|
3079
|
-
this._collisionVelocity = Vector3.Zero();
|
|
3080
|
-
this._newPosition = Vector3.Zero();
|
|
3081
|
-
this._computationVector = Vector3.Zero();
|
|
3082
|
-
this._onCollisionPositionChange = (collisionId, newPosition, collidedMesh = null) => {
|
|
3083
|
-
if (!collidedMesh) {
|
|
3084
|
-
this._previousPosition.copyFrom(this._position);
|
|
3085
|
-
}
|
|
3086
|
-
else {
|
|
3087
|
-
this.setPosition(newPosition);
|
|
3088
|
-
if (this.onCollide) {
|
|
3089
|
-
this.onCollide(collidedMesh);
|
|
3090
|
-
}
|
|
3091
|
-
}
|
|
3092
|
-
// Recompute because of constraints
|
|
3093
|
-
const cosa = Math.cos(this.alpha);
|
|
3094
|
-
const sina = Math.sin(this.alpha);
|
|
3095
|
-
const cosb = Math.cos(this.beta);
|
|
3096
|
-
let sinb = Math.sin(this.beta);
|
|
3097
|
-
if (sinb === 0) {
|
|
3098
|
-
sinb = 0.0001;
|
|
3099
|
-
}
|
|
3100
|
-
const target = this._getTargetPosition();
|
|
3101
|
-
this._computationVector.copyFromFloats(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb);
|
|
3102
|
-
target.addToRef(this._computationVector, this._newPosition);
|
|
3103
|
-
this._position.copyFrom(this._newPosition);
|
|
3104
|
-
let up = this.upVector;
|
|
3105
|
-
if (this.allowUpsideDown && this.beta < 0) {
|
|
3106
|
-
up = up.clone();
|
|
3107
|
-
up = up.negate();
|
|
3108
|
-
}
|
|
3109
|
-
this._computeViewMatrix(this._position, target, up);
|
|
3110
|
-
this._viewMatrix.addAtIndex(12, this.targetScreenOffset.x);
|
|
3111
|
-
this._viewMatrix.addAtIndex(13, this.targetScreenOffset.y);
|
|
3112
|
-
this._collisionTriggered = false;
|
|
3113
|
-
};
|
|
3114
|
-
this._target = Vector3.Zero();
|
|
3115
|
-
if (target) {
|
|
3116
|
-
this.setTarget(target);
|
|
3117
|
-
}
|
|
3118
|
-
this.alpha = alpha;
|
|
3119
|
-
this.beta = beta;
|
|
3120
|
-
this.radius = radius;
|
|
3121
|
-
this.getViewMatrix();
|
|
3122
|
-
this.inputs = new ArcRotateCameraInputsManager(this);
|
|
3123
|
-
this.inputs.addKeyboard().addMouseWheel().addPointers();
|
|
3124
|
-
}
|
|
3125
|
-
// Cache
|
|
3126
|
-
/** @internal */
|
|
3127
|
-
_initCache() {
|
|
3128
|
-
super._initCache();
|
|
3129
|
-
this._cache._target = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
|
|
3130
|
-
this._cache.alpha = undefined;
|
|
3131
|
-
this._cache.beta = undefined;
|
|
3132
|
-
this._cache.radius = undefined;
|
|
3133
|
-
this._cache.targetScreenOffset = Vector2.Zero();
|
|
3134
|
-
}
|
|
3135
|
-
/**
|
|
3136
|
-
* @internal
|
|
3137
|
-
*/
|
|
3138
|
-
_updateCache(ignoreParentClass) {
|
|
3139
|
-
if (!ignoreParentClass) {
|
|
3140
|
-
super._updateCache();
|
|
3141
|
-
}
|
|
3142
|
-
this._cache._target.copyFrom(this._getTargetPosition());
|
|
3143
|
-
this._cache.alpha = this.alpha;
|
|
3144
|
-
this._cache.beta = this.beta;
|
|
3145
|
-
this._cache.radius = this.radius;
|
|
3146
|
-
this._cache.targetScreenOffset.copyFrom(this.targetScreenOffset);
|
|
3147
|
-
}
|
|
3148
|
-
_getTargetPosition() {
|
|
3149
|
-
if (this._targetHost && this._targetHost.getAbsolutePosition) {
|
|
3150
|
-
const pos = this._targetHost.getAbsolutePosition();
|
|
3151
|
-
if (this._targetBoundingCenter) {
|
|
3152
|
-
pos.addToRef(this._targetBoundingCenter, this._target);
|
|
3153
|
-
}
|
|
3154
|
-
else {
|
|
3155
|
-
this._target.copyFrom(pos);
|
|
3156
|
-
}
|
|
3157
|
-
}
|
|
3158
|
-
const lockedTargetPosition = this._getLockedTargetPosition();
|
|
3159
|
-
if (lockedTargetPosition) {
|
|
3160
|
-
return lockedTargetPosition;
|
|
3161
|
-
}
|
|
3162
|
-
return this._target;
|
|
3163
|
-
}
|
|
3164
|
-
/**
|
|
3165
|
-
* Stores the current state of the camera (alpha, beta, radius and target)
|
|
3166
|
-
* @returns the camera itself
|
|
3167
|
-
*/
|
|
3168
|
-
storeState() {
|
|
3169
|
-
this._storedAlpha = this.alpha;
|
|
3170
|
-
this._storedBeta = this.beta;
|
|
3171
|
-
this._storedRadius = this.radius;
|
|
3172
|
-
this._storedTarget = this._getTargetPosition().clone();
|
|
3173
|
-
this._storedTargetScreenOffset = this.targetScreenOffset.clone();
|
|
3174
|
-
return super.storeState();
|
|
3175
|
-
}
|
|
3176
|
-
/**
|
|
3177
|
-
* @internal
|
|
3178
|
-
* Restored camera state. You must call storeState() first
|
|
3179
|
-
*/
|
|
3180
|
-
_restoreStateValues() {
|
|
3181
|
-
if (!super._restoreStateValues()) {
|
|
3182
|
-
return false;
|
|
3183
|
-
}
|
|
3184
|
-
this.setTarget(this._storedTarget.clone());
|
|
3185
|
-
this.alpha = this._storedAlpha;
|
|
3186
|
-
this.beta = this._storedBeta;
|
|
3187
|
-
this.radius = this._storedRadius;
|
|
3188
|
-
this.targetScreenOffset = this._storedTargetScreenOffset.clone();
|
|
3189
|
-
this.inertialAlphaOffset = 0;
|
|
3190
|
-
this.inertialBetaOffset = 0;
|
|
3191
|
-
this.inertialRadiusOffset = 0;
|
|
3192
|
-
this.inertialPanningX = 0;
|
|
3193
|
-
this.inertialPanningY = 0;
|
|
3194
|
-
return true;
|
|
3195
|
-
}
|
|
3196
|
-
// Synchronized
|
|
3197
|
-
/** @internal */
|
|
3198
|
-
_isSynchronizedViewMatrix() {
|
|
3199
|
-
if (!super._isSynchronizedViewMatrix()) {
|
|
3200
|
-
return false;
|
|
3201
|
-
}
|
|
3202
|
-
return (this._cache._target.equals(this._getTargetPosition()) &&
|
|
3203
|
-
this._cache.alpha === this.alpha &&
|
|
3204
|
-
this._cache.beta === this.beta &&
|
|
3205
|
-
this._cache.radius === this.radius &&
|
|
3206
|
-
this._cache.targetScreenOffset.equals(this.targetScreenOffset));
|
|
3207
|
-
}
|
|
3208
|
-
/**
|
|
3209
|
-
* Attached controls to the current camera.
|
|
3210
|
-
* @param ignored defines an ignored parameter kept for backward compatibility.
|
|
3211
|
-
* @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
|
|
3212
|
-
* @param useCtrlForPanning Defines whether ctrl is used for panning within the controls
|
|
3213
|
-
* @param panningMouseButton Defines whether panning is allowed through mouse click button
|
|
3214
|
-
*/
|
|
3215
|
-
attachControl(ignored, noPreventDefault, useCtrlForPanning = true, panningMouseButton = 2) {
|
|
3216
|
-
// eslint-disable-next-line prefer-rest-params
|
|
3217
|
-
const args = arguments;
|
|
3218
|
-
noPreventDefault = Tools.BackCompatCameraNoPreventDefault(args);
|
|
3219
|
-
this._useCtrlForPanning = useCtrlForPanning;
|
|
3220
|
-
this._panningMouseButton = panningMouseButton;
|
|
3221
|
-
// backwards compatibility
|
|
3222
|
-
if (typeof args[0] === "boolean") {
|
|
3223
|
-
if (args.length > 1) {
|
|
3224
|
-
this._useCtrlForPanning = args[1];
|
|
3225
|
-
}
|
|
3226
|
-
if (args.length > 2) {
|
|
3227
|
-
this._panningMouseButton = args[2];
|
|
3228
|
-
}
|
|
3229
|
-
}
|
|
3230
|
-
this.inputs.attachElement(noPreventDefault);
|
|
3231
|
-
this._reset = () => {
|
|
3232
|
-
this.inertialAlphaOffset = 0;
|
|
3233
|
-
this.inertialBetaOffset = 0;
|
|
3234
|
-
this.inertialRadiusOffset = 0;
|
|
3235
|
-
this.inertialPanningX = 0;
|
|
3236
|
-
this.inertialPanningY = 0;
|
|
3237
|
-
};
|
|
3238
|
-
}
|
|
3239
|
-
/**
|
|
3240
|
-
* Detach the current controls from the specified dom element.
|
|
3241
|
-
*/
|
|
3242
|
-
detachControl() {
|
|
3243
|
-
this.inputs.detachElement();
|
|
3244
|
-
if (this._reset) {
|
|
3245
|
-
this._reset();
|
|
3246
|
-
}
|
|
3247
|
-
}
|
|
3248
|
-
/** @internal */
|
|
3249
|
-
_checkInputs() {
|
|
3250
|
-
//if (async) collision inspection was triggered, don't update the camera's position - until the collision callback was called.
|
|
3251
|
-
if (this._collisionTriggered) {
|
|
3252
|
-
return;
|
|
3253
|
-
}
|
|
3254
|
-
this.inputs.checkInputs();
|
|
3255
|
-
// Inertia
|
|
3256
|
-
if (this.inertialAlphaOffset !== 0 || this.inertialBetaOffset !== 0 || this.inertialRadiusOffset !== 0) {
|
|
3257
|
-
const directionModifier = this.invertRotation ? -1 : 1;
|
|
3258
|
-
let inertialAlphaOffset = this.inertialAlphaOffset;
|
|
3259
|
-
if (this.beta <= 0) {
|
|
3260
|
-
inertialAlphaOffset *= -1;
|
|
3261
|
-
}
|
|
3262
|
-
if (this.getScene().useRightHandedSystem) {
|
|
3263
|
-
inertialAlphaOffset *= -1;
|
|
3264
|
-
}
|
|
3265
|
-
if (this.parent && this.parent._getWorldMatrixDeterminant() < 0) {
|
|
3266
|
-
inertialAlphaOffset *= -1;
|
|
3267
|
-
}
|
|
3268
|
-
this.alpha += inertialAlphaOffset * directionModifier;
|
|
3269
|
-
this.beta += this.inertialBetaOffset * directionModifier;
|
|
3270
|
-
this.radius -= this.inertialRadiusOffset;
|
|
3271
|
-
this.inertialAlphaOffset *= this.inertia;
|
|
3272
|
-
this.inertialBetaOffset *= this.inertia;
|
|
3273
|
-
this.inertialRadiusOffset *= this.inertia;
|
|
3274
|
-
if (Math.abs(this.inertialAlphaOffset) < Epsilon) {
|
|
3275
|
-
this.inertialAlphaOffset = 0;
|
|
3276
|
-
}
|
|
3277
|
-
if (Math.abs(this.inertialBetaOffset) < Epsilon) {
|
|
3278
|
-
this.inertialBetaOffset = 0;
|
|
3279
|
-
}
|
|
3280
|
-
if (Math.abs(this.inertialRadiusOffset) < this.speed * Epsilon) {
|
|
3281
|
-
this.inertialRadiusOffset = 0;
|
|
3282
|
-
}
|
|
3283
|
-
}
|
|
3284
|
-
// Panning inertia
|
|
3285
|
-
if (this.inertialPanningX !== 0 || this.inertialPanningY !== 0) {
|
|
3286
|
-
const localDirection = new Vector3(this.inertialPanningX, this.inertialPanningY, this.inertialPanningY);
|
|
3287
|
-
this._viewMatrix.invertToRef(this._cameraTransformMatrix);
|
|
3288
|
-
localDirection.multiplyInPlace(this.panningAxis);
|
|
3289
|
-
Vector3.TransformNormalToRef(localDirection, this._cameraTransformMatrix, this._transformedDirection);
|
|
3290
|
-
// Eliminate y if mapPanning is enabled
|
|
3291
|
-
if (this.mapPanning || !this.panningAxis.y) {
|
|
3292
|
-
this._transformedDirection.y = 0;
|
|
3293
|
-
}
|
|
3294
|
-
if (!this._targetHost) {
|
|
3295
|
-
if (this.panningDistanceLimit) {
|
|
3296
|
-
this._transformedDirection.addInPlace(this._target);
|
|
3297
|
-
const distanceSquared = Vector3.DistanceSquared(this._transformedDirection, this.panningOriginTarget);
|
|
3298
|
-
if (distanceSquared <= this.panningDistanceLimit * this.panningDistanceLimit) {
|
|
3299
|
-
this._target.copyFrom(this._transformedDirection);
|
|
3300
|
-
}
|
|
3301
|
-
}
|
|
3302
|
-
else {
|
|
3303
|
-
this._target.addInPlace(this._transformedDirection);
|
|
3304
|
-
}
|
|
3305
|
-
}
|
|
3306
|
-
this.inertialPanningX *= this.panningInertia;
|
|
3307
|
-
this.inertialPanningY *= this.panningInertia;
|
|
3308
|
-
if (Math.abs(this.inertialPanningX) < this.speed * Epsilon) {
|
|
3309
|
-
this.inertialPanningX = 0;
|
|
3310
|
-
}
|
|
3311
|
-
if (Math.abs(this.inertialPanningY) < this.speed * Epsilon) {
|
|
3312
|
-
this.inertialPanningY = 0;
|
|
3313
|
-
}
|
|
3314
|
-
}
|
|
3315
|
-
// Limits
|
|
3316
|
-
this._checkLimits();
|
|
3317
|
-
super._checkInputs();
|
|
3318
|
-
}
|
|
3319
|
-
_checkLimits() {
|
|
3320
|
-
if (this.lowerBetaLimit === null || this.lowerBetaLimit === undefined) {
|
|
3321
|
-
if (this.allowUpsideDown && this.beta > Math.PI) {
|
|
3322
|
-
this.beta = this.beta - 2 * Math.PI;
|
|
3323
|
-
}
|
|
3324
|
-
}
|
|
3325
|
-
else {
|
|
3326
|
-
if (this.beta < this.lowerBetaLimit) {
|
|
3327
|
-
this.beta = this.lowerBetaLimit;
|
|
3328
|
-
}
|
|
3329
|
-
}
|
|
3330
|
-
if (this.upperBetaLimit === null || this.upperBetaLimit === undefined) {
|
|
3331
|
-
if (this.allowUpsideDown && this.beta < -Math.PI) {
|
|
3332
|
-
this.beta = this.beta + 2 * Math.PI;
|
|
3333
|
-
}
|
|
3334
|
-
}
|
|
3335
|
-
else {
|
|
3336
|
-
if (this.beta > this.upperBetaLimit) {
|
|
3337
|
-
this.beta = this.upperBetaLimit;
|
|
3338
|
-
}
|
|
3339
|
-
}
|
|
3340
|
-
if (this.lowerAlphaLimit !== null && this.alpha < this.lowerAlphaLimit) {
|
|
3341
|
-
this.alpha = this.lowerAlphaLimit;
|
|
3342
|
-
}
|
|
3343
|
-
if (this.upperAlphaLimit !== null && this.alpha > this.upperAlphaLimit) {
|
|
3344
|
-
this.alpha = this.upperAlphaLimit;
|
|
3345
|
-
}
|
|
3346
|
-
if (this.lowerRadiusLimit !== null && this.radius < this.lowerRadiusLimit) {
|
|
3347
|
-
this.radius = this.lowerRadiusLimit;
|
|
3348
|
-
this.inertialRadiusOffset = 0;
|
|
3349
|
-
}
|
|
3350
|
-
if (this.upperRadiusLimit !== null && this.radius > this.upperRadiusLimit) {
|
|
3351
|
-
this.radius = this.upperRadiusLimit;
|
|
3352
|
-
this.inertialRadiusOffset = 0;
|
|
3353
|
-
}
|
|
3354
|
-
}
|
|
3355
|
-
/**
|
|
3356
|
-
* Rebuilds angles (alpha, beta) and radius from the give position and target
|
|
3357
|
-
*/
|
|
3358
|
-
rebuildAnglesAndRadius() {
|
|
3359
|
-
this._position.subtractToRef(this._getTargetPosition(), this._computationVector);
|
|
3360
|
-
// need to rotate to Y up equivalent if up vector not Axis.Y
|
|
3361
|
-
if (this._upVector.x !== 0 || this._upVector.y !== 1.0 || this._upVector.z !== 0) {
|
|
3362
|
-
Vector3.TransformCoordinatesToRef(this._computationVector, this._upToYMatrix, this._computationVector);
|
|
3363
|
-
}
|
|
3364
|
-
this.radius = this._computationVector.length();
|
|
3365
|
-
if (this.radius === 0) {
|
|
3366
|
-
this.radius = 0.0001; // Just to avoid division by zero
|
|
3367
|
-
}
|
|
3368
|
-
// Alpha
|
|
3369
|
-
const previousAlpha = this.alpha;
|
|
3370
|
-
if (this._computationVector.x === 0 && this._computationVector.z === 0) {
|
|
3371
|
-
this.alpha = Math.PI / 2; // avoid division by zero when looking along up axis, and set to acos(0)
|
|
3372
|
-
}
|
|
3373
|
-
else {
|
|
3374
|
-
this.alpha = Math.acos(this._computationVector.x / Math.sqrt(Math.pow(this._computationVector.x, 2) + Math.pow(this._computationVector.z, 2)));
|
|
3375
|
-
}
|
|
3376
|
-
if (this._computationVector.z < 0) {
|
|
3377
|
-
this.alpha = 2 * Math.PI - this.alpha;
|
|
3378
|
-
}
|
|
3379
|
-
// Calculate the number of revolutions between the new and old alpha values.
|
|
3380
|
-
const alphaCorrectionTurns = Math.round((previousAlpha - this.alpha) / (2.0 * Math.PI));
|
|
3381
|
-
// Adjust alpha so that its numerical representation is the closest one to the old value.
|
|
3382
|
-
this.alpha += alphaCorrectionTurns * 2.0 * Math.PI;
|
|
3383
|
-
// Beta
|
|
3384
|
-
this.beta = Math.acos(this._computationVector.y / this.radius);
|
|
3385
|
-
this._checkLimits();
|
|
3386
|
-
}
|
|
3387
|
-
/**
|
|
3388
|
-
* Use a position to define the current camera related information like alpha, beta and radius
|
|
3389
|
-
* @param position Defines the position to set the camera at
|
|
3390
|
-
*/
|
|
3391
|
-
setPosition(position) {
|
|
3392
|
-
if (this._position.equals(position)) {
|
|
3393
|
-
return;
|
|
3394
|
-
}
|
|
3395
|
-
this._position.copyFrom(position);
|
|
3396
|
-
this.rebuildAnglesAndRadius();
|
|
3397
|
-
}
|
|
3398
|
-
/**
|
|
3399
|
-
* Defines the target the camera should look at.
|
|
3400
|
-
* This will automatically adapt alpha beta and radius to fit within the new target.
|
|
3401
|
-
* Please note that setting a target as a mesh will disable panning.
|
|
3402
|
-
* @param target Defines the new target as a Vector or a mesh
|
|
3403
|
-
* @param toBoundingCenter In case of a mesh target, defines whether to target the mesh position or its bounding information center
|
|
3404
|
-
* @param allowSamePosition If false, prevents reapplying the new computed position if it is identical to the current one (optim)
|
|
3405
|
-
* @param cloneAlphaBetaRadius If true, replicate the current setup (alpha, beta, radius) on the new target
|
|
3406
|
-
*/
|
|
3407
|
-
setTarget(target, toBoundingCenter = false, allowSamePosition = false, cloneAlphaBetaRadius = false) {
|
|
3408
|
-
var _a;
|
|
3409
|
-
cloneAlphaBetaRadius = (_a = this.overrideCloneAlphaBetaRadius) !== null && _a !== void 0 ? _a : cloneAlphaBetaRadius;
|
|
3410
|
-
if (target.getBoundingInfo) {
|
|
3411
|
-
if (toBoundingCenter) {
|
|
3412
|
-
this._targetBoundingCenter = target.getBoundingInfo().boundingBox.centerWorld.clone();
|
|
3413
|
-
}
|
|
3414
|
-
else {
|
|
3415
|
-
this._targetBoundingCenter = null;
|
|
3416
|
-
}
|
|
3417
|
-
target.computeWorldMatrix();
|
|
3418
|
-
this._targetHost = target;
|
|
3419
|
-
this._target = this._getTargetPosition();
|
|
3420
|
-
this.onMeshTargetChangedObservable.notifyObservers(this._targetHost);
|
|
3421
|
-
}
|
|
3422
|
-
else {
|
|
3423
|
-
const newTarget = target;
|
|
3424
|
-
const currentTarget = this._getTargetPosition();
|
|
3425
|
-
if (currentTarget && !allowSamePosition && currentTarget.equals(newTarget)) {
|
|
3426
|
-
return;
|
|
3427
|
-
}
|
|
3428
|
-
this._targetHost = null;
|
|
3429
|
-
this._target = newTarget;
|
|
3430
|
-
this._targetBoundingCenter = null;
|
|
3431
|
-
this.onMeshTargetChangedObservable.notifyObservers(null);
|
|
3432
|
-
}
|
|
3433
|
-
if (!cloneAlphaBetaRadius) {
|
|
3434
|
-
this.rebuildAnglesAndRadius();
|
|
3435
|
-
}
|
|
3436
|
-
}
|
|
3437
|
-
/** @internal */
|
|
3438
|
-
_getViewMatrix() {
|
|
3439
|
-
// Compute
|
|
3440
|
-
const cosa = Math.cos(this.alpha);
|
|
3441
|
-
const sina = Math.sin(this.alpha);
|
|
3442
|
-
const cosb = Math.cos(this.beta);
|
|
3443
|
-
let sinb = Math.sin(this.beta);
|
|
3444
|
-
if (sinb === 0) {
|
|
3445
|
-
sinb = 0.0001;
|
|
3446
|
-
}
|
|
3447
|
-
if (this.radius === 0) {
|
|
3448
|
-
this.radius = 0.0001; // Just to avoid division by zero
|
|
3449
|
-
}
|
|
3450
|
-
const target = this._getTargetPosition();
|
|
3451
|
-
this._computationVector.copyFromFloats(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb);
|
|
3452
|
-
// Rotate according to up vector
|
|
3453
|
-
if (this._upVector.x !== 0 || this._upVector.y !== 1.0 || this._upVector.z !== 0) {
|
|
3454
|
-
Vector3.TransformCoordinatesToRef(this._computationVector, this._yToUpMatrix, this._computationVector);
|
|
3455
|
-
}
|
|
3456
|
-
target.addToRef(this._computationVector, this._newPosition);
|
|
3457
|
-
if (this.getScene().collisionsEnabled && this.checkCollisions) {
|
|
3458
|
-
const coordinator = this.getScene().collisionCoordinator;
|
|
3459
|
-
if (!this._collider) {
|
|
3460
|
-
this._collider = coordinator.createCollider();
|
|
3461
|
-
}
|
|
3462
|
-
this._collider._radius = this.collisionRadius;
|
|
3463
|
-
this._newPosition.subtractToRef(this._position, this._collisionVelocity);
|
|
3464
|
-
this._collisionTriggered = true;
|
|
3465
|
-
coordinator.getNewPosition(this._position, this._collisionVelocity, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
|
|
3466
|
-
}
|
|
3467
|
-
else {
|
|
3468
|
-
this._position.copyFrom(this._newPosition);
|
|
3469
|
-
let up = this.upVector;
|
|
3470
|
-
if (this.allowUpsideDown && sinb < 0) {
|
|
3471
|
-
up = up.negate();
|
|
3472
|
-
}
|
|
3473
|
-
this._computeViewMatrix(this._position, target, up);
|
|
3474
|
-
this._viewMatrix.addAtIndex(12, this.targetScreenOffset.x);
|
|
3475
|
-
this._viewMatrix.addAtIndex(13, this.targetScreenOffset.y);
|
|
3476
|
-
}
|
|
3477
|
-
this._currentTarget = target;
|
|
3478
|
-
return this._viewMatrix;
|
|
3479
|
-
}
|
|
3480
|
-
/**
|
|
3481
|
-
* Zooms on a mesh to be at the min distance where we could see it fully in the current viewport.
|
|
3482
|
-
* @param meshes Defines the mesh to zoom on
|
|
3483
|
-
* @param doNotUpdateMaxZ Defines whether or not maxZ should be updated whilst zooming on the mesh (this can happen if the mesh is big and the maxradius pretty small for instance)
|
|
3484
|
-
*/
|
|
3485
|
-
zoomOn(meshes, doNotUpdateMaxZ = false) {
|
|
3486
|
-
meshes = meshes || this.getScene().meshes;
|
|
3487
|
-
const minMaxVector = Mesh.MinMax(meshes);
|
|
3488
|
-
const distance = Vector3.Distance(minMaxVector.min, minMaxVector.max);
|
|
3489
|
-
this.radius = distance * this.zoomOnFactor;
|
|
3490
|
-
this.focusOn({ min: minMaxVector.min, max: minMaxVector.max, distance: distance }, doNotUpdateMaxZ);
|
|
3491
|
-
}
|
|
3492
|
-
/**
|
|
3493
|
-
* Focus on a mesh or a bounding box. This adapts the target and maxRadius if necessary but does not update the current radius.
|
|
3494
|
-
* The target will be changed but the radius
|
|
3495
|
-
* @param meshesOrMinMaxVectorAndDistance Defines the mesh or bounding info to focus on
|
|
3496
|
-
* @param doNotUpdateMaxZ Defines whether or not maxZ should be updated whilst zooming on the mesh (this can happen if the mesh is big and the maxradius pretty small for instance)
|
|
3497
|
-
*/
|
|
3498
|
-
focusOn(meshesOrMinMaxVectorAndDistance, doNotUpdateMaxZ = false) {
|
|
3499
|
-
let meshesOrMinMaxVector;
|
|
3500
|
-
let distance;
|
|
3501
|
-
if (meshesOrMinMaxVectorAndDistance.min === undefined) {
|
|
3502
|
-
// meshes
|
|
3503
|
-
const meshes = meshesOrMinMaxVectorAndDistance || this.getScene().meshes;
|
|
3504
|
-
meshesOrMinMaxVector = Mesh.MinMax(meshes);
|
|
3505
|
-
distance = Vector3.Distance(meshesOrMinMaxVector.min, meshesOrMinMaxVector.max);
|
|
3506
|
-
}
|
|
3507
|
-
else {
|
|
3508
|
-
//minMaxVector and distance
|
|
3509
|
-
const minMaxVectorAndDistance = meshesOrMinMaxVectorAndDistance;
|
|
3510
|
-
meshesOrMinMaxVector = minMaxVectorAndDistance;
|
|
3511
|
-
distance = minMaxVectorAndDistance.distance;
|
|
3512
|
-
}
|
|
3513
|
-
this._target = Mesh.Center(meshesOrMinMaxVector);
|
|
3514
|
-
if (!doNotUpdateMaxZ) {
|
|
3515
|
-
this.maxZ = distance * 2;
|
|
3516
|
-
}
|
|
3517
|
-
}
|
|
3518
|
-
/**
|
|
3519
|
-
* @override
|
|
3520
|
-
* Override Camera.createRigCamera
|
|
3521
|
-
*/
|
|
3522
|
-
createRigCamera(name, cameraIndex) {
|
|
3523
|
-
let alphaShift = 0;
|
|
3524
|
-
switch (this.cameraRigMode) {
|
|
3525
|
-
case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
|
|
3526
|
-
case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
|
|
3527
|
-
case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
|
|
3528
|
-
case Camera.RIG_MODE_STEREOSCOPIC_INTERLACED:
|
|
3529
|
-
case Camera.RIG_MODE_VR:
|
|
3530
|
-
alphaShift = this._cameraRigParams.stereoHalfAngle * (cameraIndex === 0 ? 1 : -1);
|
|
3531
|
-
break;
|
|
3532
|
-
case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
|
|
3533
|
-
alphaShift = this._cameraRigParams.stereoHalfAngle * (cameraIndex === 0 ? -1 : 1);
|
|
3534
|
-
break;
|
|
3535
|
-
}
|
|
3536
|
-
const rigCam = new ArcRotateCamera(name, this.alpha + alphaShift, this.beta, this.radius, this._target, this.getScene());
|
|
3537
|
-
rigCam._cameraRigParams = {};
|
|
3538
|
-
rigCam.isRigCamera = true;
|
|
3539
|
-
rigCam.rigParent = this;
|
|
3540
|
-
rigCam.upVector = this.upVector;
|
|
3541
|
-
rigCam.mode = this.mode;
|
|
3542
|
-
rigCam.orthoLeft = this.orthoLeft;
|
|
3543
|
-
rigCam.orthoRight = this.orthoRight;
|
|
3544
|
-
rigCam.orthoBottom = this.orthoBottom;
|
|
3545
|
-
rigCam.orthoTop = this.orthoTop;
|
|
3546
|
-
return rigCam;
|
|
3547
|
-
}
|
|
3548
|
-
/**
|
|
3549
|
-
* @internal
|
|
3550
|
-
* @override
|
|
3551
|
-
* Override Camera._updateRigCameras
|
|
3552
|
-
*/
|
|
3553
|
-
_updateRigCameras() {
|
|
3554
|
-
const camLeft = this._rigCameras[0];
|
|
3555
|
-
const camRight = this._rigCameras[1];
|
|
3556
|
-
camLeft.beta = camRight.beta = this.beta;
|
|
3557
|
-
switch (this.cameraRigMode) {
|
|
3558
|
-
case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
|
|
3559
|
-
case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
|
|
3560
|
-
case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
|
|
3561
|
-
case Camera.RIG_MODE_STEREOSCOPIC_INTERLACED:
|
|
3562
|
-
case Camera.RIG_MODE_VR:
|
|
3563
|
-
camLeft.alpha = this.alpha - this._cameraRigParams.stereoHalfAngle;
|
|
3564
|
-
camRight.alpha = this.alpha + this._cameraRigParams.stereoHalfAngle;
|
|
3565
|
-
break;
|
|
3566
|
-
case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
|
|
3567
|
-
camLeft.alpha = this.alpha + this._cameraRigParams.stereoHalfAngle;
|
|
3568
|
-
camRight.alpha = this.alpha - this._cameraRigParams.stereoHalfAngle;
|
|
3569
|
-
break;
|
|
3570
|
-
}
|
|
3571
|
-
super._updateRigCameras();
|
|
3572
|
-
}
|
|
3573
|
-
/**
|
|
3574
|
-
* Destroy the camera and release the current resources hold by it.
|
|
3575
|
-
*/
|
|
3576
|
-
dispose() {
|
|
3577
|
-
this.inputs.clear();
|
|
3578
|
-
super.dispose();
|
|
3579
|
-
}
|
|
3580
|
-
/**
|
|
3581
|
-
* Gets the current object class name.
|
|
3582
|
-
* @returns the class name
|
|
3583
|
-
*/
|
|
3584
|
-
getClassName() {
|
|
3585
|
-
return "ArcRotateCamera";
|
|
3586
|
-
}
|
|
3587
|
-
}
|
|
3588
|
-
__decorate([
|
|
3589
|
-
serialize()
|
|
3590
|
-
], ArcRotateCamera.prototype, "alpha", void 0);
|
|
3591
|
-
__decorate([
|
|
3592
|
-
serialize()
|
|
3593
|
-
], ArcRotateCamera.prototype, "beta", void 0);
|
|
3594
|
-
__decorate([
|
|
3595
|
-
serialize()
|
|
3596
|
-
], ArcRotateCamera.prototype, "radius", void 0);
|
|
3597
|
-
__decorate([
|
|
3598
|
-
serialize()
|
|
3599
|
-
], ArcRotateCamera.prototype, "overrideCloneAlphaBetaRadius", void 0);
|
|
3600
|
-
__decorate([
|
|
3601
|
-
serializeAsVector3("target")
|
|
3602
|
-
], ArcRotateCamera.prototype, "_target", void 0);
|
|
3603
|
-
__decorate([
|
|
3604
|
-
serializeAsMeshReference("targetHost")
|
|
3605
|
-
], ArcRotateCamera.prototype, "_targetHost", void 0);
|
|
3606
|
-
__decorate([
|
|
3607
|
-
serialize()
|
|
3608
|
-
], ArcRotateCamera.prototype, "inertialAlphaOffset", void 0);
|
|
3609
|
-
__decorate([
|
|
3610
|
-
serialize()
|
|
3611
|
-
], ArcRotateCamera.prototype, "inertialBetaOffset", void 0);
|
|
3612
|
-
__decorate([
|
|
3613
|
-
serialize()
|
|
3614
|
-
], ArcRotateCamera.prototype, "inertialRadiusOffset", void 0);
|
|
3615
|
-
__decorate([
|
|
3616
|
-
serialize()
|
|
3617
|
-
], ArcRotateCamera.prototype, "lowerAlphaLimit", void 0);
|
|
3618
|
-
__decorate([
|
|
3619
|
-
serialize()
|
|
3620
|
-
], ArcRotateCamera.prototype, "upperAlphaLimit", void 0);
|
|
3621
|
-
__decorate([
|
|
3622
|
-
serialize()
|
|
3623
|
-
], ArcRotateCamera.prototype, "lowerBetaLimit", void 0);
|
|
3624
|
-
__decorate([
|
|
3625
|
-
serialize()
|
|
3626
|
-
], ArcRotateCamera.prototype, "upperBetaLimit", void 0);
|
|
3627
|
-
__decorate([
|
|
3628
|
-
serialize()
|
|
3629
|
-
], ArcRotateCamera.prototype, "lowerRadiusLimit", void 0);
|
|
3630
|
-
__decorate([
|
|
3631
|
-
serialize()
|
|
3632
|
-
], ArcRotateCamera.prototype, "upperRadiusLimit", void 0);
|
|
3633
|
-
__decorate([
|
|
3634
|
-
serialize()
|
|
3635
|
-
], ArcRotateCamera.prototype, "inertialPanningX", void 0);
|
|
3636
|
-
__decorate([
|
|
3637
|
-
serialize()
|
|
3638
|
-
], ArcRotateCamera.prototype, "inertialPanningY", void 0);
|
|
3639
|
-
__decorate([
|
|
3640
|
-
serialize()
|
|
3641
|
-
], ArcRotateCamera.prototype, "pinchToPanMaxDistance", void 0);
|
|
3642
|
-
__decorate([
|
|
3643
|
-
serialize()
|
|
3644
|
-
], ArcRotateCamera.prototype, "panningDistanceLimit", void 0);
|
|
3645
|
-
__decorate([
|
|
3646
|
-
serializeAsVector3()
|
|
3647
|
-
], ArcRotateCamera.prototype, "panningOriginTarget", void 0);
|
|
3648
|
-
__decorate([
|
|
3649
|
-
serialize()
|
|
3650
|
-
], ArcRotateCamera.prototype, "panningInertia", void 0);
|
|
3651
|
-
__decorate([
|
|
3652
|
-
serialize()
|
|
3653
|
-
], ArcRotateCamera.prototype, "zoomToMouseLocation", null);
|
|
3654
|
-
__decorate([
|
|
3655
|
-
serialize()
|
|
3656
|
-
], ArcRotateCamera.prototype, "zoomOnFactor", void 0);
|
|
3657
|
-
__decorate([
|
|
3658
|
-
serializeAsVector2()
|
|
3659
|
-
], ArcRotateCamera.prototype, "targetScreenOffset", void 0);
|
|
3660
|
-
__decorate([
|
|
3661
|
-
serialize()
|
|
3662
|
-
], ArcRotateCamera.prototype, "allowUpsideDown", void 0);
|
|
3663
|
-
__decorate([
|
|
3664
|
-
serialize()
|
|
3665
|
-
], ArcRotateCamera.prototype, "useInputToRestoreState", void 0);
|
|
3666
|
-
|
|
3667
|
-
/**
|
|
3668
|
-
* A slightly extended version of the ArcRotateCamera.
|
|
3669
|
-
* Configures the camera in a way that best suites product visualization.
|
|
3670
|
-
* Also provides some convenience functions for interacting with the camera at runtime.
|
|
3671
|
-
*/
|
|
3672
|
-
class ProductCamera extends ArcRotateCamera {
|
|
3673
|
-
constructor(name, alpha, beta, radius, target, scene, configuration, setActiveOnSceneIfNoneActive) {
|
|
3674
|
-
super(name, alpha, beta, radius, target, scene, setActiveOnSceneIfNoneActive);
|
|
3675
|
-
/**
|
|
3676
|
-
* Stores the current executed target point of the camera. If the camera target changes
|
|
3677
|
-
* via panning we can notify ui about the fact to help users reset the camera.
|
|
3678
|
-
*/
|
|
3679
|
-
this.lastFocus = new Vector3(0, 0, 0);
|
|
3680
|
-
this.panDenominator = 1;
|
|
3681
|
-
// We set some sensible defaults for camera behavior. Some of
|
|
3682
|
-
// these defaults are dependant on calculated camera parameters like radius
|
|
3683
|
-
// which is why we need to ensure that these values are computing straight after the framing behavior
|
|
3684
|
-
// has run so our calculations are correctly computed based on scene scale.
|
|
3685
|
-
this.minZ = 0.01;
|
|
3686
|
-
this.setRadius(this.radius);
|
|
3687
|
-
this.enableFramingBehavior();
|
|
3688
|
-
this.wheelDeltaPercentage = 0.01;
|
|
3689
|
-
this.pinchDeltaPercentage = 0.005;
|
|
3690
|
-
this.useNaturalPinchZoom = true;
|
|
3691
|
-
// glTF assets use a +Z forward convention while the default camera faces +Z.
|
|
3692
|
-
// Rotate the camera to look at the front of the asset by default unless configured not to.
|
|
3693
|
-
if (configuration.camera.autoOrientation) {
|
|
3694
|
-
this.alpha += Math.PI;
|
|
3695
|
-
}
|
|
3696
|
-
// When configuration is available we can go through the camera specific
|
|
3697
|
-
// fields and apply them.
|
|
3698
|
-
if (configuration) {
|
|
3699
|
-
if (configuration.camera.limits.min.beta) {
|
|
3700
|
-
this.lowerBetaLimit = configuration.camera.limits.min.beta;
|
|
3701
|
-
}
|
|
3702
|
-
if (configuration.camera.limits.max.beta) {
|
|
3703
|
-
this.upperBetaLimit = configuration.camera.limits.max.beta;
|
|
3704
|
-
}
|
|
3705
|
-
if (configuration.camera.limits.min.alpha) {
|
|
3706
|
-
this.lowerAlphaLimit = configuration.camera.limits.min.alpha;
|
|
3707
|
-
}
|
|
3708
|
-
if (configuration.camera.limits.max.alpha) {
|
|
3709
|
-
this.upperAlphaLimit = configuration.camera.limits.max.alpha;
|
|
3710
|
-
}
|
|
3711
|
-
if (configuration.camera.limits.min.radius) {
|
|
3712
|
-
this.lowerRadiusLimit = configuration.camera.limits.min.radius;
|
|
3713
|
-
}
|
|
3714
|
-
if (configuration.camera.limits.max.radius) {
|
|
3715
|
-
this.upperRadiusLimit = configuration.camera.limits.max.radius;
|
|
3716
|
-
}
|
|
3717
|
-
configuration.camera.autoRotation.enabled &&
|
|
3718
|
-
this.enableAutoRotationBehavior(configuration.camera.autoRotation.idleTimeMs);
|
|
3719
|
-
}
|
|
3720
|
-
}
|
|
3721
|
-
/**
|
|
3722
|
-
* Returns the framing behavior of this camera.
|
|
3723
|
-
*/
|
|
3724
|
-
getFramingBehavior() {
|
|
3725
|
-
return this.getBehaviorByName('Framing');
|
|
3726
|
-
}
|
|
3727
|
-
/**
|
|
3728
|
-
* Returns the auto rotation behavior of this camera, this may
|
|
3729
|
-
* not always be available.
|
|
3730
|
-
*/
|
|
3731
|
-
getAutoRotationBehavior() {
|
|
3732
|
-
const autoRotate = this.getBehaviorByName('AutoRotation');
|
|
3733
|
-
if (autoRotate) {
|
|
3734
|
-
return autoRotate;
|
|
3735
|
-
}
|
|
3736
|
-
else {
|
|
3737
|
-
return undefined;
|
|
3738
|
-
}
|
|
3739
|
-
}
|
|
3740
|
-
/**
|
|
3741
|
-
* Activates framing on this camera causing the camera to focus on
|
|
3742
|
-
* the scene and bound itself in a sensible fashion to the scene content.
|
|
3743
|
-
*/
|
|
3744
|
-
enableFramingBehavior() {
|
|
3745
|
-
this.useFramingBehavior = true;
|
|
3746
|
-
const framingBehavior = this.getFramingBehavior();
|
|
3747
|
-
framingBehavior.attach(this);
|
|
3748
|
-
framingBehavior.framingTime = 0;
|
|
3749
|
-
framingBehavior.elevationReturnTime = -1;
|
|
3750
|
-
framingBehavior.zoomStopsAnimation = false;
|
|
3751
|
-
this.lowerRadiusLimit = null;
|
|
3752
|
-
// Set the target bounding box for the camera
|
|
3753
|
-
const worldExtends = calculateWorldExtends(this._scene);
|
|
3754
|
-
framingBehavior.zoomOnBoundingInfo(worldExtends.min, worldExtends.max);
|
|
3755
|
-
// Calculate a sensible default for wheel zoom speed based on newly calculated radius.
|
|
3756
|
-
this.wheelPrecision = 100 / this.radius;
|
|
3757
|
-
// If we have no lower radius at this point we must fall back to a default
|
|
3758
|
-
// to prevent the user zooming through the model...
|
|
3759
|
-
if (this.lowerRadiusLimit === null) {
|
|
3760
|
-
this.lowerRadiusLimit = 0.1;
|
|
3761
|
-
}
|
|
3762
|
-
this.lastFocus.copyFrom(this.target);
|
|
3763
|
-
return framingBehavior;
|
|
3764
|
-
}
|
|
3765
|
-
/**
|
|
3766
|
-
* Animates the camera back to the initial target when it has drifted to another position.
|
|
3767
|
-
* @param onAnimationComplete A callback when the camera has finished animating.
|
|
3768
|
-
* @param time The time in milliseconds the animation should take.
|
|
3769
|
-
*/
|
|
3770
|
-
rerunFramingBehavior(onAnimationComplete, time) {
|
|
3771
|
-
const framingBehavior = this.getFramingBehavior();
|
|
3772
|
-
framingBehavior.framingTime = time || 800;
|
|
3773
|
-
const handleAnimationComplete = () => {
|
|
3774
|
-
onAnimationComplete && onAnimationComplete();
|
|
3775
|
-
};
|
|
3776
|
-
const worldExtends = calculateWorldExtends(this._scene);
|
|
3777
|
-
const worldSize = worldExtends.max.subtract(worldExtends.min);
|
|
3778
|
-
const worldCenter = worldExtends.min.add(worldSize.scale(0.5));
|
|
3779
|
-
this.setRadius(worldSize.length() * 1.5);
|
|
3780
|
-
// Calculate a sensible default for wheel zoom speed based on newly calculated radius.
|
|
3781
|
-
this.wheelPrecision = 100 / this.radius;
|
|
3782
|
-
// Attach an observer to manage dynamic recalculation of pan speed based on zoom. This will
|
|
3783
|
-
// allow us to keep pan speed consistent regardless of zoom level.
|
|
3784
|
-
this.panningInertia = 0;
|
|
3785
|
-
this.panningOriginTarget.copyFrom(worldCenter);
|
|
3786
|
-
this.panDenominator = worldSize.length();
|
|
3787
|
-
framingBehavior.zoomOnBoundingInfo(worldExtends.min, worldExtends.max, undefined, handleAnimationComplete);
|
|
3788
|
-
framingBehavior.framingTime = 0;
|
|
3789
|
-
}
|
|
3790
|
-
/**
|
|
3791
|
-
* Activates the auto rotation behavior causing the camera to rotate slowly around
|
|
3792
|
-
* it's target.
|
|
3793
|
-
* @param idleTime The number of milliseconds before the camera starts rotating after the user last interacted.
|
|
3794
|
-
*/
|
|
3795
|
-
enableAutoRotationBehavior(idleTime = 5000) {
|
|
3796
|
-
this.useAutoRotationBehavior = true;
|
|
3797
|
-
const autoRotation = this.getAutoRotationBehavior();
|
|
3798
|
-
if (!autoRotation) {
|
|
3799
|
-
return;
|
|
3800
|
-
}
|
|
3801
|
-
autoRotation.idleRotationWaitTime = idleTime;
|
|
3802
|
-
}
|
|
3803
|
-
/**
|
|
3804
|
-
* Stops the auto rotation functionality immediately.
|
|
3805
|
-
*/
|
|
3806
|
-
disableAutoRotationBehavior() {
|
|
3807
|
-
this.useAutoRotationBehavior = false;
|
|
3808
|
-
}
|
|
3809
|
-
setRadius(radius) {
|
|
3810
|
-
this.radius = radius;
|
|
3811
|
-
this.maxZ = this.radius * 1000;
|
|
3812
|
-
this.lowerRadiusLimit = this.radius * 0.01;
|
|
3813
|
-
this.upperRadiusLimit = 1.5 * this.radius;
|
|
3814
|
-
this.wheelPrecision = 100 / this.radius;
|
|
3815
|
-
this.pinchPrecision = 300 / this.radius;
|
|
3816
|
-
}
|
|
3817
|
-
/**
|
|
3818
|
-
* A static function used to instantiate a single product camera instance on a scene. This camera will assume
|
|
3819
|
-
* the active camera role on the scene and any existing active camera will be disposed.
|
|
3820
|
-
* @param scene The scene to attach the camera to.
|
|
3821
|
-
* @param configuration A configuration object to define the cameras limitations.
|
|
3822
|
-
* @param assignActive If true the camera will be assigned as the active camera on the scene.
|
|
3823
|
-
*/
|
|
3824
|
-
static create(scene, configuration, assignActive) {
|
|
3825
|
-
// Build camera
|
|
3826
|
-
const worldExtends = calculateWorldExtends(scene);
|
|
3827
|
-
const worldSize = worldExtends.max.subtract(worldExtends.min);
|
|
3828
|
-
const worldCenter = worldExtends.min.add(worldSize.scale(0.5));
|
|
3829
|
-
const camera = new ProductCamera('ProductCamera', -(Math.PI / 2), Math.PI / 2, worldSize.length() * 1.5, worldCenter, scene, configuration);
|
|
3830
|
-
// Attach an observer to manage dynamic recalculation of pan speed based on zoom. This will
|
|
3831
|
-
// allow us to keep pan speed consistent regardless of zoom level.
|
|
3832
|
-
camera.panningInertia = 0;
|
|
3833
|
-
camera.panningOriginTarget.copyFrom(worldCenter);
|
|
3834
|
-
camera.panDenominator = worldSize.length();
|
|
3835
|
-
camera.onAfterCheckInputsObservable.add(() => {
|
|
3836
|
-
// TODO: There's still an unknown factor here. Dividing 1000 results
|
|
3837
|
-
// in a fairly good experience across the board but really tiny/massive models still
|
|
3838
|
-
// are too fast/slow respectively. Camera.radius also seems to be related...
|
|
3839
|
-
camera.panningSensibility = 1000 / camera.panDenominator;
|
|
3840
|
-
});
|
|
3841
|
-
if (assignActive) {
|
|
3842
|
-
scene.activeCamera = camera;
|
|
3843
|
-
}
|
|
3844
|
-
return camera;
|
|
3845
|
-
}
|
|
3846
|
-
}
|
|
3847
|
-
/**
|
|
3848
|
-
* Determines the bounding box of all content in the scene that should be included in
|
|
3849
|
-
* the focus of the product camera.
|
|
3850
|
-
*/
|
|
3851
|
-
function calculateWorldExtends(scene) {
|
|
3852
|
-
// TODO: Move away from depending on mesh name to determine whether or not a mesh should be targeted
|
|
3853
|
-
if (scene.meshes.length === 0) {
|
|
3854
|
-
return {
|
|
3855
|
-
min: new Vector3(-1, -1, -1),
|
|
3856
|
-
max: new Vector3(1, 1, 1),
|
|
3857
|
-
};
|
|
3858
|
-
}
|
|
3859
|
-
const targetMeshes = scene.meshes.filter((mesh) => {
|
|
3860
|
-
return (mesh.name.toLowerCase().endsWith('_t') ||
|
|
3861
|
-
mesh.name.toLowerCase().includes('_t_'));
|
|
3862
|
-
});
|
|
3863
|
-
return scene.getWorldExtends((mesh) => {
|
|
3864
|
-
return (mesh.isVisible &&
|
|
3865
|
-
mesh.isEnabled() &&
|
|
3866
|
-
(targetMeshes.length === 0 || targetMeshes.includes(mesh)));
|
|
3867
|
-
});
|
|
3868
|
-
}
|
|
3869
|
-
|
|
3870
|
-
export { ArcRotateCamera as A, CameraInputTypes as C, ProductCamera as P, TargetCamera as T, CameraInputsManager as a };
|