@needle-tools/engine 4.11.0-next.8bfb2f5 → 4.11.0-next.c7baa24
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/CHANGELOG.md +7 -1
- package/README.md +3 -1
- 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-8EmDJd2O.umd.cjs → needle-engine.bundle-DBDKvYj5.umd.cjs} +142 -142
- package/dist/{needle-engine.bundle-DtF-fcok.min.js → needle-engine.bundle-qNZSuWhD.min.js} +144 -144
- package/dist/{needle-engine.bundle-lul9TfB2.js → needle-engine.bundle-tE15q9uM.js} +6264 -6202
- 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-CAWj5cBK.umd.cjs} +2 -2
- package/dist/{vendor-CyfN5nor.js → vendor-DJBpoQcM.js} +608 -599
- package/dist/{vendor-DyavoogU.min.js → vendor-DWGd3dEf.min.js} +20 -20
- 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 +44 -21
- 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/web/ScrollFollow.js +1 -2
- package/lib/engine-components/web/ScrollFollow.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 +2 -2
- package/plugins/vite/index.js +4 -1
- package/plugins/vite/needle-app.js +103 -57
- 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 +45 -24
- 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/web/ScrollFollow.ts +1 -1
- 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,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
|
|
|
@@ -15,8 +15,9 @@ export enum OpenURLMode {
|
|
|
15
15
|
NewWindow = 2
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* OpenURL behaviour opens a URL in a new tab or window.
|
|
18
|
+
/**
|
|
19
|
+
* OpenURL behaviour opens a URL in a new tab or window when the object (or any if it's children) is clicked.
|
|
20
|
+
*
|
|
20
21
|
* @category Interactivity
|
|
21
22
|
* @group Components
|
|
22
23
|
*/
|
|
@@ -473,7 +473,7 @@ function tryGetElementsForSelector(index: number): Element | null {
|
|
|
473
473
|
|
|
474
474
|
if (!needsScrollMarkerRefresh) {
|
|
475
475
|
const element = needleScrollMarkerCache[index] || null;
|
|
476
|
-
|
|
476
|
+
return element;
|
|
477
477
|
}
|
|
478
478
|
needsScrollMarkerRefresh = false;
|
|
479
479
|
needleScrollMarkerCache.length = 0;
|
|
@@ -24,6 +24,8 @@ const debug = getParam("debugarcamera");
|
|
|
24
24
|
/**
|
|
25
25
|
* WebARCameraBackground is a component that allows to display the camera feed as a background in an AR session to more easily blend the real world with the virtual world or applying effects to the camera feed.
|
|
26
26
|
*
|
|
27
|
+
* - Example: https://samples.needle.tools/ar-camera-background
|
|
28
|
+
*
|
|
27
29
|
* @category XR
|
|
28
30
|
* @group Components
|
|
29
31
|
*/
|
|
@@ -20,7 +20,7 @@ const invertForwardMatrix = new Matrix4().makeRotationY(Math.PI);
|
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* 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.
|
|
23
|
+
* It is also responsible for scaling the user in AR and to define the center of the AR scene. If not present in the scene it will be created automatically by the WebXR component when entering an AR session.
|
|
24
24
|
*
|
|
25
25
|
* @example
|
|
26
26
|
* ```ts
|
|
@@ -27,6 +27,8 @@ const debugQuicklook = getParam("debugusdz");
|
|
|
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
|
*
|
|
30
|
+
* - Example: https://samples.needle.tools/collaborative-sandbox
|
|
31
|
+
*
|
|
30
32
|
* @example Enable VR and AR support using code
|
|
31
33
|
* ```ts
|
|
32
34
|
* import { onStart, WebXR } from "@needle-tools/engine";
|
|
@@ -290,6 +290,16 @@ class ImageTrackingExtension implements IUSDExporterExtension {
|
|
|
290
290
|
|
|
291
291
|
|
|
292
292
|
/**
|
|
293
|
+
* Add this component to a object to enable image tracking in WebXR sessions.
|
|
294
|
+
*
|
|
295
|
+
* You need to add at least one {@link WebXRImageTrackingModel} to the `trackedImages` array to define which images to track and which objects to place on top of them.
|
|
296
|
+
*
|
|
297
|
+
* **NOTE:** For Android devices, image tracking currently requires the user to enable the `chrome://flags/#webxr-incubations` flag in Chrome.
|
|
298
|
+
*
|
|
299
|
+
* **NOTE:** For iOS only one image can be tracked at a time. If you have multiple images in the `trackedImages` array, only the first one will be tracked. You can use the {@link setPrimaryImage} method to change which image is tracked before entering the XR session.
|
|
300
|
+
*
|
|
301
|
+
* - Example: https://samples.needle.tools/image-tracking
|
|
302
|
+
*
|
|
293
303
|
* @category XR
|
|
294
304
|
* @group Components
|
|
295
305
|
*/
|
|
@@ -313,7 +323,14 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
313
323
|
|
|
314
324
|
/**
|
|
315
325
|
* Add an image to track. If the image is already in the trackedImages array it won't be added again.
|
|
316
|
-
* Note: that adding images at runtime *while* in AR is not supported.
|
|
326
|
+
* Note: that adding images at runtime *while* in AR is not supported.
|
|
327
|
+
*
|
|
328
|
+
* @example
|
|
329
|
+
* ```ts
|
|
330
|
+
* const imageTracking = GameObject.getComponent(myGameObject, WebXRImageTracking);
|
|
331
|
+
* const image = new WebXRImageTrackingModel({ url: "https://example.com/my-marker.png", widthInMeters: 0.2, object: myObject });
|
|
332
|
+
* imageTracking.addImage(image, true); // add and set as primary image
|
|
333
|
+
* ```
|
|
317
334
|
*/
|
|
318
335
|
addImage(image: WebXRImageTrackingModel, asPrimary: boolean = false) {
|
|
319
336
|
if (!this.trackedImages.includes(image)) {
|
|
@@ -324,7 +341,11 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
324
341
|
}
|
|
325
342
|
|
|
326
343
|
|
|
327
|
-
|
|
344
|
+
/**
|
|
345
|
+
* List of images to track in the WebXR session. Use {@link WebXRImageTrackingModel} to define each image and the object to place on top of it.
|
|
346
|
+
*
|
|
347
|
+
* Use the `addImage()` and `setPrimaryImage()` methods to modify this array at runtime.
|
|
348
|
+
*/
|
|
328
349
|
@serializable(WebXRImageTrackingModel)
|
|
329
350
|
readonly trackedImages: WebXRImageTrackingModel[] = [];
|
|
330
351
|
|
|
@@ -339,6 +360,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
339
360
|
|
|
340
361
|
private _supported: boolean = true;
|
|
341
362
|
|
|
363
|
+
/** @internal */
|
|
342
364
|
awake(): void {
|
|
343
365
|
if (debug) console.log(this)
|
|
344
366
|
if (!this.trackedImages) return;
|
|
@@ -348,9 +370,11 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
348
370
|
}
|
|
349
371
|
}
|
|
350
372
|
}
|
|
373
|
+
/** @internal */
|
|
351
374
|
onEnable() {
|
|
352
375
|
USDZExporter.beforeExport.addEventListener(this.onBeforeUSDZExport);
|
|
353
376
|
}
|
|
377
|
+
/** @internal */
|
|
354
378
|
onDisable(): void {
|
|
355
379
|
USDZExporter.beforeExport.removeEventListener(this.onBeforeUSDZExport);
|
|
356
380
|
}
|
|
@@ -362,7 +386,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
362
386
|
}
|
|
363
387
|
|
|
364
388
|
|
|
365
|
-
|
|
389
|
+
/** @internal */
|
|
366
390
|
onBeforeXR(_mode: XRSessionMode, args: XRSessionInit & { trackedImages: Array<any> }): void {
|
|
367
391
|
// console.log("onXRRequested", args, this.trackedImages)
|
|
368
392
|
if (this.trackedImages) {
|
|
@@ -386,6 +410,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
386
410
|
}
|
|
387
411
|
}
|
|
388
412
|
|
|
413
|
+
/** @internal */
|
|
389
414
|
onEnterXR(_args: NeedleXREventArgs): void {
|
|
390
415
|
if (this.trackedImages) {
|
|
391
416
|
for (const trackedImage of this.trackedImages) {
|
|
@@ -408,6 +433,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
408
433
|
}
|
|
409
434
|
};
|
|
410
435
|
|
|
436
|
+
/** @internal */
|
|
411
437
|
onLeaveXR(_args: NeedleXREventArgs): void {
|
|
412
438
|
|
|
413
439
|
if (!this.supported && DeviceUtilities.isAndroidDevice()) {
|
|
@@ -440,6 +466,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
440
466
|
|
|
441
467
|
private readonly webXRIncubationsWarning = "Image tracking is currently not supported on this device. On Chrome for Android, you can enable the <a target=\"_blank\" href=\"#\" onclick=\"() => console.log('I')\">chrome://flags/#webxr-incubations</a> flag.";
|
|
442
468
|
|
|
469
|
+
/** @internal */
|
|
443
470
|
onUpdateXR(args: NeedleXREventArgs): void {
|
|
444
471
|
this.currentImages.length = 0;
|
|
445
472
|
|