@tonybfox/threejs-tools 1.0.2 → 1.0.4

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 (67) hide show
  1. package/dist/asset-loader/index.cjs +27 -7
  2. package/dist/asset-loader/index.d.mts +2 -1
  3. package/dist/asset-loader/index.d.ts +2 -1
  4. package/dist/asset-loader/index.mjs +1 -2
  5. package/dist/camera/index.cjs +91 -3
  6. package/dist/camera/index.d.mts +22 -1
  7. package/dist/camera/index.d.ts +22 -1
  8. package/dist/camera/index.mjs +1 -2
  9. package/dist/{chunk-L4VIIJZD.mjs → chunk-27WUVRGX.mjs} +27 -7
  10. package/dist/{chunk-EQDOX34V.mjs → chunk-2CDI7ORN.mjs} +0 -1
  11. package/dist/{chunk-EIROAPF7.mjs → chunk-FBTT6MU6.mjs} +0 -1
  12. package/dist/{chunk-VETFQ3IQ.mjs → chunk-IAZH4OHC.mjs} +0 -1
  13. package/dist/{chunk-5DP6WDB3.mjs → chunk-OZKJ3GAD.mjs} +0 -1
  14. package/dist/{chunk-IIAZ2WJJ.mjs → chunk-W4DAAAW6.mjs} +0 -1
  15. package/dist/{chunk-WMHEIUXE.mjs → chunk-XA7OKYSM.mjs} +91 -3
  16. package/dist/{chunk-BJKSICFA.mjs → chunk-YMMLYGHV.mjs} +0 -1
  17. package/dist/{chunk-P35QJCOG.mjs → chunk-ZNGFST7K.mjs} +15 -6
  18. package/dist/compass/index.cjs +15 -6
  19. package/dist/compass/index.d.mts +4 -2
  20. package/dist/compass/index.d.ts +4 -2
  21. package/dist/compass/index.mjs +1 -2
  22. package/dist/grid/index.cjs +0 -1
  23. package/dist/grid/index.mjs +1 -2
  24. package/dist/index.cjs +133 -14
  25. package/dist/index.d.mts +1 -1
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.mjs +9 -10
  28. package/dist/measurements/index.cjs +0 -1
  29. package/dist/measurements/index.mjs +1 -2
  30. package/dist/sunlight/index.cjs +0 -1
  31. package/dist/sunlight/index.mjs +1 -2
  32. package/dist/terrain/index.cjs +0 -1
  33. package/dist/terrain/index.mjs +1 -2
  34. package/dist/transform-controls/index.cjs +0 -1
  35. package/dist/transform-controls/index.mjs +1 -2
  36. package/dist/view-helper/index.cjs +0 -1
  37. package/dist/view-helper/index.mjs +1 -2
  38. package/package.json +1 -1
  39. package/dist/asset-loader/index.cjs.map +0 -1
  40. package/dist/asset-loader/index.mjs.map +0 -1
  41. package/dist/camera/index.cjs.map +0 -1
  42. package/dist/camera/index.mjs.map +0 -1
  43. package/dist/chunk-5DP6WDB3.mjs.map +0 -1
  44. package/dist/chunk-BJKSICFA.mjs.map +0 -1
  45. package/dist/chunk-EIROAPF7.mjs.map +0 -1
  46. package/dist/chunk-EQDOX34V.mjs.map +0 -1
  47. package/dist/chunk-IIAZ2WJJ.mjs.map +0 -1
  48. package/dist/chunk-L4VIIJZD.mjs.map +0 -1
  49. package/dist/chunk-P35QJCOG.mjs.map +0 -1
  50. package/dist/chunk-VETFQ3IQ.mjs.map +0 -1
  51. package/dist/chunk-WMHEIUXE.mjs.map +0 -1
  52. package/dist/compass/index.cjs.map +0 -1
  53. package/dist/compass/index.mjs.map +0 -1
  54. package/dist/grid/index.cjs.map +0 -1
  55. package/dist/grid/index.mjs.map +0 -1
  56. package/dist/index.cjs.map +0 -1
  57. package/dist/index.mjs.map +0 -1
  58. package/dist/measurements/index.cjs.map +0 -1
  59. package/dist/measurements/index.mjs.map +0 -1
  60. package/dist/sunlight/index.cjs.map +0 -1
  61. package/dist/sunlight/index.mjs.map +0 -1
  62. package/dist/terrain/index.cjs.map +0 -1
  63. package/dist/terrain/index.mjs.map +0 -1
  64. package/dist/transform-controls/index.cjs.map +0 -1
  65. package/dist/transform-controls/index.mjs.map +0 -1
  66. package/dist/view-helper/index.cjs.map +0 -1
  67. package/dist/view-helper/index.mjs.map +0 -1
