@@ -48,7 +48,7 @@
|
|
48
48
|
let code = readFileSync(mainTsFilePath, 'utf-8');
|
49
49
|
if (code.includes('import \"@needle-tools/engine\"')) {
|
50
50
|
console.log("Change main.ts and replace needle engine import with async import");
|
51
|
-
code = code.replace(/import \"@needle-tools\/engine\"/g, '
|
51
|
+
code = code.replace(/import \"@needle-tools\/engine\"/g, 'import("@needle-tools/engine") /* async import of needle engine */');
|
52
52
|
writeFileSync(mainTsFilePath, code);
|
53
53
|
}
|
54
54
|
}
|
@@ -3,6 +3,7 @@
|
|
3
3
|
import * as ThreeMeshUI from 'three-mesh-ui';
|
4
4
|
|
5
5
|
import { showGizmos } from '../../engine/engine_default_parameters.js';
|
6
|
+
import { ComponentInit } from '../../engine/engine_types.js';
|
6
7
|
import { getParam } from '../../engine/engine_utils.js';
|
7
8
|
import { Behaviour, GameObject } from "../Component.js";
|
8
9
|
import { EventSystem } from "./EventSystem.js";
|
@@ -78,11 +79,12 @@
|
|
78
79
|
// private _intermediate?: Object3D;
|
79
80
|
protected _parentComponent?: BaseUIComponent | null = undefined;
|
80
81
|
|
81
|
-
__internalNewInstanceCreated() {
|
82
|
-
super.__internalNewInstanceCreated();
|
82
|
+
__internalNewInstanceCreated(args: ComponentInit<this>) {
|
83
|
+
super.__internalNewInstanceCreated(args);
|
83
84
|
this.shadowComponent = null;
|
84
85
|
this._root = undefined;
|
85
86
|
this._parentComponent = undefined;
|
87
|
+
return this;
|
86
88
|
}
|
87
89
|
|
88
90
|
onEnable() {
|
@@ -146,7 +148,7 @@
|
|
146
148
|
if (needsUpdate)
|
147
149
|
ThreeMeshUI.update();
|
148
150
|
|
149
|
-
if(debug) console.log(this.shadowComponent)
|
151
|
+
if (debug) console.log(this.shadowComponent)
|
150
152
|
}
|
151
153
|
|
152
154
|
protected setShadowComponentOwner(current: ThreeMeshUI.MeshUIBaseElement | Object3D | null | undefined) {
|
@@ -7,6 +7,9 @@
|
|
7
7
|
|
8
8
|
export class Bloom extends PostProcessingEffect {
|
9
9
|
|
10
|
+
/** Whether to use selective bloom by default */
|
11
|
+
static useSelectiveBloom = false;
|
12
|
+
|
10
13
|
get typeName() {
|
11
14
|
return "Bloom";
|
12
15
|
}
|
@@ -18,7 +21,7 @@
|
|
18
21
|
@serializable(VolumeParameter)
|
19
22
|
scatter!: VolumeParameter;
|
20
23
|
|
21
|
-
selectiveBloom
|
24
|
+
selectiveBloom?: boolean;
|
22
25
|
|
23
26
|
init() {
|
24
27
|
this.threshold.defaultValue = 1;
|
@@ -39,6 +42,11 @@
|
|
39
42
|
|
40
43
|
onCreateEffect() {
|
41
44
|
let bloom: BloomEffect;
|
45
|
+
|
46
|
+
if (this.selectiveBloom == undefined) {
|
47
|
+
this.selectiveBloom = Bloom.useSelectiveBloom;
|
48
|
+
}
|
49
|
+
|
42
50
|
if (this.selectiveBloom) {
|
43
51
|
// https://github.com/pmndrs/postprocessing/blob/64d2829f014cfec97a46bf3c109f3abc55af0715/demo/src/demos/BloomDemo.js#L265
|
44
52
|
const selectiveBloom = bloom = new SelectiveBloomEffect(this.context.scene, this.context.mainCamera!, {
|
@@ -51,7 +59,13 @@
|
|
51
59
|
selectiveBloom.inverted = true;
|
52
60
|
}
|
53
61
|
else {
|
54
|
-
bloom = new BloomEffect(
|
62
|
+
bloom = new BloomEffect({
|
63
|
+
blendFunction: BlendFunction.ADD,
|
64
|
+
mipmapBlur: true,
|
65
|
+
luminanceThreshold: this.threshold.value,
|
66
|
+
luminanceSmoothing: this.scatter.value,
|
67
|
+
intensity: this.intensity.value,
|
68
|
+
});
|
55
69
|
}
|
56
70
|
|
57
71
|
|
@@ -1,14 +1,14 @@
|
|
1
1
|
import { Euler, Object3D, Quaternion, Scene, Vector3 } from "three";
|
2
2
|
|
3
3
|
import { isDevEnvironment } from "../engine/debug/index.js";
|
4
|
-
import { addNewComponent, destroyComponentInstance, findObjectOfType, findObjectsOfType, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent,
|
4
|
+
import { addComponent, addNewComponent, destroyComponentInstance, findObjectOfType, findObjectsOfType, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, removeComponent } from "../engine/engine_components.js";
|
5
5
|
import { activeInHierarchyFieldName } from "../engine/engine_constants.js";
|
6
6
|
import { destroy, findByGuid, foreachComponent, HideFlags, type IInstantiateOptions, instantiate, isActiveInHierarchy, isActiveSelf, isDestroyed, isUsingInstancing, markAsInstancedRendered, setActive } from "../engine/engine_gameobject.js";
|
7
7
|
import * as main from "../engine/engine_mainloop_utils.js";
|
8
8
|
import { syncDestroy, syncInstantiate } from "../engine/engine_networking_instantiate.js";
|
9
9
|
import { Context, FrameEvent } from "../engine/engine_setup.js";
|
10
10
|
import * as threeutils from "../engine/engine_three_utils.js";
|
11
|
-
import type { Collision, Constructor, ConstructorConcrete, GuidsMap, ICollider, IComponent, IGameObject, SourceIdentifier } from "../engine/engine_types.js";
|
11
|
+
import type { Collision, ComponentInit, Constructor, ConstructorConcrete, GuidsMap, ICollider, IComponent, IGameObject, SourceIdentifier } from "../engine/engine_types.js";
|
12
12
|
import type { INeedleXRSessionEventReceiver, NeedleXRControllerEventArgs, NeedleXREventArgs } from "../engine/engine_xr.js";
|
13
13
|
import { type IPointerEventHandler, PointerEventData } from "./ui/PointerEvents.js";
|
14
14
|
|
@@ -23,11 +23,47 @@
|
|
23
23
|
|
24
24
|
export abstract class GameObject extends Object3D implements Object3D, IGameObject {
|
25
25
|
|
26
|
+
// these are implemented via threejs object extensions
|
27
|
+
abstract activeSelf: boolean;
|
28
|
+
|
29
|
+
// The actual implementation / prototype of threejs is modified in js-extensions/Object3D
|
30
|
+
abstract get transform(): GameObject;
|
31
|
+
|
32
|
+
/** @deprecated use `addComponent` */
|
33
|
+
abstract addNewComponent<T extends IComponent>(type: ConstructorConcrete<T>, init?: ComponentInit<T>): T;
|
34
|
+
/** creates a new component on this gameObject */
|
35
|
+
abstract addComponent<T extends IComponent>(comp: T | ConstructorConcrete<T>, init?: ComponentInit<T>): T;
|
36
|
+
abstract removeComponent<T extends IComponent>(comp: T): T;
|
37
|
+
abstract getOrAddComponent<T>(typeName: ConstructorConcrete<T> | null): T;
|
38
|
+
abstract getComponent<T>(type: Constructor<T>): T | null;
|
39
|
+
abstract getComponents<T>(type: Constructor<T>, arr?: T[]): Array<T>;
|
40
|
+
abstract getComponentInChildren<T>(type: Constructor<T>): T | null;
|
41
|
+
abstract getComponentsInChildren<T>(type: Constructor<T>, arr?: T[]): Array<T>;
|
42
|
+
abstract getComponentInParent<T>(type: Constructor<T>): T | null;
|
43
|
+
abstract getComponentsInParent<T>(type: Constructor<T>, arr?: T[]): Array<T>;
|
44
|
+
|
45
|
+
|
46
|
+
abstract get worldPosition(): Vector3
|
47
|
+
abstract set worldPosition(val: Vector3);
|
48
|
+
abstract set worldQuaternion(val: Quaternion);
|
49
|
+
abstract get worldQuaternion(): Quaternion;
|
50
|
+
abstract set worldRotation(val: Vector3);
|
51
|
+
abstract get worldRotation(): Vector3;
|
52
|
+
abstract set worldScale(val: Vector3);
|
53
|
+
abstract get worldScale(): Vector3;
|
54
|
+
|
55
|
+
abstract get worldForward(): Vector3;
|
56
|
+
abstract get worldRight(): Vector3;
|
57
|
+
abstract get worldUp(): Vector3;
|
58
|
+
|
26
59
|
guid: string | undefined;
|
27
60
|
|
28
61
|
// Added to the threejs Object3D prototype
|
29
62
|
abstract destroy();
|
30
63
|
|
64
|
+
|
65
|
+
|
66
|
+
|
31
67
|
public static isDestroyed(go: Object3D): boolean {
|
32
68
|
return isDestroyed(go);
|
33
69
|
}
|
@@ -166,38 +202,31 @@
|
|
166
202
|
}, children);
|
167
203
|
}
|
168
204
|
|
205
|
+
/** @deprecated Use `addComponent` */
|
206
|
+
public static addNewComponent<T extends IComponent>(go: IGameObject | Object3D, type: T | ConstructorConcrete<T>, init?: ComponentInit<T>, callAwake: boolean = true): T {
|
207
|
+
return addComponent(go, type, init, { callAwake });
|
208
|
+
}
|
209
|
+
|
169
210
|
/**
|
170
|
-
*
|
211
|
+
* Add a new component (or move an existing component) to the provided object
|
171
212
|
* @param go object to add the component to
|
172
|
-
* @param
|
213
|
+
* @param instanceOrType if an instance is provided it will be moved to the new object, if a type is provided a new instance will be created and moved to the new object
|
214
|
+
* @param init optional init object to initialize the component with
|
173
215
|
* @param callAwake if true, the component will be added and awake will be called immediately
|
174
216
|
*/
|
175
|
-
public static
|
176
|
-
|
177
|
-
//@ts-ignore
|
178
|
-
addNewComponent(go, instance, callAwake);
|
179
|
-
return instance
|
217
|
+
public static addComponent<T extends IComponent>(go: IGameObject | Object3D, instanceOrType: T | ConstructorConcrete<T>, init?: ComponentInit<T>, opts?: { callAwake: boolean }): T {
|
218
|
+
return addComponent(go, instanceOrType, init, opts);
|
180
219
|
}
|
181
220
|
|
182
221
|
/**
|
183
222
|
* Moves a component to a new object
|
184
|
-
* BEWARE: this does MOVE a component. If you want to add a new component use `addNewComponent`
|
185
223
|
* @param go component to move the component to
|
186
224
|
* @param instance component to move to the GO
|
187
225
|
*/
|
188
|
-
public static
|
189
|
-
return
|
226
|
+
public static moveComponent<T extends IComponent>(go: IGameObject | Object3D, instance: T | ConstructorConcrete<T>): T {
|
227
|
+
return addComponent(go, instance);
|
190
228
|
}
|
191
229
|
|
192
|
-
/**
|
193
|
-
* Moves a component to a new object
|
194
|
-
* @param go component to move the component to
|
195
|
-
* @param instance component to move to the GO
|
196
|
-
*/
|
197
|
-
public static moveComponent<T extends IComponent>(go: IGameObject | Object3D, instance: T | ConstructorConcrete<T>) {
|
198
|
-
return moveComponentInstance(go, instance);
|
199
|
-
}
|
200
|
-
|
201
230
|
/** Removes a component from its object
|
202
231
|
* @param instance component to remove
|
203
232
|
*/
|
@@ -270,39 +299,6 @@
|
|
270
299
|
}
|
271
300
|
}
|
272
301
|
}
|
273
|
-
|
274
|
-
// these are implemented via threejs object extensions
|
275
|
-
abstract activeSelf: boolean;
|
276
|
-
|
277
|
-
// The actual implementation / prototype of threejs is modified in js-extensions/Object3D
|
278
|
-
abstract get transform(): GameObject;
|
279
|
-
|
280
|
-
/** creates a new component on this gameObject */
|
281
|
-
abstract addNewComponent<T>(type: ConstructorConcrete<T>): T | null;
|
282
|
-
/** adds an existing component to this gameObject */
|
283
|
-
abstract addComponent<T extends IComponent>(comp: T | ConstructorConcrete<T>): void;
|
284
|
-
abstract removeComponent(comp: Component): Component;
|
285
|
-
abstract getOrAddComponent<T>(typeName: ConstructorConcrete<T> | null): T;
|
286
|
-
abstract getComponent<T>(type: Constructor<T>): T | null;
|
287
|
-
abstract getComponents<T>(type: Constructor<T>, arr?: T[]): Array<T>;
|
288
|
-
abstract getComponentInChildren<T>(type: Constructor<T>): T | null;
|
289
|
-
abstract getComponentsInChildren<T>(type: Constructor<T>, arr?: T[]): Array<T>;
|
290
|
-
abstract getComponentInParent<T>(type: Constructor<T>): T | null;
|
291
|
-
abstract getComponentsInParent<T>(type: Constructor<T>, arr?: T[]): Array<T>;
|
292
|
-
|
293
|
-
|
294
|
-
abstract get worldPosition(): Vector3
|
295
|
-
abstract set worldPosition(val: Vector3);
|
296
|
-
abstract set worldQuaternion(val: Quaternion);
|
297
|
-
abstract get worldQuaternion(): Quaternion;
|
298
|
-
abstract set worldRotation(val: Vector3);
|
299
|
-
abstract get worldRotation(): Vector3;
|
300
|
-
abstract set worldScale(val: Vector3);
|
301
|
-
abstract get worldScale(): Vector3;
|
302
|
-
|
303
|
-
abstract get worldForward(): Vector3;
|
304
|
-
abstract get worldRight(): Vector3;
|
305
|
-
abstract get worldUp(): Vector3;
|
306
302
|
}
|
307
303
|
|
308
304
|
|
@@ -551,24 +547,36 @@
|
|
551
547
|
|
552
548
|
|
553
549
|
/** @internal */
|
554
|
-
constructor() {
|
550
|
+
constructor(init?: ComponentInit<Component>) {
|
555
551
|
this.__didAwake = false;
|
556
552
|
this.__didStart = false;
|
557
553
|
this.__didEnable = false;
|
558
554
|
this.__isEnabled = undefined;
|
559
555
|
this.__destroyed = false;
|
556
|
+
this._internalInit(init as ComponentInit<this>);
|
560
557
|
}
|
561
558
|
|
562
|
-
|
563
559
|
/** @internal */
|
564
|
-
__internalNewInstanceCreated() {
|
560
|
+
__internalNewInstanceCreated(init?: ComponentInit<this>): this {
|
565
561
|
this.__didAwake = false;
|
566
562
|
this.__didStart = false;
|
567
563
|
this.__didEnable = false;
|
568
564
|
this.__isEnabled = undefined;
|
569
565
|
this.__destroyed = false;
|
566
|
+
this._internalInit(init);
|
567
|
+
return this;
|
570
568
|
}
|
571
569
|
|
570
|
+
_internalInit(init?: ComponentInit<this>) {
|
571
|
+
if (typeof init === "object") {
|
572
|
+
for (const key of Object.keys(init)) {
|
573
|
+
const value = init[key];
|
574
|
+
// we don't want to allow overriding functions via init
|
575
|
+
if (typeof value === "function") continue;
|
576
|
+
(this as any)[key] = value;
|
577
|
+
}
|
578
|
+
}
|
579
|
+
}
|
572
580
|
|
573
581
|
/** @internal */
|
574
582
|
__internalAwake() {
|
@@ -767,6 +767,9 @@
|
|
767
767
|
const localP = this.gameObject.position.clone();
|
768
768
|
const localQ = this.gameObject.quaternion.clone();
|
769
769
|
const localS = this.gameObject.scale.clone();
|
770
|
+
// save the original matrix world (because if some other script is doing a raycast at the same moment the matrix will not be correct anymore....)
|
771
|
+
const matrixWorld = this.gameObject.matrixWorld.clone();
|
772
|
+
|
770
773
|
if (p) p.remove(this.gameObject);
|
771
774
|
this.gameObject.position.set(0, 0, 0);
|
772
775
|
this.gameObject.quaternion.set(0, 0, 0, 1);
|
@@ -791,6 +794,7 @@
|
|
791
794
|
this.gameObject.position.copy(localP);
|
792
795
|
this.gameObject.quaternion.copy(localQ);
|
793
796
|
this.gameObject.scale.copy(localS);
|
797
|
+
this.gameObject.matrixWorld.copy(matrixWorld);
|
794
798
|
|
795
799
|
// surface snapping
|
796
800
|
this._draggedOverObject = null;
|
@@ -22,6 +22,7 @@
|
|
22
22
|
document.addEventListener('click', onUserInteraction);
|
23
23
|
document.addEventListener('dragstart', onUserInteraction);
|
24
24
|
document.addEventListener('touchstart', onUserInteraction);
|
25
|
+
document.addEventListener('keydown', onUserInteraction);
|
25
26
|
NeedleXRSession.onXRSessionStart(() => {
|
26
27
|
onUserInteraction();
|
27
28
|
})
|
@@ -6,7 +6,7 @@
|
|
6
6
|
import { removeScriptFromContext, updateActiveInHierarchyWithoutEventCall } from "./engine_mainloop_utils.js";
|
7
7
|
import { InstantiateIdProvider } from "./engine_networking_instantiate.js";
|
8
8
|
import { Context, registerComponent } from "./engine_setup.js";
|
9
|
-
import type { Constructor, ConstructorConcrete, IComponent, IGameObject } from "./engine_types.js";
|
9
|
+
import type { ComponentInit, Constructor, ConstructorConcrete, IComponent, IGameObject } from "./engine_types.js";
|
10
10
|
import { getParam } from "./engine_utils.js";
|
11
11
|
|
12
12
|
|
@@ -24,29 +24,29 @@
|
|
24
24
|
}
|
25
25
|
|
26
26
|
|
27
|
-
export function removeComponent(go: Object3D, componentInstance:
|
28
|
-
if (!go) return;
|
29
|
-
if (!go.userData.components) return;
|
27
|
+
export function removeComponent<T extends IComponent>(go: Object3D, componentInstance: T): T {
|
28
|
+
if (!go) return componentInstance;
|
29
|
+
if (!go.userData.components) return componentInstance;
|
30
30
|
const index = go.userData.components.indexOf(componentInstance);
|
31
|
-
if (index < 0) return;
|
31
|
+
if (index < 0) return componentInstance;
|
32
32
|
|
33
33
|
ComponentLifecycleEvents.dispatchComponentLifecycleEvent(ComponentEvents.Removing, componentInstance);
|
34
34
|
|
35
35
|
//@ts-ignore
|
36
36
|
componentInstance.gameObject = null;
|
37
37
|
go.userData.components.splice(index, 1);
|
38
|
+
return componentInstance;
|
38
39
|
}
|
39
40
|
|
40
|
-
export function getOrAddComponent<T extends IComponent>(go: Object3D, typeName: ConstructorConcrete<T>): T {
|
41
|
+
export function getOrAddComponent<T extends IComponent>(go: Object3D, typeName: ConstructorConcrete<T>, init?: ComponentInit<T>): T {
|
41
42
|
const comp = getComponent(go, typeName);
|
42
43
|
if (comp) return comp;
|
43
|
-
|
44
|
-
return addNewComponent(go, newInstance) as unknown as T;
|
44
|
+
return addComponent(go, typeName, init);
|
45
45
|
}
|
46
46
|
|
47
47
|
const idProvider = new InstantiateIdProvider("addComponentIdProvider");
|
48
48
|
|
49
|
-
export function addNewComponent<T extends IComponent>(obj: Object3D, componentInstance: T, callAwake = true):
|
49
|
+
export function addNewComponent<T extends IComponent>(obj: Object3D, componentInstance: T, callAwake = true): T {
|
50
50
|
if (!obj) {
|
51
51
|
new Error("Can not add componet to null object");
|
52
52
|
}
|
@@ -75,10 +75,14 @@
|
|
75
75
|
return componentInstance;
|
76
76
|
}
|
77
77
|
|
78
|
-
export function
|
78
|
+
export function addComponent<T extends IComponent>(obj: Object3D, componentInstance: T | ConstructorConcrete<T>, init?: ComponentInit<T>, opts?: { callAwake: boolean }): T {
|
79
79
|
|
80
80
|
if (typeof componentInstance === "function") {
|
81
|
-
|
81
|
+
const instance = new componentInstance();
|
82
|
+
if (init) instance.__internalNewInstanceCreated(init);
|
83
|
+
let callAwake = true;
|
84
|
+
if (opts?.callAwake != undefined) callAwake = opts.callAwake;
|
85
|
+
return addNewComponent<T>(obj, instance, callAwake);
|
82
86
|
}
|
83
87
|
|
84
88
|
if (componentInstance.destroyed) {
|
@@ -103,6 +107,7 @@
|
|
103
107
|
if (componentInstance.guid === undefined || componentInstance.guid === "invalid") {
|
104
108
|
componentInstance.guid = idProvider.generateUUID();
|
105
109
|
}
|
110
|
+
if(init) componentInstance._internalInit(init);
|
106
111
|
registerComponent(componentInstance);
|
107
112
|
return componentInstance;
|
108
113
|
}
|
@@ -126,7 +131,7 @@
|
|
126
131
|
|
127
132
|
let didWarnAboutComponentAccess: boolean = false;
|
128
133
|
|
129
|
-
function onGetComponent<T>(obj: Object3D | null | undefined, componentType: Constructor<T>, arr?: T[]) {
|
134
|
+
function onGetComponent<T>(obj: Object3D | null | undefined, componentType: Constructor<T>, arr?: T[]): T | T[] | null {
|
130
135
|
if (obj === null || obj === undefined) return null;
|
131
136
|
if (!obj.isObject3D) {
|
132
137
|
console.error("Object is not object3D");
|
@@ -164,21 +169,24 @@
|
|
164
169
|
return arr;
|
165
170
|
}
|
166
171
|
|
167
|
-
export function getComponent<T>(obj: Object3D, componentType: Constructor<T>) {
|
168
|
-
|
172
|
+
export function getComponent<T extends IComponent>(obj: Object3D, componentType: Constructor<T>): T | null {
|
173
|
+
const result = onGetComponent(obj, componentType);
|
174
|
+
if (!result) return null;
|
175
|
+
if (Array.isArray(result)) return result[0];
|
176
|
+
return result;
|
169
177
|
}
|
170
178
|
|
171
|
-
export function getComponents<T>(obj: Object3D, componentType: Constructor<T>, arr?: T[] | null, clearArray: boolean = true): T[] {
|
179
|
+
export function getComponents<T extends IComponent>(obj: Object3D, componentType: Constructor<T>, arr?: T[] | null, clearArray: boolean = true): T[] {
|
172
180
|
if (!arr) arr = [];
|
173
181
|
if (clearArray) arr.length = 0;
|
174
182
|
onGetComponent(obj, componentType, arr);
|
175
183
|
return arr;
|
176
184
|
}
|
177
185
|
|
178
|
-
export function getComponentInChildren<T>(obj: Object3D, componentType: Constructor<T>, includeInactive?: boolean) {
|
179
|
-
const res = getComponent(obj, componentType);
|
186
|
+
export function getComponentInChildren<T extends IComponent>(obj: Object3D, componentType: Constructor<T>, includeInactive?: boolean): T | null {
|
187
|
+
const res = getComponent(obj, componentType) as IComponent | null;
|
180
188
|
if (includeInactive === false && res?.enabled === false) return null;
|
181
|
-
if (res) return res;
|
189
|
+
if (res) return res as T;
|
182
190
|
for (let i = 0; i < obj?.children?.length; i++) {
|
183
191
|
const res = getComponentInChildren(obj.children[i], componentType);
|
184
192
|
if (res) return res;
|
@@ -186,7 +194,7 @@
|
|
186
194
|
return null;
|
187
195
|
}
|
188
196
|
|
189
|
-
export function getComponentsInChildren<T>(obj: Object3D, componentType: Constructor<T>, arr?: T[], clearArray: boolean = true) {
|
197
|
+
export function getComponentsInChildren<T extends IComponent>(obj: Object3D, componentType: Constructor<T>, arr?: T[], clearArray: boolean = true): T[] | null {
|
190
198
|
if (!arr) arr = [];
|
191
199
|
if (clearArray) arr.length = 0;
|
192
200
|
|
@@ -197,7 +205,7 @@
|
|
197
205
|
return arr;
|
198
206
|
}
|
199
207
|
|
200
|
-
export function getComponentInParent<T>(obj: Object3D, componentType: Constructor<T>) {
|
208
|
+
export function getComponentInParent<T extends IComponent>(obj: Object3D, componentType: Constructor<T>): T | null {
|
201
209
|
if (!obj) return null;
|
202
210
|
if (Array.isArray(obj)) {
|
203
211
|
for (let i = 0; i < obj.length; i++) {
|
@@ -215,7 +223,7 @@
|
|
215
223
|
return null;
|
216
224
|
}
|
217
225
|
|
218
|
-
export function getComponentsInParent<T>(obj: Object3D, componentType: Constructor<T>, arr?: T[] | null, clearArray: boolean = true): T[] {
|
226
|
+
export function getComponentsInParent<T extends IComponent>(obj: Object3D, componentType: Constructor<T>, arr?: T[] | null, clearArray: boolean = true): T[] {
|
219
227
|
if (!arr) arr = [];
|
220
228
|
if (clearArray) arr.length = 0;
|
221
229
|
|
@@ -226,7 +234,7 @@
|
|
226
234
|
return arr;
|
227
235
|
}
|
228
236
|
|
229
|
-
export function findObjectOfType<T>(type: Constructor<T>, contextOrScene: Object3D | { scene: Scene }, includeInactive) {
|
237
|
+
export function findObjectOfType<T extends IComponent>(type: Constructor<T>, contextOrScene: Object3D | { scene: Scene }, includeInactive): T | null {
|
230
238
|
if (!type) return null;
|
231
239
|
if (!contextOrScene) {
|
232
240
|
contextOrScene = Context.Current;
|
@@ -244,14 +252,14 @@
|
|
244
252
|
for (const i in scene.children) {
|
245
253
|
const child = scene.children[i];
|
246
254
|
if (includeInactive === false && child[activeInHierarchyFieldName] === false) continue;
|
247
|
-
if (child.constructor == type) return child;
|
255
|
+
// if (child.constructor == type) return child as T;
|
248
256
|
const res = getComponentInChildren(child, type);
|
249
257
|
if (res) return res;
|
250
258
|
}
|
251
259
|
return null;
|
252
260
|
}
|
253
261
|
|
254
|
-
export function findObjectsOfType<T>(type: Constructor<T>, array: T[], contextOrScene): T[] {
|
262
|
+
export function findObjectsOfType<T extends IComponent>(type: Constructor<T>, array: T[], contextOrScene): T[] {
|
255
263
|
if (!type) return array;
|
256
264
|
if (!array) array = [];
|
257
265
|
array.length = 0;
|
@@ -27,7 +27,7 @@
|
|
27
27
|
import { RendererData as SceneLighting } from './engine_scenelighting.js';
|
28
28
|
import { logHierarchy } from './engine_three_utils.js';
|
29
29
|
import { Time } from './engine_time.js';
|
30
|
-
import type { CoroutineData, GLTF, ICamera, IComponent, IContext, ILight, LoadedGLTF } from "./engine_types.js";
|
30
|
+
import type { CoroutineData, GLTF, ICamera, IComponent, IContext, ILight, LoadedGLTF, Vec2 } from "./engine_types.js";
|
31
31
|
import * as utils from "./engine_utils.js";
|
32
32
|
import { delay, getParam } from './engine_utils.js';
|
33
33
|
import type { INeedleXRSessionEventReceiver, NeedleXRSession } from './engine_xr.js';
|
@@ -452,13 +452,22 @@
|
|
452
452
|
/** will request a renderer size update the next render call (will call updateSize the next update) */
|
453
453
|
requestSizeUpdate() { this._sizeChanged = true; }
|
454
454
|
|
455
|
+
/** Clamps the renderer max resolution. If undefined the max resolution is not clamped. Default is undefined */
|
456
|
+
maxRenderResolution?: Vec2;
|
457
|
+
|
455
458
|
/** update the renderer and canvas size */
|
456
459
|
updateSize(force: boolean = false) {
|
457
460
|
if (force || (!this.isManagedExternally && this.renderer.xr?.isPresenting === false)) {
|
458
461
|
this._sizeChanged = false;
|
459
462
|
const scaleFactor = this.resolutionScaleFactor;
|
460
|
-
|
461
|
-
|
463
|
+
let width = this.domWidth * scaleFactor;
|
464
|
+
let height = this.domHeight * scaleFactor;
|
465
|
+
if (this.maxRenderResolution) {
|
466
|
+
this.maxRenderResolution.x = Math.max(1, this.maxRenderResolution.x);
|
467
|
+
width = Math.min(this.maxRenderResolution.x, width);
|
468
|
+
this.maxRenderResolution.y = Math.max(1, this.maxRenderResolution.y);
|
469
|
+
height = Math.min(this.maxRenderResolution.y, height);
|
470
|
+
}
|
462
471
|
const camera = this.mainCamera as PerspectiveCamera;
|
463
472
|
this.updateAspect(camera);
|
464
473
|
this.renderer.setSize(width, height, true);
|
@@ -738,6 +747,22 @@
|
|
738
747
|
|
739
748
|
if (debug) console.log("Creating context", this.name, opts);
|
740
749
|
|
750
|
+
// wait for async imported dependencies to be loaded
|
751
|
+
// see https://linear.app/needle/issue/NE-4445
|
752
|
+
const dependenciesReady = globalThis["needle:dependencies:ready"];
|
753
|
+
if (dependenciesReady instanceof Promise) {
|
754
|
+
if (debug) console.log("Waiting for dependencies to be ready");
|
755
|
+
await dependenciesReady
|
756
|
+
.catch(err => {
|
757
|
+
if (debug || isDevEnvironment())
|
758
|
+
console.error("Needle Engine dependencies failed to load", err)
|
759
|
+
})
|
760
|
+
.then(() => {
|
761
|
+
if(debug) console.log("Needle Engine dependencies are ready");
|
762
|
+
globalThis["needle:dependencies:ready"] = true;
|
763
|
+
});
|
764
|
+
}
|
765
|
+
|
741
766
|
this.clear();
|
742
767
|
// stop the animation loop if its running during creation
|
743
768
|
// since we do not want to start enabling scripts etc before they are deserialized
|
@@ -97,6 +97,7 @@
|
|
97
97
|
obj.material["color"].set(color);
|
98
98
|
obj.material["depthTest"] = depthTest;
|
99
99
|
obj.material["depthWrite"] = false;
|
100
|
+
obj.material["fog"] = false;
|
100
101
|
}
|
101
102
|
|
102
103
|
static DrawWireSphere(center: Vec3, radius: number, color: ColorRepresentation = defaultColor, duration: number = 0, depthTest: boolean = true) {
|
@@ -106,6 +107,7 @@
|
|
106
107
|
obj.material["color"].set(color);
|
107
108
|
obj.material["depthTest"] = depthTest;
|
108
109
|
obj.material["depthWrite"] = false;
|
110
|
+
obj.material["fog"] = false;
|
109
111
|
}
|
110
112
|
|
111
113
|
static DrawSphere(center: Vec3, radius: number, color: ColorRepresentation = defaultColor, duration: number = 0, depthTest: boolean = true) {
|
@@ -126,6 +128,7 @@
|
|
126
128
|
obj.material["depthTest"] = depthTest;
|
127
129
|
obj.material["wireframe"] = true;
|
128
130
|
obj.material["depthWrite"] = false;
|
131
|
+
obj.material["fog"] = false;
|
129
132
|
}
|
130
133
|
|
131
134
|
static DrawWireBox3(box: Box3, color: ColorRepresentation = defaultColor, duration: number = 0, depthTest: boolean = true) {
|
@@ -137,6 +140,7 @@
|
|
137
140
|
obj.material["depthTest"] = depthTest;
|
138
141
|
obj.material["wireframe"] = true;
|
139
142
|
obj.material["depthWrite"] = false;
|
143
|
+
obj.material["fog"] = false;
|
140
144
|
}
|
141
145
|
|
142
146
|
private static _up = new Vector3(0, 1, 0);
|
@@ -73,7 +73,17 @@
|
|
73
73
|
readonly mode: XRTargetRayMode;
|
74
74
|
/** A ray in worldspace for the event.
|
75
75
|
* If the ray is undefined you can also use `space.worldForward` and `space.worldPosition` */
|
76
|
-
|
76
|
+
get ray(): Ray {
|
77
|
+
if (!this._ray) {
|
78
|
+
this._ray = new Ray(this.space.worldPosition.clone(), this.space.worldForward.clone());
|
79
|
+
}
|
80
|
+
return this._ray;
|
81
|
+
}
|
82
|
+
private set ray(value: Ray) { this._ray = value; }
|
83
|
+
/**@returns true if this event has a ray. If you access the ray property a ray will automatically created */
|
84
|
+
get hasRay() { return this._ray !== undefined; }
|
85
|
+
private _ray: Ray | undefined;
|
86
|
+
|
77
87
|
/** The device space (this object is not necessarily rendered in the scene but you can access or copy the matrix)
|
78
88
|
* E.g. you can access the input world space source position with `space.worldPosition` or world direction with `space.worldForward`
|
79
89
|
*/
|
@@ -118,7 +128,7 @@
|
|
118
128
|
this.origin = init.origin;
|
119
129
|
this.source = source;
|
120
130
|
this.mode = init.mode;
|
121
|
-
this.
|
131
|
+
this._ray = init.ray;
|
122
132
|
this.space = init.device;
|
123
133
|
}
|
124
134
|
|
@@ -9,6 +9,17 @@
|
|
9
9
|
import { CircularBuffer } from "./engine_utils.js";
|
10
10
|
import type { INeedleXRSessionEventReceiver, NeedleXRSession } from "./engine_xr.js";
|
11
11
|
|
12
|
+
/** Removes all properties that match TypesToFilter */
|
13
|
+
type FilterTypes<T, TypesToFilter> = { [P in keyof T as T[P] extends TypesToFilter ? never : P]: T[P] };
|
14
|
+
/** Removes all undefined functions */
|
15
|
+
type NoUndefinedNoFunctions<T> = FilterTypes<T, Function | undefined | null>;
|
16
|
+
/* Removes all properties that start with a specific prefix */
|
17
|
+
type FilterStartingWith<T, Prefix extends string> = { [P in keyof T as P extends (`${Prefix}${infer _X}`) ? never : P]: T[P] };
|
18
|
+
/** Removes all properties that start with an underscore */
|
19
|
+
type NoInternals<T> = FilterStartingWith<T, "_">;
|
20
|
+
type NoInternalNeedleEngineState<T> = Omit<T, "destroyed" | "gameObject" | "activeAndEnabled" | "context" | "isComponent" | "scene" | "up" | "forward" | "right" | "worldRotation" | "worldEuler" | "worldPosition" | "worldQuaternion">;
|
21
|
+
export type ComponentInit<T> = Partial<NoInternalNeedleEngineState<NoInternals<NoUndefinedNoFunctions<T>>>>
|
22
|
+
|
12
23
|
export type GLTF = GLTF3 & {
|
13
24
|
// asset: { generator: string, version: string }
|
14
25
|
// animations: AnimationClip[];
|
@@ -88,11 +99,12 @@
|
|
88
99
|
get transform(): IGameObject;
|
89
100
|
|
90
101
|
/** Add a new component to this object. Expects a component type (e.g. `addNewComponent(Animator)`) */
|
91
|
-
addNewComponent<T>(type: Constructor<T>): T
|
102
|
+
addNewComponent<T extends IComponent>(type: Constructor<T>, init?: ComponentInit<T>): T;
|
92
103
|
/** Remove a component from this object. Expected a component instance
|
93
104
|
* @returns the removed component (equal to the passed in component)
|
94
105
|
*/
|
95
|
-
|
106
|
+
addComponent<T extends IComponent>(comp: T | ConstructorConcrete<T>, init?: ComponentInit<T>): T;
|
107
|
+
removeComponent<T extends IComponent>(comp: T): T;
|
96
108
|
/** Searches for a component type on this object. If no component of the searched type exists yet a new instance will be created and returned */
|
97
109
|
getOrAddComponent<T>(typeName: Constructor<T> | null): T;
|
98
110
|
/** Tries to find a component of a type on this object.
|
@@ -144,10 +156,11 @@
|
|
144
156
|
context: any;
|
145
157
|
|
146
158
|
get activeAndEnabled(): boolean;
|
147
|
-
|
148
159
|
/** @internal */
|
149
|
-
__internalNewInstanceCreated();
|
160
|
+
__internalNewInstanceCreated(init?: ComponentInit<any>);
|
150
161
|
/** @internal */
|
162
|
+
_internalInit(init?: ComponentInit<any>);
|
163
|
+
/** @internal */
|
151
164
|
__internalAwake();
|
152
165
|
/** @internal */
|
153
166
|
__internalStart();
|
@@ -173,7 +173,7 @@
|
|
173
173
|
|
174
174
|
// raycast
|
175
175
|
const options = new RaycastOptions();
|
176
|
-
if (pointerEvent.
|
176
|
+
if (pointerEvent.hasRay) {
|
177
177
|
options.ray = pointerEvent.ray;
|
178
178
|
}
|
179
179
|
else {
|
@@ -303,6 +303,7 @@
|
|
303
303
|
|
304
304
|
private assignHitInformation(args: PointerEventData, hit?: Intersection) {
|
305
305
|
if (!hit) {
|
306
|
+
args.intersection = undefined;
|
306
307
|
args.point = undefined;
|
307
308
|
args.normal = undefined;
|
308
309
|
args.face = undefined;
|
@@ -310,6 +311,7 @@
|
|
310
311
|
args.instanceId = undefined;
|
311
312
|
}
|
312
313
|
else {
|
314
|
+
args.intersection = hit;
|
313
315
|
args.point = hit.point;
|
314
316
|
args.normal = hit.normal;
|
315
317
|
args.face = hit.face;
|
@@ -4,6 +4,7 @@
|
|
4
4
|
import SimpleStateBehavior from "three-mesh-ui/examples/behaviors/states/SimpleStateBehavior.js"
|
5
5
|
|
6
6
|
import { serializable } from '../../engine/engine_serialization_decorator.js';
|
7
|
+
import { ComponentInit } from '../../engine/engine_types.js';
|
7
8
|
import { NEEDLE_progressive } from '../../engine/extensions/NEEDLE_progressive.js';
|
8
9
|
import { GameObject } from '../Component.js';
|
9
10
|
import { RGBAColor } from "../js-extensions/RGBAColor.js"
|
@@ -89,11 +90,12 @@
|
|
89
90
|
this.markDirty();
|
90
91
|
}
|
91
92
|
|
92
|
-
__internalNewInstanceCreated():
|
93
|
-
super.__internalNewInstanceCreated();
|
93
|
+
__internalNewInstanceCreated(init: ComponentInit<this>): this {
|
94
|
+
super.__internalNewInstanceCreated(init);
|
94
95
|
this._rect = null;
|
95
96
|
this.uiObject = null;
|
96
97
|
if (this._color) this._color = this._color.clone();
|
98
|
+
return this;
|
97
99
|
}
|
98
100
|
|
99
101
|
setState(state: string) {
|
@@ -202,22 +204,22 @@
|
|
202
204
|
if (tex) {
|
203
205
|
// workaround for https://github.com/needle-tools/needle-engine-support/issues/109
|
204
206
|
// if (tex.colorSpace === SRGBColorSpace || !tex.colorSpace || true) {
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
}
|
214
|
-
else {
|
215
|
-
const clone = tex.clone();
|
216
|
-
clone.colorSpace = LinearSRGBColorSpace;
|
217
|
-
Graphic.textureCache.set(tex, clone);
|
218
|
-
tex = clone;
|
219
|
-
}
|
207
|
+
if (Graphic.textureCache.has(tex)) {
|
208
|
+
tex = Graphic.textureCache.get(tex)!;
|
209
|
+
} else {
|
210
|
+
if (tex.isRenderTargetTexture) {
|
211
|
+
// we can not clone the texture if it's a render target
|
212
|
+
// otherwise it won't be updated anymore in the UI
|
213
|
+
// TODO: below maskable graphic is flipped but settings a rendertexture results in the texture being upside down.
|
214
|
+
// we should remove the flip below (scale.y *= -1) but this needs to be tested with all UI components
|
220
215
|
}
|
216
|
+
else {
|
217
|
+
const clone = tex.clone();
|
218
|
+
clone.colorSpace = LinearSRGBColorSpace;
|
219
|
+
Graphic.textureCache.set(tex, clone);
|
220
|
+
tex = clone;
|
221
|
+
}
|
222
|
+
}
|
221
223
|
// }
|
222
224
|
this.setOptions({ backgroundImage: tex, borderRadius: 0, backgroundOpacity: this.color.alpha, backgroundSize: "stretch" });
|
223
225
|
NEEDLE_progressive.assignTextureLOD(this.context, this.sourceId, tex, 0).then(res => {
|
@@ -51,14 +51,14 @@
|
|
51
51
|
if (_result.scene.children.length === 1) {
|
52
52
|
const obj = _result.scene.children[0];
|
53
53
|
// add a component to the root of the scene
|
54
|
-
settings = GameObject.addNewComponent(obj, SceneLightSettings, false);
|
54
|
+
settings = GameObject.addNewComponent(obj, SceneLightSettings, {}, false);
|
55
55
|
}
|
56
56
|
// if the scene already has multiple children we add it as a new object
|
57
57
|
else {
|
58
58
|
const lightSettings = new Object3D();
|
59
59
|
lightSettings.name = "LightSettings " + this.sourceId;
|
60
60
|
_result.scene.add(lightSettings);
|
61
|
-
settings = GameObject.addNewComponent(lightSettings, SceneLightSettings, false);
|
61
|
+
settings = GameObject.addNewComponent(lightSettings, SceneLightSettings, {}, false);
|
62
62
|
}
|
63
63
|
settings.sourceId = this.sourceId;
|
64
64
|
settings.ambientIntensity = ext.ambientIntensity;
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import { Object3D, Quaternion, Vector3 } from "three";
|
2
2
|
import { TransformControlsGizmo } from "three/examples/jsm/controls/TransformControls.js";
|
3
3
|
|
4
|
-
import { addNewComponent, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent,
|
5
|
-
import { destroy,isActiveSelf, setActive } from "../../engine/engine_gameobject.js";
|
4
|
+
import { addComponent, addNewComponent, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, removeComponent } from "../../engine/engine_components.js";
|
5
|
+
import { destroy, isActiveSelf, setActive } from "../../engine/engine_gameobject.js";
|
6
6
|
import {
|
7
7
|
getTempVector,
|
8
8
|
getWorldPosition,
|
@@ -12,13 +12,14 @@
|
|
12
12
|
setWorldPosition,
|
13
13
|
setWorldQuaternion,
|
14
14
|
setWorldRotation,
|
15
|
-
setWorldScale
|
15
|
+
setWorldScale
|
16
|
+
}
|
16
17
|
from "../../engine/engine_three_utils.js";
|
17
|
-
import type { Constructor, ConstructorConcrete, IComponent as Component,IComponent } from "../../engine/engine_types.js";
|
18
|
+
import type { ComponentInit,Constructor, ConstructorConcrete, IComponent as Component, IComponent, IGameObject } from "../../engine/engine_types.js";
|
18
19
|
import { applyPrototypeExtensions, registerPrototypeExtensions } from "./ExtensionUtils.js";
|
19
20
|
|
20
21
|
|
21
|
-
|
22
|
+
/** used to decorate cloned object3D objects with the same added components defined above */
|
22
23
|
export function apply(object: Object3D) {
|
23
24
|
if (object && object.isObject3D === true) {
|
24
25
|
applyPrototypeExtensions(object, Object3D);
|
@@ -37,20 +38,21 @@
|
|
37
38
|
destroy(this);
|
38
39
|
}
|
39
40
|
|
40
|
-
|
41
|
-
|
41
|
+
|
42
|
+
Object3D.prototype["addComponent"] = function <T extends IComponent>(comp: T | ConstructorConcrete<T>, init?: ComponentInit<T>) {
|
43
|
+
return addComponent(this, comp, init);
|
42
44
|
}
|
43
45
|
|
44
|
-
Object3D.prototype["addNewComponent"] = function <T extends Component>(type: ConstructorConcrete<T>) {
|
45
|
-
return
|
46
|
+
Object3D.prototype["addNewComponent"] = function <T extends Component>(type: ConstructorConcrete<T>, init?: ComponentInit<T>) {
|
47
|
+
return addComponent(this, type, init);
|
46
48
|
}
|
47
49
|
|
48
50
|
Object3D.prototype["removeComponent"] = function (inst: Component) {
|
49
51
|
return removeComponent(this, inst);
|
50
52
|
}
|
51
53
|
|
52
|
-
Object3D.prototype["getOrAddComponent"] = function <T extends IComponent>(typeName: ConstructorConcrete<T>): T {
|
53
|
-
return getOrAddComponent<T>(this, typeName);
|
54
|
+
Object3D.prototype["getOrAddComponent"] = function <T extends IComponent>(typeName: ConstructorConcrete<T>, init?: ComponentInit<T>): T {
|
55
|
+
return getOrAddComponent<T>(this, typeName, init);
|
54
56
|
}
|
55
57
|
|
56
58
|
Object3D.prototype["getComponent"] = function <T extends IComponent>(type: Constructor<T>) {
|
@@ -73,7 +75,7 @@
|
|
73
75
|
return getComponentInParent(this, type);
|
74
76
|
}
|
75
77
|
|
76
|
-
Object3D.prototype["getComponentsInParent"] = function <T>(type: Constructor<T>, arr?: []) {
|
78
|
+
Object3D.prototype["getComponentsInParent"] = function <T extends IComponent>(type: Constructor<T>, arr?: []) {
|
77
79
|
return getComponentsInParent(this, type, arr);
|
78
80
|
}
|
79
81
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { type Face, Object3D, Vector3 } from "three";
|
1
|
+
import { type Face, Intersection,Object3D, Vector3 } from "three";
|
2
2
|
|
3
3
|
import { Input, type InputEventNames, NEPointerEvent } from "../../engine/engine_input.js";
|
4
4
|
import type { GamepadButtonName, MouseButtonName } from "../../engine/engine_types.js";
|
@@ -102,6 +102,8 @@
|
|
102
102
|
distance?: number;
|
103
103
|
/** The instance ID of an object hit by a raycast (if a instanced object was hit) */
|
104
104
|
instanceId?: number;
|
105
|
+
/** The three intersection */
|
106
|
+
intersection?: Intersection;
|
105
107
|
|
106
108
|
isDown: boolean | undefined;
|
107
109
|
isUp: boolean | undefined;
|
@@ -588,6 +588,12 @@
|
|
588
588
|
return;
|
589
589
|
}
|
590
590
|
|
591
|
+
if (debugRenderer == this.name && this.gameObject instanceof Mesh) {
|
592
|
+
this.gameObject.geometry.computeBoundingSphere();
|
593
|
+
const tempCenter = getTempVector(this.gameObject.geometry.boundingSphere.center).applyMatrix4(this.gameObject.matrixWorld);
|
594
|
+
Gizmos.DrawWireSphere(tempCenter, this.gameObject.geometry.boundingSphere.radius, 0x00ddff);
|
595
|
+
}
|
596
|
+
|
591
597
|
if (this.isMultiMaterialObject(this.gameObject) && this.gameObject.children?.length > 0) {
|
592
598
|
for (const ch of this.gameObject.children) {
|
593
599
|
this.applySettings(ch);
|
@@ -776,7 +782,6 @@
|
|
776
782
|
}
|
777
783
|
|
778
784
|
export class MeshRenderer extends Renderer {
|
779
|
-
|
780
785
|
}
|
781
786
|
|
782
787
|
export class SkinnedMeshRenderer extends MeshRenderer {
|
@@ -18,6 +18,11 @@
|
|
18
18
|
@serializeable(VolumeProfile)
|
19
19
|
sharedProfile?: VolumeProfile;
|
20
20
|
|
21
|
+
/** Currently active postprocessing effects */
|
22
|
+
get effects() {
|
23
|
+
return this._effects;
|
24
|
+
}
|
25
|
+
|
21
26
|
private _postprocessing?: PostProcessingHandler;
|
22
27
|
private _effects: PostProcessingEffect[] = [];
|
23
28
|
|
@@ -37,7 +42,7 @@
|
|
37
42
|
}
|
38
43
|
});
|
39
44
|
}
|
40
|
-
|
45
|
+
|
41
46
|
// ensure the profile is initialized
|
42
47
|
this.sharedProfile?.init();
|
43
48
|
}
|
@@ -63,7 +63,19 @@
|
|
63
63
|
return;
|
64
64
|
|
65
65
|
const oldValue = this._value;
|
66
|
-
if (debug)
|
66
|
+
if (debug) {
|
67
|
+
let hasChanged = true;
|
68
|
+
if (typeof oldValue == "number" && typeof val == "number") {
|
69
|
+
const oldFixed = oldValue?.toFixed(4);
|
70
|
+
const newFixed = val?.toFixed(4);
|
71
|
+
if (oldFixed != newFixed) {
|
72
|
+
hasChanged = true;
|
73
|
+
}
|
74
|
+
else hasChanged = false;
|
75
|
+
}
|
76
|
+
if (hasChanged)
|
77
|
+
console.log("VolumeParameter: value changed from", oldValue, "to", val);
|
78
|
+
}
|
67
79
|
|
68
80
|
if (!this._active && this._defaultValue !== undefined) {
|
69
81
|
// when setting the default value we dont process them (default values are explicitly set from the effect that declares them
|