@galacean/cli 0.0.1-alpha.5 → 0.0.1-alpha.7
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/bin/galacean.js +1 -0
- package/dist/cli.bundle.cjs +61161 -43062
- package/package.json +5 -2
- package/dist/assets/templates/web/index.html.ejs +0 -143
- package/dist/assets/templates/web/main.js.ejs +0 -41
- package/dist/assets/templates/web/package.json.ejs +0 -55
- package/dist/assets/templates/web/project.json.ejs +0 -3
- package/dist/assets/templates/web/src/App.tsx.ejs +0 -27
- package/dist/assets/templates/web/src/App.vue.ejs +0 -41
- package/dist/assets/templates/web/src/index.ts.ejs +0 -1065
- package/dist/assets/templates/web/src/scripts/index.ts.ejs +0 -9
- package/dist/assets/templates/web/tsconfig.json.ejs +0 -9
- package/dist/assets/templates/web/vite.config.ts.ejs +0 -27
|
@@ -1,1065 +0,0 @@
|
|
|
1
|
-
const debugChannel = new BroadcastChannel('Galacean_Editor_Channel');
|
|
2
|
-
|
|
3
|
-
debugChannel.addEventListener("message", (e) => {
|
|
4
|
-
if (!(e.data && typeof e.data === 'object')) return;
|
|
5
|
-
const type = e.data.type;
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
import "./scripts";
|
|
9
|
-
import {
|
|
10
|
-
Camera, AssetType, Scene, WebGLEngine, Loader, Logger, WebGLEngineConfiguration, ParserContext, HierarchyParser, Component
|
|
11
|
-
} from "@galacean/engine";
|
|
12
|
-
|
|
13
|
-
<% if(features.spine) { %>
|
|
14
|
-
import { SpineAnimationRenderer } from "@galacean/engine-spine";
|
|
15
|
-
<% } %>
|
|
16
|
-
<% if(features.lottie) { %>
|
|
17
|
-
import { LottieAnimation } from "@galacean/engine-lottie";
|
|
18
|
-
<% } %>
|
|
19
|
-
<% if(features.physicsLite) { %>
|
|
20
|
-
import { LitePhysics } from "@galacean/engine-physics-lite";
|
|
21
|
-
<% } %>
|
|
22
|
-
<% if(features.physx) { %>
|
|
23
|
-
import { PhysXPhysics } from "@galacean/engine-physics-physx";
|
|
24
|
-
<% } %>
|
|
25
|
-
|
|
26
|
-
<% if(features.xr) { %>
|
|
27
|
-
import { WebXRDevice } from "@galacean/engine-xr-webxr";
|
|
28
|
-
import { XROrigin, XRAnchorManager, XRImageManager, XRPlaneManager } from "@galacean/engine-toolkit-xr";
|
|
29
|
-
Loader.registerClass("XR Origin", XROrigin);
|
|
30
|
-
Loader.registerClass("XR Anchor Manager", XRAnchorManager);
|
|
31
|
-
Loader.registerClass("XR Image Manager", XRImageManager);
|
|
32
|
-
Loader.registerClass("XR Plane Manager", XRPlaneManager);
|
|
33
|
-
<% } %>
|
|
34
|
-
|
|
35
|
-
<% if(features.shaderlab) { %>
|
|
36
|
-
import { ShaderLab } from "@galacean/engine-shaderlab";
|
|
37
|
-
import { registerIncludes } from "@galacean/engine-shader";
|
|
38
|
-
<% } %>
|
|
39
|
-
|
|
40
|
-
<% if(features.gui) { %>
|
|
41
|
-
import { registerGUI } from "@galacean/engine-ui";
|
|
42
|
-
registerGUI();
|
|
43
|
-
<% } %>
|
|
44
|
-
|
|
45
|
-
<% if(debug.orbitControl) { %>
|
|
46
|
-
import { OrbitControl as ToolkitOrbitControl } from "@galacean/engine-toolkit";
|
|
47
|
-
<% } %>
|
|
48
|
-
|
|
49
|
-
<% if(debug.stats) { %>
|
|
50
|
-
import { Stats } from "@galacean/engine-toolkit";
|
|
51
|
-
|
|
52
|
-
Stats.hookRequest();
|
|
53
|
-
|
|
54
|
-
debugChannel.addEventListener("message", (e) => {
|
|
55
|
-
if (!(e.data && typeof e.data === 'object')) return;
|
|
56
|
-
|
|
57
|
-
const type = e.data.type;
|
|
58
|
-
if (type === 'toggle-stats-visible') {
|
|
59
|
-
if (!_statsComponent) {
|
|
60
|
-
_statsComponent = engine.sceneManager.activeScene._componentsManager._activeCameras.get(0).entity.addComponent(Stats);
|
|
61
|
-
}
|
|
62
|
-
const value = e.data.payload;
|
|
63
|
-
if(value) {
|
|
64
|
-
_statsComponent.enabled = true;
|
|
65
|
-
} else {
|
|
66
|
-
_statsComponent.enabled = false;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
<% } %>
|
|
71
|
-
|
|
72
|
-
<% if(debug.godMode) { %>
|
|
73
|
-
import {
|
|
74
|
-
Canvas,
|
|
75
|
-
Entity,
|
|
76
|
-
InputManager,
|
|
77
|
-
Keys,
|
|
78
|
-
PointerButton,
|
|
79
|
-
Script,
|
|
80
|
-
Transform,
|
|
81
|
-
Vector2,
|
|
82
|
-
Vector3,
|
|
83
|
-
MathUtil,
|
|
84
|
-
Matrix
|
|
85
|
-
} from "@galacean/engine";
|
|
86
|
-
<% } %>
|
|
87
|
-
import projectInfo from "../project.json";
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<% if(debug.eventDebugger) { %>
|
|
91
|
-
function eventDebugger() {
|
|
92
|
-
const originOnFunc = WebGLEngine.prototype.on;
|
|
93
|
-
const message = {
|
|
94
|
-
type: "collect-preview-runtime-event",
|
|
95
|
-
payload: {},
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
WebGLEngine.prototype.on = function(type, listener) {
|
|
99
|
-
originOnFunc.call(this, type, listener);
|
|
100
|
-
message.payload.inputEvents = this.eventNames();
|
|
101
|
-
debugChannel.postMessage(message);
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
WebGLEngine.prototype._dispatch = WebGLEngine.prototype.dispatch;
|
|
105
|
-
|
|
106
|
-
WebGLEngine.prototype.dispatch = function(event, data) {
|
|
107
|
-
this._dispatch(event, data);
|
|
108
|
-
// message.payload.outputEvent = event;
|
|
109
|
-
debugChannel.postMessage(message, "*");
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
debugChannel.addEventListener("message", (e) => {
|
|
113
|
-
if (!(e.data && typeof e.data === 'object')) return;
|
|
114
|
-
const type = e.data.type;
|
|
115
|
-
if (type === 'trigger-preview-runtime-event') {
|
|
116
|
-
engine.dispatch(e.data.payload.eventName, e.data.payload.data);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
eventDebugger();
|
|
122
|
-
<% } %>
|
|
123
|
-
|
|
124
|
-
<% if(debug.hotReload) { %>
|
|
125
|
-
function engineEnhancement(): void {
|
|
126
|
-
// @ts-ignore
|
|
127
|
-
WebGLEngine.prototype._engineObjectMap = new Map<string, string>();
|
|
128
|
-
|
|
129
|
-
// @ts-ignore
|
|
130
|
-
HierarchyParser.prototype._addComponentPlugin = function (
|
|
131
|
-
componentId: string,
|
|
132
|
-
component: Component
|
|
133
|
-
) {
|
|
134
|
-
this._engine._engineObjectMap.set(componentId, component);
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
// @ts-ignore
|
|
138
|
-
HierarchyParser.prototype._addEntityPlugin = function (
|
|
139
|
-
entityId: string,
|
|
140
|
-
entity: Entity
|
|
141
|
-
) {
|
|
142
|
-
this._engine._engineObjectMap.set(entityId, entity);
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
engineEnhancement();
|
|
146
|
-
|
|
147
|
-
debugChannel.addEventListener("message", (e) => {
|
|
148
|
-
if (!(e.data && typeof e.data === 'object')) return;
|
|
149
|
-
const type = e.data.type;
|
|
150
|
-
if (type === 'script-inspector-value-change') {
|
|
151
|
-
const component = engine._componentsMap.get(e.data.payload.instanceId);
|
|
152
|
-
if (component) {
|
|
153
|
-
component[e.data.payload.property] = e.data.payload.value;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (type === 'scene-inspector-value-change') {
|
|
158
|
-
const { property, value } = e.data.payload;
|
|
159
|
-
engine.sceneManager.activeScene[property] = value;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
})
|
|
163
|
-
<% } %>
|
|
164
|
-
|
|
165
|
-
export async function init(canvas: HTMLCanvasElement) {
|
|
166
|
-
const config: WebGLEngineConfiguration = {
|
|
167
|
-
canvas,
|
|
168
|
-
physics: undefined,
|
|
169
|
-
shaderLab: undefined,
|
|
170
|
-
graphicDeviceOptions: projectInfo.runtimeOptions.webGLRendererOptions
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
<% if(features.xr) { %>
|
|
174
|
-
config.xrDevice = new WebXRDevice();
|
|
175
|
-
<% } %>
|
|
176
|
-
<% if(features.shaderlab) { %>
|
|
177
|
-
config.shaderLab = new ShaderLab();
|
|
178
|
-
Logger.enable();
|
|
179
|
-
registerIncludes();
|
|
180
|
-
<% } %>
|
|
181
|
-
<% if(features.physicsLite) { %>
|
|
182
|
-
config.physics = new LitePhysics();
|
|
183
|
-
<% } %>
|
|
184
|
-
<% if(features.physx) { %>
|
|
185
|
-
config.physics = new PhysXPhysics();
|
|
186
|
-
<% } %>
|
|
187
|
-
<% if(debug.stats) { %>
|
|
188
|
-
<% } %>
|
|
189
|
-
|
|
190
|
-
const engine = await WebGLEngine.create(config);
|
|
191
|
-
document.oncontextmenu = (e) => {
|
|
192
|
-
e.preventDefault();
|
|
193
|
-
};
|
|
194
|
-
engine.canvas.resizeByClientSize(projectInfo.runtimeOptions.devicePixelRatioMode === "Fixed" ? projectInfo.runtimeOptions.devicePixelRatio : undefined);
|
|
195
|
-
|
|
196
|
-
<% if(features.lottie) { %>
|
|
197
|
-
Loader.registerClass("LottieAnimation", LottieAnimation);
|
|
198
|
-
<% } %>
|
|
199
|
-
<% if(features.spine) { %>
|
|
200
|
-
Loader.registerClass("SpineAnimationRenderer", SpineAnimationRenderer);
|
|
201
|
-
<% } %>
|
|
202
|
-
|
|
203
|
-
await engine.resourceManager
|
|
204
|
-
.load({
|
|
205
|
-
url: projectInfo.url,
|
|
206
|
-
type: AssetType.Project,
|
|
207
|
-
})
|
|
208
|
-
.onProgress(
|
|
209
|
-
(loaded: number, total: number) => {
|
|
210
|
-
const percentage = Math.round((loaded / total) * 100);
|
|
211
|
-
console.log(`Overall progress: ${percentage}% (${loaded}/${total} files loaded)`);
|
|
212
|
-
console.log(`Files loaded: project config + ${loaded - 1} project files`);
|
|
213
|
-
|
|
214
|
-
window.parent.postMessage({ loaded, total }, "*");
|
|
215
|
-
// Update your loading ui here
|
|
216
|
-
},
|
|
217
|
-
// Track detailed progress (individual file loading)
|
|
218
|
-
(url: string, loaded: number, total: number) => {
|
|
219
|
-
const percentage = Math.round((loaded / total) * 100);
|
|
220
|
-
console.log(`Loading ${url}: ${percentage}% (${loaded}/${total} bytes)`);
|
|
221
|
-
|
|
222
|
-
// Update detailed progress display here
|
|
223
|
-
}
|
|
224
|
-
)
|
|
225
|
-
.catch((e) => {
|
|
226
|
-
throw e;
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
<% if(debug.orbitControl) { %>
|
|
230
|
-
try {
|
|
231
|
-
const cameras = [];
|
|
232
|
-
const rootEntities = engine.sceneManager.activeScene.rootEntities;
|
|
233
|
-
for (let i = 0, n = rootEntities.length; i < n; i++) {
|
|
234
|
-
cameras.push(...rootEntities[i].getComponentsIncludeChildren(Camera, []));
|
|
235
|
-
}
|
|
236
|
-
for (let j = 0, n = cameras.length; j < n; j++) {
|
|
237
|
-
cameras[0].entity.addComponent(ToolkitOrbitControl);
|
|
238
|
-
}
|
|
239
|
-
} catch (e) {
|
|
240
|
-
console.log(e);
|
|
241
|
-
}
|
|
242
|
-
<% } %>
|
|
243
|
-
|
|
244
|
-
window.engine = engine;
|
|
245
|
-
|
|
246
|
-
<% if(features.xr) { %>
|
|
247
|
-
function addXRButton(content: string): HTMLButtonElement {
|
|
248
|
-
const button = document.createElement("button");
|
|
249
|
-
button.textContent = content;
|
|
250
|
-
const { style } = button;
|
|
251
|
-
style.position = "absolute";
|
|
252
|
-
style.bottom = "20px";
|
|
253
|
-
style.padding = "12px 6px";
|
|
254
|
-
style.border = "1px solid rgb(255, 255, 255)";
|
|
255
|
-
style.borderRadius = "4px";
|
|
256
|
-
style.background = "rgba(0, 0, 0, 0.1)";
|
|
257
|
-
style.color = "rgb(255, 255, 255)";
|
|
258
|
-
style.font = "13px sans-serif";
|
|
259
|
-
style.textAlign = "center";
|
|
260
|
-
style.opacity = "0.5";
|
|
261
|
-
style.outline = "none";
|
|
262
|
-
style.zIndex = "999";
|
|
263
|
-
style.cursor = "pointer";
|
|
264
|
-
style.left = "calc(50% - 50px)";
|
|
265
|
-
style.width = "100px";
|
|
266
|
-
document.body.appendChild(button);
|
|
267
|
-
return button;
|
|
268
|
-
}
|
|
269
|
-
const xrManager = engine.xrManager;
|
|
270
|
-
let xrMode = 0;
|
|
271
|
-
if (xrManager.origin) {
|
|
272
|
-
const inputManager = xrManager.inputManager;
|
|
273
|
-
const camera = inputManager.getTrackedDevice(3);
|
|
274
|
-
const leftCamera = inputManager.getTrackedDevice(4);
|
|
275
|
-
const rightCamera = inputManager.getTrackedDevice(5);
|
|
276
|
-
if(leftCamera._camera && rightCamera._camera) {
|
|
277
|
-
xrMode = 2;
|
|
278
|
-
} else if(camera._camera) {
|
|
279
|
-
xrMode = 1;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
if(xrMode !== 0) {
|
|
283
|
-
xrManager.sessionManager.isSupportedMode(xrMode).then(
|
|
284
|
-
() => {
|
|
285
|
-
addXRButton(xrMode === 1 ? "进入 AR" : "进入 VR").onclick = () => {
|
|
286
|
-
xrManager.enterXR(xrMode);
|
|
287
|
-
};
|
|
288
|
-
},
|
|
289
|
-
(error) => {
|
|
290
|
-
addXRButton("not support")
|
|
291
|
-
console.error(error);
|
|
292
|
-
}
|
|
293
|
-
);
|
|
294
|
-
}
|
|
295
|
-
<% } %>
|
|
296
|
-
|
|
297
|
-
<% if(debug.autoResize) { %>
|
|
298
|
-
// auto resize canvas
|
|
299
|
-
const _canvas = document.getElementById('canvas');
|
|
300
|
-
const ob = new ResizeObserver(() => {
|
|
301
|
-
engine.canvas.resizeByClientSize();
|
|
302
|
-
});
|
|
303
|
-
ob.observe(_canvas);
|
|
304
|
-
<% } %>
|
|
305
|
-
|
|
306
|
-
<% if(debug.godMode) { %>
|
|
307
|
-
|
|
308
|
-
enum ControlEvent {
|
|
309
|
-
Default = "control-default",
|
|
310
|
-
Rotate = "control-rotating",
|
|
311
|
-
Zoom = "control-zoom",
|
|
312
|
-
Pan = "control-paning",
|
|
313
|
-
Around = "control-around",
|
|
314
|
-
Fly = "control-fly",
|
|
315
|
-
Enter = "editorControl-enter",
|
|
316
|
-
Leave = "editorControl-leave",
|
|
317
|
-
SpeedChange = "flySpeedChange",
|
|
318
|
-
PanOn = "editorControl-pan"
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Prevent gimbal lock.
|
|
322
|
-
const ESP = MathUtil.zeroTolerance;
|
|
323
|
-
|
|
324
|
-
class Spherical {
|
|
325
|
-
private static _xAxis: Vector3 = new Vector3();
|
|
326
|
-
private static _yAxis: Vector3 = new Vector3();
|
|
327
|
-
private static _zAxis: Vector3 = new Vector3();
|
|
328
|
-
private _matrix: Matrix = new Matrix();
|
|
329
|
-
private _matrixInv: Matrix = new Matrix();
|
|
330
|
-
constructor(public radius?: number, public phi?: number, public theta?: number) {
|
|
331
|
-
this.radius = radius !== undefined ? radius : 1.0;
|
|
332
|
-
this.phi = phi !== undefined ? phi : 0;
|
|
333
|
-
this.theta = theta !== undefined ? theta : 0;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
makeSafe(): Spherical {
|
|
337
|
-
const count = Math.floor(this.phi / Math.PI);
|
|
338
|
-
this.phi = MathUtil.clamp(this.phi, count * Math.PI + ESP, (count + 1) * Math.PI - ESP);
|
|
339
|
-
return this;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
set(radius: number, phi: number, theta: number): Spherical {
|
|
343
|
-
this.radius = radius;
|
|
344
|
-
this.phi = phi;
|
|
345
|
-
this.theta = theta;
|
|
346
|
-
return this;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
setYAxis(up: Vector3): void {
|
|
350
|
-
const { _xAxis: xAxis, _yAxis: yAxis, _zAxis: zAxis } = Spherical;
|
|
351
|
-
if (Vector3.equals(xAxis.set(1, 0, 0), yAxis.copyFrom(up).normalize())) {
|
|
352
|
-
xAxis.set(0, 1, 0);
|
|
353
|
-
}
|
|
354
|
-
Vector3.cross(xAxis, yAxis, zAxis);
|
|
355
|
-
zAxis.normalize();
|
|
356
|
-
Vector3.cross(yAxis, zAxis, xAxis);
|
|
357
|
-
const { elements: es } = this._matrix;
|
|
358
|
-
(es[0] = xAxis.x), (es[1] = xAxis.y), (es[2] = xAxis.z);
|
|
359
|
-
(es[4] = yAxis.x), (es[5] = yAxis.y), (es[6] = yAxis.z);
|
|
360
|
-
(es[8] = zAxis.x), (es[9] = zAxis.y), (es[10] = zAxis.z);
|
|
361
|
-
|
|
362
|
-
const { elements: eInv } = this._matrixInv;
|
|
363
|
-
(eInv[0] = xAxis.x), (eInv[4] = xAxis.y), (eInv[8] = xAxis.z);
|
|
364
|
-
(eInv[1] = yAxis.x), (eInv[5] = yAxis.y), (eInv[9] = yAxis.z);
|
|
365
|
-
(eInv[2] = zAxis.x), (eInv[6] = zAxis.y), (eInv[10] = zAxis.z);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
setFromVec3(value: Vector3, atTheBack = false): Spherical {
|
|
369
|
-
value.transformNormal(this._matrixInv);
|
|
370
|
-
this.radius = value.length();
|
|
371
|
-
if (this.radius === 0) {
|
|
372
|
-
this.theta = 0;
|
|
373
|
-
this.phi = 0;
|
|
374
|
-
} else {
|
|
375
|
-
if (atTheBack) {
|
|
376
|
-
this.phi = 2 * Math.PI - Math.acos(MathUtil.clamp(value.y / this.radius, -1, 1));
|
|
377
|
-
this.theta = Math.atan2(-value.x, -value.z);
|
|
378
|
-
} else {
|
|
379
|
-
this.phi = Math.acos(MathUtil.clamp(value.y / this.radius, -1, 1));
|
|
380
|
-
this.theta = Math.atan2(value.x, value.z);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
return this;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
setToVec3(value: Vector3): boolean {
|
|
387
|
-
const { radius, phi, theta } = this;
|
|
388
|
-
const sinPhiRadius = Math.sin(phi) * radius;
|
|
389
|
-
this.phi -= Math.floor(this.phi / Math.PI / 2) * Math.PI * 2;
|
|
390
|
-
value.set(sinPhiRadius * Math.sin(theta), radius * Math.cos(phi), sinPhiRadius * Math.cos(theta));
|
|
391
|
-
value.transformNormal(this._matrix);
|
|
392
|
-
return this.phi > Math.PI;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
class OrbitControl extends Script {
|
|
397
|
-
canvas: Canvas;
|
|
398
|
-
input: InputManager;
|
|
399
|
-
camera: Camera;
|
|
400
|
-
cameraTransform: Transform;
|
|
401
|
-
|
|
402
|
-
/** Whether to automatically rotate the camera, the default is false. */
|
|
403
|
-
autoRotate = false;
|
|
404
|
-
/** The radian of automatic rotation per second. */
|
|
405
|
-
autoRotateSpeed: number = Math.PI;
|
|
406
|
-
/** Whether to enable camera damping, the default is true. */
|
|
407
|
-
enableDamping = true;
|
|
408
|
-
/** Rotation speed, default is 1.0 . */
|
|
409
|
-
rotateSpeed = 1.0;
|
|
410
|
-
/** Camera zoom speed, the default is 1.0. */
|
|
411
|
-
zoomSpeed = 1.0;
|
|
412
|
-
/** Keyboard translation speed, the default is 7.0 . */
|
|
413
|
-
keyPanSpeed = 7.0;
|
|
414
|
-
/** Rotation damping parameter, default is 0.1 . */
|
|
415
|
-
dampingFactor = 0.1;
|
|
416
|
-
/** Zoom damping parameter, default is 0.2 . */
|
|
417
|
-
zoomFactor = 0.2;
|
|
418
|
-
/** The minimum distance, the default is 0.1, should be greater than 0. */
|
|
419
|
-
minDistance = 0.000001;
|
|
420
|
-
/** The maximum distance, the default is infinite, should be greater than the minimum distance. */
|
|
421
|
-
maxDistance = Infinity;
|
|
422
|
-
/** Minimum zoom speed, the default is 0.0. */
|
|
423
|
-
minZoom = 0.0;
|
|
424
|
-
/** Maximum zoom speed, the default is positive infinity. */
|
|
425
|
-
maxZoom = Infinity;
|
|
426
|
-
/** The minimum radian in the vertical direction, the default is 1 degree. */
|
|
427
|
-
minPolarAngle = 1;
|
|
428
|
-
/** The maximum radian in the vertical direction, the default is 179 degree. */
|
|
429
|
-
maxPolarAngle: number = (179 / 180) * Math.PI;
|
|
430
|
-
/** The minimum radian in the horizontal direction, the default is negative infinity. */
|
|
431
|
-
minAzimuthAngle = -Infinity;
|
|
432
|
-
/** The maximum radian in the horizontal direction, the default is positive infinity. */
|
|
433
|
-
maxAzimuthAngle = Infinity;
|
|
434
|
-
/** Movement distance per second, the unit is the unit before MVP conversion. */
|
|
435
|
-
movementSpeed = 2;
|
|
436
|
-
/** factor of movement speed */
|
|
437
|
-
speedFactor = 1.0;
|
|
438
|
-
|
|
439
|
-
private _up: Vector3 = new Vector3(0, 1, 0);
|
|
440
|
-
private _target: Vector3 = new Vector3();
|
|
441
|
-
private _atTheBack = false;
|
|
442
|
-
private _spherical: Spherical = new Spherical();
|
|
443
|
-
private _sphericalDelta: Spherical = new Spherical();
|
|
444
|
-
private _sphericalDump: Spherical = new Spherical();
|
|
445
|
-
private _sphericalFree: Spherical = new Spherical();
|
|
446
|
-
private _zoomFrag = 0;
|
|
447
|
-
private _scale = 1;
|
|
448
|
-
private _panOffset: Vector3 = new Vector3();
|
|
449
|
-
private _tempVec3: Vector3 = new Vector3();
|
|
450
|
-
private _tempVec2: Vector3 = new Vector3();
|
|
451
|
-
private _tempVec: Vector3 = new Vector3();
|
|
452
|
-
private _topVec: Vector3 = new Vector3(0, 1, 0);
|
|
453
|
-
private _bottomVec: Vector3 = new Vector3(0, -1, 0);
|
|
454
|
-
private _tempForward: Vector3 = new Vector3();
|
|
455
|
-
private _tempTarget: Vector3 = new Vector3();
|
|
456
|
-
private _tempVecDelta: Vector2 = new Vector2();
|
|
457
|
-
|
|
458
|
-
private _radius = 0;
|
|
459
|
-
private _isAltDown = false;
|
|
460
|
-
private _transformDirty = false;
|
|
461
|
-
private _inEditing = false;
|
|
462
|
-
private _lastFlySpeed = 0;
|
|
463
|
-
private _flyDirection = new Vector3();
|
|
464
|
-
private _damping = 0.8;
|
|
465
|
-
private _dampingThreshold = 0.01;
|
|
466
|
-
|
|
467
|
-
/*
|
|
468
|
-
* Return up vector.
|
|
469
|
-
*/
|
|
470
|
-
get up(): Vector3 {
|
|
471
|
-
return this._up;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
set up(value: Vector3) {
|
|
475
|
-
this._up.copyFrom(value);
|
|
476
|
-
this._spherical.setYAxis(value);
|
|
477
|
-
this._atTheBack = false;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* Return target position.
|
|
482
|
-
* */
|
|
483
|
-
get target(): Vector3 {
|
|
484
|
-
return this._target;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
set target(value: Vector3) {
|
|
488
|
-
this._target.copyFrom(value);
|
|
489
|
-
this._atTheBack = false;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
set inEditing(value: boolean) {
|
|
493
|
-
if (this._inEditing !== value) {
|
|
494
|
-
this._inEditing = value;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
this.engine.dispatch(value ? ControlEvent.Enter : ControlEvent.Leave);
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
onAwake(): void {
|
|
501
|
-
const { engine, entity } = this;
|
|
502
|
-
this.canvas = engine.canvas;
|
|
503
|
-
this.input = engine.inputManager;
|
|
504
|
-
this.camera = entity.getComponent(Camera);
|
|
505
|
-
this.cameraTransform = entity.transform;
|
|
506
|
-
this._spherical.setYAxis(this._up);
|
|
507
|
-
this._atTheBack = false;
|
|
508
|
-
|
|
509
|
-
/** Init spherical. */
|
|
510
|
-
Vector3.transformByQuat(this._tempVec3.set(0, 0, -1), this.cameraTransform.rotationQuaternion, this._tempVec3);
|
|
511
|
-
this._sphericalFree.setFromVec3(this._tempVec3, this._atTheBack);
|
|
512
|
-
|
|
513
|
-
// alt key
|
|
514
|
-
// 需要拿到全局 alt down, 而inputManager为防止与其他面板快捷键冲突需要挂在canvas上
|
|
515
|
-
document.addEventListener("keydown", (event) => {
|
|
516
|
-
this._isAltDown = event.altKey;
|
|
517
|
-
});
|
|
518
|
-
document.addEventListener("keyup", (event) => {
|
|
519
|
-
this._isAltDown = event.altKey;
|
|
520
|
-
});
|
|
521
|
-
|
|
522
|
-
// 此处重写了 pointerManager 的事件监听
|
|
523
|
-
// 在 viewport 编辑态时,需要阻拦触控点所有的默认行为
|
|
524
|
-
// @ts-ignore
|
|
525
|
-
const pointerManager = this.engine.inputManager._pointerManager;
|
|
526
|
-
pointerManager._removeEventListener();
|
|
527
|
-
const { _nativeEvents: nativeEvents } = pointerManager;
|
|
528
|
-
// @ts-ignore
|
|
529
|
-
const { _webCanvas: webCanvas } = engine.canvas;
|
|
530
|
-
pointerManager._onPointerEvent = (evt: PointerEvent) => {
|
|
531
|
-
// @ts-ignore
|
|
532
|
-
if (evt.type === "pointerdown" && evt.target !== webCanvas) return;
|
|
533
|
-
this._inEditing && evt.preventDefault();
|
|
534
|
-
nativeEvents.push(evt);
|
|
535
|
-
};
|
|
536
|
-
pointerManager._addEventListener();
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
onUpdate(deltaTime: number): void {
|
|
540
|
-
const inputManager = this.input;
|
|
541
|
-
// 维护编辑态
|
|
542
|
-
// 1. 若触控按下,则进入编辑态
|
|
543
|
-
if (inputManager.isPointerDown() || inputManager.isKeyDown()) {
|
|
544
|
-
this.inEditing = true;
|
|
545
|
-
}
|
|
546
|
-
// 2. 若当前没有触控,则退出编辑态
|
|
547
|
-
if (!inputManager.isPointerHeldDown() && !inputManager.isKeyHeldDown()) {
|
|
548
|
-
this.inEditing = false;
|
|
549
|
-
}
|
|
550
|
-
const { _inEditing: inEditing } = this;
|
|
551
|
-
const primaryDown = inputManager.isPointerHeldDown(PointerButton.Primary);
|
|
552
|
-
const secondaryDown = inputManager.isPointerHeldDown(PointerButton.Secondary);
|
|
553
|
-
const auxiliaryDown = inputManager.isPointerHeldDown(PointerButton.Auxiliary);
|
|
554
|
-
// 判断滚轮
|
|
555
|
-
if (secondaryDown) {
|
|
556
|
-
this._updateSpeed(inputManager.wheelDelta);
|
|
557
|
-
} else {
|
|
558
|
-
this._zoom(inputManager.wheelDelta);
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
// 判断 fly
|
|
562
|
-
const { movementSpeed } = this;
|
|
563
|
-
const delta = this._tempVec2.set(0, 0, 0);
|
|
564
|
-
|
|
565
|
-
if ((secondaryDown && inputManager.isKeyHeldDown(Keys.KeyA)) || inputManager.isKeyHeldDown(Keys.ArrowLeft)) {
|
|
566
|
-
delta.x -= movementSpeed;
|
|
567
|
-
}
|
|
568
|
-
if ((secondaryDown && inputManager.isKeyHeldDown(Keys.KeyD)) || inputManager.isKeyHeldDown(Keys.ArrowRight)) {
|
|
569
|
-
delta.x += movementSpeed;
|
|
570
|
-
}
|
|
571
|
-
if (secondaryDown && inputManager.isKeyHeldDown(Keys.KeyQ)) {
|
|
572
|
-
delta.y -= movementSpeed;
|
|
573
|
-
}
|
|
574
|
-
if (secondaryDown && inputManager.isKeyHeldDown(Keys.KeyE)) {
|
|
575
|
-
delta.y += movementSpeed;
|
|
576
|
-
}
|
|
577
|
-
if ((secondaryDown && inputManager.isKeyHeldDown(Keys.KeyS)) || inputManager.isKeyHeldDown(Keys.ArrowDown)) {
|
|
578
|
-
delta.z += movementSpeed;
|
|
579
|
-
}
|
|
580
|
-
if ((secondaryDown && inputManager.isKeyHeldDown(Keys.KeyW)) || inputManager.isKeyHeldDown(Keys.ArrowUp)) {
|
|
581
|
-
delta.z -= movementSpeed;
|
|
582
|
-
}
|
|
583
|
-
this._fly(delta, deltaTime);
|
|
584
|
-
|
|
585
|
-
let controlType = ControlEvent.Default;
|
|
586
|
-
|
|
587
|
-
// 判断 panning, around, zoom 和 rotating
|
|
588
|
-
if (inEditing) {
|
|
589
|
-
const onlyPrimaryDown = primaryDown && !secondaryDown;
|
|
590
|
-
const onlySecondaryDown = !primaryDown && secondaryDown;
|
|
591
|
-
const bothDown = primaryDown && secondaryDown;
|
|
592
|
-
const deltaPosition = inputManager.pointers[0]?.deltaPosition || this._tempVecDelta.set(0, 0);
|
|
593
|
-
const altDown = this._isAltDown;
|
|
594
|
-
const ctrlDown = inputManager.isKeyHeldDown(Keys.ControlLeft) || inputManager.isKeyHeldDown(Keys.ControlRight);
|
|
595
|
-
const metaDown = inputManager.isKeyHeldDown(Keys.MetaLeft) || inputManager.isKeyHeldDown(Keys.MetaRight);
|
|
596
|
-
|
|
597
|
-
// change cursor for next move implication
|
|
598
|
-
if (altDown && !metaDown) {
|
|
599
|
-
controlType = ControlEvent.Rotate;
|
|
600
|
-
}
|
|
601
|
-
if (altDown && ctrlDown) {
|
|
602
|
-
controlType = ControlEvent.Zoom;
|
|
603
|
-
}
|
|
604
|
-
if (auxiliaryDown || (altDown && metaDown)) {
|
|
605
|
-
controlType = ControlEvent.Pan;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
if (bothDown || (altDown && ctrlDown && onlyPrimaryDown)) {
|
|
609
|
-
controlType = ControlEvent.Zoom;
|
|
610
|
-
this._zoom(deltaPosition);
|
|
611
|
-
} else if (altDown && onlyPrimaryDown && !metaDown) {
|
|
612
|
-
controlType = ControlEvent.Rotate;
|
|
613
|
-
this._rotate(deltaPosition);
|
|
614
|
-
} else if (onlySecondaryDown) {
|
|
615
|
-
controlType = ControlEvent.Around;
|
|
616
|
-
this._around(deltaPosition);
|
|
617
|
-
} else if (onlyPrimaryDown || auxiliaryDown || (altDown && metaDown && onlyPrimaryDown)) {
|
|
618
|
-
controlType = ControlEvent.Pan;
|
|
619
|
-
this._pan(deltaPosition);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
this._transformDirty && this._updateTransform();
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
private _rotate(delta: Vector2): void {
|
|
626
|
-
if (delta.x === 0 && delta.y === 0) {
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
const radianLeft = ((2 * Math.PI * delta.x) / this.canvas.width) * this.rotateSpeed;
|
|
630
|
-
this._sphericalDelta.theta -= radianLeft;
|
|
631
|
-
const radianUp = ((2 * Math.PI * delta.y) / this.canvas.height) * this.rotateSpeed;
|
|
632
|
-
this._sphericalDelta.phi -= radianUp;
|
|
633
|
-
if (this.enableDamping) {
|
|
634
|
-
this._sphericalDump.theta = -radianLeft;
|
|
635
|
-
this._sphericalDump.phi = -radianUp;
|
|
636
|
-
}
|
|
637
|
-
this._transformDirty = true;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
private _zoom(delta: Vector2 | Vector3): void {
|
|
641
|
-
if (delta.y === 0) {
|
|
642
|
-
return;
|
|
643
|
-
}
|
|
644
|
-
const factor = this._easeOutExpo(this._getDistToTarget());
|
|
645
|
-
if (delta.y > 0) {
|
|
646
|
-
this._scale /= Math.pow(0.95, this.zoomSpeed * factor);
|
|
647
|
-
} else if (delta.y < 0) {
|
|
648
|
-
this._scale *= Math.pow(0.95, this.zoomSpeed * factor);
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
this._transformDirty = true;
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
private _pan(delta: Vector2): void {
|
|
655
|
-
if (delta.x === 0 && delta.y === 0) {
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
658
|
-
const { cameraTransform } = this;
|
|
659
|
-
const { elements } = cameraTransform.worldMatrix;
|
|
660
|
-
const { height } = this.canvas;
|
|
661
|
-
const targetDistance =
|
|
662
|
-
Vector3.distance(cameraTransform.position, this.target) * (this.camera.fieldOfView / 2) * (Math.PI / 180);
|
|
663
|
-
const distanceLeft = -2 * delta.x * (targetDistance / height);
|
|
664
|
-
const distanceUp = 2 * delta.y * (targetDistance / height);
|
|
665
|
-
this._panOffset.x += elements[0] * distanceLeft + elements[4] * distanceUp;
|
|
666
|
-
this._panOffset.y += elements[1] * distanceLeft + elements[5] * distanceUp;
|
|
667
|
-
this._panOffset.z += elements[2] * distanceLeft + elements[6] * distanceUp;
|
|
668
|
-
this._transformDirty = true;
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
private _fly(moveDelta: Vector3, delta: number): void {
|
|
672
|
-
if (moveDelta.x === 0 && moveDelta.y === 0 && moveDelta.z === 0) {
|
|
673
|
-
if (this._lastFlySpeed > this._dampingThreshold) {
|
|
674
|
-
this._lastFlySpeed *= this._damping;
|
|
675
|
-
const length = delta * this.movementSpeed * this._easeOutExpo(this._lastFlySpeed);
|
|
676
|
-
this._flyUpdate(length);
|
|
677
|
-
} else {
|
|
678
|
-
this._lastFlySpeed = 0;
|
|
679
|
-
}
|
|
680
|
-
return;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
const factor = this._getDistToTarget() * 0.024154589371980676;
|
|
684
|
-
this._lastFlySpeed += delta;
|
|
685
|
-
const length = delta * this.movementSpeed * factor * (1 + this._lastFlySpeed * this._lastFlySpeed * 10);
|
|
686
|
-
|
|
687
|
-
this._flyDirection.copyFrom(moveDelta);
|
|
688
|
-
this._flyUpdate(length);
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
private _around(moveDelta: Vector2): void {
|
|
692
|
-
if (moveDelta.x === 0 && moveDelta.y === 0) {
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
695
|
-
this._tempVec3.copyFrom(this.cameraTransform.worldUp);
|
|
696
|
-
this._atTheBack = this._tempVec3.y <= 0;
|
|
697
|
-
|
|
698
|
-
Vector3.transformByQuat(this._tempVec3.set(0, 0, -1), this.cameraTransform.rotationQuaternion, this._tempVec3);
|
|
699
|
-
this._sphericalFree.setFromVec3(this._tempVec3, this._atTheBack);
|
|
700
|
-
|
|
701
|
-
const canvas = this.engine.canvas;
|
|
702
|
-
const deltaAlpha = (-moveDelta.x * 180) / canvas.width;
|
|
703
|
-
const deltaPhi = (moveDelta.y * 180) / canvas.height;
|
|
704
|
-
this._sphericalFree.theta += MathUtil.degreeToRadian(deltaAlpha);
|
|
705
|
-
this._sphericalFree.phi += MathUtil.degreeToRadian(deltaPhi);
|
|
706
|
-
this._sphericalFree.makeSafe();
|
|
707
|
-
this._atTheBack = this._sphericalFree.setToVec3(this._tempVec2);
|
|
708
|
-
Vector3.add(this.cameraTransform.position, this._tempVec2, this._tempVec2);
|
|
709
|
-
this._atTheBack
|
|
710
|
-
? this.cameraTransform.lookAt(this._tempVec2, this._bottomVec)
|
|
711
|
-
: this.cameraTransform.lookAt(this._tempVec2, this._topVec);
|
|
712
|
-
|
|
713
|
-
this._updateTarget();
|
|
714
|
-
this._transformDirty = true;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
private _updateSpeed(delta: Vector3) {
|
|
718
|
-
if (delta.y === 0) return;
|
|
719
|
-
this.speedFactor = MathUtil.clamp(this.speedFactor - delta.y / 500, 0.001, 50);
|
|
720
|
-
this.engine.dispatch(ControlEvent.SpeedChange, this.speedFactor);
|
|
721
|
-
this.movementSpeed = 10.0 * this.speedFactor;
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
private _updateTarget() {
|
|
725
|
-
this._radius = Vector3.distance(this.cameraTransform.worldPosition, this.target);
|
|
726
|
-
const currentPos = this.cameraTransform.worldPosition;
|
|
727
|
-
this._tempForward = this.cameraTransform.worldForward.clone();
|
|
728
|
-
this._tempForward.normalize().scale(this._radius);
|
|
729
|
-
Vector3.add(currentPos, this._tempForward, this._tempTarget);
|
|
730
|
-
|
|
731
|
-
this._tempVec.copyFrom(this._atTheBack ? this._bottomVec : this._topVec);
|
|
732
|
-
|
|
733
|
-
this._spherical.setYAxis(this._tempVec);
|
|
734
|
-
this._target = this._tempTarget;
|
|
735
|
-
this._up.copyFrom(this._tempVec);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
private _updateTransform(): void {
|
|
739
|
-
const { cameraTransform, target, _spherical, _tempVec2: _tempVec31, _sphericalDelta, _panOffset } = this;
|
|
740
|
-
|
|
741
|
-
_tempVec31.copyFrom(cameraTransform.worldUp);
|
|
742
|
-
this._atTheBack = _tempVec31.y <= 0;
|
|
743
|
-
|
|
744
|
-
Vector3.subtract(cameraTransform.position, target, _tempVec31);
|
|
745
|
-
_spherical.setFromVec3(_tempVec31, this._atTheBack);
|
|
746
|
-
_spherical.theta += _sphericalDelta.theta;
|
|
747
|
-
_spherical.phi += _sphericalDelta.phi;
|
|
748
|
-
_spherical.theta = Math.max(this.minAzimuthAngle, Math.min(this.maxAzimuthAngle, _spherical.theta));
|
|
749
|
-
_spherical.phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, _spherical.phi));
|
|
750
|
-
_spherical.makeSafe();
|
|
751
|
-
if (this._scale !== 1) {
|
|
752
|
-
this._zoomFrag = _spherical.radius * (this._scale - 1);
|
|
753
|
-
}
|
|
754
|
-
_spherical.radius += this._zoomFrag;
|
|
755
|
-
|
|
756
|
-
_spherical.radius = Math.max(this.minDistance, Math.min(this.maxDistance, _spherical.radius));
|
|
757
|
-
this._atTheBack = _spherical.setToVec3(_tempVec31);
|
|
758
|
-
|
|
759
|
-
// Camera move
|
|
760
|
-
Vector3.add(target.add(_panOffset), _tempVec31, cameraTransform.worldPosition);
|
|
761
|
-
cameraTransform.lookAt(target, this._atTheBack ? this._bottomVec : this._topVec);
|
|
762
|
-
|
|
763
|
-
// Reset cache value.
|
|
764
|
-
this._zoomFrag = 0;
|
|
765
|
-
this._scale = 1;
|
|
766
|
-
_sphericalDelta.set(0, 0, 0);
|
|
767
|
-
_panOffset.set(0, 0, 0);
|
|
768
|
-
this._transformDirty = false;
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
private _flyUpdate(length: number) {
|
|
772
|
-
const dist = this._flyDirection.normalize().scale(length);
|
|
773
|
-
this.cameraTransform.translate(dist, true);
|
|
774
|
-
Vector3.transformByQuat(dist, this.entity.transform.worldRotationQuaternion, this._tempVec3);
|
|
775
|
-
this._target.add(this._tempVec3);
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
private _easeOutExpo(t: number): number {
|
|
779
|
-
return t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
private _getDistToTarget(): number {
|
|
783
|
-
Vector3.subtract(this.target, this.cameraTransform.worldPosition, this._tempVec3);
|
|
784
|
-
return this._tempVec3.length();
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
class OrthoControl extends Script {
|
|
789
|
-
canvas: Canvas;
|
|
790
|
-
input: InputManager;
|
|
791
|
-
camera: Camera;
|
|
792
|
-
cameraTransform: Transform;
|
|
793
|
-
|
|
794
|
-
/** Target position. */
|
|
795
|
-
target: Vector3 = new Vector3();
|
|
796
|
-
/** Up vector */
|
|
797
|
-
up: Vector3 = new Vector3(0, 1, 0);
|
|
798
|
-
/** Camera zoom speed, the default is 1.0. */
|
|
799
|
-
zoomSpeed = 1.0;
|
|
800
|
-
/** Minimum zoom speed, the default is 0.0. */
|
|
801
|
-
minZoom = 0.0;
|
|
802
|
-
/** Maximum zoom speed, the default is positive infinity. */
|
|
803
|
-
maxZoom = Infinity;
|
|
804
|
-
/** Movement distance per second, the unit is the unit before MVP conversion. */
|
|
805
|
-
movementSpeed = 10.0;
|
|
806
|
-
|
|
807
|
-
private _zoomScaleUnit = 3;
|
|
808
|
-
private _scale = 1;
|
|
809
|
-
private _realScale = 1;
|
|
810
|
-
|
|
811
|
-
private _transformDirty = false;
|
|
812
|
-
|
|
813
|
-
private _panOffset: Vector2 = new Vector2();
|
|
814
|
-
private _tempVec2: Vector2 = new Vector2();
|
|
815
|
-
private _tempVec3: Vector3 = new Vector3();
|
|
816
|
-
|
|
817
|
-
private _isAltDown = false;
|
|
818
|
-
private _inEditing = false;
|
|
819
|
-
|
|
820
|
-
set inEditing(value: boolean) {
|
|
821
|
-
if (this._inEditing !== value) {
|
|
822
|
-
this._inEditing = value;
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
this.engine.dispatch(value ? ControlEvent.Enter : ControlEvent.Leave);
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
constructor(entity: Entity) {
|
|
829
|
-
super(entity);
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
checkAltPressed = (event: KeyboardEvent) => {
|
|
833
|
-
this._isAltDown = event.altKey;
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
onAwake(): void {
|
|
837
|
-
const { engine, entity } = this;
|
|
838
|
-
this.canvas = engine.canvas;
|
|
839
|
-
this.input = engine.inputManager;
|
|
840
|
-
this.camera = entity.getComponent(Camera);
|
|
841
|
-
this.cameraTransform = entity.transform;
|
|
842
|
-
|
|
843
|
-
document.addEventListener("keydown", this.checkAltPressed);
|
|
844
|
-
document.addEventListener("keyup", this.checkAltPressed);
|
|
845
|
-
|
|
846
|
-
// 此处重写了 pointerManager 的事件监听
|
|
847
|
-
// 在 viewport 编辑态时,需要阻拦触控点所有的默认行为
|
|
848
|
-
// @ts-ignore
|
|
849
|
-
const pointerManager = this.engine.inputManager._pointerManager;
|
|
850
|
-
pointerManager._removeEventListener();
|
|
851
|
-
const { _nativeEvents: nativeEvents } = pointerManager;
|
|
852
|
-
// @ts-ignore
|
|
853
|
-
const { _webCanvas: webCanvas } = engine.canvas;
|
|
854
|
-
pointerManager._onPointerEvent = (evt: PointerEvent) => {
|
|
855
|
-
// @ts-ignore
|
|
856
|
-
if (evt.type === "pointerdown" && evt.target !== webCanvas) return;
|
|
857
|
-
this._inEditing && evt.preventDefault();
|
|
858
|
-
nativeEvents.push(evt);
|
|
859
|
-
};
|
|
860
|
-
pointerManager._addEventListener();
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
onUpdate(): void {
|
|
864
|
-
const inputManager = this._engine.inputManager; // 维护编辑态
|
|
865
|
-
// 1. 若触控按下,则进入编辑态
|
|
866
|
-
//@ts-ignore
|
|
867
|
-
if (inputManager.isPointerDown() || inputManager.isKeyDown()) {
|
|
868
|
-
this.inEditing = true;
|
|
869
|
-
}
|
|
870
|
-
// 2. 若当前没有触控,则退出编辑态
|
|
871
|
-
if (!inputManager.isPointerHeldDown() && !inputManager.isKeyHeldDown()) {
|
|
872
|
-
this.inEditing = false;
|
|
873
|
-
}
|
|
874
|
-
const { _inEditing: inEditing } = this;
|
|
875
|
-
const { _tempVec2: delta } = this;
|
|
876
|
-
let controlEvent = ControlEvent.Default;
|
|
877
|
-
|
|
878
|
-
// wheel
|
|
879
|
-
const wheelDelta = inputManager.wheelDelta;
|
|
880
|
-
if (wheelDelta.x !== 0 || wheelDelta.y !== 0 || wheelDelta.z !== 0) {
|
|
881
|
-
controlEvent = ControlEvent.Zoom;
|
|
882
|
-
this._zoom(wheelDelta);
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
// keyboard event
|
|
886
|
-
delta.x = delta.y = 0;
|
|
887
|
-
if (inputManager.isKeyHeldDown(Keys.ArrowLeft)) {
|
|
888
|
-
delta.x += this.movementSpeed;
|
|
889
|
-
controlEvent = ControlEvent.Pan;
|
|
890
|
-
this._pan(delta);
|
|
891
|
-
} else if (inputManager.isKeyHeldDown(Keys.ArrowRight)) {
|
|
892
|
-
delta.x -= this.movementSpeed;
|
|
893
|
-
controlEvent = ControlEvent.Pan;
|
|
894
|
-
this._pan(delta);
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
if (inputManager.isKeyHeldDown(Keys.ArrowDown)) {
|
|
898
|
-
delta.y -= this.movementSpeed;
|
|
899
|
-
controlEvent = ControlEvent.Pan;
|
|
900
|
-
this._pan(delta);
|
|
901
|
-
} else if (inputManager.isKeyHeldDown(Keys.ArrowUp)) {
|
|
902
|
-
delta.y += this.movementSpeed;
|
|
903
|
-
controlEvent = ControlEvent.Pan;
|
|
904
|
-
this._pan(delta);
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
// pointer event
|
|
908
|
-
if (inEditing) {
|
|
909
|
-
const primaryDown = inputManager.isPointerHeldDown(PointerButton.Primary);
|
|
910
|
-
const secondaryDown = inputManager.isPointerHeldDown(PointerButton.Secondary);
|
|
911
|
-
const auxiliaryDown = inputManager.isPointerHeldDown(PointerButton.Auxiliary);
|
|
912
|
-
|
|
913
|
-
const altDown = this._isAltDown;
|
|
914
|
-
const metaDown = inputManager.isKeyHeldDown(Keys.MetaLeft) || inputManager.isKeyHeldDown(Keys.MetaRight);
|
|
915
|
-
const onlyPrimaryDown = primaryDown && !secondaryDown;
|
|
916
|
-
const bothDown = primaryDown && secondaryDown;
|
|
917
|
-
|
|
918
|
-
const deltaPosition = inputManager.pointers[0]?.deltaPosition || delta;
|
|
919
|
-
|
|
920
|
-
if ((altDown && metaDown && onlyPrimaryDown) || bothDown) {
|
|
921
|
-
controlEvent = ControlEvent.Zoom;
|
|
922
|
-
this._zoom(deltaPosition);
|
|
923
|
-
} else if (onlyPrimaryDown || (!altDown && metaDown && onlyPrimaryDown) || auxiliaryDown) {
|
|
924
|
-
controlEvent = ControlEvent.Pan;
|
|
925
|
-
this._pan(deltaPosition);
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
this._transformDirty && this._updateTransform();
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
private _zoom(delta: Vector2 | Vector3): void {
|
|
933
|
-
const scaleFactor = Math.pow(0.96, this.zoomSpeed);
|
|
934
|
-
if (delta.y > 0) {
|
|
935
|
-
this._scale /= scaleFactor;
|
|
936
|
-
this._realScale++;
|
|
937
|
-
} else if (delta.y < 0) {
|
|
938
|
-
this._scale *= scaleFactor;
|
|
939
|
-
this._realScale--;
|
|
940
|
-
}
|
|
941
|
-
this._updateZoomScaleUnit();
|
|
942
|
-
this._transformDirty = true;
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
private _updateZoomScaleUnit(): void {
|
|
946
|
-
const realScale = Math.abs(this._realScale);
|
|
947
|
-
if (realScale < 25) {
|
|
948
|
-
this._zoomScaleUnit = 3;
|
|
949
|
-
} else if (realScale < 50) {
|
|
950
|
-
this._zoomScaleUnit = 2.8;
|
|
951
|
-
} else {
|
|
952
|
-
this._zoomScaleUnit = 2.6;
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
private _pan(moveDelta: Vector2): void {
|
|
957
|
-
this._panOffset.copyFrom(moveDelta);
|
|
958
|
-
|
|
959
|
-
this._transformDirty = true;
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
private _updateTransform(): void {
|
|
963
|
-
const { cameraTransform, camera, _panOffset } = this;
|
|
964
|
-
|
|
965
|
-
// Update Zoom
|
|
966
|
-
const sizeDiff = this._zoomScaleUnit * Math.log1p(camera.orthographicSize) * (this._scale - 1);
|
|
967
|
-
const size = camera.orthographicSize + sizeDiff;
|
|
968
|
-
camera.orthographicSize = Math.max(this.minZoom, Math.min(this.maxZoom, size));
|
|
969
|
-
|
|
970
|
-
// Update X and Y
|
|
971
|
-
const { width, height } = this.canvas;
|
|
972
|
-
const { x, y } = _panOffset;
|
|
973
|
-
const doubleOrthographicSize = camera.orthographicSize * 2;
|
|
974
|
-
const width3D = doubleOrthographicSize * camera.aspectRatio;
|
|
975
|
-
const height3D = doubleOrthographicSize;
|
|
976
|
-
const cameraPosition = cameraTransform.position;
|
|
977
|
-
const curPosition = this._tempVec3;
|
|
978
|
-
curPosition.x = cameraPosition.x - (x * width3D) / width;
|
|
979
|
-
curPosition.y = cameraPosition.y + (y * height3D) / height;
|
|
980
|
-
curPosition.z = cameraPosition.z;
|
|
981
|
-
|
|
982
|
-
// Update camera transform
|
|
983
|
-
cameraTransform.position = curPosition;
|
|
984
|
-
/** Reset cache value. */
|
|
985
|
-
this._scale = 1;
|
|
986
|
-
_panOffset.set(0, 0);
|
|
987
|
-
this._transformDirty = false;
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
onDestroy() {
|
|
991
|
-
document.removeEventListener("keydown", this.checkAltPressed);
|
|
992
|
-
document.removeEventListener("keyup", this.checkAltPressed);
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
<% } %>
|
|
996
|
-
|
|
997
|
-
<% if(debug.stats || debug.godMode) { %>
|
|
998
|
-
// toggle stats display
|
|
999
|
-
let _statsComponent = null;
|
|
1000
|
-
let _inGodMode = false;
|
|
1001
|
-
const debugChannel = new BroadcastChannel('Galacean_Editor_Channel');
|
|
1002
|
-
|
|
1003
|
-
const __defaultClipPlane__ = {
|
|
1004
|
-
near: 0,
|
|
1005
|
-
far: 0,
|
|
1006
|
-
};
|
|
1007
|
-
|
|
1008
|
-
const __debugClipPlane__ = {
|
|
1009
|
-
near: 0.03,
|
|
1010
|
-
far: 10000,
|
|
1011
|
-
};
|
|
1012
|
-
|
|
1013
|
-
const onGodModeChange = (inGodMode: boolean) => {
|
|
1014
|
-
const _activeCameras = engine.sceneManager.activeScene._componentsManager._activeCameras;
|
|
1015
|
-
if (_activeCameras.length === 0) return;
|
|
1016
|
-
|
|
1017
|
-
const defaultActiveCamera = _activeCameras.get(0);
|
|
1018
|
-
const defaultActiveCameraEntity = defaultActiveCamera.entity;
|
|
1019
|
-
|
|
1020
|
-
__defaultClipPlane__.near = defaultActiveCamera.nearClipPlane;
|
|
1021
|
-
__defaultClipPlane__.far = defaultActiveCamera.farClipPlane;
|
|
1022
|
-
|
|
1023
|
-
if (!defaultActiveCameraEntity) return;
|
|
1024
|
-
const controlType = defaultActiveCamera.isOrthographic ? OrthoControl : OrbitControl;
|
|
1025
|
-
const control = defaultActiveCameraEntity.getComponent(controlType);
|
|
1026
|
-
if(inGodMode && !control) {
|
|
1027
|
-
defaultActiveCameraEntity.addComponent(controlType);
|
|
1028
|
-
defaultActiveCamera.nearClipPlane = __debugClipPlane__.near;
|
|
1029
|
-
defaultActiveCamera.farClipPlane = __debugClipPlane__.far;
|
|
1030
|
-
} else if(!inGodMode && control) {
|
|
1031
|
-
control.destroy(true);
|
|
1032
|
-
defaultActiveCamera.nearClipPlane = __defaultClipPlane__.near;
|
|
1033
|
-
defaultActiveCamera.farClipPlane = __defaultClipPlane__.far;
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
onGodModeChange(_inGodMode);
|
|
1038
|
-
|
|
1039
|
-
debugChannel.addEventListener("message", (e) => {
|
|
1040
|
-
if (!(e.data && typeof e.data === 'object')) return;
|
|
1041
|
-
|
|
1042
|
-
const type = e.data.type;
|
|
1043
|
-
|
|
1044
|
-
if (type === 'toggle-stats-visible') {
|
|
1045
|
-
if (!_statsComponent) {
|
|
1046
|
-
_statsComponent = engine.sceneManager.activeScene._componentsManager._activeCameras.get(0).entity.addComponent(Stats);
|
|
1047
|
-
}
|
|
1048
|
-
const value = e.data.payload;
|
|
1049
|
-
if(value) {
|
|
1050
|
-
_statsComponent.enabled = true;
|
|
1051
|
-
} else {
|
|
1052
|
-
_statsComponent.enabled = false;
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
if(type === 'toggle-god-mode') {
|
|
1057
|
-
onGodModeChange(_inGodMode = e.data.payload);
|
|
1058
|
-
}
|
|
1059
|
-
});
|
|
1060
|
-
<% } %>
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
engine.run();
|
|
1064
|
-
return engine;
|
|
1065
|
-
};
|