@needle-tools/engine 4.8.7-next.e134730 → 4.8.8-next.5537a55

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 (89) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +31 -23
  3. package/components.needle.json +1 -1
  4. package/dist/{needle-engine.bundle-CvRpjtJj.js → needle-engine.bundle-BoZqXGLO.js} +6957 -6906
  5. package/dist/{needle-engine.bundle-DrGsgE4t.min.js → needle-engine.bundle-CpsmWsJo.min.js} +144 -144
  6. package/dist/{needle-engine.bundle-X9nxhICu.umd.cjs → needle-engine.bundle-D6vHQoPC.umd.cjs} +147 -147
  7. package/dist/needle-engine.js +2 -2
  8. package/dist/needle-engine.min.js +1 -1
  9. package/dist/needle-engine.umd.cjs +1 -1
  10. package/lib/engine/engine_addressables.d.ts +12 -12
  11. package/lib/engine/engine_addressables.js +30 -23
  12. package/lib/engine/engine_addressables.js.map +1 -1
  13. package/lib/engine/engine_animation.d.ts +1 -3
  14. package/lib/engine/engine_animation.js +15 -10
  15. package/lib/engine/engine_animation.js.map +1 -1
  16. package/lib/engine/engine_assetdatabase.js +6 -6
  17. package/lib/engine/engine_assetdatabase.js.map +1 -1
  18. package/lib/engine/engine_camera.d.ts +8 -1
  19. package/lib/engine/engine_camera.js +25 -0
  20. package/lib/engine/engine_camera.js.map +1 -1
  21. package/lib/engine/engine_context.d.ts +9 -0
  22. package/lib/engine/engine_context.js +15 -0
  23. package/lib/engine/engine_context.js.map +1 -1
  24. package/lib/engine/engine_gameobject.js +2 -2
  25. package/lib/engine/engine_gameobject.js.map +1 -1
  26. package/lib/engine/engine_loaders.callbacks.d.ts +1 -0
  27. package/lib/engine/engine_loaders.callbacks.js +1 -0
  28. package/lib/engine/engine_loaders.callbacks.js.map +1 -1
  29. package/lib/engine/engine_loaders.js +15 -11
  30. package/lib/engine/engine_loaders.js.map +1 -1
  31. package/lib/engine/webcomponents/needle-engine.attributes.d.ts +1 -0
  32. package/lib/engine/webcomponents/needle-engine.d.ts +2 -2
  33. package/lib/engine/webcomponents/needle-engine.js +19 -21
  34. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  35. package/lib/engine-components/Animation.js +2 -1
  36. package/lib/engine-components/Animation.js.map +1 -1
  37. package/lib/engine-components/AnimationUtilsAutoplay.js +1 -6
  38. package/lib/engine-components/AnimationUtilsAutoplay.js.map +1 -1
  39. package/lib/engine-components/Camera.d.ts +2 -0
  40. package/lib/engine-components/Camera.js +5 -1
  41. package/lib/engine-components/Camera.js.map +1 -1
  42. package/lib/engine-components/DropListener.d.ts +21 -15
  43. package/lib/engine-components/DropListener.js +38 -34
  44. package/lib/engine-components/DropListener.js.map +1 -1
  45. package/lib/engine-components/LookAtConstraint.d.ts +5 -1
  46. package/lib/engine-components/LookAtConstraint.js +8 -0
  47. package/lib/engine-components/LookAtConstraint.js.map +1 -1
  48. package/lib/engine-components/OrbitControls.d.ts +30 -9
  49. package/lib/engine-components/OrbitControls.js +53 -14
  50. package/lib/engine-components/OrbitControls.js.map +1 -1
  51. package/lib/engine-components/Skybox.js +8 -9
  52. package/lib/engine-components/Skybox.js.map +1 -1
  53. package/lib/engine-components/api.d.ts +1 -0
  54. package/lib/engine-components/api.js.map +1 -1
  55. package/lib/engine-components/export/usdz/Extension.d.ts +1 -1
  56. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +1 -1
  57. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -1
  58. package/lib/engine-components/export/usdz/USDZExporter.d.ts +7 -0
  59. package/lib/engine-components/export/usdz/USDZExporter.js +8 -1
  60. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  61. package/lib/engine-components/webxr/WebXRImageTracking.d.ts +4 -2
  62. package/lib/engine-components/webxr/WebXRImageTracking.js +117 -81
  63. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  64. package/package.json +1 -1
  65. package/plugins/common/files.js +6 -3
  66. package/plugins/vite/alias.js +26 -17
  67. package/plugins/vite/editor-connection.js +4 -4
  68. package/src/engine/engine_addressables.ts +44 -33
  69. package/src/engine/engine_animation.ts +17 -10
  70. package/src/engine/engine_assetdatabase.ts +7 -7
  71. package/src/engine/engine_camera.ts +40 -1
  72. package/src/engine/engine_context.ts +21 -1
  73. package/src/engine/engine_gameobject.ts +2 -2
  74. package/src/engine/engine_loaders.callbacks.ts +1 -0
  75. package/src/engine/engine_loaders.ts +18 -13
  76. package/src/engine/webcomponents/needle-engine.attributes.ts +2 -0
  77. package/src/engine/webcomponents/needle-engine.ts +21 -21
  78. package/src/engine-components/Animation.ts +1 -1
  79. package/src/engine-components/AnimationUtilsAutoplay.ts +1 -6
  80. package/src/engine-components/Camera.ts +7 -1
  81. package/src/engine-components/DropListener.ts +44 -34
  82. package/src/engine-components/LookAtConstraint.ts +9 -1
  83. package/src/engine-components/OrbitControls.ts +78 -22
  84. package/src/engine-components/Skybox.ts +9 -10
  85. package/src/engine-components/api.ts +2 -1
  86. package/src/engine-components/export/usdz/Extension.ts +1 -1
  87. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +1 -1
  88. package/src/engine-components/export/usdz/USDZExporter.ts +21 -12
  89. package/src/engine-components/webxr/WebXRImageTracking.ts +138 -90
