@needle-tools/engine 3.2.5-alpha.1 → 3.2.7-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 (68) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/needle-engine.js +6145 -6019
  3. package/dist/needle-engine.min.js +275 -275
  4. package/dist/needle-engine.umd.cjs +273 -273
  5. package/lib/engine/api.d.ts +3 -1
  6. package/lib/engine/api.js +2 -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_physics.js +24 -1
  16. package/lib/engine/engine_physics.js.map +1 -1
  17. package/lib/engine/engine_scenelighting.d.ts +68 -0
  18. package/lib/engine/{engine_rendererdata.js → engine_scenelighting.js} +94 -24
  19. package/lib/engine/engine_scenelighting.js.map +1 -0
  20. package/lib/engine/engine_serialization_core.d.ts +5 -8
  21. package/lib/engine/engine_serialization_core.js.map +1 -1
  22. package/lib/engine/extensions/NEEDLE_lighting_settings.d.ts +4 -1
  23. package/lib/engine/extensions/NEEDLE_lighting_settings.js +45 -21
  24. package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
  25. package/lib/engine/extensions/NEEDLE_techniques_webgl.js +3 -3
  26. package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
  27. package/lib/engine/extensions/index.d.ts +5 -0
  28. package/lib/engine/extensions/index.js +6 -0
  29. package/lib/engine/extensions/index.js.map +1 -0
  30. package/lib/engine-components/Component.js +28 -3
  31. package/lib/engine-components/Component.js.map +1 -1
  32. package/lib/engine-components/Renderer.js +1 -1
  33. package/lib/engine-components/Renderer.js.map +1 -1
  34. package/lib/engine-components/SceneSwitcher.d.ts +2 -0
  35. package/lib/engine-components/SceneSwitcher.js +16 -4
  36. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  37. package/lib/engine-components/api.d.ts +1 -0
  38. package/lib/engine-components/api.js +1 -0
  39. package/lib/engine-components/api.js.map +1 -1
  40. package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +1 -1
  41. package/lib/engine-components/postprocessing/VolumeParameter.d.ts +1 -1
  42. package/lib/engine-components/postprocessing/VolumeParameter.js +7 -6
  43. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  44. package/lib/engine-components/webxr/index.d.ts +1 -0
  45. package/lib/engine-components/webxr/index.js +1 -0
  46. package/lib/engine-components/webxr/index.js.map +1 -1
  47. package/lib/tsconfig.tsbuildinfo +1 -1
  48. package/package.json +1 -1
  49. package/src/engine/api.ts +3 -1
  50. package/src/engine/codegen/register_types.js +2 -2
  51. package/src/engine/engine_context.ts +5 -3
  52. package/src/engine/engine_element_loading.ts +0 -1
  53. package/src/engine/engine_mainloop_utils.ts +4 -2
  54. package/src/engine/engine_physics.ts +20 -1
  55. package/src/engine/{engine_rendererdata.ts → engine_scenelighting.ts} +95 -24
  56. package/src/engine/engine_serialization_core.ts +7 -8
  57. package/src/engine/extensions/NEEDLE_lighting_settings.ts +53 -26
  58. package/src/engine/extensions/NEEDLE_techniques_webgl.ts +3 -3
  59. package/src/engine/extensions/index.ts +5 -0
  60. package/src/engine-components/Component.ts +28 -3
  61. package/src/engine-components/Renderer.ts +1 -1
  62. package/src/engine-components/SceneSwitcher.ts +14 -4
  63. package/src/engine-components/api.ts +1 -0
  64. package/src/engine-components/postprocessing/PostProcessingHandler.ts +1 -1
  65. package/src/engine-components/postprocessing/VolumeParameter.ts +7 -6
  66. package/src/engine-components/webxr/index.ts +1 -0
  67. package/lib/engine/engine_rendererdata.d.ts +0 -49
  68. 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.1",
3
+ "version": "3.2.7-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,11 +27,13 @@ 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";
36
38
  export * from "./engine_three_utils";
37
39
  export * from "./engine_time";
@@ -1,5 +1,5 @@
1
1
  import { TypeStore } from "./../engine_typestore"
2
-
2
+
3
3
  // Import types
4
4
  import { __Ignore } from "../../engine-components/codegen/components";
5
5
  import { AlignmentConstraint } from "../../engine-components/AlignmentConstraint";
@@ -187,7 +187,7 @@ import { XRGrabModel } from "../../engine-components/webxr/WebXRGrabRendering";
187
187
  import { XRGrabRendering } from "../../engine-components/webxr/WebXRGrabRendering";
