@shapediver/viewer.rendering-engine.camera-engine 3.3.3 → 3.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -10
- package/src/implementation/CameraEngine.ts +0 -386
- package/src/implementation/camera/AbstractCamera.ts +0 -324
- package/src/implementation/camera/OrthographicCamera.ts +0 -282
- package/src/implementation/camera/PerspectiveCamera.ts +0 -250
- package/src/implementation/controls/AbstractCameraControls.ts +0 -660
- package/src/implementation/controls/CameraControlsEventDistribution.ts +0 -289
- package/src/implementation/controls/CameraControlsLogic.ts +0 -534
- package/src/implementation/controls/OrthographicCameraControls.ts +0 -36
- package/src/implementation/controls/PerspectiveCameraControls.ts +0 -37
- package/src/implementation/interpolation/CameraInterpolationManager.ts +0 -149
- package/src/implementation/interpolation/interpolationMethods/CameraCylindricalInterpolation.ts +0 -83
- package/src/implementation/interpolation/interpolationMethods/CameraLinearInterpolation.ts +0 -41
- package/src/implementation/interpolation/interpolationMethods/CameraMultipleInterpolation.ts +0 -61
- package/src/implementation/interpolation/interpolationMethods/CameraOrthographicInterpolation.ts +0 -41
- package/src/implementation/interpolation/interpolationMethods/CameraSphericalInterpolation.ts +0 -65
- package/src/index.ts +0 -28
- package/src/interfaces/ICameraEngine.ts +0 -33
- package/src/interfaces/camera/ICamera.ts +0 -88
- package/src/interfaces/camera/IOrthographicCamera.ts +0 -36
- package/src/interfaces/camera/IPerspectiveCamera.ts +0 -18
- package/src/interfaces/controls/ICameraControls.ts +0 -80
- package/src/interfaces/controls/ICameraControlsEventDistribution.ts +0 -11
- package/src/interfaces/controls/ICameraControlsLogic.ts +0 -15
- package/src/interfaces/interpolation/ICameraInterpolation.ts +0 -9
- package/tsconfig.json +0 -17
|
@@ -1,534 +0,0 @@
|
|
|
1
|
-
import { Box, Sphere, Spherical } from '@shapediver/viewer.shared.math';
|
|
2
|
-
import { Adjustments, ICameraControls } from '../../interfaces/controls/ICameraControls';
|
|
3
|
-
import { ICameraControlsLogic } from '../../interfaces/controls/ICameraControlsLogic';
|
|
4
|
-
import {
|
|
5
|
-
mat4,
|
|
6
|
-
quat,
|
|
7
|
-
vec2,
|
|
8
|
-
vec3
|
|
9
|
-
} from 'gl-matrix';
|
|
10
|
-
import { OrthographicCamera } from '../camera/OrthographicCamera';
|
|
11
|
-
import { PerspectiveCamera } from '../camera/PerspectiveCamera';
|
|
12
|
-
import { CAMERA_TYPE } from '../../interfaces/ICameraEngine';
|
|
13
|
-
import { ORTHOGRAPHIC_CAMERA_DIRECTION } from '../../interfaces/camera/IOrthographicCamera';
|
|
14
|
-
|
|
15
|
-
export class CameraControlsLogic implements ICameraControlsLogic {
|
|
16
|
-
// #region Properties (13)
|
|
17
|
-
|
|
18
|
-
private _adjustedSettings = {
|
|
19
|
-
autoRotationSpeed: () => this._controls.autoRotationSpeed * this._settingsAdjustments.autoRotationSpeed,
|
|
20
|
-
damping: () => this._controls.damping * this._settingsAdjustments.damping,
|
|
21
|
-
movementSmoothness: () => this._controls.movementSmoothness * this._settingsAdjustments.movementSmoothness,
|
|
22
|
-
panSpeed: () => this._controls.panSpeed * this._settingsAdjustments.panSpeed,
|
|
23
|
-
rotationSpeed: () => this._controls.rotationSpeed * this._settingsAdjustments.rotationSpeed,
|
|
24
|
-
zoomSpeed: () => this._controls.zoomSpeed * this._settingsAdjustments.zoomSpeed,
|
|
25
|
-
};
|
|
26
|
-
private _damping = {
|
|
27
|
-
rotation: {
|
|
28
|
-
time: 0,
|
|
29
|
-
duration: 0,
|
|
30
|
-
theta: 0,
|
|
31
|
-
phi: 0
|
|
32
|
-
},
|
|
33
|
-
zoom: {
|
|
34
|
-
time: 0,
|
|
35
|
-
duration: 0,
|
|
36
|
-
delta: 0
|
|
37
|
-
},
|
|
38
|
-
pan: {
|
|
39
|
-
time: 0,
|
|
40
|
-
duration: 0,
|
|
41
|
-
offset: vec3.create()
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
private _dollyDelta = 0;
|
|
45
|
-
private _dollyEnd = 0;
|
|
46
|
-
private _dollyStart = 0;
|
|
47
|
-
private _panDelta = vec2.create();
|
|
48
|
-
private _panEnd = vec2.create();
|
|
49
|
-
private _panStart = vec2.create();
|
|
50
|
-
private _quat: quat;
|
|
51
|
-
private _quatInverse: quat;
|
|
52
|
-
private _rotateDelta = vec2.create();
|
|
53
|
-
private _rotateEnd = vec2.create();
|
|
54
|
-
private _rotateStart = vec2.create();
|
|
55
|
-
|
|
56
|
-
// #endregion Properties (13)
|
|
57
|
-
|
|
58
|
-
// #region Constructors (1)
|
|
59
|
-
|
|
60
|
-
constructor(private readonly _controls: ICameraControls, private readonly _settingsAdjustments: Adjustments, private readonly _touchAdjustments: Adjustments) {
|
|
61
|
-
this._quat = quat.fromValues(-Math.sin(Math.PI / 4), 0, 0, Math.sin(Math.PI / 4));
|
|
62
|
-
this._quatInverse = quat.fromValues(Math.sin(Math.PI / 4), 0, 0, Math.sin(Math.PI / 4));
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// #endregion Constructors (1)
|
|
66
|
-
|
|
67
|
-
// #region Public Methods (7)
|
|
68
|
-
|
|
69
|
-
public isWithinRestrictions(position: vec3, target: vec3): boolean {
|
|
70
|
-
const pBox = new Box(this._controls.cubePositionRestriction.min, this._controls.cubePositionRestriction.max),
|
|
71
|
-
pSphere = new Sphere(this._controls.spherePositionRestriction.center, this._controls.spherePositionRestriction.radius),
|
|
72
|
-
tBox = new Box(this._controls.cubeTargetRestriction.min, this._controls.cubeTargetRestriction.max),
|
|
73
|
-
tSphere = new Sphere(this._controls.sphereTargetRestriction.center, this._controls.sphereTargetRestriction.radius);
|
|
74
|
-
|
|
75
|
-
if (!(pBox.containsPoint(position) && pSphere.containsPoint(position))) return false;
|
|
76
|
-
if (!(tBox.containsPoint(target) && tSphere.containsPoint(target))) return false;
|
|
77
|
-
|
|
78
|
-
const currentDistance = vec3.distance(position, target);
|
|
79
|
-
if (currentDistance > this._controls.zoomRestriction.maxDistance || currentDistance < this._controls.zoomRestriction.minDistance) return false;
|
|
80
|
-
|
|
81
|
-
const minPolarAngle = this._controls.rotationRestriction.minPolarAngle * (Math.PI / 180),
|
|
82
|
-
maxPolarAngle = this._controls.rotationRestriction.maxPolarAngle * (Math.PI / 180),
|
|
83
|
-
minAzimuthAngle = this._controls.rotationRestriction.minAzimuthAngle * (Math.PI / 180),
|
|
84
|
-
maxAzimuthAngle = this._controls.rotationRestriction.maxAzimuthAngle * (Math.PI / 180);
|
|
85
|
-
|
|
86
|
-
if (minAzimuthAngle !== -Infinity ||
|
|
87
|
-
maxAzimuthAngle !== Infinity ||
|
|
88
|
-
minPolarAngle !== 0 ||
|
|
89
|
-
maxPolarAngle !== 180) {
|
|
90
|
-
const offset = vec3.sub(vec3.create(), position, target);
|
|
91
|
-
vec3.transformQuat(offset, offset, this._quat);
|
|
92
|
-
const spherical = new Spherical().fromVec3(offset);
|
|
93
|
-
|
|
94
|
-
if (spherical.theta < minAzimuthAngle ||
|
|
95
|
-
spherical.theta > maxAzimuthAngle ||
|
|
96
|
-
spherical.phi < minPolarAngle ||
|
|
97
|
-
spherical.phi > maxPolarAngle) {
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return true;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
public pan(x: number, y: number, active: boolean, touch: boolean): void {
|
|
106
|
-
if (!active) {
|
|
107
|
-
this._panStart = vec2.fromValues(x, y);
|
|
108
|
-
} else {
|
|
109
|
-
this._panEnd = vec2.fromValues(x, y);
|
|
110
|
-
vec2.sub(this._panDelta, this._panEnd, this._panStart);
|
|
111
|
-
if (this._panDelta[0] === 0 && this._panDelta[1] === 0) return;
|
|
112
|
-
vec2.copy(this._panStart, this._panEnd);
|
|
113
|
-
|
|
114
|
-
const adjustedPanSpeed = this._adjustedSettings.panSpeed() * (touch ? this._touchAdjustments.panSpeed : 1.0);
|
|
115
|
-
const offset = this.panDeltaToOffset(vec2.mul(vec2.create(), this._panDelta, vec2.fromValues(adjustedPanSpeed, adjustedPanSpeed)));
|
|
116
|
-
|
|
117
|
-
if (this._damping.pan.duration > 0) {
|
|
118
|
-
if (offset[0] < 0) {
|
|
119
|
-
offset[0] = Math.min(offset[0], this._adjustedSettings.movementSmoothness() * this._damping.pan.offset[0]);
|
|
120
|
-
} else {
|
|
121
|
-
offset[0] = Math.max(offset[0], this._adjustedSettings.movementSmoothness() * this._damping.pan.offset[0]);
|
|
122
|
-
}
|
|
123
|
-
if (offset[1] < 0) {
|
|
124
|
-
offset[1] = Math.min(offset[1], this._adjustedSettings.movementSmoothness() * this._damping.pan.offset[1]);
|
|
125
|
-
} else {
|
|
126
|
-
offset[1] = Math.max(offset[1], this._adjustedSettings.movementSmoothness() * this._damping.pan.offset[1]);
|
|
127
|
-
}
|
|
128
|
-
if (offset[2] < 0) {
|
|
129
|
-
offset[2] = Math.min(offset[2], this._adjustedSettings.movementSmoothness() * this._damping.pan.offset[2]);
|
|
130
|
-
} else {
|
|
131
|
-
offset[2] = Math.max(offset[2], this._adjustedSettings.movementSmoothness() * this._damping.pan.offset[2]);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const damping = 1 - Math.max(0.01, Math.min(0.99, this._adjustedSettings.damping()));
|
|
136
|
-
|
|
137
|
-
const framesOffsetX = (Math.log(1 / Math.abs(offset[0])) - 5 * Math.log(10)) / (Math.log(damping));
|
|
138
|
-
const framesOffsetY = (Math.log(1 / Math.abs(offset[1])) - 5 * Math.log(10)) / (Math.log(damping));
|
|
139
|
-
const framesOffsetZ = (Math.log(1 / Math.abs(offset[2])) - 5 * Math.log(10)) / (Math.log(damping));
|
|
140
|
-
this._damping.pan.time = 0;
|
|
141
|
-
this._damping.pan.duration = Math.max(framesOffsetX, Math.max(framesOffsetY, framesOffsetZ)) * 16.6666;
|
|
142
|
-
this._damping.pan.offset = vec3.clone(offset);
|
|
143
|
-
|
|
144
|
-
this._damping.rotation.duration = 0;
|
|
145
|
-
this._damping.zoom.duration = 0;
|
|
146
|
-
|
|
147
|
-
this._controls.applyTargetVector(offset, true);
|
|
148
|
-
this._controls.applyPositionVector(offset, true);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
public reset() {
|
|
153
|
-
this._damping = {
|
|
154
|
-
rotation: {
|
|
155
|
-
time: 0,
|
|
156
|
-
duration: 0,
|
|
157
|
-
theta: 0,
|
|
158
|
-
phi: 0
|
|
159
|
-
},
|
|
160
|
-
zoom: {
|
|
161
|
-
time: 0,
|
|
162
|
-
duration: 0,
|
|
163
|
-
delta: 0
|
|
164
|
-
},
|
|
165
|
-
pan: {
|
|
166
|
-
time: 0,
|
|
167
|
-
duration: 0,
|
|
168
|
-
offset: vec3.create()
|
|
169
|
-
},
|
|
170
|
-
};
|
|
171
|
-
this._dollyDelta = 0;
|
|
172
|
-
this._dollyEnd = 0;
|
|
173
|
-
this._dollyStart = 0;
|
|
174
|
-
this._panDelta = vec2.create();
|
|
175
|
-
this._panEnd = vec2.create();
|
|
176
|
-
this._panStart = vec2.create();
|
|
177
|
-
this._rotateDelta = vec2.create();
|
|
178
|
-
this._rotateEnd = vec2.create();
|
|
179
|
-
this._rotateStart = vec2.create();
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
public restrict(position: vec3, target: vec3, sceneRotation: vec2): { position: vec3, target: vec3, sceneRotation: vec2 } {
|
|
183
|
-
const pBox = new Box(this._controls.cubePositionRestriction.min, this._controls.cubePositionRestriction.max),
|
|
184
|
-
pSphere = new Sphere(this._controls.spherePositionRestriction.center, this._controls.spherePositionRestriction.radius),
|
|
185
|
-
tBox = new Box(this._controls.cubeTargetRestriction.min, this._controls.cubeTargetRestriction.max),
|
|
186
|
-
tSphere = new Sphere(this._controls.sphereTargetRestriction.center, this._controls.sphereTargetRestriction.radius);
|
|
187
|
-
|
|
188
|
-
if (!pBox.containsPoint(position))
|
|
189
|
-
position = pBox.clampPoint(position);
|
|
190
|
-
|
|
191
|
-
if (!pSphere.containsPoint(position))
|
|
192
|
-
position = pSphere.clampPoint(position);
|
|
193
|
-
|
|
194
|
-
if (!tBox.containsPoint(target))
|
|
195
|
-
target = tBox.clampPoint(target);
|
|
196
|
-
|
|
197
|
-
if (!tSphere.containsPoint(target))
|
|
198
|
-
target = tSphere.clampPoint(target);
|
|
199
|
-
|
|
200
|
-
// zoom restrictions
|
|
201
|
-
const currentDistance = vec3.distance(position, target);
|
|
202
|
-
if (currentDistance > this._controls.zoomRestriction.maxDistance || currentDistance < this._controls.zoomRestriction.minDistance) {
|
|
203
|
-
const direction = vec3.normalize(vec3.create(), vec3.subtract(vec3.create(), position, target));
|
|
204
|
-
const distance = Math.max(this._controls.zoomRestriction.minDistance, Math.min(this._controls.zoomRestriction.maxDistance, currentDistance));
|
|
205
|
-
vec3.add(position, vec3.multiply(position, direction, vec3.fromValues(distance, distance, distance)), target);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// angle restrictions
|
|
209
|
-
const minPolarAngle = this._controls.rotationRestriction.minPolarAngle * (Math.PI / 180),
|
|
210
|
-
maxPolarAngle = this._controls.rotationRestriction.maxPolarAngle * (Math.PI / 180),
|
|
211
|
-
minAzimuthAngle = this._controls.rotationRestriction.minAzimuthAngle * (Math.PI / 180),
|
|
212
|
-
maxAzimuthAngle = this._controls.rotationRestriction.maxAzimuthAngle * (Math.PI / 180);
|
|
213
|
-
|
|
214
|
-
if (minAzimuthAngle !== -Infinity ||
|
|
215
|
-
maxAzimuthAngle !== Infinity ||
|
|
216
|
-
minPolarAngle !== 0 ||
|
|
217
|
-
maxPolarAngle !== 180 ||
|
|
218
|
-
this._controls.enableAzimuthRotation === false ||
|
|
219
|
-
this._controls.enablePolarRotation === false ||
|
|
220
|
-
this._controls.enableObjectControls === true
|
|
221
|
-
) {
|
|
222
|
-
let offset = vec3.subtract(vec3.create(), position, target);
|
|
223
|
-
vec3.transformQuat(offset, offset, this._quat);
|
|
224
|
-
|
|
225
|
-
const spherical = new Spherical().fromVec3(offset);
|
|
226
|
-
|
|
227
|
-
if (spherical.theta < minAzimuthAngle ||
|
|
228
|
-
spherical.theta > maxAzimuthAngle ||
|
|
229
|
-
spherical.phi < minPolarAngle ||
|
|
230
|
-
spherical.phi > maxPolarAngle ||
|
|
231
|
-
this._controls.enableAzimuthRotation === false ||
|
|
232
|
-
this._controls.enablePolarRotation === false ||
|
|
233
|
-
this._controls.enableObjectControls === true
|
|
234
|
-
) {
|
|
235
|
-
spherical.theta = Math.max(minAzimuthAngle, Math.min(maxAzimuthAngle, spherical.theta));
|
|
236
|
-
spherical.phi = Math.max(minPolarAngle, Math.min(maxPolarAngle, spherical.phi));
|
|
237
|
-
|
|
238
|
-
if (this._controls.enableAzimuthRotation === false || this._controls.enablePolarRotation === false || this._controls.enableObjectControls === true) {
|
|
239
|
-
const defaultOffset = vec3.subtract(vec3.create(), this._controls.camera.defaultPosition, this._controls.camera.defaultTarget);
|
|
240
|
-
vec3.transformQuat(defaultOffset, defaultOffset, this._quat);
|
|
241
|
-
|
|
242
|
-
const defaultSpherical = new Spherical().fromVec3(defaultOffset);
|
|
243
|
-
if (this._controls.enableAzimuthRotation === false) spherical.theta = defaultSpherical.theta;
|
|
244
|
-
if (this._controls.enablePolarRotation === false) spherical.phi = defaultSpherical.phi;
|
|
245
|
-
|
|
246
|
-
if(this._controls.enableObjectControls) {
|
|
247
|
-
spherical.theta = defaultSpherical.theta;
|
|
248
|
-
spherical.phi = defaultSpherical.phi;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
spherical.makeSafe();
|
|
253
|
-
offset = spherical.toVec3();
|
|
254
|
-
vec3.transformQuat(offset, offset, this._quatInverse);
|
|
255
|
-
vec3.add(position, offset, target);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
if ((sceneRotation[1] < minAzimuthAngle ||
|
|
259
|
-
sceneRotation[1] > maxAzimuthAngle ||
|
|
260
|
-
sceneRotation[0] < minPolarAngle ||
|
|
261
|
-
sceneRotation[0] > maxPolarAngle ||
|
|
262
|
-
this._controls.enableAzimuthRotation === false ||
|
|
263
|
-
this._controls.enablePolarRotation === false) &&
|
|
264
|
-
this._controls.enableObjectControls === false
|
|
265
|
-
) {
|
|
266
|
-
sceneRotation[1] = this._controls.enableAzimuthRotation === false ? 0 : Math.max(minAzimuthAngle, Math.min(maxAzimuthAngle, sceneRotation[1]));
|
|
267
|
-
sceneRotation[0] = this._controls.enablePolarRotation === false ? 0 : Math.max(minPolarAngle, Math.min(maxPolarAngle, sceneRotation[0]));
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return { position, target, sceneRotation };
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
public rotate(x: number, y: number, active: boolean, touch: boolean): void {
|
|
275
|
-
if (this._controls.camera.type === CAMERA_TYPE.ORTHOGRAPHIC && (this._controls.camera as OrthographicCamera).direction !== ORTHOGRAPHIC_CAMERA_DIRECTION.CUSTOM) return;
|
|
276
|
-
|
|
277
|
-
if (!active) {
|
|
278
|
-
this._rotateStart = vec2.fromValues(x, y);
|
|
279
|
-
} else {
|
|
280
|
-
this._rotateEnd = vec2.fromValues(x, y);
|
|
281
|
-
vec2.subtract(this._rotateDelta, this._rotateEnd, this._rotateStart);
|
|
282
|
-
vec2.copy(this._rotateStart, this._rotateEnd);
|
|
283
|
-
|
|
284
|
-
if (!this._controls.canvas) return;
|
|
285
|
-
if (this._controls.canvas.clientWidth == 0 || this._controls.canvas.clientHeight == 0) return;
|
|
286
|
-
|
|
287
|
-
const spherical = new Spherical();
|
|
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;
|
|
291
|
-
|
|
292
|
-
if (this._damping.rotation.duration > 0) {
|
|
293
|
-
const thetaDelta = this._damping.rotation.theta - spherical.theta;
|
|
294
|
-
spherical.theta += thetaDelta * this._adjustedSettings.movementSmoothness();
|
|
295
|
-
|
|
296
|
-
const phiDelta = this._damping.rotation.phi - spherical.phi;
|
|
297
|
-
spherical.phi += phiDelta * this._adjustedSettings.movementSmoothness();
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
let sphericalForOffset = spherical;
|
|
301
|
-
if(this._controls.enableTurntableControls)
|
|
302
|
-
sphericalForOffset = new Spherical(1.0, spherical.phi, 0);
|
|
303
|
-
|
|
304
|
-
const offset = this.rotationSphericalToOffset(sphericalForOffset);
|
|
305
|
-
|
|
306
|
-
const damping = 1 - Math.max(0.01, Math.min(1, this._adjustedSettings.damping()));
|
|
307
|
-
const framesTheta = (Math.log(1 / Math.abs(spherical.theta)) - 5 * Math.log(10)) / (Math.log(damping));
|
|
308
|
-
const framesPhi = (Math.log(1 / Math.abs(spherical.phi)) - 5 * Math.log(10)) / (Math.log(damping));
|
|
309
|
-
|
|
310
|
-
this._damping.rotation.time = 0;
|
|
311
|
-
this._damping.rotation.duration = Math.max(framesTheta, framesPhi) * 16.6666;
|
|
312
|
-
this._damping.rotation.theta = spherical.theta;
|
|
313
|
-
this._damping.rotation.phi = spherical.phi;
|
|
314
|
-
|
|
315
|
-
this._damping.pan.duration = 0;
|
|
316
|
-
this._damping.zoom.duration = 0;
|
|
317
|
-
|
|
318
|
-
this._controls.applyPositionVector(offset, true);
|
|
319
|
-
|
|
320
|
-
if (this._controls.enableTurntableControls) this._controls.applyRotation([0, spherical.theta], true);
|
|
321
|
-
if (this._controls.enableObjectControls) this._controls.applyRotation([spherical.phi, spherical.theta], true);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
public update(time: number, manualInteraction: boolean): void {
|
|
326
|
-
if (manualInteraction === true) {
|
|
327
|
-
this._damping.zoom.duration = 0;
|
|
328
|
-
this._damping.pan.duration = 0;
|
|
329
|
-
this._damping.rotation.duration = 0;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const damping = 1 - Math.max(0.01, Math.min(1, this._adjustedSettings.damping()));
|
|
333
|
-
|
|
334
|
-
if (this._damping.pan.duration > 0) {
|
|
335
|
-
if (this._damping.pan.time + time > this._damping.pan.duration) {
|
|
336
|
-
this._damping.pan.time = this._damping.pan.duration;
|
|
337
|
-
this._damping.pan.duration = 0;
|
|
338
|
-
} else {
|
|
339
|
-
this._damping.pan.time += time;
|
|
340
|
-
|
|
341
|
-
const frameSinceStart = this._damping.pan.time / 16.6666;
|
|
342
|
-
const dampingFrames = Math.pow(damping, frameSinceStart);
|
|
343
|
-
const offset = vec3.multiply(vec3.create(), this._damping.pan.offset, vec3.fromValues(dampingFrames, dampingFrames, dampingFrames));
|
|
344
|
-
this._controls.applyTargetVector(offset);
|
|
345
|
-
this._controls.applyPositionVector(offset);
|
|
346
|
-
}
|
|
347
|
-
} else {
|
|
348
|
-
this._damping.pan.time = 0;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
if (this._damping.rotation.duration > 0) {
|
|
352
|
-
if (this._damping.rotation.time + time > this._damping.rotation.duration) {
|
|
353
|
-
this._damping.rotation.time = this._damping.rotation.duration;
|
|
354
|
-
this._damping.rotation.duration = 0;
|
|
355
|
-
} else {
|
|
356
|
-
this._damping.rotation.time += time;
|
|
357
|
-
|
|
358
|
-
const frameSinceStart = this._damping.rotation.time / 16.6666;
|
|
359
|
-
const spherical = new Spherical();
|
|
360
|
-
spherical.theta = this._damping.rotation.theta * Math.pow(damping, frameSinceStart);
|
|
361
|
-
spherical.phi = this._damping.rotation.phi * Math.pow(damping, frameSinceStart);
|
|
362
|
-
|
|
363
|
-
let sphericalForOffset = spherical;
|
|
364
|
-
if(this._controls.enableTurntableControls)
|
|
365
|
-
sphericalForOffset = new Spherical(1.0, spherical.phi, 0);
|
|
366
|
-
|
|
367
|
-
const offset = this.rotationSphericalToOffset(sphericalForOffset);
|
|
368
|
-
this._controls.applyPositionVector(offset);
|
|
369
|
-
|
|
370
|
-
if (this._controls.enableTurntableControls) this._controls.applyRotation([0, spherical.theta]);
|
|
371
|
-
if (this._controls.enableObjectControls) this._controls.applyRotation([spherical.phi, spherical.theta]);
|
|
372
|
-
}
|
|
373
|
-
} else {
|
|
374
|
-
this._damping.rotation.time = 0;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (this._damping.zoom.duration > 0) {
|
|
378
|
-
if (this._damping.zoom.time + time > this._damping.zoom.duration) {
|
|
379
|
-
this._damping.zoom.time = this._damping.zoom.duration;
|
|
380
|
-
this._damping.zoom.duration = 0;
|
|
381
|
-
} else {
|
|
382
|
-
this._damping.zoom.time += time;
|
|
383
|
-
|
|
384
|
-
const frameSinceStart = this._damping.zoom.time / 16.6666;
|
|
385
|
-
const delta = this._damping.zoom.delta * Math.pow(damping, frameSinceStart);
|
|
386
|
-
const offset = this.zoomDistanceToOffset(delta);
|
|
387
|
-
this._controls.applyPositionVector(offset);
|
|
388
|
-
}
|
|
389
|
-
} else {
|
|
390
|
-
this._damping.zoom.time = 0;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
if (this._controls.enableAutoRotation) {
|
|
394
|
-
const spherical = new Spherical(1.0, 0.0, -this._adjustedSettings.autoRotationSpeed());
|
|
395
|
-
|
|
396
|
-
let sphericalForOffset = spherical;
|
|
397
|
-
if(this._controls.enableTurntableControls)
|
|
398
|
-
sphericalForOffset = new Spherical(1.0, spherical.phi, 0);
|
|
399
|
-
const offset = this.rotationSphericalToOffset(sphericalForOffset);
|
|
400
|
-
|
|
401
|
-
this._controls.applyPositionVector(offset);
|
|
402
|
-
if (this._controls.enableTurntableControls) this._controls.applyRotation([0, spherical.theta]);
|
|
403
|
-
if (this._controls.enableObjectControls) this._controls.applyRotation([spherical.phi, spherical.theta]);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
public zoom(x: number, y: number, active: boolean, touch: boolean): void {
|
|
408
|
-
const distance = Math.sqrt(x * x + y * y);
|
|
409
|
-
|
|
410
|
-
if (!active) {
|
|
411
|
-
this._dollyStart = distance;
|
|
412
|
-
} else {
|
|
413
|
-
this._dollyEnd = distance;
|
|
414
|
-
this._dollyDelta = this._dollyEnd - this._dollyStart;
|
|
415
|
-
this._dollyStart = this._dollyEnd;
|
|
416
|
-
|
|
417
|
-
if (this._damping.zoom.duration > 0) {
|
|
418
|
-
if (this._dollyDelta < 0) {
|
|
419
|
-
this._dollyDelta = Math.min(this._dollyDelta, this._adjustedSettings.movementSmoothness() * this._damping.zoom.delta);
|
|
420
|
-
} else {
|
|
421
|
-
this._dollyDelta = Math.max(this._dollyDelta, this._adjustedSettings.movementSmoothness() * this._damping.zoom.delta);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
const delta = - this._dollyDelta * this._adjustedSettings.zoomSpeed() * (touch ? this._touchAdjustments.zoomSpeed : 1.0);
|
|
426
|
-
|
|
427
|
-
const damping = 1 - Math.max(0.01, Math.min(1, this._adjustedSettings.damping()));
|
|
428
|
-
const framesDelta = (Math.log(1 / Math.abs(this._dollyDelta)) - 5 * Math.log(10)) / (Math.log(damping));
|
|
429
|
-
this._damping.zoom.time = 0;
|
|
430
|
-
this._damping.zoom.duration = framesDelta * 16.6666;
|
|
431
|
-
this._damping.zoom.delta = delta;
|
|
432
|
-
|
|
433
|
-
this._damping.rotation.duration = 0;
|
|
434
|
-
this._damping.pan.duration = 0;
|
|
435
|
-
|
|
436
|
-
const offset = this.zoomDistanceToOffset(delta);
|
|
437
|
-
this._controls.applyPositionVector(offset, true);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// #endregion Public Methods (7)
|
|
442
|
-
|
|
443
|
-
// #region Private Methods (3)
|
|
444
|
-
|
|
445
|
-
private panDeltaToOffset(panDelta: vec2): vec3 {
|
|
446
|
-
const offset = vec3.create();
|
|
447
|
-
const panOffset = vec3.create();
|
|
448
|
-
|
|
449
|
-
if (!this._controls.canvas) return offset;
|
|
450
|
-
if (this._controls.canvas.clientWidth == 0 || this._controls.canvas.clientHeight == 0) return offset;
|
|
451
|
-
|
|
452
|
-
// perspective
|
|
453
|
-
vec3.subtract(offset, this._controls.getPositionWithManualUpdates(), this._controls.getTargetWithManualUpdates());
|
|
454
|
-
if(this._controls.camera instanceof OrthographicCamera) {
|
|
455
|
-
const orthographicCamera: OrthographicCamera = <OrthographicCamera>this._controls.camera;
|
|
456
|
-
const mat = mat4.targetTo(mat4.create(), orthographicCamera.position, orthographicCamera.target, orthographicCamera.up);
|
|
457
|
-
|
|
458
|
-
// // we use only clientHeight here so aspect ratio does not distort speed
|
|
459
|
-
// // left
|
|
460
|
-
const v1 = vec3.fromValues(mat[0], mat[1], mat[2]);
|
|
461
|
-
const scalar1 = -(panDelta[0] * (orthographicCamera.right - orthographicCamera.left) * 0.5 / this._controls.canvas?.clientHeight /** orthographicCamera.zoom */);
|
|
462
|
-
vec3.multiply(v1, v1, vec3.fromValues(scalar1, scalar1, scalar1));
|
|
463
|
-
vec3.add(panOffset, panOffset, v1);
|
|
464
|
-
|
|
465
|
-
// // up
|
|
466
|
-
const v2 = vec3.fromValues(mat[4], mat[5], mat[6]);
|
|
467
|
-
const scalar2 = panDelta[1] * (orthographicCamera.right - orthographicCamera.left) * 0.5 / this._controls.canvas?.clientHeight /** orthographicCamera.zoom */;
|
|
468
|
-
vec3.multiply(v2, v2, vec3.fromValues(scalar2, scalar2, scalar2));
|
|
469
|
-
vec3.add(panOffset, panOffset, v2);
|
|
470
|
-
} else {
|
|
471
|
-
let targetDistance = vec3.length(offset);
|
|
472
|
-
|
|
473
|
-
// half of the fov is center to top of screen
|
|
474
|
-
targetDistance *= Math.tan((((<PerspectiveCamera>this._controls.camera).fov / 2) * Math.PI) / 180.0);
|
|
475
|
-
|
|
476
|
-
// we use only clientHeight here so aspect ratio does not distort speed
|
|
477
|
-
// left
|
|
478
|
-
const mat = mat4.targetTo(mat4.create(), this._controls.camera.position, this._controls.camera.target, vec3.fromValues(0, 0, 1));
|
|
479
|
-
|
|
480
|
-
const v1 = vec3.fromValues(mat[0], mat[1], mat[2]);
|
|
481
|
-
const scalar1 = -(2 * panDelta[0] * targetDistance / this._controls.canvas?.clientHeight);
|
|
482
|
-
vec3.multiply(v1, v1, vec3.fromValues(scalar1, scalar1, scalar1));
|
|
483
|
-
vec3.add(panOffset, panOffset, v1);
|
|
484
|
-
|
|
485
|
-
// // up
|
|
486
|
-
const v2 = vec3.fromValues(mat[4], mat[5], mat[6]);
|
|
487
|
-
const scalar2 = 2 * panDelta[1] * targetDistance / this._controls.canvas?.clientHeight;
|
|
488
|
-
vec3.multiply(v2, v2, vec3.fromValues(scalar2, scalar2, scalar2));
|
|
489
|
-
vec3.add(panOffset, panOffset, v2);
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
return vec3.clone(panOffset);
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
private rotationSphericalToOffset(s: Spherical): vec3 {
|
|
496
|
-
let offset = vec3.create();
|
|
497
|
-
vec3.subtract(offset, this._controls.getPositionWithManualUpdates(), this._controls.getTargetWithManualUpdates());
|
|
498
|
-
vec3.transformQuat(offset, offset, this._quat);
|
|
499
|
-
const spherical = new Spherical().fromVec3(offset);
|
|
500
|
-
|
|
501
|
-
spherical.theta += s.theta;
|
|
502
|
-
spherical.phi += s.phi;
|
|
503
|
-
|
|
504
|
-
const minAzimuthAngle = this._controls.rotationRestriction.minAzimuthAngle * (Math.PI / 180),
|
|
505
|
-
maxAzimuthAngle = this._controls.rotationRestriction.maxAzimuthAngle * (Math.PI / 180);
|
|
506
|
-
|
|
507
|
-
if (spherical.theta > Math.PI) {
|
|
508
|
-
spherical.theta -= 2 * Math.PI;
|
|
509
|
-
if (minAzimuthAngle > spherical.theta) {
|
|
510
|
-
spherical.theta += 2 * Math.PI;
|
|
511
|
-
}
|
|
512
|
-
} else if (spherical.theta < -Math.PI) {
|
|
513
|
-
spherical.theta += 2 * Math.PI;
|
|
514
|
-
if (maxAzimuthAngle < spherical.theta) {
|
|
515
|
-
spherical.theta -= 2 * Math.PI;
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
spherical.makeSafe();
|
|
520
|
-
offset = spherical.toVec3();
|
|
521
|
-
offset = vec3.transformQuat(vec3.create(), offset, this._quatInverse);
|
|
522
|
-
offset = vec3.add(vec3.create(), offset, this._controls.getTargetWithManualUpdates());
|
|
523
|
-
offset = vec3.subtract(vec3.create(), offset, this._controls.getPositionWithManualUpdates());
|
|
524
|
-
return vec3.clone(offset);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
private zoomDistanceToOffset(distance: number): vec3 {
|
|
528
|
-
const offset = vec3.create();
|
|
529
|
-
vec3.subtract(offset, this._controls.getPositionWithManualUpdates(), this._controls.getTargetWithManualUpdates());
|
|
530
|
-
return vec3.multiply(vec3.create(), offset, vec3.fromValues(distance, distance, distance));
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// #endregion Private Methods (3)
|
|
534
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { AbstractCameraControls } from './AbstractCameraControls';
|
|
2
|
-
import { ICamera } from '../..';
|
|
3
|
-
import { CameraControlsLogic } from './CameraControlsLogic';
|
|
4
|
-
import { CameraControlsEventDistribution, } from './CameraControlsEventDistribution';
|
|
5
|
-
export class OrthographicCameraControls extends AbstractCameraControls {
|
|
6
|
-
// #region Properties (2)
|
|
7
|
-
|
|
8
|
-
private _settingsAdjustments = {
|
|
9
|
-
autoRotationSpeed: 2 * Math.PI / 60 / 60,
|
|
10
|
-
damping: 1.0,
|
|
11
|
-
movementSmoothness: 1.0,
|
|
12
|
-
panSpeed: 1.75,
|
|
13
|
-
rotationSpeed: Math.PI,
|
|
14
|
-
zoomSpeed: 0.025,
|
|
15
|
-
};
|
|
16
|
-
private _touchAdjustments = {
|
|
17
|
-
autoRotationSpeed: 1.0,
|
|
18
|
-
damping: 1.0,
|
|
19
|
-
movementSmoothness: 1.0,
|
|
20
|
-
panSpeed: 4.0 / 1.75,
|
|
21
|
-
rotationSpeed: 1.5,
|
|
22
|
-
zoomSpeed: 100.0,
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
// #endregion Properties (2)
|
|
26
|
-
|
|
27
|
-
// #region Constructors (1)
|
|
28
|
-
|
|
29
|
-
constructor(camera: ICamera, enabled: boolean) {
|
|
30
|
-
super(camera, enabled);
|
|
31
|
-
this._cameraLogic = new CameraControlsLogic(this, this._settingsAdjustments, this._touchAdjustments);
|
|
32
|
-
this._cameraControlsEventDistribution = new CameraControlsEventDistribution(this, this._cameraLogic);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// #endregion Constructors (1)
|
|
36
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { AbstractCameraControls } from './AbstractCameraControls';
|
|
2
|
-
import { CameraControlsLogic } from './CameraControlsLogic';
|
|
3
|
-
import { ICamera } from '../..';
|
|
4
|
-
import { CameraControlsEventDistribution, } from './CameraControlsEventDistribution';
|
|
5
|
-
|
|
6
|
-
export class PerspectiveCameraControls extends AbstractCameraControls {
|
|
7
|
-
// #region Properties (3)
|
|
8
|
-
|
|
9
|
-
private _settingsAdjustments = {
|
|
10
|
-
autoRotationSpeed: 2 * Math.PI / 60 / 60,
|
|
11
|
-
damping: 1.0,
|
|
12
|
-
movementSmoothness: 1.0,
|
|
13
|
-
panSpeed: 1.75,
|
|
14
|
-
rotationSpeed: Math.PI,
|
|
15
|
-
zoomSpeed: 0.025,
|
|
16
|
-
};
|
|
17
|
-
private _touchAdjustments = {
|
|
18
|
-
autoRotationSpeed: 1.0,
|
|
19
|
-
damping: 1.0,
|
|
20
|
-
movementSmoothness: 1.0,
|
|
21
|
-
panSpeed: 1.0 / 1.75,
|
|
22
|
-
rotationSpeed: 1.5,
|
|
23
|
-
zoomSpeed: 100.0,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
// #endregion Properties (3)
|
|
27
|
-
|
|
28
|
-
// #region Constructors (1)
|
|
29
|
-
|
|
30
|
-
constructor(camera: ICamera, enabled: boolean) {
|
|
31
|
-
super(camera, enabled);
|
|
32
|
-
this._cameraLogic = new CameraControlsLogic(this, this._settingsAdjustments, this._touchAdjustments);
|
|
33
|
-
this._cameraControlsEventDistribution = new CameraControlsEventDistribution(this, this._cameraLogic);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// #endregion Constructors (1)
|
|
37
|
-
}
|