@needle-tools/engine 4.11.4 → 4.11.5-next.53316bf

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 (164) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/components.needle.json +1 -1
  3. package/dist/generateMeshBVH.worker-mO20N_b8.js +21 -0
  4. package/dist/{gltf-progressive-GwdQV1Qx.umd.cjs → gltf-progressive-DWcmTMCh.umd.cjs} +1 -1
  5. package/dist/{gltf-progressive-CftVUJy3.min.js → gltf-progressive-DZrY8VT6.min.js} +2 -2
  6. package/dist/{gltf-progressive-BvlZQAkt.js → gltf-progressive-DgYz5BYa.js} +19 -19
  7. package/dist/loader.worker-Dip-PthR.js +23 -0
  8. package/dist/{needle-engine.bundle-CQdk7IvU.min.js → needle-engine.bundle-BR5nmLCs.min.js} +155 -160
  9. package/dist/{needle-engine.bundle-BxK1-fWD.umd.cjs → needle-engine.bundle-Cb9jKt1y.umd.cjs} +154 -159
  10. package/dist/{needle-engine.bundle-DmMrUPFQ.js → needle-engine.bundle-D6G3NMe4.js} +5964 -5815
  11. package/dist/needle-engine.d.ts +17848 -1
  12. package/dist/needle-engine.js +336 -335
  13. package/dist/needle-engine.min.js +1 -1
  14. package/dist/needle-engine.umd.cjs +1 -1
  15. package/dist/{postprocessing-CJC0Npcd.js → postprocessing-BTW9pD_s.js} +1822 -1723
  16. package/dist/{postprocessing-DrM4PWU3.umd.cjs → postprocessing-CMgoN5t5.umd.cjs} +229 -158
  17. package/dist/{postprocessing-l7zsdO_Q.min.js → postprocessing-DYDtB188.min.js} +227 -156
  18. package/dist/rapier-B3oL1ap-.js +5217 -0
  19. package/dist/rapier-DJ-luMxr.min.js +1 -0
  20. package/dist/rapier-DQltNJbN.umd.cjs +1 -0
  21. package/dist/{three-BDW9I486.min.js → three-B7CT31Bt.min.js} +1 -5
  22. package/dist/{three-MHVqtJYj.js → three-DfMvBzXi.js} +0 -5
  23. package/dist/{three-examples-CgwGHSgz.umd.cjs → three-examples-CsW4_6LI.umd.cjs} +2 -7
  24. package/dist/{three-examples-fvEPSC8L.min.js → three-examples-D1P7eEhn.min.js} +2 -7
  25. package/dist/{three-examples-C5Ht-QFN.js → three-examples-D1SK93ek.js} +1 -7
  26. package/dist/{three-mesh-ui-BjWTTk1R.js → three-mesh-ui-C_uSB5dD.js} +1 -1
  27. package/dist/{three-mesh-ui-Bm32sS2a.umd.cjs → three-mesh-ui-DpATDXwU.umd.cjs} +1 -1
  28. package/dist/{three-mesh-ui-CLdkp21K.min.js → three-mesh-ui-LQ44s0AL.min.js} +1 -1
  29. package/dist/{three-iFaDq9U3.umd.cjs → three-qj71I7J3.umd.cjs} +2 -6
  30. package/dist/{vendor-CsyK1CFs.min.js → vendor-BKGa4GE0.min.js} +34 -39
  31. package/dist/{vendor-petGQl0N.js → vendor-D0zoswDa.js} +1626 -1605
  32. package/dist/{vendor-6kAXU6fm.umd.cjs → vendor-UCpFAwt1.umd.cjs} +30 -35
  33. package/lib/engine/api.d.ts +1 -1
  34. package/lib/engine/api.js +1 -1
  35. package/lib/engine/api.js.map +1 -1
  36. package/lib/engine/debug/debug_spector.d.ts +16 -0
  37. package/lib/engine/debug/debug_spector.js +28 -0
  38. package/lib/engine/debug/debug_spector.js.map +1 -0
  39. package/lib/engine/engine_addressables.d.ts +74 -11
  40. package/lib/engine/engine_addressables.js +74 -11
  41. package/lib/engine/engine_addressables.js.map +1 -1
  42. package/lib/engine/engine_application.d.ts +7 -0
  43. package/lib/engine/engine_application.js +8 -1
  44. package/lib/engine/engine_application.js.map +1 -1
  45. package/lib/engine/engine_camera.fit.d.ts +48 -3
  46. package/lib/engine/engine_camera.fit.js +29 -0
  47. package/lib/engine/engine_camera.fit.js.map +1 -1
  48. package/lib/engine/engine_context.d.ts +33 -8
  49. package/lib/engine/engine_context.js +47 -8
  50. package/lib/engine/engine_context.js.map +1 -1
  51. package/lib/engine/engine_loaders.d.ts +0 -6
  52. package/lib/engine/engine_loaders.js +5 -5
  53. package/lib/engine/engine_loaders.js.map +1 -1
  54. package/lib/engine/engine_physics.js +6 -2
  55. package/lib/engine/engine_physics.js.map +1 -1
  56. package/lib/engine/engine_physics_rapier.d.ts +11 -2
  57. package/lib/engine/engine_physics_rapier.js +9 -0
  58. package/lib/engine/engine_physics_rapier.js.map +1 -1
  59. package/lib/engine/engine_scenelighting.d.ts +12 -1
  60. package/lib/engine/engine_scenelighting.js +21 -1
  61. package/lib/engine/engine_scenelighting.js.map +1 -1
  62. package/lib/engine/engine_texture.d.ts +1 -1
  63. package/lib/engine/engine_tonemapping.d.ts +1 -1
  64. package/lib/engine/engine_types.d.ts +16 -0
  65. package/lib/engine/engine_typestore.d.ts +1 -0
  66. package/lib/engine/engine_typestore.js +5 -6
  67. package/lib/engine/engine_typestore.js.map +1 -1
  68. package/lib/engine/engine_utils_qrcode.js +1 -1
  69. package/lib/engine/engine_utils_qrcode.js.map +1 -1
  70. package/lib/engine/extensions/NEEDLE_components.d.ts +4 -4
  71. package/lib/engine/extensions/NEEDLE_components.js +36 -17
  72. package/lib/engine/extensions/NEEDLE_components.js.map +1 -1
  73. package/lib/engine/extensions/NEEDLE_lightmaps.js +2 -2
  74. package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
  75. package/lib/engine/extensions/extensions.d.ts +2 -2
  76. package/lib/engine/extensions/extensions.js +11 -5
  77. package/lib/engine/extensions/extensions.js.map +1 -1
  78. package/lib/engine/webcomponents/buttons.d.ts +3 -1
  79. package/lib/engine/webcomponents/buttons.js +3 -1
  80. package/lib/engine/webcomponents/buttons.js.map +1 -1
  81. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +39 -2
  82. package/lib/engine/webcomponents/needle menu/needle-menu.js +39 -2
  83. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  84. package/lib/engine/webcomponents/needle-engine.attributes.d.ts +1 -0
  85. package/lib/engine/webcomponents/needle-engine.d.ts +1 -0
  86. package/lib/engine/webcomponents/needle-engine.js +3 -0
  87. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  88. package/lib/engine/xr/NeedleXRSession.js +2 -1
  89. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  90. package/lib/engine-components/Component.d.ts +5 -0
  91. package/lib/engine-components/Component.js +7 -0
  92. package/lib/engine-components/Component.js.map +1 -1
  93. package/lib/engine-components/ReflectionProbe.js +16 -10
  94. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  95. package/lib/engine-components/Renderer.js +16 -42
  96. package/lib/engine-components/Renderer.js.map +1 -1
  97. package/lib/engine-components/RendererInstancing.d.ts +5 -3
  98. package/lib/engine-components/RendererInstancing.js +64 -31
  99. package/lib/engine-components/RendererInstancing.js.map +1 -1
  100. package/lib/engine-components/RendererLightmap.d.ts +1 -0
  101. package/lib/engine-components/RendererLightmap.js +24 -18
  102. package/lib/engine-components/RendererLightmap.js.map +1 -1
  103. package/lib/engine-components/Skybox.d.ts +15 -5
  104. package/lib/engine-components/Skybox.js +37 -25
  105. package/lib/engine-components/Skybox.js.map +1 -1
  106. package/lib/engine-components/export/usdz/USDZExporter.d.ts +24 -3
  107. package/lib/engine-components/export/usdz/USDZExporter.js +36 -2
  108. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  109. package/lib/engine-components/timeline/PlayableDirector.d.ts +2 -1
  110. package/lib/engine-components/timeline/PlayableDirector.js +16 -9
  111. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  112. package/lib/engine-components/web/CursorFollow.d.ts +1 -0
  113. package/lib/engine-components/web/CursorFollow.js +2 -0
  114. package/lib/engine-components/web/CursorFollow.js.map +1 -1
  115. package/lib/engine-components/webxr/WebXR.js +4 -0
  116. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  117. package/lib/engine-components/webxr/controllers/XRControllerModel.js +1 -1
  118. package/lib/engine-components/webxr/controllers/XRControllerModel.js.map +1 -1
  119. package/lib/needle-engine.js +2 -1
  120. package/lib/needle-engine.js.map +1 -1
  121. package/package.json +15 -12
  122. package/plugins/types/needleConfig.d.ts +1 -1
  123. package/plugins/types/next.d.ts +1 -1
  124. package/plugins/types/userconfig.d.ts +1 -1
  125. package/src/engine/api.ts +1 -1
  126. package/src/engine/debug/debug_spector.ts +43 -0
  127. package/src/engine/engine_addressables.ts +75 -11
  128. package/src/engine/engine_application.ts +16 -1
  129. package/src/engine/engine_camera.fit.ts +49 -4
  130. package/src/engine/engine_context.ts +59 -10
  131. package/src/engine/engine_loaders.ts +6 -6
  132. package/src/engine/engine_physics.ts +6 -2
  133. package/src/engine/engine_physics_rapier.ts +11 -2
  134. package/src/engine/engine_scenelighting.ts +30 -8
  135. package/src/engine/engine_texture.ts +1 -1
  136. package/src/engine/engine_tonemapping.ts +1 -1
  137. package/src/engine/engine_types.ts +17 -0
  138. package/src/engine/engine_typestore.ts +5 -6
  139. package/src/engine/engine_utils_qrcode.ts +1 -1
  140. package/src/engine/extensions/NEEDLE_components.ts +47 -26
  141. package/src/engine/extensions/NEEDLE_lightmaps.ts +2 -2
  142. package/src/engine/extensions/extensions.ts +11 -5
  143. package/src/engine/webcomponents/buttons.ts +3 -1
  144. package/src/engine/webcomponents/needle menu/needle-menu.ts +40 -3
  145. package/src/engine/webcomponents/needle-engine.attributes.ts +2 -1
  146. package/src/engine/webcomponents/needle-engine.ts +4 -0
  147. package/src/engine/xr/NeedleXRSession.ts +3 -1
  148. package/src/engine-components/Component.ts +9 -1
  149. package/src/engine-components/ReflectionProbe.ts +18 -10
  150. package/src/engine-components/Renderer.ts +16 -44
  151. package/src/engine-components/RendererInstancing.ts +69 -33
  152. package/src/engine-components/RendererLightmap.ts +27 -17
  153. package/src/engine-components/Skybox.ts +47 -36
  154. package/src/engine-components/export/usdz/USDZExporter.ts +52 -5
  155. package/src/engine-components/timeline/PlayableDirector.ts +16 -10
  156. package/src/engine-components/web/CursorFollow.ts +3 -0
  157. package/src/engine-components/webxr/WebXR.ts +4 -0
  158. package/src/engine-components/webxr/controllers/XRControllerModel.ts +1 -1
  159. package/src/needle-engine.ts +4 -2
  160. package/dist/generateMeshBVH.worker-B9bjdr6J.js +0 -25
  161. package/dist/loader.worker-CiTwpNPW.js +0 -27
  162. package/dist/rapier-BqdcSmKY.umd.cjs +0 -1
  163. package/dist/rapier-Cg3w3nFI.min.js +0 -1
  164. package/dist/rapier-sU12SWAs.js +0 -5217
