@shapediver/viewer.rendering-engine.camera-engine 2.11.0 → 2.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/implementation/camera/AbstractCamera.d.ts +5 -3
- package/dist/implementation/camera/AbstractCamera.d.ts.map +1 -1
- package/dist/implementation/camera/AbstractCamera.js +26 -18
- package/dist/implementation/camera/AbstractCamera.js.map +1 -1
- package/dist/implementation/controls/AbstractCameraControls.d.ts +13 -7
- package/dist/implementation/controls/AbstractCameraControls.d.ts.map +1 -1
- package/dist/implementation/controls/AbstractCameraControls.js +71 -38
- package/dist/implementation/controls/AbstractCameraControls.js.map +1 -1
- package/dist/implementation/controls/OrthographicCameraControls.d.ts.map +1 -1
- package/dist/implementation/controls/OrthographicCameraControls.js +2 -2
- package/dist/implementation/controls/OrthographicCameraControls.js.map +1 -1
- package/dist/implementation/controls/PerspectiveCameraControls.d.ts +15 -3
- package/dist/implementation/controls/PerspectiveCameraControls.d.ts.map +1 -1
- package/dist/implementation/controls/PerspectiveCameraControls.js +108 -78
- package/dist/implementation/controls/PerspectiveCameraControls.js.map +1 -1
- package/dist/implementation/controls/orthographic/CameraControlsEventDistribution.d.ts +3 -3
- package/dist/implementation/controls/orthographic/CameraControlsEventDistribution.d.ts.map +1 -1
- package/dist/implementation/controls/orthographic/CameraControlsEventDistribution.js +31 -23
- package/dist/implementation/controls/orthographic/CameraControlsEventDistribution.js.map +1 -1
- package/dist/implementation/controls/orthographic/CameraControlsLogic.d.ts.map +1 -1
- package/dist/implementation/controls/orthographic/CameraControlsLogic.js +36 -38
- package/dist/implementation/controls/orthographic/CameraControlsLogic.js.map +1 -1
- package/dist/implementation/controls/perspective/CameraControlsEventDistribution.d.ts +4 -4
- package/dist/implementation/controls/perspective/CameraControlsEventDistribution.d.ts.map +1 -1
- package/dist/implementation/controls/perspective/CameraControlsEventDistribution.js +39 -32
- package/dist/implementation/controls/perspective/CameraControlsEventDistribution.js.map +1 -1
- package/dist/implementation/controls/perspective/CameraControlsLogic.d.ts +3 -2
- package/dist/implementation/controls/perspective/CameraControlsLogic.d.ts.map +1 -1
- package/dist/implementation/controls/perspective/CameraControlsLogic.js +88 -66
- package/dist/implementation/controls/perspective/CameraControlsLogic.js.map +1 -1
- package/dist/interfaces/camera/ICamera.d.ts +9 -8
- package/dist/interfaces/camera/ICamera.d.ts.map +1 -1
- package/dist/interfaces/controls/ICameraControls.d.ts +4 -3
- package/dist/interfaces/controls/ICameraControls.d.ts.map +1 -1
- package/dist/interfaces/controls/ICameraControlsLogic.d.ts +3 -2
- package/dist/interfaces/controls/ICameraControlsLogic.d.ts.map +1 -1
- package/dist/interfaces/controls/IPerspectiveCameraControls.d.ts +4 -0
- package/dist/interfaces/controls/IPerspectiveCameraControls.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/implementation/camera/AbstractCamera.ts +44 -37
- package/src/implementation/controls/AbstractCameraControls.ts +113 -70
- package/src/implementation/controls/OrthographicCameraControls.ts +9 -9
- package/src/implementation/controls/PerspectiveCameraControls.ts +114 -73
- package/src/implementation/controls/orthographic/CameraControlsEventDistribution.ts +61 -56
- package/src/implementation/controls/orthographic/CameraControlsLogic.ts +45 -53
- package/src/implementation/controls/perspective/CameraControlsEventDistribution.ts +83 -80
- package/src/implementation/controls/perspective/CameraControlsLogic.ts +100 -81
- package/src/interfaces/camera/ICamera.ts +31 -26
- package/src/interfaces/controls/ICameraControls.ts +5 -5
- package/src/interfaces/controls/ICameraControlsLogic.ts +6 -2
- package/src/interfaces/controls/IPerspectiveCameraControls.ts +10 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { mat4, quat, vec2, vec3 } from 'gl-matrix'
|
|
2
|
-
import { Box, Sphere, Spherical } from '@shapediver/viewer.shared.math'
|
|
1
|
+
import { mat4, quat, vec2, vec3 } from 'gl-matrix';
|
|
2
|
+
import { Box, Sphere, Spherical } from '@shapediver/viewer.shared.math';
|
|
3
3
|
|
|
4
|
-
import { PerspectiveCameraControls } from '../PerspectiveCameraControls'
|
|
5
|
-
import { ICameraControlsLogic } from '../../../interfaces/controls/ICameraControlsLogic'
|
|
6
|
-
import { PerspectiveCamera } from '../../camera/PerspectiveCamera'
|
|
4
|
+
import { PerspectiveCameraControls } from '../PerspectiveCameraControls';
|
|
5
|
+
import { ICameraControlsLogic } from '../../../interfaces/controls/ICameraControlsLogic';
|
|
6
|
+
import { PerspectiveCamera } from '../../camera/PerspectiveCamera';
|
|
7
7
|
|
|
8
8
|
export class CameraControlsLogic implements ICameraControlsLogic {
|
|
9
9
|
// #region Properties (15)
|
|
@@ -49,7 +49,7 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
49
49
|
autoRotationSpeed: 2 * Math.PI / 60 / 60,
|
|
50
50
|
damping: 1.0,
|
|
51
51
|
movementSmoothness: 1.0,
|
|
52
|
-
panSpeed:
|
|
52
|
+
panSpeed: 1.75,
|
|
53
53
|
rotationSpeed: Math.PI,
|
|
54
54
|
zoomSpeed: 0.025,
|
|
55
55
|
};
|
|
@@ -57,8 +57,8 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
57
57
|
autoRotationSpeed: 1.0,
|
|
58
58
|
damping: 1.0,
|
|
59
59
|
movementSmoothness: 1.0,
|
|
60
|
-
panSpeed: 1.
|
|
61
|
-
rotationSpeed:
|
|
60
|
+
panSpeed: 1.0 / 1.75,
|
|
61
|
+
rotationSpeed: 1.5,
|
|
62
62
|
zoomSpeed: 100.0,
|
|
63
63
|
};
|
|
64
64
|
|
|
@@ -76,7 +76,7 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
76
76
|
// #region Public Methods (7)
|
|
77
77
|
|
|
78
78
|
public isWithinRestrictions(position: vec3, target: vec3): boolean {
|
|
79
|
-
|
|
79
|
+
const pBox = new Box(this._controls.cubePositionRestriction.min, this._controls.cubePositionRestriction.max),
|
|
80
80
|
pSphere = new Sphere(this._controls.spherePositionRestriction.center, this._controls.spherePositionRestriction.radius),
|
|
81
81
|
tBox = new Box(this._controls.cubeTargetRestriction.min, this._controls.cubeTargetRestriction.max),
|
|
82
82
|
tSphere = new Sphere(this._controls.sphereTargetRestriction.center, this._controls.sphereTargetRestriction.radius);
|
|
@@ -84,10 +84,10 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
84
84
|
if (!(pBox.containsPoint(position) && pSphere.containsPoint(position))) return false;
|
|
85
85
|
if (!(tBox.containsPoint(target) && tSphere.containsPoint(target))) return false;
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
const currentDistance = vec3.distance(position, target);
|
|
88
88
|
if (currentDistance > this._controls.zoomRestriction.maxDistance || currentDistance < this._controls.zoomRestriction.minDistance) return false;
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
const minPolarAngle = this._controls.rotationRestriction.minPolarAngle * (Math.PI / 180),
|
|
91
91
|
maxPolarAngle = this._controls.rotationRestriction.maxPolarAngle * (Math.PI / 180),
|
|
92
92
|
minAzimuthAngle = this._controls.rotationRestriction.minAzimuthAngle * (Math.PI / 180),
|
|
93
93
|
maxAzimuthAngle = this._controls.rotationRestriction.maxAzimuthAngle * (Math.PI / 180);
|
|
@@ -96,7 +96,7 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
96
96
|
maxAzimuthAngle !== Infinity ||
|
|
97
97
|
minPolarAngle !== 0 ||
|
|
98
98
|
maxPolarAngle !== 180) {
|
|
99
|
-
|
|
99
|
+
const offset = vec3.sub(vec3.create(), position, target);
|
|
100
100
|
vec3.transformQuat(offset, offset, this._quat);
|
|
101
101
|
const spherical = new Spherical().fromVec3(offset);
|
|
102
102
|
|
|
@@ -112,10 +112,6 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
public pan(x: number, y: number, active: boolean, touch: boolean): void {
|
|
115
|
-
if (touch) {
|
|
116
|
-
x = x / window.devicePixelRatio;
|
|
117
|
-
y = y / window.devicePixelRatio;
|
|
118
|
-
}
|
|
119
115
|
|
|
120
116
|
if (!active) {
|
|
121
117
|
this._panStart = vec2.fromValues(x, y);
|
|
@@ -123,11 +119,10 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
123
119
|
this._panEnd = vec2.fromValues(x, y);
|
|
124
120
|
vec2.sub(this._panDelta, this._panEnd, this._panStart);
|
|
125
121
|
if (this._panDelta[0] === 0 && this._panDelta[1] === 0) return;
|
|
126
|
-
|
|
127
122
|
vec2.copy(this._panStart, this._panEnd);
|
|
128
123
|
|
|
129
124
|
const adjustedPanSpeed = this._adjustedSettings.panSpeed() * (touch ? this._touchAdjustments.panSpeed : 1.0);
|
|
130
|
-
|
|
125
|
+
const offset = this.panDeltaToOffset(vec2.mul(vec2.create(), this._panDelta, vec2.fromValues(adjustedPanSpeed, adjustedPanSpeed)));
|
|
131
126
|
|
|
132
127
|
if (this._damping.pan.duration > 0) {
|
|
133
128
|
if (offset[0] < 0) {
|
|
@@ -147,11 +142,11 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
147
142
|
}
|
|
148
143
|
}
|
|
149
144
|
|
|
150
|
-
|
|
145
|
+
const damping = 1 - Math.max(0.01, Math.min(0.99, this._adjustedSettings.damping()));
|
|
151
146
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
147
|
+
const framesOffsetX = (Math.log(1 / Math.abs(offset[0])) - 5 * Math.log(10)) / (Math.log(damping));
|
|
148
|
+
const framesOffsetY = (Math.log(1 / Math.abs(offset[1])) - 5 * Math.log(10)) / (Math.log(damping));
|
|
149
|
+
const framesOffsetZ = (Math.log(1 / Math.abs(offset[2])) - 5 * Math.log(10)) / (Math.log(damping));
|
|
155
150
|
this._damping.pan.time = 0;
|
|
156
151
|
this._damping.pan.duration = Math.max(framesOffsetX, Math.max(framesOffsetY, framesOffsetZ)) * 16.6666;
|
|
157
152
|
this._damping.pan.offset = vec3.clone(offset);
|
|
@@ -194,8 +189,8 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
194
189
|
this._rotateStart = vec2.create();
|
|
195
190
|
}
|
|
196
191
|
|
|
197
|
-
public restrict(position: vec3, target: vec3): { position: vec3, target: vec3 } {
|
|
198
|
-
|
|
192
|
+
public restrict(position: vec3, target: vec3, sceneRotation: vec2): { position: vec3, target: vec3, sceneRotation: vec2 } {
|
|
193
|
+
const pBox = new Box(this._controls.cubePositionRestriction.min, this._controls.cubePositionRestriction.max),
|
|
199
194
|
pSphere = new Sphere(this._controls.spherePositionRestriction.center, this._controls.spherePositionRestriction.radius),
|
|
200
195
|
tBox = new Box(this._controls.cubeTargetRestriction.min, this._controls.cubeTargetRestriction.max),
|
|
201
196
|
tSphere = new Sphere(this._controls.sphereTargetRestriction.center, this._controls.sphereTargetRestriction.radius);
|
|
@@ -213,15 +208,15 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
213
208
|
target = tSphere.clampPoint(target);
|
|
214
209
|
|
|
215
210
|
// zoom restrictions
|
|
216
|
-
|
|
211
|
+
const currentDistance = vec3.distance(position, target);
|
|
217
212
|
if (currentDistance > this._controls.zoomRestriction.maxDistance || currentDistance < this._controls.zoomRestriction.minDistance) {
|
|
218
|
-
|
|
219
|
-
|
|
213
|
+
const direction = vec3.normalize(vec3.create(), vec3.subtract(vec3.create(), position, target));
|
|
214
|
+
const distance = Math.max(this._controls.zoomRestriction.minDistance, Math.min(this._controls.zoomRestriction.maxDistance, currentDistance));
|
|
220
215
|
vec3.add(position, vec3.multiply(position, direction, vec3.fromValues(distance, distance, distance)), target);
|
|
221
216
|
}
|
|
222
217
|
|
|
223
218
|
// angle restrictions
|
|
224
|
-
|
|
219
|
+
const minPolarAngle = this._controls.rotationRestriction.minPolarAngle * (Math.PI / 180),
|
|
225
220
|
maxPolarAngle = this._controls.rotationRestriction.maxPolarAngle * (Math.PI / 180),
|
|
226
221
|
minAzimuthAngle = this._controls.rotationRestriction.minAzimuthAngle * (Math.PI / 180),
|
|
227
222
|
maxAzimuthAngle = this._controls.rotationRestriction.maxAzimuthAngle * (Math.PI / 180);
|
|
@@ -229,7 +224,10 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
229
224
|
if (minAzimuthAngle !== -Infinity ||
|
|
230
225
|
maxAzimuthAngle !== Infinity ||
|
|
231
226
|
minPolarAngle !== 0 ||
|
|
232
|
-
maxPolarAngle !== 180
|
|
227
|
+
maxPolarAngle !== 180 ||
|
|
228
|
+
this._controls.enableAzimuthRotation === false ||
|
|
229
|
+
this._controls.enablePolarRotation === false
|
|
230
|
+
) {
|
|
233
231
|
let offset = vec3.subtract(vec3.create(), position, target);
|
|
234
232
|
vec3.transformQuat(offset, offset, this._quat);
|
|
235
233
|
|
|
@@ -238,53 +236,72 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
238
236
|
if (spherical.theta < minAzimuthAngle ||
|
|
239
237
|
spherical.theta > maxAzimuthAngle ||
|
|
240
238
|
spherical.phi < minPolarAngle ||
|
|
241
|
-
spherical.phi > maxPolarAngle
|
|
239
|
+
spherical.phi > maxPolarAngle ||
|
|
240
|
+
this._controls.enableAzimuthRotation === false ||
|
|
241
|
+
this._controls.enablePolarRotation === false
|
|
242
|
+
) {
|
|
242
243
|
spherical.theta = Math.max(minAzimuthAngle, Math.min(maxAzimuthAngle, spherical.theta));
|
|
243
244
|
spherical.phi = Math.max(minPolarAngle, Math.min(maxPolarAngle, spherical.phi));
|
|
245
|
+
|
|
246
|
+
if (this._controls.enableAzimuthRotation === false || this._controls.enablePolarRotation === false) {
|
|
247
|
+
const defaultOffset = vec3.subtract(vec3.create(), this._controls.camera.defaultPosition, this._controls.camera.defaultTarget);
|
|
248
|
+
vec3.transformQuat(defaultOffset, defaultOffset, this._quat);
|
|
249
|
+
|
|
250
|
+
const defaultSpherical = new Spherical().fromVec3(defaultOffset);
|
|
251
|
+
if (this._controls.enableAzimuthRotation === false) spherical.theta = defaultSpherical.theta;
|
|
252
|
+
if (this._controls.enablePolarRotation === false) spherical.phi = defaultSpherical.phi;
|
|
253
|
+
}
|
|
254
|
+
|
|
244
255
|
spherical.makeSafe();
|
|
245
256
|
offset = spherical.toVec3();
|
|
246
257
|
vec3.transformQuat(offset, offset, this._quatInverse);
|
|
247
258
|
vec3.add(position, offset, target);
|
|
248
259
|
}
|
|
260
|
+
|
|
261
|
+
if (sceneRotation[1] < minAzimuthAngle ||
|
|
262
|
+
sceneRotation[1] > maxAzimuthAngle ||
|
|
263
|
+
sceneRotation[0] < minPolarAngle ||
|
|
264
|
+
sceneRotation[0] > maxPolarAngle ||
|
|
265
|
+
this._controls.enableAzimuthRotation === false ||
|
|
266
|
+
this._controls.enablePolarRotation === false) {
|
|
267
|
+
sceneRotation[1] = this._controls.enableAzimuthRotation === false ? 0 : Math.max(minAzimuthAngle, Math.min(maxAzimuthAngle, sceneRotation[1]));
|
|
268
|
+
sceneRotation[0] = this._controls.enablePolarRotation === false ? 0 : Math.max(minPolarAngle, Math.min(maxPolarAngle, sceneRotation[0]));
|
|
269
|
+
}
|
|
249
270
|
}
|
|
250
271
|
|
|
251
|
-
return { position, target };
|
|
272
|
+
return { position, target, sceneRotation };
|
|
252
273
|
}
|
|
253
274
|
|
|
254
275
|
public rotate(x: number, y: number, active: boolean, touch: boolean): void {
|
|
255
|
-
if (touch) {
|
|
256
|
-
x = x / window.devicePixelRatio;
|
|
257
|
-
y = y / window.devicePixelRatio;
|
|
258
|
-
}
|
|
259
276
|
|
|
260
277
|
if (!active) {
|
|
261
|
-
this._rotateStart = vec2.fromValues(x, y)
|
|
278
|
+
this._rotateStart = vec2.fromValues(x, y);
|
|
262
279
|
} else {
|
|
263
|
-
this._rotateEnd = vec2.fromValues(x, y)
|
|
264
|
-
vec2.subtract(this._rotateDelta, this._rotateEnd, this._rotateStart)
|
|
265
|
-
vec2.copy(this._rotateStart, this._rotateEnd)
|
|
280
|
+
this._rotateEnd = vec2.fromValues(x, y);
|
|
281
|
+
vec2.subtract(this._rotateDelta, this._rotateEnd, this._rotateStart);
|
|
282
|
+
vec2.copy(this._rotateStart, this._rotateEnd);
|
|
266
283
|
|
|
267
284
|
if (!this._controls.canvas) return;
|
|
268
285
|
if (this._controls.canvas.clientWidth == 0 || this._controls.canvas.clientHeight == 0) return;
|
|
269
286
|
|
|
270
287
|
const spherical = new Spherical();
|
|
271
|
-
|
|
272
|
-
spherical.theta -= rotationSpeed * this._rotateDelta[0];
|
|
273
|
-
spherical.phi -= rotationSpeed * this._rotateDelta[1];
|
|
288
|
+
const rotationSpeed = this._adjustedSettings.rotationSpeed() * (touch ? this._touchAdjustments.rotationSpeed : 1.0);
|
|
289
|
+
spherical.theta -= rotationSpeed * this._rotateDelta[0] / this._controls.canvas.clientHeight;
|
|
290
|
+
spherical.phi -= rotationSpeed * this._rotateDelta[1] / this._controls.canvas.clientHeight;
|
|
274
291
|
|
|
275
292
|
if (this._damping.rotation.duration > 0) {
|
|
276
|
-
|
|
293
|
+
const thetaDelta = this._damping.rotation.theta - spherical.theta;
|
|
277
294
|
spherical.theta += thetaDelta * this._adjustedSettings.movementSmoothness();
|
|
278
295
|
|
|
279
|
-
|
|
296
|
+
const phiDelta = this._damping.rotation.phi - spherical.phi;
|
|
280
297
|
spherical.phi += phiDelta * this._adjustedSettings.movementSmoothness();
|
|
281
298
|
}
|
|
282
299
|
|
|
283
|
-
|
|
300
|
+
const offset = this.rotationSphericalToOffset(this._controls.enableTurntableControls ? new Spherical(1.0, spherical.phi, 0) : spherical);
|
|
284
301
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
302
|
+
const damping = 1 - Math.max(0.01, Math.min(1, this._adjustedSettings.damping()));
|
|
303
|
+
const framesTheta = (Math.log(1 / Math.abs(spherical.theta)) - 5 * Math.log(10)) / (Math.log(damping));
|
|
304
|
+
const framesPhi = (Math.log(1 / Math.abs(spherical.phi)) - 5 * Math.log(10)) / (Math.log(damping));
|
|
288
305
|
|
|
289
306
|
this._damping.rotation.time = 0;
|
|
290
307
|
this._damping.rotation.duration = Math.max(framesTheta, framesPhi) * 16.6666;
|
|
@@ -295,6 +312,7 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
295
312
|
this._damping.zoom.duration = 0;
|
|
296
313
|
|
|
297
314
|
this._controls.applyPositionVector(offset, true);
|
|
315
|
+
if (this._controls.enableTurntableControls) this._controls.applyRotation([0, spherical.theta], true);
|
|
298
316
|
}
|
|
299
317
|
}
|
|
300
318
|
|
|
@@ -305,7 +323,7 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
305
323
|
this._damping.rotation.duration = 0;
|
|
306
324
|
}
|
|
307
325
|
|
|
308
|
-
|
|
326
|
+
const damping = 1 - Math.max(0.01, Math.min(1, this._adjustedSettings.damping()));
|
|
309
327
|
|
|
310
328
|
if (this._damping.pan.duration > 0) {
|
|
311
329
|
if (this._damping.pan.time + time > this._damping.pan.duration) {
|
|
@@ -314,9 +332,9 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
314
332
|
} else {
|
|
315
333
|
this._damping.pan.time += time;
|
|
316
334
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
335
|
+
const frameSinceStart = this._damping.pan.time / 16.6666;
|
|
336
|
+
const dampingFrames = Math.pow(damping, frameSinceStart);
|
|
337
|
+
const offset = vec3.multiply(vec3.create(), this._damping.pan.offset, vec3.fromValues(dampingFrames, dampingFrames, dampingFrames));
|
|
320
338
|
this._controls.applyTargetVector(offset);
|
|
321
339
|
this._controls.applyPositionVector(offset);
|
|
322
340
|
}
|
|
@@ -331,12 +349,13 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
331
349
|
} else {
|
|
332
350
|
this._damping.rotation.time += time;
|
|
333
351
|
|
|
334
|
-
|
|
335
|
-
|
|
352
|
+
const frameSinceStart = this._damping.rotation.time / 16.6666;
|
|
353
|
+
const spherical = new Spherical();
|
|
336
354
|
spherical.theta = this._damping.rotation.theta * Math.pow(damping, frameSinceStart);
|
|
337
355
|
spherical.phi = this._damping.rotation.phi * Math.pow(damping, frameSinceStart);
|
|
338
|
-
|
|
356
|
+
const offset = this.rotationSphericalToOffset(this._controls.enableTurntableControls ? new Spherical(1.0, spherical.phi, 0) : spherical);
|
|
339
357
|
this._controls.applyPositionVector(offset);
|
|
358
|
+
if (this._controls.enableTurntableControls) this._controls.applyRotation([0, spherical.theta]);
|
|
340
359
|
}
|
|
341
360
|
} else {
|
|
342
361
|
this._damping.rotation.time = 0;
|
|
@@ -349,9 +368,9 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
349
368
|
} else {
|
|
350
369
|
this._damping.zoom.time += time;
|
|
351
370
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
371
|
+
const frameSinceStart = this._damping.zoom.time / 16.6666;
|
|
372
|
+
const delta = this._damping.zoom.delta * Math.pow(damping, frameSinceStart);
|
|
373
|
+
const offset = this.zoomDistanceToOffset(delta);
|
|
355
374
|
this._controls.applyPositionVector(offset);
|
|
356
375
|
}
|
|
357
376
|
} else {
|
|
@@ -359,17 +378,15 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
359
378
|
}
|
|
360
379
|
|
|
361
380
|
if (this._controls.enableAutoRotation) {
|
|
362
|
-
|
|
363
|
-
|
|
381
|
+
const spherical = new Spherical(1.0, 0.0, -this._adjustedSettings.autoRotationSpeed());
|
|
382
|
+
const offset = this.rotationSphericalToOffset(this._controls.enableTurntableControls ? new Spherical(1.0, spherical.phi, 0) : spherical);
|
|
364
383
|
this._controls.applyPositionVector(offset);
|
|
384
|
+
if (this._controls.enableTurntableControls) this._controls.applyRotation([0, spherical.theta]);
|
|
365
385
|
}
|
|
366
386
|
}
|
|
367
387
|
|
|
368
388
|
public zoom(x: number, y: number, active: boolean, touch: boolean): void {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
if (touch)
|
|
372
|
-
distance = distance / window.devicePixelRatio;
|
|
389
|
+
const distance = Math.sqrt(x * x + y * y);
|
|
373
390
|
|
|
374
391
|
if (!active) {
|
|
375
392
|
this._dollyStart = distance;
|
|
@@ -386,10 +403,10 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
386
403
|
}
|
|
387
404
|
}
|
|
388
405
|
|
|
389
|
-
|
|
406
|
+
const delta = - this._dollyDelta * this._adjustedSettings.zoomSpeed() * (touch ? this._touchAdjustments.zoomSpeed : 1.0);
|
|
390
407
|
|
|
391
|
-
|
|
392
|
-
|
|
408
|
+
const damping = 1 - Math.max(0.01, Math.min(1, this._adjustedSettings.damping()));
|
|
409
|
+
const framesDelta = (Math.log(1 / Math.abs(this._dollyDelta)) - 5 * Math.log(10)) / (Math.log(damping));
|
|
393
410
|
this._damping.zoom.time = 0;
|
|
394
411
|
this._damping.zoom.duration = framesDelta * 16.6666;
|
|
395
412
|
this._damping.zoom.delta = delta;
|
|
@@ -397,7 +414,7 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
397
414
|
this._damping.rotation.duration = 0;
|
|
398
415
|
this._damping.pan.duration = 0;
|
|
399
416
|
|
|
400
|
-
|
|
417
|
+
const offset = this.zoomDistanceToOffset(delta);
|
|
401
418
|
this._controls.applyPositionVector(offset, true);
|
|
402
419
|
}
|
|
403
420
|
}
|
|
@@ -407,12 +424,15 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
407
424
|
// #region Private Methods (3)
|
|
408
425
|
|
|
409
426
|
private panDeltaToOffset(panDelta: vec2): vec3 {
|
|
410
|
-
|
|
411
|
-
|
|
427
|
+
const offset = vec3.create();
|
|
428
|
+
const panOffset = vec3.create();
|
|
429
|
+
|
|
430
|
+
if (!this._controls.canvas) return offset;
|
|
431
|
+
if (this._controls.canvas.clientWidth == 0 || this._controls.canvas.clientHeight == 0) return offset;
|
|
412
432
|
|
|
413
433
|
// perspective
|
|
414
434
|
vec3.subtract(offset, this._controls.getPositionWithManualUpdates(), this._controls.getTargetWithManualUpdates());
|
|
415
|
-
|
|
435
|
+
let targetDistance = vec3.length(offset);
|
|
416
436
|
|
|
417
437
|
// half of the fov is center to top of screen
|
|
418
438
|
targetDistance *= Math.tan((((<PerspectiveCamera>this._controls.camera).fov / 2) * Math.PI) / 180.0);
|
|
@@ -422,13 +442,13 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
422
442
|
const mat = mat4.targetTo(mat4.create(), this._controls.camera.position, this._controls.camera.target, vec3.fromValues(0, 0, 1));
|
|
423
443
|
|
|
424
444
|
const v1 = vec3.fromValues(mat[0], mat[1], mat[2]);
|
|
425
|
-
const scalar1 = -(2 * panDelta[0] * targetDistance);
|
|
445
|
+
const scalar1 = -(2 * panDelta[0] * targetDistance / this._controls.canvas?.clientHeight);
|
|
426
446
|
vec3.multiply(v1, v1, vec3.fromValues(scalar1, scalar1, scalar1));
|
|
427
447
|
vec3.add(panOffset, panOffset, v1);
|
|
428
448
|
|
|
429
449
|
// // up
|
|
430
|
-
const v2 = vec3.fromValues(mat[4], mat[5], mat[6])
|
|
431
|
-
const scalar2 = 2 * panDelta[1] * targetDistance;
|
|
450
|
+
const v2 = vec3.fromValues(mat[4], mat[5], mat[6]);
|
|
451
|
+
const scalar2 = 2 * panDelta[1] * targetDistance / this._controls.canvas?.clientHeight;
|
|
432
452
|
vec3.multiply(v2, v2, vec3.fromValues(scalar2, scalar2, scalar2));
|
|
433
453
|
vec3.add(panOffset, panOffset, v2);
|
|
434
454
|
|
|
@@ -439,13 +459,13 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
439
459
|
let offset = vec3.create();
|
|
440
460
|
vec3.subtract(offset, this._controls.getPositionWithManualUpdates(), this._controls.getTargetWithManualUpdates());
|
|
441
461
|
vec3.transformQuat(offset, offset, this._quat);
|
|
442
|
-
|
|
462
|
+
const spherical = new Spherical().fromVec3(offset);
|
|
443
463
|
|
|
444
464
|
spherical.theta += s.theta;
|
|
445
465
|
spherical.phi += s.phi;
|
|
446
466
|
|
|
447
|
-
|
|
448
|
-
|
|
467
|
+
const minAzimuthAngle = this._controls.rotationRestriction.minAzimuthAngle * (Math.PI / 180),
|
|
468
|
+
maxAzimuthAngle = this._controls.rotationRestriction.maxAzimuthAngle * (Math.PI / 180);
|
|
449
469
|
|
|
450
470
|
if (spherical.theta > Math.PI) {
|
|
451
471
|
spherical.theta -= 2 * Math.PI;
|
|
@@ -462,17 +482,16 @@ export class CameraControlsLogic implements ICameraControlsLogic {
|
|
|
462
482
|
spherical.makeSafe();
|
|
463
483
|
offset = spherical.toVec3();
|
|
464
484
|
offset = vec3.transformQuat(vec3.create(), offset, this._quatInverse);
|
|
465
|
-
offset = vec3.add(vec3.create(), offset, this._controls.getTargetWithManualUpdates())
|
|
485
|
+
offset = vec3.add(vec3.create(), offset, this._controls.getTargetWithManualUpdates());
|
|
466
486
|
offset = vec3.subtract(vec3.create(), offset, this._controls.getPositionWithManualUpdates());
|
|
467
487
|
return vec3.clone(offset);
|
|
468
|
-
|
|
469
488
|
}
|
|
470
489
|
|
|
471
490
|
private zoomDistanceToOffset(distance: number): vec3 {
|
|
472
|
-
|
|
491
|
+
const offset = vec3.create();
|
|
473
492
|
vec3.subtract(offset, this._controls.getPositionWithManualUpdates(), this._controls.getTargetWithManualUpdates());
|
|
474
493
|
return vec3.multiply(vec3.create(), offset, vec3.fromValues(distance, distance, distance));
|
|
475
494
|
}
|
|
476
495
|
|
|
477
496
|
// #endregion Private Methods (3)
|
|
478
|
-
}
|
|
497
|
+
}
|
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-types */
|
|
2
|
+
import { vec2, vec3 } from 'gl-matrix';
|
|
3
|
+
import { ITreeNode, ITreeNodeData } from '@shapediver/viewer.shared.node-tree';
|
|
3
4
|
|
|
4
|
-
import { ICameraControls } from '../controls/ICameraControls'
|
|
5
|
-
import { CAMERA_TYPE } from '../ICameraEngine'
|
|
6
|
-
import { IBox } from '@shapediver/viewer.shared.math'
|
|
7
|
-
import { SettingsEngine } from '@shapediver/viewer.shared.services'
|
|
5
|
+
import { ICameraControls } from '../controls/ICameraControls';
|
|
6
|
+
import { CAMERA_TYPE } from '../ICameraEngine';
|
|
7
|
+
import { IBox } from '@shapediver/viewer.shared.math';
|
|
8
|
+
import { SettingsEngine } from '@shapediver/viewer.shared.services';
|
|
8
9
|
|
|
9
10
|
export interface ICameraOptions {
|
|
11
|
+
// #region Properties (4)
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The coordinate type of the camera interpolation. (default: 'cylindrical')
|
|
15
|
+
*/
|
|
16
|
+
coordinates?: 'spherical' | 'linear' | 'cylindrical';
|
|
17
|
+
/**
|
|
18
|
+
* The duration of the camera movement. (default: cameraMovementDuration set in the settings)
|
|
19
|
+
* When set to 0, the camera is immediately updated to the specified position and target.
|
|
20
|
+
*/
|
|
21
|
+
duration?: number;
|
|
10
22
|
/**
|
|
11
23
|
* The easing type of the camera interpolation. (default: 'Quadratic.InOut')
|
|
12
24
|
*/
|
|
13
|
-
easing?: 'Linear.None' |
|
|
25
|
+
easing?: 'Linear.None' |
|
|
14
26
|
'Quadratic.In' | 'Quadratic.Out' | 'Quadratic.InOut' |
|
|
15
27
|
'Cubic.In' | 'Cubic.Out' | 'Cubic.InOut' |
|
|
16
28
|
'Quartic.In' | 'Quartic.Out' | 'Quartic.InOut' |
|
|
@@ -20,25 +32,17 @@ export interface ICameraOptions {
|
|
|
20
32
|
'Circular.In' | 'Circular.Out' | 'Circular.InOut' |
|
|
21
33
|
'Elastic.In' | 'Elastic.Out' | 'Elastic.InOut' |
|
|
22
34
|
'Back.In' | 'Back.Out' | 'Back.InOut' |
|
|
23
|
-
'Bounce.In' | 'Bounce.Out' | 'Bounce.InOut' |
|
|
24
|
-
Function;
|
|
25
|
-
/**
|
|
26
|
-
* The duration of the camera movement. (default: cameraMovementDuration set in the settings)
|
|
27
|
-
* When set to 0, the camera is immediately updated to the specified position and target.
|
|
28
|
-
*/
|
|
29
|
-
duration?: number;
|
|
30
|
-
/**
|
|
31
|
-
* The coordinate type of the camera interpolation. (default: 'cylindrical')
|
|
32
|
-
*/
|
|
33
|
-
coordinates?: 'spherical' | 'linear' | 'cylindrical';
|
|
35
|
+
'Bounce.In' | 'Bounce.Out' | 'Bounce.InOut' | Function;
|
|
34
36
|
/**
|
|
35
37
|
* The interpolation type of the camera interpolation. (default: 'CatmullRom')
|
|
36
38
|
*/
|
|
37
39
|
interpolation?: 'Linear' | 'Bezier' | 'CatmullRom' | Function
|
|
40
|
+
|
|
41
|
+
// #endregion Properties (4)
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
export interface ICamera extends ITreeNodeData {
|
|
41
|
-
// #region Properties (
|
|
45
|
+
// #region Properties (20)
|
|
42
46
|
|
|
43
47
|
readonly controls: ICameraControls;
|
|
44
48
|
readonly id: string;
|
|
@@ -51,28 +55,29 @@ export interface ICamera extends ITreeNodeData {
|
|
|
51
55
|
defaultPosition: vec3;
|
|
52
56
|
defaultTarget: vec3;
|
|
53
57
|
enableCameraControls: boolean;
|
|
54
|
-
position: vec3;
|
|
55
58
|
name?: string;
|
|
56
59
|
node?: ITreeNode;
|
|
57
60
|
order?: number;
|
|
61
|
+
position: vec3;
|
|
58
62
|
revertAtMouseUp: boolean;
|
|
59
63
|
revertAtMouseUpDuration: number;
|
|
64
|
+
sceneRotation: vec2;
|
|
60
65
|
target: vec3;
|
|
61
66
|
useNodeData: boolean;
|
|
62
67
|
zoomExtentsFactor: number;
|
|
63
68
|
|
|
64
|
-
// #endregion Properties (
|
|
69
|
+
// #endregion Properties (20)
|
|
65
70
|
|
|
66
|
-
// #region Public Methods (
|
|
71
|
+
// #region Public Methods (8)
|
|
67
72
|
|
|
68
73
|
animate(path: { position: vec3, target: vec3 }[], options?: ICameraOptions): Promise<boolean>;
|
|
69
74
|
applySettings(settingsEngine: SettingsEngine): void;
|
|
70
|
-
reset(options?: ICameraOptions): Promise<boolean>;
|
|
71
|
-
set(position: vec3, target: vec3, options?: ICameraOptions): Promise<boolean>;
|
|
72
|
-
zoomTo(zoomTarget?: IBox, options?: ICameraOptions): Promise<boolean>;
|
|
73
75
|
calculateZoomTo(zoomTarget?: IBox, startingPosition?: vec3, startingTarget?: vec3): { position: vec3; target: vec3; };
|
|
74
76
|
project(p: vec3): vec2;
|
|
77
|
+
reset(options?: ICameraOptions): Promise<boolean>;
|
|
78
|
+
set(position: vec3, target: vec3, options?: ICameraOptions): Promise<boolean>;
|
|
75
79
|
unproject(p: vec3): vec3;
|
|
80
|
+
zoomTo(zoomTarget?: IBox, options?: ICameraOptions): Promise<boolean>;
|
|
76
81
|
|
|
77
|
-
// #endregion Public Methods (
|
|
82
|
+
// #endregion Public Methods (8)
|
|
78
83
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { mat4, vec3 } from
|
|
2
|
-
import { ICamera, ICameraOptions } from
|
|
3
|
-
import { ICameraControlsEventDistribution } from
|
|
1
|
+
import { mat4, vec2, vec3 } from 'gl-matrix';
|
|
2
|
+
import { ICamera, ICameraOptions } from '../camera/ICamera';
|
|
3
|
+
import { ICameraControlsEventDistribution } from './ICameraControlsEventDistribution';
|
|
4
4
|
|
|
5
5
|
export interface ICameraControls {
|
|
6
6
|
// #region Properties (6)
|
|
@@ -23,7 +23,7 @@ export interface ICameraControls {
|
|
|
23
23
|
applyTargetMatrix(matrix: mat4, manualInteraction?: boolean | undefined): void;
|
|
24
24
|
applyTargetVector(vector: vec3, manualInteraction?: boolean | undefined): void;
|
|
25
25
|
applyUpMatrix(matrix: mat4, manualInteraction?: boolean | undefined): void;
|
|
26
|
-
assignViewer(viewportId: string, canvas: HTMLCanvasElement):void;
|
|
26
|
+
assignViewer(viewportId: string, canvas: HTMLCanvasElement): void;
|
|
27
27
|
getPositionWithManualUpdates(): vec3;
|
|
28
28
|
getPositionWithUpdates(): vec3;
|
|
29
29
|
getTargetWithManualUpdates(): vec3;
|
|
@@ -31,7 +31,7 @@ export interface ICameraControls {
|
|
|
31
31
|
isMoving(): boolean;
|
|
32
32
|
isWithinRestrictions(position: vec3, target: vec3): boolean;
|
|
33
33
|
reset(): void;
|
|
34
|
-
update(time: number): { position: vec3, target: vec3 };
|
|
34
|
+
update(time: number): { position: vec3, target: vec3, sceneRotation: vec2 };
|
|
35
35
|
|
|
36
36
|
// #endregion Public Methods (15)
|
|
37
37
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { vec3 } from 'gl-matrix'
|
|
1
|
+
import { vec2, vec3 } from 'gl-matrix';
|
|
2
2
|
|
|
3
3
|
export interface ICameraControlsLogic {
|
|
4
|
+
// #region Public Methods (4)
|
|
5
|
+
|
|
4
6
|
isWithinRestrictions(position: any, target: any): boolean;
|
|
5
7
|
reset(): void;
|
|
6
|
-
restrict(p: vec3, t: vec3): { position: vec3, target: vec3 };
|
|
8
|
+
restrict(p: vec3, t: vec3, s?: vec2): { position: vec3, target: vec3, sceneRotation?: vec2 };
|
|
7
9
|
update(time: number, manualInteraction: boolean): void
|
|
10
|
+
|
|
11
|
+
// #endregion Public Methods (4)
|
|
8
12
|
}
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import { vec3 } from 'gl-matrix'
|
|
1
|
+
import { vec3 } from 'gl-matrix';
|
|
2
2
|
|
|
3
|
-
import { ICameraControls } from './ICameraControls'
|
|
3
|
+
import { ICameraControls } from './ICameraControls';
|
|
4
4
|
|
|
5
5
|
export interface IPerspectiveCameraControls extends ICameraControls {
|
|
6
|
+
// #region Properties (23)
|
|
7
|
+
|
|
6
8
|
autoRotationSpeed: number;
|
|
7
9
|
cubePositionRestriction: { min: vec3, max: vec3 };
|
|
8
10
|
cubeTargetRestriction: { min: vec3, max: vec3 };
|
|
9
11
|
damping: number;
|
|
10
12
|
enableAutoRotation: boolean;
|
|
13
|
+
enableAzimuthRotation: boolean;
|
|
11
14
|
enableKeyPan: boolean;
|
|
12
15
|
enablePan: boolean;
|
|
16
|
+
enablePolarRotation: boolean;
|
|
13
17
|
enableRotation: boolean;
|
|
18
|
+
enableTurntableControls: boolean;
|
|
14
19
|
enableZoom: boolean;
|
|
15
20
|
input: { keys: { up: number, down: number, left: number, right: number }, mouse: { rotate: number, zoom: number, pan: number }, touch: { rotate: number, zoom: number, pan: number } };
|
|
16
21
|
keyPanSpeed: number;
|
|
@@ -20,6 +25,9 @@ export interface IPerspectiveCameraControls extends ICameraControls {
|
|
|
20
25
|
rotationSpeed: number;
|
|
21
26
|
spherePositionRestriction: { center: vec3, radius: number };
|
|
22
27
|
sphereTargetRestriction: { center: vec3, radius: number };
|
|
28
|
+
turntableCenter: vec3;
|
|
23
29
|
zoomRestriction: { minDistance: number, maxDistance: number };
|
|
24
30
|
zoomSpeed: number;
|
|
31
|
+
|
|
32
|
+
// #endregion Properties (23)
|
|
25
33
|
}
|