@needle-tools/engine 2.35.5-pre → 2.36.0-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 +19 -0
- package/dist/needle-engine.d.ts +160 -110
- package/dist/needle-engine.js +370 -365
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +61 -56
- package/dist/needle-engine.min.js.map +4 -4
- package/lib/engine/debug/debug_overlay.js +12 -1
- package/lib/engine/debug/debug_overlay.js.map +1 -1
- package/lib/engine/engine_element_loading.js +1 -1
- package/lib/engine/engine_element_loading.js.map +1 -1
- package/lib/engine/engine_gameobject.d.ts +1 -0
- package/lib/engine/engine_gameobject.js +13 -1
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_gltf_builtin_components.js +4 -0
- package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
- package/lib/engine/engine_mainloop_utils.d.ts +1 -1
- package/lib/engine/engine_mainloop_utils.js +7 -3
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_physics.d.ts +29 -28
- package/lib/engine/engine_physics.js +85 -86
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_serialization_core.js +14 -6
- package/lib/engine/engine_serialization_core.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_time.d.ts +1 -0
- package/lib/engine/engine_time.js +1 -0
- package/lib/engine/engine_time.js.map +1 -1
- package/lib/engine/engine_types.d.ts +1 -0
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine/engine_typestore.d.ts +1 -0
- package/lib/engine/engine_typestore.js +1 -0
- package/lib/engine/engine_typestore.js.map +1 -1
- package/lib/engine/engine_utils.js +1 -1
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_animator_controller_model.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_techniques_webgl.js +5 -0
- package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
- package/lib/engine-components/Animation.d.ts +5 -1
- package/lib/engine-components/Animation.js +21 -0
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/AnimatorController.d.ts +1 -0
- package/lib/engine-components/AnimatorController.js +14 -7
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/BoxHelperComponent.d.ts +2 -2
- package/lib/engine-components/BoxHelperComponent.js +27 -9
- package/lib/engine-components/BoxHelperComponent.js.map +1 -1
- package/lib/engine-components/Component.d.ts +2 -1
- package/lib/engine-components/Component.js +11 -5
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/GroundProjection.d.ts +2 -0
- package/lib/engine-components/GroundProjection.js +18 -6
- package/lib/engine-components/GroundProjection.js.map +1 -1
- package/lib/engine-components/ReflectionProbe.d.ts +22 -0
- package/lib/engine-components/ReflectionProbe.js +134 -0
- package/lib/engine-components/ReflectionProbe.js.map +1 -0
- package/lib/engine-components/Renderer.d.ts +13 -2
- package/lib/engine-components/Renderer.js +96 -45
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/WebARSessionRoot.d.ts +7 -7
- package/lib/engine-components/WebARSessionRoot.js +7 -7
- package/lib/engine-components/WebARSessionRoot.js.map +1 -1
- package/lib/engine-components/WebXR.d.ts +9 -8
- package/lib/engine-components/WebXR.js +40 -24
- package/lib/engine-components/WebXR.js.map +1 -1
- package/lib/engine-components/WebXRAvatar.d.ts +4 -5
- package/lib/engine-components/WebXRAvatar.js +9 -8
- package/lib/engine-components/WebXRAvatar.js.map +1 -1
- package/lib/engine-components/WebXRController.d.ts +21 -21
- package/lib/engine-components/WebXRController.js +79 -63
- package/lib/engine-components/WebXRController.js.map +1 -1
- package/lib/engine-components/WebXRGrabRendering.d.ts +3 -3
- package/lib/engine-components/WebXRGrabRendering.js +2 -2
- package/lib/engine-components/WebXRGrabRendering.js.map +1 -1
- package/lib/engine-components/WebXRSync.d.ts +8 -8
- package/lib/engine-components/WebXRSync.js +15 -15
- package/lib/engine-components/WebXRSync.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +1 -0
- package/lib/engine-components/codegen/components.js +1 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.d.ts +1 -0
- package/lib/engine-components/ui/EventSystem.js +21 -1
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/codegen/register_types.js +293 -0
- package/src/engine/debug/debug_overlay.ts +9 -2
- package/src/engine/engine_element_loading.ts +1 -1
- package/src/engine/engine_gameobject.ts +17 -4
- package/src/engine/engine_gltf_builtin_components.ts +5 -1
- package/src/engine/engine_mainloop_utils.ts +7 -3
- package/src/engine/engine_physics.ts +130 -130
- package/src/engine/engine_serialization_core.ts +14 -7
- package/src/engine/engine_setup.ts +1 -1
- package/src/engine/engine_time.ts +2 -0
- package/src/engine/engine_types.ts +1 -0
- package/src/engine/engine_typestore.ts +2 -0
- package/src/engine/engine_utils.ts +3 -2
- package/src/engine/extensions/EXT_texture_exr.js +1 -1
- package/src/engine/extensions/NEEDLE_animator_controller_model.ts +2 -1
- package/src/engine/extensions/NEEDLE_techniques_webgl.ts +7 -0
- package/src/engine-components/Animation.ts +16 -1
- package/src/engine-components/AnimatorController.ts +19 -9
- package/src/engine-components/BoxHelperComponent.ts +29 -9
- package/src/engine-components/Component.ts +11 -5
- package/src/engine-components/GroundProjection.ts +22 -7
- package/src/engine-components/ReflectionProbe.ts +141 -0
- package/src/engine-components/Renderer.ts +796 -737
- package/src/engine-components/WebARSessionRoot.ts +16 -16
- package/src/engine-components/WebXR.ts +53 -48
- package/src/engine-components/WebXRAvatar.ts +16 -16
- package/src/engine-components/WebXRController.ts +129 -107
- package/src/engine-components/WebXRGrabRendering.ts +6 -6
- package/src/engine-components/WebXRSync.ts +20 -20
- package/src/engine-components/codegen/components.ts +1 -0
- package/src/engine-components/ui/EventSystem.ts +26 -3
|
@@ -226,6 +226,7 @@ export interface IWatch {
|
|
|
226
226
|
dispose();
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
|
|
229
230
|
// TODO: make it possible to add multiple watches to the same object property
|
|
230
231
|
class WatchImpl implements IWatch {
|
|
231
232
|
subscribeWrite(callback: WriteCallback) {
|
|
@@ -236,14 +237,14 @@ class WatchImpl implements IWatch {
|
|
|
236
237
|
constructor(object: object, prop: string) {
|
|
237
238
|
this._object = object;
|
|
238
239
|
this._prop = prop;
|
|
239
|
-
this._wrapperProp = "
|
|
240
|
+
this._wrapperProp = Symbol("$" + prop);
|
|
240
241
|
this.apply();
|
|
241
242
|
}
|
|
242
243
|
|
|
243
244
|
private _applied: boolean = false;
|
|
244
245
|
private _object: any;
|
|
245
246
|
private _prop: string;
|
|
246
|
-
private _wrapperProp:
|
|
247
|
+
private _wrapperProp: symbol;
|
|
247
248
|
|
|
248
249
|
apply() {
|
|
249
250
|
if (this._applied) return;
|
|
@@ -32,7 +32,7 @@ export class EXT_texture_exr {
|
|
|
32
32
|
const extension = textureDef.extensions[ name ];
|
|
33
33
|
|
|
34
34
|
// TODO should the loader be cached here?
|
|
35
|
-
|
|
35
|
+
const loader = new EXRLoader(parser.options.manager);
|
|
36
36
|
|
|
37
37
|
if(debug) console.log("EXT_texture_exr.loadTexture", extension, loader);
|
|
38
38
|
|
|
@@ -97,7 +97,7 @@ export declare type Motion = {
|
|
|
97
97
|
action_loopback?: AnimationAction,
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
export function createMotion(name:string, id
|
|
100
|
+
export function createMotion(name: string, id?: InstantiateIdProvider): Motion {
|
|
101
101
|
return {
|
|
102
102
|
name: "",
|
|
103
103
|
isLooping: false,
|
|
@@ -123,6 +123,7 @@ export declare type Transition = {
|
|
|
123
123
|
hasExitTime: number,
|
|
124
124
|
destinationState: number | State,
|
|
125
125
|
conditions: Condition[],
|
|
126
|
+
// isAny?: boolean
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
export declare type Condition = {
|
|
@@ -203,6 +203,9 @@ export class CustomShader extends RawShaderMaterial {
|
|
|
203
203
|
if (this.uniforms["_TimeParameters"]) {
|
|
204
204
|
this.uniforms["_TimeParameters"].value = context.rendererData.timeVec4;
|
|
205
205
|
}
|
|
206
|
+
else if (this.uniforms["_Time"]) {
|
|
207
|
+
this.uniforms["_Time"].value = context.rendererData.timeVec4;
|
|
208
|
+
}
|
|
206
209
|
|
|
207
210
|
const mainLight: ILight | null = context.mainLight;
|
|
208
211
|
if (mainLight) {
|
|
@@ -327,6 +330,10 @@ export class NEEDLE_techniques_webgl implements GLTFLoaderPlugin {
|
|
|
327
330
|
|
|
328
331
|
const uniforms: {} = {};
|
|
329
332
|
const techniqueUniforms = technique.uniforms;
|
|
333
|
+
|
|
334
|
+
if (vert.includes("_Time"))
|
|
335
|
+
uniforms["_Time"] = { value: new THREE.Vector4(0, 0, 0, 0) };
|
|
336
|
+
|
|
330
337
|
for (const u in techniqueUniforms) {
|
|
331
338
|
const uniformName = u;
|
|
332
339
|
// const uniformValues = techniqueUniforms[u];
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Behaviour } from "./Component";
|
|
2
2
|
import * as THREE from 'three'
|
|
3
|
-
import { AnimationAction, AnimationClip } from "three";
|
|
3
|
+
import { AnimationAction, AnimationClip, Vector2 } from "three";
|
|
4
4
|
import { MixerEvent } from "./Animator";
|
|
5
5
|
import { serializeable } from "../engine/engine_serialization_decorator";
|
|
6
6
|
import { InstancingUtil } from "../engine/engine_instancing";
|
|
7
|
+
import { Mathf } from "../engine/engine_math";
|
|
7
8
|
|
|
8
9
|
export declare class PlayOptions {
|
|
9
10
|
fadeDuration?: number;
|
|
@@ -12,6 +13,8 @@ export declare class PlayOptions {
|
|
|
12
13
|
startTime?: number;
|
|
13
14
|
endTime?: number;
|
|
14
15
|
clampWhenFinished?: boolean;
|
|
16
|
+
minMaxSpeed?: Vector2;
|
|
17
|
+
minMaxOffsetNormalized?: Vector2;
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
export class Animation extends Behaviour {
|
|
@@ -21,6 +24,12 @@ export class Animation extends Behaviour {
|
|
|
21
24
|
@serializeable()
|
|
22
25
|
randomStartTime: boolean = true;
|
|
23
26
|
|
|
27
|
+
@serializeable(Vector2)
|
|
28
|
+
minMaxSpeed?: Vector2;
|
|
29
|
+
|
|
30
|
+
@serializeable(Vector2)
|
|
31
|
+
minMaxOffsetNormalized?: Vector2;
|
|
32
|
+
|
|
24
33
|
private _tempAnimationClipBeforeGameObjectExisted: AnimationClip | null = null;
|
|
25
34
|
get clip(): AnimationClip | null {
|
|
26
35
|
return this.animations?.length ? this.animations[0] : null;
|
|
@@ -120,6 +129,9 @@ export class Animation extends Behaviour {
|
|
|
120
129
|
console.error("Could not find clip", clipOrNumber)
|
|
121
130
|
return;
|
|
122
131
|
}
|
|
132
|
+
if(!options) options = {};
|
|
133
|
+
if(!options.minMaxOffsetNormalized) options.minMaxOffsetNormalized = this.minMaxOffsetNormalized;
|
|
134
|
+
if(!options.minMaxSpeed) options.minMaxSpeed = this.minMaxSpeed;
|
|
123
135
|
for (const act of this.actions) {
|
|
124
136
|
if (act.getClip() === clip) {
|
|
125
137
|
return this.internalOnPlay(act, options);
|
|
@@ -150,6 +162,9 @@ export class Animation extends Behaviour {
|
|
|
150
162
|
action.enabled = true;
|
|
151
163
|
action.time = 0;
|
|
152
164
|
action.timeScale = 1;
|
|
165
|
+
const clip = action.getClip();
|
|
166
|
+
if(options?.minMaxOffsetNormalized) action.time = Mathf.lerp(options.minMaxOffsetNormalized.x, options.minMaxOffsetNormalized.y, Math.random()) * clip.duration;
|
|
167
|
+
if(options?.minMaxSpeed) action.timeScale = Mathf.lerp(options.minMaxSpeed.x, options.minMaxSpeed.y, Math.random());
|
|
153
168
|
if (options?.clampWhenFinished) action.clampWhenFinished = true;
|
|
154
169
|
if (options?.startTime !== undefined) action.time = options.startTime;
|
|
155
170
|
|
|
@@ -188,6 +188,8 @@ export class AnimatorController {
|
|
|
188
188
|
|
|
189
189
|
private evaluateTransitions() {
|
|
190
190
|
|
|
191
|
+
const currentLayer = 0;
|
|
192
|
+
|
|
191
193
|
let didEnterStateThisFrame = false;
|
|
192
194
|
if (!this._activeState) {
|
|
193
195
|
this.setStartTransition();
|
|
@@ -200,8 +202,11 @@ export class AnimatorController {
|
|
|
200
202
|
let index = 0;
|
|
201
203
|
for (const transition of state.transitions) {
|
|
202
204
|
++index;
|
|
203
|
-
// transition without exit time and without condition are ignored
|
|
204
|
-
if (!transition.hasExitTime && transition.conditions.length <= 0)
|
|
205
|
+
// transition without exit time and without condition that transition to itself are ignored
|
|
206
|
+
if (!transition.hasExitTime && transition.conditions.length <= 0) {
|
|
207
|
+
// if (this._activeState && this.getState(transition.destinationState, currentLayer)?.hash === this._activeState.hash)
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
205
210
|
|
|
206
211
|
let allConditionsAreMet = true;
|
|
207
212
|
for (const cond of transition.conditions) {
|
|
@@ -213,7 +218,7 @@ export class AnimatorController {
|
|
|
213
218
|
if (!allConditionsAreMet) continue;
|
|
214
219
|
|
|
215
220
|
if (debug && allConditionsAreMet) {
|
|
216
|
-
console.log("All conditions are met", transition
|
|
221
|
+
console.log("All conditions are met", transition);
|
|
217
222
|
}
|
|
218
223
|
|
|
219
224
|
// disable triggers
|
|
@@ -279,17 +284,22 @@ export class AnimatorController {
|
|
|
279
284
|
|
|
280
285
|
}
|
|
281
286
|
|
|
287
|
+
private getState(state : State | number, layerIndex:number) : State | null {
|
|
288
|
+
if (typeof state === "number") {
|
|
289
|
+
if (state == -1) state = this.model.layers[layerIndex].stateMachine.defaultState; // exit state -> entry state
|
|
290
|
+
state = this.model.layers[layerIndex].stateMachine.states[state];
|
|
291
|
+
}
|
|
292
|
+
return state;
|
|
293
|
+
}
|
|
294
|
+
|
|
282
295
|
private transitionTo(state: State | number, durationInSec: number, offsetNormalized: number) {
|
|
283
296
|
|
|
284
297
|
if (!this.animator) return;
|
|
285
298
|
|
|
286
299
|
const layerIndex = 0;
|
|
287
300
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
state = this.model.layers[layerIndex].stateMachine.states[state];
|
|
291
|
-
}
|
|
292
|
-
|
|
301
|
+
state = this.getState(state, layerIndex) as State;
|
|
302
|
+
|
|
293
303
|
if (!state?.motion || !state.motion.clip) {
|
|
294
304
|
// if(debug) console.warn("State has no clip or motion", state);
|
|
295
305
|
return;
|
|
@@ -409,7 +419,7 @@ export class AnimatorController {
|
|
|
409
419
|
const sm = layer.stateMachine;
|
|
410
420
|
for (let index = 0; index < sm.states.length; index++) {
|
|
411
421
|
const state = sm.states[index];
|
|
412
|
-
|
|
422
|
+
|
|
413
423
|
// ensure we have a motion even if none was exported
|
|
414
424
|
if (!state.motion) {
|
|
415
425
|
state.motion = createMotion(state.name);
|
|
@@ -9,12 +9,12 @@ const gizmos = getParam("gizmos");
|
|
|
9
9
|
export class BoxHelperComponent extends Behaviour {
|
|
10
10
|
|
|
11
11
|
private box: THREE.Box3 | null = null;
|
|
12
|
-
private testBox: THREE.Box3 = new THREE.Box3();
|
|
12
|
+
private static testBox: THREE.Box3 = new THREE.Box3();
|
|
13
13
|
private _lastMatrixUpdateFrame: number = -1;
|
|
14
14
|
private static _position: THREE.Vector3 = new THREE.Vector3();
|
|
15
15
|
private static _size: THREE.Vector3 = new THREE.Vector3(.01, .01, .01);
|
|
16
16
|
|
|
17
|
-
public isInBox(obj: THREE.Object3D): boolean | undefined {
|
|
17
|
+
public isInBox(obj: THREE.Object3D, scaleFactor? : number): boolean | undefined {
|
|
18
18
|
if (!obj) return undefined;
|
|
19
19
|
|
|
20
20
|
// if (!obj.geometry.boundingBox) obj.geometry.computeBoundingBox();
|
|
@@ -23,22 +23,39 @@ export class BoxHelperComponent extends Behaviour {
|
|
|
23
23
|
if (!this.box) {
|
|
24
24
|
this.box = new THREE.Box3();
|
|
25
25
|
}
|
|
26
|
-
this.updateBox(false);
|
|
27
26
|
|
|
28
|
-
if (obj.type === "Mesh")
|
|
29
|
-
|
|
27
|
+
if (obj.type === "Mesh") {
|
|
28
|
+
BoxHelperComponent.testBox.setFromObject(obj);
|
|
29
|
+
}
|
|
30
|
+
else if (obj.type === "Group") {
|
|
31
|
+
if (obj.children.length > 0) {
|
|
32
|
+
BoxHelperComponent.testBox.setFromCenterAndSize(
|
|
33
|
+
BoxHelperComponent._position.set(0, 0, 0),
|
|
34
|
+
BoxHelperComponent._size.set(0, 0, 0)
|
|
35
|
+
);
|
|
36
|
+
for (let i = 0; i < obj.children.length; i++) {
|
|
37
|
+
const ch = obj.children[i];
|
|
38
|
+
if (ch.type === "Mesh") {
|
|
39
|
+
BoxHelperComponent.testBox.expandByObject(obj);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
30
44
|
else {
|
|
31
45
|
const wp = getWorldPosition(obj, BoxHelperComponent._position);
|
|
32
46
|
const size = getWorldScale(obj, BoxHelperComponent._size);
|
|
33
|
-
|
|
47
|
+
if(scaleFactor !== undefined) size.multiplyScalar(scaleFactor);
|
|
48
|
+
BoxHelperComponent.testBox.setFromCenterAndSize(wp, size);
|
|
34
49
|
}
|
|
35
50
|
|
|
51
|
+
// console.log("Obj box:", obj.name, obj.uuid, BoxHelperComponent.testBox.getCenter(new THREE.Vector3()), BoxHelperComponent.testBox.getSize(new THREE.Vector3()),
|
|
52
|
+
// "\nTest box:", this.box.getCenter(new THREE.Vector3()), this.box.getSize(new THREE.Vector3()), this.context.time.frameCount);
|
|
36
53
|
// this.tp.copy(obj.geometry.boundingBox);
|
|
37
54
|
// // this.tp.setFromCenterAndSize(obj.position, obj.scale);
|
|
38
55
|
// this.tp.applyMatrix4(obj.matrixWorld);
|
|
39
56
|
// console.log(this.tp);
|
|
40
57
|
// console.log(this.box?.min, this.box?.max, this.tp.min, this.tp.max);
|
|
41
|
-
return this.box?.intersectsBox(
|
|
58
|
+
return this.box?.intersectsBox(BoxHelperComponent.testBox);
|
|
42
59
|
}
|
|
43
60
|
|
|
44
61
|
public intersects(box: THREE.Box3): boolean {
|
|
@@ -51,9 +68,12 @@ export class BoxHelperComponent extends Behaviour {
|
|
|
51
68
|
this.box = new THREE.Box3();
|
|
52
69
|
}
|
|
53
70
|
if (force || this.context.time.frameCount != this._lastMatrixUpdateFrame) {
|
|
71
|
+
const firstUpdate = this._lastMatrixUpdateFrame < 0;
|
|
54
72
|
this._lastMatrixUpdateFrame = this.context.time.frameCount;
|
|
55
|
-
|
|
56
|
-
|
|
73
|
+
const updateParents: boolean = firstUpdate; // updating parents seems to cause falsely calculated positions sometimes?
|
|
74
|
+
const wp = getWorldPosition(this.gameObject, BoxHelperComponent._position, updateParents);
|
|
75
|
+
const size = getWorldScale(this.gameObject, BoxHelperComponent._size);
|
|
76
|
+
this.box.setFromCenterAndSize(wp, size);
|
|
57
77
|
}
|
|
58
78
|
return this.box;
|
|
59
79
|
}
|
|
@@ -8,7 +8,7 @@ import { Object3D } from "three";
|
|
|
8
8
|
import { syncDestroy, syncInstantiate } from "../engine/engine_networking_instantiate";
|
|
9
9
|
import { ConstructorConcrete, SourceIdentifier, IComponent, IGameObject, Constructor, GuidsMap, UIDProvider, Collision } from "../engine/engine_types";
|
|
10
10
|
import { addNewComponentInstance, destroyComponentInstance, findObjectOfType, findObjectsOfType, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, moveComponentInstance, removeComponent } from "../engine/engine_components";
|
|
11
|
-
import { findByGuid, destroy, InstantiateOptions, instantiate, HideFlags, foreachComponent, markAsInstancedRendered, isActiveInHierarchy, isActiveSelf, isUsingInstancing } from "../engine/engine_gameobject";
|
|
11
|
+
import { findByGuid, destroy, InstantiateOptions, instantiate, HideFlags, foreachComponent, markAsInstancedRendered, isActiveInHierarchy, isActiveSelf, isUsingInstancing, setActive } from "../engine/engine_gameobject";
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
// export interface ISerializationCallbackReceiver {
|
|
@@ -23,10 +23,10 @@ abstract class GameObject extends THREE.Object3D implements THREE.Object3D, IGam
|
|
|
23
23
|
|
|
24
24
|
guid: string | undefined;
|
|
25
25
|
|
|
26
|
-
public static setActive(go: THREE.Object3D, active: boolean, processStart: boolean = true) {
|
|
26
|
+
public static setActive(go: THREE.Object3D, active: boolean, processStart: boolean = true, setVisible: boolean = true) {
|
|
27
27
|
if (!go) return;
|
|
28
|
-
go
|
|
29
|
-
main.
|
|
28
|
+
setActive(go, active, setVisible);
|
|
29
|
+
main.updateIsActive(go);
|
|
30
30
|
if (active && processStart)
|
|
31
31
|
main.processStart(Context.Current, go);
|
|
32
32
|
}
|
|
@@ -82,10 +82,12 @@ abstract class GameObject extends THREE.Object3D implements THREE.Object3D, IGam
|
|
|
82
82
|
context = Context.Current;
|
|
83
83
|
}
|
|
84
84
|
parent.add(instance);
|
|
85
|
-
|
|
85
|
+
setActive(instance, true);
|
|
86
|
+
main.updateIsActive(instance);
|
|
86
87
|
if (context) {
|
|
87
88
|
GameObject.foreachComponent(instance, (comp: Component) => {
|
|
88
89
|
main.addScriptToArrays(comp, context!);
|
|
90
|
+
if(comp.__internalDidAwakeAndStart) return;
|
|
89
91
|
if (context!.new_script_start.includes(comp) === false) {
|
|
90
92
|
context!.new_script_start.push(comp as Behaviour);
|
|
91
93
|
}
|
|
@@ -102,6 +104,8 @@ abstract class GameObject extends THREE.Object3D implements THREE.Object3D, IGam
|
|
|
102
104
|
public static remove(instance: THREE.Object3D | null | undefined) {
|
|
103
105
|
if (!instance) return;
|
|
104
106
|
instance.parent?.remove(instance);
|
|
107
|
+
setActive(instance, false);
|
|
108
|
+
main.updateIsActive(instance);
|
|
105
109
|
GameObject.foreachComponent(instance, (comp) => {
|
|
106
110
|
main.processRemoveFromScene(comp);
|
|
107
111
|
}, true);
|
|
@@ -354,6 +358,8 @@ class Component implements IComponent, EventTarget {
|
|
|
354
358
|
protected __isEnabled: boolean | undefined = undefined;
|
|
355
359
|
private __destroyed: boolean = false;
|
|
356
360
|
|
|
361
|
+
get __internalDidAwakeAndStart() { return this.__didAwake && this.__didStart; }
|
|
362
|
+
|
|
357
363
|
__internalNewInstanceCreated() {
|
|
358
364
|
this.__didAwake = false;
|
|
359
365
|
this.__didStart = false;
|
|
@@ -41,12 +41,13 @@ export class GroundProjectedEnv extends Behaviour {
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
onEnable() {
|
|
44
|
-
this.
|
|
45
|
-
if (
|
|
46
|
-
this.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
// TODO: if we do this in the first frame we can not disable it again. Something buggy with the watch?!
|
|
45
|
+
if (this.context.time.frameCount > 0)
|
|
46
|
+
this.updateAndCreate();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
start() {
|
|
50
|
+
this.updateAndCreate();
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
onDisable() {
|
|
@@ -54,8 +55,22 @@ export class GroundProjectedEnv extends Behaviour {
|
|
|
54
55
|
this.env?.removeFromParent();
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
private updateAndCreate() {
|
|
59
|
+
this.updateProjection();
|
|
60
|
+
if (!this._watcher) {
|
|
61
|
+
this._watcher = new Watch(this.context.scene, "environment");
|
|
62
|
+
this._watcher.subscribeWrite(_ => {
|
|
63
|
+
this.updateProjection();
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
this._watcher.apply();
|
|
67
|
+
}
|
|
68
|
+
|
|
57
69
|
updateProjection() {
|
|
58
|
-
if (!this.context.scene.environment)
|
|
70
|
+
if (!this.context.scene.environment) {
|
|
71
|
+
this.env?.removeFromParent();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
59
74
|
if (!this.env || this.context.scene.environment !== this._lastEnvironment) {
|
|
60
75
|
console.log("Create/Update Ground Projection", this.context.scene.environment.name);
|
|
61
76
|
this.env = new GroundProjection(this.context.scene.environment);
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Behaviour } from "./Component";
|
|
2
|
+
import { Box3, Color, EquirectangularReflectionMapping, LineBasicMaterial, Material, MeshStandardMaterial, Object3D, sRGBEncoding, Texture, Vector3, WebGLCubeRenderTarget, WebGLRenderTarget } from "three";
|
|
3
|
+
import { serializeable } from "../engine/engine_serialization";
|
|
4
|
+
import { Context } from "../engine/engine_setup";
|
|
5
|
+
import { getWorldPosition, getWorldScale } from "../engine/engine_three_utils";
|
|
6
|
+
import { IRenderer } from "../engine/engine_types";
|
|
7
|
+
import { BoxHelperComponent } from "./BoxHelperComponent";
|
|
8
|
+
import { getParam } from "../engine/engine_utils";
|
|
9
|
+
|
|
10
|
+
export const debug = getParam("debugreflectionprobe");
|
|
11
|
+
const disable = getParam("noreflectionprobe");
|
|
12
|
+
|
|
13
|
+
export class ReflectionProbe extends Behaviour {
|
|
14
|
+
|
|
15
|
+
private static _probes: Map<Context, ReflectionProbe[]> = new Map();
|
|
16
|
+
|
|
17
|
+
public static get(object: Object3D | null | undefined, context: Context, isAnchor:boolean): ReflectionProbe | null {
|
|
18
|
+
if (!object || object.isObject3D !== true) return null;
|
|
19
|
+
if (disable) return null;
|
|
20
|
+
const probes = ReflectionProbe._probes.get(context);
|
|
21
|
+
if (probes) {
|
|
22
|
+
for (const probe of probes) {
|
|
23
|
+
if (!probe.__didAwake) probe.__internalAwake();
|
|
24
|
+
if (probe.enabled && probe.isInBox(object, isAnchor ? .00000001 : undefined)) {
|
|
25
|
+
if (debug) console.log("Found reflection probe", object.name, probe.name);
|
|
26
|
+
return probe;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (debug)
|
|
31
|
+
console.debug("Did not find reflection probe", object.name, isAnchor, object);
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
private _texture!: Texture;
|
|
38
|
+
set texture(tex: Texture) {
|
|
39
|
+
this._texture = tex;
|
|
40
|
+
}
|
|
41
|
+
get texture(): Texture {
|
|
42
|
+
return this._texture;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@serializeable(Vector3)
|
|
46
|
+
center?: Vector3;
|
|
47
|
+
@serializeable(Vector3)
|
|
48
|
+
size?: Vector3;
|
|
49
|
+
|
|
50
|
+
private _boxHelper?: BoxHelperComponent;
|
|
51
|
+
|
|
52
|
+
private isInBox(obj: Object3D, scaleFactor?: number) {
|
|
53
|
+
return this._boxHelper?.isInBox(obj, scaleFactor);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
constructor() {
|
|
57
|
+
super();
|
|
58
|
+
if (!ReflectionProbe._probes.has(this.context)) {
|
|
59
|
+
ReflectionProbe._probes.set(this.context, []);
|
|
60
|
+
}
|
|
61
|
+
ReflectionProbe._probes.get(this.context)?.push(this);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
awake() {
|
|
65
|
+
this._boxHelper = this.gameObject.addNewComponent(BoxHelperComponent) as BoxHelperComponent;
|
|
66
|
+
this._boxHelper.updateBox(true);
|
|
67
|
+
if (debug)
|
|
68
|
+
this._boxHelper.showHelper(0x555500, true);
|
|
69
|
+
|
|
70
|
+
if (this.texture) {
|
|
71
|
+
this.texture.mapping = EquirectangularReflectionMapping;
|
|
72
|
+
this.texture.encoding = sRGBEncoding;
|
|
73
|
+
// this.texture.rotation = Math.PI;
|
|
74
|
+
// this.texture.flipY = true;
|
|
75
|
+
this.texture.needsUpdate = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
onDestroy() {
|
|
80
|
+
const probes = ReflectionProbe._probes.get(this.context);
|
|
81
|
+
if (probes) {
|
|
82
|
+
const index = probes.indexOf(this);
|
|
83
|
+
if (index >= 0) {
|
|
84
|
+
probes.splice(index, 1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
// when objects are rendered and they share material
|
|
91
|
+
// and some need reflection probe and some don't
|
|
92
|
+
// we need to make sure we don't override the material but use a copy
|
|
93
|
+
|
|
94
|
+
private static _rendererMaterialsCache: Map<IRenderer, Array<{ orig: Material, copy: Material }>> = new Map();
|
|
95
|
+
|
|
96
|
+
onSet(_rend: IRenderer) {
|
|
97
|
+
if (disable) return;
|
|
98
|
+
if (_rend.sharedMaterials?.length <= 0) return;
|
|
99
|
+
if (!this.texture) return;
|
|
100
|
+
|
|
101
|
+
let rendererCache = ReflectionProbe._rendererMaterialsCache.get(_rend);
|
|
102
|
+
if (!rendererCache) {
|
|
103
|
+
rendererCache = [];
|
|
104
|
+
ReflectionProbe._rendererMaterialsCache.set(_rend, rendererCache);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// TODO: dont clone material for every renderer that uses reflection probes, we can do it once per material when they use the same reflection texture
|
|
108
|
+
|
|
109
|
+
// need to make sure materials are not shared when using reflection probes
|
|
110
|
+
// otherwise some renderers outside of the probe will be affected or vice versa
|
|
111
|
+
for (let i = 0; i < _rend.sharedMaterials.length; i++) {
|
|
112
|
+
const orig = _rend.sharedMaterials[i];
|
|
113
|
+
if (!orig) continue;
|
|
114
|
+
if (orig["envMap"] === undefined) continue;
|
|
115
|
+
let cached = rendererCache[i];
|
|
116
|
+
let copy = cached?.copy;
|
|
117
|
+
if (!cached) {
|
|
118
|
+
const clone = orig.clone();
|
|
119
|
+
copy = clone;
|
|
120
|
+
rendererCache.push({ orig, copy });
|
|
121
|
+
|
|
122
|
+
copy["__reflection_probe"] = this;
|
|
123
|
+
copy["envMap"] = this.texture;
|
|
124
|
+
|
|
125
|
+
if (debug)
|
|
126
|
+
console.log("Set reflection", _rend.name, _rend.guid);
|
|
127
|
+
}
|
|
128
|
+
_rend.sharedMaterials[i] = copy;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
onUnset(_rend: IRenderer) {
|
|
133
|
+
const rendererCache = ReflectionProbe._rendererMaterialsCache.get(_rend);
|
|
134
|
+
if (rendererCache) {
|
|
135
|
+
for (let i = 0; i < rendererCache.length; i++) {
|
|
136
|
+
const cached = rendererCache[i];
|
|
137
|
+
_rend.sharedMaterials[i] = cached.orig;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|