@@ -9,6 +9,10 @@ const debug = getParam("debuglightmaps");
9
9
 
10
10
  declare type MaterialWithLightmap = Material & { lightMap?: Texture | null };
11
11
 
12
+ let cloningCounter = 0;
13
+
14
+ const $lightmapVersion = Symbol("lightmap-material-version");
15
+
12
16
 
13
17
  /**
14
18
  * This component is automatically added by the {@link Renderer} component if the object has lightmap uvs AND we have a lightmap.
@@ -37,6 +41,8 @@ export class RendererLightmap {
37
41
  private lightmapScaleOffset: Vector4 = new Vector4(1, 1, 0, 0);
38
42
 
39
43
  private readonly renderer: Renderer;
44
+ private readonly clonedMaterials = new Array<Material>();
45
+
40
46
  private get context(): Context { return this.renderer.context; }
41
47
  private get gameObject() { return this.renderer.gameObject; }
42
48
  private lightmapTexture: Texture | null = null;
@@ -89,8 +95,7 @@ export class RendererLightmap {
89
95
 
90
96
  const mat = this.renderer.sharedMaterials[i];
91
97
  if (!mat) continue;
92
-
93
- const newMat = this.ensureLightmapMaterial(mat);
98
+ const newMat = this.ensureLightmapMaterial(mat, i);
94
99
  if (mat !== newMat) {
95
100
  this.renderer.sharedMaterials[i] = newMat;
96
101
  }
@@ -118,23 +123,28 @@ export class RendererLightmap {
118
123
  }
119
124
  }
120
125
 
121
- private ensureLightmapMaterial(material: Material) {
126
+ private ensureLightmapMaterial(material: Material, index: number) {
122
127
  if (!material.userData) material.userData = {};
123
128
  // if (material instanceof MeshPhysicalMaterial) {
124
129
  // return material;
125
130
  // }
126
131
  // check if the material version has changed and only then clone the material
127
- if (material["NEEDLE:lightmap-material-version"] != material.version) {
128
- if (material["NEEDLE:lightmap-material-version"] == undefined) {
129
- if (debug) console.warn("Cloning material for lightmap " + material.name);
130
- const mat: Material = material.clone();
131
- if (!mat.name?.includes("(lightmap)")) mat.name = material.name + " (lightmap)";
132
- material = mat;
133
- material.onBeforeCompile = this.onBeforeCompile;
134
- }
135
- else {
136
- // we need to clone the material
132
+ if (this.clonedMaterials[index] !== material) {
133
+ if (debug) {
134
+ ++cloningCounter;
135
+ if (cloningCounter++ < 1000) {
136
+ console.warn(`Cloning material for lightmap ${this.renderer.name}: '${material.name}'`);
137
+ }
138
+ else if (cloningCounter === 1000) {
139
+ console.warn(`Further material cloning for lightmaps suppressed to avoid flooding the console.`);
140
+ }
137
141
  }
142
+ const mat: Material = material.clone();
143
+ if (!mat.name?.includes("(lightmap)")) mat.name = material.name + " (lightmap)";
144
+ material = mat;
145
+ material.onBeforeCompile = this.onBeforeCompile;
146
+ this.clonedMaterials[index] = material;
147
+
138
148
  }
139
149
  return material;
140
150
  }
@@ -144,22 +154,22 @@ export class RendererLightmap {
144
154
  if (material instanceof MeshPhysicalMaterial && material.transmission > 0) {
145
155
  return;
146
156
  }
147
- const hasChanged = material.lightMap !== this.lightmapTexture || material["NEEDLE:lightmap-material-version"] !== material.version;
157
+ const hasChanged = material.lightMap !== this.lightmapTexture || material[$lightmapVersion] !== material.version;
148
158
  if (!hasChanged) {
149
159
  return;
150
160
  }
151
161
 
152
- if (debug) console.log("Assigning lightmap", material.name, material.version, material);
162
+ if (debug) console.log(`Assigning lightmap texture ${this.renderer.name}: '${material.name}' (${material.version} ${material[$lightmapVersion]})`);
153
163
 
154
164
  // assign the lightmap
155
165
  material.lightMap = this.lightmapTexture;
156
166
  material.needsUpdate = true;
157
167
  // store the version of the material
158
- material["NEEDLE:lightmap-material-version"] = material.version;
168
+ material[$lightmapVersion] = material.version;
159
169
  }
160
170
 
161
171
  private onBeforeCompile = (shader: WebGLProgramParametersWithUniforms, _) => {
162
- if (debug) console.log("Lightmaps, before compile\n", shader)
172
+ if (debug === "verbose") console.log("Lightmaps, before compile\n", shader)
163
173
  this.lightmapScaleOffsetUniform.value = this.lightmapScaleOffset;
164
174
  this.lightmapUniform.value = this.lightmapTexture;
165
175
  shader.uniforms.lightmapScaleOffset = this.lightmapScaleOffsetUniform;
@@ -1,16 +1,14 @@
1
- import { CompressedCubeTexture, CubeRefractionMapping, CubeTexture, CubeUVReflectionMapping, EquirectangularRefractionMapping, SRGBColorSpace, Texture, TextureLoader } from "three"
2
- import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader.js";
3
- import { KTX2Loader } from "three/examples/jsm/loaders/KTX2Loader.js";
4
- import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
1
+ import { CompressedCubeTexture, CubeTexture, CubeUVReflectionMapping, EquirectangularRefractionMapping, Texture } from "three"
5
2
 
3
+ import { isDevEnvironment } from "../engine/debug/debug.js";
6
4
  import { ContextEvent, ContextRegistry } from "../engine/engine_context_registry.js";
7
5
  import { syncField } from "../engine/engine_networking_auto.js";
8
6
  import { loadPMREM } from "../engine/engine_pmrem.js";
9
7
  import { serializable } from "../engine/engine_serialization_decorator.js";
10
8
  import { type IContext } from "../engine/engine_types.js";
11
- import { addAttributeChangeCallback, getParam, PromiseAllWithErrors, removeAttributeChangeCallback, toSourceId } from "../engine/engine_utils.js";
9
+ import { addAttributeChangeCallback, getParam, removeAttributeChangeCallback, toSourceId } from "../engine/engine_utils.js";
12
10
  import { registerObservableAttribute } from "../engine/webcomponents/needle-engine.extras.js";
13
- import { Camera, ClearFlags } from "./Camera.js";
11
+ import { Camera } from "./Camera.js";
14
12
  import { Behaviour, GameObject } from "./Component.js";
15
13
 
16
14
  const debug = getParam("debugskybox");
@@ -18,6 +16,29 @@ const debug = getParam("debugskybox");
18
16
  registerObservableAttribute("background-image");
19
17
  registerObservableAttribute("environment-image");
20
18
 
19
+
20
+ type MagicSkyboxName = "studio" | "blurred-skybox" | "quicklook-ar" | "quicklook";
21
+ const MagicSkyboxNames: Record<MagicSkyboxName, { url: string, url_low: string }> = {
22
+ "studio": {
23
+ url: "https://cdn.needle.tools/static/skybox/modelviewer-Neutral.pmrem4x4.ktx2?pmrem",
24
+ url_low: "https://cdn.needle.tools/static/skybox/modelviewer-Neutral-small.pmrem4x4.ktx2?pmrem"
25
+ },
26
+ "blurred-skybox": {
27
+ url: "https://cdn.needle.tools/static/skybox/blurred-skybox.pmrem4x4.ktx2?pmrem",
28
+ url_low: "https://cdn.needle.tools/static/skybox/blurred-skybox-small.pmrem4x4.ktx2?pmrem"
29
+ },
30
+ "quicklook-ar": {
31
+ url: "https://cdn.needle.tools/static/skybox/QuickLook-ARMode.pmrem4x4.ktx2?pmrem",
32
+ url_low: "https://cdn.needle.tools/static/skybox/QuickLook-ARMode-small.pmrem4x4.ktx2?pmrem"
33
+ },
34
+ "quicklook": {
35
+ url: "https://cdn.needle.tools/static/skybox/QuickLook-ObjectMode.pmrem4x4.ktx2?pmrem",
36
+ url_low: "https://cdn.needle.tools/static/skybox/QuickLook-ObjectMode-small.pmrem4x4.ktx2?pmrem"
37
+ }
38
+ } as const;
39
+ type AnyString = string & { _brand?: never };
40
+
41
+
21
42
  function createRemoteSkyboxComponent(context: IContext, url: string, skybox: boolean, environment: boolean, attribute: "background-image" | "environment-image") {
22
43
 
23
44
  // when the user sets the attribute to a color we can not handle it as a skybox url.
@@ -91,8 +112,9 @@ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, () => {
91
112
  });
92
113
 
93
114
 
115
+
94
116
  /**
95
- * RemoteSkybox is a component that allows you to set the skybox of a scene from a URL or a local file.
117
+ * RemoteSkybox is a component that allows you to set the skybox or environment texture of a scene from a URL, a local file or a static skybox name.
96
118
  * It supports .hdr, .exr, .jpg, .png files.
97
119
  *
98
120
  * ### Events
@@ -127,8 +149,13 @@ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, () => {
127
149
  export class RemoteSkybox extends Behaviour {
128
150
 
129
151
  /**
130
- * URL to a remote skybox. This value can also use a magic skybox name. Options are "quicklook", "quicklook-ar", "studio", "blurred-skybox".
131
- * To update the skybox/environment map use `setSkybox(url)`
152
+ * URL to a remote skybox.
153
+ * To update the skybox/environment map use `setSkybox(url)`.
154
+ *
155
+ * The url can also be set to a magic skybox name.
156
+ * Magic name options are: "quicklook", "quicklook-ar", "studio", "blurred-skybox".
157
+ * These will resolve to built-in skyboxes hosted on the Needle CDN that are static, optimized for the web and will never change.
158
+ *
132
159
  * @example
133
160
  * ```ts
134
161
  * skybox.url = "https://example.com/skybox.hdr";
@@ -136,7 +163,7 @@ export class RemoteSkybox extends Behaviour {
136
163
  */
