-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathOrbitControls.js
More file actions
119 lines (100 loc) · 3.89 KB
/
Copy pathOrbitControls.js
File metadata and controls
119 lines (100 loc) · 3.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
export class Orbital {
constructor(renderer) {
// The renderer is "composed" inside the orbital
this.render = renderer;
this.canvas = renderer.canvas;
this.forward = renderer.forward
this.right = renderer.right
this.up = renderer.up
this.cameraPos = renderer.cameraPos;
this.cameraTarget = renderer.cameraTarget;
this.updateVectors = renderer.updateVectors.bind(renderer);
// and so on...
this.isDragging = false;
this.computeSpherical();
this.attachDOMEvents();
}
attachDOMEvents() {
this.canvas.addEventListener('mousedown', this.onMouseDown.bind(this));
this.canvas.addEventListener('mousemove', this.onMouseMove.bind(this));
this.canvas.addEventListener('mouseup', this.onMouseUp.bind(this));
this.canvas.addEventListener('wheel', this.onMouseWheel.bind(this));
}
computeSpherical() {
const dx = this.cameraPos[0] - this.cameraTarget[0];
const dy = this.cameraPos[1] - this.cameraTarget[1];
const dz = this.cameraPos[2] - this.cameraTarget[2];
this.radius = Math.sqrt(dx*dx + dy*dy + dz*dz);
this.theta = Math.atan2(dz, dx);
this.phi = Math.acos(dy / this.radius);
}
updateCameraPosition() {
const x = this.radius * Math.sin(this.phi) * Math.cos(this.theta);
const y = this.radius * Math.cos(this.phi);
const z = this.radius * Math.sin(this.phi) * Math.sin(this.theta);
// Correctly add x→0, y→1, z→2
this.cameraPos[0] = this.cameraTarget[0] + x;
this.cameraPos[1] = this.cameraTarget[1] + y;
this.cameraPos[2] = this.cameraTarget[2] + z;
}
onMouseDown(event) {
this.isDragging = true;
this.lastMouseX = event.clientX;
this.lastMouseY = event.clientY;
event.preventDefault();
}
onMouseUp(event) {
this.isDragging = false;
event.preventDefault();
}
onMouseMove(event) {
if (!this.isDragging) return;
const deltaX = event.clientX - this.lastMouseX;
const deltaY = event.clientY - this.lastMouseY;
this.lastMouseX = event.clientX;
this.lastMouseY = event.clientY;
if (event.shiftKey) {
this.pan(deltaX, deltaY);
} else {
this.rotate(deltaX, deltaY);
}
this.updateVectors();
this.render.render();
event.preventDefault();
}
onMouseWheel(event) {
this.zoom(event.deltaY);
this.updateVectors();
this.render.render();
event.preventDefault();
}
rotate(deltaX, deltaY) {
const sensitivity = 0.01;
// Horizontal drag changes theta (azimuth)
this.phi += deltaX * sensitivity;
// Vertical drag changes phi (polar)
this.theta += deltaY * sensitivity;
// Clamp phi to avoid flipping over the poles
this.phi = Math.max(0.01 * Math.PI, Math.min(Math.PI, 0.99*this.phi));
this.updateCameraPosition();
}
pan(deltaX, deltaY) {
const sensitivity = 0.005 * this.radius;
const panX = this.right[0] * deltaX * sensitivity + this.up[0] * deltaY * sensitivity;
const panY = this.right[1] * deltaX * sensitivity + this.up[1] * (-deltaY) * sensitivity;
const panZ = this.right[2] * deltaX * sensitivity + this.up[2] * (-deltaY) * sensitivity;
this.cameraTarget[0] += panX;
this.cameraTarget[1] += panY;
this.cameraTarget[2] += panZ;
this.cameraPos[0] += panX;
this.cameraPos[1] += panY;
this.cameraPos[2] += panZ;
}
zoom(deltaY) {
const sensitivity = 0.001;
this.radius *= 1 + deltaY * sensitivity;
this.radius = Math.max(0.1, Math.min(this.radius, 1000));
this.updateCameraPosition();
this.render.render()
}
}