@openusd-wasm/three-loader 0.0.2 → 0.0.3
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/README.md +12 -0
- package/dist/openusd_three_loader.d.ts +7 -27
- package/dist/openusd_three_loader.js +387 -846
- package/package.json +6 -4
|
@@ -1,506 +1,7 @@
|
|
|
1
1
|
import { createPxr } from "@openusd-wasm/pxr";
|
|
2
2
|
import * as THREE from "three";
|
|
3
3
|
import { FileLoader, Loader } from "three";
|
|
4
|
-
|
|
5
|
-
const DEFAULT_ASSET_SEARCH_EXTENSIONS = [
|
|
6
|
-
".usd",
|
|
7
|
-
".usda",
|
|
8
|
-
".usdc",
|
|
9
|
-
".usdz",
|
|
10
|
-
".png",
|
|
11
|
-
".jpg",
|
|
12
|
-
".jpeg",
|
|
13
|
-
".webp",
|
|
14
|
-
".ktx2",
|
|
15
|
-
".exr",
|
|
16
|
-
".hdr",
|
|
17
|
-
".mdl"
|
|
18
|
-
];
|
|
19
|
-
const DEFAULT_ASSET_SEARCH_ROOTS = [
|
|
20
|
-
"resource",
|
|
21
|
-
"resources",
|
|
22
|
-
"asset",
|
|
23
|
-
"assets",
|
|
24
|
-
"img",
|
|
25
|
-
"image",
|
|
26
|
-
"images",
|
|
27
|
-
"texture",
|
|
28
|
-
"textures",
|
|
29
|
-
"material",
|
|
30
|
-
"materials"
|
|
31
|
-
];
|
|
32
|
-
const DEFAULT_MAX_ASSET_REFERENCES = 80;
|
|
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
|
-
]);
|
|
48
|
-
function toFetchableUrl(value) {
|
|
49
|
-
try {
|
|
50
|
-
const url = new URL(value, globalThis.location?.href);
|
|
51
|
-
return url.protocol === "http:" || url.protocol === "https:" || url.protocol === "file:" ? url.href : null;
|
|
52
|
-
} catch {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
function normalizeFsRelativePath(path) {
|
|
57
|
-
const parts = [];
|
|
58
|
-
for (const part of path.replaceAll("\\", "/").split("/")) {
|
|
59
|
-
if (!part || part === ".") continue;
|
|
60
|
-
if (part === "..") {
|
|
61
|
-
parts.pop();
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
parts.push(part);
|
|
65
|
-
}
|
|
66
|
-
return parts.join("/");
|
|
67
|
-
}
|
|
68
|
-
function dirname(path) {
|
|
69
|
-
const normalized = normalizeFsRelativePath(path);
|
|
70
|
-
const index = normalized.lastIndexOf("/");
|
|
71
|
-
return index === -1 ? "" : normalized.slice(0, index);
|
|
72
|
-
}
|
|
73
|
-
function joinRelativePath(base, path) {
|
|
74
|
-
return normalizeFsRelativePath(base ? `${base}/${path}` : path);
|
|
75
|
-
}
|
|
76
|
-
function extensionOf(path) {
|
|
77
|
-
const match = /\.([A-Za-z0-9]+)$/.exec(path.split(/[?#]/)[0] ?? path);
|
|
78
|
-
return match ? `.${match[1]?.toLowerCase()}` : "";
|
|
79
|
-
}
|
|
80
|
-
function contentTypeForPath(path) {
|
|
81
|
-
switch (extensionOf(path)) {
|
|
82
|
-
case ".png": return "image/png";
|
|
83
|
-
case ".jpg":
|
|
84
|
-
case ".jpeg": return "image/jpeg";
|
|
85
|
-
case ".webp": return "image/webp";
|
|
86
|
-
default: return "application/octet-stream";
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
function baseName(path) {
|
|
90
|
-
return normalizeFsRelativePath(path).split("/").pop() ?? "";
|
|
91
|
-
}
|
|
92
|
-
function fileNameForSource$1(sourcePath) {
|
|
93
|
-
const name = (sourcePath.split(/[?#]/)[0] ?? sourcePath).split("/").filter(Boolean).pop();
|
|
94
|
-
return name && /\.[a-z0-9]+$/i.test(name) ? name : "scene.usda";
|
|
95
|
-
}
|
|
96
|
-
function toArrayBuffer(data) {
|
|
97
|
-
const buffer = new ArrayBuffer(data.byteLength);
|
|
98
|
-
new Uint8Array(buffer).set(data);
|
|
99
|
-
return buffer;
|
|
100
|
-
}
|
|
101
|
-
function trimAssetReference(value) {
|
|
102
|
-
let ref = value.trim();
|
|
103
|
-
if (!ref || ref.length > 220) return null;
|
|
104
|
-
ref = ref.replace(/^[@<"']+/, "").replace(/[@>"')\]},;]+$/g, "");
|
|
105
|
-
if (!ref || ref.startsWith("#") || ref.startsWith("$")) return null;
|
|
106
|
-
if (/^[A-Za-z]:[\\/]/.test(ref)) return null;
|
|
107
|
-
if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(ref)) return null;
|
|
108
|
-
if (ref.startsWith("/")) return null;
|
|
109
|
-
if (/[\0\r\n\t\f\v]/.test(ref)) return null;
|
|
110
|
-
if (!/^[ A-Za-z0-9._~!$&'()+,;=@/-]+$/.test(ref)) return null;
|
|
111
|
-
return ref;
|
|
112
|
-
}
|
|
113
|
-
function isUsdCrate(data) {
|
|
114
|
-
return data[0] === 80 && data[1] === 88 && data[2] === 82 && data[3] === 45 && data[4] === 85 && data[5] === 83 && data[6] === 68 && data[7] === 67;
|
|
115
|
-
}
|
|
116
|
-
function startsWithAssetSearchRoot(value) {
|
|
117
|
-
return /^(resource|resources|asset|assets|img|image|images|texture|textures|material|materials)(\/|$)/i.test(value);
|
|
118
|
-
}
|
|
119
|
-
function startsWithAssetSearchRootPath(value) {
|
|
120
|
-
const normalized = normalizeFsRelativePath(value);
|
|
121
|
-
return normalized.includes("/") && startsWithAssetSearchRoot(normalized);
|
|
122
|
-
}
|
|
123
|
-
function looksLikeExtensionlessAssetPath(value) {
|
|
124
|
-
const parts = normalizeFsRelativePath(value).split("/");
|
|
125
|
-
if (parts.length < 2 || parts.length > 3) return false;
|
|
126
|
-
if (parts.some((part) => part.length < 2 || part.length > 80)) return false;
|
|
127
|
-
if (parts.some((part) => part.startsWith("."))) return false;
|
|
128
|
-
if (parts.some((part) => !/^[A-Za-z0-9._-]+$/.test(part))) return false;
|
|
129
|
-
if (!/_/.test(value) || !/\d/.test(value)) return false;
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
function looksLikeKnownExtensionlessAsset(value) {
|
|
133
|
-
const normalized = normalizeFsRelativePath(value);
|
|
134
|
-
if (!normalized.includes("/")) return false;
|
|
135
|
-
return [
|
|
136
|
-
"material",
|
|
137
|
-
"model",
|
|
138
|
-
"scene"
|
|
139
|
-
].includes(baseName(normalized).toLowerCase());
|
|
140
|
-
}
|
|
141
|
-
function looksLikeAssetReference(value, searchExtensions, includeExtensionlessAssetPaths, wholeString) {
|
|
142
|
-
const extension = extensionOf(value);
|
|
143
|
-
if (extension) {
|
|
144
|
-
if (!searchExtensions.includes(extension)) return false;
|
|
145
|
-
const name = baseName(value);
|
|
146
|
-
if (name === extension) return false;
|
|
147
|
-
if (wholeString && !value.startsWith("./") && !value.startsWith("../") && !value.includes("/")) return name.length >= 8;
|
|
148
|
-
return true;
|
|
149
|
-
}
|
|
150
|
-
if (value.startsWith("./") || value.startsWith("../")) {
|
|
151
|
-
const relative = normalizeFsRelativePath(value);
|
|
152
|
-
if (startsWithAssetSearchRootPath(relative)) return looksLikeExtensionlessAssetPath(relative) || looksLikeKnownExtensionlessAsset(relative);
|
|
153
|
-
return looksLikeExtensionlessAssetPath(relative);
|
|
154
|
-
}
|
|
155
|
-
if (startsWithAssetSearchRootPath(value)) return looksLikeExtensionlessAssetPath(value) || looksLikeKnownExtensionlessAsset(value);
|
|
156
|
-
return includeExtensionlessAssetPaths && looksLikeExtensionlessAssetPath(value);
|
|
157
|
-
}
|
|
158
|
-
function extractAsciiStrings(data) {
|
|
159
|
-
const strings = [];
|
|
160
|
-
let current = "";
|
|
161
|
-
for (const byte of data) if (byte >= 32 && byte <= 126) current += String.fromCharCode(byte);
|
|
162
|
-
else {
|
|
163
|
-
if (current.length >= 4) strings.push(current);
|
|
164
|
-
current = "";
|
|
165
|
-
}
|
|
166
|
-
if (current.length >= 4) strings.push(current);
|
|
167
|
-
return strings;
|
|
168
|
-
}
|
|
169
|
-
function discoverAssetReferences(data, searchExtensions, includeExtensionlessAssetPaths = false) {
|
|
170
|
-
const out = /* @__PURE__ */ new Set();
|
|
171
|
-
for (const text of extractAsciiStrings(data)) {
|
|
172
|
-
const whole = trimAssetReference(text);
|
|
173
|
-
if (whole && looksLikeAssetReference(whole, searchExtensions, includeExtensionlessAssetPaths, true)) out.add(whole);
|
|
174
|
-
for (const match of text.matchAll(/@([^@\n\r]+)@/g)) {
|
|
175
|
-
const ref = trimAssetReference(match[1] ?? "");
|
|
176
|
-
if (ref && looksLikeAssetReference(ref, searchExtensions, includeExtensionlessAssetPaths, false)) out.add(ref);
|
|
177
|
-
}
|
|
178
|
-
for (const match of text.matchAll(/["']([^"'\n\r]+\.(?:usd|usda|usdc|usdz|png|jpe?g|webp|ktx2|exr|hdr|mdl))["']/gi)) {
|
|
179
|
-
const ref = trimAssetReference(match[1] ?? "");
|
|
180
|
-
if (ref && looksLikeAssetReference(ref, searchExtensions, includeExtensionlessAssetPaths, false)) out.add(ref);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return [...out];
|
|
184
|
-
}
|
|
185
|
-
function discoverAssetSearchRoots(data, searchRoots) {
|
|
186
|
-
const out = /* @__PURE__ */ new Set();
|
|
187
|
-
const rootSet = new Set(searchRoots);
|
|
188
|
-
for (const text of extractAsciiStrings(data)) {
|
|
189
|
-
const ref = trimAssetReference(text);
|
|
190
|
-
if (!ref) continue;
|
|
191
|
-
const segment = firstPathSegment(ref);
|
|
192
|
-
if (rootSet.has(segment) && normalizeFsRelativePath(ref).includes("/")) out.add(segment);
|
|
193
|
-
}
|
|
194
|
-
return [...out];
|
|
195
|
-
}
|
|
196
|
-
function buildExtensionVariants(path, searchExtensions) {
|
|
197
|
-
const normalized = normalizeFsRelativePath(path);
|
|
198
|
-
if (!normalized) return [];
|
|
199
|
-
if (extensionOf(normalized)) return [normalized];
|
|
200
|
-
return [...searchExtensions.map((extension) => `${normalized}${extension}`), normalized];
|
|
201
|
-
}
|
|
202
|
-
function buildReferencePathVariants(relativePath) {
|
|
203
|
-
const normalized = normalizeFsRelativePath(relativePath);
|
|
204
|
-
if (!normalized) return [];
|
|
205
|
-
return [{
|
|
206
|
-
path: normalized,
|
|
207
|
-
aliases: [normalized]
|
|
208
|
-
}];
|
|
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
|
-
}
|
|
245
|
-
function unique(values) {
|
|
246
|
-
return [...new Set(values)];
|
|
247
|
-
}
|
|
248
|
-
function uniqueFileCount(files) {
|
|
249
|
-
return new Set(Object.values(files)).size;
|
|
250
|
-
}
|
|
251
|
-
function firstPathSegment(path) {
|
|
252
|
-
return normalizeFsRelativePath(path).split("/")[0] ?? "";
|
|
253
|
-
}
|
|
254
|
-
function normalizeSearchRoots(roots) {
|
|
255
|
-
return unique((roots ?? DEFAULT_ASSET_SEARCH_ROOTS).map((root) => normalizeFsRelativePath(root)).filter(Boolean));
|
|
256
|
-
}
|
|
257
|
-
function inferReferencedSearchRoots(refs, searchRoots) {
|
|
258
|
-
const rootSet = new Set(searchRoots);
|
|
259
|
-
return unique(refs.map((ref) => firstPathSegment(ref)).filter((segment) => rootSet.has(segment)));
|
|
260
|
-
}
|
|
261
|
-
function buildFetchAttempts(ref, sourceUrl, sourceRelativePath, searchExtensions, rootSourceUrl, searchRoots) {
|
|
262
|
-
const sourceDir = dirname(sourceRelativePath);
|
|
263
|
-
const attempts = [];
|
|
264
|
-
const seen = /* @__PURE__ */ new Set();
|
|
265
|
-
const normalizedRef = normalizeFsRelativePath(ref);
|
|
266
|
-
const isDotRelative = /^\.{1,2}\//.test(ref);
|
|
267
|
-
const candidates = [];
|
|
268
|
-
function addCandidate(fsPath, fetchPath, baseUrl, aliases = []) {
|
|
269
|
-
const normalizedFsPath = normalizeFsRelativePath(fsPath);
|
|
270
|
-
if (!normalizedFsPath) return;
|
|
271
|
-
candidates.push({
|
|
272
|
-
fsPath: normalizedFsPath,
|
|
273
|
-
fetchPath,
|
|
274
|
-
baseUrl,
|
|
275
|
-
aliases: unique([
|
|
276
|
-
normalizedRef,
|
|
277
|
-
normalizedFsPath,
|
|
278
|
-
...aliases
|
|
279
|
-
].filter(Boolean))
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
if (!isDotRelative) {
|
|
283
|
-
for (const root of searchRoots) if (normalizedRef !== root && !normalizedRef.startsWith(`${root}/`)) addCandidate(`${root}/${normalizedRef}`, `${root}/${normalizedRef}`, rootSourceUrl);
|
|
284
|
-
}
|
|
285
|
-
addCandidate(joinRelativePath(sourceDir, ref), ref, sourceUrl);
|
|
286
|
-
if (!isDotRelative && sourceDir) addCandidate(normalizedRef, normalizedRef, rootSourceUrl);
|
|
287
|
-
for (const candidate of candidates) for (const variant of buildReferencePathVariants(candidate.fsPath)) {
|
|
288
|
-
const fsAliases = new Set([...candidate.aliases, ...variant.aliases]);
|
|
289
|
-
for (const pathWithExtension of buildExtensionVariants(variant.path, searchExtensions)) {
|
|
290
|
-
const extension = extensionOf(pathWithExtension);
|
|
291
|
-
fsAliases.add(pathWithExtension);
|
|
292
|
-
const fetchPath = extensionOf(candidate.fetchPath) ? candidate.fetchPath : `${candidate.fetchPath}${extension}`;
|
|
293
|
-
try {
|
|
294
|
-
const url = new URL(fetchPath, candidate.baseUrl).href;
|
|
295
|
-
if (seen.has(url)) continue;
|
|
296
|
-
seen.add(url);
|
|
297
|
-
attempts.push({
|
|
298
|
-
url,
|
|
299
|
-
fsPaths: [...fsAliases],
|
|
300
|
-
sourceRelativePath: pathWithExtension,
|
|
301
|
-
packageRemapAliases: buildPackageRemapAliases(sourceRelativePath, pathWithExtension)
|
|
302
|
-
});
|
|
303
|
-
} catch {}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
return attempts;
|
|
307
|
-
}
|
|
308
|
-
async function fetchBinary(url) {
|
|
309
|
-
try {
|
|
310
|
-
const response = await fetch(url);
|
|
311
|
-
if (!response.ok) return null;
|
|
312
|
-
return new Uint8Array(await response.arrayBuffer());
|
|
313
|
-
} catch {
|
|
314
|
-
return null;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
async function autoResolveAssetFiles(rootData, options) {
|
|
318
|
-
const sourcePath = options.sourcePath ?? "";
|
|
319
|
-
if (options.autoResolveAssets === false || !sourcePath) return {};
|
|
320
|
-
const sourceUrl = toFetchableUrl(sourcePath);
|
|
321
|
-
if (!sourceUrl) return {};
|
|
322
|
-
const searchExtensions = options.assetSearchExtensions ?? DEFAULT_ASSET_SEARCH_EXTENSIONS;
|
|
323
|
-
const configuredSearchRoots = normalizeSearchRoots(options.assetSearchRoots);
|
|
324
|
-
const maxFiles = options.maxAssetReferences ?? DEFAULT_MAX_ASSET_REFERENCES;
|
|
325
|
-
const maxDepth = options.maxAssetReferenceDepth ?? DEFAULT_MAX_ASSET_REFERENCE_DEPTH;
|
|
326
|
-
const rootRelativePath = normalizeFsRelativePath(options.fileName ?? fileNameForSource$1(sourcePath));
|
|
327
|
-
const files = {};
|
|
328
|
-
const ownedPackageAliases = /* @__PURE__ */ new Set();
|
|
329
|
-
const packageAliasConflicts = /* @__PURE__ */ new Set();
|
|
330
|
-
const fetchedUrls = /* @__PURE__ */ new Set();
|
|
331
|
-
const queued = /* @__PURE__ */ new Set();
|
|
332
|
-
const rootRefs = discoverAssetReferences(rootData, searchExtensions, true);
|
|
333
|
-
const inferredSearchRoots = unique([...inferReferencedSearchRoots(rootRefs, configuredSearchRoots), ...discoverAssetSearchRoots(rootData, configuredSearchRoots)]);
|
|
334
|
-
const queue = rootRefs.map((ref) => ({
|
|
335
|
-
ref,
|
|
336
|
-
sourceUrl,
|
|
337
|
-
rootSourceUrl: sourceUrl,
|
|
338
|
-
sourceRelativePath: rootRelativePath,
|
|
339
|
-
searchRoots: inferredSearchRoots,
|
|
340
|
-
depth: 0
|
|
341
|
-
}));
|
|
342
|
-
for (const item of queue) queued.add(`${item.sourceUrl}\n${item.ref}`);
|
|
343
|
-
while (queue.length > 0 && uniqueFileCount(files) < maxFiles) {
|
|
344
|
-
const item = queue.shift();
|
|
345
|
-
if (!item || item.depth > maxDepth) continue;
|
|
346
|
-
for (const attempt of buildFetchAttempts(item.ref, item.sourceUrl, item.sourceRelativePath, searchExtensions, item.rootSourceUrl, item.searchRoots)) {
|
|
347
|
-
if (fetchedUrls.has(attempt.url)) continue;
|
|
348
|
-
fetchedUrls.add(attempt.url);
|
|
349
|
-
const data = await fetchBinary(attempt.url);
|
|
350
|
-
if (!data) continue;
|
|
351
|
-
for (const fsPath of attempt.fsPaths) {
|
|
352
|
-
ownedPackageAliases.delete(fsPath);
|
|
353
|
-
files[fsPath] = data;
|
|
354
|
-
}
|
|
355
|
-
addPackageRemapAliases(files, attempt.packageRemapAliases, data, ownedPackageAliases, packageAliasConflicts);
|
|
356
|
-
if (item.depth < maxDepth) {
|
|
357
|
-
const sourceRelativePath = attempt.sourceRelativePath;
|
|
358
|
-
if (sourceRelativePath) for (const ref of discoverAssetReferences(data, searchExtensions, !isUsdCrate(data))) {
|
|
359
|
-
const queueKey = `${attempt.url}\n${ref}`;
|
|
360
|
-
if (queued.has(queueKey)) continue;
|
|
361
|
-
queued.add(queueKey);
|
|
362
|
-
const nestedSearchRoots = unique([...item.searchRoots, ...inferReferencedSearchRoots([sourceRelativePath], configuredSearchRoots)]);
|
|
363
|
-
queue.push({
|
|
364
|
-
ref,
|
|
365
|
-
sourceUrl: attempt.url,
|
|
366
|
-
rootSourceUrl: item.rootSourceUrl,
|
|
367
|
-
sourceRelativePath,
|
|
368
|
-
searchRoots: nestedSearchRoots,
|
|
369
|
-
depth: item.depth + 1
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
break;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
return files;
|
|
377
|
-
}
|
|
378
|
-
function isMetadataAssetReference(value, searchExtensions) {
|
|
379
|
-
if (/^(blob|data):/i.test(value)) return false;
|
|
380
|
-
if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(value)) return false;
|
|
381
|
-
if (value.startsWith("/")) return false;
|
|
382
|
-
return searchExtensions.includes(extensionOf(value));
|
|
383
|
-
}
|
|
384
|
-
function collectMetadataAssetReferences(value, searchExtensions, refs = /* @__PURE__ */ new Set()) {
|
|
385
|
-
if (!value) return refs;
|
|
386
|
-
if (Array.isArray(value)) {
|
|
387
|
-
for (const item of value) collectMetadataAssetReferences(item, searchExtensions, refs);
|
|
388
|
-
return refs;
|
|
389
|
-
}
|
|
390
|
-
if (typeof value !== "object") return refs;
|
|
391
|
-
const asset = value;
|
|
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);
|
|
394
|
-
return refs;
|
|
395
|
-
}
|
|
396
|
-
async function autoResolveTextureFiles(metadata, existingFiles, options) {
|
|
397
|
-
const sourcePath = options.sourcePath ?? "";
|
|
398
|
-
if (options.autoResolveAssets === false || !sourcePath) return {};
|
|
399
|
-
const sourceUrl = toFetchableUrl(sourcePath);
|
|
400
|
-
if (!sourceUrl) return {};
|
|
401
|
-
const searchExtensions = options.assetSearchExtensions ?? DEFAULT_ASSET_SEARCH_EXTENSIONS;
|
|
402
|
-
const configuredSearchRoots = normalizeSearchRoots(options.assetSearchRoots);
|
|
403
|
-
const textureRefs = [...collectMetadataAssetReferences(metadata, searchExtensions)];
|
|
404
|
-
const searchRoots = unique([...inferReferencedSearchRoots(Object.keys(existingFiles), configuredSearchRoots), ...inferReferencedSearchRoots(textureRefs, configuredSearchRoots)]);
|
|
405
|
-
const maxFiles = options.maxAssetReferences ?? DEFAULT_MAX_ASSET_REFERENCES;
|
|
406
|
-
const remainingFiles = Math.max(maxFiles - uniqueFileCount(existingFiles), 0);
|
|
407
|
-
if (remainingFiles === 0) return {};
|
|
408
|
-
const rootRelativePath = normalizeFsRelativePath(options.fileName ?? fileNameForSource$1(sourcePath));
|
|
409
|
-
const files = {};
|
|
410
|
-
const ownedPackageAliases = /* @__PURE__ */ new Set();
|
|
411
|
-
const packageAliasConflicts = /* @__PURE__ */ new Set();
|
|
412
|
-
const fetchedUrls = /* @__PURE__ */ new Set();
|
|
413
|
-
let resolvedFiles = 0;
|
|
414
|
-
for (const ref of textureRefs) {
|
|
415
|
-
if (resolvedFiles >= remainingFiles) break;
|
|
416
|
-
for (const attempt of buildFetchAttempts(ref, sourceUrl, rootRelativePath, searchExtensions, sourceUrl, searchRoots)) {
|
|
417
|
-
if (attempt.fsPaths.some((path) => existingFiles[path] || files[path])) break;
|
|
418
|
-
if (fetchedUrls.has(attempt.url)) continue;
|
|
419
|
-
fetchedUrls.add(attempt.url);
|
|
420
|
-
const data = await fetchBinary(attempt.url);
|
|
421
|
-
if (!data) continue;
|
|
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);
|
|
427
|
-
resolvedFiles += 1;
|
|
428
|
-
break;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
return files;
|
|
432
|
-
}
|
|
433
|
-
function readZipEntryName(data, start, length) {
|
|
434
|
-
return new TextDecoder().decode(data.subarray(start, start + length));
|
|
435
|
-
}
|
|
436
|
-
function extractStoredZipEntries(data) {
|
|
437
|
-
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
438
|
-
const entries = /* @__PURE__ */ new Map();
|
|
439
|
-
let offset = 0;
|
|
440
|
-
while (offset + 30 <= data.byteLength) {
|
|
441
|
-
if (view.getUint32(offset, true) !== 67324752) break;
|
|
442
|
-
const method = view.getUint16(offset + 8, true);
|
|
443
|
-
const compressedSize = view.getUint32(offset + 18, true);
|
|
444
|
-
const fileNameLength = view.getUint16(offset + 26, true);
|
|
445
|
-
const extraLength = view.getUint16(offset + 28, true);
|
|
446
|
-
const nameStart = offset + 30;
|
|
447
|
-
const dataStart = nameStart + fileNameLength + extraLength;
|
|
448
|
-
const dataEnd = dataStart + compressedSize;
|
|
449
|
-
if (dataEnd > data.byteLength) break;
|
|
450
|
-
const name = normalizeFsRelativePath(readZipEntryName(data, nameStart, fileNameLength));
|
|
451
|
-
if (name && method === 0) entries.set(name, data.slice(dataStart, dataEnd));
|
|
452
|
-
offset = dataEnd;
|
|
453
|
-
}
|
|
454
|
-
return entries;
|
|
455
|
-
}
|
|
456
|
-
function createTextureResolverFromEntries(entries) {
|
|
457
|
-
if (typeof Blob === "undefined" || typeof URL === "undefined" || typeof URL.createObjectURL !== "function") return null;
|
|
458
|
-
const imageEntries = new Map([...entries].filter(([path]) => [
|
|
459
|
-
".png",
|
|
460
|
-
".jpg",
|
|
461
|
-
".jpeg",
|
|
462
|
-
".webp"
|
|
463
|
-
].includes(extensionOf(path))));
|
|
464
|
-
if (imageEntries.size === 0) return null;
|
|
465
|
-
const byBaseName = /* @__PURE__ */ new Map();
|
|
466
|
-
for (const path of imageEntries.keys()) {
|
|
467
|
-
const name = baseName(path);
|
|
468
|
-
byBaseName.set(name, byBaseName.has(name) ? null : path);
|
|
469
|
-
}
|
|
470
|
-
const urls = /* @__PURE__ */ new Map();
|
|
471
|
-
const urlForEntry = (path) => {
|
|
472
|
-
const entry = imageEntries.get(path);
|
|
473
|
-
if (!entry) return null;
|
|
474
|
-
let url = urls.get(path);
|
|
475
|
-
if (!url) {
|
|
476
|
-
url = URL.createObjectURL(new Blob([toArrayBuffer(entry)], { type: contentTypeForPath(path) }));
|
|
477
|
-
urls.set(path, url);
|
|
478
|
-
}
|
|
479
|
-
return url;
|
|
480
|
-
};
|
|
481
|
-
const resolvePath = (value) => {
|
|
482
|
-
if (!value) return null;
|
|
483
|
-
const normalized = normalizeFsRelativePath(value.split(/[?#]/)[0] ?? value);
|
|
484
|
-
if (!normalized) return null;
|
|
485
|
-
if (imageEntries.has(normalized)) return urlForEntry(normalized);
|
|
486
|
-
const suffixMatches = [...imageEntries.keys()].filter((path) => path.endsWith(`/${normalized}`));
|
|
487
|
-
if (suffixMatches.length === 1 && suffixMatches[0]) return urlForEntry(suffixMatches[0]);
|
|
488
|
-
const virtualFsMatches = [...imageEntries.keys()].filter((path) => normalized.endsWith(`/${path}`));
|
|
489
|
-
if (virtualFsMatches.length === 1 && virtualFsMatches[0]) return urlForEntry(virtualFsMatches[0]);
|
|
490
|
-
const uniqueBaseName = byBaseName.get(baseName(normalized));
|
|
491
|
-
return uniqueBaseName ? urlForEntry(uniqueBaseName) : null;
|
|
492
|
-
};
|
|
493
|
-
return {
|
|
494
|
-
urls,
|
|
495
|
-
resolve(asset) {
|
|
496
|
-
return resolvePath(asset.resolvedPath) ?? resolvePath(asset.path) ?? resolvePath(asset.url) ?? null;
|
|
497
|
-
}
|
|
498
|
-
};
|
|
499
|
-
}
|
|
500
|
-
function createPackageTextureResolver(data) {
|
|
501
|
-
return createTextureResolverFromEntries(extractStoredZipEntries(data));
|
|
502
|
-
}
|
|
503
|
-
//#endregion
|
|
4
|
+
import { autoResolveAssetFiles, autoResolveTextureFiles, createPackageTextureResolver, createTextureResolverFromEntries, findPackageRootLayer } from "@openusd-wasm/utils";
|
|
504
5
|
//#region src/metadata.ts
|
|
505
6
|
const MATERIAL_INPUT_SUFFIXES = [
|
|
506
7
|
"diffuseColor",
|
|
@@ -517,11 +18,13 @@ const MATERIAL_INPUT_SUFFIXES = [
|
|
|
517
18
|
"file",
|
|
518
19
|
"wrapS",
|
|
519
20
|
"wrapT",
|
|
21
|
+
"st",
|
|
22
|
+
"in",
|
|
23
|
+
"varname",
|
|
520
24
|
"scale",
|
|
521
25
|
"translation",
|
|
522
26
|
"rotation"
|
|
523
27
|
];
|
|
524
|
-
const MATERIAL_ASSET_ATTRIBUTE_NAMES = new Set(["info:mdl:sourceAsset"]);
|
|
525
28
|
const JOINT_TYPES = {
|
|
526
29
|
PhysicsFixedJoint: "fixed",
|
|
527
30
|
PhysicsRevoluteJoint: "revolute",
|
|
@@ -536,6 +39,13 @@ function dispose$1(value) {
|
|
|
536
39
|
function disposeAll(values) {
|
|
537
40
|
for (let i = values.length - 1; i >= 0; --i) dispose$1(values[i]);
|
|
538
41
|
}
|
|
42
|
+
function pathToString(path) {
|
|
43
|
+
if (path && typeof path === "object") {
|
|
44
|
+
const maybePath = path;
|
|
45
|
+
if (typeof maybePath.GetString === "function") return String(maybePath.GetString());
|
|
46
|
+
}
|
|
47
|
+
return String(path);
|
|
48
|
+
}
|
|
539
49
|
function isValid$1(value) {
|
|
540
50
|
if (!value) return false;
|
|
541
51
|
if (typeof value.IsValid === "function") return Boolean(value.IsValid());
|
|
@@ -593,170 +103,24 @@ function toVector4(value) {
|
|
|
593
103
|
}
|
|
594
104
|
return null;
|
|
595
105
|
}
|
|
596
|
-
function identityMatrix() {
|
|
597
|
-
return [
|
|
598
|
-
1,
|
|
599
|
-
0,
|
|
600
|
-
0,
|
|
601
|
-
0,
|
|
602
|
-
0,
|
|
603
|
-
1,
|
|
604
|
-
0,
|
|
605
|
-
0,
|
|
606
|
-
0,
|
|
607
|
-
0,
|
|
608
|
-
1,
|
|
609
|
-
0,
|
|
610
|
-
0,
|
|
611
|
-
0,
|
|
612
|
-
0,
|
|
613
|
-
1
|
|
614
|
-
];
|
|
615
|
-
}
|
|
616
|
-
function multiplyMatrices(a, b) {
|
|
617
|
-
const out = new Array(16).fill(0);
|
|
618
|
-
for (let row = 0; row < 4; row += 1) for (let column = 0; column < 4; column += 1) out[row * 4 + column] = (a[row * 4] ?? 0) * (b[column] ?? 0) + (a[row * 4 + 1] ?? 0) * (b[4 + column] ?? 0) + (a[row * 4 + 2] ?? 0) * (b[8 + column] ?? 0) + (a[row * 4 + 3] ?? 0) * (b[12 + column] ?? 0);
|
|
619
|
-
return out;
|
|
620
|
-
}
|
|
621
106
|
function matricesNearlyEqual(a, b) {
|
|
622
107
|
if (!a || !b || a.length < 16 || b.length < 16) return false;
|
|
623
108
|
return a.every((value, index) => Math.abs(value - (b[index] ?? 0)) < 1e-8);
|
|
624
109
|
}
|
|
625
|
-
function matrixFromXformOp(opName, value) {
|
|
626
|
-
const numbers = toNumberArray(value);
|
|
627
|
-
if (numbers.length === 0) return null;
|
|
628
|
-
if (opName.startsWith("xformOp:transform")) return numbers.length >= 16 ? numbers.slice(0, 16) : null;
|
|
629
|
-
if (opName.startsWith("xformOp:translate")) return [
|
|
630
|
-
1,
|
|
631
|
-
0,
|
|
632
|
-
0,
|
|
633
|
-
0,
|
|
634
|
-
0,
|
|
635
|
-
1,
|
|
636
|
-
0,
|
|
637
|
-
0,
|
|
638
|
-
0,
|
|
639
|
-
0,
|
|
640
|
-
1,
|
|
641
|
-
0,
|
|
642
|
-
numbers[0] ?? 0,
|
|
643
|
-
numbers[1] ?? 0,
|
|
644
|
-
numbers[2] ?? 0,
|
|
645
|
-
1
|
|
646
|
-
];
|
|
647
|
-
if (opName.startsWith("xformOp:scale")) return [
|
|
648
|
-
numbers[0] ?? 1,
|
|
649
|
-
0,
|
|
650
|
-
0,
|
|
651
|
-
0,
|
|
652
|
-
0,
|
|
653
|
-
numbers[1] ?? numbers[0] ?? 1,
|
|
654
|
-
0,
|
|
655
|
-
0,
|
|
656
|
-
0,
|
|
657
|
-
0,
|
|
658
|
-
numbers[2] ?? numbers[0] ?? 1,
|
|
659
|
-
0,
|
|
660
|
-
0,
|
|
661
|
-
0,
|
|
662
|
-
0,
|
|
663
|
-
1
|
|
664
|
-
];
|
|
665
|
-
if (opName.startsWith("xformOp:rotate")) return rotationMatrixFromXformOp(opName, numbers);
|
|
666
|
-
return null;
|
|
667
|
-
}
|
|
668
|
-
function rotationMatrixFromXformOp(opName, degrees) {
|
|
669
|
-
const rotateX = (degree) => {
|
|
670
|
-
const radians = degree * Math.PI / 180;
|
|
671
|
-
const cos = Math.cos(radians);
|
|
672
|
-
const sin = Math.sin(radians);
|
|
673
|
-
return [
|
|
674
|
-
1,
|
|
675
|
-
0,
|
|
676
|
-
0,
|
|
677
|
-
0,
|
|
678
|
-
0,
|
|
679
|
-
cos,
|
|
680
|
-
sin,
|
|
681
|
-
0,
|
|
682
|
-
0,
|
|
683
|
-
-sin,
|
|
684
|
-
cos,
|
|
685
|
-
0,
|
|
686
|
-
0,
|
|
687
|
-
0,
|
|
688
|
-
0,
|
|
689
|
-
1
|
|
690
|
-
];
|
|
691
|
-
};
|
|
692
|
-
const rotateY = (degree) => {
|
|
693
|
-
const radians = degree * Math.PI / 180;
|
|
694
|
-
const cos = Math.cos(radians);
|
|
695
|
-
const sin = Math.sin(radians);
|
|
696
|
-
return [
|
|
697
|
-
cos,
|
|
698
|
-
0,
|
|
699
|
-
-sin,
|
|
700
|
-
0,
|
|
701
|
-
0,
|
|
702
|
-
1,
|
|
703
|
-
0,
|
|
704
|
-
0,
|
|
705
|
-
sin,
|
|
706
|
-
0,
|
|
707
|
-
cos,
|
|
708
|
-
0,
|
|
709
|
-
0,
|
|
710
|
-
0,
|
|
711
|
-
0,
|
|
712
|
-
1
|
|
713
|
-
];
|
|
714
|
-
};
|
|
715
|
-
const rotateZ = (degree) => {
|
|
716
|
-
const radians = degree * Math.PI / 180;
|
|
717
|
-
const cos = Math.cos(radians);
|
|
718
|
-
const sin = Math.sin(radians);
|
|
719
|
-
return [
|
|
720
|
-
cos,
|
|
721
|
-
sin,
|
|
722
|
-
0,
|
|
723
|
-
0,
|
|
724
|
-
-sin,
|
|
725
|
-
cos,
|
|
726
|
-
0,
|
|
727
|
-
0,
|
|
728
|
-
0,
|
|
729
|
-
0,
|
|
730
|
-
1,
|
|
731
|
-
0,
|
|
732
|
-
0,
|
|
733
|
-
0,
|
|
734
|
-
0,
|
|
735
|
-
1
|
|
736
|
-
];
|
|
737
|
-
};
|
|
738
|
-
const suffix = opName.split(":")[1] ?? "";
|
|
739
|
-
if (suffix === "rotateX") return rotateX(degrees[0] ?? 0);
|
|
740
|
-
if (suffix === "rotateY") return rotateY(degrees[0] ?? 0);
|
|
741
|
-
if (suffix === "rotateZ") return rotateZ(degrees[0] ?? 0);
|
|
742
|
-
const axes = suffix.replace(/^rotate/, "").split("");
|
|
743
|
-
if (axes.length === 0) return null;
|
|
744
|
-
return axes.reduce((matrix, axis, index) => {
|
|
745
|
-
const degree = degrees[index] ?? 0;
|
|
746
|
-
const next = axis === "X" ? rotateX(degree) : axis === "Y" ? rotateY(degree) : axis === "Z" ? rotateZ(degree) : null;
|
|
747
|
-
return next ? multiplyMatrices(matrix, next) : matrix;
|
|
748
|
-
}, identityMatrix());
|
|
749
|
-
}
|
|
750
110
|
function attr(prim, name, time, defaultValue = null) {
|
|
751
111
|
const attribute = prim.GetAttribute(name);
|
|
752
112
|
try {
|
|
753
|
-
|
|
754
|
-
const value = attribute.Get(time);
|
|
755
|
-
return value === null || value === void 0 ? defaultValue : normalizeValue(value);
|
|
113
|
+
return attributeValue(attribute, time, defaultValue);
|
|
756
114
|
} finally {
|
|
757
115
|
dispose$1(attribute);
|
|
758
116
|
}
|
|
759
117
|
}
|
|
118
|
+
function attributeValue(attribute, time, defaultValue = null, authoredOnly = false) {
|
|
119
|
+
if (!isValid$1(attribute)) return defaultValue;
|
|
120
|
+
if (authoredOnly && typeof attribute.HasAuthoredValue === "function" && !attribute.HasAuthoredValue()) return defaultValue;
|
|
121
|
+
const value = attribute.Get(time);
|
|
122
|
+
return value === null || value === void 0 ? defaultValue : normalizeValue(value);
|
|
123
|
+
}
|
|
760
124
|
function attrMetadata(prim, name, key, defaultValue = null) {
|
|
761
125
|
const attribute = prim.GetAttribute(name);
|
|
762
126
|
try {
|
|
@@ -767,20 +131,64 @@ function attrMetadata(prim, name, key, defaultValue = null) {
|
|
|
767
131
|
dispose$1(attribute);
|
|
768
132
|
}
|
|
769
133
|
}
|
|
770
|
-
function
|
|
771
|
-
|
|
134
|
+
function relationshipTargetPaths(relationship) {
|
|
135
|
+
if (!isValid$1(relationship)) return [];
|
|
136
|
+
const targets = relationship.GetTargets();
|
|
137
|
+
if (!Array.isArray(targets)) return [];
|
|
138
|
+
try {
|
|
139
|
+
return targets.map(pathToString);
|
|
140
|
+
} finally {
|
|
141
|
+
disposeAll(targets);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function schemaAttributeValue(schema, methodName, time, defaultValue = null, authoredOnly = false) {
|
|
145
|
+
const attribute = schema[methodName]();
|
|
146
|
+
try {
|
|
147
|
+
return attributeValue(attribute, time, defaultValue, authoredOnly);
|
|
148
|
+
} finally {
|
|
149
|
+
dispose$1(attribute);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function schemaRelationshipTargets(schema, methodName) {
|
|
153
|
+
const relationship = schema[methodName]();
|
|
772
154
|
try {
|
|
773
|
-
|
|
774
|
-
const targets = relationship.GetTargets();
|
|
775
|
-
return Array.isArray(targets) ? targets.map(String) : [];
|
|
155
|
+
return relationshipTargetPaths(relationship);
|
|
776
156
|
} finally {
|
|
777
157
|
dispose$1(relationship);
|
|
778
158
|
}
|
|
779
159
|
}
|
|
780
|
-
function
|
|
781
|
-
const
|
|
782
|
-
if (!
|
|
783
|
-
|
|
160
|
+
function assetPathValue(assetPath) {
|
|
161
|
+
const path = typeof assetPath.GetAssetPath === "function" ? String(assetPath.GetAssetPath()) : "";
|
|
162
|
+
if (!path) return null;
|
|
163
|
+
const resolvedPath = typeof assetPath.GetResolvedPath === "function" ? String(assetPath.GetResolvedPath()) : "";
|
|
164
|
+
return resolvedPath ? {
|
|
165
|
+
path,
|
|
166
|
+
resolvedPath
|
|
167
|
+
} : { path };
|
|
168
|
+
}
|
|
169
|
+
function propertyPathPrimPath(path) {
|
|
170
|
+
if (path && typeof path === "object") {
|
|
171
|
+
const maybePath = path;
|
|
172
|
+
if (typeof maybePath.GetPrimPath === "function") {
|
|
173
|
+
const primPath = maybePath.GetPrimPath();
|
|
174
|
+
try {
|
|
175
|
+
return pathToString(primPath) || null;
|
|
176
|
+
} finally {
|
|
177
|
+
dispose$1(primPath);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return pathToString(path).split(/\.(?:outputs|inputs):/)[0] || null;
|
|
182
|
+
}
|
|
183
|
+
function inputSourcePrimPath(input) {
|
|
184
|
+
const connections = input.GetRawConnectedSourcePaths();
|
|
185
|
+
if (!Array.isArray(connections)) return null;
|
|
186
|
+
try {
|
|
187
|
+
if (connections.length === 0) return null;
|
|
188
|
+
return propertyPathPrimPath(connections[0]);
|
|
189
|
+
} finally {
|
|
190
|
+
disposeAll(connections);
|
|
191
|
+
}
|
|
784
192
|
}
|
|
785
193
|
function primChildren(prim) {
|
|
786
194
|
const children = prim.GetChildren();
|
|
@@ -794,24 +202,37 @@ function primAtPath(pxr, stage, path) {
|
|
|
794
202
|
dispose$1(sdfPath);
|
|
795
203
|
}
|
|
796
204
|
}
|
|
797
|
-
function materialBinding(prim) {
|
|
798
|
-
|
|
799
|
-
let ownsCurrent = false;
|
|
205
|
+
function materialBinding(pxr, prim) {
|
|
206
|
+
const binding = new pxr.UsdShade.MaterialBindingAPI(prim);
|
|
800
207
|
try {
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
208
|
+
if (!isValid$1(binding)) return null;
|
|
209
|
+
const computed = binding.ComputeBoundMaterial("", false);
|
|
210
|
+
if (!Array.isArray(computed)) return null;
|
|
211
|
+
const [material, bindingRel] = computed;
|
|
212
|
+
try {
|
|
213
|
+
if (!isValid$1(bindingRel)) return null;
|
|
214
|
+
const resolvedPath = pxr.UsdShade.MaterialBindingAPI.GetResolvedTargetPathFromBindingRel(bindingRel);
|
|
215
|
+
try {
|
|
216
|
+
const path = pathToString(resolvedPath);
|
|
217
|
+
if (path) return path;
|
|
218
|
+
} finally {
|
|
219
|
+
dispose$1(resolvedPath);
|
|
220
|
+
}
|
|
221
|
+
if (!material || !isValid$1(material)) return null;
|
|
222
|
+
const materialPrim = material.GetPrim();
|
|
223
|
+
try {
|
|
224
|
+
return isValid$1(materialPrim) ? String(materialPrim.GetPath()) : null;
|
|
225
|
+
} finally {
|
|
226
|
+
dispose$1(materialPrim);
|
|
227
|
+
}
|
|
228
|
+
} finally {
|
|
229
|
+
disposeAll(computed);
|
|
808
230
|
}
|
|
809
|
-
return null;
|
|
810
231
|
} finally {
|
|
811
|
-
|
|
232
|
+
dispose$1(binding);
|
|
812
233
|
}
|
|
813
234
|
}
|
|
814
|
-
function localTransformForPrim(pxr, prim) {
|
|
235
|
+
function localTransformForPrim(pxr, prim, time) {
|
|
815
236
|
if (!prim.IsA("Xformable")) return {
|
|
816
237
|
localMatrix: null,
|
|
817
238
|
resetsXformStack: false
|
|
@@ -822,7 +243,7 @@ function localTransformForPrim(pxr, prim) {
|
|
|
822
243
|
localMatrix: null,
|
|
823
244
|
resetsXformStack: false
|
|
824
245
|
};
|
|
825
|
-
const transform = xformable.GetLocalTransformation();
|
|
246
|
+
const transform = xformable.GetLocalTransformation(time);
|
|
826
247
|
return {
|
|
827
248
|
localMatrix: toNumberArray(transform?.matrix),
|
|
828
249
|
resetsXformStack: Boolean(transform?.resetsXformStack)
|
|
@@ -842,7 +263,7 @@ function parentPathForPrim(prim) {
|
|
|
842
263
|
}
|
|
843
264
|
function getModelView(pxr, prims, time) {
|
|
844
265
|
return { prims: prims.map((prim) => {
|
|
845
|
-
const transform = localTransformForPrim(pxr, prim);
|
|
266
|
+
const transform = localTransformForPrim(pxr, prim, time);
|
|
846
267
|
return {
|
|
847
268
|
path: String(prim.GetPath()),
|
|
848
269
|
parentPath: parentPathForPrim(prim),
|
|
@@ -891,13 +312,27 @@ function asFloat(value, fallback = 0) {
|
|
|
891
312
|
const number = asFiniteNumber(value);
|
|
892
313
|
return number === null ? fallback : number;
|
|
893
314
|
}
|
|
315
|
+
function shaderId(shader) {
|
|
316
|
+
const id = shader.GetShaderId();
|
|
317
|
+
return typeof id === "string" && id ? id : null;
|
|
318
|
+
}
|
|
319
|
+
function shaderInputValue(shader, inputName, time, defaultValue = null) {
|
|
320
|
+
const input = shader.GetInput(inputName);
|
|
321
|
+
try {
|
|
322
|
+
if (!isValid$1(input)) return defaultValue;
|
|
323
|
+
const value = input.Get(time);
|
|
324
|
+
return value === null || value === void 0 ? defaultValue : normalizeValue(value);
|
|
325
|
+
} finally {
|
|
326
|
+
dispose$1(input);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
894
329
|
function shaderInputConnectionPath(shader, inputName) {
|
|
895
|
-
const
|
|
330
|
+
const input = shader.GetInput(inputName);
|
|
896
331
|
try {
|
|
897
|
-
if (!isValid$1(
|
|
898
|
-
return
|
|
332
|
+
if (!isValid$1(input)) return null;
|
|
333
|
+
return inputSourcePrimPath(input);
|
|
899
334
|
} finally {
|
|
900
|
-
dispose$1(
|
|
335
|
+
dispose$1(input);
|
|
901
336
|
}
|
|
902
337
|
}
|
|
903
338
|
function shaderChildByPath(material, path) {
|
|
@@ -910,29 +345,41 @@ function shaderChildByPath(material, path) {
|
|
|
910
345
|
}
|
|
911
346
|
}
|
|
912
347
|
function primvarNameForTextureShader(pxr, stage, material, textureShader, time) {
|
|
913
|
-
const stSourcePath = shaderInputConnectionPath(textureShader, "
|
|
348
|
+
const stSourcePath = shaderInputConnectionPath(textureShader, "st");
|
|
914
349
|
if (!stSourcePath) return null;
|
|
915
350
|
const stSource = shaderChildByPath(material, stSourcePath) ?? primAtPath(pxr, stage, stSourcePath);
|
|
916
351
|
try {
|
|
917
352
|
if (!isValid$1(stSource)) return null;
|
|
918
|
-
const
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
const nestedSourcePath = shaderInputConnectionPath(stSource, "inputs:in") ?? shaderInputConnectionPath(stSource, "inputs:st");
|
|
925
|
-
if (!nestedSourcePath) return null;
|
|
926
|
-
const nestedSource = shaderChildByPath(material, nestedSourcePath) ?? primAtPath(pxr, stage, nestedSourcePath);
|
|
927
|
-
try {
|
|
928
|
-
if (!isValid$1(nestedSource) || attr(nestedSource, "info:id", time) !== "UsdPrimvarReader_float2") return null;
|
|
929
|
-
const varname = attr(nestedSource, "inputs:varname", time);
|
|
353
|
+
const stShader = new pxr.UsdShade.Shader(stSource);
|
|
354
|
+
try {
|
|
355
|
+
if (!isValid$1(stShader)) return null;
|
|
356
|
+
const id = shaderId(stShader);
|
|
357
|
+
if (id === "UsdPrimvarReader_float2") {
|
|
358
|
+
const varname = shaderInputValue(stShader, "varname", time);
|
|
930
359
|
return typeof varname === "string" && varname ? varname : null;
|
|
931
|
-
} finally {
|
|
932
|
-
dispose$1(nestedSource);
|
|
933
360
|
}
|
|
361
|
+
if (id === "UsdTransform2d") {
|
|
362
|
+
const nestedSourcePath = shaderInputConnectionPath(stShader, "in") ?? shaderInputConnectionPath(stShader, "st");
|
|
363
|
+
if (!nestedSourcePath) return null;
|
|
364
|
+
const nestedSource = shaderChildByPath(material, nestedSourcePath) ?? primAtPath(pxr, stage, nestedSourcePath);
|
|
365
|
+
try {
|
|
366
|
+
if (!isValid$1(nestedSource)) return null;
|
|
367
|
+
const nestedShader = new pxr.UsdShade.Shader(nestedSource);
|
|
368
|
+
try {
|
|
369
|
+
if (!isValid$1(nestedShader) || shaderId(nestedShader) !== "UsdPrimvarReader_float2") return null;
|
|
370
|
+
const varname = shaderInputValue(nestedShader, "varname", time);
|
|
371
|
+
return typeof varname === "string" && varname ? varname : null;
|
|
372
|
+
} finally {
|
|
373
|
+
dispose$1(nestedShader);
|
|
374
|
+
}
|
|
375
|
+
} finally {
|
|
376
|
+
dispose$1(nestedSource);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return null;
|
|
380
|
+
} finally {
|
|
381
|
+
dispose$1(stShader);
|
|
934
382
|
}
|
|
935
|
-
return null;
|
|
936
383
|
} finally {
|
|
937
384
|
dispose$1(stSource);
|
|
938
385
|
}
|
|
@@ -944,10 +391,16 @@ function texturePrimvarForMaterial(pxr, stage, materialPath, time) {
|
|
|
944
391
|
if (!isValid$1(material)) return "primvars:st";
|
|
945
392
|
const children = primChildren(material);
|
|
946
393
|
try {
|
|
947
|
-
for (const
|
|
948
|
-
if (
|
|
949
|
-
const
|
|
950
|
-
|
|
394
|
+
for (const child of children) {
|
|
395
|
+
if (child.GetTypeName() !== "Shader") continue;
|
|
396
|
+
const shader = new pxr.UsdShade.Shader(child);
|
|
397
|
+
try {
|
|
398
|
+
if (!isValid$1(shader) || shaderId(shader) !== "UsdUVTexture") continue;
|
|
399
|
+
const varname = primvarNameForTextureShader(pxr, stage, material, shader, time);
|
|
400
|
+
if (varname) return `primvars:${varname}`;
|
|
401
|
+
} finally {
|
|
402
|
+
dispose$1(shader);
|
|
403
|
+
}
|
|
951
404
|
}
|
|
952
405
|
} finally {
|
|
953
406
|
disposeAll(children);
|
|
@@ -964,30 +417,36 @@ function textureTransformForMaterial(pxr, stage, materialPath, time) {
|
|
|
964
417
|
if (!isValid$1(material)) return null;
|
|
965
418
|
const children = primChildren(material);
|
|
966
419
|
try {
|
|
967
|
-
for (const
|
|
968
|
-
if (
|
|
969
|
-
const
|
|
420
|
+
for (const child of children) {
|
|
421
|
+
if (child.GetTypeName() !== "Shader") continue;
|
|
422
|
+
const shader = new pxr.UsdShade.Shader(child);
|
|
970
423
|
try {
|
|
971
|
-
if (!isValid$1(
|
|
972
|
-
const sourcePath =
|
|
424
|
+
if (!isValid$1(shader) || shaderId(shader) !== "UsdUVTexture") continue;
|
|
425
|
+
const sourcePath = shaderInputConnectionPath(shader, "st");
|
|
973
426
|
if (!sourcePath) return null;
|
|
974
427
|
const transform = primAtPath(pxr, stage, sourcePath);
|
|
975
428
|
try {
|
|
976
|
-
if (!isValid$1(transform)
|
|
977
|
-
const
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
429
|
+
if (!isValid$1(transform)) return null;
|
|
430
|
+
const transformShader = new pxr.UsdShade.Shader(transform);
|
|
431
|
+
try {
|
|
432
|
+
if (!isValid$1(transformShader) || shaderId(transformShader) !== "UsdTransform2d") return null;
|
|
433
|
+
const scale = asVec2(shaderInputValue(transformShader, "scale", time), [1, 1]);
|
|
434
|
+
const translation = asVec2(shaderInputValue(transformShader, "translation", time), [0, 0]);
|
|
435
|
+
return {
|
|
436
|
+
scaleX: scale[0],
|
|
437
|
+
scaleY: scale[1],
|
|
438
|
+
translateX: translation[0],
|
|
439
|
+
translateY: translation[1],
|
|
440
|
+
rotation: asFloat(shaderInputValue(transformShader, "rotation", time))
|
|
441
|
+
};
|
|
442
|
+
} finally {
|
|
443
|
+
dispose$1(transformShader);
|
|
444
|
+
}
|
|
986
445
|
} finally {
|
|
987
446
|
dispose$1(transform);
|
|
988
447
|
}
|
|
989
448
|
} finally {
|
|
990
|
-
dispose$1(
|
|
449
|
+
dispose$1(shader);
|
|
991
450
|
}
|
|
992
451
|
}
|
|
993
452
|
} finally {
|
|
@@ -1023,7 +482,7 @@ function triangulateMesh(pxr, stage, prim, time) {
|
|
|
1023
482
|
const faceIndices = toNumberArray(attr(prim, "faceVertexIndices", time, []));
|
|
1024
483
|
const normals = toArray(attr(prim, "normals", time, []));
|
|
1025
484
|
const normalInterpolation = String(attrMetadata(prim, "normals", "interpolation", attr(prim, "normals:interpolation", time, "")) || "") || null;
|
|
1026
|
-
const boundMaterial = materialBinding(prim);
|
|
485
|
+
const boundMaterial = materialBinding(pxr, prim);
|
|
1027
486
|
const uv = meshPrimvar(prim, texturePrimvarForMaterial(pxr, stage, boundMaterial, time), time);
|
|
1028
487
|
const colors = toArray(attr(prim, "primvars:displayColor", time, []));
|
|
1029
488
|
const opacities = toArray(attr(prim, "primvars:displayOpacity", time, []));
|
|
@@ -1082,177 +541,244 @@ function getModelElements(pxr, stage, prims, time) {
|
|
|
1082
541
|
elements.push({
|
|
1083
542
|
path: String(prim.GetPath()),
|
|
1084
543
|
doubleSided: Boolean(attr(prim, "doubleSided", time, false)),
|
|
1085
|
-
material: materialBinding(prim),
|
|
544
|
+
material: materialBinding(pxr, prim),
|
|
1086
545
|
geometry: triangulateMesh(pxr, stage, prim, time)
|
|
1087
546
|
});
|
|
1088
547
|
}
|
|
1089
548
|
return elements;
|
|
1090
549
|
}
|
|
1091
|
-
function
|
|
550
|
+
function collectShadeInputs(connectable, time) {
|
|
1092
551
|
const inputs = {};
|
|
1093
|
-
const
|
|
552
|
+
const shadeInputs = connectable.GetInputs();
|
|
1094
553
|
try {
|
|
1095
|
-
for (const
|
|
1096
|
-
const
|
|
1097
|
-
if (!
|
|
1098
|
-
const
|
|
1099
|
-
const
|
|
554
|
+
for (const input of shadeInputs) {
|
|
555
|
+
const baseName = String(input.GetBaseName());
|
|
556
|
+
if (!MATERIAL_INPUT_SUFFIXES.some((suffix) => baseName.endsWith(suffix))) continue;
|
|
557
|
+
const name = String(input.GetFullName());
|
|
558
|
+
const value = input.Get(time);
|
|
559
|
+
const connections = input.GetRawConnectedSourcePaths();
|
|
1100
560
|
if (value !== null && value !== void 0) inputs[name] = normalizeValue(value);
|
|
1101
|
-
if (Array.isArray(connections)
|
|
561
|
+
if (Array.isArray(connections)) try {
|
|
562
|
+
if (connections.length > 0) inputs[`${name}.connect`] = connections.map(pathToString);
|
|
563
|
+
} finally {
|
|
564
|
+
disposeAll(connections);
|
|
565
|
+
}
|
|
1102
566
|
}
|
|
1103
567
|
} finally {
|
|
1104
|
-
disposeAll(
|
|
568
|
+
disposeAll(shadeInputs);
|
|
1105
569
|
}
|
|
1106
570
|
return inputs;
|
|
1107
571
|
}
|
|
1108
|
-
function
|
|
572
|
+
function collectShaderSourceAssets(shader) {
|
|
573
|
+
const inputs = {};
|
|
574
|
+
const sourceTypes = shader.GetSourceTypes();
|
|
575
|
+
if (!Array.isArray(sourceTypes)) return inputs;
|
|
576
|
+
for (const sourceType of sourceTypes) {
|
|
577
|
+
const sourceTypeName = String(sourceType);
|
|
578
|
+
const sourceAsset = shader.GetSourceAsset(sourceTypeName);
|
|
579
|
+
try {
|
|
580
|
+
const value = assetPathValue(sourceAsset);
|
|
581
|
+
if (!value) continue;
|
|
582
|
+
const name = sourceTypeName ? `info:${sourceTypeName}:sourceAsset` : "info:sourceAsset";
|
|
583
|
+
inputs[name] = value;
|
|
584
|
+
} finally {
|
|
585
|
+
dispose$1(sourceAsset);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return inputs;
|
|
589
|
+
}
|
|
590
|
+
function getModelMaterials(pxr, prims, time) {
|
|
1109
591
|
const materials = [];
|
|
1110
592
|
for (const prim of prims) {
|
|
1111
593
|
if (prim.GetTypeName() !== "Material") continue;
|
|
594
|
+
const material = new pxr.UsdShade.Material(prim);
|
|
1112
595
|
const children = primChildren(prim);
|
|
1113
596
|
const shaders = [];
|
|
1114
597
|
try {
|
|
598
|
+
if (!isValid$1(material)) continue;
|
|
1115
599
|
for (const child of children) {
|
|
1116
600
|
if (child.GetTypeName() !== "Shader") continue;
|
|
1117
|
-
const
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
601
|
+
const shader = new pxr.UsdShade.Shader(child);
|
|
602
|
+
try {
|
|
603
|
+
if (!isValid$1(shader)) continue;
|
|
604
|
+
const idValue = shader.GetShaderId();
|
|
605
|
+
const id = typeof idValue === "string" && idValue ? idValue : null;
|
|
606
|
+
const inputs = {
|
|
607
|
+
...collectShadeInputs(shader, time),
|
|
608
|
+
...collectShaderSourceAssets(shader)
|
|
609
|
+
};
|
|
610
|
+
if (Object.keys(inputs).length === 0 && id !== "UsdPreviewSurface" && id !== "UsdUVTexture") continue;
|
|
611
|
+
shaders.push({
|
|
612
|
+
path: String(child.GetPath()),
|
|
613
|
+
id,
|
|
614
|
+
inputs
|
|
615
|
+
});
|
|
616
|
+
} finally {
|
|
617
|
+
dispose$1(shader);
|
|
618
|
+
}
|
|
1126
619
|
}
|
|
620
|
+
materials.push({
|
|
621
|
+
path: String(prim.GetPath()),
|
|
622
|
+
inputs: collectShadeInputs(material, time),
|
|
623
|
+
shaders
|
|
624
|
+
});
|
|
1127
625
|
} finally {
|
|
1128
626
|
disposeAll(children);
|
|
627
|
+
dispose$1(material);
|
|
1129
628
|
}
|
|
1130
|
-
materials.push({
|
|
1131
|
-
path: String(prim.GetPath()),
|
|
1132
|
-
inputs: collectShaderInputs(prim, time),
|
|
1133
|
-
shaders
|
|
1134
|
-
});
|
|
1135
629
|
}
|
|
1136
630
|
return materials;
|
|
1137
631
|
}
|
|
1138
|
-
function driveForNamespace(prim, namespace, time) {
|
|
632
|
+
function driveForNamespace(pxr, prim, namespace, time) {
|
|
633
|
+
const driveAPI = new pxr.UsdPhysics.DriveAPI(prim, namespace);
|
|
1139
634
|
const drive = {
|
|
1140
|
-
targetPosition:
|
|
1141
|
-
targetVelocity:
|
|
1142
|
-
stiffness:
|
|
1143
|
-
damping:
|
|
1144
|
-
maxForce:
|
|
635
|
+
targetPosition: null,
|
|
636
|
+
targetVelocity: null,
|
|
637
|
+
stiffness: null,
|
|
638
|
+
damping: null,
|
|
639
|
+
maxForce: null
|
|
1145
640
|
};
|
|
1146
|
-
|
|
641
|
+
try {
|
|
642
|
+
if (!isValid$1(driveAPI)) return null;
|
|
643
|
+
drive.targetPosition = asFiniteNumber(schemaAttributeValue(driveAPI, "GetTargetPositionAttr", time, null, true));
|
|
644
|
+
drive.targetVelocity = asFiniteNumber(schemaAttributeValue(driveAPI, "GetTargetVelocityAttr", time, null, true));
|
|
645
|
+
drive.stiffness = asFiniteNumber(schemaAttributeValue(driveAPI, "GetStiffnessAttr", time, null, true));
|
|
646
|
+
drive.damping = asFiniteNumber(schemaAttributeValue(driveAPI, "GetDampingAttr", time, null, true));
|
|
647
|
+
drive.maxForce = asFiniteNumber(schemaAttributeValue(driveAPI, "GetMaxForceAttr", time, null, true));
|
|
648
|
+
return Object.values(drive).some((value) => value !== null) ? drive : null;
|
|
649
|
+
} finally {
|
|
650
|
+
dispose$1(driveAPI);
|
|
651
|
+
}
|
|
1147
652
|
}
|
|
1148
653
|
function jointTypeForPrim(typeName) {
|
|
1149
654
|
if (JOINT_TYPES[typeName]) return JOINT_TYPES[typeName];
|
|
1150
655
|
if (typeName.startsWith("Physics") && typeName.endsWith("Joint")) return typeName.slice(7, -5).toLowerCase() || "joint";
|
|
1151
656
|
return null;
|
|
1152
657
|
}
|
|
1153
|
-
function
|
|
658
|
+
function jointLimitSchema(pxr, prim, typeName) {
|
|
659
|
+
switch (typeName) {
|
|
660
|
+
case "PhysicsRevoluteJoint": return new pxr.UsdPhysics.RevoluteJoint(prim);
|
|
661
|
+
case "PhysicsPrismaticJoint": return new pxr.UsdPhysics.PrismaticJoint(prim);
|
|
662
|
+
case "PhysicsSphericalJoint": return new pxr.UsdPhysics.SphericalJoint(prim);
|
|
663
|
+
case "PhysicsDistanceJoint": return new pxr.UsdPhysics.DistanceJoint(prim);
|
|
664
|
+
default: return null;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
function jointAxisAndLimits(pxr, prim, typeName, time) {
|
|
668
|
+
const schema = jointLimitSchema(pxr, prim, typeName);
|
|
669
|
+
if (!schema) return {
|
|
670
|
+
axis: null,
|
|
671
|
+
lowerLimit: null,
|
|
672
|
+
upperLimit: null
|
|
673
|
+
};
|
|
674
|
+
try {
|
|
675
|
+
if (!isValid$1(schema)) return {
|
|
676
|
+
axis: null,
|
|
677
|
+
lowerLimit: null,
|
|
678
|
+
upperLimit: null
|
|
679
|
+
};
|
|
680
|
+
if (typeName === "PhysicsSphericalJoint") {
|
|
681
|
+
const axis = schemaAttributeValue(schema, "GetAxisAttr", time);
|
|
682
|
+
return {
|
|
683
|
+
axis: typeof axis === "string" ? axis : null,
|
|
684
|
+
lowerLimit: asFiniteNumber(schemaAttributeValue(schema, "GetConeAngle0LimitAttr", time, null, true)),
|
|
685
|
+
upperLimit: asFiniteNumber(schemaAttributeValue(schema, "GetConeAngle1LimitAttr", time, null, true))
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
if (typeName === "PhysicsDistanceJoint") return {
|
|
689
|
+
axis: null,
|
|
690
|
+
lowerLimit: asFiniteNumber(schemaAttributeValue(schema, "GetMinDistanceAttr", time, null, true)),
|
|
691
|
+
upperLimit: asFiniteNumber(schemaAttributeValue(schema, "GetMaxDistanceAttr", time, null, true))
|
|
692
|
+
};
|
|
693
|
+
const axis = schemaAttributeValue(schema, "GetAxisAttr", time);
|
|
694
|
+
return {
|
|
695
|
+
axis: typeof axis === "string" ? axis : null,
|
|
696
|
+
lowerLimit: asFiniteNumber(schemaAttributeValue(schema, "GetLowerLimitAttr", time)),
|
|
697
|
+
upperLimit: asFiniteNumber(schemaAttributeValue(schema, "GetUpperLimitAttr", time))
|
|
698
|
+
};
|
|
699
|
+
} finally {
|
|
700
|
+
dispose$1(schema);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
function getModelJoints(pxr, prims, time) {
|
|
1154
704
|
const joints = [];
|
|
1155
705
|
for (const prim of prims) {
|
|
1156
706
|
const typeName = String(prim.GetTypeName());
|
|
1157
707
|
const jointType = jointTypeForPrim(typeName);
|
|
1158
708
|
if (!jointType) continue;
|
|
1159
|
-
const
|
|
1160
|
-
|
|
709
|
+
const joint = new pxr.UsdPhysics.Joint(prim);
|
|
710
|
+
if (!isValid$1(joint)) {
|
|
711
|
+
dispose$1(joint);
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
const angularDrive = driveForNamespace(pxr, prim, "angular", time);
|
|
715
|
+
const linearDrive = driveForNamespace(pxr, prim, "linear", time);
|
|
1161
716
|
const drives = {};
|
|
1162
717
|
if (angularDrive) drives.angular = angularDrive;
|
|
1163
718
|
if (linearDrive) drives.linear = linearDrive;
|
|
1164
|
-
const body0 =
|
|
1165
|
-
const body1 =
|
|
719
|
+
const body0 = schemaRelationshipTargets(joint, "GetBody0Rel");
|
|
720
|
+
const body1 = schemaRelationshipTargets(joint, "GetBody1Rel");
|
|
1166
721
|
const drive = jointType === "prismatic" ? linearDrive ?? angularDrive : angularDrive ?? linearDrive;
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
722
|
+
const axisAndLimits = jointAxisAndLimits(pxr, prim, typeName, time);
|
|
723
|
+
try {
|
|
724
|
+
joints.push({
|
|
725
|
+
path: String(prim.GetPath()),
|
|
726
|
+
name: String(prim.GetName()),
|
|
727
|
+
typeName,
|
|
728
|
+
jointType,
|
|
729
|
+
body0: body0[0] ?? null,
|
|
730
|
+
body1: body1[0] ?? null,
|
|
731
|
+
...axisAndLimits,
|
|
732
|
+
localPos0: toVector3(schemaAttributeValue(joint, "GetLocalPos0Attr", time, [
|
|
733
|
+
0,
|
|
734
|
+
0,
|
|
735
|
+
0
|
|
736
|
+
]), [
|
|
737
|
+
0,
|
|
738
|
+
0,
|
|
739
|
+
0
|
|
740
|
+
]),
|
|
741
|
+
localPos1: toVector3(schemaAttributeValue(joint, "GetLocalPos1Attr", time, [
|
|
742
|
+
0,
|
|
743
|
+
0,
|
|
744
|
+
0
|
|
745
|
+
]), [
|
|
746
|
+
0,
|
|
747
|
+
0,
|
|
748
|
+
0
|
|
749
|
+
]),
|
|
750
|
+
localRot0: toVector4(schemaAttributeValue(joint, "GetLocalRot0Attr", time)),
|
|
751
|
+
localRot1: toVector4(schemaAttributeValue(joint, "GetLocalRot1Attr", time)),
|
|
752
|
+
enabled: Boolean(schemaAttributeValue(joint, "GetJointEnabledAttr", time, true)),
|
|
753
|
+
drive,
|
|
754
|
+
drives
|
|
755
|
+
});
|
|
756
|
+
} finally {
|
|
757
|
+
dispose$1(joint);
|
|
758
|
+
}
|
|
1201
759
|
}
|
|
1202
760
|
return joints;
|
|
1203
761
|
}
|
|
1204
|
-
function stageTimingFromLayer(rootLayer) {
|
|
1205
|
-
const text = String(rootLayer.ExportToString?.() ?? "");
|
|
1206
|
-
const numberFor = (name) => {
|
|
1207
|
-
const match = new RegExp(`${name}\\s*=\\s*(-?\\d+(?:\\.\\d+)?)`).exec(text);
|
|
1208
|
-
if (!match?.[1]) return null;
|
|
1209
|
-
const value = Number(match[1]);
|
|
1210
|
-
return Number.isFinite(value) ? value : null;
|
|
1211
|
-
};
|
|
1212
|
-
return {
|
|
1213
|
-
startTimeCode: numberFor("startTimeCode"),
|
|
1214
|
-
endTimeCode: numberFor("endTimeCode"),
|
|
1215
|
-
timeCodesPerSecond: numberFor("timeCodesPerSecond") ?? 24
|
|
1216
|
-
};
|
|
1217
|
-
}
|
|
1218
762
|
function getStageInfo(pxr, stage, options) {
|
|
1219
763
|
const defaultPrim = stage.GetDefaultPrim();
|
|
1220
|
-
const rootLayer = stage.GetRootLayer();
|
|
1221
764
|
try {
|
|
1222
|
-
const timing = stageTimingFromLayer(rootLayer);
|
|
1223
765
|
return {
|
|
1224
766
|
sourcePath: options.sourcePath,
|
|
1225
767
|
rootLayerIdentifier: options.rootLayerIdentifier,
|
|
1226
768
|
defaultPrim: isValid$1(defaultPrim) ? String(defaultPrim.GetPath()) : null,
|
|
1227
769
|
upAxis: String(pxr.UsdGeom.GetStageUpAxis(stage)),
|
|
1228
|
-
|
|
770
|
+
startTimeCode: stage.GetStartTimeCode(),
|
|
771
|
+
endTimeCode: stage.GetEndTimeCode(),
|
|
772
|
+
timeCodesPerSecond: stage.GetTimeCodesPerSecond()
|
|
1229
773
|
};
|
|
1230
774
|
} finally {
|
|
1231
|
-
dispose$1(rootLayer);
|
|
1232
775
|
dispose$1(defaultPrim);
|
|
1233
776
|
}
|
|
1234
777
|
}
|
|
1235
|
-
function localMatrixFromXformOps(prim, time) {
|
|
1236
|
-
const opOrder = toArray(attr(prim, "xformOpOrder", time, [])).map(String);
|
|
1237
|
-
if (opOrder.length === 0) return null;
|
|
1238
|
-
let matrix = identityMatrix();
|
|
1239
|
-
let foundOp = false;
|
|
1240
|
-
for (const opName of opOrder) {
|
|
1241
|
-
if (opName.startsWith("!")) {
|
|
1242
|
-
matrix = identityMatrix();
|
|
1243
|
-
continue;
|
|
1244
|
-
}
|
|
1245
|
-
const opMatrix = matrixFromXformOp(opName, attr(prim, opName, time));
|
|
1246
|
-
if (!opMatrix) continue;
|
|
1247
|
-
matrix = multiplyMatrices(matrix, opMatrix);
|
|
1248
|
-
foundOp = true;
|
|
1249
|
-
}
|
|
1250
|
-
return foundOp ? matrix : null;
|
|
1251
|
-
}
|
|
1252
778
|
function sampleLocalMatrix(pxr, prim, frame) {
|
|
1253
779
|
const time = new pxr.Usd.TimeCode(frame);
|
|
1254
780
|
try {
|
|
1255
|
-
return
|
|
781
|
+
return localTransformForPrim(pxr, prim, time).localMatrix;
|
|
1256
782
|
} finally {
|
|
1257
783
|
dispose$1(time);
|
|
1258
784
|
}
|
|
@@ -1269,10 +795,10 @@ function animationSampleFrames(start, end) {
|
|
|
1269
795
|
});
|
|
1270
796
|
}
|
|
1271
797
|
function getModelAnimations(pxr, prims, stageInfo) {
|
|
1272
|
-
const start = stageInfo.startTimeCode
|
|
1273
|
-
const end = stageInfo.endTimeCode
|
|
1274
|
-
const timeCodesPerSecond = stageInfo.timeCodesPerSecond
|
|
1275
|
-
if (
|
|
798
|
+
const start = stageInfo.startTimeCode;
|
|
799
|
+
const end = stageInfo.endTimeCode;
|
|
800
|
+
const timeCodesPerSecond = stageInfo.timeCodesPerSecond;
|
|
801
|
+
if (end <= start) return [];
|
|
1276
802
|
const frames = animationSampleFrames(start, end);
|
|
1277
803
|
if (frames.length < 2) return [];
|
|
1278
804
|
const transforms = [];
|
|
@@ -1319,8 +845,8 @@ function extractUSDModelData(pxr, stage, options = {}) {
|
|
|
1319
845
|
stage: stageInfo,
|
|
1320
846
|
view: getModelView(pxr, prims, time),
|
|
1321
847
|
elements: getModelElements(pxr, stage, prims, time),
|
|
1322
|
-
materials: getModelMaterials(prims, time),
|
|
1323
|
-
joints: getModelJoints(prims, time),
|
|
848
|
+
materials: getModelMaterials(pxr, prims, time),
|
|
849
|
+
joints: getModelJoints(pxr, prims, time),
|
|
1324
850
|
animations: getModelAnimations(pxr, prims, stageInfo)
|
|
1325
851
|
};
|
|
1326
852
|
} finally {
|
|
@@ -1625,13 +1151,19 @@ function deleteFileIfExists(pxr, path) {
|
|
|
1625
1151
|
if (pxr.FS.exists(path)) pxr.FS.deleteFile(path);
|
|
1626
1152
|
} catch {}
|
|
1627
1153
|
}
|
|
1628
|
-
|
|
1629
|
-
const directory = joinFsPath(
|
|
1154
|
+
function createUSDInputDirectory(pxr, workingDirectory) {
|
|
1155
|
+
const directory = joinFsPath(workingDirectory, String(++nextLoadId));
|
|
1630
1156
|
pxr.FS.createDir(directory);
|
|
1631
|
-
|
|
1157
|
+
return directory;
|
|
1158
|
+
}
|
|
1159
|
+
async function writeUSDFiles(pxr, directory, files) {
|
|
1160
|
+
for (const [relativePath, file] of Object.entries(files ?? {})) {
|
|
1632
1161
|
const filePath = joinFsPath(directory, relativePath);
|
|
1633
1162
|
pxr.FS.writeFile(filePath, await sourceToWritableData(file));
|
|
1634
1163
|
}
|
|
1164
|
+
}
|
|
1165
|
+
async function writeUSDInput(pxr, directory, input, options) {
|
|
1166
|
+
await writeUSDFiles(pxr, directory, options.files);
|
|
1635
1167
|
const path = joinFsPath(directory, sanitizeFileName(options.fileName));
|
|
1636
1168
|
pxr.FS.writeFile(path, input);
|
|
1637
1169
|
return path;
|
|
@@ -1714,15 +1246,19 @@ var USDLoader = class extends Loader {
|
|
|
1714
1246
|
const extension = extensionForPath(mergedOptions.fileName);
|
|
1715
1247
|
const writableData = await sourceToWritableData(input);
|
|
1716
1248
|
const packageTextureResolver = extension === "usdz" && writableData instanceof Uint8Array ? createPackageTextureResolver(writableData) : null;
|
|
1717
|
-
|
|
1718
|
-
const
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
}
|
|
1249
|
+
const packageRootLayer = extension === "usdz" && writableData instanceof Uint8Array ? mergedOptions.usdzLayer ?? findPackageRootLayer(writableData) ?? void 0 : mergedOptions.usdzLayer;
|
|
1250
|
+
const rootFileName = sanitizeFileName(mergedOptions.fileName);
|
|
1251
|
+
const directory = createUSDInputDirectory(pxr, mergedOptions.workingDirectory);
|
|
1252
|
+
const filePath = await writeUSDInput(pxr, directory, writableData, {
|
|
1253
|
+
fileName: rootFileName,
|
|
1254
|
+
files: mergedOptions.files
|
|
1724
1255
|
});
|
|
1725
|
-
|
|
1256
|
+
let autoFiles = extension !== "usdz" ? await autoResolveAssetFiles(pxr, filePath, {
|
|
1257
|
+
...mergedOptions,
|
|
1258
|
+
fileName: rootFileName
|
|
1259
|
+
}) : {};
|
|
1260
|
+
await writeUSDFiles(pxr, directory, autoFiles);
|
|
1261
|
+
const { stage, identifier } = openStage(pxr, filePath, extension, packageRootLayer);
|
|
1726
1262
|
try {
|
|
1727
1263
|
const metadata = extractUSDModelData(pxr, stage, {
|
|
1728
1264
|
sourcePath: mergedOptions.sourcePath,
|
|
@@ -1778,7 +1314,7 @@ function limitsForJoint(joint) {
|
|
|
1778
1314
|
}
|
|
1779
1315
|
function initialValueForJoint(joint) {
|
|
1780
1316
|
const { lower, upper } = limitsForJoint(joint);
|
|
1781
|
-
return clamp(joint.drive?.targetPosition ??
|
|
1317
|
+
return clamp(joint.drive?.targetPosition ?? 0, lower, upper);
|
|
1782
1318
|
}
|
|
1783
1319
|
function isManipulableJoint(joint) {
|
|
1784
1320
|
return joint.enabled && (joint.jointType === "revolute" || joint.jointType === "prismatic");
|
|
@@ -1844,7 +1380,12 @@ function jointValueKey(model, joint) {
|
|
|
1844
1380
|
return `${model.root.uuid}:${joint.path}`;
|
|
1845
1381
|
}
|
|
1846
1382
|
function localAxisForJoint(joint) {
|
|
1847
|
-
|
|
1383
|
+
const axis = axisVectors[joint.axis ?? ""]?.clone() ?? axisVectors.X.clone();
|
|
1384
|
+
const rotation = joint.localRot0;
|
|
1385
|
+
if (!rotation) return axis;
|
|
1386
|
+
const quaternion = new THREE.Quaternion(rotation[1] ?? 0, rotation[2] ?? 0, rotation[3] ?? 0, rotation[0] ?? 1);
|
|
1387
|
+
if (quaternion.lengthSq() < 1e-10) return axis;
|
|
1388
|
+
return axis.applyQuaternion(quaternion.normalize());
|
|
1848
1389
|
}
|
|
1849
1390
|
function localPivotForJoint(joint) {
|
|
1850
1391
|
return new THREE.Vector3(joint.localPos0[0] ?? 0, joint.localPos0[1] ?? 0, joint.localPos0[2] ?? 0);
|
|
@@ -2204,4 +1745,4 @@ var USDManipulationControls = class {
|
|
|
2204
1745
|
}
|
|
2205
1746
|
};
|
|
2206
1747
|
//#endregion
|
|
2207
|
-
export { USDLoader, USDManipulationControls,
|
|
1748
|
+
export { USDLoader, USDManipulationControls, buildUSDObject, createUSDLoadedModel, extractUSDModelData };
|