@needle-tools/engine 4.11.0-beta.1 → 4.11.0-next.687516a
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-CXVECA3a.js → gltf-progressive-BvlZQAkt.js} +3 -3
- package/dist/{gltf-progressive-D4Z_Khp3.min.js → gltf-progressive-CftVUJy3.min.js} +1 -1
- package/dist/{gltf-progressive-CHeORqEv.umd.cjs → gltf-progressive-GwdQV1Qx.umd.cjs} +1 -1
- package/dist/{needle-engine.bundle-CFc4UIqz.umd.cjs → needle-engine.bundle-COautGiS.umd.cjs} +142 -142
- package/dist/{needle-engine.bundle-6j5gE-aQ.min.js → needle-engine.bundle-RxTD8sUI.min.js} +142 -142
- package/dist/{needle-engine.bundle-BDZ09xyt.js → needle-engine.bundle-vaRDfJpp.js} +6211 -6145
- package/dist/needle-engine.d.ts +6 -0
- package/dist/needle-engine.js +4 -4
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{postprocessing-DQ2pynXW.js → postprocessing-CJC0Npcd.js} +2 -2
- package/dist/{postprocessing-BsnRNRRS.umd.cjs → postprocessing-DrM4PWU3.umd.cjs} +1 -1
- package/dist/{postprocessing-BHMVuZQ1.min.js → postprocessing-l7zsdO_Q.min.js} +1 -1
- package/dist/{three-qw28ZtTy.min.js → three-BDW9I486.min.js} +13 -13
- package/dist/{three-CJSAehtG.js → three-MHVqtJYj.js} +1 -0
- package/dist/{three-examples-Doq0rvFU.js → three-examples-C5Ht-QFN.js} +1 -1
- package/dist/{three-examples-Deqc1bNw.umd.cjs → three-examples-CgwGHSgz.umd.cjs} +1 -1
- package/dist/{three-examples-BivkhnvN.min.js → three-examples-fvEPSC8L.min.js} +1 -1
- package/dist/{three-B-jwTHao.umd.cjs → three-iFaDq9U3.umd.cjs} +13 -13
- package/dist/{three-mesh-ui-CktOi6oI.js → three-mesh-ui-BjWTTk1R.js} +1 -1
- package/dist/{three-mesh-ui-CsHwj9cJ.umd.cjs → three-mesh-ui-Bm32sS2a.umd.cjs} +1 -1
- package/dist/{three-mesh-ui-DhYXcXZe.min.js → three-mesh-ui-CLdkp21K.min.js} +1 -1
- package/dist/{vendor-BcsPRUmt.umd.cjs → vendor-C-oI7A4Z.umd.cjs} +2 -2
- package/dist/{vendor-CyfN5nor.js → vendor-D4AePCCt.js} +609 -599
- package/dist/{vendor-DyavoogU.min.js → vendor-DlEKkX1e.min.js} +25 -25
- package/lib/engine/js-extensions/Object3D.d.ts +6 -0
- package/lib/engine/js-extensions/Object3D.js +15 -0
- package/lib/engine/js-extensions/Object3D.js.map +1 -1
- package/lib/engine-components/Collider.d.ts +26 -0
- package/lib/engine-components/Collider.js +26 -0
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/ContactShadows.d.ts +11 -2
- package/lib/engine-components/ContactShadows.js +11 -2
- package/lib/engine-components/ContactShadows.js.map +1 -1
- package/lib/engine-components/DropListener.d.ts +3 -0
- package/lib/engine-components/DropListener.js +40 -19
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/Duplicatable.d.ts +2 -2
- package/lib/engine-components/Duplicatable.js +2 -2
- package/lib/engine-components/EventList.d.ts +18 -1
- package/lib/engine-components/EventList.js +18 -1
- package/lib/engine-components/EventList.js.map +1 -1
- package/lib/engine-components/GroundProjection.d.ts +3 -0
- package/lib/engine-components/GroundProjection.js +3 -0
- package/lib/engine-components/GroundProjection.js.map +1 -1
- package/lib/engine-components/Interactable.d.ts +4 -0
- package/lib/engine-components/Interactable.js +4 -0
- package/lib/engine-components/Interactable.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +4 -2
- package/lib/engine-components/OrbitControls.js +31 -3
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/RigidBody.d.ts +5 -0
- package/lib/engine-components/RigidBody.js +5 -0
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SeeThrough.js +20 -0
- package/lib/engine-components/SeeThrough.js.map +1 -1
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +4 -2
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +69 -14
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -1
- package/lib/engine-components/ui/Text.js +6 -1
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/engine-components/utils/LookAt.d.ts +3 -0
- package/lib/engine-components/utils/LookAt.js +3 -0
- package/lib/engine-components/utils/LookAt.js.map +1 -1
- package/lib/engine-components/utils/OpenURL.d.ts +2 -1
- package/lib/engine-components/utils/OpenURL.js +2 -1
- package/lib/engine-components/utils/OpenURL.js.map +1 -1
- package/lib/engine-components/webxr/WebARCameraBackground.d.ts +2 -0
- package/lib/engine-components/webxr/WebARCameraBackground.js +2 -0
- package/lib/engine-components/webxr/WebARCameraBackground.js.map +1 -1
- package/lib/engine-components/webxr/WebARSessionRoot.d.ts +1 -1
- package/lib/engine-components/webxr/WebARSessionRoot.js +1 -1
- package/lib/engine-components/webxr/WebXR.d.ts +2 -0
- package/lib/engine-components/webxr/WebXR.js +2 -0
- package/lib/engine-components/webxr/WebXR.js.map +1 -1
- package/lib/engine-components/webxr/WebXRImageTracking.d.ts +29 -0
- package/lib/engine-components/webxr/WebXRImageTracking.js +29 -0
- package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
- package/package.json +3 -3
- package/src/engine/js-extensions/Object3D.ts +24 -0
- package/src/engine-components/Collider.ts +27 -1
- package/src/engine-components/ContactShadows.ts +12 -4
- package/src/engine-components/DropListener.ts +43 -23
- package/src/engine-components/Duplicatable.ts +2 -2
- package/src/engine-components/EventList.ts +18 -1
- package/src/engine-components/GroundProjection.ts +4 -1
- package/src/engine-components/Interactable.ts +4 -1
- package/src/engine-components/OrbitControls.ts +27 -3
- package/src/engine-components/RigidBody.ts +6 -1
- package/src/engine-components/SeeThrough.ts +42 -2
- package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +117 -17
- package/src/engine-components/ui/Text.ts +11 -2
- package/src/engine-components/utils/LookAt.ts +3 -0
- package/src/engine-components/utils/OpenURL.ts +3 -2
- package/src/engine-components/webxr/WebARCameraBackground.ts +2 -0
- package/src/engine-components/webxr/WebARSessionRoot.ts +1 -1
- package/src/engine-components/webxr/WebXR.ts +2 -0
- package/src/engine-components/webxr/WebXRImageTracking.ts +30 -3
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Box3, Object3D, Vector2, Vector3 } from "three";
|
|
2
2
|
|
|
3
3
|
import { isDevEnvironment } from "../engine/debug/index.js";
|
|
4
4
|
import { AnimationUtils } from "../engine/engine_animation.js";
|
|
5
|
-
import { addComponent } from "../engine/engine_components.js";
|
|
6
5
|
import { Context } from "../engine/engine_context.js";
|
|
7
6
|
import { destroy } from "../engine/engine_gameobject.js";
|
|
8
7
|
import { Gizmos } from "../engine/engine_gizmos.js";
|
|
9
8
|
import { getLoader } from "../engine/engine_gltf.js";
|
|
10
9
|
import { BlobStorage } from "../engine/engine_networking_blob.js";
|
|
11
10
|
import { PreviewHelper } from "../engine/engine_networking_files.js";
|
|
12
|
-
import {
|
|
11
|
+
import { InstantiateIdProvider } from "../engine/engine_networking_instantiate.js";
|
|
13
12
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
14
13
|
import { fitObjectIntoVolume, getBoundingBox, placeOnSurface } from "../engine/engine_three_utils.js";
|
|
15
|
-
import {
|
|
14
|
+
import { Model, Vec3 } from "../engine/engine_types.js";
|
|
16
15
|
import { getParam, setParamWithoutReload } from "../engine/engine_utils.js";
|
|
17
16
|
import { determineMimeTypeFromExtension } from "../engine/engine_utils_format.js";
|
|
18
|
-
import { Animation } from "./Animation.js";
|
|
19
17
|
import { Behaviour } from "./Component.js";
|
|
20
18
|
import { EventList } from "./EventList.js";
|
|
19
|
+
import { Renderer } from "./Renderer.js";
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
22
|
* Debug mode can be enabled with the URL parameter `?debugdroplistener`, which
|
|
@@ -116,6 +115,8 @@ const blobKeyName = "blob";
|
|
|
116
115
|
* If {@link useNetworking} is enabled, the DropListener will automatically synchronize dropped files to other connected clients.
|
|
117
116
|
* Enable {@link fitIntoVolume} to automatically scale dropped objects to fit within the volume defined by {@link fitVolumeSize}.
|
|
118
117
|
*
|
|
118
|
+
* - Example: [DropListener Sample](https://droplistener-zubcksz1veaoo.needle.run/)
|
|
119
|
+
*
|
|
119
120
|
* The following events are dispatched by the DropListener:
|
|
120
121
|
* - **object-added** - dispatched when a new object is added to the scene
|
|
121
122
|
* - **file-dropped** - dispatched when a file is dropped into the scene
|
|
@@ -214,7 +215,14 @@ export class DropListener extends Behaviour {
|
|
|
214
215
|
}
|
|
215
216
|
|
|
216
217
|
|
|
217
|
-
|
|
218
|
+
awake() {
|
|
219
|
+
for (const ch of this.gameObject.children) {
|
|
220
|
+
if (this.dropArea && ch.contains(this.dropArea)) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
this._addedObjects.push(ch);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
218
226
|
|
|
219
227
|
// #region internals
|
|
220
228
|
|
|
@@ -223,7 +231,15 @@ export class DropListener extends Behaviour {
|
|
|
223
231
|
this.context.renderer.domElement.addEventListener("dragover", this.onDrag);
|
|
224
232
|
this.context.renderer.domElement.addEventListener("drop", this.onDrop);
|
|
225
233
|
window.addEventListener("paste", this.handlePaste);
|
|
226
|
-
this.context.connection.beginListen("droplistener", this.onNetworkEvent)
|
|
234
|
+
this.context.connection.beginListen("droplistener", this.onNetworkEvent);
|
|
235
|
+
if (isDevEnvironment()) {
|
|
236
|
+
if (this.dropArea) {
|
|
237
|
+
const anyRenderer = this.dropArea.getComponentInChildren(Renderer);
|
|
238
|
+
if (!anyRenderer) {
|
|
239
|
+
console.warn("[DropListener] The assigned DropArea does not seem to have a renderer/mesh. Drag and Drop events will not be detected.");
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
227
243
|
}
|
|
228
244
|
/** @internal */
|
|
229
245
|
onDisable(): void {
|
|
@@ -473,7 +489,7 @@ export class DropListener extends Behaviour {
|
|
|
473
489
|
if (doDestroy) {
|
|
474
490
|
for (const prev of this._addedObjects) {
|
|
475
491
|
if (prev.parent === this.gameObject) {
|
|
476
|
-
destroy(
|
|
492
|
+
prev.destroy();
|
|
477
493
|
}
|
|
478
494
|
}
|
|
479
495
|
}
|
|
@@ -596,24 +612,28 @@ export class DropListener extends Behaviour {
|
|
|
596
612
|
* @returns True if the drop is valid (either no drop area is set or the drop occurred inside it)
|
|
597
613
|
*/
|
|
598
614
|
private testIfIsInDropArea(ctx: DropContext): boolean {
|
|
615
|
+
const screenPoint = this.context.input.convertScreenspaceToRaycastSpace(ctx.screenposition.clone());
|
|
616
|
+
const hits = this.context.physics.raycast({
|
|
617
|
+
screenPoint,
|
|
618
|
+
recursive: true,
|
|
619
|
+
testObject: obj => {
|
|
620
|
+
// Ignore hits on the already added objects, they don't count as part of the dropzone
|
|
621
|
+
if (this._addedObjects.some(o => o.contains(obj))) return false;
|
|
622
|
+
return true;
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
if (!hits.length) {
|
|
626
|
+
if (isDevEnvironment()) console.log(`Dropped outside of drop area for DropListener \"${this.name}\".`);
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
const hit = hits[0];
|
|
599
631
|
if (this.dropArea) {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
targets: [this.dropArea],
|
|
603
|
-
screenPoint,
|
|
604
|
-
recursive: true,
|
|
605
|
-
testObject: obj => {
|
|
606
|
-
// Ignore hits on the already added objects, they don't count as part of the dropzone
|
|
607
|
-
if (this._addedObjects.includes(obj)) return false;
|
|
608
|
-
return true;
|
|
609
|
-
}
|
|
610
|
-
});
|
|
611
|
-
if (!hits.length) {
|
|
612
|
-
if (isDevEnvironment()) console.log(`Dropped outside of drop area for DropListener \"${this.name}\".`);
|
|
613
|
-
return false;
|
|
632
|
+
if (this.dropArea.contains(hit.object)) {
|
|
633
|
+
return true;
|
|
614
634
|
}
|
|
615
635
|
}
|
|
616
|
-
return
|
|
636
|
+
return false;
|
|
617
637
|
}
|
|
618
638
|
|
|
619
639
|
}
|
|
@@ -12,8 +12,8 @@ import { type IPointerEventHandler, PointerEventData } from "./ui/PointerEvents.
|
|
|
12
12
|
import { ObjectRaycaster } from "./ui/Raycaster.js";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* The Duplicatable component is used to duplicate a assigned {@link GameObject} when a pointer event occurs on the
|
|
16
|
-
*
|
|
15
|
+
* The Duplicatable component is used to duplicate a assigned {@link GameObject} when a pointer event occurs on the object.
|
|
16
|
+
*
|
|
17
17
|
* @category Interactivity
|
|
18
18
|
* @group Components
|
|
19
19
|
*/
|
|
@@ -97,7 +97,24 @@ export class EventListEvent<TArgs extends any> extends Event { //implements Arra
|
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
|
-
* The EventList is a class that can be used to create a list of event listeners that can be invoked
|
|
100
|
+
* The EventList is a class that can be used to create a list of event listeners that can be invoked.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* // create an event list
|
|
105
|
+
* const onClick = new EventList<(event: MouseEvent) => void>();
|
|
106
|
+
*
|
|
107
|
+
* // add an event listener
|
|
108
|
+
* onClick.addEventListener((event) => {
|
|
109
|
+
* console.log("Clicked!", event);
|
|
110
|
+
* });
|
|
111
|
+
*
|
|
112
|
+
* // invoke the event list
|
|
113
|
+
* onClick.invoke(new MouseEvent("click"));
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @category Events
|
|
117
|
+
* @group Utilities
|
|
101
118
|
*/
|
|
102
119
|
export class EventList<TArgs extends any = any> implements IEventList {
|
|
103
120
|
|
|
@@ -10,7 +10,10 @@ import { Behaviour } from "./Component.js";
|
|
|
10
10
|
const debug = getParam("debuggroundprojection");
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* GroundProjectedEnv creates a ground projection of the current environment map.
|
|
13
|
+
* GroundProjectedEnv creates a ground projection of the current environment map.
|
|
14
|
+
*
|
|
15
|
+
* - Example https://engine.needle.tools/samples/ground-projection
|
|
16
|
+
*
|
|
14
17
|
* @category Rendering
|
|
15
18
|
* @group Components
|
|
16
19
|
*/
|
|
@@ -10,6 +10,9 @@ export class UsageMarker extends Behaviour
|
|
|
10
10
|
public usedBy: any = null;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* An empty component that can be used to mark an object as interactable.
|
|
15
|
+
* @group Components
|
|
16
|
+
*/
|
|
14
17
|
/** @deprecated */
|
|
15
18
|
export class Interactable extends Behaviour {}
|
|
@@ -255,7 +255,12 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
255
255
|
* @default 1
|
|
256
256
|
*/
|
|
257
257
|
@serializable()
|
|
258
|
-
targetLerpDuration
|
|
258
|
+
get targetLerpDuration() { return this._lookTargetLerpDuration; }
|
|
259
|
+
set targetLerpDuration(v) { this._lookTargetLerpDuration = v; }
|
|
260
|
+
private _lookTargetLerpDuration: number = 1;
|
|
261
|
+
|
|
262
|
+
@serializable(Object3D)
|
|
263
|
+
targetBounds: Object3D | null = null;
|
|
259
264
|
|
|
260
265
|
/**
|
|
261
266
|
* Rotate the camera left (or right) by the specified angle in radians.
|
|
@@ -326,7 +331,6 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
326
331
|
private _lookTargetStartPosition: Vector3 = new Vector3();
|
|
327
332
|
private _lookTargetEndPosition: Vector3 = new Vector3();
|
|
328
333
|
private _lookTargetLerp01: number = 0;
|
|
329
|
-
private _lookTargetLerpDuration: number = 0;
|
|
330
334
|
|
|
331
335
|
private _cameraLerpActive: boolean = false;
|
|
332
336
|
private _cameraStartPosition: Vector3 = new Vector3();
|
|
@@ -685,6 +689,26 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
685
689
|
}
|
|
686
690
|
}
|
|
687
691
|
|
|
692
|
+
if (this.targetBounds) {
|
|
693
|
+
// #region target bounds
|
|
694
|
+
const targetVector = this._controls.target;
|
|
695
|
+
const boundsCenter = this.targetBounds.worldPosition;
|
|
696
|
+
const boundsHalfSize = getTempVector(this.targetBounds.worldScale).multiplyScalar(0.5);
|
|
697
|
+
const min = getTempVector(boundsCenter).sub(boundsHalfSize);
|
|
698
|
+
const max = getTempVector(boundsCenter).add(boundsHalfSize);
|
|
699
|
+
const newTarget = getTempVector(this._controls.target).clamp(min, max);
|
|
700
|
+
const duration = .1;
|
|
701
|
+
if (duration <= 0) targetVector.copy(newTarget);
|
|
702
|
+
else targetVector.lerp(newTarget, this.context.time.deltaTime / duration);
|
|
703
|
+
if (this._lookTargetLerpActive) {
|
|
704
|
+
if (duration <= 0) this._lookTargetEndPosition.copy(newTarget);
|
|
705
|
+
else this._lookTargetEndPosition.lerp(newTarget, this.context.time.deltaTime / (duration * 5));
|
|
706
|
+
}
|
|
707
|
+
if (debug) {
|
|
708
|
+
Gizmos.DrawWireBox(boundsCenter, boundsHalfSize.multiplyScalar(2), 0xffaa00);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
688
712
|
|
|
689
713
|
if (this._controls) {
|
|
690
714
|
if (this.debugLog)
|
|
@@ -1000,7 +1024,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1000
1024
|
*/
|
|
1001
1025
|
fitCamera(options?: OrbitFitCameraOptions);
|
|
1002
1026
|
/** @deprecated Use fitCamera(options) */
|
|
1003
|
-
fitCamera(objects?: Object3D | Array<Object3D>, options?: Omit<OrbitFitCameraOptions, "objects">);
|
|
1027
|
+
fitCamera(objects?: Object3D | Array<Object3D>, options?: Omit<OrbitFitCameraOptions, "objects">);
|
|
1004
1028
|
fitCamera(objectsOrOptions?: Object3D | Array<Object3D> | OrbitFitCameraOptions, options?: OrbitFitCameraOptions): void {
|
|
1005
1029
|
|
|
1006
1030
|
|
|
@@ -134,7 +134,12 @@ class TransformWatch {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
/**
|
|
137
|
-
* A Rigidbody is used together with a Collider to create physical interactions between objects in the scene.
|
|
137
|
+
* A Rigidbody is used together with a Collider to create physical interactions between objects in the scene.
|
|
138
|
+
*
|
|
139
|
+
* - Example: https://samples.needle.tools/physics-basic
|
|
140
|
+
* - Example: https://samples.needle.tools/physics-playground
|
|
141
|
+
* - Example: https://samples.needle.tools/physics-&-animation
|
|
142
|
+
*
|
|
138
143
|
* @category Physics
|
|
139
144
|
* @group Components
|
|
140
145
|
*/
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { Material, Object3D, Vector3 } from "three";
|
|
1
|
+
import { Material, Object3D, Object3DEventMap, Vector3 } from "three";
|
|
2
2
|
|
|
3
3
|
import { Gizmos } from "../engine/engine_gizmos.js";
|
|
4
4
|
import { Mathf } from "../engine/engine_math.js";
|
|
5
5
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
6
6
|
import { getTempVector } from "../engine/engine_three_utils.js";
|
|
7
7
|
import { getParam } from "../engine/engine_utils.js";
|
|
8
|
+
import { USDObject, USDZExporterContext } from "./api.js";
|
|
8
9
|
import { Behaviour } from "./Component.js";
|
|
10
|
+
import { IUSDExporterExtension } from "./export/usdz/Extension.js";
|
|
11
|
+
import { USDZExporter } from "./export/usdz/USDZExporter.js";
|
|
9
12
|
import { Renderer } from "./Renderer.js";
|
|
10
13
|
|
|
11
14
|
const debugSeeThrough = getParam("debugseethrough");
|
|
@@ -102,6 +105,7 @@ export class SeeThrough extends Behaviour {
|
|
|
102
105
|
onEnable() {
|
|
103
106
|
this._needsUpdate = true;
|
|
104
107
|
this._renderer = null;
|
|
108
|
+
SeeThroughUsdzExporterPlugin.components.push(this);
|
|
105
109
|
}
|
|
106
110
|
|
|
107
111
|
/** @internal */
|
|
@@ -118,6 +122,9 @@ export class SeeThrough extends Behaviour {
|
|
|
118
122
|
this.rendererMaterials.delete(r);
|
|
119
123
|
this.rendererMaterialsOriginal.delete(r);
|
|
120
124
|
});
|
|
125
|
+
|
|
126
|
+
const index = SeeThroughUsdzExporterPlugin.components.indexOf(this);
|
|
127
|
+
if (index !== -1) SeeThroughUsdzExporterPlugin.components.splice(index, 1);
|
|
121
128
|
}
|
|
122
129
|
|
|
123
130
|
/**
|
|
@@ -253,4 +260,37 @@ export class SeeThrough extends Behaviour {
|
|
|
253
260
|
});
|
|
254
261
|
}
|
|
255
262
|
|
|
256
|
-
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
;
|
|
267
|
+
class SeeThroughUsdzExporterPlugin implements IUSDExporterExtension {
|
|
268
|
+
|
|
269
|
+
static readonly components: SeeThrough[] = [];
|
|
270
|
+
|
|
271
|
+
get extensionName() {
|
|
272
|
+
return "SeeThrough";
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// onExportObject(object: Object3D<Object3DEventMap>, model: USDObject, context: USDZExporterContext) {
|
|
276
|
+
// const component = SeeThroughUsdzExporterPlugin.components.find(c => c.gameObject === object);
|
|
277
|
+
// if(!component) return;
|
|
278
|
+
// console.log("OH MY GOD SEE THROUGH USDZ EXPORTER", component, model);
|
|
279
|
+
|
|
280
|
+
// model.materialName = "AlphaHashMaterialInstance"; // we could make this unique per object if needed
|
|
281
|
+
|
|
282
|
+
// model.addEventListener("serialize", (writer, context) => {
|
|
283
|
+
// writer.appendLine(`# SeeThrough component on ${object.name}`);
|
|
284
|
+
// });
|
|
285
|
+
// }
|
|
286
|
+
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const seeThroughUsdzExporterPlugin = new SeeThroughUsdzExporterPlugin();
|
|
290
|
+
|
|
291
|
+
USDZExporter.beforeExport.addEventListener(args => {
|
|
292
|
+
if (SeeThroughUsdzExporterPlugin.components.length === 0) return;
|
|
293
|
+
if (args.exporter.extensions.includes(seeThroughUsdzExporterPlugin) === false) {
|
|
294
|
+
args.exporter.extensions.push(seeThroughUsdzExporterPlugin);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
@@ -112,6 +112,10 @@ const PositionIdentity = new Vector3();
|
|
|
112
112
|
const QuaternionIdentity = new Quaternion();
|
|
113
113
|
const ScaleIdentity = new Vector3(1,1,1);
|
|
114
114
|
|
|
115
|
+
// #region USDObject
|
|
116
|
+
|
|
117
|
+
type USDObjectEventType = "serialize" & ({} & string);
|
|
118
|
+
|
|
115
119
|
class USDObject {
|
|
116
120
|
|
|
117
121
|
static USDObject_export_id = 0;
|
|
@@ -153,12 +157,13 @@ class USDObject {
|
|
|
153
157
|
private set isDynamic( value ) { this._isDynamic = value; }
|
|
154
158
|
geometry: BufferGeometry | null;
|
|
155
159
|
material: MeshStandardMaterial | MeshBasicMaterial | Material | MeshPhysicalNodeMaterial | null;
|
|
160
|
+
// usdMaterial?: USDMaterial;
|
|
156
161
|
camera: PerspectiveCamera | OrthographicCamera | null;
|
|
157
162
|
parent: USDObject | null;
|
|
158
163
|
skinnedMesh: SkinnedMesh | null;
|
|
159
164
|
children: Array<USDObject | null> = [];
|
|
160
165
|
animations: AnimationClip[] | null;
|
|
161
|
-
_eventListeners:
|
|
166
|
+
_eventListeners: Record<USDObjectEventType, Function[]>;
|
|
162
167
|
|
|
163
168
|
// these are for tracking which xformops are needed
|
|
164
169
|
needsTranslate: boolean = false;
|
|
@@ -201,7 +206,7 @@ class USDObject {
|
|
|
201
206
|
this.camera = camera;
|
|
202
207
|
this.parent = null;
|
|
203
208
|
this.children = [];
|
|
204
|
-
this._eventListeners = {}
|
|
209
|
+
this._eventListeners = {} as Record<USDObjectEventType, Function[]>;
|
|
205
210
|
this._isDynamic = false;
|
|
206
211
|
this.skinnedMesh = skinnedMesh;
|
|
207
212
|
this.animations = animations;
|
|
@@ -287,7 +292,7 @@ class USDObject {
|
|
|
287
292
|
|
|
288
293
|
}
|
|
289
294
|
|
|
290
|
-
addEventListener( evt, listener: ( writer: USDWriter, context: USDZExporterContext ) => void ) {
|
|
295
|
+
addEventListener( evt : USDObjectEventType, listener: ( writer: USDWriter, context: USDZExporterContext ) => void ) {
|
|
291
296
|
|
|
292
297
|
if ( ! this._eventListeners[ evt ] ) this._eventListeners[ evt ] = [];
|
|
293
298
|
this._eventListeners[ evt ].push( listener );
|
|
@@ -316,6 +321,67 @@ class USDObject {
|
|
|
316
321
|
}
|
|
317
322
|
|
|
318
323
|
|
|
324
|
+
// #region USDMaterial
|
|
325
|
+
|
|
326
|
+
// class MaterialInput {
|
|
327
|
+
// name: string;
|
|
328
|
+
// }
|
|
329
|
+
|
|
330
|
+
class USDMaterial {
|
|
331
|
+
|
|
332
|
+
static USDMaterial_id = 0;
|
|
333
|
+
|
|
334
|
+
readonly material: Material;
|
|
335
|
+
readonly id: number;
|
|
336
|
+
|
|
337
|
+
name: string;
|
|
338
|
+
|
|
339
|
+
isOverride: boolean = false;
|
|
340
|
+
isInstanceable: boolean = false;
|
|
341
|
+
|
|
342
|
+
constructor( material: Material ) {
|
|
343
|
+
this.material = material;
|
|
344
|
+
this.id = USDMaterial.USDMaterial_id ++;
|
|
345
|
+
this.name = makeNameSafe( material.name || 'Material_' + this.id );
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
readonly inputs: Record<string, string | number | boolean | number[] | undefined> = {};
|
|
349
|
+
|
|
350
|
+
// addInput( name: string, value: "" ) {
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
// }
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
serialize( writer: USDWriter, _context: USDZExporterContext ) {
|
|
358
|
+
|
|
359
|
+
const name = this.name;
|
|
360
|
+
|
|
361
|
+
writer.appendLine( `def Material "${this.name}" ${name ?`( displayName = "${makeDisplayNameSafe(name)}" )` : ''}` );
|
|
362
|
+
writer.beginBlock();
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
writer.closeBlock();
|
|
366
|
+
|
|
367
|
+
// def Material "${materialName}" ${material.name ?`(
|
|
368
|
+
// displayName = "${material.name}"
|
|
369
|
+
// )` : ''}
|
|
370
|
+
// {
|
|
371
|
+
// token outputs:mtlx:surface.connect = ${materialRoot}/${materialName}/Occlusion.outputs:out>
|
|
372
|
+
|
|
373
|
+
// def Shader "Occlusion"
|
|
374
|
+
// {
|
|
375
|
+
// uniform token info:id = "${mode}"
|
|
376
|
+
// token outputs:out
|
|
377
|
+
// }
|
|
378
|
+
// }`;
|
|
379
|
+
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// #region USDDocument
|
|
384
|
+
|
|
319
385
|
class USDDocument extends USDObject {
|
|
320
386
|
|
|
321
387
|
stageLength: number;
|
|
@@ -448,6 +514,7 @@ ${comments}
|
|
|
448
514
|
|
|
449
515
|
}
|
|
450
516
|
|
|
517
|
+
|
|
451
518
|
const newLine = '\n';
|
|
452
519
|
const materialRoot = '</StageRoot/Materials';
|
|
453
520
|
|
|
@@ -540,6 +607,8 @@ class USDWriter {
|
|
|
540
607
|
|
|
541
608
|
declare type TextureMap = {[name: string]: {texture: Texture, scale?: Vector4}};
|
|
542
609
|
|
|
610
|
+
// #region USDZExporterContext
|
|
611
|
+
|
|
543
612
|
class USDZExporterContext {
|
|
544
613
|
root?: Object3D;
|
|
545
614
|
exporter: USDZExporter;
|
|
@@ -576,6 +645,10 @@ class USDZExporterContext {
|
|
|
576
645
|
|
|
577
646
|
}
|
|
578
647
|
|
|
648
|
+
makeNameSafe( str ) {
|
|
649
|
+
return makeNameSafe( str );
|
|
650
|
+
}
|
|
651
|
+
|
|
579
652
|
}
|
|
580
653
|
|
|
581
654
|
/**[documentation](https://developer.apple.com/documentation/arkit/usdz_schemas_for_ar/preliminary_anchoringapi/preliminary_anchoring_type) */
|
|
@@ -597,6 +670,8 @@ class USDZExporterOptions {
|
|
|
597
670
|
exportInvisible: boolean = false;
|
|
598
671
|
}
|
|
599
672
|
|
|
673
|
+
// #region USDZExporter
|
|
674
|
+
|
|
600
675
|
class USDZExporter {
|
|
601
676
|
debug: boolean;
|
|
602
677
|
pruneUnusedNodes: boolean;
|
|
@@ -698,13 +773,7 @@ class USDZExporter {
|
|
|
698
773
|
}
|
|
699
774
|
|
|
700
775
|
Progress.report('export-usdz', { message: "Parsing document", autoStep: 10 });
|
|
701
|
-
await parseDocument( context,
|
|
702
|
-
// injected after stageRoot.
|
|
703
|
-
// TODO property use context/writer instead of string concat
|
|
704
|
-
Progress.report('export-usdz', "Building materials");
|
|
705
|
-
const result = buildMaterials( materials, textures, options.quickLookCompatible );
|
|
706
|
-
return result;
|
|
707
|
-
} );
|
|
776
|
+
await parseDocument( context, options );
|
|
708
777
|
|
|
709
778
|
Progress.report("export-usdz", "Invoking onAfterSerialize");
|
|
710
779
|
await invokeAll( context, 'onAfterSerialize' );
|
|
@@ -726,7 +795,7 @@ class USDZExporter {
|
|
|
726
795
|
const final = header + '\n' + context.output;
|
|
727
796
|
|
|
728
797
|
// full output file
|
|
729
|
-
if ( this.debug ) console.
|
|
798
|
+
if ( this.debug ) console.debug( final );
|
|
730
799
|
|
|
731
800
|
files[ modelFileName ] = fflate.strToU8( final );
|
|
732
801
|
context.output = '';
|
|
@@ -822,6 +891,9 @@ class USDZExporter {
|
|
|
822
891
|
|
|
823
892
|
}
|
|
824
893
|
|
|
894
|
+
// #endregion
|
|
895
|
+
|
|
896
|
+
// #region traverse
|
|
825
897
|
function traverse( object: Object3D, parentModel: USDObject, context: USDZExporterContext, keepObject?: (object: Object3D) => boolean ) {
|
|
826
898
|
|
|
827
899
|
if (!context.exportInvisible && !object.visible) return;
|
|
@@ -919,6 +991,8 @@ function traverse( object: Object3D, parentModel: USDObject, context: USDZExport
|
|
|
919
991
|
|
|
920
992
|
}
|
|
921
993
|
|
|
994
|
+
// #endregion
|
|
995
|
+
|
|
922
996
|
function logUsdHierarchy( object: USDObject, prefix: string, ...extraLogObjects: any[] ) {
|
|
923
997
|
|
|
924
998
|
const item = {};
|
|
@@ -1020,7 +1094,8 @@ function prune ( object: USDObject, options : {
|
|
|
1020
1094
|
return canBePruned;
|
|
1021
1095
|
}
|
|
1022
1096
|
|
|
1023
|
-
|
|
1097
|
+
// #region parseDocument
|
|
1098
|
+
async function parseDocument( context: USDZExporterContext, options: USDZExporterOptions ) {
|
|
1024
1099
|
|
|
1025
1100
|
Progress.start("export-usdz-resources", "export-usdz");
|
|
1026
1101
|
const resources: Array<() => void> = [];
|
|
@@ -1086,14 +1161,21 @@ async function parseDocument( context: USDZExporterContext, afterStageRoot: () =
|
|
|
1086
1161
|
|
|
1087
1162
|
writer.closeBlock();
|
|
1088
1163
|
writer.closeBlock();
|
|
1089
|
-
|
|
1164
|
+
|
|
1165
|
+
// TODO property use context/writer instead of string concat
|
|
1166
|
+
Progress.report('export-usdz', "Building materials");
|
|
1167
|
+
const result = buildMaterials( context.materials, context.textures, options.quickLookCompatible );
|
|
1168
|
+
writer.appendLine(result);
|
|
1169
|
+
|
|
1090
1170
|
writer.closeBlock();
|
|
1091
1171
|
|
|
1092
1172
|
Progress.report("export-usdz", "write to string")
|
|
1093
1173
|
context.output += writer.toString();
|
|
1094
1174
|
|
|
1095
1175
|
}
|
|
1176
|
+
// #endregion
|
|
1096
1177
|
|
|
1178
|
+
// #region addResources
|
|
1097
1179
|
function addResources( object: USDObject | null, context: USDZExporterContext, resources: Array<() => void>) {
|
|
1098
1180
|
|
|
1099
1181
|
if ( !object ) return;
|
|
@@ -1132,7 +1214,7 @@ function addResources( object: USDObject | null, context: USDZExporterContext, r
|
|
|
1132
1214
|
|
|
1133
1215
|
if ( material ) {
|
|
1134
1216
|
|
|
1135
|
-
if (
|
|
1217
|
+
if ( context.materials.get( material.uuid ) === undefined ) {
|
|
1136
1218
|
|
|
1137
1219
|
context.materials[ material.uuid ] = material;
|
|
1138
1220
|
|
|
@@ -1169,6 +1251,10 @@ async function invokeAll( context: USDZExporterContext, name: string, writer: US
|
|
|
1169
1251
|
}
|
|
1170
1252
|
|
|
1171
1253
|
}
|
|
1254
|
+
|
|
1255
|
+
// #endregion
|
|
1256
|
+
|
|
1257
|
+
// #region GPU utils
|
|
1172
1258
|
let _renderer: WebGLRenderer | null = null;
|
|
1173
1259
|
let renderTarget: WebGLRenderTarget | null = null;
|
|
1174
1260
|
let fullscreenQuadGeometry: PlaneGeometry | null;
|
|
@@ -1431,7 +1517,9 @@ function getPathToSkeleton(bone: Object3D, assumedRoot: Object3D) {
|
|
|
1431
1517
|
return path;
|
|
1432
1518
|
}
|
|
1433
1519
|
|
|
1434
|
-
//
|
|
1520
|
+
// #endregion
|
|
1521
|
+
|
|
1522
|
+
// #region XForm
|
|
1435
1523
|
|
|
1436
1524
|
export function buildXform( model: USDObject | null, writer: USDWriter, context: USDZExporterContext ) {
|
|
1437
1525
|
|
|
@@ -1635,7 +1723,7 @@ function buildMatrixRow( array, offset ) {
|
|
|
1635
1723
|
|
|
1636
1724
|
}
|
|
1637
1725
|
|
|
1638
|
-
// Mesh
|
|
1726
|
+
// #region Mesh
|
|
1639
1727
|
|
|
1640
1728
|
function buildMeshObject( geometry: BufferGeometry, bonesArray: Bone[] = [], quickLookCompatible: boolean = true) {
|
|
1641
1729
|
|
|
@@ -1948,7 +2036,9 @@ function buildVector2Array( attribute: BufferAttribute | InterleavedBufferAttrib
|
|
|
1948
2036
|
|
|
1949
2037
|
}
|
|
1950
2038
|
|
|
1951
|
-
//
|
|
2039
|
+
// #endregion
|
|
2040
|
+
|
|
2041
|
+
// #region Materials
|
|
1952
2042
|
|
|
1953
2043
|
function buildMaterials( materials: Map<string, Material>, textures: TextureMap, quickLookCompatible = false ) {
|
|
1954
2044
|
|
|
@@ -2103,10 +2193,14 @@ function buildTexture( texture: Texture, mapType: MapType, quickLookCompatible:
|
|
|
2103
2193
|
}`;
|
|
2104
2194
|
}
|
|
2105
2195
|
|
|
2196
|
+
|
|
2106
2197
|
function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quickLookCompatible = false ) {
|
|
2107
2198
|
|
|
2108
2199
|
const materialName = getMaterialName(material);
|
|
2109
2200
|
|
|
2201
|
+
// TODO: refactor to USDMaterial class
|
|
2202
|
+
// const usdMaterial = new USDMaterial(material);
|
|
2203
|
+
|
|
2110
2204
|
// Special case: occluder material
|
|
2111
2205
|
// Supported on iOS 18+ and visionOS 1+
|
|
2112
2206
|
const isShadowCatcherMaterial =
|
|
@@ -2330,6 +2424,7 @@ function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quick
|
|
|
2330
2424
|
}
|
|
2331
2425
|
}
|
|
2332
2426
|
|
|
2427
|
+
|
|
2333
2428
|
return `
|
|
2334
2429
|
|
|
2335
2430
|
def Material "${materialName}" ${material.name ?`(
|
|
@@ -2368,6 +2463,8 @@ ${samplers.join( '\n' )}` : ''}
|
|
|
2368
2463
|
}`;
|
|
2369
2464
|
}
|
|
2370
2465
|
|
|
2466
|
+
// #endregion
|
|
2467
|
+
|
|
2371
2468
|
function buildColor( color ) {
|
|
2372
2469
|
|
|
2373
2470
|
return `(${color.r}, ${color.g}, ${color.b})`;
|
|
@@ -2407,6 +2504,9 @@ const formatsWithAlphaChannel = [
|
|
|
2407
2504
|
36492, // RGBA_BPTC_Format
|
|
2408
2505
|
];
|
|
2409
2506
|
|
|
2507
|
+
|
|
2508
|
+
// #region exports
|
|
2509
|
+
|
|
2410
2510
|
export {
|
|
2411
2511
|
buildMatrix,
|
|
2412
2512
|
decompressGpuTexture,
|
|
@@ -284,7 +284,7 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
284
284
|
return opts;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
-
private feedText(text: string, richText: boolean)
|
|
287
|
+
private feedText(text: string, richText: boolean): void {
|
|
288
288
|
// if (!text || text.length <= 0) return;
|
|
289
289
|
// if (!text ) return;
|
|
290
290
|
if (debug) console.log("feedText", this.uiObject, text, richText);
|
|
@@ -511,6 +511,15 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
511
511
|
}
|
|
512
512
|
|
|
513
513
|
private getFamilyNameWithCorrectSuffix(familyName: string, style: FontStyle): string {
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
// the URL decorator resolves the URL to absolute URLs - we need to remove the domain part since we're only interested in the path
|
|
517
|
+
if (familyName.startsWith("https:") || familyName.startsWith("http:")) {
|
|
518
|
+
const url = new URL(familyName);
|
|
519
|
+
familyName = url.pathname;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
|
|
514
523
|
// we can only change the style for the family if the name has a suffix (e.g. Arial-Bold)
|
|
515
524
|
const styleSeparator = familyName.lastIndexOf('-');
|
|
516
525
|
if (styleSeparator < 0) return familyName;
|
|
@@ -532,7 +541,7 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
532
541
|
fontBaseName = fontBaseName.substring(pathSeparatorIndex + 1);
|
|
533
542
|
}
|
|
534
543
|
const isUpperCase = fontBaseName[0] === fontBaseName[0].toUpperCase();
|
|
535
|
-
const fontNameWithoutSuffix = familyName.substring(0, styleSeparator);
|
|
544
|
+
const fontNameWithoutSuffix = familyName.substring(0, styleSeparator > pathSeparatorIndex ? styleSeparator : familyName.length);
|
|
536
545
|
if (debug) console.log("Select font: ", familyName, FontStyle[style], fontBaseName, isUpperCase, fontNameWithoutSuffix);
|
|
537
546
|
|
|
538
547
|
switch (style) {
|
|
@@ -11,6 +11,9 @@ import { Behaviour } from "../Component.js";
|
|
|
11
11
|
/**
|
|
12
12
|
* LookAt behaviour makes the object look at a target object or the camera.
|
|
13
13
|
* It can also invert the forward direction and keep the up direction.
|
|
14
|
+
*
|
|
15
|
+
* @category Interactivity, Everywhere Actions
|
|
16
|
+
* @group Components
|
|
14
17
|
*/
|
|
15
18
|
export class LookAt extends Behaviour implements UsdzBehaviour {
|
|
16
19
|
|