@@ -52,11 +52,13 @@
|
|
52
52
|
}
|
53
53
|
}, false);
|
54
54
|
});
|
55
|
+
if (debug) console.log("onBeforeBuildDocument: all components", this.behaviourComponents);
|
55
56
|
return Promise.all(beforeCreateDocumentPromises);
|
56
57
|
}
|
57
58
|
|
58
59
|
onExportObject(_object, model: USDObject, context) {
|
59
60
|
for (const beh of this.behaviourComponents) {
|
61
|
+
if (debug) console.log("onExportObject: createBehaviours", beh);
|
60
62
|
beh.createBehaviours?.call(beh, this, model, context);
|
61
63
|
}
|
62
64
|
}
|
@@ -12,7 +12,7 @@
|
|
12
12
|
import { Behaviour, GameObject } from "../../../../Component.js";
|
13
13
|
import type { IPointerClickHandler, PointerEventData } from "../../../../ui/PointerEvents.js";
|
14
14
|
import { ObjectRaycaster,Raycaster } from "../../../../ui/Raycaster.js";
|
15
|
-
import { makeNameSafeForUSD,USDDocument, USDObject, USDZExporterContext } from "../../ThreeUSDZExporter.js";
|
15
|
+
import { makeNameSafeForUSD,USDDocument, USDObject, USDWriter, USDZExporterContext } from "../../ThreeUSDZExporter.js";
|
16
16
|
import { AnimationExtension, RegisteredAnimationInfo, type UsdzAnimation } from "../Animation.js";
|
17
17
|
import { AudioExtension } from "./AudioExtension.js";
|
18
18
|
import type { BehaviorExtension, UsdzBehaviour } from "./Behaviour.js";
|
@@ -521,6 +521,23 @@
|
|
521
521
|
));
|
522
522
|
}
|
523
523
|
|
524
|
+
// add InputTargetComponent for VisionOS direct/indirect interactions
|
525
|
+
const addInputTargetComponent = (model: USDObject) => {
|
526
|
+
const empty = USDObject.createEmpty();
|
527
|
+
empty.name = "InputTarget";
|
528
|
+
empty.displayName = undefined;
|
529
|
+
empty.type = "RealityKitComponent";
|
530
|
+
empty.onSerialize = (writer: USDWriter) => {
|
531
|
+
writer.appendLine("bool allowsDirectInput = 1");
|
532
|
+
writer.appendLine("bool allowsIndirectInput = 1");
|
533
|
+
writer.appendLine('uniform token info:id = "RealityKit.InputTarget"');
|
534
|
+
};
|
535
|
+
model.add(empty);
|
536
|
+
}
|
537
|
+
|
538
|
+
addInputTargetComponent(selfModel);
|
539
|
+
if (this.toggleModel) addInputTargetComponent(this.toggleModel);
|
540
|
+
|
524
541
|
// Ensure initial states are set correctly so that we get the same result as was currently active in the runtime
|
525
542
|
const objectsToHide = new Array<USDObject>();
|
526
543
|
if (!this.targetStateBeforeCreatingDocument)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Object3D } from "three";
|
1
|
+
import { Object3D, Vector3 } from "three";
|
2
2
|
|
3
3
|
import { EnumToPrimitiveUnion, getParam } from "../../../../../engine/engine_utils.js";
|
4
4
|
import { makeNameSafeForUSD,USDDocument, USDObject, USDWriter } from "../../ThreeUSDZExporter.js";
|
@@ -47,9 +47,9 @@
|
|
47
47
|
else
|
48
48
|
triggerString = `<${this.trigger.id}>`;
|
49
49
|
|
50
|
-
writer.appendLine(`rel triggers = ${triggerString}
|
50
|
+
writer.appendLine(`rel triggers = ${triggerString}`);
|
51
51
|
writer.appendLine(`rel actions = <${this.action.id}>`);
|
52
|
-
writer.appendLine(`uniform bool exclusive = ${this.exclusive}`);
|
52
|
+
writer.appendLine(`uniform bool exclusive = ${this.exclusive ? 1 : 0}`); // Apple uses 0 and 1 for bools
|
53
53
|
writer.appendLine();
|
54
54
|
if (Array.isArray(this.trigger)) {
|
55
55
|
for (const trigger of this.trigger) {
|
@@ -218,8 +218,8 @@
|
|
218
218
|
writer.appendLine();
|
219
219
|
|
220
220
|
writer.appendLine(`token info:id = "Group"`);
|
221
|
-
writer.appendLine(`bool loops = ${this.loops
|
222
|
-
writer.appendLine(`int performCount = ${Math.max(0, this.performCount)}
|
221
|
+
writer.appendLine(`bool loops = ${this.loops}`);
|
222
|
+
writer.appendLine(`int performCount = ${this.loops > 0 ? 0 : Math.max(0, this.performCount)}`);
|
223
223
|
writer.appendLine(`token type = "${this.type}"`);
|
224
224
|
writer.appendLine();
|
225
225
|
|
@@ -260,7 +260,7 @@
|
|
260
260
|
tokenId?: string;
|
261
261
|
affectedObjects?: string | Target;
|
262
262
|
easeType?: EaseType;;
|
263
|
-
motionType: EmphasizeActionMotionType | VisibilityActionMotionType =
|
263
|
+
motionType: EmphasizeActionMotionType | VisibilityActionMotionType | undefined = undefined;
|
264
264
|
duration?: number;
|
265
265
|
moveDistance?: number;
|
266
266
|
style?: MotionStyle;
|
@@ -276,6 +276,7 @@
|
|
276
276
|
gain?: number;
|
277
277
|
auralMode?: AuralMode;
|
278
278
|
multiplePerformOperation?: MultiplePerformOperation;
|
279
|
+
velocity?: Vec3;
|
279
280
|
|
280
281
|
clone(): ActionModel {
|
281
282
|
const copy = new ActionModel();
|
@@ -309,7 +310,10 @@
|
|
309
310
|
writer.appendLine(`token easeType = "${this.easeType}"`);
|
310
311
|
if (this.tokenId)
|
311
312
|
writer.appendLine(`token info:id = "${this.tokenId}"`);
|
312
|
-
|
313
|
+
if (this.tokenId === "ChangeScene")
|
314
|
+
writer.appendLine(`rel scene = </StageRoot/Scenes/Scene>`);
|
315
|
+
if (this.motionType !== undefined)
|
316
|
+
writer.appendLine(`token motionType = "${this.motionType}"`);
|
313
317
|
if (typeof this.moveDistance === "number")
|
314
318
|
writer.appendLine(`double moveDistance = ${this.moveDistance} `);
|
315
319
|
if (this.style)
|
@@ -349,6 +353,9 @@
|
|
349
353
|
if (typeof this.multiplePerformOperation === "string") {
|
350
354
|
writer.appendLine(`token multiplePerformOperation = "${this.multiplePerformOperation}"`);
|
351
355
|
}
|
356
|
+
if (typeof this.velocity === "object") {
|
357
|
+
writer.appendLine(`vector3d velocity = (${this.velocity.x}, ${this.velocity.y}, ${this.velocity.z})`);
|
358
|
+
}
|
352
359
|
writer.closeBlock();
|
353
360
|
}
|
354
361
|
}
|
@@ -452,6 +459,7 @@
|
|
452
459
|
const act = new ActionModel();
|
453
460
|
act.tokenId = "Wait";
|
454
461
|
act.duration = duration;
|
462
|
+
act.motionType = undefined;
|
455
463
|
return act;
|
456
464
|
}
|
457
465
|
|
@@ -480,6 +488,8 @@
|
|
480
488
|
const act = new ActionModel(targets);
|
481
489
|
act.tokenId = "Transform";
|
482
490
|
act.duration = duration;
|
491
|
+
// Workaround for a bug in QuickLook: if duration is 0, loops stop somewhat randomly. FB13759712
|
492
|
+
act.duration = Math.max(0.000001, duration);
|
483
493
|
act.type = transformType;
|
484
494
|
act.easeType = duration > 0 ? easeType : "none";
|
485
495
|
if (Array.isArray(transformTarget)) {
|
@@ -500,6 +510,23 @@
|
|
500
510
|
return act;
|
501
511
|
}
|
502
512
|
|
513
|
+
// Supported only on VisionOS, Preliminary Behaviours can affect RealityKit physics as well
|
514
|
+
static impulseAction(targets: Target, velocity: Vec3) {
|
515
|
+
const act = new ActionModel(targets);
|
516
|
+
act.tokenId = "Impulse";
|
517
|
+
act.velocity = velocity;
|
518
|
+
return act;
|
519
|
+
}
|
520
|
+
|
521
|
+
// Currently doesn't work on VisionOS, see FB13761990
|
522
|
+
/*
|
523
|
+
static reloadSceneAction() {
|
524
|
+
const act = new ActionModel();
|
525
|
+
act.tokenId = "ChangeScene";
|
526
|
+
// rel scene = ... is implicit since we only allow one scene right now
|
527
|
+
return act;
|
528
|
+
}
|
529
|
+
*/
|
503
530
|
}
|
504
531
|
|
505
532
|
export { Vec3 as USDVec3 }
|
@@ -1,4 +1,6 @@
|
|
1
1
|
import { isDevEnvironment } from "./debug/index.js";
|
2
|
+
import { RoomEvents } from "./engine_networking.js";
|
3
|
+
import { INetworkConnection, SendQueue } from "./engine_networking_types.js";
|
2
4
|
import type { IComponent } from "./engine_types.js";
|
3
5
|
import { getParam } from "./engine_utils.js";
|
4
6
|
|
@@ -40,8 +42,6 @@
|
|
40
42
|
private changedProperties: { [key: string]: any } = {};
|
41
43
|
private data = {};
|
42
44
|
|
43
|
-
private _boundEvent?: Function;
|
44
|
-
private _handleReceivingMethod?: Function;
|
45
45
|
|
46
46
|
get networkingKey(): string {
|
47
47
|
return this.comp.guid;
|
@@ -57,10 +57,8 @@
|
|
57
57
|
this._isInit = true;
|
58
58
|
this.comp = comp;
|
59
59
|
// console.log("INIT", this.comp.name, this.networkingKey);
|
60
|
-
this.
|
61
|
-
this.comp.context.
|
62
|
-
this._handleReceivingMethod = this.onHandleReceiving.bind(this);
|
63
|
-
this.comp.context.connection.beginListen(this.networkingKey, this._handleReceivingMethod);
|
60
|
+
this.comp.context.post_render_callbacks.push(this.onHandleSending);
|
61
|
+
this.comp.context.connection.beginListen(this.networkingKey, this.onHandleReceiving);
|
64
62
|
|
65
63
|
const state = this.comp.context.connection.tryGetState(this.comp.guid);
|
66
64
|
if (state) this.onHandleReceiving(state);
|
@@ -68,10 +66,8 @@
|
|
68
66
|
|
69
67
|
destroy() {
|
70
68
|
if (!this._isInit) return;
|
71
|
-
|
72
|
-
|
73
|
-
if (this._handleReceivingMethod)
|
74
|
-
this.comp.context.connection.stopListen(this.networkingKey, this._handleReceivingMethod);
|
69
|
+
this.comp.context.post_render_callbacks.splice(this.comp.context.post_render_callbacks.indexOf(this.onHandleSending), 1);
|
70
|
+
this.comp.context.connection.stopListen(this.networkingKey, this.onHandleReceiving);
|
75
71
|
//@ts-ignore
|
76
72
|
this.comp = null;
|
77
73
|
this._isInit = false;
|
@@ -84,12 +80,11 @@
|
|
84
80
|
this.changedProperties[propertyName] = value;
|
85
81
|
}
|
86
82
|
|
87
|
-
private onHandleSending() {
|
83
|
+
private onHandleSending = () => {
|
88
84
|
if (!this.hasChanges) return;
|
89
85
|
this.hasChanges = false;
|
90
|
-
|
91
|
-
|
92
|
-
if (!net || !net.isConnected) {
|
86
|
+
const net = this.comp.context.connection as INetworkConnection
|
87
|
+
if (!net || !net.isConnected || !net.isInRoom) {
|
93
88
|
for (const key in this.changedProperties)
|
94
89
|
delete this.changedProperties[key];
|
95
90
|
return;
|
@@ -105,11 +100,12 @@
|
|
105
100
|
this.data[name] = value;
|
106
101
|
}
|
107
102
|
// console.log("SEND", this.comp.name, this.data, this.networkingKey);
|
108
|
-
net.send(this.networkingKey, this.data);
|
103
|
+
net.send(this.networkingKey, this.data, SendQueue.Queued);
|
109
104
|
}
|
110
105
|
|
111
|
-
private onHandleReceiving(val) {
|
112
|
-
if(debug)
|
106
|
+
private onHandleReceiving = (val) => {
|
107
|
+
if (debug)
|
108
|
+
console.log("RECEIVE", this.comp.name, this.comp.guid, val);
|
113
109
|
if (!this._isInit) return;
|
114
110
|
if (!this.comp) return;
|
115
111
|
const guid = val.guid;
|
@@ -13,7 +13,6 @@
|
|
13
13
|
|
14
14
|
export declare interface INetworkConnection {
|
15
15
|
get isConnected(): boolean;
|
16
|
-
|
16
|
+
get isInRoom(): boolean;
|
17
17
|
send(key: string, data: IModel | object | boolean | null | string | number, queue: SendQueue): unknown;
|
18
|
-
|
19
18
|
}
|
@@ -1023,7 +1023,11 @@
|
|
1023
1023
|
if (!this.eventQueue) {
|
1024
1024
|
this.eventQueue = new EventQueue(false);
|
1025
1025
|
}
|
1026
|
-
if (dt) {
|
1026
|
+
if (dt === undefined || dt <= 0) {
|
1027
|
+
this._isUpdatingPhysicsWorld = false;
|
1028
|
+
return;
|
1029
|
+
}
|
1030
|
+
else if (dt !== undefined) {
|
1027
1031
|
// if we make to sudden changes to the timestep the physics can get unstable
|
1028
1032
|
// https://rapier.rs/docs/user_guides/javascript/integration_parameters/#dt
|
1029
1033
|
this.world.timestep = Mathf.lerp(this.world.timestep, dt, 0.8);
|
@@ -1,3 +1,3 @@
|
|
1
1
|
export { type UsdzBehaviour } from "./extensions/behavior/Behaviour.js";
|
2
|
-
export { imageToCanvas,USDObject } from "./ThreeUSDZExporter.js";
|
2
|
+
export { imageToCanvas, makeNameSafeForUSD, USDZExporter as NeedleUSDZExporter, USDObject, USDWriter,type USDZExporterContext } from "./ThreeUSDZExporter.js";
|
3
3
|
export { USDZExporter } from "./USDZExporter.js";
|
@@ -93,7 +93,8 @@
|
|
93
93
|
|
94
94
|
uuid: string;
|
95
95
|
name: string;
|
96
|
-
|
96
|
+
type?: string; // by default, Xform is used
|
97
|
+
displayName?: string;
|
97
98
|
matrix: Matrix4;
|
98
99
|
private _isDynamic: boolean;
|
99
100
|
get isDynamic() { return this._isDynamic; }
|
@@ -1218,13 +1219,17 @@
|
|
1218
1219
|
}
|
1219
1220
|
else if ( camera )
|
1220
1221
|
writer.beginBlock( `def Camera "${name}"`, "(", false );
|
1222
|
+
else if ( model.type !== undefined)
|
1223
|
+
writer.beginBlock( `def ${model.type} "${name}"` );
|
1221
1224
|
else
|
1222
1225
|
writer.beginBlock( `def Xform "${name}"`, "(", false);
|
1223
1226
|
|
1224
1227
|
if (model.displayName)
|
1225
1228
|
writer.appendLine(`displayName = "${model.displayName}"`);
|
1226
|
-
|
1227
|
-
|
1229
|
+
if (model.type === undefined) {
|
1230
|
+
writer.closeBlock( ")" );
|
1231
|
+
writer.beginBlock();
|
1232
|
+
}
|
1228
1233
|
|
1229
1234
|
if ( geometry && material ) {
|
1230
1235
|
const materialName = getMaterialName(material);
|
@@ -1245,10 +1250,11 @@
|
|
1245
1250
|
writer.appendLine( `rel skel:animationSource = <Rig/_anim>`);
|
1246
1251
|
writer.appendLine( `matrix4d xformOp:transform = ${buildMatrix(new Matrix4())}` ); // always identity / in world space
|
1247
1252
|
}
|
1248
|
-
else {
|
1253
|
+
else if (model.type === undefined) {
|
1249
1254
|
writer.appendLine( `matrix4d xformOp:transform = ${transform}` );
|
1250
1255
|
}
|
1251
|
-
|
1256
|
+
if (model.type === undefined)
|
1257
|
+
writer.appendLine( 'uniform token[] xformOpOrder = ["xformOp:transform"]' );
|
1252
1258
|
|
1253
1259
|
if ( camera ) {
|
1254
1260
|
|
@@ -150,6 +150,12 @@
|
|
150
150
|
private _didBind: boolean = false;
|
151
151
|
private _animator: Animator | null = null;
|
152
152
|
|
153
|
+
|
154
|
+
onDisable() {
|
155
|
+
// if this track is disabled we need to stop the currently active actions
|
156
|
+
this.mixer?.stopAllAction();
|
157
|
+
}
|
158
|
+
|
153
159
|
// Using this callback instead of onEnable etc
|
154
160
|
// because we want to re-enable the animator when the director is at the end and wrap mode is set to none
|
155
161
|
// in which case the director is stopped (but not disabled)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Matrix4, Mesh, Object3D } from "three";
|
1
|
+
import { Matrix4, Mesh, Object3D, Quaternion, Vector3 } from "three";
|
2
2
|
|
3
3
|
import { showBalloonMessage, showBalloonWarning } from "../../../engine/debug/index.js";
|
4
4
|
import { hasProLicense } from "../../../engine/engine_license.js";
|
@@ -8,6 +8,7 @@
|
|
8
8
|
import { Behaviour, GameObject } from "../../Component.js";
|
9
9
|
import { Renderer } from "../../Renderer.js"
|
10
10
|
import { WebARSessionRoot } from "../../webxr/WebARSessionRoot.js";
|
11
|
+
import { WebXR } from "../../webxr/WebXR.js";
|
11
12
|
import { WebXRButtonFactory } from "../../webxr/WebXRButtons.js";
|
12
13
|
import { XRFlag, XRState, XRStateFlag } from "../../webxr/XRFlag.js";
|
13
14
|
import type { IUSDExporterExtension } from "./Extension.js";
|
@@ -280,6 +281,7 @@
|
|
280
281
|
}
|
281
282
|
|
282
283
|
private readonly _currentExportTasks = new Map<Object3D, Promise<Blob | null>>();
|
284
|
+
private _previousTimeScale: number = 1;
|
283
285
|
|
284
286
|
private async internalExport(objectToExport: Object3D): Promise<Blob | null> {
|
285
287
|
|
@@ -335,9 +337,6 @@
|
|
335
337
|
const currentXRState = XRState.Global.Mask;
|
336
338
|
XRState.Global.Set(XRStateFlag.AR);
|
337
339
|
|
338
|
-
// make sure we apply the AR scale
|
339
|
-
this.applyWebARSessionRoot();
|
340
|
-
|
341
340
|
const exporter = new ThreeUSDZExporter();
|
342
341
|
const extensions: any = [...this.extensions]
|
343
342
|
|
@@ -349,6 +348,13 @@
|
|
349
348
|
Progress.report("export-usdz", "Invoking before-export");
|
350
349
|
this.dispatchEvent(new CustomEvent("before-export", { detail: eventArgs }))
|
351
350
|
|
351
|
+
// make sure we apply the AR scale
|
352
|
+
this.applyWebARSessionRoot();
|
353
|
+
|
354
|
+
// freeze time
|
355
|
+
this._previousTimeScale = this.context.time.timeScale;
|
356
|
+
this.context.time.timeScale = 0;
|
357
|
+
|
352
358
|
// Implicit registration and actions for Animators and Animation components
|
353
359
|
// Currently, Animators properly build PlayAnimation actions, but Animation components don't.
|
354
360
|
|
@@ -366,7 +372,7 @@
|
|
366
372
|
exporter.keepObject = (object) => {
|
367
373
|
// TODO We need to take more care with disabled renderers. This currently breaks when any renderer is disabled
|
368
374
|
// and then enabled at runtime by e.g. SetActiveOnClick, requiring extra work to enable them before export,
|
369
|
-
// cache their state, and then reset their state after export.
|
375
|
+
// cache their state, and then reset their state after export.
|
370
376
|
const renderer = GameObject.getComponent(object, Renderer)
|
371
377
|
if (renderer && !renderer.enabled) return false;
|
372
378
|
return true;
|
@@ -396,6 +402,11 @@
|
|
396
402
|
|
397
403
|
const blob = new Blob([arraybuffer], { type: 'model/vnd.usdz+zip' });
|
398
404
|
|
405
|
+
this.revertWebARSessionRoot();
|
406
|
+
|
407
|
+
// unfreeze time
|
408
|
+
this.context.time.timeScale = this._previousTimeScale;
|
409
|
+
|
399
410
|
Progress.report("export-usdz", "Invoking after-export");
|
400
411
|
|
401
412
|
this.dispatchEvent(new CustomEvent("after-export", { detail: eventArgs }))
|
@@ -531,6 +542,12 @@
|
|
531
542
|
}
|
532
543
|
|
533
544
|
private static invertForwardMatrix = new Matrix4().makeRotationY(Math.PI);
|
545
|
+
|
546
|
+
private _rootSessionRootWasAppliedTo: Object3D | null = null;
|
547
|
+
private _rootPositionBeforeExport: Vector3 = new Vector3();
|
548
|
+
private _rootRotationBeforeExport: Quaternion = new Quaternion();
|
549
|
+
private _rootScaleBeforeExport: Vector3 = new Vector3();
|
550
|
+
|
534
551
|
private applyWebARSessionRoot() {
|
535
552
|
if (!this.objectToExport) return;
|
536
553
|
|
@@ -539,23 +556,39 @@
|
|
539
556
|
let sessionRoot = GameObject.getComponentInParent(this.objectToExport, WebARSessionRoot);
|
540
557
|
const hasSessionRootInParentHierarchy = sessionRoot !== null && sessionRoot !== undefined;
|
541
558
|
// if it's not in the parent hierarchy BUT in the child hierarchy we apply it to the sessionRoot object itself
|
542
|
-
// that
|
559
|
+
// that's the case when no objectToExport is explictly assigned and the whole scene is being exported
|
543
560
|
if(!sessionRoot) sessionRoot = GameObject.getComponentInChildren(this.objectToExport, WebARSessionRoot);
|
544
561
|
|
545
|
-
if (debug) console.log("applyWebARSessionRoot", sessionRoot);
|
562
|
+
if (debug) console.log("applyWebARSessionRoot", sessionRoot, sessionRoot?.arScale);
|
546
563
|
|
564
|
+
let arScale = 1;
|
565
|
+
let invertForward = false;
|
566
|
+
const target = hasSessionRootInParentHierarchy || !sessionRoot ? this.objectToExport : sessionRoot.gameObject;
|
567
|
+
|
547
568
|
if (!sessionRoot) {
|
548
|
-
|
549
|
-
|
569
|
+
const xr = GameObject.findObjectOfType(WebXR);
|
570
|
+
if (xr) arScale = xr.arSceneScale;
|
550
571
|
}
|
572
|
+
else {
|
573
|
+
arScale = sessionRoot.arScale;
|
574
|
+
invertForward = sessionRoot.invertForward;
|
575
|
+
}
|
551
576
|
|
552
577
|
// either apply the scale to the object being exported or to the sessionRoot object itself
|
553
|
-
const
|
554
|
-
|
555
|
-
|
556
|
-
|
578
|
+
const scale = 1 / arScale;
|
579
|
+
|
580
|
+
this._rootSessionRootWasAppliedTo = target;
|
581
|
+
this._rootPositionBeforeExport.copy(target.position);
|
582
|
+
this._rootRotationBeforeExport.copy(target.quaternion);
|
583
|
+
this._rootScaleBeforeExport.copy(target.scale);
|
584
|
+
|
585
|
+
target.scale.multiplyScalar(scale);
|
586
|
+
// legacy, should likely be deleted
|
587
|
+
if (invertForward) {
|
557
588
|
target.matrix.multiply(USDZExporter.invertForwardMatrix);
|
558
589
|
}
|
590
|
+
// udate childs as well
|
591
|
+
target.updateMatrixWorld(true);
|
559
592
|
|
560
593
|
// TODO we should refactor this and use one common method in WebARSessionRoot to place an object –
|
561
594
|
// basically the inverted effect of WebARSessionRoot.onApplyPose()
|
@@ -563,7 +596,21 @@
|
|
563
596
|
// TODO why are we not reverting this transformation after the export?
|
564
597
|
}
|
565
598
|
|
599
|
+
private revertWebARSessionRoot() {
|
600
|
+
if (!this.objectToExport) return;
|
601
|
+
if (!this._rootSessionRootWasAppliedTo) return;
|
566
602
|
|
603
|
+
const target = this._rootSessionRootWasAppliedTo;
|
604
|
+
target.position.copy(this._rootPositionBeforeExport);
|
605
|
+
target.quaternion.copy(this._rootRotationBeforeExport);
|
606
|
+
target.scale.copy(this._rootScaleBeforeExport);
|
607
|
+
|
608
|
+
// udate childs as well
|
609
|
+
target.updateMatrixWorld(true);
|
610
|
+
this._rootSessionRootWasAppliedTo = null;
|
611
|
+
}
|
612
|
+
|
613
|
+
|
567
614
|
private createQuicklookButton() {
|
568
615
|
const buttoncontainer = WebXRButtonFactory.getOrCreate();
|
569
616
|
const button = buttoncontainer.createQuicklookButton();
|
@@ -243,7 +243,7 @@
|
|
243
243
|
|
244
244
|
const loader = new GLTFLoader();
|
245
245
|
addDracoAndKTX2Loaders(loader, context);
|
246
|
-
await registerExtensions(loader, context, this.sourceId
|
246
|
+
await registerExtensions(loader, context, this.sourceId ?? "");
|
247
247
|
loader.setPath('https://cdn.jsdelivr.net/npm/@webxr-input-profiles/[email protected]/dist/profiles/generic-hand/');
|
248
248
|
|
249
249
|
// TODO: we should handle the loading here ourselves to not have this requirement of a specific model name
|