188
188
  import { XRRig } from "../../engine-components/webxr/WebXRRig";
189
189
  import { XRState } from "../../engine-components/XRFlag";
190
-
190
+
191
191
  // Register types
192
192
  TypeStore.add("__Ignore", __Ignore);
193
193
  TypeStore.add("AlignmentConstraint", AlignmentConstraint);
@@ -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 {
@@ -1082,7 +1082,7 @@ class PhysicsCollisionHandler {
1082
1082
  // if one is a trigger we dont get collisions but want to raise the trigger events
1083
1083
  if (self.isTrigger || other.isTrigger) {
1084
1084
  foreachComponent(self.gameObject, (c: IComponent) => {
1085
- if (c.onTriggerEnter) {
1085
+ if (c.onTriggerEnter && !c.destroyed) {
1086
1086
  c.onTriggerEnter(other);
1087
1087
  }
1088
1088
  this.activeTriggers.push({ collider: self, component: c, otherCollider: other });
@@ -1093,6 +1093,7 @@ class PhysicsCollisionHandler {
1093
1093
  // TODO: we dont respect the flip value here!
1094
1094
  this.world.contactPair(selfBody, otherBody, (manifold, _flipped) => {
1095
1095
  foreachComponent(object, (c: IComponent) => {
1096
+ if(c.destroyed) return;
1096
1097
  const hasDeclaredEventMethod = c.onCollisionEnter || c.onCollisionStay || c.onCollisionExit;
1097
1098
  if (hasDeclaredEventMethod || debugCollisions) {
1098
1099
  if (!collision) {
@@ -1137,6 +1138,7 @@ class PhysicsCollisionHandler {
1137
1138
  private onHandleCollisionStay() {
1138
1139
  for (const active of this.activeCollisionsStay) {
1139
1140
  const c = active.component;
1141
+ if(c.destroyed) continue;
1140
1142
  if (c.activeAndEnabled && c.onCollisionStay) {
1141
1143
  const arg = active.collision;
1142
1144
  c.onCollisionStay(arg);
@@ -1144,6 +1146,7 @@ class PhysicsCollisionHandler {
1144
1146
  }
1145
1147
  for (const active of this.activeTriggers) {
1146
1148
  const c = active.component;
1149
+ if(c.destroyed) continue;
1147
1150
  if (c.activeAndEnabled && c.onTriggerStay) {
1148
1151
  const arg = active.otherCollider;
1149
1152
  c.onTriggerStay(arg);
@@ -1152,9 +1155,15 @@ class PhysicsCollisionHandler {
1152
1155
  }
1153
1156
 
1154
1157
  private onCollisionEnded(self: ICollider, other: ICollider) {
1158
+ if(self.destroyed || other.destroyed) return;
1155
1159
  for (let i = 0; i < this.activeCollisions.length; i++) {
1156
1160
  const active = this.activeCollisions[i];
1157
1161
  const collider = active.collider;
1162
+ if(collider.destroyed) {
1163
+ this.activeCollisions.splice(i, 1);
1164
+ i--;
1165
+ continue;
1166
+ }
1158
1167
  if (collider === self && active.collision.collider === other) {
1159
1168
  const c = active.component;
1160
1169
  this.activeCollisions.splice(i, 1);
@@ -1168,6 +1177,11 @@ class PhysicsCollisionHandler {
1168
1177
  for (let i = 0; i < this.activeCollisionsStay.length; i++) {
1169
1178
  const active = this.activeCollisionsStay[i];
1170
1179
  const collider = active.collider;
1180
+ if(collider.destroyed) {
1181
+ this.activeCollisionsStay.splice(i, 1);
1182
+ i--;
1183
+ continue;
1184
+ }
1171
1185
  if (collider === self && active.collision.collider === other) {
1172
1186
  const c = active.component;
1173
1187
  this.activeCollisionsStay.splice(i, 1);
@@ -1181,6 +1195,11 @@ class PhysicsCollisionHandler {
1181
1195
  for (let i = 0; i < this.activeTriggers.length; i++) {
1182
1196
  const active = this.activeTriggers[i];
1183
1197
  const collider = active.collider;
1198
+ if(collider.destroyed) {
1199
+ this.activeTriggers.splice(i, 1);
1200
+ i--;
1201
+ continue;
1202
+ }
1184
1203
  if (collider === self && active.otherCollider === other) {
1185
1204
  const c = active.component;
1186
1205
  this.activeTriggers.splice(i, 1);
@@ -5,6 +5,7 @@ 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
 
@@ -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);
121
+ }
122
+
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);
73
133
  }
74
134
 
75
- registerReflection(sourceId: SourceIdentifier, reflectionTexture: Texture) {
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)!);
@@ -205,7 +275,8 @@ export class LightData {
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 = [];
@@ -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,13 @@ 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";
11
+ import { Mathf } from "../engine_math";
10
12
 
11
13
  export const EXTENSION_NAME = "NEEDLE_lighting_settings";
12
14
  const debug = getParam("debugenvlight");
@@ -42,7 +44,7 @@ export class NEEDLE_lighting_settings implements GLTFLoaderPlugin {
42
44
  const ext: LightingSettings = extensions[EXTENSION_NAME];
43
45
  if (ext) {
44
46
  if (debug)
45
- console.log("Apply \"" + this.name + "\", src: \"" + this.sourceId + "\"", ext);
47
+ console.log("Loaded \"" + this.name + "\", src: \"" + this.sourceId + "\"", ext);
46
48
  let settings: SceneLightSettings | undefined = undefined;
47
49
  // If the result scene has only one child we add the LightingSettingsComponent to that child
48
50
  if (_result.scene.children.length === 1) {
@@ -50,10 +52,9 @@ export class NEEDLE_lighting_settings implements GLTFLoaderPlugin {
50
52
  settings = GameObject.addNewComponent(_result.scene.children[0], SceneLightSettings, false);
51
53
  }
52
54
  // if the scene already has multiple children we add it as a new object
53
- else
54
- {
55
+ else {
55
56
  const lightSettings = new Object3D();
56
- lightSettings.name = "Needle LightSettings";
57
+ lightSettings.name = "LightSettings " + this.sourceId;
57
58
  _result.scene.add(lightSettings);
58
59
  settings = GameObject.addNewComponent(lightSettings, SceneLightSettings, false);
59
60
  }
@@ -64,7 +65,6 @@ export class NEEDLE_lighting_settings implements GLTFLoaderPlugin {
64
65
  settings.ambientTrilight = ext.ambientTrilight.map(c => new Color().fromArray(c));
65
66
  settings.ambientMode = ext.ambientMode;
66
67
  settings.environmentReflectionSource = ext.environmentReflectionSource;
67
- if (this.context) this.context.rendererData.registerSceneLightSettings(settings);
68
68
  }
69
69
  }
70
70
  return null;
@@ -72,6 +72,12 @@ export class NEEDLE_lighting_settings implements GLTFLoaderPlugin {
72
72
 
73
73
  }
74
74
 
75
+ ContextRegistry.registerCallback(ContextEvent.ContextCreated, e => {
76
+ const ctx = e.context as Context;
77
+ const lightingSettings = GameObject.findObjectOfType(SceneLightSettings, ctx as Context);
78
+ if (lightingSettings?.sourceId) ctx.sceneLighting.enable(lightingSettings.sourceId);
79
+ })
80
+
75
81
  // exists once per gltf scene root (if it contains reflection)
76
82
  // when enabled it does currently automatically set the reflection
77
83
  // this might not be desireable
@@ -85,6 +91,7 @@ export class SceneLightSettings extends Behaviour {
85
91
 
86
92
  private _hasReflection: boolean = false;
87
93
  private _ambientLightObj?: AmbientLight;
94
+ private _hemisphereLightObj?: HemisphereLight;
88
95
  // used when skybox is used to support ambient intensity for "non custom shaders"
89
96
  private _lightProbeObj?: LightProbe;
90
97
 
@@ -94,11 +101,15 @@ export class SceneLightSettings extends Behaviour {
94
101
  const tex = this.context.lightmaps.tryGet(this.sourceId, type, 0);
95
102
  this._hasReflection = tex !== null && tex !== undefined;
96
103
  if (tex)
97
- this.context.rendererData.registerReflection(this.sourceId, tex);
104
+ this.context.sceneLighting.internalRegisterReflection(this.sourceId, tex);
98
105
  }
99
106
 
107
+ this.enabled = false;
108
+ this.context.sceneLighting.internalRegisterSceneLightSettings(this);
109
+
100
110
  if (debug) {
101
111
  window.addEventListener("keydown", evt => {
112
+ if(this.destroyed) return;
102
113
  switch (evt.key) {
103
114
  case "l":
104
115
  this.enabled = !this.enabled;
@@ -108,17 +119,26 @@ export class SceneLightSettings extends Behaviour {
108
119
  }
109
120
  }
110
121
 
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
- }
122
+ onDestroy(): void {
123
+ this.context.sceneLighting.internalUnregisterSceneLightSettings(this);
124
+ }
125
+
126
+ private calculateIntensityFactor(col:Color){
127
+ const intensity = Math.max(col.r, col.g, col.b);// * 0.2126 + col.g * 0.7152 + col.b * 0.0722;
128
+ const factor = 2.2 * Mathf.lerp(0, 1.33, intensity); // scale based on intensity
129
+ return factor;
130
+ }
131
+
132
+ onEnable(): void {
133
+ if (debug) console.warn("💡🟡 >>> Enable lighting", this.sourceId, this);
134
+
119
135
  if (this.ambientMode == AmbientMode.Flat) {
120
136
  if (this.ambientLight && !this._ambientLightObj) {
121
- this._ambientLightObj = new AmbientLight(this.ambientLight, this.ambientIntensity);
137
+ // TODO: currently ambient intensity is always exported as 1? The exported values are not correct in threejs
138
+ // the following calculation is a workaround to get the correct intensity
139
+ const factor = this.calculateIntensityFactor(this.ambientLight);
140
+ this._ambientLightObj = new AmbientLight(this.ambientLight, this.ambientIntensity * factor);
141
+ if (debug) console.log("Created ambient light", this.sourceId, this._ambientLightObj, this.ambientIntensity, factor)
122
142
  }
123
143
  if (this._ambientLightObj) {
124
144
  this.gameObject.add(this._ambientLightObj)
@@ -129,23 +149,26 @@ export class SceneLightSettings extends Behaviour {
129
149
  if (this.ambientTrilight) {
130
150
  const ground = this.ambientTrilight[0];
131
151
  const sky = this.ambientTrilight[this.ambientTrilight.length - 1];
132
- const hemisphere = new HemisphereLight(sky, ground, this.ambientIntensity);
133
- this.gameObject.add(hemisphere)
152
+ const factor = this.calculateIntensityFactor(sky);
153
+ this._hemisphereLightObj = new HemisphereLight(sky, ground, this.ambientIntensity * factor);
154
+ this.gameObject.add(this._hemisphereLightObj)
155
+ if (debug) console.log("Created hemisphere ambient light", this.sourceId, this._hemisphereLightObj, this.ambientIntensity, factor)
134
156
  }
135
157
  }
136
158
  else {
137
159
  if (this._ambientLightObj)
138
160
  this._ambientLightObj.removeFromParent();
161
+ if (this._hemisphereLightObj)
162
+ this._hemisphereLightObj.removeFromParent();
139
163
 
140
164
  // create light probe object
141
165
  if (!this._lightProbeObj) {
142
166
  if (this.sourceId) {
143
- this.context.rendererData.getSceneLightingData(this.sourceId).then(data => {
167
+ this.context.sceneLighting.internalGetSceneLightingData(this.sourceId).then(data => {
144
168
  if (!data) return;
145
169
  this._lightProbeObj = data.lightProbe;
146
170
  if (this.enabled && !this.destroyed && this._lightProbeObj) {
147
- if (debug)
148
- console.log("Add", this.sourceId, data);
171
+ if (debug) console.log("Add", this.sourceId, data);
149
172
  this.gameObject.add(this._lightProbeObj);
150
173
  }
151
174
  });
@@ -159,16 +182,20 @@ export class SceneLightSettings extends Behaviour {
159
182
  }
160
183
 
161
184
  if (this.sourceId)
162
- this.context.rendererData.enableReflection(this.sourceId);
185
+ this.context.sceneLighting.internalEnableReflection(this.sourceId);
163
186
 
164
187
  }
165
188
 
166
189
  onDisable() {
167
190
  if (debug)
168
- console.log("Disable envlight:", this.sourceId, this);
169
- if (this._lightProbeObj) this._lightProbeObj.removeFromParent();
170
- if(this._ambientLightObj) this._ambientLightObj.removeFromParent();
191
+ console.warn("💡⚫ <<< Disable lighting:", this.sourceId, this);
192
+ if (this._lightProbeObj)
193
+ this._lightProbeObj.removeFromParent();
194
+ if (this._ambientLightObj)
195
+ this._ambientLightObj.removeFromParent();
196
+ if (this._hemisphereLightObj)
197
+ this._hemisphereLightObj.removeFromParent();
171
198
  if (this.sourceId)
172
- this.context.rendererData.disableReflection(this.sourceId);
199
+ this.context.sceneLighting.internalDisableReflection(this.sourceId);
173
200
  }
174
201
  }
@@ -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"