137
164
  @syncField(RemoteSkybox.prototype.urlChangedSyncField)
138
165
  @serializable(URL)
139
- url?: string;
166
+ url: MagicSkyboxName | AnyString = "studio";
140
167
 
141
168
  /**
142
169
  * When enabled a user can drop a link to a skybox image on the scene to set the skybox.
@@ -208,7 +235,7 @@ export class RemoteSkybox extends Behaviour {
208
235
  * @param name Define name of the file with extension if it isn't apart of the url
209
236
  * @returns Whether the skybox was successfully set
210
237
  */
211
- async setSkybox(url: string | undefined | null, name?: string) {
238
+ async setSkybox(url: MagicSkyboxName | AnyString | undefined | null, name?: string) {
212
239
  if (!this.activeAndEnabled) return false;
213
240
 
214
241
  url = tryParseMagicSkyboxName(url, this.environment, this.background);
@@ -404,38 +431,22 @@ export class RemoteSkybox extends Behaviour {
404
431
 
405
432
 
406
433
 
407
-
408
434
  function tryParseMagicSkyboxName(str: string | null | undefined, environment: boolean, background: boolean): string | null {
409
435
 
410
436
  if (str === null || str === undefined) return null;
411
437
 
412
438
  const useLowRes = environment && !background;
413
439
 
414
- switch (str.toLowerCase()) {
415
- case "studio":
416
- if (useLowRes) {
417
- return "https://cdn.needle.tools/static/skybox/modelviewer-Neutral-small.pmrem4x4.ktx2?pmrem";
418
- }
419
- return "https://cdn.needle.tools/static/skybox/modelviewer-Neutral.pmrem4x4.ktx2?pmrem";
420
-
421
- case "blurred-skybox":
422
- if (useLowRes) {
423
- return "https://cdn.needle.tools/static/skybox/blurred-skybox-small.pmrem4x4.ktx2?pmrem";
424
- }
425
- return "https://cdn.needle.tools/static/skybox/blurred-skybox.pmrem4x4.ktx2?pmrem";
426
- case "quicklook-ar":
427
- if (useLowRes) {
428
- return "https://cdn.needle.tools/static/skybox/QuickLook-ARMode-small.pmrem4x4.ktx2?pmrem";
429
- }
430
- return "https://cdn.needle.tools/static/skybox/QuickLook-ARMode.pmrem4x4.ktx2?pmrem";
431
- case "quicklook":
432
- if (useLowRes) {
433
- return "https://cdn.needle.tools/static/skybox/QuickLook-ObjectMode-small.pmrem4x4.ktx2?pmrem";
434
- }
435
- return "https://cdn.needle.tools/static/skybox/QuickLook-ObjectMode.pmrem4x4.ktx2?pmrem";
440
+ const value = MagicSkyboxNames[str.toLowerCase() as MagicSkyboxName];
441
+ if (value) {
442
+ return useLowRes ? value.url_low : value.url;
443
+ }
444
+ else if (typeof str === "string" && str?.length && (isDevEnvironment() || debug)) {
445
+ const noUrlOrFile = !str.startsWith("http") && !str.startsWith("file:") && !str.startsWith("blob:") && !str.startsWith("data:");
446
+ if(noUrlOrFile) {
447
+ console.warn(`RemoteSkybox: Unknown magic skybox name "${str}". Valid names are: ${Object.keys(MagicSkyboxNames).map(n => `"${n}"`).join(", ")}`);
448
+ }
436
449
  }
437
-
438
-
439
450
 
440
451
  return str;
441
452
  }
@@ -1,5 +1,5 @@
1
1
  import { NEEDLE_progressive } from "@needle-tools/gltf-progressive";
2
- import { Euler, EventDispatcher, Matrix4, Mesh, Object3D, Quaternion, Vector3 } from "three";
2
+ import { Euler, Material, Matrix4, Mesh, Object3D, Quaternion, Vector3 } from "three";
3
3
 
4
4
  import { isDevEnvironment, showBalloonMessage, showBalloonWarning } from "../../../engine/debug/index.js";
5
5
  import { hasProLicense } from "../../../engine/engine_license.js";
@@ -53,6 +53,23 @@ export class CustomBranding {
53
53
  callToActionURL?: string;
54
54
  }
55
55
 
56
+ type BeforeLODExportArguments = {
57
+ readonly exporter: USDZExporter;
58
+ /** The type of LOD being exported, either a texture or a mesh */
59
+ readonly type: "texture" | "mesh";
60
+ /** The Renderer gameobject */
61
+ readonly object: Object3D;
62
+ /** The mesh being exported, if applicable */
63
+ readonly mesh?: Mesh;
64
+ /** The material being exported, if applicable */
65
+ readonly material?: Material;
66
+ /** By default LOD 0 will be exported (highest quality).
67
+ * Set to a different LOD level if needed.
68
+ * Set to -1 to disable LOD export and simply export the current version.
69
+ */
70
+ overrideLevel?: number;
71
+ }
72
+
56
73
  /**
57
74
  * Exports the current scene or a specific object as USDZ file and opens it in QuickLook on iOS/iPadOS/visionOS.
58
75
  * The USDZ file is generated using the Needle Engine ThreeUSDZExporter.
@@ -72,8 +89,12 @@ export class CustomBranding {
72
89
  */
73
90
  export class USDZExporter extends Behaviour {
74
91
 
75
- static readonly beforeExport = new EventList<{ exporter: USDZExporter }>();
76
- static readonly afterExport = new EventList<{ exporter: USDZExporter }>();
92
+ /** Called before the USDZ file is exported */
93
+ static readonly beforeExport = new EventList<{ readonly exporter: USDZExporter }>();
94
+ /** Called after the USDZ file has been exported */
95
+ static readonly afterExport = new EventList<{ readonly exporter: USDZExporter }>();
96
+ /** Called before LOD level are exported. Can be used to override the LOD export settings */
97
+ static readonly beforeLODExport = new EventList<BeforeLODExportArguments>();
77
98
 
78
99
  /**
79
100
  * Assign the object to export as USDZ file. If undefined or null, the whole scene will be exported.
@@ -329,7 +350,20 @@ export class USDZExporter extends Behaviour {
329
350
  for (const rend of renderers) {
330
351
  for (const mesh of rend.sharedMeshes) {
331
352
  if (mesh) {
332
- const task = NEEDLE_progressive.assignMeshLOD(mesh, 0);
353
+ let lodLevel = 0;
354
+ const args: BeforeLODExportArguments = { exporter: this, type: "mesh" as const, object: rend.gameObject, mesh: mesh, };
355
+ USDZExporter.beforeLODExport.invoke(args);
356
+ if (args.overrideLevel !== undefined) {
357
+ if (args.overrideLevel === -1) {
358
+ if (debug) console.warn("Skipping LOD export for mesh due to overrideLevel -1", rend.gameObject, mesh);
359
+ continue; // skip LOD assignment
360
+ }
361
+ else if (args.overrideLevel >= 0) {
362
+ lodLevel = args.overrideLevel;
363
+ if (debug) console.log("Overriding LOD level for mesh export to level " + lodLevel + " " + mesh.name);
364
+ }
365
+ }
366
+ const task = NEEDLE_progressive.assignMeshLOD(mesh, lodLevel);
333
367
  if (task instanceof Promise)
334
368
  progressiveLoading.push(new Promise<void>((resolve, reject) => {
335
369
  task.then(() => {
@@ -342,7 +376,20 @@ export class USDZExporter extends Behaviour {
342
376
  }
343
377
  for (const mat of rend.sharedMaterials) {
344
378
  if (mat) {
345
- const task = NEEDLE_progressive.assignTextureLOD(mat, 0);
379
+ let lodLevel = 0;
380
+ const args: BeforeLODExportArguments = { exporter: this, type: "texture" as const, object: rend.gameObject, material: mat };
381
+ USDZExporter.beforeLODExport.invoke(args);
382
+ if (args.overrideLevel !== undefined) {
383
+ if (args.overrideLevel === -1) {
384
+ if (debug) console.warn("Skipping LOD assignment due to overrideLevel -1", rend.gameObject, mat);
385
+ continue; // skip LOD assignment
386
+ }
387
+ else if (args.overrideLevel >= 0) {
388
+ lodLevel = args.overrideLevel;
389
+ if (debug) console.log("Overriding LOD level for texture export to level " + lodLevel + " " + mat.name);
390
+ }
391
+ }
392
+ const task = NEEDLE_progressive.assignTextureLOD(mat, lodLevel);
346
393
  if (task instanceof Promise)
347
394
  progressiveLoading.push(new Promise<void>((resolve, reject) => {
348
395
  task.then(() => {
@@ -114,8 +114,7 @@ export class PlayableDirector extends Behaviour {
114
114
 
115
115
  /** @internal */
116
116
  awake(): void {
117
- if (debug)
118
- console.log(this, this.playableAsset);
117
+ if (debug) console.log(`[Timeline] Awake '${this.name}'`, this);
119
118
 
120
119
  this.rebuildGraph();
121
120
 
@@ -134,6 +133,8 @@ export class PlayableDirector extends Behaviour {
134
133
 
135
134
  /** @internal */
136
135
  onEnable() {
136
+ if (debug) console.log("[Timeline] OnEnable", this.name, this.playOnAwake);
137
+
137
138
  for (const track of this._audioTracks) {
138
139
  track.onEnable?.();
139
140
  }
@@ -162,6 +163,8 @@ export class PlayableDirector extends Behaviour {
162
163
 
163
164
  /** @internal */
164
165
  onDisable(): void {
166
+ if (debug) console.log("[Timeline] OnDisable", this.name);
167
+
165
168
  this.stop();
166
169
  for (const track of this._audioTracks) {
167
170
  track.onDisable?.();
@@ -360,14 +363,17 @@ export class PlayableDirector extends Behaviour {
360
363
  private readonly _controlTracks: Array<Tracks.ControlTrackHandler> = [];
361
364
  private readonly _customTracks: Array<Tracks.TrackHandler> = [];
362
365
 
363
- private readonly _allTracks: Array<Array<Tracks.TrackHandler>> = [
364
- this._animationTracks,
365
- this._audioTracks,
366
- this._signalTracks,
367
- this._markerTracks,
368
- this._controlTracks,
369
- this._customTracks
370
- ];
366
+ private readonly _tracksArray: Array<Array<Tracks.TrackHandler>> = [];
367
+ private get _allTracks(): Array<Array<Tracks.TrackHandler>> {
368
+ this._tracksArray.length = 0;
369
+ this._tracksArray.push(this._animationTracks);
370
+ this._tracksArray.push(this._audioTracks);
371
+ this._tracksArray.push(this._signalTracks);
372
+ this._tracksArray.push(this._markerTracks);
373
+ this._tracksArray.push(this._controlTracks);
374
+ this._tracksArray.push(this._customTracks);
375
+ return this._tracksArray;
376
+ }
371
377
 
372
378
  /** should be called after evaluate if the director was playing */
373
379
  private invokePauseChangedMethodsOnTracks() {
@@ -20,6 +20,9 @@ const debug = getParam("debugcursor");
20
20
  */
21
21
  export class CursorFollow extends Behaviour {
22
22
 
23
+ // testing this for compilation
24
+ static readonly NAME = "CursorFollow";
25
+
23
26
  /**
24
27
  * Damping for the movement, set to 0 for instant movement
25
28
  * @default 0
@@ -331,6 +331,10 @@ export class WebXR extends Behaviour {
331
331
  console.warn(`WebXR: another WebXR component is already active (${WebXR.activeWebXRComponent?.name}). This is ignored: ${this.name}`);
332
332
  return;
333
333
  }
334
+ if (this.activeAndEnabled === false || this.destroyed) {
335
+ console.debug("[WebXR] onBeforeXR called on disabled or destroyed component");
336
+ return;
337
+ }
334
338
  WebXR.activeWebXRComponent = this;
335
339
 
336
340
  if (_mode == "immersive-ar" && this.useDepthSensing) {
@@ -284,7 +284,7 @@ export class XRControllerModel extends Behaviour {
284
284
 
285
285
  const loader = new GLTFLoader();
286
286
  addDracoAndKTX2Loaders(loader, context);
287
- await registerExtensions(loader, context, this.sourceId ?? "");
287
+ await registerExtensions(loader, context, this.sourceId ?? "", this.sourceId ?? "");
288
288
  const componentsExtension = registerComponentExtension(loader);
289
289
 
290
290
  let filename = "";
@@ -7,7 +7,7 @@ export * from "./engine-components-experimental/api.js";
7
7
  export * from "./engine-schemes/api.js";
8
8
 
9
9
  // make accessible for external javascript
10
- import { Context, loadAsset, NeedleXRSession, onAfterRender, onBeforeRender, onClear, onDestroy, onInitialized, onStart, onUpdate, VERSION } from "./engine/api.js";
10
+ import { Context, loadAsset, NeedleXRSession, onAfterRender, onBeforeRender, onClear, onDestroy, onInitialized, onStart, onUpdate, TypeStore, VERSION } from "./engine/api.js";
11
11
  const Needle = {
12
12
  VERSION: VERSION,
13
13
  Context: Context,
@@ -15,6 +15,7 @@ const Needle = {
15
15
  assets: {
16
16
  loadFromURL: loadAsset,
17
17
  },
18
+ types: TypeStore,
18
19
  onStart: onStart,
19
20
  onUpdate: onUpdate,
20
21
  onBeforeRender: onBeforeRender,
@@ -22,7 +23,8 @@ const Needle = {
22
23
  onInitializedContext: onInitialized,
23
24
  onDestroyContext: onDestroy,
24
25
  onClearContext: onClear,
25
- };
26
+ } as const;
27
+
26
28
  if (globalThis["Needle"]?.VERSION !== undefined) {
27
29
  console.warn(`Needle Engine is already imported: ${globalThis["Needle"].VERSION}`);
28
30
  }