@needle-tools/engine 2.61.0-pre → 2.62.2-pre
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/CHANGELOG.md +24 -0
- package/dist/needle-engine.js +25826 -25563
- package/dist/needle-engine.umd.cjs +244 -246
- package/lib/engine/api.d.ts +1 -0
- package/lib/engine/api.js +1 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/debug/debug_overlay.js +9 -9
- package/lib/engine/debug/debug_overlay.js.map +1 -1
- package/lib/engine/engine.js +0 -2
- package/lib/engine/engine.js.map +1 -1
- package/lib/engine/engine_addressables.js +16 -5
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_camera.d.ts +4 -0
- package/lib/engine/engine_camera.js +13 -0
- package/lib/engine/engine_camera.js.map +1 -0
- package/lib/engine/engine_element.d.ts +1 -0
- package/lib/engine/engine_element.js +17 -1
- package/lib/engine/engine_element.js.map +1 -1
- package/lib/engine/engine_input.d.ts +2 -0
- package/lib/engine/engine_input.js +14 -0
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_loaders.d.ts +1 -0
- package/lib/engine/engine_loaders.js +12 -0
- package/lib/engine/engine_loaders.js.map +1 -1
- package/lib/engine/engine_setup.js +1 -1
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_types.d.ts +4 -0
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine/extensions/extension_utils.js +1 -1
- package/lib/engine/extensions/extension_utils.js.map +1 -1
- package/lib/engine/js-extensions/Camera.d.ts +1 -0
- package/lib/engine/js-extensions/Camera.js +37 -0
- package/lib/engine/js-extensions/Camera.js.map +1 -0
- package/lib/engine/js-extensions/Layers.js +1 -0
- package/lib/engine/js-extensions/Layers.js.map +1 -1
- package/lib/engine/js-extensions/index.d.ts +2 -0
- package/lib/engine/js-extensions/index.js +3 -0
- package/lib/engine/js-extensions/index.js.map +1 -0
- package/lib/engine-components/Animation.js +12 -3
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/CameraUtils.d.ts +1 -3
- package/lib/engine-components/CameraUtils.js +34 -17
- package/lib/engine-components/CameraUtils.js.map +1 -1
- package/lib/engine-components/Light.d.ts +4 -1
- package/lib/engine-components/Light.js +17 -2
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +4 -1
- package/lib/engine-components/OrbitControls.js +13 -2
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/timeline/PlayableDirector.js +27 -17
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/timeline/TimelineTracks.js +7 -1
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/engine-components/ui/BaseUIComponent.d.ts +3 -0
- package/lib/engine-components/ui/BaseUIComponent.js +20 -10
- package/lib/engine-components/ui/BaseUIComponent.js.map +1 -1
- package/lib/engine-components/ui/Button.js +7 -3
- package/lib/engine-components/ui/Button.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.js +23 -42
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/lib/engine-components/ui/Graphic.d.ts +1 -0
- package/lib/engine-components/ui/Graphic.js +7 -0
- package/lib/engine-components/ui/Graphic.js.map +1 -1
- package/lib/engine-components/ui/Interfaces.d.ts +2 -1
- package/lib/engine-components/ui/RaycastUtils.js +2 -0
- package/lib/engine-components/ui/RaycastUtils.js.map +1 -1
- package/lib/engine-components/ui/Text.js +11 -1
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/needle-engine.d.ts +1 -0
- package/lib/needle-engine.js +1 -2
- package/lib/needle-engine.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/engine/api.ts +2 -1
- package/src/engine/debug/debug_overlay.ts +9 -9
- package/src/engine/engine.ts +0 -3
- package/src/engine/engine_addressables.ts +13 -5
- package/src/engine/engine_camera.ts +18 -0
- package/src/engine/engine_element.ts +17 -1
- package/src/engine/engine_input.ts +17 -5
- package/src/engine/engine_loaders.ts +13 -0
- package/src/engine/engine_setup.ts +2 -1
- package/src/engine/engine_types.ts +9 -4
- package/src/engine/extensions/extension_utils.ts +1 -1
- package/src/engine/js-extensions/Camera.ts +35 -0
- package/src/engine/js-extensions/Layers.ts +2 -1
- package/src/engine/js-extensions/index.ts +2 -0
- package/src/engine-components/Animation.ts +11 -3
- package/src/engine-components/CameraUtils.ts +42 -20
- package/src/engine-components/Light.ts +16 -3
- package/src/engine-components/OrbitControls.ts +18 -6
- package/src/engine-components/timeline/PlayableDirector.ts +25 -17
- package/src/engine-components/timeline/TimelineTracks.ts +9 -3
- package/src/engine-components/ui/BaseUIComponent.ts +21 -11
- package/src/engine-components/ui/Button.ts +7 -3
- package/src/engine-components/ui/EventSystem.ts +22 -42
- package/src/engine-components/ui/Graphic.ts +7 -0
- package/src/engine-components/ui/Interfaces.ts +3 -1
- package/src/engine-components/ui/RaycastUtils.ts +2 -1
- package/src/engine-components/ui/Text.ts +13 -2
- package/src/needle-engine.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.62.2-pre",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally.",
|
|
5
5
|
"main": "dist/needle-engine.umd.cjs",
|
|
6
6
|
"module": "dist/needle-engine.js",
|
package/src/engine/api.ts
CHANGED
|
@@ -115,39 +115,37 @@ const logsContainerStyles = `
|
|
|
115
115
|
|
|
116
116
|
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
div {
|
|
118
|
+
div[data-needle_engine_debug_overlay] {
|
|
120
119
|
font-family: 'Roboto', sans-serif;
|
|
121
120
|
font-weight: 400;
|
|
122
121
|
}
|
|
123
122
|
|
|
124
|
-
strong {
|
|
123
|
+
div[data-needle_engine_debug_overlay] strong {
|
|
125
124
|
font-weight: 700;
|
|
126
125
|
}
|
|
127
126
|
|
|
128
|
-
a {
|
|
127
|
+
div[data-needle_engine_debug_overlay] a {
|
|
129
128
|
color: white;
|
|
130
129
|
text-decoration: none;
|
|
131
130
|
border-bottom: 1px solid rgba(255, 255, 255, 0.3);
|
|
132
131
|
}
|
|
133
132
|
|
|
134
|
-
a:hover {
|
|
133
|
+
div[data-needle_engine_debug_overlay] a:hover {
|
|
135
134
|
text-decoration: none;
|
|
136
135
|
border: none;
|
|
137
136
|
}
|
|
138
137
|
|
|
139
|
-
.log strong {
|
|
138
|
+
div[data-needle_engine_debug_overlay] .log strong {
|
|
140
139
|
color: rgba(200,200,200,.9);
|
|
141
140
|
}
|
|
142
141
|
|
|
143
|
-
.warn strong {
|
|
142
|
+
div[data-needle_engine_debug_overlay] .warn strong {
|
|
144
143
|
color: rgba(255,255,230, 1);
|
|
145
144
|
}
|
|
146
145
|
|
|
147
|
-
.error strong {
|
|
146
|
+
div[data-needle_engine_debug_overlay] .error strong {
|
|
148
147
|
color: rgba(255,100,120, 1);
|
|
149
148
|
}
|
|
150
|
-
|
|
151
149
|
`;
|
|
152
150
|
|
|
153
151
|
function getLogsContainer(domElement: HTMLElement): HTMLElement {
|
|
@@ -155,6 +153,7 @@ function getLogsContainer(domElement: HTMLElement): HTMLElement {
|
|
|
155
153
|
return errorContainer.get(domElement)!;
|
|
156
154
|
} else {
|
|
157
155
|
const container = document.createElement("div");
|
|
156
|
+
container.setAttribute("data-needle_engine_debug_overlay", "");
|
|
158
157
|
container.classList.add(arContainerClassName);
|
|
159
158
|
container.classList.add("desktop");
|
|
160
159
|
container.classList.add("debug-container");
|
|
@@ -206,6 +205,7 @@ function getMessageContainer(type: LogType, msg: string): HTMLElement {
|
|
|
206
205
|
}
|
|
207
206
|
}
|
|
208
207
|
const element = document.createElement("div");
|
|
208
|
+
element.setAttribute("data-id", "__needle_engine_debug_overlay");
|
|
209
209
|
element.style.marginRight = "5px";
|
|
210
210
|
element.style.padding = ".5em";
|
|
211
211
|
element.style.backgroundColor = "rgba(0,0,0,.9)";
|
package/src/engine/engine.ts
CHANGED
|
@@ -60,7 +60,7 @@ export class AssetReference {
|
|
|
60
60
|
return ref;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
private static currentlyInstantiating: string
|
|
63
|
+
private static currentlyInstantiating: Map<string, number> = new Map<string, number>();
|
|
64
64
|
|
|
65
65
|
get asset(): any {
|
|
66
66
|
return this._glbRoot ?? this._asset;
|
|
@@ -236,12 +236,16 @@ export class AssetReference {
|
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
let count = AssetReference.currentlyInstantiating.get(this.uri);
|
|
240
|
+
// allow up to 100 instantiations of the same prefab in the same frame
|
|
241
|
+
if (count !== undefined && count >= 100) {
|
|
242
|
+
console.error("Recursive or too many instantiations of " + this.uri + " in the same frame (" + count + ")");
|
|
241
243
|
return null;
|
|
242
244
|
}
|
|
243
245
|
try {
|
|
244
|
-
|
|
246
|
+
if (count === undefined) count = 0;
|
|
247
|
+
count += 1;
|
|
248
|
+
AssetReference.currentlyInstantiating.set(this.uri, count);
|
|
245
249
|
if (networked) {
|
|
246
250
|
options.context = context;
|
|
247
251
|
const prefab = this.asset;
|
|
@@ -259,7 +263,11 @@ export class AssetReference {
|
|
|
259
263
|
}
|
|
260
264
|
}
|
|
261
265
|
finally {
|
|
262
|
-
context.post_render_callbacks.push(() =>
|
|
266
|
+
context.post_render_callbacks.push(() => {
|
|
267
|
+
if (count === undefined || count < 0) count = 0;
|
|
268
|
+
else count -= 1;
|
|
269
|
+
AssetReference.currentlyInstantiating.set(this.uri, count)
|
|
270
|
+
});
|
|
263
271
|
}
|
|
264
272
|
|
|
265
273
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ICameraController } from "./engine_types";
|
|
2
|
+
import { Camera } from "three";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const $cameraController = Symbol("cameraController");
|
|
6
|
+
|
|
7
|
+
export function getCameraController(cam: Camera): ICameraController | null {
|
|
8
|
+
return cam[$cameraController];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function setCameraController(cam: Camera, cameraController: ICameraController, active: boolean) {
|
|
12
|
+
if (active)
|
|
13
|
+
cam[$cameraController] = cameraController;
|
|
14
|
+
else{
|
|
15
|
+
if(cam[$cameraController] === cameraController)
|
|
16
|
+
cam[$cameraController] = null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -79,6 +79,12 @@ export class EngineElement extends HTMLElement implements INeedleEngineComponent
|
|
|
79
79
|
public get loadingProgress01(): number { return this._loadingProgress01; }
|
|
80
80
|
public get loadingFinished(): boolean { return this.loadingProgress01 > .999; }
|
|
81
81
|
|
|
82
|
+
public get cameraControls(): boolean {
|
|
83
|
+
const attr = this.getAttribute("camera-controls");
|
|
84
|
+
if(attr === null || attr === "False" || attr === "false" || attr === "0") return false;
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
82
88
|
public getContext(): Promise<Context> {
|
|
83
89
|
return new Promise((res, _rej) => {
|
|
84
90
|
if (this._context && this.loadingFinished) {
|
|
@@ -237,7 +243,17 @@ export class EngineElement extends HTMLElement implements INeedleEngineComponent
|
|
|
237
243
|
}
|
|
238
244
|
|
|
239
245
|
static get observedAttributes() {
|
|
240
|
-
return [
|
|
246
|
+
return [
|
|
247
|
+
"hash",
|
|
248
|
+
"src",
|
|
249
|
+
"camera-controls",
|
|
250
|
+
"loadstart",
|
|
251
|
+
"progress",
|
|
252
|
+
"loadfinished",
|
|
253
|
+
"dracoDecoderPath",
|
|
254
|
+
"dracoDecoderType",
|
|
255
|
+
"ktx2DecoderPath"
|
|
256
|
+
];
|
|
241
257
|
}
|
|
242
258
|
|
|
243
259
|
attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
|
|
@@ -220,6 +220,7 @@ export class Input extends EventTarget {
|
|
|
220
220
|
private _pointerPositionDown: THREE.Vector2[] = [new THREE.Vector2()];
|
|
221
221
|
private _pointerDownTime: number[] = [];
|
|
222
222
|
private _pointerUpTime: number[] = [];
|
|
223
|
+
private _pointerUpTimestamp: number[] = [];
|
|
223
224
|
private _pointerIds: number[] = [];
|
|
224
225
|
private _pointerTypes: string[] = [""];
|
|
225
226
|
private _mouseWheelChanged: boolean[] = [false];
|
|
@@ -411,13 +412,15 @@ export class Input extends EventTarget {
|
|
|
411
412
|
}
|
|
412
413
|
}
|
|
413
414
|
|
|
414
|
-
private onTouchUp(evt) {
|
|
415
|
+
private onTouchUp(evt: TouchEvent) {
|
|
415
416
|
if (evt.changedTouches.length <= 0) return;
|
|
416
417
|
for (let i = 0; i < evt.changedTouches.length; i++) {
|
|
417
418
|
const touch = evt.changedTouches[i];
|
|
418
|
-
const id = this.getPointerIndex(touch.identifier)
|
|
419
|
-
|
|
420
|
-
|
|
419
|
+
const id = this.getPointerIndex(touch.identifier);
|
|
420
|
+
|
|
421
|
+
if (!this.isNewEvent(evt.timeStamp, id, this._pointerUpTimestamp)) continue;
|
|
422
|
+
|
|
423
|
+
if (debug) showBalloonMessage(`touch up #${id}, identifier:${touch.identifier}`);
|
|
421
424
|
const args: PointerEventArgs = { button: id, clientX: touch.clientX, clientY: touch.clientY, pointerType: PointerType.Touch, source: evt };
|
|
422
425
|
this.onUp(args);
|
|
423
426
|
}
|
|
@@ -440,11 +443,20 @@ export class Input extends EventTarget {
|
|
|
440
443
|
private onMouseUp(evt: MouseEvent) {
|
|
441
444
|
if (evt.defaultPrevented) return;
|
|
442
445
|
let i = evt.button;
|
|
446
|
+
if (!this.isNewEvent(evt.timeStamp, i, this._pointerUpTimestamp)) return;
|
|
443
447
|
this.onUp({ button: i, clientX: evt.clientX, clientY: evt.clientY, pointerType: PointerType.Mouse, source: evt });
|
|
444
448
|
}
|
|
445
449
|
|
|
450
|
+
// Prevent the same event being handled twice (e.g. on touch we get a mouseUp and touchUp evt with the same timestamp)
|
|
451
|
+
private isNewEvent(timestamp: number, index: number, arr: number[]): boolean {
|
|
452
|
+
while (arr.length <= index) arr.push(-1);
|
|
453
|
+
if (timestamp === arr[index]) return false;
|
|
454
|
+
arr[index] = timestamp;
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
|
|
446
458
|
private isInRect(e: { clientX: number, clientY: number }): boolean {
|
|
447
|
-
if(this.context.isInXR) return true;
|
|
459
|
+
if (this.context.isInXR) return true;
|
|
448
460
|
const rect = this.context.domElement.getBoundingClientRect();
|
|
449
461
|
const px = e.clientX;
|
|
450
462
|
const py = e.clientY;
|
|
@@ -3,6 +3,8 @@ import { Context } from "./engine_setup"
|
|
|
3
3
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
|
|
4
4
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
5
5
|
import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
|
|
6
|
+
import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js';
|
|
7
|
+
|
|
6
8
|
import { getParam } from "./engine_utils";
|
|
7
9
|
|
|
8
10
|
const debug = getParam("debugdecoders");
|
|
@@ -11,6 +13,7 @@ const DEFAULT_DRACO_DECODER_LOCATION ='https://www.gstatic.com/draco/versioned/d
|
|
|
11
13
|
const DEFAULT_KTX2_TRANSCODER_LOCATION ='https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/';
|
|
12
14
|
|
|
13
15
|
let dracoLoader: DRACOLoader;
|
|
16
|
+
let meshoptDecoder: MeshoptDecoder;
|
|
14
17
|
let ktx2Loader: KTX2Loader;
|
|
15
18
|
|
|
16
19
|
export function setDracoDecoderPath(path: string | undefined) {
|
|
@@ -40,6 +43,11 @@ export function setKtx2TranscoderPath(path: string) {
|
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
45
|
|
|
46
|
+
export function setMeshoptDecoder(_meshoptDecoder: any) {
|
|
47
|
+
if (_meshoptDecoder !== undefined)
|
|
48
|
+
meshoptDecoder = _meshoptDecoder;
|
|
49
|
+
}
|
|
50
|
+
|
|
43
51
|
export function addDracoAndKTX2Loaders(loader: GLTFLoader, context: Context) {
|
|
44
52
|
if (!dracoLoader) {
|
|
45
53
|
dracoLoader = new DRACOLoader();
|
|
@@ -54,7 +62,12 @@ export function addDracoAndKTX2Loaders(loader: GLTFLoader, context: Context) {
|
|
|
54
62
|
if (context.renderer)
|
|
55
63
|
ktx2Loader.detectSupport(context.renderer);
|
|
56
64
|
}
|
|
65
|
+
if (!meshoptDecoder) {
|
|
66
|
+
meshoptDecoder = MeshoptDecoder;
|
|
67
|
+
if (debug) console.log("Using the default meshopt decoder");
|
|
68
|
+
}
|
|
57
69
|
|
|
58
70
|
loader.setDRACOLoader(dracoLoader);
|
|
59
71
|
loader.setKTX2Loader(ktx2Loader);
|
|
72
|
+
loader.setMeshoptDecoder(meshoptDecoder);
|
|
60
73
|
}
|
|
@@ -504,7 +504,6 @@ export class Context implements IContext {
|
|
|
504
504
|
this.domElement.prepend(this.renderer.domElement);
|
|
505
505
|
|
|
506
506
|
Context._current = this;
|
|
507
|
-
ContextRegistry.dispatchCallback(ContextEvent.ContextCreated, this);
|
|
508
507
|
|
|
509
508
|
// Setup
|
|
510
509
|
Context._current = this;
|
|
@@ -591,6 +590,8 @@ export class Context implements IContext {
|
|
|
591
590
|
|
|
592
591
|
if (debug)
|
|
593
592
|
logHierarchy(this.scene, true);
|
|
593
|
+
|
|
594
|
+
ContextRegistry.dispatchCallback(ContextEvent.ContextCreated, this);
|
|
594
595
|
}
|
|
595
596
|
|
|
596
597
|
private render(_, frame) {
|
|
@@ -30,10 +30,11 @@ export declare type CoroutineData = {
|
|
|
30
30
|
export interface IContext {
|
|
31
31
|
alias?: string | null;
|
|
32
32
|
|
|
33
|
-
scene
|
|
34
|
-
renderer
|
|
35
|
-
mainCamera
|
|
36
|
-
|
|
33
|
+
scene: Scene;
|
|
34
|
+
renderer: WebGLRenderer;
|
|
35
|
+
mainCamera: Camera | null;
|
|
36
|
+
mainCameraComponent: ICamera | undefined;
|
|
37
|
+
domElement: HTMLElement;
|
|
37
38
|
|
|
38
39
|
scripts: IComponent[];
|
|
39
40
|
scripts_pausedChanged: IComponent[];
|
|
@@ -158,6 +159,10 @@ export declare interface ICamera extends IComponent {
|
|
|
158
159
|
screenPointToRay(x: number, y: number, ray?: Ray): Ray;
|
|
159
160
|
}
|
|
160
161
|
|
|
162
|
+
export declare interface ICameraController {
|
|
163
|
+
get isCameraController(): boolean;
|
|
164
|
+
}
|
|
165
|
+
|
|
161
166
|
export declare interface ILight extends IComponent {
|
|
162
167
|
intensity: number;
|
|
163
168
|
color: Color;
|
|
@@ -43,7 +43,7 @@ function internalResolve(paths: DependencyInfo[], parser: GLTFParser, obj, promi
|
|
|
43
43
|
// handle json pointer in string variable
|
|
44
44
|
if (typeof val === "string") {
|
|
45
45
|
const ext = resolveExtension(parser, val);
|
|
46
|
-
if (ext !== null) {
|
|
46
|
+
if (ext !== null && ext !== undefined) {
|
|
47
47
|
if (typeof ext.then === "function")
|
|
48
48
|
promises.push(ext.then(res => obj[key] = res));
|
|
49
49
|
else obj[key] = ext;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { PerspectiveCamera } from "three";
|
|
2
|
+
|
|
3
|
+
// Wrap camera FOV to allow animation of fov
|
|
4
|
+
Object.defineProperty(PerspectiveCamera.prototype, "fov", {
|
|
5
|
+
get: function () {
|
|
6
|
+
return this._fov;;
|
|
7
|
+
},
|
|
8
|
+
set: function (val) {
|
|
9
|
+
const changed = val !== this._fov;
|
|
10
|
+
this._fov = val;
|
|
11
|
+
if (changed && this.view !== undefined) this.updateProjectionMatrix();
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
Object.defineProperty(PerspectiveCamera.prototype, "near", {
|
|
16
|
+
get: function () {
|
|
17
|
+
return this._near;
|
|
18
|
+
},
|
|
19
|
+
set: function (val) {
|
|
20
|
+
const changed = val !== this._near;
|
|
21
|
+
this._near = val;
|
|
22
|
+
if (changed && this.view !== undefined) this.updateProjectionMatrix();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
Object.defineProperty(PerspectiveCamera.prototype, "far", {
|
|
27
|
+
get: function () {
|
|
28
|
+
return this._far;
|
|
29
|
+
},
|
|
30
|
+
set: function (val) {
|
|
31
|
+
const changed = val !== this._far;
|
|
32
|
+
this._far = val;
|
|
33
|
+
if (changed && this.view !== undefined) this.updateProjectionMatrix();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
@@ -145,12 +145,19 @@ export class Animation extends Behaviour {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
play(clipOrNumber: AnimationClip | number | string | undefined, options?: PlayOptions): Promise<AnimationAction> | void {
|
|
148
|
+
if (debug) console.log("PLAY", clipOrNumber)
|
|
148
149
|
this.init();
|
|
149
|
-
if (!this.mixer)
|
|
150
|
+
if (!this.mixer) {
|
|
151
|
+
if (debug) console.warn("Missing mixer", this);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
150
154
|
if (clipOrNumber === undefined) clipOrNumber = 0;
|
|
151
155
|
let clip: AnimationClip | undefined = clipOrNumber as AnimationClip;
|
|
152
156
|
if (typeof clipOrNumber === 'number') {
|
|
153
|
-
if (clipOrNumber >= this.animations.length)
|
|
157
|
+
if (clipOrNumber >= this.animations.length) {
|
|
158
|
+
if (debug) console.log("No animation at index", clipOrNumber)
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
154
161
|
clip = this.animations[clipOrNumber];
|
|
155
162
|
}
|
|
156
163
|
else if (typeof clipOrNumber === "string") {
|
|
@@ -205,7 +212,8 @@ export class Animation extends Behaviour {
|
|
|
205
212
|
action.loop = options.loop ? THREE.LoopRepeat : THREE.LoopOnce;
|
|
206
213
|
else action.loop = THREE.LoopOnce;
|
|
207
214
|
action.play();
|
|
208
|
-
|
|
215
|
+
if (debug)
|
|
216
|
+
console.log("PLAY", action.getClip().name, action)
|
|
209
217
|
|
|
210
218
|
const handle = new AnimationHandle(action, this.mixer!, options, _ => {
|
|
211
219
|
this._handles.splice(this._handles.indexOf(handle), 1);
|
|
@@ -1,32 +1,54 @@
|
|
|
1
1
|
import { OrbitControls } from "./OrbitControls";
|
|
2
|
-
import { Camera } from "./Camera";
|
|
3
2
|
import { addNewComponent } from "../engine/engine_components";
|
|
4
|
-
import {
|
|
5
|
-
import { ICamera
|
|
6
|
-
import { lookAtInverse } from "../engine/engine_three_utils";
|
|
3
|
+
import { Object3D } from "three";
|
|
4
|
+
import { ICamera } from "../engine/engine_types";
|
|
7
5
|
import { RGBAColor } from "./js-extensions/RGBAColor";
|
|
8
6
|
import { ContextEvent, ContextRegistry } from "../engine/engine_context_registry";
|
|
9
|
-
|
|
7
|
+
import { getCameraController } from "../engine/engine_camera";
|
|
8
|
+
import { Camera } from "./Camera";
|
|
9
|
+
import { EngineElement } from "../engine/engine_element";
|
|
10
10
|
|
|
11
11
|
ContextRegistry.registerCallback(ContextEvent.MissingCamera, (evt) => {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
const scene = evt.context.scene;
|
|
13
|
+
const srcId = "unknown";
|
|
14
14
|
|
|
15
|
+
const cameraObject = new Object3D();
|
|
16
|
+
scene.add(cameraObject);
|
|
15
17
|
|
|
16
|
-
export function createCameraWithOrbitControl(scene: Scene, source: SourceIdentifier): ICamera {
|
|
17
|
-
const srcId = source;
|
|
18
|
-
const go = new Object3D();
|
|
19
|
-
scene.add(go);
|
|
20
18
|
const camInstance = new Camera();
|
|
21
|
-
const cam = addNewComponent(
|
|
19
|
+
const cam = addNewComponent(cameraObject, camInstance, true) as ICamera
|
|
22
20
|
cam.sourceId = srcId;
|
|
23
21
|
cam.clearFlags = 2;
|
|
24
22
|
cam.backgroundColor = new RGBAColor(0.5, 0.5, 0.5, 1);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
|
|
24
|
+
cameraObject.position.x = -2;
|
|
25
|
+
cameraObject.position.y = 2;
|
|
26
|
+
cameraObject.position.z = 2;
|
|
27
|
+
return cam;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
ContextRegistry.registerCallback(ContextEvent.ContextCreated, (evt) => {
|
|
31
|
+
if (!evt.context.mainCamera) return;
|
|
32
|
+
|
|
33
|
+
// check if the <needle-engine controls> is not set to false
|
|
34
|
+
const engineElement = evt.context.domElement as EngineElement
|
|
35
|
+
|
|
36
|
+
if (engineElement?.cameraControls === true) {
|
|
37
|
+
|
|
38
|
+
// Check if something else already acts as a camera controller
|
|
39
|
+
const existing = getCameraController(evt.context.mainCamera);
|
|
40
|
+
if (existing?.isCameraController === true) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const cam = evt.context.mainCameraComponent;
|
|
45
|
+
const cameraObject = cam?.gameObject;
|
|
46
|
+
if (cameraObject) {
|
|
47
|
+
const orbit = addNewComponent(cameraObject, new OrbitControls(), false) as OrbitControls;
|
|
48
|
+
orbit.sourceId = "unknown";
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.warn("Missing camera object, can not add orbit controls")
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
})
|
|
@@ -95,7 +95,17 @@ export class Light extends Behaviour implements ILight {
|
|
|
95
95
|
public innerSpotAngle: number = 1;
|
|
96
96
|
|
|
97
97
|
@serializable(Color)
|
|
98
|
-
|
|
98
|
+
set color(val: Color) {
|
|
99
|
+
this._color = val;
|
|
100
|
+
if (this.light !== undefined) {
|
|
101
|
+
this.light.color = val;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
get color(): Color {
|
|
105
|
+
if (this.light) return this.light.color;
|
|
106
|
+
return this._color;
|
|
107
|
+
}
|
|
108
|
+
public _color: THREE.Color = new THREE.Color(0xffffff);
|
|
99
109
|
|
|
100
110
|
@serializable()
|
|
101
111
|
set shadowNearPlane(val: number) {
|
|
@@ -242,13 +252,14 @@ export class Light extends Behaviour implements ILight {
|
|
|
242
252
|
|
|
243
253
|
awake() {
|
|
244
254
|
this.color = new THREE.Color(this.color ?? 0xffffff);
|
|
245
|
-
if(debug) console.log(this.name, this);
|
|
255
|
+
if (debug) console.log(this.name, this);
|
|
246
256
|
}
|
|
247
257
|
|
|
248
258
|
onEnable(): void {
|
|
249
259
|
this.createLight();
|
|
250
260
|
if (this.isBaked) return;
|
|
251
261
|
else if (this.light) {
|
|
262
|
+
this.light.visible = true;
|
|
252
263
|
if (this.selfIsLight) {
|
|
253
264
|
// nothing to do
|
|
254
265
|
}
|
|
@@ -257,12 +268,14 @@ export class Light extends Behaviour implements ILight {
|
|
|
257
268
|
}
|
|
258
269
|
if (this.type === LightType.Directional)
|
|
259
270
|
this.startCoroutine(this.updateMainLightRoutine(), FrameEvent.LateUpdate);
|
|
260
|
-
|
|
261
271
|
this._webXRStartedListener = WebXR.addEventListener(WebXREvent.XRStarted, this.onWebXRStarted.bind(this));
|
|
262
272
|
this._webXREndedListener = WebXR.addEventListener(WebXREvent.XRStopped, this.onWebXREnded.bind(this));
|
|
263
273
|
}
|
|
264
274
|
|
|
265
275
|
onDisable() {
|
|
276
|
+
if (this.light) {
|
|
277
|
+
this.light.visible = false;
|
|
278
|
+
}
|
|
266
279
|
WebXR.removeEventListener(WebXREvent.XRStarted, this._webXRStartedListener);
|
|
267
280
|
WebXR.removeEventListener(WebXREvent.XRStopped, this._webXREndedListener);
|
|
268
281
|
}
|
|
@@ -6,17 +6,23 @@ import { RaycastOptions } from "../engine/engine_physics";
|
|
|
6
6
|
import { serializable } from "../engine/engine_serialization_decorator";
|
|
7
7
|
import { getParam, isMobileDevice } from "../engine/engine_utils";
|
|
8
8
|
|
|
9
|
-
import { Box3, Object3D, PerspectiveCamera, Vector2, Vector3 } from "three";
|
|
9
|
+
import { Camera as ThreeCamera, Box3, Object3D, PerspectiveCamera, Vector2, Vector3 } from "three";
|
|
10
10
|
import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
|
11
11
|
import { EventSystem, EventSystemEvents } from "./ui/EventSystem";
|
|
12
|
-
import {
|
|
12
|
+
import { ICameraController } from "../engine/engine_types";
|
|
13
|
+
import { setCameraController } from "../engine/engine_camera";
|
|
13
14
|
|
|
14
15
|
const freeCam = getParam("freecam");
|
|
15
16
|
|
|
16
17
|
const disabledKeys = { LEFT: "", UP: "", RIGHT: "", BOTTOM: "" };
|
|
17
18
|
let defaultKeys: any = undefined;
|
|
18
19
|
|
|
19
|
-
export class OrbitControls extends Behaviour {
|
|
20
|
+
export class OrbitControls extends Behaviour implements ICameraController {
|
|
21
|
+
|
|
22
|
+
get isCameraController(): boolean {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
20
26
|
public get controls() {
|
|
21
27
|
return this._controls;
|
|
22
28
|
}
|
|
@@ -64,6 +70,7 @@ export class OrbitControls extends Behaviour {
|
|
|
64
70
|
|
|
65
71
|
private _eventSystem?: EventSystem;
|
|
66
72
|
private _afterHandleInputFn?: any;
|
|
73
|
+
private _camera : Camera | null = null;
|
|
67
74
|
|
|
68
75
|
targetElement: HTMLElement | null = null;
|
|
69
76
|
|
|
@@ -98,8 +105,10 @@ export class OrbitControls extends Behaviour {
|
|
|
98
105
|
|
|
99
106
|
onEnable() {
|
|
100
107
|
this._enableTime = this.context.time.time;
|
|
101
|
-
const
|
|
102
|
-
|
|
108
|
+
const cameraComponent = GameObject.getComponent(this.gameObject, Camera);
|
|
109
|
+
this._camera = cameraComponent;
|
|
110
|
+
const cam = cameraComponent?.cam;
|
|
111
|
+
if (cam) setCameraController(cam, this, true);
|
|
103
112
|
if (!this._controls) {
|
|
104
113
|
console.assert(cam !== null && cam !== undefined, "Missing camera", this);
|
|
105
114
|
if (cam)
|
|
@@ -153,6 +162,9 @@ export class OrbitControls extends Behaviour {
|
|
|
153
162
|
}
|
|
154
163
|
|
|
155
164
|
onDisable() {
|
|
165
|
+
if (this._camera?.cam) {
|
|
166
|
+
setCameraController(this._camera.cam, this, false);
|
|
167
|
+
}
|
|
156
168
|
if (this._controls) {
|
|
157
169
|
this._controls.enabled = false;
|
|
158
170
|
this._controls.autoRotate = false;
|
|
@@ -160,7 +172,7 @@ export class OrbitControls extends Behaviour {
|
|
|
160
172
|
}
|
|
161
173
|
}
|
|
162
174
|
|
|
163
|
-
private _shouldDisable
|
|
175
|
+
private _shouldDisable: boolean = false;
|
|
164
176
|
private afterHandleInput() {
|
|
165
177
|
if (this._controls && this._eventSystem) {
|
|
166
178
|
this._shouldDisable = this._eventSystem.hasActiveUI;
|