@needle-tools/engine 3.2.5-alpha → 3.2.6-alpha
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 +12 -0
- package/dist/needle-engine.js +7125 -6981
- package/dist/needle-engine.min.js +277 -277
- package/dist/needle-engine.umd.cjs +275 -275
- package/lib/engine/api.d.ts +4 -1
- package/lib/engine/api.js +3 -1
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/engine_context.d.ts +4 -2
- package/lib/engine/engine_context.js +5 -3
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_element_loading.js +0 -1
- package/lib/engine/engine_element_loading.js.map +1 -1
- package/lib/engine/engine_mainloop_utils.js +4 -2
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_scenelighting.d.ts +68 -0
- package/lib/engine/{engine_rendererdata.js → engine_scenelighting.js} +102 -30
- package/lib/engine/engine_scenelighting.js.map +1 -0
- package/lib/engine/engine_serialization_core.d.ts +5 -8
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_lighting_settings.d.ts +3 -1
- package/lib/engine/extensions/NEEDLE_lighting_settings.js +32 -20
- package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_techniques_webgl.js +3 -3
- package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
- package/lib/engine/extensions/index.d.ts +5 -0
- package/lib/engine/extensions/index.js +6 -0
- package/lib/engine/extensions/index.js.map +1 -0
- package/lib/engine-components/Component.js +15 -3
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/Renderer.js +1 -1
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.d.ts +2 -0
- package/lib/engine-components/SceneSwitcher.js +16 -4
- package/lib/engine-components/SceneSwitcher.js.map +1 -1
- package/lib/engine-components/api.d.ts +1 -0
- package/lib/engine-components/api.js +1 -0
- package/lib/engine-components/api.js.map +1 -1
- package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +1 -1
- package/lib/engine-components/postprocessing/VolumeParameter.d.ts +1 -1
- package/lib/engine-components/postprocessing/VolumeParameter.js +7 -6
- package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
- package/lib/engine-components/webxr/index.d.ts +2 -0
- package/lib/engine-components/webxr/index.js +2 -0
- package/lib/engine-components/webxr/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/engine/api.ts +4 -1
- package/src/engine/engine_context.ts +5 -3
- package/src/engine/engine_element_loading.ts +0 -1
- package/src/engine/engine_mainloop_utils.ts +4 -2
- package/src/engine/{engine_rendererdata.ts → engine_scenelighting.ts} +109 -36
- package/src/engine/engine_serialization_core.ts +7 -8
- package/src/engine/extensions/NEEDLE_lighting_settings.ts +40 -25
- package/src/engine/extensions/NEEDLE_techniques_webgl.ts +3 -3
- package/src/engine/extensions/index.ts +5 -0
- package/src/engine-components/Component.ts +15 -3
- package/src/engine-components/Renderer.ts +1 -1
- package/src/engine-components/SceneSwitcher.ts +14 -4
- package/src/engine-components/api.ts +1 -0
- package/src/engine-components/postprocessing/PostProcessingHandler.ts +1 -1
- package/src/engine-components/postprocessing/VolumeParameter.ts +7 -6
- package/src/engine-components/webxr/index.ts +3 -1
- package/lib/engine/engine_rendererdata.d.ts +0 -49
- package/lib/engine/engine_rendererdata.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.6-alpha",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in",
|
|
5
5
|
"main": "dist/needle-engine.umd.cjs",
|
|
6
6
|
"type": "module",
|
package/src/engine/api.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
export * from "./extensions
|
|
2
|
+
export * from "./extensions"
|
|
3
3
|
export * from "./engine_addressables";
|
|
4
4
|
export * from "./engine_application"
|
|
5
5
|
export * from "./engine_assetdatabase"
|
|
@@ -27,12 +27,15 @@ export * from "./engine_patcher"
|
|
|
27
27
|
export * from "./engine_playerview"
|
|
28
28
|
export * from "./engine_physics"
|
|
29
29
|
export * from "./engine_physics.types"
|
|
30
|
+
export * from "./engine_scenelighting"
|
|
30
31
|
export * from "./engine_input";
|
|
31
32
|
export * from "./engine_math";
|
|
32
33
|
export * from "./js-extensions";
|
|
33
34
|
export * from "./engine_scenetools";
|
|
34
35
|
export * from "./engine_serialization";
|
|
36
|
+
export { type ISerializable } from "./engine_serialization_core";
|
|
35
37
|
export * from "./engine_texture";
|
|
38
|
+
export * from "./engine_three_utils";
|
|
36
39
|
export * from "./engine_time";
|
|
37
40
|
export * from "./engine_types";
|
|
38
41
|
export * from "./engine_utils_screenshot";
|
|
@@ -18,7 +18,7 @@ import { AssetDatabase } from './engine_assetdatabase';
|
|
|
18
18
|
import { logHierarchy } from './engine_three_utils';
|
|
19
19
|
|
|
20
20
|
import * as Stats from 'three/examples/jsm/libs/stats.module';
|
|
21
|
-
import { RendererData } from './
|
|
21
|
+
import { RendererData as SceneLighting } from './engine_scenelighting';
|
|
22
22
|
import { Addressables } from './engine_addressables';
|
|
23
23
|
import { Application } from './engine_application';
|
|
24
24
|
import { LightDataRegistry, ILightDataRegistry } from './engine_lightdata';
|
|
@@ -225,7 +225,9 @@ export class Context implements IContext {
|
|
|
225
225
|
*/
|
|
226
226
|
assets: AssetDatabase;
|
|
227
227
|
mainLight: ILight | null = null;
|
|
228
|
-
|
|
228
|
+
/** @deprecated Use sceneLighting */
|
|
229
|
+
get rendererData() { return this.sceneLighting }
|
|
230
|
+
sceneLighting: SceneLighting;
|
|
229
231
|
addressables: Addressables;
|
|
230
232
|
lightmaps: ILightDataRegistry;
|
|
231
233
|
players: PlayerViewManager;
|
|
@@ -278,7 +280,7 @@ export class Context implements IContext {
|
|
|
278
280
|
this.physics = new Physics(this);
|
|
279
281
|
this.connection = new NetworkConnection(this);
|
|
280
282
|
this.assets = new AssetDatabase();
|
|
281
|
-
this.
|
|
283
|
+
this.sceneLighting = new SceneLighting(this);
|
|
282
284
|
this.addressables = new Addressables(this);
|
|
283
285
|
this.lightmaps = new LightDataRegistry(this);
|
|
284
286
|
this.players = new PlayerViewManager(this);
|
|
@@ -176,7 +176,6 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
176
176
|
this._loadingElement = existing || document.createElement("div");
|
|
177
177
|
|
|
178
178
|
const loadingStyle: LoadingStyleOption = this._element.getAttribute("loading-style") as LoadingStyleOption;
|
|
179
|
-
console.log(loadingStyle);
|
|
180
179
|
|
|
181
180
|
const hasLicense = hasProLicense();
|
|
182
181
|
if (!existing) {
|
|
@@ -267,8 +267,10 @@ function updateIsActiveInHierarchyRecursiveRuntime(go: Object3D, activeInHierarc
|
|
|
267
267
|
if (activeInHierarchy) {
|
|
268
268
|
if (comp.enabled) {
|
|
269
269
|
utils.safeInvoke(comp.__internalAwake.bind(comp));
|
|
270
|
-
comp
|
|
271
|
-
|
|
270
|
+
if (comp.enabled) {
|
|
271
|
+
comp["__didEnable"] = true;
|
|
272
|
+
comp.onEnable();
|
|
273
|
+
}
|
|
272
274
|
}
|
|
273
275
|
}
|
|
274
276
|
else {
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { Vector4, EquirectangularReflectionMapping, sRGBEncoding, WebGLCubeRenderTarget, Texture, LightProbe, Color } from "three";
|
|
1
|
+
import { Vector4, EquirectangularReflectionMapping, sRGBEncoding, WebGLCubeRenderTarget, Texture, LightProbe, Color, SphericalHarmonics3 } from "three";
|
|
2
2
|
import { LightProbeGenerator } from "three/examples/jsm/lights/LightProbeGenerator.js"
|
|
3
3
|
import { Context } from "./engine_setup";
|
|
4
4
|
import { SceneLightSettings } from "./extensions/NEEDLE_lighting_settings";
|
|
5
5
|
import { createFlatTexture, createTrilightTexture } from "./engine_shaders";
|
|
6
6
|
import { getParam } from "./engine_utils";
|
|
7
7
|
import { SourceIdentifier } from "./engine_types";
|
|
8
|
+
import { AssetReference } from "./engine_addressables";
|
|
8
9
|
|
|
9
10
|
const debug = getParam("debugenvlight");
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
export declare type SphericalHarmonicsData = {
|
|
13
14
|
array: number[],
|
|
14
|
-
texture:
|
|
15
|
+
texture: WebGLCubeRenderTarget | Texture,
|
|
15
16
|
lightProbe?: LightProbe
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -36,8 +37,8 @@ export class RendererData {
|
|
|
36
37
|
this.context.pre_update_callbacks.push(this.preUpdate.bind(this))
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
private
|
|
40
|
-
private
|
|
40
|
+
private _currentLightSettingsId?: SourceIdentifier;
|
|
41
|
+
private _sceneLightSettings?: Map<SourceIdentifier, SceneLightSettings>;
|
|
41
42
|
|
|
42
43
|
private preUpdate() {
|
|
43
44
|
const time = this.context.time;
|
|
@@ -52,40 +53,103 @@ export class RendererData {
|
|
|
52
53
|
return this._timevec4;
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
/** the current environment intensity */
|
|
55
57
|
get environmentIntensity(): number {
|
|
56
|
-
if (!this.
|
|
57
|
-
if (!this.
|
|
58
|
-
const settings = this.
|
|
59
|
-
if(settings)
|
|
58
|
+
if (!this._sceneLightSettings) return 1;
|
|
59
|
+
if (!this._currentLightSettingsId) return 1;
|
|
60
|
+
const settings = this._sceneLightSettings.get(this._currentLightSettingsId);
|
|
61
|
+
if (settings)
|
|
60
62
|
return settings.ambientIntensity;// * Math.PI * .5;
|
|
61
63
|
return 1;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
/** Get all currently registered scene light settings */
|
|
67
|
+
get sceneLightSettings() { return this._sceneLightSettings?.values() }
|
|
68
|
+
|
|
69
|
+
/** set the scene lighting from a specific scene. Will disable any previously enabled lighting settings */
|
|
70
|
+
enable(sourceId: SourceIdentifier | AssetReference) {
|
|
71
|
+
if(sourceId instanceof AssetReference)
|
|
72
|
+
sourceId = sourceId.uri;
|
|
73
|
+
const settings = this._sceneLightSettings?.get(sourceId);
|
|
74
|
+
if (!settings) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (debug) console.log("Enable scene light settings", sourceId, settings);
|
|
78
|
+
if (sourceId !== this._currentLightSettingsId && this._currentLightSettingsId) {
|
|
79
|
+
this.disable(this._currentLightSettingsId);
|
|
80
|
+
}
|
|
81
|
+
this._currentLightSettingsId = sourceId;
|
|
82
|
+
settings.enabled = true;
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** disable the lighting of a specific scene, will only have any effect if it is currently active */
|
|
87
|
+
disable(sourceId: SourceIdentifier | AssetReference) {
|
|
88
|
+
if(sourceId instanceof AssetReference)
|
|
89
|
+
sourceId = sourceId.uri;
|
|
90
|
+
if (sourceId === null || sourceId === undefined) return false;
|
|
91
|
+
const settings = this._sceneLightSettings?.get(sourceId);
|
|
92
|
+
if (!settings) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
if (debug) console.log("Disable scene light settings", sourceId, settings);
|
|
96
|
+
settings.enabled = false;
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Disables the currently active scene lighting (if any), returns the id of the previously active lighting */
|
|
101
|
+
disableCurrent() : SourceIdentifier | null {
|
|
102
|
+
if (this._currentLightSettingsId) {
|
|
103
|
+
const prev = this._currentLightSettingsId;
|
|
104
|
+
this.disable(this._currentLightSettingsId);
|
|
105
|
+
return prev
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
/** @internal */
|
|
112
|
+
internalRegisterSceneLightSettings(sceneLightSettings: SceneLightSettings) {
|
|
65
113
|
const sourceId = sceneLightSettings.sourceId;
|
|
66
|
-
if(!sourceId){
|
|
114
|
+
if (!sourceId) {
|
|
67
115
|
console.error("Missing source id for scene light settings, can not register:", sceneLightSettings);
|
|
68
116
|
return;
|
|
69
117
|
}
|
|
70
|
-
if (debug) console.log("Register
|
|
71
|
-
if (!this.
|
|
72
|
-
this.
|
|
118
|
+
if (debug) console.log("Register " + sceneLightSettings?.sourceId + " lighting", sceneLightSettings);
|
|
119
|
+
if (!this._sceneLightSettings) this._sceneLightSettings = new Map();
|
|
120
|
+
this._sceneLightSettings.set(sourceId, sceneLightSettings);
|
|
73
121
|
}
|
|
74
122
|
|
|
75
|
-
|
|
123
|
+
/** @internal */
|
|
124
|
+
internalUnregisterSceneLightSettings(sceneLightSettings: SceneLightSettings) {
|
|
125
|
+
const sourceId = sceneLightSettings.sourceId;
|
|
126
|
+
if (!sourceId) {
|
|
127
|
+
console.error("Missing source id for scene light settings, can not unregister:", sceneLightSettings);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (debug) console.log("Unregister " + sceneLightSettings?.sourceId + " lighting", sceneLightSettings);
|
|
131
|
+
if (!this._sceneLightSettings) return;
|
|
132
|
+
this._sceneLightSettings.delete(sourceId);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** @internal */
|
|
136
|
+
internalRegisterReflection(sourceId: SourceIdentifier, reflectionTexture: Texture) {
|
|
76
137
|
if (debug) console.log("Register reflection", sourceId, reflectionTexture);
|
|
77
138
|
const h = new LightData(this.context, reflectionTexture, 1);
|
|
78
139
|
this._lighting[sourceId] = h;
|
|
79
140
|
}
|
|
80
141
|
|
|
81
|
-
|
|
142
|
+
/** @internal */
|
|
143
|
+
internalGetReflection(sourceId: SourceIdentifier): LightData | null | undefined {
|
|
82
144
|
return this._lighting[sourceId];
|
|
83
145
|
}
|
|
84
146
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
147
|
+
private __currentReflectionId: SourceIdentifier | null = null;
|
|
148
|
+
|
|
149
|
+
/** @internal */
|
|
150
|
+
internalEnableReflection(sourceId: SourceIdentifier) {
|
|
151
|
+
this.__currentReflectionId = sourceId;
|
|
152
|
+
const settings = this._sceneLightSettings?.get(sourceId);
|
|
89
153
|
|
|
90
154
|
if (debug) {
|
|
91
155
|
console.log("Enable reflection", sourceId, settings ? AmbientMode[settings.ambientMode] : "Unknown ambient mode");
|
|
@@ -95,9 +159,9 @@ export class RendererData {
|
|
|
95
159
|
case AmbientMode.Skybox:
|
|
96
160
|
case AmbientMode.Custom:
|
|
97
161
|
// only set environment reflection when ambient mode is skybox or custom
|
|
98
|
-
const existing = this.
|
|
162
|
+
const existing = this.internalGetReflection(sourceId);
|
|
99
163
|
if (existing && existing.Source) {
|
|
100
|
-
if (debug) console.log("Setting environment reflection", existing
|
|
164
|
+
if (debug) console.log("Setting environment reflection", existing);
|
|
101
165
|
const scene = this.context.scene;
|
|
102
166
|
const tex = existing.Source;
|
|
103
167
|
tex.encoding = sRGBEncoding;
|
|
@@ -136,13 +200,19 @@ export class RendererData {
|
|
|
136
200
|
}
|
|
137
201
|
}
|
|
138
202
|
|
|
139
|
-
|
|
140
|
-
|
|
203
|
+
/** @internal */
|
|
204
|
+
internalDisableReflection(sourceId?: SourceIdentifier) {
|
|
205
|
+
if (sourceId && sourceId !== this.__currentReflectionId) {
|
|
206
|
+
if(debug) console.log("Not disabling reflection for", sourceId, "because it is not the current light settings id", this.__currentReflectionId)
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (debug) console.log("Disable reflection", sourceId)
|
|
141
210
|
const scene = this.context.scene;
|
|
142
211
|
scene.environment = null;
|
|
143
212
|
}
|
|
144
213
|
|
|
145
|
-
|
|
214
|
+
/** @internal */
|
|
215
|
+
async internalGetSceneLightingData(sourceId: SourceIdentifier): Promise<SphericalHarmonicsData> {
|
|
146
216
|
if (debug)
|
|
147
217
|
console.log("GET SCENE LIGHT DATA", sourceId);
|
|
148
218
|
|
|
@@ -157,7 +227,7 @@ export class RendererData {
|
|
|
157
227
|
if (this._waitPromise) return this._waitPromise;
|
|
158
228
|
this._waitPromise = new Promise((res, _rej) => {
|
|
159
229
|
let interval = setInterval(async () => {
|
|
160
|
-
const ex = this.
|
|
230
|
+
const ex = this.internalGetReflection(sourceId);
|
|
161
231
|
if (ex) {
|
|
162
232
|
clearInterval(interval);
|
|
163
233
|
res(ex.getSphericalHarmonicsArray(this.environmentIntensity ?? 1)!);
|
|
@@ -178,13 +248,13 @@ export class LightData {
|
|
|
178
248
|
get Array(): number[] | undefined { return this._sphericalHarmonicsArray; }
|
|
179
249
|
|
|
180
250
|
private _context: Context;
|
|
181
|
-
private _source:
|
|
182
|
-
private _sphericalHarmonics:
|
|
251
|
+
private _source: Texture;
|
|
252
|
+
private _sphericalHarmonics: SphericalHarmonics3 | null = null;
|
|
183
253
|
private _sphericalHarmonicsArray?: number[];
|
|
184
254
|
private _ambientScale: number = 1;
|
|
185
255
|
private _lightProbe?: LightProbe;
|
|
186
256
|
|
|
187
|
-
constructor(context: Context, tex:
|
|
257
|
+
constructor(context: Context, tex: Texture, ambientScale: number = 1) {
|
|
188
258
|
this._context = context;
|
|
189
259
|
this._source = tex;
|
|
190
260
|
this._ambientScale = ambientScale;
|
|
@@ -199,13 +269,14 @@ export class LightData {
|
|
|
199
269
|
|
|
200
270
|
try {
|
|
201
271
|
const reflection = this._source;
|
|
202
|
-
let rt:
|
|
272
|
+
let rt: WebGLCubeRenderTarget | null = null;
|
|
203
273
|
if (reflection) {
|
|
204
274
|
if (debug) console.log("GENERATING LIGHT PROBE", reflection, this.Source);
|
|
205
275
|
const size = Math.min(reflection.image.width, 512);
|
|
206
276
|
const target = new WebGLCubeRenderTarget(size);
|
|
207
277
|
rt = target.fromEquirectangularTexture(this._context.renderer, reflection);
|
|
208
|
-
this.
|
|
278
|
+
// Not sure why we did assign the resulting texture here again but this causes rendering to break when toggling env lighting (e.g. on website) because this texture will then be set as the scene.environment
|
|
279
|
+
// this._source = rt.texture;
|
|
209
280
|
}
|
|
210
281
|
|
|
211
282
|
this._sphericalHarmonicsArray = [];
|
|
@@ -216,13 +287,15 @@ export class LightData {
|
|
|
216
287
|
// console.log(intensityFactor, lightFactor);
|
|
217
288
|
this._sphericalHarmonics = sampledProbe.sh;
|
|
218
289
|
this._sphericalHarmonicsArray = this._sphericalHarmonics.toArray();
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
this._sphericalHarmonicsArray
|
|
290
|
+
if (this._sphericalHarmonicsArray) {
|
|
291
|
+
const factor = ((intensityFactor) / (Math.PI * .5));
|
|
292
|
+
for (let i = 0; i < this._sphericalHarmonicsArray.length; i++) {
|
|
293
|
+
this._sphericalHarmonicsArray[i] *= factor;
|
|
294
|
+
}
|
|
295
|
+
sampledProbe.sh.scale(lightFactor);
|
|
296
|
+
if (this._source)
|
|
297
|
+
return { array: this._sphericalHarmonicsArray, texture: this._source, lightProbe: sampledProbe };
|
|
222
298
|
}
|
|
223
|
-
sampledProbe.sh.scale(lightFactor);
|
|
224
|
-
if (this._source)
|
|
225
|
-
return { array: this._sphericalHarmonicsArray, texture: this._source, lightProbe: sampledProbe };
|
|
226
299
|
}
|
|
227
300
|
}
|
|
228
301
|
catch (err) {
|
|
@@ -3,7 +3,7 @@ import { getParam } from "./engine_utils";
|
|
|
3
3
|
import { AnimationClip, Material, Mesh, Object3D, Texture } from "three";
|
|
4
4
|
import { Context } from "./engine_setup";
|
|
5
5
|
import { isPersistentAsset } from "./extensions/NEEDLE_persistent_assets";
|
|
6
|
-
import { SourceIdentifier } from "./engine_types";
|
|
6
|
+
import { ConstructorConcrete, SourceIdentifier } from "./engine_types";
|
|
7
7
|
import { debugExtension } from "../engine/engine_default_parameters";
|
|
8
8
|
import { LogType, addLog } from "./debug/debug_overlay";
|
|
9
9
|
import { isLocalNetwork } from "./engine_networking_utils";
|
|
@@ -12,7 +12,6 @@ import { $BuiltInTypeFlag } from "./engine_typestore";
|
|
|
12
12
|
const debug = getParam("debugserializer");
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
export type Constructor<T> = { new(...args: any[]): T };
|
|
16
15
|
export declare type NodeToObjectMap = { [nodeId: string]: Object3D };
|
|
17
16
|
export declare type ObjectToNodeMap = { [uuid: string]: number };
|
|
18
17
|
|
|
@@ -125,7 +124,7 @@ export abstract class TypeSerializer implements ITypeSerializer {
|
|
|
125
124
|
// }
|
|
126
125
|
// }
|
|
127
126
|
|
|
128
|
-
constructor(type:
|
|
127
|
+
constructor(type: ConstructorConcrete<any> | ConstructorConcrete<any>[]) {
|
|
129
128
|
if (Array.isArray(type)) {
|
|
130
129
|
for (const key of type)
|
|
131
130
|
helper.register(key.name, this);
|
|
@@ -141,7 +140,7 @@ export abstract class TypeSerializer implements ITypeSerializer {
|
|
|
141
140
|
|
|
142
141
|
|
|
143
142
|
export interface ITypeInformation {
|
|
144
|
-
type?:
|
|
143
|
+
type?: ConstructorConcrete<any>;
|
|
145
144
|
}
|
|
146
145
|
|
|
147
146
|
/** holds information if a field was undefined before serialization. This gives us info if we might want to warn the user about missing attributes */
|
|
@@ -182,7 +181,7 @@ export class SerializationContext {
|
|
|
182
181
|
objectToNode?: ObjectToNodeMap;
|
|
183
182
|
context?: Context;
|
|
184
183
|
path?: string;
|
|
185
|
-
type?:
|
|
184
|
+
type?: ConstructorConcrete<any>;
|
|
186
185
|
/** holds information if a field was undefined before serialization. This gives us info if we might want to warn the user about missing attributes */
|
|
187
186
|
implementationInformation?: ImplementationInformation;
|
|
188
187
|
|
|
@@ -193,7 +192,7 @@ export class SerializationContext {
|
|
|
193
192
|
|
|
194
193
|
|
|
195
194
|
export interface ISerializable {
|
|
196
|
-
$serializedTypes?: { [key: string]:
|
|
195
|
+
$serializedTypes?: { [key: string]: ConstructorConcrete<any> | ITypeInformation | null };
|
|
197
196
|
// onDeserialize?(context: SerializationContext): void;
|
|
198
197
|
// example:
|
|
199
198
|
/* $serializedTypes : {
|
|
@@ -337,7 +336,7 @@ export function deserializeObject(obj: ISerializable, serializedData: object, co
|
|
|
337
336
|
}
|
|
338
337
|
// it can also just contain a constructor
|
|
339
338
|
else {
|
|
340
|
-
const constructor = typeInfoOrConstructor as
|
|
339
|
+
const constructor = typeInfoOrConstructor as ConstructorConcrete<any>;
|
|
341
340
|
return deserializeObjectWithType(data, constructor, context, undefined, obj[key]);
|
|
342
341
|
}
|
|
343
342
|
}
|
|
@@ -460,7 +459,7 @@ declare type TypeDeserializeReference = {
|
|
|
460
459
|
serializer?: ITypeSerializer
|
|
461
460
|
}
|
|
462
461
|
|
|
463
|
-
function deserializeObjectWithType(data: any, typeOrConstructor:
|
|
462
|
+
function deserializeObjectWithType(data: any, typeOrConstructor: ConstructorConcrete<any>, context: SerializationContext, typeContext?: TypeDeserializeReference, currentValue?: any): any {
|
|
464
463
|
|
|
465
464
|
// e.g. @serializable((data) => { })
|
|
466
465
|
let typeIsFunction = typeof typeOrConstructor === "function" && (typeOrConstructor.prototype === undefined);
|
|
@@ -2,11 +2,12 @@ import { AmbientLight, Color, HemisphereLight, Object3D } from "three";
|
|
|
2
2
|
import { GLTF, GLTFLoaderPlugin, GLTFParser } from "three/examples/jsm/loaders/GLTFLoader";
|
|
3
3
|
import { SourceIdentifier } from "../engine_types";
|
|
4
4
|
import { Behaviour, GameObject } from "../../engine-components/Component";
|
|
5
|
-
import { AmbientMode, DefaultReflectionMode } from "../
|
|
5
|
+
import { AmbientMode, DefaultReflectionMode } from "../engine_scenelighting";
|
|
6
6
|
import { LightmapType } from "./NEEDLE_lightmaps";
|
|
7
7
|
import { getParam } from "../engine_utils";
|
|
8
8
|
import { Context } from "../engine_setup";
|
|
9
9
|
import { LightProbe } from "three";
|
|
10
|
+
import { ContextEvent, ContextRegistry } from "../engine_context_registry";
|
|
10
11
|
|
|
11
12
|
export const EXTENSION_NAME = "NEEDLE_lighting_settings";
|
|
12
13
|
const debug = getParam("debugenvlight");
|
|
@@ -42,7 +43,7 @@ export class NEEDLE_lighting_settings implements GLTFLoaderPlugin {
|
|
|
42
43
|
const ext: LightingSettings = extensions[EXTENSION_NAME];
|
|
43
44
|
if (ext) {
|
|
44
45
|
if (debug)
|
|
45
|
-
console.log("
|
|
46
|
+
console.log("Loaded \"" + this.name + "\", src: \"" + this.sourceId + "\"", ext);
|
|
46
47
|
let settings: SceneLightSettings | undefined = undefined;
|
|
47
48
|
// If the result scene has only one child we add the LightingSettingsComponent to that child
|
|
48
49
|
if (_result.scene.children.length === 1) {
|
|
@@ -50,10 +51,9 @@ export class NEEDLE_lighting_settings implements GLTFLoaderPlugin {
|
|
|
50
51
|
settings = GameObject.addNewComponent(_result.scene.children[0], SceneLightSettings, false);
|
|
51
52
|
}
|
|
52
53
|
// if the scene already has multiple children we add it as a new object
|
|
53
|
-
else
|
|
54
|
-
{
|
|
54
|
+
else {
|
|
55
55
|
const lightSettings = new Object3D();
|
|
56
|
-
lightSettings.name = "
|
|
56
|
+
lightSettings.name = "LightSettings " + this.sourceId;
|
|
57
57
|
_result.scene.add(lightSettings);
|
|
58
58
|
settings = GameObject.addNewComponent(lightSettings, SceneLightSettings, false);
|
|
59
59
|
}
|
|
@@ -64,7 +64,6 @@ export class NEEDLE_lighting_settings implements GLTFLoaderPlugin {
|
|
|
64
64
|
settings.ambientTrilight = ext.ambientTrilight.map(c => new Color().fromArray(c));
|
|
65
65
|
settings.ambientMode = ext.ambientMode;
|
|
66
66
|
settings.environmentReflectionSource = ext.environmentReflectionSource;
|
|
67
|
-
if (this.context) this.context.rendererData.registerSceneLightSettings(settings);
|
|
68
67
|
}
|
|
69
68
|
}
|
|
70
69
|
return null;
|
|
@@ -72,6 +71,12 @@ export class NEEDLE_lighting_settings implements GLTFLoaderPlugin {
|
|
|
72
71
|
|
|
73
72
|
}
|
|
74
73
|
|
|
74
|
+
ContextRegistry.registerCallback(ContextEvent.ContextCreated, e => {
|
|
75
|
+
const ctx = e.context as Context;
|
|
76
|
+
const lightingSettings = GameObject.findObjectOfType(SceneLightSettings, ctx as Context);
|
|
77
|
+
if (lightingSettings?.sourceId) ctx.sceneLighting.enable(lightingSettings.sourceId);
|
|
78
|
+
})
|
|
79
|
+
|
|
75
80
|
// exists once per gltf scene root (if it contains reflection)
|
|
76
81
|
// when enabled it does currently automatically set the reflection
|
|
77
82
|
// this might not be desireable
|
|
@@ -85,6 +90,7 @@ export class SceneLightSettings extends Behaviour {
|
|
|
85
90
|
|
|
86
91
|
private _hasReflection: boolean = false;
|
|
87
92
|
private _ambientLightObj?: AmbientLight;
|
|
93
|
+
private _hemisphereLightObj?: HemisphereLight;
|
|
88
94
|
// used when skybox is used to support ambient intensity for "non custom shaders"
|
|
89
95
|
private _lightProbeObj?: LightProbe;
|
|
90
96
|
|
|
@@ -94,11 +100,15 @@ export class SceneLightSettings extends Behaviour {
|
|
|
94
100
|
const tex = this.context.lightmaps.tryGet(this.sourceId, type, 0);
|
|
95
101
|
this._hasReflection = tex !== null && tex !== undefined;
|
|
96
102
|
if (tex)
|
|
97
|
-
this.context.
|
|
103
|
+
this.context.sceneLighting.internalRegisterReflection(this.sourceId, tex);
|
|
98
104
|
}
|
|
99
105
|
|
|
106
|
+
this.enabled = false;
|
|
107
|
+
this.context.sceneLighting.internalRegisterSceneLightSettings(this);
|
|
108
|
+
|
|
100
109
|
if (debug) {
|
|
101
110
|
window.addEventListener("keydown", evt => {
|
|
111
|
+
if(this.destroyed) return;
|
|
102
112
|
switch (evt.key) {
|
|
103
113
|
case "l":
|
|
104
114
|
this.enabled = !this.enabled;
|
|
@@ -108,17 +118,17 @@ export class SceneLightSettings extends Behaviour {
|
|
|
108
118
|
}
|
|
109
119
|
}
|
|
110
120
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
121
|
+
onDestroy(): void {
|
|
122
|
+
this.context.sceneLighting.internalUnregisterSceneLightSettings(this);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
onEnable(): void {
|
|
126
|
+
if (debug) console.warn("💡🟡 >>> Enable lighting", this.sourceId, this);
|
|
127
|
+
|
|
119
128
|
if (this.ambientMode == AmbientMode.Flat) {
|
|
120
129
|
if (this.ambientLight && !this._ambientLightObj) {
|
|
121
130
|
this._ambientLightObj = new AmbientLight(this.ambientLight, this.ambientIntensity);
|
|
131
|
+
if (debug) console.log("Created ambient light", this.sourceId, this._ambientLightObj)
|
|
122
132
|
}
|
|
123
133
|
if (this._ambientLightObj) {
|
|
124
134
|
this.gameObject.add(this._ambientLightObj)
|
|
@@ -129,23 +139,24 @@ export class SceneLightSettings extends Behaviour {
|
|
|
129
139
|
if (this.ambientTrilight) {
|
|
130
140
|
const ground = this.ambientTrilight[0];
|
|
131
141
|
const sky = this.ambientTrilight[this.ambientTrilight.length - 1];
|
|
132
|
-
|
|
133
|
-
this.gameObject.add(
|
|
142
|
+
this._hemisphereLightObj = new HemisphereLight(sky, ground, this.ambientIntensity);
|
|
143
|
+
this.gameObject.add(this._hemisphereLightObj)
|
|
134
144
|
}
|
|
135
145
|
}
|
|
136
146
|
else {
|
|
137
147
|
if (this._ambientLightObj)
|
|
138
148
|
this._ambientLightObj.removeFromParent();
|
|
149
|
+
if (this._hemisphereLightObj)
|
|
150
|
+
this._hemisphereLightObj.removeFromParent();
|
|
139
151
|
|
|
140
152
|
// create light probe object
|
|
141
153
|
if (!this._lightProbeObj) {
|
|
142
154
|
if (this.sourceId) {
|
|
143
|
-
this.context.
|
|
155
|
+
this.context.sceneLighting.internalGetSceneLightingData(this.sourceId).then(data => {
|
|
144
156
|
if (!data) return;
|
|
145
157
|
this._lightProbeObj = data.lightProbe;
|
|
146
158
|
if (this.enabled && !this.destroyed && this._lightProbeObj) {
|
|
147
|
-
if (debug)
|
|
148
|
-
console.log("Add", this.sourceId, data);
|
|
159
|
+
if (debug) console.log("Add", this.sourceId, data);
|
|
149
160
|
this.gameObject.add(this._lightProbeObj);
|
|
150
161
|
}
|
|
151
162
|
});
|
|
@@ -159,16 +170,20 @@ export class SceneLightSettings extends Behaviour {
|
|
|
159
170
|
}
|
|
160
171
|
|
|
161
172
|
if (this.sourceId)
|
|
162
|
-
this.context.
|
|
173
|
+
this.context.sceneLighting.internalEnableReflection(this.sourceId);
|
|
163
174
|
|
|
164
175
|
}
|
|
165
176
|
|
|
166
177
|
onDisable() {
|
|
167
178
|
if (debug)
|
|
168
|
-
console.
|
|
169
|
-
if (this._lightProbeObj)
|
|
170
|
-
|
|
179
|
+
console.warn("💡⚫ <<< Disable lighting:", this.sourceId, this);
|
|
180
|
+
if (this._lightProbeObj)
|
|
181
|
+
this._lightProbeObj.removeFromParent();
|
|
182
|
+
if (this._ambientLightObj)
|
|
183
|
+
this._ambientLightObj.removeFromParent();
|
|
184
|
+
if (this._hemisphereLightObj)
|
|
185
|
+
this._hemisphereLightObj.removeFromParent();
|
|
171
186
|
if (this.sourceId)
|
|
172
|
-
this.context.
|
|
187
|
+
this.context.sceneLighting.internalDisableReflection(this.sourceId);
|
|
173
188
|
}
|
|
174
189
|
}
|
|
@@ -118,7 +118,7 @@ export class CustomShader extends RawShaderMaterial {
|
|
|
118
118
|
console.error("Missing context");
|
|
119
119
|
return;
|
|
120
120
|
}
|
|
121
|
-
const data = await context.
|
|
121
|
+
const data = await context.sceneLighting.internalGetSceneLightingData(this.identifier);
|
|
122
122
|
if (!data || !data.array) {
|
|
123
123
|
console.warn("Missing lighting data for custom shader, getSceneLightingData did not return anything");
|
|
124
124
|
return;
|
|
@@ -210,10 +210,10 @@ export class CustomShader extends RawShaderMaterial {
|
|
|
210
210
|
// this._lastFrame = context.time.frame;
|
|
211
211
|
|
|
212
212
|
if (this.uniforms["_TimeParameters"]) {
|
|
213
|
-
this.uniforms["_TimeParameters"].value = context.
|
|
213
|
+
this.uniforms["_TimeParameters"].value = context.sceneLighting.timeVec4;
|
|
214
214
|
}
|
|
215
215
|
else if (this.uniforms["_Time"]) {
|
|
216
|
-
this.uniforms["_Time"].value = context.
|
|
216
|
+
this.uniforms["_Time"].value = context.sceneLighting.timeVec4;
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
const mainLight: ILight | null = context.mainLight;
|
|
@@ -470,7 +470,13 @@ export class Component implements IComponent, EventTarget {
|
|
|
470
470
|
|
|
471
471
|
/** @internal */
|
|
472
472
|
__internalEnable(): boolean {
|
|
473
|
-
|
|
473
|
+
// Don't change enable before awake
|
|
474
|
+
// But a user can change enable during awake
|
|
475
|
+
if (!this.__didAwake) return false;
|
|
476
|
+
if (this.__didEnable) {
|
|
477
|
+
this.__isEnabled = true;
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
474
480
|
// console.trace("INTERNAL ENABLE");
|
|
475
481
|
this.__didEnable = true;
|
|
476
482
|
this.onEnable();
|
|
@@ -480,7 +486,13 @@ export class Component implements IComponent, EventTarget {
|
|
|
480
486
|
|
|
481
487
|
/** @internal */
|
|
482
488
|
__internalDisable() {
|
|
483
|
-
|
|
489
|
+
// Don't change enable before awake
|
|
490
|
+
// But a user can change enable during awake
|
|
491
|
+
if (!this.__didAwake) return;
|
|
492
|
+
if (!this.__didEnable) {
|
|
493
|
+
this.__isEnabled = false;
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
484
496
|
this.__didEnable = false;
|
|
485
497
|
this.onDisable();
|
|
486
498
|
this.__isEnabled = false;
|
|
@@ -496,7 +508,7 @@ export class Component implements IComponent, EventTarget {
|
|
|
496
508
|
|
|
497
509
|
|
|
498
510
|
get enabled(): boolean {
|
|
499
|
-
return this.__isEnabled
|
|
511
|
+
return typeof this.__isEnabled === "boolean" ? this.__isEnabled : true; // if it has no enabled field it is always enabled
|
|
500
512
|
}
|
|
501
513
|
set enabled(val: boolean) {
|
|
502
514
|
// when called from animationclip we receive numbers
|
|
@@ -617,7 +617,7 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
617
617
|
|
|
618
618
|
if (material.envMapIntensity !== undefined) {
|
|
619
619
|
const factor = this.hasLightmap ? Math.PI : 1;
|
|
620
|
-
material.envMapIntensity = Math.max(0, this.context.
|
|
620
|
+
material.envMapIntensity = Math.max(0, this.context.sceneLighting.environmentIntensity / factor);
|
|
621
621
|
}
|
|
622
622
|
// if (this._reflectionProbe?.texture) {
|
|
623
623
|
// material.envMap = this._reflectionProbe.texture;
|