@@ -39,6 +39,7 @@ var THREE = __toESM(require("three"));
39
39
  var import_GLTFLoader = require("three/examples/jsm/loaders/GLTFLoader.js");
40
40
  var import_FBXLoader = require("three/examples/jsm/loaders/FBXLoader.js");
41
41
  var import_OBJLoader = require("three/examples/jsm/loaders/OBJLoader.js");
42
+ var import_USDLoader = require("three/examples/jsm/loaders/USDLoader.js");
42
43
  var AssetLoader = class extends THREE.EventDispatcher {
43
44
  constructor() {
44
45
  super();
@@ -51,6 +52,7 @@ var AssetLoader = class extends THREE.EventDispatcher {
51
52
  this.gltfLoader = new import_GLTFLoader.GLTFLoader();
52
53
  this.fbxLoader = new import_FBXLoader.FBXLoader();
53
54
  this.objLoader = new import_OBJLoader.OBJLoader();
55
+ this.usdLoader = new import_USDLoader.USDLoader();
54
56
  }
55
57
  /**
56
58
  * Create a placeholder cube with shader effect
@@ -68,7 +70,9 @@ var AssetLoader = class extends THREE.EventDispatcher {
68
70
  opacity: { value: opacity },
69
71
  fillProgress: { value: 0 },
70
72
  time: { value: 0 },
71
- isError: { value: 0 }
73
+ isError: { value: 0 },
74
+ yMin: { value: -height / 2 },
75
+ yMax: { value: height / 2 }
72
76
  },
73
77
  vertexShader: `
74
78
  varying vec3 vPosition;
@@ -83,15 +87,17 @@ var AssetLoader = class extends THREE.EventDispatcher {
83
87
  uniform float fillProgress;
84
88
  uniform float time;
85
89
  uniform float isError;
90
+ uniform float yMin;
91
+ uniform float yMax;
86
92
  varying vec3 vPosition;
87
93
 
88
94
  void main() {
89
- float normalizedY = (vPosition.y + 1.0) / 2.0; // Normalize from -1,1 to 0,1
95
+ float normalizedY = (vPosition.y - yMin) / (yMax - yMin); // Normalize based on actual geometry bounds
90
96
  float alpha = opacity;
91
97
 
92
98
  // Create fill-up effect
93
99
  if (normalizedY > fillProgress) {
94
- alpha *= 0.3; // Reduce opacity for unfilled parts
100
+ alpha *= 0.1; // Reduce opacity for unfilled parts
95
101
  }
96
102
 
97
103
  // Error state effects
@@ -217,7 +223,7 @@ var AssetLoader = class extends THREE.EventDispatcher {
217
223
  lowResUrl,
218
224
  enableCaching = true,
219
225
  placeholderColor = 5227511,
220
- placeholderOpacity = 0.8,
226
+ placeholderOpacity = 0.4,
221
227
  errorColor = 16729156,
222
228
  errorOpacity = 0.5
223
229
  } = options;
@@ -278,14 +284,17 @@ var AssetLoader = class extends THREE.EventDispatcher {
278
284
  loadModel(type, url, isLowRes) {
279
285
  return new Promise((resolve, reject) => {
280
286
  const onProgress = (event) => {
281
- const percentage = event.loaded / event.total * 100;
287
+ let percentage = -1;
288
+ if (event.lengthComputable && event.total > 0 && event.loaded <= event.total) {
289
+ percentage = event.loaded / event.total * 100;
290
+ }
282
291
  this.dispatchEvent({
283
292
  type: "progress",
284
293
  loaded: event.loaded,
285
294
  total: event.total,
286
295
  percentage
287
296
  });
288
- if (!isLowRes) {
297
+ if (!isLowRes && percentage >= 0) {
289
298
  this.updatePlaceholder(percentage / 100);
290
299
  }
291
300
  };
@@ -327,6 +336,18 @@ var AssetLoader = class extends THREE.EventDispatcher {
327
336
  onError
328
337
  );
329
338
  break;
339
+ case "usd":
340
+ case "usdz":
341
+ this.usdLoader.load(
342
+ url,
343
+ (usd) => {
344
+ this.positionAssetAtBottomCenter(usd);
345
+ resolve(usd);
346
+ },
347
+ onProgress,
348
+ onError
349
+ );
350
+ break;
330
351
  default:
331
352
  reject(new Error(`Unsupported asset type: ${type}`));
332
353
  }
@@ -373,4 +394,3 @@ var AssetLoader = class extends THREE.EventDispatcher {
373
394
  0 && (module.exports = {
374
395
  AssetLoader
375
396
  });
376
- //# sourceMappingURL=index.cjs.map
@@ -19,7 +19,7 @@ interface AssetLoaderEventMap {
19
19
  lowRes: THREE.Object3D;
20
20
  };
21
21
  }
22
- type AssetType = 'gltf' | 'fbx' | 'obj';
22
+ type AssetType = 'gltf' | 'fbx' | 'obj' | 'usd' | 'usdz';
23
23
  interface AssetLoaderOptions {
24
24
  type: AssetType;
25
25
  url: string;
@@ -36,6 +36,7 @@ declare class AssetLoader extends THREE.EventDispatcher<AssetLoaderEventMap> {
36
36
  private gltfLoader;
37
37
  private fbxLoader;
38
38
  private objLoader;
39
+ private usdLoader;
39
40
  private placeholder;
40
41
  private loadedAsset;
41
42
  private lowResAsset;
@@ -19,7 +19,7 @@ interface AssetLoaderEventMap {
19
19
  lowRes: THREE.Object3D;
20
20
  };
21
21
  }
22
- type AssetType = 'gltf' | 'fbx' | 'obj';
22
+ type AssetType = 'gltf' | 'fbx' | 'obj' | 'usd' | 'usdz';
23
23
  interface AssetLoaderOptions {
24
24
  type: AssetType;
25
25
  url: string;
@@ -36,6 +36,7 @@ declare class AssetLoader extends THREE.EventDispatcher<AssetLoaderEventMap> {
36
36
  private gltfLoader;
37
37
  private fbxLoader;
38
38
  private objLoader;
39
+ private usdLoader;
39
40
  private placeholder;
40
41
  private loadedAsset;
41
42
  private lowResAsset;
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  AssetLoader
3
- } from "../chunk-L4VIIJZD.mjs";
3
+ } from "../chunk-27WUVRGX.mjs";
4
4
  export {
5
5
  AssetLoader
6
6
  };
7
- //# sourceMappingURL=index.mjs.map
@@ -100,6 +100,7 @@ var DualCameraControls = class extends import_camera_controls.default {
100
100
  const initialCamera = initialMode === "orthographic" ? orthographicCamera : perspectiveCamera;
101
101
  super(initialCamera, domElement);
102
102
  this.updateClock = new THREE.Clock();
103
+ this.externalCamera = null;
103
104
  const initialTarget = toVector3(
104
105
  options.initialTarget,
105
106
  [0, 0, 0],
@@ -135,9 +136,10 @@ var DualCameraControls = class extends import_camera_controls.default {
135
136
  * Switch to the perspective camera while keeping the current framing.
136
137
  */
137
138
  switchToPerspective(enableTransition = false) {
138
- if (this.activeMode === "perspective") {
139
+ if (this.activeMode === "perspective" && !this.externalCamera) {
139
140
  return;
140
141
  }
142
+ this.externalCamera = null;
141
143
  const target = this.getTarget(tempVec3A);
142
144
  const position = this.getPosition(tempVec3B);
143
145
  const aspect = resolveAspect(this.renderer, this.domElementRef);
@@ -169,9 +171,10 @@ var DualCameraControls = class extends import_camera_controls.default {
169
171
  * Switch to the orthographic camera while keeping the current framing.
170
172
  */
171
173
  switchToOrthographic(enableTransition = false) {
172
- if (this.activeMode === "orthographic") {
174
+ if (this.activeMode === "orthographic" && !this.externalCamera) {
173
175
  return;
174
176
  }
177
+ this.externalCamera = null;
175
178
  const target = this.getTarget(tempVec3A);
176
179
  const position = this.getPosition(tempVec3B);
177
180
  const aspect = resolveAspect(this.renderer, this.domElementRef);
@@ -209,6 +212,92 @@ var DualCameraControls = class extends import_camera_controls.default {
209
212
  this.switchToPerspective(enableTransition);
210
213
  }
211
214
  }
215
+ /**
216
+ * Returns true if currently using an external camera.
217
+ */
218
+ get isUsingExternalCamera() {
219
+ return this.externalCamera !== null;
220
+ }
221
+ /**
222
+ * Sets an external camera to use with the controls.
223
+ * This allows using a camera created outside of DualCameraControls.
224
+ * Call `clearExternalCamera()` to return to the internal cameras.
225
+ */
226
+ setCamera(camera, target, enableTransition = false) {
227
+ const previousCamera = this.camera;
228
+ this.externalCamera = camera;
229
+ const aspect = resolveAspect(this.renderer, this.domElementRef);
230
+ if (camera.type === "PerspectiveCamera") {
231
+ ;
232
+ camera.aspect = aspect;
233
+ camera.updateProjectionMatrix();
234
+ } else if (camera.type === "OrthographicCamera") {
235
+ const ortho = camera;
236
+ const currentHeight = (ortho.top - ortho.bottom) * 0.5;
237
+ const newHalfWidth = currentHeight * aspect;
238
+ ortho.left = -newHalfWidth;
239
+ ortho.right = newHalfWidth;
240
+ ortho.updateProjectionMatrix();
241
+ }
242
+ this.camera = camera;
243
+ const mode = camera.type === "PerspectiveCamera" ? "perspective" : "orthographic";
244
+ this.activeMode = mode;
245
+ this.updateInputBindingsForMode(mode);
246
+ const targetVec = toVector3(target, [0, 0, 0], tempVec3A);
247
+ void this.setLookAt(
248
+ camera.position.x,
249
+ camera.position.y,
250
+ camera.position.z,
251
+ targetVec.x,
252
+ targetVec.y,
253
+ targetVec.z,
254
+ enableTransition
255
+ );
256
+ this.dispatchEvent({
257
+ type: "externalcamerachange",
258
+ camera,
259
+ previousCamera
260
+ });
261
+ }
262
+ /**
263
+ * Clears the external camera and returns to using the internal cameras.
264
+ * Will switch to the camera matching the current mode.
265
+ */
266
+ clearExternalCamera(enableTransition = false) {
267
+ if (!this.externalCamera) {
268
+ return;
269
+ }
270
+ const target = this.getTarget(tempVec3A);
271
+ const position = this.getPosition(tempVec3B);
272
+ this.externalCamera = null;
273
+ const internalCamera = this.activeMode === "orthographic" ? this.orthographicCamera : this.perspectiveCamera;
274
+ internalCamera.position.copy(position);
275
+ internalCamera.quaternion.copy(this.camera.quaternion);
276
+ internalCamera.up.copy(this.camera.up);
277
+ const aspect = resolveAspect(this.renderer, this.domElementRef);
278
+ if (this.activeMode === "orthographic") {
279
+ this.updateOrthographicFrustum(position, target, aspect);
280
+ } else {
281
+ this.perspectiveCamera.aspect = aspect;
282
+ this.perspectiveCamera.updateProjectionMatrix();
283
+ }
284
+ this.camera = internalCamera;
285
+ void this.setLookAt(
286
+ position.x,
287
+ position.y,
288
+ position.z,
289
+ target.x,
290
+ target.y,
291
+ target.z,
292
+ enableTransition
293
+ );
294
+ this.dispatchEvent({
295
+ type: "modechange",
296
+ mode: this.activeMode,
297
+ previousMode: this.activeMode,
298
+ camera: internalCamera
299
+ });
300
+ }
212
301
  /**
213
302
  * Update camera projection parameters when the viewport size changes.
214
303
  */
@@ -302,4 +391,3 @@ function resolveAspect(renderer, domElement) {
302
391
  0 && (module.exports = {
303
392
  DualCameraControls
304
393
  });
305
- //# sourceMappingURL=index.cjs.map
@@ -31,6 +31,11 @@ interface ModeChangedEvent {
31
31
  previousMode: CameraMode;
32
32
  camera: THREE.PerspectiveCamera | THREE.OrthographicCamera;
33
33
  }
34
+ interface ExternalCameraChangedEvent {
35
+ type: 'externalcamerachange';
36
+ camera: THREE.PerspectiveCamera | THREE.OrthographicCamera;
37
+ previousCamera: THREE.PerspectiveCamera | THREE.OrthographicCamera;
38
+ }
34
39
  /**
35
40
  * Camera controls that manage both perspective and orthographic cameras while
36
41
  * extending {@link CameraControls}. Provides helpers to toggle between the
@@ -44,6 +49,7 @@ declare class DualCameraControls extends CameraControls {
44
49
  private activeMode;
45
50
  private readonly minOrthoHalfHeight;
46
51
  private readonly updateClock;
52
+ private externalCamera;
47
53
  constructor(renderer: THREE.WebGLRenderer, options?: DualCameraControlsOptions);
48
54
  get mode(): CameraMode;
49
55
  /**
@@ -62,6 +68,21 @@ declare class DualCameraControls extends CameraControls {
62
68
  * Toggles between perspective and orthographic camera modes.
63
69
  */
64
70
  toggleCameraMode(enableTransition?: boolean): void;
71
+ /**
72
+ * Returns true if currently using an external camera.
73
+ */
74
+ get isUsingExternalCamera(): boolean;
75
+ /**
76
+ * Sets an external camera to use with the controls.
77
+ * This allows using a camera created outside of DualCameraControls.
78
+ * Call `clearExternalCamera()` to return to the internal cameras.
79
+ */
80
+ setCamera(camera: THREE.PerspectiveCamera | THREE.OrthographicCamera, target?: Vector3Like, enableTransition?: boolean): void;
81
+ /**
82
+ * Clears the external camera and returns to using the internal cameras.
83
+ * Will switch to the camera matching the current mode.
84
+ */
85
+ clearExternalCamera(enableTransition?: boolean): void;
65
86
  /**
66
87
  * Update camera projection parameters when the viewport size changes.
67
88
  */
@@ -79,4 +100,4 @@ declare class DualCameraControls extends CameraControls {
79
100
  private updateOrthographicFrustum;
80
101
  }
81
102
 
82
- export { type CameraMode, DualCameraControls, type DualCameraControlsOptions, type ModeChangedEvent, type OrthographicCameraConfig, type PerspectiveCameraConfig };
103
+ export { type CameraMode, DualCameraControls, type DualCameraControlsOptions, type ExternalCameraChangedEvent, type ModeChangedEvent, type OrthographicCameraConfig, type PerspectiveCameraConfig };
@@ -31,6 +31,11 @@ interface ModeChangedEvent {
31
31
  previousMode: CameraMode;
32
32
  camera: THREE.PerspectiveCamera | THREE.OrthographicCamera;
33
33
  }
34
+ interface ExternalCameraChangedEvent {
35
+ type: 'externalcamerachange';
36
+ camera: THREE.PerspectiveCamera | THREE.OrthographicCamera;
37
+ previousCamera: THREE.PerspectiveCamera | THREE.OrthographicCamera;
38
+ }
34
39
  /**
35
40
  * Camera controls that manage both perspective and orthographic cameras while
36
41
  * extending {@link CameraControls}. Provides helpers to toggle between the
@@ -44,6 +49,7 @@ declare class DualCameraControls extends CameraControls {
44
49
  private activeMode;
45
50
  private readonly minOrthoHalfHeight;
46
51
  private readonly updateClock;
52
+ private externalCamera;
47
53
  constructor(renderer: THREE.WebGLRenderer, options?: DualCameraControlsOptions);
48
54
  get mode(): CameraMode;
49
55
  /**
@@ -62,6 +68,21 @@ declare class DualCameraControls extends CameraControls {
62
68
  * Toggles between perspective and orthographic camera modes.
63
69
  */
64
70
  toggleCameraMode(enableTransition?: boolean): void;
71
+ /**
72
+ * Returns true if currently using an external camera.
73
+ */
74
+ get isUsingExternalCamera(): boolean;
75
+ /**
76
+ * Sets an external camera to use with the controls.
77
+ * This allows using a camera created outside of DualCameraControls.
78
+ * Call `clearExternalCamera()` to return to the internal cameras.
79
+ */
80
+ setCamera(camera: THREE.PerspectiveCamera | THREE.OrthographicCamera, target?: Vector3Like, enableTransition?: boolean): void;
81
+ /**
82
+ * Clears the external camera and returns to using the internal cameras.
83
+ * Will switch to the camera matching the current mode.
84
+ */
85
+ clearExternalCamera(enableTransition?: boolean): void;
65
86
  /**
66
87
  * Update camera projection parameters when the viewport size changes.
67
88
  */
@@ -79,4 +100,4 @@ declare class DualCameraControls extends CameraControls {
79
100
  private updateOrthographicFrustum;
80
101
  }
81
102
 
82
- export { type CameraMode, DualCameraControls, type DualCameraControlsOptions, type ModeChangedEvent, type OrthographicCameraConfig, type PerspectiveCameraConfig };
103
+ export { type CameraMode, DualCameraControls, type DualCameraControlsOptions, type ExternalCameraChangedEvent, type ModeChangedEvent, type OrthographicCameraConfig, type PerspectiveCameraConfig };
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  DualCameraControls
3
- } from "../chunk-WMHEIUXE.mjs";
3
+ } from "../chunk-XA7OKYSM.mjs";
4
4
  export {
5
5
  DualCameraControls
6
6
  };
7
- //# sourceMappingURL=index.mjs.map
@@ -3,6 +3,7 @@ import * as THREE from "three";
3
3
  import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
4
4
  import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader.js";
5
5
  import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader.js";
6
+ import { USDLoader } from "three/examples/jsm/loaders/USDLoader.js";
6
7
  var AssetLoader = class extends THREE.EventDispatcher {
7
8
  constructor() {
8
9
  super();
@@ -15,6 +16,7 @@ var AssetLoader = class extends THREE.EventDispatcher {
15
16
  this.gltfLoader = new GLTFLoader();
16
17
  this.fbxLoader = new FBXLoader();
17
18
  this.objLoader = new OBJLoader();
19
+ this.usdLoader = new USDLoader();
18
20
  }
19
21
  /**
20
22
  * Create a placeholder cube with shader effect
@@ -32,7 +34,9 @@ var AssetLoader = class extends THREE.EventDispatcher {
32
34
  opacity: { value: opacity },
33
35
  fillProgress: { value: 0 },
34
36
  time: { value: 0 },
35
- isError: { value: 0 }
37
+ isError: { value: 0 },
38
+ yMin: { value: -height / 2 },
39
+ yMax: { value: height / 2 }
36
40
  },
37
41
  vertexShader: `
38
42
  varying vec3 vPosition;
@@ -47,15 +51,17 @@ var AssetLoader = class extends THREE.EventDispatcher {
47
51
  uniform float fillProgress;
48
52
  uniform float time;
49
53
  uniform float isError;
54
+ uniform float yMin;
55
+ uniform float yMax;
50
56
  varying vec3 vPosition;
51
57
 
52
58
  void main() {
53
- float normalizedY = (vPosition.y + 1.0) / 2.0; // Normalize from -1,1 to 0,1
59
+ float normalizedY = (vPosition.y - yMin) / (yMax - yMin); // Normalize based on actual geometry bounds
54
60
  float alpha = opacity;
55
61
 
56
62
  // Create fill-up effect
57
63
  if (normalizedY > fillProgress) {
58
- alpha *= 0.3; // Reduce opacity for unfilled parts
64
+ alpha *= 0.1; // Reduce opacity for unfilled parts
59
65
  }
60
66
 
61
67
  // Error state effects
@@ -181,7 +187,7 @@ var AssetLoader = class extends THREE.EventDispatcher {
181
187
  lowResUrl,
182
188
  enableCaching = true,
183
189
  placeholderColor = 5227511,
184
- placeholderOpacity = 0.8,
190
+ placeholderOpacity = 0.4,
185
191
  errorColor = 16729156,
186
192
  errorOpacity = 0.5
187
193
  } = options;
@@ -242,14 +248,17 @@ var AssetLoader = class extends THREE.EventDispatcher {
242
248
  loadModel(type, url, isLowRes) {
243
249
  return new Promise((resolve, reject) => {
244
250
  const onProgress = (event) => {
245
- const percentage = event.loaded / event.total * 100;
251
+ let percentage = -1;
252
+ if (event.lengthComputable && event.total > 0 && event.loaded <= event.total) {
253
+ percentage = event.loaded / event.total * 100;
254
+ }
246
255
  this.dispatchEvent({
247
256
  type: "progress",
248
257
  loaded: event.loaded,
249
258
  total: event.total,
250
259
  percentage
251
260
  });
252
- if (!isLowRes) {
261
+ if (!isLowRes && percentage >= 0) {
253
262
  this.updatePlaceholder(percentage / 100);
254
263
  }
255
264
  };
@@ -291,6 +300,18 @@ var AssetLoader = class extends THREE.EventDispatcher {
291
300
  onError
292
301
  );
293
302
  break;
303
+ case "usd":
304
+ case "usdz":
305
+ this.usdLoader.load(
306
+ url,
307
+ (usd) => {
308
+ this.positionAssetAtBottomCenter(usd);
309
+ resolve(usd);
310
+ },
311
+ onProgress,
312
+ onError
313
+ );
314
+ break;
294
315
  default:
295
316
  reject(new Error(`Unsupported asset type: ${type}`));
296
317
  }
@@ -337,4 +358,3 @@ var AssetLoader = class extends THREE.EventDispatcher {
337
358
  export {
338
359
  AssetLoader
339
360
  };
340
- //# sourceMappingURL=chunk-L4VIIJZD.mjs.map
@@ -161,4 +161,3 @@ var InfiniteGrid = class extends THREE.Object3D {
161
161
  export {
162
162
  InfiniteGrid
163
163
  };
164
- //# sourceMappingURL=chunk-EQDOX34V.mjs.map
@@ -384,4 +384,3 @@ var TerrainTool = class extends THREE.EventDispatcher {
384
384
  export {
385
385
  TerrainTool
386
386
  };
387
- //# sourceMappingURL=chunk-EIROAPF7.mjs.map
@@ -397,4 +397,3 @@ var ViewHelper = class extends THREE.EventDispatcher {
397
397
  export {
398
398
  ViewHelper
399
399
  };
400
- //# sourceMappingURL=chunk-VETFQ3IQ.mjs.map
@@ -1158,4 +1158,3 @@ export {
1158
1158
  SnapMode,
1159
1159
  MeasurementTool
1160
1160
  };
1161
- //# sourceMappingURL=chunk-5DP6WDB3.mjs.map
@@ -402,4 +402,3 @@ var SunLightTool = class extends THREE.EventDispatcher {
402
402
  export {
403
403
  SunLightTool
404
404
  };
405
- //# sourceMappingURL=chunk-IIAZ2WJJ.mjs.map
@@ -64,6 +64,7 @@ var DualCameraControls = class extends CameraControls {
64
64
  const initialCamera = initialMode === "orthographic" ? orthographicCamera : perspectiveCamera;
65
65
  super(initialCamera, domElement);
66
66
  this.updateClock = new THREE.Clock();
67
+ this.externalCamera = null;
67
68
  const initialTarget = toVector3(
68
69
  options.initialTarget,
69
70
  [0, 0, 0],
@@ -99,9 +100,10 @@ var DualCameraControls = class extends CameraControls {
99
100
  * Switch to the perspective camera while keeping the current framing.
100
101
  */
101
102
  switchToPerspective(enableTransition = false) {
102
- if (this.activeMode === "perspective") {
103
+ if (this.activeMode === "perspective" && !this.externalCamera) {
103
104
  return;
104
105
  }
106
+ this.externalCamera = null;
105
107
  const target = this.getTarget(tempVec3A);
106
108
  const position = this.getPosition(tempVec3B);
107
109
  const aspect = resolveAspect(this.renderer, this.domElementRef);
@@ -133,9 +135,10 @@ var DualCameraControls = class extends CameraControls {
133
135
  * Switch to the orthographic camera while keeping the current framing.
134
136
  */
135
137
  switchToOrthographic(enableTransition = false) {
136
- if (this.activeMode === "orthographic") {
138
+ if (this.activeMode === "orthographic" && !this.externalCamera) {
137
139
  return;
138
140
  }
141
+ this.externalCamera = null;
139
142
  const target = this.getTarget(tempVec3A);
140
143
  const position = this.getPosition(tempVec3B);
141
144
  const aspect = resolveAspect(this.renderer, this.domElementRef);
@@ -173,6 +176,92 @@ var DualCameraControls = class extends CameraControls {
173
176
  this.switchToPerspective(enableTransition);
174
177
  }
175
178
  }
179
+ /**
180
+ * Returns true if currently using an external camera.
181
+ */
182
+ get isUsingExternalCamera() {
183
+ return this.externalCamera !== null;
184
+ }
185
+ /**
186
+ * Sets an external camera to use with the controls.
187
+ * This allows using a camera created outside of DualCameraControls.
188
+ * Call `clearExternalCamera()` to return to the internal cameras.
189
+ */
190
+ setCamera(camera, target, enableTransition = false) {
191
+ const previousCamera = this.camera;
192
+ this.externalCamera = camera;
193
+ const aspect = resolveAspect(this.renderer, this.domElementRef);
194
+ if (camera.type === "PerspectiveCamera") {
195
+ ;
196
+ camera.aspect = aspect;
197
+ camera.updateProjectionMatrix();
198
+ } else if (camera.type === "OrthographicCamera") {
199
+ const ortho = camera;
200
+ const currentHeight = (ortho.top - ortho.bottom) * 0.5;
201
+ const newHalfWidth = currentHeight * aspect;
202
+ ortho.left = -newHalfWidth;
203
+ ortho.right = newHalfWidth;
204
+ ortho.updateProjectionMatrix();
205
+ }
206
+ this.camera = camera;
207
+ const mode = camera.type === "PerspectiveCamera" ? "perspective" : "orthographic";
208
+ this.activeMode = mode;
209
+ this.updateInputBindingsForMode(mode);
210
+ const targetVec = toVector3(target, [0, 0, 0], tempVec3A);
211
+ void this.setLookAt(
212
+ camera.position.x,
213
+ camera.position.y,
214
+ camera.position.z,
215
+ targetVec.x,
216
+ targetVec.y,
217
+ targetVec.z,
218
+ enableTransition
219
+ );
220
+ this.dispatchEvent({
221
+ type: "externalcamerachange",
222
+ camera,
223
+ previousCamera
224
+ });
225
+ }
226
+ /**
227
+ * Clears the external camera and returns to using the internal cameras.
228
+ * Will switch to the camera matching the current mode.
229
+ */
230
+ clearExternalCamera(enableTransition = false) {
231
+ if (!this.externalCamera) {
232
+ return;
233
+ }
234
+ const target = this.getTarget(tempVec3A);
235
+ const position = this.getPosition(tempVec3B);
236
+ this.externalCamera = null;
237
+ const internalCamera = this.activeMode === "orthographic" ? this.orthographicCamera : this.perspectiveCamera;
238
+ internalCamera.position.copy(position);
239
+ internalCamera.quaternion.copy(this.camera.quaternion);
240
+ internalCamera.up.copy(this.camera.up);
241
+ const aspect = resolveAspect(this.renderer, this.domElementRef);
242
+ if (this.activeMode === "orthographic") {
243
+ this.updateOrthographicFrustum(position, target, aspect);
244
+ } else {
245
+ this.perspectiveCamera.aspect = aspect;
246
+ this.perspectiveCamera.updateProjectionMatrix();
247
+ }
248
+ this.camera = internalCamera;
249
+ void this.setLookAt(
250
+ position.x,
251
+ position.y,
252
+ position.z,
253
+ target.x,
254
+ target.y,
255
+ target.z,
256
+ enableTransition
257
+ );
258
+ this.dispatchEvent({
259
+ type: "modechange",
260
+ mode: this.activeMode,
261
+ previousMode: this.activeMode,
262
+ camera: internalCamera
263
+ });
264
+ }
176
265
  /**
177
266
  * Update camera projection parameters when the viewport size changes.
178
267
  */
@@ -266,4 +355,3 @@ function resolveAspect(renderer, domElement) {
266
355
  export {
267
356
  DualCameraControls
268
357
  };
269
- //# sourceMappingURL=chunk-WMHEIUXE.mjs.map
@@ -1576,4 +1576,3 @@ export {
1576
1576
  TransformControlsGizmo,
1577
1577
  TransformControlsPlane
1578
1578
  };
1579
- //# sourceMappingURL=chunk-BJKSICFA.mjs.map