@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.
Files changed (64) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/needle-engine.js +7125 -6981
  3. package/dist/needle-engine.min.js +277 -277
  4. package/dist/needle-engine.umd.cjs +275 -275
  5. package/lib/engine/api.d.ts +4 -1
  6. package/lib/engine/api.js +3 -1
  7. package/lib/engine/api.js.map +1 -1
  8. package/lib/engine/engine_context.d.ts +4 -2
  9. package/lib/engine/engine_context.js +5 -3
  10. package/lib/engine/engine_context.js.map +1 -1
  11. package/lib/engine/engine_element_loading.js +0 -1
  12. package/lib/engine/engine_element_loading.js.map +1 -1
  13. package/lib/engine/engine_mainloop_utils.js +4 -2
  14. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  15. package/lib/engine/engine_scenelighting.d.ts +68 -0
  16. package/lib/engine/{engine_rendererdata.js → engine_scenelighting.js} +102 -30
  17. package/lib/engine/engine_scenelighting.js.map +1 -0
  18. package/lib/engine/engine_serialization_core.d.ts +5 -8
  19. package/lib/engine/engine_serialization_core.js.map +1 -1
  20. package/lib/engine/extensions/NEEDLE_lighting_settings.d.ts +3 -1
  21. package/lib/engine/extensions/NEEDLE_lighting_settings.js +32 -20
  22. package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
  23. package/lib/engine/extensions/NEEDLE_techniques_webgl.js +3 -3
  24. package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
  25. package/lib/engine/extensions/index.d.ts +5 -0
  26. package/lib/engine/extensions/index.js +6 -0
  27. package/lib/engine/extensions/index.js.map +1 -0
  28. package/lib/engine-components/Component.js +15 -3
  29. package/lib/engine-components/Component.js.map +1 -1
  30. package/lib/engine-components/Renderer.js +1 -1
  31. package/lib/engine-components/Renderer.js.map +1 -1
  32. package/lib/engine-components/SceneSwitcher.d.ts +2 -0
  33. package/lib/engine-components/SceneSwitcher.js +16 -4
  34. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  35. package/lib/engine-components/api.d.ts +1 -0
  36. package/lib/engine-components/api.js +1 -0
  37. package/lib/engine-components/api.js.map +1 -1
  38. package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +1 -1
  39. package/lib/engine-components/postprocessing/VolumeParameter.d.ts +1 -1
  40. package/lib/engine-components/postprocessing/VolumeParameter.js +7 -6
  41. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  42. package/lib/engine-components/webxr/index.d.ts +2 -0
  43. package/lib/engine-components/webxr/index.js +2 -0
  44. package/lib/engine-components/webxr/index.js.map +1 -1
  45. package/lib/tsconfig.tsbuildinfo +1 -1
  46. package/package.json +1 -1
  47. package/src/engine/api.ts +4 -1
  48. package/src/engine/engine_context.ts +5 -3
  49. package/src/engine/engine_element_loading.ts +0 -1
  50. package/src/engine/engine_mainloop_utils.ts +4 -2
  51. package/src/engine/{engine_rendererdata.ts → engine_scenelighting.ts} +109 -36
  52. package/src/engine/engine_serialization_core.ts +7 -8
  53. package/src/engine/extensions/NEEDLE_lighting_settings.ts +40 -25
  54. package/src/engine/extensions/NEEDLE_techniques_webgl.ts +3 -3
  55. package/src/engine/extensions/index.ts +5 -0
  56. package/src/engine-components/Component.ts +15 -3
  57. package/src/engine-components/Renderer.ts +1 -1
  58. package/src/engine-components/SceneSwitcher.ts +14 -4
  59. package/src/engine-components/api.ts +1 -0
  60. package/src/engine-components/postprocessing/PostProcessingHandler.ts +1 -1
  61. package/src/engine-components/postprocessing/VolumeParameter.ts +7 -6
  62. package/src/engine-components/webxr/index.ts +3 -1
  63. package/lib/engine/engine_rendererdata.d.ts +0 -49
  64. 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.5-alpha",
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/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 './engine_rendererdata';
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
- rendererData: RendererData;
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.rendererData = new RendererData(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["__didEnable"] = true;
271
- comp.onEnable();
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: THREE.WebGLCubeRenderTarget | THREE.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 _currentReflectionId?: SourceIdentifier;
40
- private sceneLightSettings?: Map<SourceIdentifier, SceneLightSettings>;
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.sceneLightSettings) return 1;
57
- if (!this._currentReflectionId) return 1;
58
- const settings = this.sceneLightSettings.get(this._currentReflectionId);
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
- registerSceneLightSettings(sceneLightSettings: SceneLightSettings) {
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 lighting settings", sceneLightSettings?.sourceId, sceneLightSettings);
71
- if (!this.sceneLightSettings) this.sceneLightSettings = new Map();
72
- this.sceneLightSettings.set(sourceId, sceneLightSettings);
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
- registerReflection(sourceId: SourceIdentifier, reflectionTexture: Texture) {
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
- getReflection(sourceId: SourceIdentifier): LightData | null | undefined {
142
+ /** @internal */
143
+ internalGetReflection(sourceId: SourceIdentifier): LightData | null | undefined {
82
144
  return this._lighting[sourceId];
83
145
  }
84
146
 
85
- enableReflection(sourceId: SourceIdentifier) {
86
- const previousId = this._currentReflectionId;
87
- this._currentReflectionId = sourceId;
88
- const settings = this.sceneLightSettings?.get(sourceId);
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.getReflection(sourceId);
162
+ const existing = this.internalGetReflection(sourceId);
99
163
  if (existing && existing.Source) {
100
- if (debug) console.log("Setting environment reflection", existing.Source);
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
- disableReflection(sourceId? : SourceIdentifier) {
140
- if(sourceId && sourceId !== this._currentReflectionId) return;
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
- async getSceneLightingData(sourceId: SourceIdentifier): Promise<SphericalHarmonicsData> {
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.getReflection(sourceId);
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: THREE.Texture;
182
- private _sphericalHarmonics: THREE.SphericalHarmonics3 | null = null;
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: THREE.Texture, ambientScale: number = 1) {
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: THREE.WebGLCubeRenderTarget | null = null;
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._source = rt.texture;
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
- const factor = ((intensityFactor) / (Math.PI * .5));
220
- for (let i = 0; i < this._sphericalHarmonicsArray.length; i++) {
221
- this._sphericalHarmonicsArray[i] *= factor;
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: Constructor<any> | Constructor<any>[]) {
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?: Constructor<any>;
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?: Constructor<any>;
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]: Constructor<any> | ITypeInformation | null };
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 Constructor<any>;
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: Constructor<any>, context: SerializationContext, typeContext?: TypeDeserializeReference, currentValue?: any): any {
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 "../engine_rendererdata";
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("Apply \"" + this.name + "\", src: \"" + this.sourceId + "\"", ext);
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 = "Needle LightSettings";
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.rendererData.registerReflection(this.sourceId, tex);
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
- onEnable() {
112
- const isActive = this.context.mainCameraComponent?.sourceId === this.sourceId;
113
- if (debug) console.log("Enable scene lighting", this.sourceId, isActive, this, this.context.mainCameraComponent?.sourceId);
114
- if (!isActive) {
115
- if(debug) console.warn("This environment light is not active??!", this.context.mainCameraComponent?.sourceId)
116
- this.enabled = false;
117
- return;
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
- const hemisphere = new HemisphereLight(sky, ground, this.ambientIntensity);
133
- this.gameObject.add(hemisphere)
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.rendererData.getSceneLightingData(this.sourceId).then(data => {
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.rendererData.enableReflection(this.sourceId);
173
+ this.context.sceneLighting.internalEnableReflection(this.sourceId);
163
174
 
164
175
  }
165
176
 
166
177
  onDisable() {
167
178
  if (debug)
168
- console.log("Disable envlight:", this.sourceId, this);
169
- if (this._lightProbeObj) this._lightProbeObj.removeFromParent();
170
- if(this._ambientLightObj) this._ambientLightObj.removeFromParent();
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.rendererData.disableReflection(this.sourceId);
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.rendererData.getSceneLightingData(this.identifier);
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.rendererData.timeVec4;
213
+ this.uniforms["_TimeParameters"].value = context.sceneLighting.timeVec4;
214
214
  }
215
215
  else if (this.uniforms["_Time"]) {
216
- this.uniforms["_Time"].value = context.rendererData.timeVec4;
216
+ this.uniforms["_Time"].value = context.sceneLighting.timeVec4;
217
217
  }
218
218
 
219
219
  const mainLight: ILight | null = context.mainLight;
@@ -0,0 +1,5 @@
1
+ export * from "./extensions"
2
+ export * from "./NEEDLE_animator_controller_model"
3
+ export * from "./NEEDLE_progressive"
4
+ export { CustomShader } from "./NEEDLE_techniques_webgl"
5
+ export { SceneLightSettings } from "./NEEDLE_lighting_settings"
@@ -470,7 +470,13 @@ export class Component implements IComponent, EventTarget {
470
470
 
471
471
  /** @internal */
472
472
  __internalEnable(): boolean {
473
- if (this.__didEnable) return false;
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
- if (!this.__didEnable) return;
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 ?? true; // if it has no enabled field it is always enabled
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.rendererData.environmentIntensity / factor);
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;