@needle-tools/engine 4.12.0-beta.2 → 4.12.0-next.58a3049
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.
- package/components.needle.json +1 -1
- package/dist/{gltf-progressive-Rs-ojtXy.umd.cjs → gltf-progressive-Bfpfaz84.umd.cjs} +1 -1
- package/dist/{gltf-progressive-DnLBuGK5.js → gltf-progressive-DPunMlEM.js} +1 -1
- package/dist/{gltf-progressive-BmSygnAC.min.js → gltf-progressive-hFPACYio.min.js} +1 -1
- package/dist/{needle-engine.bundle-DKrAL5Vo.min.js → needle-engine.bundle-B0kv56HS.min.js} +145 -144
- package/dist/{needle-engine.bundle-CG9VEmXC.umd.cjs → needle-engine.bundle-BmK_kKrT.umd.cjs} +142 -141
- package/dist/{needle-engine.bundle-CO2y_WSU.js → needle-engine.bundle-Dxc1qRsY.js} +8187 -8002
- package/dist/needle-engine.d.ts +12 -5
- package/dist/needle-engine.js +47 -47
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{postprocessing-DZtb9Nnn.umd.cjs → postprocessing-BHQvwehB.umd.cjs} +1 -1
- package/dist/{postprocessing-B5ksn9-G.min.js → postprocessing-ClLv0reO.min.js} +1 -1
- package/dist/{postprocessing-__7s9wON.js → postprocessing-DLI2N3LL.js} +1 -1
- package/dist/{three-examples-y2GeYlze.js → three-examples-D4rE49Ui.js} +10 -2
- package/dist/{three-examples-MsJjauyk.min.js → three-examples-DB5Uoja4.min.js} +2 -2
- package/dist/{three-examples-Dho7cuu4.umd.cjs → three-examples-Djbk6WA4.umd.cjs} +2 -2
- package/lib/engine/debug/debug_console.js +1 -1
- package/lib/engine/debug/debug_console.js.map +1 -1
- package/lib/engine/engine_context.js +2 -0
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_license.d.ts +18 -0
- package/lib/engine/engine_license.js +160 -9
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_networking.js +15 -0
- package/lib/engine/engine_networking.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.js +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
- package/lib/engine/engine_three_utils.js +2 -2
- package/lib/engine/engine_three_utils.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -1
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +2 -0
- package/lib/engine/webcomponents/needle menu/needle-menu.js +33 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.js +49 -8
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine-components/Camera.js +4 -1
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/DragControls.js +1 -1
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/DropListener.d.ts +1 -0
- package/lib/engine-components/DropListener.js +26 -8
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/EventList.js +4 -1
- package/lib/engine-components/EventList.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.d.ts +3 -2
- package/lib/engine-components/SceneSwitcher.js +20 -11
- package/lib/engine-components/SceneSwitcher.js.map +1 -1
- package/lib/engine-components/SpectatorCamera.js +1 -1
- package/lib/engine-components/SpectatorCamera.js.map +1 -1
- package/lib/engine-components/api.d.ts +1 -1
- package/lib/engine-components/api.js +1 -1
- package/lib/engine-components/api.js.map +1 -1
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +8 -0
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js.map +1 -1
- package/lib/engine-components/webxr/Avatar.js +1 -1
- package/lib/engine-components/webxr/Avatar.js.map +1 -1
- package/lib/engine-components/webxr/WebARSessionRoot.d.ts +5 -2
- package/lib/engine-components/webxr/WebARSessionRoot.js +5 -2
- package/lib/engine-components/webxr/WebARSessionRoot.js.map +1 -1
- package/lib/engine-components/webxr/WebXR.d.ts +3 -1
- package/lib/engine-components/webxr/WebXR.js +3 -1
- package/lib/engine-components/webxr/WebXR.js.map +1 -1
- package/package.json +3 -3
- package/src/engine/debug/debug_console.ts +1 -1
- package/src/engine/engine_context.ts +2 -0
- package/src/engine/engine_license.ts +176 -9
- package/src/engine/engine_networking.ts +15 -0
- package/src/engine/engine_serialization_builtin_serializer.ts +1 -1
- package/src/engine/engine_three_utils.ts +4 -2
- package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -1
- package/src/engine/webcomponents/needle menu/needle-menu.ts +35 -2
- package/src/engine/xr/NeedleXRSession.ts +56 -11
- package/src/engine-components/Camera.ts +4 -1
- package/src/engine-components/DragControls.ts +1 -1
- package/src/engine-components/DropListener.ts +29 -8
- package/src/engine-components/EventList.ts +5 -1
- package/src/engine-components/SceneSwitcher.ts +23 -13
- package/src/engine-components/SpectatorCamera.ts +1 -1
- package/src/engine-components/api.ts +1 -1
- package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +11 -0
- package/src/engine-components/webxr/Avatar.ts +1 -1
- package/src/engine-components/webxr/WebARSessionRoot.ts +7 -3
- package/src/engine-components/webxr/WebXR.ts +4 -2
|
@@ -6,6 +6,7 @@ import { Context, FrameEvent } from "../engine_context.js";
|
|
|
6
6
|
import { ContextEvent, ContextRegistry } from "../engine_context_registry.js";
|
|
7
7
|
import { isDestroyed } from "../engine_gameobject.js";
|
|
8
8
|
import { Gizmos } from "../engine_gizmos.js";
|
|
9
|
+
import { Telemetry } from "../engine_license.js";
|
|
9
10
|
import { registerFrameEventCallback, unregisterFrameEventCallback } from "../engine_lifecycle_functions_internal.js";
|
|
10
11
|
import { getBoundingBox, getTempQuaternion, getTempVector, getWorldPosition, getWorldQuaternion, getWorldScale, setWorldPosition, setWorldQuaternion, setWorldScale } from "../engine_three_utils.js";
|
|
11
12
|
import type { ICamera, IComponent, INeedleXRSession } from "../engine_types.js";
|
|
@@ -98,12 +99,12 @@ async function handleSessionGranted() {
|
|
|
98
99
|
}
|
|
99
100
|
// Check if AR is supported, otherwise we can't do anything
|
|
100
101
|
if (!(await navigator.xr?.isSessionSupported("immersive-ar")) && defaultMode === "immersive-ar") {
|
|
101
|
-
console.warn("[NeedleXRSession:granted] Neither VR nor AR supported, aborting session start.");
|
|
102
|
+
// console.warn("[NeedleXRSession:granted] Neither VR nor AR supported, aborting session start.");
|
|
102
103
|
// showBalloonMessage("NeidleXRSession: Neither VR nor AR supported, aborting session start.");
|
|
103
104
|
return;
|
|
104
105
|
}
|
|
105
106
|
} catch (e) {
|
|
106
|
-
console.
|
|
107
|
+
console.debug("[NeedleXRSession:granted] Error while checking XR support:", e);
|
|
107
108
|
// showBalloonWarning("NeedleXRSession: Error while checking XR support: " + (e as Error).message);
|
|
108
109
|
return;
|
|
109
110
|
}
|
|
@@ -148,6 +149,7 @@ async function handleSessionGranted() {
|
|
|
148
149
|
navigator.xr?.addEventListener('sessiongranted', async () => {
|
|
149
150
|
// enableSpatialConsole(true);
|
|
150
151
|
|
|
152
|
+
|
|
151
153
|
const lastSessionMode = sessionStorage.getItem("needle_xr_session_mode") as XRSessionMode;
|
|
152
154
|
const lastSessionInit = sessionStorage.getItem("needle_xr_session_init") ?? null;
|
|
153
155
|
const init = lastSessionInit ? JSON.parse(lastSessionInit) : null;
|
|
@@ -459,24 +461,55 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
459
461
|
if (DeviceUtilities.isiOS()) {
|
|
460
462
|
|
|
461
463
|
const arSupported = await this.isARSupported().catch(() => false);
|
|
462
|
-
|
|
464
|
+
|
|
463
465
|
// On VisionOS, we use QuickLook for AR experiences; no AppClip support for now.
|
|
464
466
|
if (DeviceUtilities.isVisionOS() && !arSupported && (mode === "ar" || mode === "immersive-ar")) {
|
|
465
467
|
mode = "quicklook";
|
|
466
468
|
}
|
|
467
469
|
|
|
468
470
|
if (mode === "quicklook") {
|
|
471
|
+
Telemetry.sendEvent(Context.Current, "xr", {
|
|
472
|
+
action: "quicklook_export",
|
|
473
|
+
source: "NeedleXRSession.start",
|
|
474
|
+
});
|
|
469
475
|
InternalUSDZRegistry.exportAndOpen();
|
|
470
476
|
return null;
|
|
471
477
|
}
|
|
472
|
-
|
|
478
|
+
|
|
473
479
|
if (!arSupported && (mode === "immersive-ar" || mode === "ar")) {
|
|
474
|
-
//
|
|
475
|
-
//
|
|
476
|
-
const url =`https://appclip.needle.tools/ar?url=${
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
+
// const debugAppClip = getParam("debugappclip")
|
|
481
|
+
// Forward to the AppClip experience (Using the apple.com url the appclip overlay shows immediately)
|
|
482
|
+
// const url =`https://appclip.needle.tools/ar?url=${(location.href)}`;
|
|
483
|
+
const url = new URL("https://appclip.apple.com/id?p=tools.needle.launch-app.Clip");
|
|
484
|
+
url.searchParams.set("url", location.href);
|
|
485
|
+
|
|
486
|
+
const urlStr = url.toString();
|
|
487
|
+
|
|
488
|
+
Telemetry.sendEvent(Context.Current, "xr", {
|
|
489
|
+
action: "app_clip_launch",
|
|
490
|
+
source: "NeedleXRSession.start",
|
|
491
|
+
url: urlStr,
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
// if we are in an iframe, we need to navigate the top window
|
|
495
|
+
const topWindow = window.top || window;
|
|
496
|
+
try {
|
|
497
|
+
console.debug("iOS device detected - opening Needle App Clip for AR experience", { mode, init, url });
|
|
498
|
+
// navigate to app clip url but keep the current url in history, open in same tab
|
|
499
|
+
// eslint-disable-next-line xss/no-location-href-assign
|
|
500
|
+
topWindow.location.href = urlStr;
|
|
501
|
+
}
|
|
502
|
+
catch (e) {
|
|
503
|
+
console.warn("Error navigating to AppClip " + urlStr + "\n", e);
|
|
504
|
+
// if top window navigation fails and we are in an iframe, we try to navigate the top window directly
|
|
505
|
+
const weAreInIframe = window !== window.top;
|
|
506
|
+
if (weAreInIframe) {
|
|
507
|
+
// we can try to open a new tab as a fallback
|
|
508
|
+
window.open(urlStr, "_blank");
|
|
509
|
+
}
|
|
510
|
+
// eslint-disable-next-line xss/no-location-href-assign
|
|
511
|
+
else window.location.href = urlStr;
|
|
512
|
+
}
|
|
480
513
|
|
|
481
514
|
return null;
|
|
482
515
|
}
|
|
@@ -486,7 +519,7 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
486
519
|
console.warn("QuickLook mode is only supported on iOS devices");
|
|
487
520
|
return null;
|
|
488
521
|
}
|
|
489
|
-
|
|
522
|
+
|
|
490
523
|
// Since we now know we are not on iOS, ar mode becomes "immersive-ar"
|
|
491
524
|
if (mode == "ar") {
|
|
492
525
|
mode = "immersive-ar";
|
|
@@ -586,6 +619,12 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
586
619
|
listener({ mode, init });
|
|
587
620
|
}
|
|
588
621
|
if (debug) showBalloonMessage("Requesting " + mode + " session (" + Date.now() + ")");
|
|
622
|
+
Telemetry.sendEvent(Context.Current, "xr", {
|
|
623
|
+
action: "session_request",
|
|
624
|
+
mode: mode,
|
|
625
|
+
features: ((init.requiredFeatures ?? []).concat(init.optionalFeatures ?? [])).join(","),
|
|
626
|
+
source: "NeedleXRSession.start",
|
|
627
|
+
});
|
|
589
628
|
this._currentSessionRequest = navigator?.xr?.requestSession(mode, init);
|
|
590
629
|
this._currentSessionRequestMode = mode;
|
|
591
630
|
/**@type {XRSystem} */
|
|
@@ -1162,6 +1201,12 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1162
1201
|
|
|
1163
1202
|
console.debug("XR Session ended");
|
|
1164
1203
|
|
|
1204
|
+
Telemetry.sendEvent(Context.Current, "xr", {
|
|
1205
|
+
action: "session_end",
|
|
1206
|
+
mode: this.mode,
|
|
1207
|
+
source: "NeedleXRSession.onEnd",
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1165
1210
|
deleteSessionInfo();
|
|
1166
1211
|
|
|
1167
1212
|
this.onAfterRender();
|
|
@@ -8,7 +8,7 @@ import { Context } from "../engine/engine_setup.js";
|
|
|
8
8
|
import { RenderTexture } from "../engine/engine_texture.js";
|
|
9
9
|
import { getTempColor, getWorldPosition } from "../engine/engine_three_utils.js";
|
|
10
10
|
import type { ICamera } from "../engine/engine_types.js"
|
|
11
|
-
import { getParam } from "../engine/engine_utils.js";
|
|
11
|
+
import { DeviceUtilities, getParam } from "../engine/engine_utils.js";
|
|
12
12
|
import { NeedleXREventArgs } from "../engine/engine_xr.js";
|
|
13
13
|
import { RGBAColor } from "../engine/js-extensions/index.js";
|
|
14
14
|
import { Behaviour, GameObject } from "./Component.js";
|
|
@@ -664,6 +664,9 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
664
664
|
else if (navigator.userAgent?.includes("Mozilla") && navigator.userAgent?.includes("Mobile WebXRViewer/v2")) {
|
|
665
665
|
transparent = true;
|
|
666
666
|
}
|
|
667
|
+
else if(DeviceUtilities.isNeedleAppClip()) {
|
|
668
|
+
return true;
|
|
669
|
+
}
|
|
667
670
|
}
|
|
668
671
|
}
|
|
669
672
|
|
|
@@ -447,7 +447,7 @@ export class DragControls extends Behaviour implements IPointerEventHandler {
|
|
|
447
447
|
if (!this || !this._isDragging) return;
|
|
448
448
|
this._isDragging = false;
|
|
449
449
|
for (const rb of this._draggingRigidbodies) {
|
|
450
|
-
rb.setVelocity(rb.smoothedVelocity);
|
|
450
|
+
rb.setVelocity(rb.smoothedVelocity.multiplyScalar(this.context.time.deltaTime));
|
|
451
451
|
}
|
|
452
452
|
this._draggingRigidbodies.length = 0;
|
|
453
453
|
this._targetObject = null;
|
|
@@ -10,7 +10,7 @@ import { BlobStorage } from "../engine/engine_networking_blob.js";
|
|
|
10
10
|
import { PreviewHelper } from "../engine/engine_networking_files.js";
|
|
11
11
|
import { InstantiateIdProvider } from "../engine/engine_networking_instantiate.js";
|
|
12
12
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
13
|
-
import { fitObjectIntoVolume, getBoundingBox, placeOnSurface } from "../engine/engine_three_utils.js";
|
|
13
|
+
import { fitObjectIntoVolume, getBoundingBox, getWorldScale, placeOnSurface } from "../engine/engine_three_utils.js";
|
|
14
14
|
import { Model, Vec3 } from "../engine/engine_types.js";
|
|
15
15
|
import { getParam, setParamWithoutReload } from "../engine/engine_utils.js";
|
|
16
16
|
import { determineMimeTypeFromExtension } from "../engine/engine_utils_format.js";
|
|
@@ -111,6 +111,7 @@ const blobKeyName = "blob";
|
|
|
111
111
|
|
|
112
112
|
/** The DropListener component is used to listen for drag and drop events in the browser and add the dropped files to the scene
|
|
113
113
|
* It can be used to allow users to drag and drop glTF files into the scene to add new objects.
|
|
114
|
+
* Existing child objects will behave like placeholders and will be removed when new files are dropped.
|
|
114
115
|
*
|
|
115
116
|
* If {@link useNetworking} is enabled, the DropListener will automatically synchronize dropped files to other connected clients.
|
|
116
117
|
* Enable {@link fitIntoVolume} to automatically scale dropped objects to fit within the volume defined by {@link fitVolumeSize}.
|
|
@@ -522,22 +523,42 @@ export class DropListener extends Behaviour {
|
|
|
522
523
|
|
|
523
524
|
const obj = model.scene;
|
|
524
525
|
|
|
525
|
-
|
|
526
|
-
this.gameObject
|
|
527
|
-
obj.position.set(0, 0, 0);
|
|
528
|
-
obj.quaternion.identity();
|
|
526
|
+
obj.position.copy(this.gameObject.worldPosition);
|
|
527
|
+
let scale = getWorldScale(this.gameObject);
|
|
529
528
|
|
|
530
|
-
|
|
531
|
-
|
|
529
|
+
let localPos = new Vector3(0,0,0);
|
|
530
|
+
scale.x = Math.abs(scale.x);
|
|
531
|
+
scale.y = Math.abs(scale.y);
|
|
532
|
+
scale.z = Math.abs(scale.z);
|
|
533
|
+
let localScale =obj.scale.clone();
|
|
534
|
+
|
|
535
|
+
// TODOs: handle rotation when Gizmos APIs has changed to support it
|
|
532
536
|
|
|
533
|
-
const volume = new Box3().setFromCenterAndSize(new Vector3(0, this.fitVolumeSize.y * .5, 0).add(this.gameObject.worldPosition), this.fitVolumeSize);
|
|
537
|
+
const volume = new Box3().setFromCenterAndSize(new Vector3(0, this.fitVolumeSize.y * scale.y * .5, 0).add(this.gameObject.worldPosition), this.fitVolumeSize.clone().multiply(scale));
|
|
534
538
|
if (debug) Gizmos.DrawWireBox3(volume, 0x0000ff, 5);
|
|
535
539
|
if (this.fitIntoVolume) {
|
|
540
|
+
|
|
536
541
|
fitObjectIntoVolume(obj, volume, {
|
|
537
542
|
position: !this.placeAtHitPosition
|
|
538
543
|
});
|
|
544
|
+
|
|
545
|
+
// to match parent scale later, divide by it
|
|
546
|
+
localScale = obj.scale.clone().divide(scale);
|
|
547
|
+
// just take the computed offset from fitting
|
|
548
|
+
localPos = obj.worldPosition.clone().sub(this.gameObject.worldPosition).divide(scale);
|
|
549
|
+
if (debug) Gizmos.DrawSphere(localPos, 0.1, 0xff0000, 5);
|
|
539
550
|
}
|
|
540
551
|
|
|
552
|
+
// use attach to ignore the DropListener scale (e.g. if the parent object scale is not uniform)
|
|
553
|
+
this.gameObject.attach(obj);
|
|
554
|
+
obj.position.copy(localPos);
|
|
555
|
+
obj.quaternion.identity();
|
|
556
|
+
obj.scale.copy(localScale);
|
|
557
|
+
if (debug) Gizmos.DrawArrow(this.gameObject.worldPosition, obj.getWorldPosition(new Vector3()), 0x00ff00, 5);
|
|
558
|
+
|
|
559
|
+
this._addedObjects.push(obj);
|
|
560
|
+
this._addedModels.push(model);
|
|
561
|
+
|
|
541
562
|
if (this.placeAtHitPosition && ctx && ctx.screenposition) {
|
|
542
563
|
obj.visible = false; // < don't raycast on the placed object
|
|
543
564
|
const rc = this.context.physics.raycast({ screenPoint: this.context.input.convertScreenspaceToRaycastSpace(ctx.screenposition.clone()) });
|
|
@@ -78,7 +78,11 @@ export class CallInfo {
|
|
|
78
78
|
// If the target is a property
|
|
79
79
|
else {
|
|
80
80
|
if (this.arguments) {
|
|
81
|
-
|
|
81
|
+
|
|
82
|
+
if (args !== undefined && args.length > 0)
|
|
83
|
+
this.target[this.methodName] = args[0];
|
|
84
|
+
else
|
|
85
|
+
this.target[this.methodName] = this.arguments[0];
|
|
82
86
|
}
|
|
83
87
|
else {
|
|
84
88
|
this.target[this.methodName] = args[0];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EquirectangularReflectionMapping, Object3D, Scene, Texture } from "three";
|
|
2
2
|
|
|
3
3
|
import { AssetReference } from "../engine/engine_addressables.js";
|
|
4
|
-
import { destroy } from "../engine/engine_gameobject.js";
|
|
4
|
+
import { destroy, instantiate } from "../engine/engine_gameobject.js";
|
|
5
5
|
import { InputEvents } from "../engine/engine_input.js";
|
|
6
6
|
import { isLocalNetwork } from "../engine/engine_networking_utils.js";
|
|
7
7
|
import { serializable } from "../engine/engine_serialization.js";
|
|
@@ -247,14 +247,23 @@ export class SceneSwitcher extends Behaviour {
|
|
|
247
247
|
|
|
248
248
|
private _currentIndex: number = -1;
|
|
249
249
|
private _currentScene: AssetReference | undefined = undefined;
|
|
250
|
+
private _currentSceneAsset: Object3D | undefined = undefined;
|
|
250
251
|
private _engineElementOverserver: MutationObserver | undefined = undefined;
|
|
251
252
|
|
|
252
253
|
private _preloadScheduler?: PreLoadScheduler;
|
|
253
254
|
|
|
254
255
|
private _menuButtons?: HTMLElement[];
|
|
255
256
|
|
|
257
|
+
// this is the scene that was requested last
|
|
258
|
+
private __lastSwitchScene?: AssetReference;
|
|
259
|
+
private __lastSwitchScenePromise?: Promise<boolean>;
|
|
260
|
+
|
|
256
261
|
/** @internal */
|
|
257
262
|
awake(): void {
|
|
263
|
+
this._currentScene = undefined;
|
|
264
|
+
this._lastLoadingScene = undefined;
|
|
265
|
+
this.__lastSwitchScenePromise = undefined;
|
|
266
|
+
|
|
258
267
|
if (this.scenes === undefined) this.scenes = [];
|
|
259
268
|
// remove all scenes from the url that are in the scenes array at startup
|
|
260
269
|
for (const scene of this.scenes) {
|
|
@@ -538,10 +547,6 @@ export class SceneSwitcher extends Behaviour {
|
|
|
538
547
|
return false;
|
|
539
548
|
}
|
|
540
549
|
|
|
541
|
-
// this is the scene that was requested last
|
|
542
|
-
private __lastSwitchScene?: AssetReference;
|
|
543
|
-
private __lastSwitchScenePromise?: Promise<boolean>;
|
|
544
|
-
|
|
545
550
|
/**
|
|
546
551
|
* Switch to a scene by its AssetReference.
|
|
547
552
|
* If the scene is already loaded it will be unloaded and the new scene will be loaded.
|
|
@@ -601,14 +606,13 @@ export class SceneSwitcher extends Behaviour {
|
|
|
601
606
|
const res = sceneListener.sceneClosing();
|
|
602
607
|
if (res instanceof Promise) await res;
|
|
603
608
|
}
|
|
604
|
-
|
|
605
|
-
//
|
|
609
|
+
|
|
610
|
+
// // if the current scene has a URL (so it can be reloaded)
|
|
611
|
+
// // then we unload it
|
|
606
612
|
if (current.hasUrl)
|
|
607
613
|
current.unload();
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
GameObject.remove(current.asset as any as Object3D);
|
|
611
|
-
}
|
|
614
|
+
|
|
615
|
+
if (this._currentSceneAsset) destroy(this._currentSceneAsset, true, false);
|
|
612
616
|
}
|
|
613
617
|
}
|
|
614
618
|
|
|
@@ -658,7 +662,6 @@ export class SceneSwitcher extends Behaviour {
|
|
|
658
662
|
if (debug) console.log("[SceneSwitcher] ADD", scene.url);
|
|
659
663
|
this._currentScene = scene;
|
|
660
664
|
|
|
661
|
-
|
|
662
665
|
// Experimental: replace the whole content of the scene
|
|
663
666
|
if (experimental_clearSceneOnLoad) {
|
|
664
667
|
const camera = this.context.mainCameraComponent?.gameObject || this.context.mainCamera;
|
|
@@ -672,7 +675,14 @@ export class SceneSwitcher extends Behaviour {
|
|
|
672
675
|
}
|
|
673
676
|
}
|
|
674
677
|
|
|
675
|
-
|
|
678
|
+
// @TODO: if multiple scene switcher or scenes use this asset already it will be moved
|
|
679
|
+
if (!scene.asset.parent) {
|
|
680
|
+
this._currentSceneAsset = scene.asset;
|
|
681
|
+
GameObject.add(scene.asset, this.gameObject);
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
this._currentSceneAsset = instantiate(scene.asset, { parent: this.gameObject });
|
|
685
|
+
}
|
|
676
686
|
|
|
677
687
|
if (this.useSceneLighting)
|
|
678
688
|
this.context.sceneLighting.enable(scene);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Color, Object3D, PerspectiveCamera, Quaternion, Vector3, WebGLState } from "three";
|
|
2
|
-
import { PlayerState } from "../engine-components-experimental/networking/PlayerSync.js";
|
|
3
2
|
|
|
4
3
|
import { InputEvents } from "../engine/engine_input.js";
|
|
5
4
|
import { RoomEvents } from "../engine/engine_networking.js";
|
|
@@ -10,6 +9,7 @@ import { serializable } from "../engine/engine_serialization.js";
|
|
|
10
9
|
import { Context } from "../engine/engine_setup.js";
|
|
11
10
|
import type { ICamera } from "../engine/engine_types.js";
|
|
12
11
|
import { DeviceUtilities, getParam } from "../engine/engine_utils.js";
|
|
12
|
+
import { PlayerState } from "../engine-components-experimental/networking/PlayerSync.js";
|
|
13
13
|
import { Camera } from "./Camera.js";
|
|
14
14
|
import { Behaviour, Component, GameObject } from "./Component.js";
|
|
15
15
|
import { OrbitControls } from "./OrbitControls.js";
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
37
|
export * from "./codegen/components.js";
|
|
38
|
-
export { Behaviour, Component, GameObject } from "./Component.js";
|
|
39
38
|
export { Collider } from "./Collider.js"; // export abstract type
|
|
39
|
+
export { Behaviour, Component, GameObject } from "./Component.js";
|
|
40
40
|
|
|
41
41
|
// We dont want to export everything in the extensions
|
|
42
42
|
export { ClearFlags } from "./Camera.js"
|
|
@@ -11,6 +11,7 @@ import { Animation } from "../../../../Animation.js";
|
|
|
11
11
|
import { Animator } from "../../../../Animator.js";
|
|
12
12
|
import { AudioSource } from "../../../../AudioSource.js";
|
|
13
13
|
import { Behaviour, GameObject } from "../../../../Component.js";
|
|
14
|
+
import { Rigidbody } from "../../../../RigidBody.js";
|
|
14
15
|
import type { IPointerClickHandler, PointerEventData } from "../../../../ui/PointerEvents.js";
|
|
15
16
|
import { ObjectRaycaster,Raycaster } from "../../../../ui/Raycaster.js";
|
|
16
17
|
import { makeNameSafeForUSD,USDDocument, USDObject, USDZExporterContext } from "../../ThreeUSDZExporter.js";
|
|
@@ -68,6 +69,16 @@ export class ChangeTransformOnClick extends Behaviour implements IPointerClickHa
|
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
onPointerClick(args: PointerEventData) {
|
|
72
|
+
|
|
73
|
+
const rbs = this.object?.getComponentsInChildren(Rigidbody);
|
|
74
|
+
|
|
75
|
+
if (rbs){
|
|
76
|
+
for (const rb of rbs) {
|
|
77
|
+
rb.resetVelocities();
|
|
78
|
+
rb.resetForcesAndTorques();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
71
82
|
args.use();
|
|
72
83
|
if (this.coroutine) this.stopCoroutine(this.coroutine);
|
|
73
84
|
if (!this.relativeMotion)
|
|
@@ -2,6 +2,7 @@ import { Mesh, Object3D, Quaternion, Vector3 } from "three";
|
|
|
2
2
|
|
|
3
3
|
import { AssetReference } from "../../engine/engine_addressables.js";
|
|
4
4
|
import { ObjectUtils, PrimitiveType } from "../../engine/engine_create_objects.js";
|
|
5
|
+
import { ViewDevice } from "../../engine/engine_playerview.js";
|
|
5
6
|
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
|
6
7
|
import type { IGameObject } from "../../engine/engine_types.js";
|
|
7
8
|
import { getParam, PromiseAllWithErrors } from "../../engine/engine_utils.js";
|
|
@@ -12,7 +13,6 @@ import { Behaviour, GameObject } from "../Component.js";
|
|
|
12
13
|
import { SyncedTransform } from "../SyncedTransform.js";
|
|
13
14
|
import { AvatarMarker } from "./WebXRAvatar.js";
|
|
14
15
|
import { XRFlag } from "./XRFlag.js";
|
|
15
|
-
import { ViewDevice } from "../../engine/engine_playerview.js";
|
|
16
16
|
|
|
17
17
|
const debug = getParam("debugwebxr");
|
|
18
18
|
|
|
@@ -10,6 +10,7 @@ import type { IComponent, IGameObject } from "../../engine/engine_types.js";
|
|
|
10
10
|
import { DeviceUtilities, getParam } from "../../engine/engine_utils.js";
|
|
11
11
|
import { NeedleXRController, type NeedleXREventArgs, type NeedleXRHitTestResult, NeedleXRSession } from "../../engine/engine_xr.js";
|
|
12
12
|
import { Behaviour, GameObject } from "../Component.js";
|
|
13
|
+
import type { WebXR } from "./WebXR.js";
|
|
13
14
|
|
|
14
15
|
// https://github.com/takahirox/takahirox.github.io/blob/master/js.mmdeditor/examples/js/controls/DeviceOrientationControls.js
|
|
15
16
|
|
|
@@ -20,14 +21,17 @@ const invertForwardMatrix = new Matrix4().makeRotationY(Math.PI);
|
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* The WebARSessionRoot is the root object for a WebAR session and used to place the scene in AR.
|
|
23
|
-
* It is also responsible for scaling the user in AR and to define the center of the AR scene.
|
|
24
|
+
* It is also responsible for scaling the user in AR and to define the center of the AR scene.
|
|
25
|
+
* If not present in the scene it will be created automatically by the WebXR component when entering an AR session.
|
|
24
26
|
*
|
|
25
|
-
* @
|
|
27
|
+
* **Note**: If the WebXR component {@link WebXR.autoCenter} option is enabled the scene will be automatically centered based on the content in the scene.
|
|
28
|
+
*
|
|
29
|
+
* @example Callback when the scene has been placed in AR:
|
|
26
30
|
* ```ts
|
|
27
31
|
* WebARSessionRoot.onPlaced((args) => {
|
|
28
32
|
* console.log("Scene has been placed in AR");
|
|
29
33
|
* });
|
|
30
|
-
* ```
|
|
34
|
+
* ```
|
|
31
35
|
*
|
|
32
36
|
* @summary Root object for WebAR sessions, managing scene placement and user scaling in AR.
|
|
33
37
|
* @category XR
|
|
@@ -23,7 +23,7 @@ const debug = getParam("debugwebxr");
|
|
|
23
23
|
const debugQuicklook = getParam("debugusdz");
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Use the WebXR component to enable VR
|
|
26
|
+
* Use the WebXR component to enable VR and AR on iOS and Android in your scene. VisionOS support is also provided via QuickLook USDZ export.
|
|
27
27
|
*
|
|
28
28
|
* The WebXR component is a simple to use wrapper around the {@link NeedleXRSession} API and adds some additional features like creating buttons for AR, VR, enabling default movement behaviour ({@link XRControllerMovement}) and controller rendering ({@link XRControllerModel}), as well as handling AR placement and Quicklook USDZ export.
|
|
29
29
|
*
|
|
@@ -146,7 +146,9 @@ export class WebXR extends Behaviour {
|
|
|
146
146
|
|
|
147
147
|
/**
|
|
148
148
|
* When enabled, the AR session root center will be automatically adjusted to place the center of the scene.
|
|
149
|
-
* This helps ensure the scene is properly aligned with detected surfaces.
|
|
149
|
+
* This helps ensure the scene is properly aligned with detected surfaces.
|
|
150
|
+
*
|
|
151
|
+
* **Note**: This option overrides the placement of the {@link WebARSessionRoot} component if both are used.
|
|
150
152
|
*/
|
|
151
153
|
@serializable()
|
|
152
154
|
autoCenter: boolean = false;
|