@@ -649,12 +649,12 @@ export class OrbitControls extends Behaviour implements ICameraController {
649
649
  if (this._lookTargetLerpActive) {
650
650
  this._lookTargetLerp01 += this.context.time.deltaTime / this._lookTargetLerpDuration;
651
651
  if (this._lookTargetLerp01 >= 1) {
652
- this._controls.target.copy(this._lookTargetEndPosition);
652
+ this.lerpLookTarget(this._lookTargetEndPosition, this._lookTargetEndPosition, 1);
653
653
  this._lookTargetLerpActive = false;
654
654
  this.dispatchEvent(new CameraTargetReachedEvent(this, "lookat"));
655
655
  } else {
656
656
  const t = Mathf.easeInOutCubic(this._lookTargetLerp01);
657
- this._controls.target.lerpVectors(this._lookTargetStartPosition, this._lookTargetEndPosition, t);
657
+ this.lerpLookTarget(this._lookTargetStartPosition, this._lookTargetEndPosition, t);
658
658
  }
659
659
  }
660
660
 
@@ -729,7 +729,9 @@ export class OrbitControls extends Behaviour implements ICameraController {
729
729
 
730
730
  // this._controls.zoomToCursor = this.zoomToCursor;
731
731
  if (!this.context.isInXR) {
732
- if (!freeCam && this.lookAtConstraint?.locked) this.setLookTargetFromConstraint(0, this.lookAtConstraint01);
732
+ if (!freeCam && this.lookAtConstraint?.locked && !this._lookTargetLerpActive) {
733
+ this.setLookTargetFromConstraint(0, this.lookAtConstraint01);
734
+ }
733
735
  this._controls.update(this.context.time.deltaTime);
734
736
 
735
737
  if (debug) {
@@ -887,6 +889,8 @@ export class OrbitControls extends Behaviour implements ICameraController {
887
889
  }
888
890
  else this._fovLerpDuration = this.targetLerpDuration;
889
891
  }
892
+
893
+ // if (this.context.mainCameraComponent) this.context.mainCameraComponent.fieldOfView = fov;
890
894
  }
891
895
 
892
896
  /** Moves the camera look-at target to a position smoothly.
@@ -910,7 +914,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
910
914
  }
911
915
 
912
916
  if (immediateOrDuration === true) {
913
- this._controls.target.copy(this._lookTargetEndPosition);
917
+ this.lerpLookTarget(this._lookTargetEndPosition, this._lookTargetEndPosition, 1);
914
918
  }
915
919
  else {
916
920
  this._lookTargetLerpActive = true;
@@ -941,20 +945,18 @@ export class OrbitControls extends Behaviour implements ICameraController {
941
945
  const target = sources[index];
942
946
  if (target) {
943
947
  target.getWorldPosition(this._lookTargetEndPosition);
944
- this.lerpLookTarget(this._lookTargetEndPosition, t);
948
+ this.lerpLookTarget(this._controls.target, this._lookTargetEndPosition, t);
945
949
  return true;
946
950
  }
947
951
  }
948
952
  return false;
949
953
  }
950
954
 
951
- /** @deprecated use `controls.target.lerp(position, delta)` */
952
- public lerpTarget(position: Vector3, delta: number) { return this.lerpLookTarget(position, delta); }
953
-
954
- private lerpLookTarget(position: Vector3, delta: number) {
955
+ private lerpLookTarget(start: Vector3, position: Vector3, t: number) {
955
956
  if (!this._controls) return;
956
- if (delta >= 1) this._controls.target.copy(position);
957
- else this._controls.target.lerp(position, delta);
957
+ if (t >= 1) this._controls.target.copy(position);
958
+ else this._controls.target.lerpVectors(start, position, t);
959
+ if (this.lookAtConstraint) this.lookAtConstraint.setConstraintPosition(this._controls.target);
958
960
  }
959
961
 
960
962
  private setTargetFromRaycast(ray?: Ray, immediateOrDuration: number | boolean = false): boolean {
@@ -984,10 +986,11 @@ export class OrbitControls extends Behaviour implements ICameraController {
984
986
  */
985
987
  fitCamera(options?: FitCameraOptions);
986
988
  fitCamera(objects?: Object3D | Array<Object3D>, options?: Omit<FitCameraOptions, "objects">);
987
- fitCamera(objectsOrOptions?: Object3D | Array<Object3D> | FitCameraOptions, options?: FitCameraOptions) {
989
+ fitCamera(objectsOrOptions?: Object3D | Array<Object3D> | FitCameraOptions, options?: FitCameraOptions): void {
988
990
 
989
991
  if (this.context.isInXR) {
990
992
  // camera fitting in XR is not supported
993
+ console.warn('[OrbitControls] Can not fit camera while XR session is active');
991
994
  return;
992
995
  }
993
996
 
@@ -1032,7 +1035,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
1032
1035
  return;
1033
1036
  }
1034
1037
  if (!options) options = {}
1035
- const { immediate = false, centerCamera = "y", cameraNearFar = "auto", fitOffset = 1.1, fov = camera?.fov } = options;
1038
+ const { immediate = false, centerCamera, cameraNearFar = "auto", fitOffset = 1.1, fov = camera?.fov } = options;
1036
1039
  const size = new Vector3();
1037
1040
  const center = new Vector3();
1038
1041
  // TODO would be much better to calculate the bounds in camera space instead of world space -
@@ -1063,7 +1066,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
1063
1066
  return;
1064
1067
  }
1065
1068
 
1066
- const verticalFov = options.fov || camera.fov;
1069
+ const verticalFov = fov;
1067
1070
  const horizontalFov = 2 * Math.atan(Math.tan(verticalFov * Math.PI / 360 / 2) * camera.aspect) / Math.PI * 360;
1068
1071
  const fitHeightDistance = size.y / (2 * Math.atan(Math.PI * verticalFov / 360));
1069
1072
  const fitWidthDistance = size.x / (2 * Math.atan(Math.PI * horizontalFov / 360));
@@ -1078,9 +1081,18 @@ export class OrbitControls extends Behaviour implements ICameraController {
1078
1081
  this.minZoom = distance * 0.01;
1079
1082
 
1080
1083
  const verticalOffset = 0.05;
1081
-
1082
1084
  const lookAt = center.clone();
1083
1085
  lookAt.y -= size.y * verticalOffset;
1086
+ if (options.targetOffset) {
1087
+ if (options.targetOffset.x !== undefined) lookAt.x += options.targetOffset.x;
1088
+ if (options.targetOffset.y !== undefined) lookAt.y += options.targetOffset.y;
1089
+ if (options.targetOffset.z !== undefined) lookAt.z += options.targetOffset.z;
1090
+ }
1091
+ if (options.relativeTargetOffset) {
1092
+ if (options.relativeTargetOffset.x !== undefined) lookAt.x += options.relativeTargetOffset.x * size.x;
1093
+ if (options.relativeTargetOffset.y !== undefined) lookAt.y += options.relativeTargetOffset.y * size.y;
1094
+ if (options.relativeTargetOffset.z !== undefined) lookAt.z += options.relativeTargetOffset.z * size.z;
1095
+ }
1084
1096
  this.setLookTargetPosition(lookAt, immediate);
1085
1097
  this.setFieldOfView(options.fov, immediate);
1086
1098
 
@@ -1107,9 +1119,13 @@ export class OrbitControls extends Behaviour implements ICameraController {
1107
1119
  camera.updateMatrixWorld();
1108
1120
  camera.updateProjectionMatrix();
1109
1121
 
1110
- const cameraWp = getWorldPosition(camera);
1111
1122
  const direction = center.clone();
1112
- direction.sub(cameraWp);
1123
+ if (options.fitDirection) {
1124
+ direction.sub(new Vector3().copy(options.fitDirection).multiplyScalar(1_000_000));
1125
+ }
1126
+ else {
1127
+ direction.sub(camera.worldPosition);
1128
+ }
1113
1129
  if (centerCamera === "y")
1114
1130
  direction.y = 0;
1115
1131
  direction.normalize();
@@ -1118,6 +1134,16 @@ export class OrbitControls extends Behaviour implements ICameraController {
1118
1134
  direction.y += -verticalOffset * 4 * distance;
1119
1135
 
1120
1136
  let cameraLocalPosition = center.clone().sub(direction);
1137
+ if (options.cameraOffset) {
1138
+ if (options.cameraOffset.x !== undefined) cameraLocalPosition.x += options.cameraOffset.x;
1139
+ if (options.cameraOffset.y !== undefined) cameraLocalPosition.y += options.cameraOffset.y;
1140
+ if (options.cameraOffset.z !== undefined) cameraLocalPosition.z += options.cameraOffset.z;
1141
+ }
1142
+ if (options.relativeCameraOffset) {
1143
+ if (options.relativeCameraOffset.x !== undefined) cameraLocalPosition.x += options.relativeCameraOffset.x * size.x;
1144
+ if (options.relativeCameraOffset.y !== undefined) cameraLocalPosition.y += options.relativeCameraOffset.y * size.y;
1145
+ if (options.relativeCameraOffset.z !== undefined) cameraLocalPosition.z += options.relativeCameraOffset.z * size.z;
1146
+ }
1121
1147
  if (camera.parent) {
1122
1148
  cameraLocalPosition = camera.parent.worldToLocal(cameraLocalPosition);
1123
1149
  }
@@ -1154,23 +1180,53 @@ export class OrbitControls extends Behaviour implements ICameraController {
1154
1180
  /**
1155
1181
  * Options for fitting the camera to the scene. Used in {@link OrbitControls.fitCamera}
1156
1182
  */
1157
- declare type FitCameraOptions = {
1183
+ export type FitCameraOptions = {
1158
1184
  /** When enabled debug rendering will be shown */
1159
1185
  debug?: boolean,
1160
1186
  /**
1161
1187
  * The objects to fit the camera to. If not provided the scene children will be used
1162
1188
  */
1163
1189
  objects?: Object3D[] | Object3D;
1164
- /** Fit offset: A factor to multiply the distance to the objects by
1165
- * @default 1.1
1166
- */
1167
- fitOffset?: number,
1168
1190
  /** If true the camera will move immediately to the new position, otherwise it will lerp
1169
1191
  * @default false
1170
1192
  */
1171
1193
  immediate?: boolean,
1194
+
1195
+ /** Fit offset: A factor to multiply the distance to the objects by
1196
+ * @default 1.1
1197
+ */
1198
+ fitOffset?: number,
1199
+
1200
+ /** The direction from which the camera should be fitted in worldspace. If not defined the current camera's position will be used */
1201
+ fitDirection?: Vector3Like,
1202
+
1172
1203
  /** If set to "y" the camera will be centered in the y axis */
1173
1204
  centerCamera?: "none" | "y",
1205
+ /** Set to 'auto' to update the camera near or far plane based on the fitted-objects bounds */
1174
1206
  cameraNearFar?: "keep" | "auto",
1207
+
1208
+ /**
1209
+ * Offset the camera position in world space
1210
+ */
1211
+ cameraOffset?: Partial<Vector3Like>,
1212
+ /**
1213
+ * Offset the camera position relative to the size of the objects being focused on (e.g. x: 0.5).
1214
+ * Value range: -1 to 1
1215
+ */
1216
+ relativeCameraOffset?: Partial<Vector3Like>,
1217
+
1218
+ /**
1219
+ * Offset the camera target position in world space
1220
+ */
1221
+ targetOffset?: Partial<Vector3Like>,
1222
+ /**
1223
+ * Offset the camera target position relative to the size of the objects being focused on.
1224
+ * Value range: -1 to 1
1225
+ */
1226
+ relativeTargetOffset?: Partial<Vector3Like>,
1227
+
1228
+ /**
1229
+ * Field of view (FOV) for the camera
1230
+ */
1175
1231
  fov?: number,
1176
1232
  }
@@ -48,21 +48,20 @@ function createRemoteSkyboxComponent(context: IContext, url: string, skybox: boo
48
48
  const promises = new Array<Promise<any>>();
49
49
  ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, (args) => {
50
50
  const context = args.context;
51
- const skyboxImage = context.domElement.getAttribute("background-image");
51
+ const backgroundImage = context.domElement.getAttribute("background-image");
52
52
  const environmentImage = context.domElement.getAttribute("environment-image");
53
- const envAndSkyboxAreSame = skyboxImage === environmentImage;
54
-
55
- if (skyboxImage && !envAndSkyboxAreSame) {
56
- if (debug) console.log("Creating remote skybox to load " + skyboxImage);
53
+
54
+ if (backgroundImage) {
55
+ if (debug) console.log("Creating RemoteSkybox to load background " + backgroundImage);
57
56
  // if the user is loading a GLB without a camera then the CameraUtils (which creates the default camera)
58
57
  // checks if we have this attribute set and then sets the skybox clearflags accordingly
59
58
  // if the user has a GLB with a camera but set to solid color then the skybox image is not visible -> we will just warn then and not override the camera settings
60
- const promise = createRemoteSkyboxComponent(context, skyboxImage, true, false, "background-image");
59
+ const promise = createRemoteSkyboxComponent(context, backgroundImage, true, false, "background-image");
61
60
  if (promise) promises.push(promise);
62
61
  }
63
62
  if (environmentImage) {
64
- if (debug) console.log("Creating remote environment to load " + environmentImage);
65
- const promise = createRemoteSkyboxComponent(context, environmentImage, envAndSkyboxAreSame, true, "environment-image");
63
+ if (debug) console.log("Creating RemoteSkybox to load environment " + environmentImage);
64
+ const promise = createRemoteSkyboxComponent(context, environmentImage, false, true, "environment-image");
66
65
  if (promise) promises.push(promise);
67
66
  }
68
67
  });
@@ -200,7 +199,7 @@ export class RemoteSkybox extends Behaviour {
200
199
  console.warn("Potentially invalid skybox URL: \"" + name + "\" on " + (this.name || this.gameObject?.name || "context"));
201
200
  }
202
201
 
203
- if (debug) console.log("Set remote skybox url: " + url);
202
+ if (debug) console.log("Set RemoteSkybox url: " + url);
204
203
 
205
204
  if (this._prevUrl === url && this._prevLoadedEnvironment) {
206
205
  this.apply();
@@ -258,7 +257,7 @@ export class RemoteSkybox extends Behaviour {
258
257
  this._prevBackground = this.context.scene.background;
259
258
  if (this.context.scene.environment !== envMap)
260
259
  this._prevEnvironment = this.context.scene.environment;
261
- if (debug) console.log("Set remote skybox", this.url, !Camera.backgroundShouldBeTransparent(this.context));
260
+ if (debug) console.log("Set RemoteSkybox (" + ((this.environment && this.background) ? "environment and background" : this.environment ? "environment" : this.background ? "background" : "none") + ")", this.url, !Camera.backgroundShouldBeTransparent(this.context));
262
261
  if (this.environment)
263
262
  this.context.scene.environment = envMap;
264
263
  if (this.background && !Camera.backgroundShouldBeTransparent(this.context))
@@ -51,7 +51,8 @@ import "./CameraUtils.js"
51
51
  import "./AnimationUtils.js"
52
52
  import "./AnimationUtilsAutoplay.js"
53
53
 
54
- export { DragMode } from "./DragControls.js"
54
+ export { DragMode } from "./DragControls.js";
55
+ export { type FitCameraOptions } from "./OrbitControls.js";
55
56
  export type { DropListenerNetworkEventArguments, DropListenerOnDropArguments } from "./DropListener.js";
56
57
  export * from "./particlesystem/api.js"
57
58
 
@@ -21,5 +21,5 @@ export interface IUSDExporterExtension {
21
21
  onAfterBuildDocument?(context: USDZExporterContext);
22
22
  onExportObject?(object: Object3D, model: USDObject, context: USDZExporterContext);
23
23
  onAfterSerialize?(context: USDZExporterContext);
24
- onAfterHierarchy?(context: USDZExporterContext, writer: USDWriter);
24
+ onAfterHierarchy?(context: USDZExporterContext, writer: USDWriter) : void | Promise<void>;
25
25
  }
@@ -1082,7 +1082,7 @@ async function parseDocument( context: USDZExporterContext, afterStageRoot: () =
1082
1082
  Progress.end("export-usdz-xforms");
1083
1083
 
1084
1084
  Progress.report("export-usdz", "invoke onAfterHierarchy");
1085
- invokeAll( context, 'onAfterHierarchy', writer );
1085
+ await invokeAll( context, 'onAfterHierarchy', writer );
1086
1086
 
1087
1087
  writer.closeBlock();
1088
1088
  writer.closeBlock();
@@ -1,5 +1,5 @@
1
1
  import { NEEDLE_progressive } from "@needle-tools/gltf-progressive";
2
- import { Euler, Matrix4, Mesh, Object3D, Quaternion, Vector3 } from "three";
2
+ import { Euler, EventDispatcher, 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";
@@ -12,6 +12,7 @@ import { InstancingHandler } from "../../../engine-components/RendererInstancing
12
12
  import { Collider } from "../../Collider.js";
13
13
  import { Behaviour, GameObject } from "../../Component.js";
14
14
  import { ContactShadows } from "../../ContactShadows.js";
15
+ import { EventList } from "../../EventList.js";
15
16
  import { GroundProjectedEnv } from "../../GroundProjection.js";
16
17
  import { Renderer } from "../../Renderer.js"
17
18
  import { Rigidbody } from "../../RigidBody.js";
@@ -71,6 +72,9 @@ export class CustomBranding {
71
72
  */
72
73
  export class USDZExporter extends Behaviour {
73
74
 
75
+ static readonly beforeExport = new EventList<{ exporter: USDZExporter }>();
76
+ static readonly afterExport = new EventList<{ exporter: USDZExporter }>();
77
+
74
78
  /**
75
79
  * Assign the object to export as USDZ file. If undefined or null, the whole scene will be exported.
76
80
  */
@@ -210,7 +214,7 @@ export class USDZExporter extends Behaviour {
210
214
  * Creates an USDZ file from the current scene or assigned objectToExport and opens it in QuickLook.
211
215
  * @returns a Promise<Blob> containing the USDZ file
212
216
  */
213
- async exportAndOpen() : Promise<Blob | null> {
217
+ async exportAndOpen(): Promise<Blob | null> {
214
218
 
215
219
  let name = this.exportFileName ?? this.objectToExport?.name ?? this.name;
216
220
  name += "-" + getFormattedDate(); // seems iOS caches the file in some cases, this ensures we always have a fresh file
@@ -221,7 +225,7 @@ export class USDZExporter extends Behaviour {
221
225
  }
222
226
 
223
227
  if (!this.link) this.link = ensureQuicklookLinkIsCreated(this.context, DeviceUtilities.supportsQuickLookAR());
224
-
228
+
225
229
  // ability to specify a custom USDZ file to be used instead of a dynamic one
226
230
  if (this.customUsdzFile) {
227
231
  if (debug) console.log("Exporting custom usdz", this.customUsdzFile)
@@ -234,14 +238,19 @@ export class USDZExporter extends Behaviour {
234
238
  return null;
235
239
  }
236
240
 
237
- const blob = await this.export(this.objectToExport);
241
+ USDZExporter.beforeExport.invoke({ exporter: this });
242
+ const blob = await this.export(this.objectToExport)
243
+ .finally(() => {
244
+ USDZExporter.afterExport.invoke({ exporter: this });
245
+ });
246
+
238
247
  if (!blob) {
239
248
  console.error("USDZ generation failed. Please report a bug", this);
240
249
  return null;
241
250
  }
242
251
 
243
252
  if (debug) console.log("USDZ generation done. Downloading as " + name);
244
-
253
+
245
254
  // TODO Potentially we have to detect QuickLook availability here,
246
255
  // and download the file instead. But browsers keep changing how they deal with non-user-initiated downloads...
247
256
  // https://webkit.org/blog/8421/viewing-augmented-reality-assets-in-safari-for-ios/#:~:text=inside%20the%20anchor.-,Feature%20Detection,-To%20detect%20support
@@ -364,7 +373,7 @@ export class USDZExporter extends Behaviour {
364
373
  if (this.interactive) {
365
374
  defaultExtensions.push(new BehaviorExtension());
366
375
  defaultExtensions.push(new AudioExtension());
367
-
376
+
368
377
  // If physics are enabled, and there are any Rigidbody components in the scene,
369
378
  // add the PhysicsExtension to the default extensions.
370
379
  if (globalThis["NEEDLE_USE_RAPIER"]) {
@@ -632,13 +641,13 @@ export class USDZExporter extends Behaviour {
632
641
  private _rootPositionBeforeExport: Vector3 = new Vector3();
633
642
  private _rootRotationBeforeExport: Quaternion = new Quaternion();
634
643
  private _rootScaleBeforeExport: Vector3 = new Vector3();
635
-
636
- getARScaleAndTarget(): { scale: number, _invertForward: boolean, target: Object3D, sessionRoot: Object3D | null} {
637
- if (!this.objectToExport) return { scale: 1, _invertForward: false, target: this.gameObject, sessionRoot: null};
644
+
645
+ getARScaleAndTarget(): { scale: number, _invertForward: boolean, target: Object3D, sessionRoot: Object3D | null } {
646
+ if (!this.objectToExport) return { scale: 1, _invertForward: false, target: this.gameObject, sessionRoot: null };
638
647
 
639
648
  const xr = GameObject.findObjectOfType(WebXR);
640
649
  let sessionRoot = GameObject.getComponentInParent(this.objectToExport, WebARSessionRoot);
641
- if(!sessionRoot) sessionRoot = GameObject.getComponentInChildren(this.objectToExport, WebARSessionRoot);
650
+ if (!sessionRoot) sessionRoot = GameObject.getComponentInChildren(this.objectToExport, WebARSessionRoot);
642
651
 
643
652
  let arScale = 1;
644
653
  let _invertForward = false;
@@ -653,7 +662,7 @@ export class USDZExporter extends Behaviour {
653
662
  // eslint-disable-next-line deprecation/deprecation
654
663
  _invertForward = sessionRoot.invertForward;
655
664
  }
656
-
665
+
657
666
  const scale = 1 / arScale;
658
667
  const result = { scale, _invertForward, target, sessionRoot: sessionRoot?.gameObject ?? null };
659
668
  return result;
@@ -699,7 +708,7 @@ export class USDZExporter extends Behaviour {
699
708
  private createQuicklookButton() {
700
709
  const buttoncontainer = WebXRButtonFactory.getOrCreate();
701
710
  const button = buttoncontainer.createQuicklookButton();
702
- if(!button.parentNode) this.context.menu.appendChild(button);
711
+ if (!button.parentNode) this.context.menu.appendChild(button);
703
712
  return button;
704
713
  }
705
714
  }