dylanebert HF staff commited on
Commit
49c931b
·
1 Parent(s): 4dbe7ae
viewer/src/lib/splat.js/cameras/Camera.ts CHANGED
@@ -1,7 +1,6 @@
1
  import { Object3D } from "../core/Object3D";
2
  import { Matrix3 } from "../math/Matrix3";
3
  import { Matrix4 } from "../math/Matrix4";
4
- import { Quaternion } from "../math/Quaternion";
5
  import { Vector3 } from "../math/Vector3";
6
 
7
  class Camera extends Object3D {
 
1
  import { Object3D } from "../core/Object3D";
2
  import { Matrix3 } from "../math/Matrix3";
3
  import { Matrix4 } from "../math/Matrix4";
 
4
  import { Vector3 } from "../math/Vector3";
5
 
6
  class Camera extends Object3D {
viewer/src/lib/splat.js/controls/OrbitControls.ts CHANGED
@@ -1,23 +1,8 @@
1
  import type { Camera } from "../cameras/Camera";
2
- import { EventDispatcher } from "../core/EventDispatcher";
3
  import { Matrix3 } from "../math/Matrix3";
4
- import { Quaternion } from "../math/Quaternion";
5
  import { Vector3 } from "../math/Vector3";
6
 
7
- class OrbitControls extends EventDispatcher {
8
- camera: Camera;
9
- domElement: HTMLElement;
10
-
11
- target: Vector3 = new Vector3();
12
- alpha: number = 0;
13
- beta: number = 0;
14
- radius: number = 5;
15
-
16
- desiredTarget: Vector3;
17
- desiredAlpha: number;
18
- desiredBeta: number;
19
- desiredRadius: number;
20
-
21
  minBeta: number = (5 * Math.PI) / 180;
22
  maxBeta: number = (85 * Math.PI) / 180;
23
  minZoom: number = 0.1;
@@ -27,45 +12,124 @@ class OrbitControls extends EventDispatcher {
27
  zoomSpeed: number = 1;
28
  dampening: number = 0.3;
29
 
 
 
 
30
  constructor(camera: Camera, domElement: HTMLElement) {
31
- super();
 
 
 
32
 
33
- this.camera = camera;
34
- this.domElement = domElement;
 
 
35
 
36
- this.desiredTarget = this.target.clone();
37
- this.desiredAlpha = this.alpha;
38
- this.desiredBeta = this.beta;
39
- this.desiredRadius = this.radius;
40
- }
41
 
42
- lerp(a: number, b: number, t: number) {
43
- return (1 - t) * a + t * b;
44
- }
45
 
46
- pan(dx: number, dy: number) {
47
- const R = this.camera.rotation.buffer;
48
- const right = new Vector3(R[0], R[3], R[6]);
49
- const up = new Vector3(R[1], R[4], R[7]);
50
- this.desiredTarget.add(right.multiply(dx));
51
- this.desiredTarget.add(up.multiply(dy));
52
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
- update() {
55
- this.alpha = this.lerp(this.alpha, this.desiredAlpha, this.dampening);
56
- this.beta = this.lerp(this.beta, this.desiredBeta, this.dampening);
57
- this.radius = this.lerp(this.radius, this.desiredRadius, this.dampening);
58
- this.target = this.target.lerp(this.desiredTarget, this.dampening);
59
-
60
- const x = this.target.x + this.radius * Math.sin(this.alpha) * Math.cos(this.beta);
61
- const y = this.target.y - this.radius * Math.sin(this.beta);
62
- const z = this.target.z - this.radius * Math.cos(this.alpha) * Math.cos(this.beta);
63
- this.camera.position.set(x, y, z);
64
-
65
- const direction = this.target.clone().subtract(this.camera.position).normalize();
66
- const rx = Math.asin(-direction.y);
67
- const ry = Math.atan2(direction.x, direction.z);
68
- this.camera.rotation = Matrix3.RotationFromEuler(new Vector3(rx, ry, 0));
69
  }
70
  }
71
 
 
1
  import type { Camera } from "../cameras/Camera";
 
2
  import { Matrix3 } from "../math/Matrix3";
 
3
  import { Vector3 } from "../math/Vector3";
4
 
5
+ class OrbitControls {
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  minBeta: number = (5 * Math.PI) / 180;
7
  maxBeta: number = (85 * Math.PI) / 180;
8
  minZoom: number = 0.1;
 
12
  zoomSpeed: number = 1;
13
  dampening: number = 0.3;
14
 
15
+ update: () => void;
16
+ dispose: () => void;
17
+
18
  constructor(camera: Camera, domElement: HTMLElement) {
19
+ let target = new Vector3();
20
+ let alpha = 0;
21
+ let beta = 0;
22
+ let radius = 5;
23
 
24
+ let desiredTarget = target.clone();
25
+ let desiredAlpha = alpha;
26
+ let desiredBeta = beta;
27
+ let desiredRadius = radius;
28
 
29
+ let dragging = false;
30
+ let panning = false;
31
+ let lastX = 0;
32
+ let lastY = 0;
 
33
 
34
+ const computeZoomNorm = () => {
35
+ return 0.1 + (0.9 * (desiredRadius - this.minZoom)) / (this.maxZoom - this.minZoom);
36
+ };
37
 
38
+ const onPointerDown = (e: PointerEvent) => {
39
+ e.preventDefault();
40
+ e.stopPropagation();
41
+
42
+ dragging = true;
43
+ if (e.pointerType === "touch") {
44
+ panning = e.pointerId === 2;
45
+ } else {
46
+ panning = e.button === 2;
47
+ }
48
+ lastX = e.clientX;
49
+ lastY = e.clientY;
50
+ window.addEventListener("pointerup", onPointerUp);
51
+ window.addEventListener("pointercancel", onPointerUp);
52
+ };
53
+
54
+ const onPointerUp = (e: PointerEvent) => {
55
+ e.preventDefault();
56
+ e.stopPropagation();
57
+
58
+ dragging = false;
59
+ panning = false;
60
+ window.removeEventListener("pointerup", onPointerUp);
61
+ window.removeEventListener("pointercancel", onPointerUp);
62
+ };
63
+
64
+ const onPointerMove = (e: PointerEvent) => {
65
+ e.preventDefault();
66
+ e.stopPropagation();
67
+
68
+ if (!dragging) return;
69
+
70
+ const dx = e.clientX - lastX;
71
+ const dy = e.clientY - lastY;
72
+ const zoomNorm = computeZoomNorm();
73
+
74
+ if (panning) {
75
+ const panX = -dx * this.panSpeed * 0.01 * zoomNorm;
76
+ const panY = -dy * this.panSpeed * 0.01 * zoomNorm;
77
+ const R = camera.rotation.buffer;
78
+ const right = new Vector3(R[0], R[3], R[6]);
79
+ const up = new Vector3(R[1], R[4], R[7]);
80
+ desiredTarget.add(right.multiply(panX));
81
+ desiredTarget.add(up.multiply(panY));
82
+ } else {
83
+ desiredAlpha -= dx * this.orbitSpeed * 0.005;
84
+ desiredBeta += dy * this.orbitSpeed * 0.005;
85
+ desiredBeta = Math.min(Math.max(desiredBeta, this.minBeta), this.maxBeta);
86
+ }
87
+
88
+ lastX = e.clientX;
89
+ lastY = e.clientY;
90
+ };
91
+
92
+ const onWheel = (e: WheelEvent) => {
93
+ e.preventDefault();
94
+ e.stopPropagation();
95
+
96
+ const zoomNorm = computeZoomNorm();
97
+ desiredRadius += e.deltaY * this.zoomSpeed * 0.02 * zoomNorm;
98
+ desiredRadius = Math.min(Math.max(desiredRadius, this.minZoom), this.maxZoom);
99
+ };
100
+
101
+ const lerp = (a: number, b: number, t: number) => {
102
+ return (1 - t) * a + t * b;
103
+ };
104
+
105
+ this.update = () => {
106
+ alpha = lerp(alpha, desiredAlpha, this.dampening);
107
+ beta = lerp(beta, desiredBeta, this.dampening);
108
+ radius = lerp(radius, desiredRadius, this.dampening);
109
+ target = target.lerp(desiredTarget, this.dampening);
110
+
111
+ const x = target.x + radius * Math.sin(alpha) * Math.cos(beta);
112
+ const y = target.y - radius * Math.sin(beta);
113
+ const z = target.z - radius * Math.cos(alpha) * Math.cos(beta);
114
+ camera.position.set(x, y, z);
115
+
116
+ const direction = target.clone().subtract(camera.position).normalize();
117
+ const rx = Math.asin(-direction.y);
118
+ const ry = Math.atan2(direction.x, direction.z);
119
+ camera.rotation = Matrix3.RotationFromEuler(new Vector3(rx, ry, 0));
120
+ };
121
+
122
+ this.dispose = () => {
123
+ domElement.removeEventListener("pointerdown", onPointerDown);
124
+ domElement.removeEventListener("pointermove", onPointerMove);
125
+ domElement.removeEventListener("wheel", onWheel);
126
+ };
127
+
128
+ domElement.addEventListener("pointerdown", onPointerDown);
129
+ domElement.addEventListener("pointermove", onPointerMove);
130
+ domElement.addEventListener("wheel", onWheel);
131
 
132
+ this.update();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  }
134
  }
135
 
viewer/src/lib/splat.js/core/EventDispatcher.ts DELETED
@@ -1,38 +0,0 @@
1
- class EventDispatcher {
2
- listeners: { [key: string]: Function[] } = {};
3
-
4
- addEventListener(type: string, listener: Function): void {
5
- if (this.listeners[type] === undefined) {
6
- this.listeners[type] = [];
7
- }
8
- if (this.listeners[type].indexOf(listener) === -1) {
9
- this.listeners[type].push(listener);
10
- }
11
- }
12
-
13
- hasEventListener(type: string, listener: Function): boolean {
14
- return this.listeners[type] !== undefined && this.listeners[type].indexOf(listener) !== -1;
15
- }
16
-
17
- removeEventListener(type: string, listener: Function): void {
18
- const listenerArray = this.listeners[type];
19
- if (listenerArray !== undefined) {
20
- const index = listenerArray.indexOf(listener);
21
- if (index !== -1) {
22
- listenerArray.splice(index, 1);
23
- }
24
- }
25
- }
26
-
27
- dispatchEvent(event: { type: string }): void {
28
- const listenerArray = this.listeners[event.type];
29
- if (listenerArray !== undefined) {
30
- const array = listenerArray.slice(0);
31
- for (let i = 0, l = array.length; i < l; i++) {
32
- array[i].call(this, event);
33
- }
34
- }
35
- }
36
- }
37
-
38
- export { EventDispatcher };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
viewer/src/lib/splat.js/core/Object3D.ts CHANGED
@@ -1,5 +1,4 @@
1
  import { Vector3 } from "../math/Vector3";
2
- import { Quaternion } from "../math/Quaternion";
3
  import { Matrix3 } from "../math/Matrix3";
4
 
5
  class Object3D {
 
1
  import { Vector3 } from "../math/Vector3";
 
2
  import { Matrix3 } from "../math/Matrix3";
3
 
4
  class Object3D {
viewer/src/routes/viewer/[slug]/SplatViewer.ts CHANGED
@@ -213,23 +213,9 @@ export class SplatViewer implements IViewer {
213
  document.addEventListener("dragleave", this.preventDefault);
214
  document.addEventListener("contextmenu", this.preventDefault);
215
 
216
- this.handleTouchStart = this.handleTouchStart.bind(this);
217
- this.handleTouchEnd = this.handleTouchEnd.bind(this);
218
- this.handleTouchMove = this.handleTouchMove.bind(this);
219
- this.handleMouseDown = this.handleMouseDown.bind(this);
220
- this.handleMouseUp = this.handleMouseUp.bind(this);
221
- this.handleMouseMove = this.handleMouseMove.bind(this);
222
- this.handleMouseWheel = this.handleMouseWheel.bind(this);
223
  this.handleDrop = this.handleDrop.bind(this);
224
  this.handleResize = this.handleResize.bind(this);
225
 
226
- this.canvas.addEventListener("touchstart", this.handleTouchStart);
227
- this.canvas.addEventListener("touchend", this.handleTouchEnd);
228
- this.canvas.addEventListener("touchmove", this.handleTouchMove);
229
- this.canvas.addEventListener("mousedown", this.handleMouseDown);
230
- this.canvas.addEventListener("mouseup", this.handleMouseUp);
231
- this.canvas.addEventListener("mousemove", this.handleMouseMove);
232
- this.canvas.addEventListener("wheel", this.handleMouseWheel);
233
  this.canvas.addEventListener("drop", this.handleDrop);
234
 
235
  window.addEventListener("resize", this.handleResize);
@@ -295,98 +281,6 @@ export class SplatViewer implements IViewer {
295
  }
296
  }
297
 
298
- handleTouchStart(e: TouchEvent) {
299
- e.preventDefault();
300
- this.dragging = true;
301
- this.panning = e.touches.length === 2;
302
- this.lastX = e.touches[0].clientX;
303
- this.lastY = e.touches[0].clientY;
304
- }
305
-
306
- handleTouchEnd(e: TouchEvent) {
307
- e.preventDefault();
308
- this.dragging = false;
309
- this.panning = false;
310
- }
311
-
312
- computeZoomNorm() {
313
- return (
314
- 0.1 +
315
- (0.9 * (this.orbitControls.desiredRadius - this.orbitControls.minZoom)) /
316
- (this.orbitControls.maxZoom - this.orbitControls.minZoom)
317
- );
318
- }
319
-
320
- handleTouchMove(e: TouchEvent) {
321
- e.preventDefault();
322
- if (!this.dragging) return;
323
- const dx = e.touches[0].clientX - this.lastX;
324
- const dy = e.touches[0].clientY - this.lastY;
325
- const zoomNorm = this.computeZoomNorm();
326
-
327
- if (this.panning) {
328
- this.orbitControls.pan(
329
- -dx * this.orbitControls.panSpeed * 0.01 * zoomNorm,
330
- -dy * this.orbitControls.panSpeed * 0.01 * zoomNorm
331
- );
332
- } else {
333
- this.orbitControls.desiredAlpha -= dx * this.orbitControls.orbitSpeed * 0.005;
334
- this.orbitControls.desiredBeta += dy * this.orbitControls.orbitSpeed * 0.005;
335
- this.orbitControls.desiredBeta = Math.min(
336
- Math.max(this.orbitControls.desiredBeta, this.orbitControls.minBeta),
337
- this.orbitControls.maxBeta
338
- );
339
- }
340
-
341
- this.lastX = e.touches[0].clientX;
342
- this.lastY = e.touches[0].clientY;
343
- }
344
-
345
- handleMouseDown(e: MouseEvent) {
346
- this.dragging = true;
347
- this.panning = e.button === 2;
348
- this.lastX = e.clientX;
349
- this.lastY = e.clientY;
350
- }
351
-
352
- handleMouseUp(e: MouseEvent) {
353
- this.dragging = false;
354
- this.panning = false;
355
- }
356
-
357
- handleMouseMove(e: MouseEvent) {
358
- if (!this.dragging) return;
359
- const dx = e.clientX - this.lastX;
360
- const dy = e.clientY - this.lastY;
361
- const zoomNorm = this.computeZoomNorm();
362
-
363
- if (this.panning) {
364
- this.orbitControls.pan(
365
- -dx * this.orbitControls.panSpeed * 0.01 * zoomNorm,
366
- -dy * this.orbitControls.panSpeed * 0.01 * zoomNorm
367
- );
368
- } else {
369
- this.orbitControls.desiredAlpha -= dx * this.orbitControls.orbitSpeed * 0.005;
370
- this.orbitControls.desiredBeta += dy * this.orbitControls.orbitSpeed * 0.005;
371
- this.orbitControls.desiredBeta = Math.min(
372
- Math.max(this.orbitControls.desiredBeta, this.orbitControls.minBeta),
373
- this.orbitControls.maxBeta
374
- );
375
- }
376
-
377
- this.lastX = e.clientX;
378
- this.lastY = e.clientY;
379
- }
380
-
381
- handleMouseWheel(e: WheelEvent) {
382
- const zoomNorm = this.computeZoomNorm();
383
- this.orbitControls.desiredRadius += e.deltaY * this.orbitControls.zoomSpeed * 0.02 * zoomNorm;
384
- this.orbitControls.desiredRadius = Math.min(
385
- Math.max(this.orbitControls.desiredRadius, this.orbitControls.minZoom),
386
- this.orbitControls.maxZoom
387
- );
388
- }
389
-
390
  handleDrop(e: DragEvent) {
391
  e.preventDefault();
392
  e.stopPropagation();
@@ -426,6 +320,7 @@ export class SplatViewer implements IViewer {
426
 
427
  dispose() {
428
  this.worker.terminate();
 
429
 
430
  this.gl.disableVertexAttribArray(this.a_position);
431
  this.gl.disableVertexAttribArray(this.a_center);
@@ -465,13 +360,6 @@ export class SplatViewer implements IViewer {
465
  document.removeEventListener("dragleave", this.preventDefault);
466
  document.removeEventListener("contextmenu", this.preventDefault);
467
 
468
- this.canvas.removeEventListener("touchstart", this.handleTouchStart);
469
- this.canvas.removeEventListener("touchend", this.handleTouchEnd);
470
- this.canvas.removeEventListener("touchmove", this.handleTouchMove);
471
- this.canvas.removeEventListener("mousedown", this.handleMouseDown);
472
- this.canvas.removeEventListener("mouseup", this.handleMouseUp);
473
- this.canvas.removeEventListener("mousemove", this.handleMouseMove);
474
- this.canvas.removeEventListener("wheel", this.handleMouseWheel);
475
  this.canvas.removeEventListener("drop", this.handleDrop);
476
 
477
  window.removeEventListener("resize", this.handleResize);
 
213
  document.addEventListener("dragleave", this.preventDefault);
214
  document.addEventListener("contextmenu", this.preventDefault);
215
 
 
 
 
 
 
 
 
216
  this.handleDrop = this.handleDrop.bind(this);
217
  this.handleResize = this.handleResize.bind(this);
218
 
 
 
 
 
 
 
 
219
  this.canvas.addEventListener("drop", this.handleDrop);
220
 
221
  window.addEventListener("resize", this.handleResize);
 
281
  }
282
  }
283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  handleDrop(e: DragEvent) {
285
  e.preventDefault();
286
  e.stopPropagation();
 
320
 
321
  dispose() {
322
  this.worker.terminate();
323
+ this.orbitControls.dispose();
324
 
325
  this.gl.disableVertexAttribArray(this.a_position);
326
  this.gl.disableVertexAttribArray(this.a_center);
 
360
  document.removeEventListener("dragleave", this.preventDefault);
361
  document.removeEventListener("contextmenu", this.preventDefault);
362
 
 
 
 
 
 
 
 
363
  this.canvas.removeEventListener("drop", this.handleDrop);
364
 
365
  window.removeEventListener("resize", this.handleResize);