@openusd-wasm/three-loader 0.0.1 → 0.0.2

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.
@@ -233,6 +233,18 @@ declare class USDManipulationControls {
233
233
  private restoreHighlight;
234
234
  }
235
235
  //#endregion
236
+ //#region src/asset-resolver.d.ts
237
+ declare function autoResolveAssetFiles(rootData: Uint8Array, options: USDLoaderParseOptions): Promise<Record<string, Uint8Array>>;
238
+ declare function autoResolveTextureFiles(metadata: USDModelData, existingFiles: Record<string, Uint8Array>, options: USDLoaderParseOptions): Promise<Record<string, Uint8Array>>;
239
+ declare function createTextureResolverFromEntries(entries: Map<string, Uint8Array>): {
240
+ resolve: USDTextureResolver;
241
+ urls: Map<string, string>;
242
+ } | null;
243
+ declare function createPackageTextureResolver(data: Uint8Array): {
244
+ resolve: USDTextureResolver;
245
+ urls: Map<string, string>;
246
+ } | null;
247
+ //#endregion
236
248
  //#region src/metadata.d.ts
237
249
  declare function extractUSDModelData(pxr: Pxr, stage: PxrObject, options?: ExtractUSDModelDataOptions): USDModelData;
238
250
  //#endregion
@@ -240,4 +252,4 @@ declare function extractUSDModelData(pxr: Pxr, stage: PxrObject, options?: Extra
240
252
  declare function buildUSDObject(data: USDModelData, options?: BuildUSDObjectOptions): THREE.Group;
241
253
  declare function createUSDLoadedModel(data: USDModelData, pxr: USDLoadedModel['pxr'], rootLayerIdentifier: string, options?: BuildUSDObjectOptions, stage?: unknown): USDLoadedModel;
242
254
  //#endregion
243
- export { type BuildUSDObjectOptions, type ExtractUSDModelDataOptions, type PxrObject, type USDAnimationInfo, type USDAssetValue, type USDFileExtension, type USDJointDriveInfo, type USDJointInfo, type USDLoadedModel, USDLoader, type USDLoaderOptions, type USDLoaderParseOptions, type USDManipulationChangeEvent, USDManipulationControls, type USDManipulationControlsOptions, type USDManipulationHoverEvent, type USDMaterialInfo, type USDMeshElement, type USDMeshGeometryData, type USDModelData, type USDShaderInfo, type USDSourceInput, type USDStageInfo, type USDTextureResolver, type USDTextureResolverContext, type USDTransformAnimation, type USDTransformAnimationSample, type USDVector2, type USDVector3, type USDVector4, type USDViewPrim, buildUSDObject, createUSDLoadedModel, extractUSDModelData };
255
+ export { type BuildUSDObjectOptions, type ExtractUSDModelDataOptions, type PxrObject, type USDAnimationInfo, type USDAssetValue, type USDFileExtension, type USDJointDriveInfo, type USDJointInfo, type USDLoadedModel, USDLoader, type USDLoaderOptions, type USDLoaderParseOptions, type USDManipulationChangeEvent, USDManipulationControls, type USDManipulationControlsOptions, type USDManipulationHoverEvent, type USDMaterialInfo, type USDMeshElement, type USDMeshGeometryData, type USDModelData, type USDShaderInfo, type USDSourceInput, type USDStageInfo, type USDTextureResolver, type USDTextureResolverContext, type USDTransformAnimation, type USDTransformAnimationSample, type USDVector2, type USDVector3, type USDVector4, type USDViewPrim, autoResolveAssetFiles, autoResolveTextureFiles, buildUSDObject, createPackageTextureResolver, createTextureResolverFromEntries, createUSDLoadedModel, extractUSDModelData };
@@ -13,7 +13,8 @@ const DEFAULT_ASSET_SEARCH_EXTENSIONS = [
13
13
  ".webp",
14
14
  ".ktx2",
15
15
  ".exr",
16
- ".hdr"
16
+ ".hdr",
17
+ ".mdl"
17
18
  ];
18
19
  const DEFAULT_ASSET_SEARCH_ROOTS = [
19
20
  "resource",
@@ -30,6 +31,20 @@ const DEFAULT_ASSET_SEARCH_ROOTS = [
30
31
  ];
31
32
  const DEFAULT_MAX_ASSET_REFERENCES = 80;
32
33
  const DEFAULT_MAX_ASSET_REFERENCE_DEPTH = 4;
34
+ const DEFAULT_PACKAGE_REMAP_ALIAS_COUNT = 16;
35
+ const USD_LAYER_EXTENSIONS = new Set([
36
+ ".usd",
37
+ ".usda",
38
+ ".usdc",
39
+ ".usdz"
40
+ ]);
41
+ const TEXTURE_DIRECTORY_NAMES = new Set([
42
+ "img",
43
+ "image",
44
+ "images",
45
+ "texture",
46
+ "textures"
47
+ ]);
33
48
  function toFetchableUrl(value) {
34
49
  try {
35
50
  const url = new URL(value, globalThis.location?.href);
@@ -91,8 +106,8 @@ function trimAssetReference(value) {
91
106
  if (/^[A-Za-z]:[\\/]/.test(ref)) return null;
92
107
  if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(ref)) return null;
93
108
  if (ref.startsWith("/")) return null;
94
- if (ref.includes("\0") || /\s/.test(ref)) return null;
95
- if (!/^[A-Za-z0-9._~!$&'()+,;=@/-]+$/.test(ref)) return null;
109
+ if (/[\0\r\n\t\f\v]/.test(ref)) return null;
110
+ if (!/^[ A-Za-z0-9._~!$&'()+,;=@/-]+$/.test(ref)) return null;
96
111
  return ref;
97
112
  }
98
113
  function isUsdCrate(data) {
@@ -192,6 +207,41 @@ function buildReferencePathVariants(relativePath) {
192
207
  aliases: [normalized]
193
208
  }];
194
209
  }
210
+ function buildPackageRemapAliases(sourceRelativePath, assetPath) {
211
+ const extension = extensionOf(assetPath);
212
+ if (!extension || USD_LAYER_EXTENSIONS.has(extension)) return [];
213
+ const name = baseName(assetPath);
214
+ if (!name) return [];
215
+ const aliasDirs = new Set([dirname(sourceRelativePath)]);
216
+ const assetDir = dirname(assetPath);
217
+ const assetParentDir = dirname(assetDir);
218
+ const assetTextureDir = baseName(assetDir).toLowerCase();
219
+ if (TEXTURE_DIRECTORY_NAMES.has(assetTextureDir)) aliasDirs.add(assetParentDir);
220
+ return unique([...aliasDirs].flatMap((aliasDir) => Array.from({ length: DEFAULT_PACKAGE_REMAP_ALIAS_COUNT }, (_, index) => joinRelativePath(aliasDir, `${index}/${name}`))));
221
+ }
222
+ function addPackageRemapAliases(files, aliases, data, ownedAliases, aliasConflicts, existingFiles = {}) {
223
+ for (const alias of aliases) {
224
+ if (aliasConflicts.has(alias)) continue;
225
+ const existingInput = existingFiles[alias];
226
+ if (existingInput && existingInput !== data) {
227
+ aliasConflicts.add(alias);
228
+ continue;
229
+ }
230
+ const existing = files[alias];
231
+ if (existing && existing !== data) {
232
+ if (ownedAliases.has(alias)) {
233
+ delete files[alias];
234
+ ownedAliases.delete(alias);
235
+ }
236
+ aliasConflicts.add(alias);
237
+ continue;
238
+ }
239
+ if (!existing) {
240
+ files[alias] = data;
241
+ ownedAliases.add(alias);
242
+ }
243
+ }
244
+ }
195
245
  function unique(values) {
196
246
  return [...new Set(values)];
197
247
  }
@@ -246,7 +296,9 @@ function buildFetchAttempts(ref, sourceUrl, sourceRelativePath, searchExtensions
246
296
  seen.add(url);
247
297
  attempts.push({
248
298
  url,
249
- fsPaths: [...fsAliases]
299
+ fsPaths: [...fsAliases],
300
+ sourceRelativePath: pathWithExtension,
301
+ packageRemapAliases: buildPackageRemapAliases(sourceRelativePath, pathWithExtension)
250
302
  });
251
303
  } catch {}
252
304
  }
@@ -273,6 +325,8 @@ async function autoResolveAssetFiles(rootData, options) {
273
325
  const maxDepth = options.maxAssetReferenceDepth ?? DEFAULT_MAX_ASSET_REFERENCE_DEPTH;
274
326
  const rootRelativePath = normalizeFsRelativePath(options.fileName ?? fileNameForSource$1(sourcePath));
275
327
  const files = {};
328
+ const ownedPackageAliases = /* @__PURE__ */ new Set();
329
+ const packageAliasConflicts = /* @__PURE__ */ new Set();
276
330
  const fetchedUrls = /* @__PURE__ */ new Set();
277
331
  const queued = /* @__PURE__ */ new Set();
278
332
  const rootRefs = discoverAssetReferences(rootData, searchExtensions, true);
@@ -294,9 +348,13 @@ async function autoResolveAssetFiles(rootData, options) {
294
348
  fetchedUrls.add(attempt.url);
295
349
  const data = await fetchBinary(attempt.url);
296
350
  if (!data) continue;
297
- for (const fsPath of attempt.fsPaths) files[fsPath] = data;
351
+ for (const fsPath of attempt.fsPaths) {
352
+ ownedPackageAliases.delete(fsPath);
353
+ files[fsPath] = data;
354
+ }
355
+ addPackageRemapAliases(files, attempt.packageRemapAliases, data, ownedPackageAliases, packageAliasConflicts);
298
356
  if (item.depth < maxDepth) {
299
- const sourceRelativePath = attempt.fsPaths.find((path) => extensionOf(path)) ?? attempt.fsPaths[0];
357
+ const sourceRelativePath = attempt.sourceRelativePath;
300
358
  if (sourceRelativePath) for (const ref of discoverAssetReferences(data, searchExtensions, !isUsdCrate(data))) {
301
359
  const queueKey = `${attempt.url}\n${ref}`;
302
360
  if (queued.has(queueKey)) continue;
@@ -317,27 +375,22 @@ async function autoResolveAssetFiles(rootData, options) {
317
375
  }
318
376
  return files;
319
377
  }
320
- function isTextureAssetReference(value) {
378
+ function isMetadataAssetReference(value, searchExtensions) {
321
379
  if (/^(blob|data):/i.test(value)) return false;
322
380
  if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(value)) return false;
323
381
  if (value.startsWith("/")) return false;
324
- return [
325
- ".png",
326
- ".jpg",
327
- ".jpeg",
328
- ".webp"
329
- ].includes(extensionOf(value));
382
+ return searchExtensions.includes(extensionOf(value));
330
383
  }
331
- function collectTextureAssetReferences(value, refs = /* @__PURE__ */ new Set()) {
384
+ function collectMetadataAssetReferences(value, searchExtensions, refs = /* @__PURE__ */ new Set()) {
332
385
  if (!value) return refs;
333
386
  if (Array.isArray(value)) {
334
- for (const item of value) collectTextureAssetReferences(item, refs);
387
+ for (const item of value) collectMetadataAssetReferences(item, searchExtensions, refs);
335
388
  return refs;
336
389
  }
337
390
  if (typeof value !== "object") return refs;
338
391
  const asset = value;
339
- for (const item of [asset.path, asset.url]) if (typeof item === "string" && isTextureAssetReference(item)) refs.add(item);
340
- for (const item of Object.values(value)) collectTextureAssetReferences(item, refs);
392
+ for (const item of [asset.path, asset.url]) if (typeof item === "string" && isMetadataAssetReference(item, searchExtensions)) refs.add(item);
393
+ for (const item of Object.values(value)) collectMetadataAssetReferences(item, searchExtensions, refs);
341
394
  return refs;
342
395
  }
343
396
  async function autoResolveTextureFiles(metadata, existingFiles, options) {
@@ -347,13 +400,15 @@ async function autoResolveTextureFiles(metadata, existingFiles, options) {
347
400
  if (!sourceUrl) return {};
348
401
  const searchExtensions = options.assetSearchExtensions ?? DEFAULT_ASSET_SEARCH_EXTENSIONS;
349
402
  const configuredSearchRoots = normalizeSearchRoots(options.assetSearchRoots);
350
- const textureRefs = [...collectTextureAssetReferences(metadata)];
403
+ const textureRefs = [...collectMetadataAssetReferences(metadata, searchExtensions)];
351
404
  const searchRoots = unique([...inferReferencedSearchRoots(Object.keys(existingFiles), configuredSearchRoots), ...inferReferencedSearchRoots(textureRefs, configuredSearchRoots)]);
352
405
  const maxFiles = options.maxAssetReferences ?? DEFAULT_MAX_ASSET_REFERENCES;
353
406
  const remainingFiles = Math.max(maxFiles - uniqueFileCount(existingFiles), 0);
354
407
  if (remainingFiles === 0) return {};
355
408
  const rootRelativePath = normalizeFsRelativePath(options.fileName ?? fileNameForSource$1(sourcePath));
356
409
  const files = {};
410
+ const ownedPackageAliases = /* @__PURE__ */ new Set();
411
+ const packageAliasConflicts = /* @__PURE__ */ new Set();
357
412
  const fetchedUrls = /* @__PURE__ */ new Set();
358
413
  let resolvedFiles = 0;
359
414
  for (const ref of textureRefs) {
@@ -364,7 +419,11 @@ async function autoResolveTextureFiles(metadata, existingFiles, options) {
364
419
  fetchedUrls.add(attempt.url);
365
420
  const data = await fetchBinary(attempt.url);
366
421
  if (!data) continue;
367
- for (const fsPath of attempt.fsPaths) files[fsPath] = data;
422
+ for (const fsPath of attempt.fsPaths) {
423
+ ownedPackageAliases.delete(fsPath);
424
+ files[fsPath] = data;
425
+ }
426
+ addPackageRemapAliases(files, attempt.packageRemapAliases, data, ownedPackageAliases, packageAliasConflicts, existingFiles);
368
427
  resolvedFiles += 1;
369
428
  break;
370
429
  }
@@ -462,6 +521,7 @@ const MATERIAL_INPUT_SUFFIXES = [
462
521
  "translation",
463
522
  "rotation"
464
523
  ];
524
+ const MATERIAL_ASSET_ATTRIBUTE_NAMES = new Set(["info:mdl:sourceAsset"]);
465
525
  const JOINT_TYPES = {
466
526
  PhysicsFixedJoint: "fixed",
467
527
  PhysicsRevoluteJoint: "revolute",
@@ -1034,8 +1094,7 @@ function collectShaderInputs(prim, time) {
1034
1094
  try {
1035
1095
  for (const attribute of attributes) {
1036
1096
  const name = String(attribute.GetName());
1037
- if (!name.includes("inputs:")) continue;
1038
- if (!MATERIAL_INPUT_SUFFIXES.some((suffix) => name.endsWith(suffix))) continue;
1097
+ if (!(name.includes("inputs:") && MATERIAL_INPUT_SUFFIXES.some((suffix) => name.endsWith(suffix))) && !MATERIAL_ASSET_ATTRIBUTE_NAMES.has(name)) continue;
1039
1098
  const value = attribute.Get(time);
1040
1099
  const connections = attribute.GetConnections();
1041
1100
  if (value !== null && value !== void 0) inputs[name] = normalizeValue(value);
@@ -2145,4 +2204,4 @@ var USDManipulationControls = class {
2145
2204
  }
2146
2205
  };
2147
2206
  //#endregion
2148
- export { USDLoader, USDManipulationControls, buildUSDObject, createUSDLoadedModel, extractUSDModelData };
2207
+ export { USDLoader, USDManipulationControls, autoResolveAssetFiles, autoResolveTextureFiles, buildUSDObject, createPackageTextureResolver, createTextureResolverFromEntries, createUSDLoadedModel, extractUSDModelData };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openusd-wasm/three-loader",
3
3
  "type": "module",
4
- "version": "0.0.1",
4
+ "version": "0.0.2",
5
5
  "description": "Three.js loader for OpenUSD assets backed by @openusd-wasm/pxr.",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/openusd-wasm/openusd-pxr-wasm",
@@ -35,7 +35,7 @@
35
35
  "tsdown": "^0.22.0",
36
36
  "typescript": "^6.0.3",
37
37
  "vitest": "^4.1.5",
38
- "@openusd-wasm/pxr": "0.0.1"
38
+ "@openusd-wasm/pxr": "0.0.2"
39
39
  },
40
40
  "publishConfig": {
41
41
  "access": "public"