@openusd-wasm/three-loader 0.0.1 → 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 +6 -14
- package/dist/openusd_three_loader.js +386 -786
- package/package.json +6 -4
|
@@ -1,447 +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
|
-
];
|
|
18
|
-
const DEFAULT_ASSET_SEARCH_ROOTS = [
|
|
19
|
-
"resource",
|
|
20
|
-
"resources",
|
|
21
|
-
"asset",
|
|
22
|
-
"assets",
|
|
23
|
-
"img",
|
|
24
|
-
"image",
|
|
25
|
-
"images",
|
|
26
|
-
"texture",
|
|
27
|
-
"textures",
|
|
28
|
-
"material",
|
|
29
|
-
"materials"
|
|
30
|
-
];
|
|
31
|
-
const DEFAULT_MAX_ASSET_REFERENCES = 80;
|
|
32
|
-
const DEFAULT_MAX_ASSET_REFERENCE_DEPTH = 4;
|
|
33
|
-
function toFetchableUrl(value) {
|
|
34
|
-
try {
|
|
35
|
-
const url = new URL(value, globalThis.location?.href);
|
|
36
|
-
return url.protocol === "http:" || url.protocol === "https:" || url.protocol === "file:" ? url.href : null;
|
|
37
|
-
} catch {
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
function normalizeFsRelativePath(path) {
|
|
42
|
-
const parts = [];
|
|
43
|
-
for (const part of path.replaceAll("\\", "/").split("/")) {
|
|
44
|
-
if (!part || part === ".") continue;
|
|
45
|
-
if (part === "..") {
|
|
46
|
-
parts.pop();
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
parts.push(part);
|
|
50
|
-
}
|
|
51
|
-
return parts.join("/");
|
|
52
|
-
}
|
|
53
|
-
function dirname(path) {
|
|
54
|
-
const normalized = normalizeFsRelativePath(path);
|
|
55
|
-
const index = normalized.lastIndexOf("/");
|
|
56
|
-
return index === -1 ? "" : normalized.slice(0, index);
|
|
57
|
-
}
|
|
58
|
-
function joinRelativePath(base, path) {
|
|
59
|
-
return normalizeFsRelativePath(base ? `${base}/${path}` : path);
|
|
60
|
-
}
|
|
61
|
-
function extensionOf(path) {
|
|
62
|
-
const match = /\.([A-Za-z0-9]+)$/.exec(path.split(/[?#]/)[0] ?? path);
|
|
63
|
-
return match ? `.${match[1]?.toLowerCase()}` : "";
|
|
64
|
-
}
|
|
65
|
-
function contentTypeForPath(path) {
|
|
66
|
-
switch (extensionOf(path)) {
|
|
67
|
-
case ".png": return "image/png";
|
|
68
|
-
case ".jpg":
|
|
69
|
-
case ".jpeg": return "image/jpeg";
|
|
70
|
-
case ".webp": return "image/webp";
|
|
71
|
-
default: return "application/octet-stream";
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function baseName(path) {
|
|
75
|
-
return normalizeFsRelativePath(path).split("/").pop() ?? "";
|
|
76
|
-
}
|
|
77
|
-
function fileNameForSource$1(sourcePath) {
|
|
78
|
-
const name = (sourcePath.split(/[?#]/)[0] ?? sourcePath).split("/").filter(Boolean).pop();
|
|
79
|
-
return name && /\.[a-z0-9]+$/i.test(name) ? name : "scene.usda";
|
|
80
|
-
}
|
|
81
|
-
function toArrayBuffer(data) {
|
|
82
|
-
const buffer = new ArrayBuffer(data.byteLength);
|
|
83
|
-
new Uint8Array(buffer).set(data);
|
|
84
|
-
return buffer;
|
|
85
|
-
}
|
|
86
|
-
function trimAssetReference(value) {
|
|
87
|
-
let ref = value.trim();
|
|
88
|
-
if (!ref || ref.length > 220) return null;
|
|
89
|
-
ref = ref.replace(/^[@<"']+/, "").replace(/[@>"')\]},;]+$/g, "");
|
|
90
|
-
if (!ref || ref.startsWith("#") || ref.startsWith("$")) return null;
|
|
91
|
-
if (/^[A-Za-z]:[\\/]/.test(ref)) return null;
|
|
92
|
-
if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(ref)) return null;
|
|
93
|
-
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;
|
|
96
|
-
return ref;
|
|
97
|
-
}
|
|
98
|
-
function isUsdCrate(data) {
|
|
99
|
-
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;
|
|
100
|
-
}
|
|
101
|
-
function startsWithAssetSearchRoot(value) {
|
|
102
|
-
return /^(resource|resources|asset|assets|img|image|images|texture|textures|material|materials)(\/|$)/i.test(value);
|
|
103
|
-
}
|
|
104
|
-
function startsWithAssetSearchRootPath(value) {
|
|
105
|
-
const normalized = normalizeFsRelativePath(value);
|
|
106
|
-
return normalized.includes("/") && startsWithAssetSearchRoot(normalized);
|
|
107
|
-
}
|
|
108
|
-
function looksLikeExtensionlessAssetPath(value) {
|
|
109
|
-
const parts = normalizeFsRelativePath(value).split("/");
|
|
110
|
-
if (parts.length < 2 || parts.length > 3) return false;
|
|
111
|
-
if (parts.some((part) => part.length < 2 || part.length > 80)) return false;
|
|
112
|
-
if (parts.some((part) => part.startsWith("."))) return false;
|
|
113
|
-
if (parts.some((part) => !/^[A-Za-z0-9._-]+$/.test(part))) return false;
|
|
114
|
-
if (!/_/.test(value) || !/\d/.test(value)) return false;
|
|
115
|
-
return true;
|
|
116
|
-
}
|
|
117
|
-
function looksLikeKnownExtensionlessAsset(value) {
|
|
118
|
-
const normalized = normalizeFsRelativePath(value);
|
|
119
|
-
if (!normalized.includes("/")) return false;
|
|
120
|
-
return [
|
|
121
|
-
"material",
|
|
122
|
-
"model",
|
|
123
|
-
"scene"
|
|
124
|
-
].includes(baseName(normalized).toLowerCase());
|
|
125
|
-
}
|
|
126
|
-
function looksLikeAssetReference(value, searchExtensions, includeExtensionlessAssetPaths, wholeString) {
|
|
127
|
-
const extension = extensionOf(value);
|
|
128
|
-
if (extension) {
|
|
129
|
-
if (!searchExtensions.includes(extension)) return false;
|
|
130
|
-
const name = baseName(value);
|
|
131
|
-
if (name === extension) return false;
|
|
132
|
-
if (wholeString && !value.startsWith("./") && !value.startsWith("../") && !value.includes("/")) return name.length >= 8;
|
|
133
|
-
return true;
|
|
134
|
-
}
|
|
135
|
-
if (value.startsWith("./") || value.startsWith("../")) {
|
|
136
|
-
const relative = normalizeFsRelativePath(value);
|
|
137
|
-
if (startsWithAssetSearchRootPath(relative)) return looksLikeExtensionlessAssetPath(relative) || looksLikeKnownExtensionlessAsset(relative);
|
|
138
|
-
return looksLikeExtensionlessAssetPath(relative);
|
|
139
|
-
}
|
|
140
|
-
if (startsWithAssetSearchRootPath(value)) return looksLikeExtensionlessAssetPath(value) || looksLikeKnownExtensionlessAsset(value);
|
|
141
|
-
return includeExtensionlessAssetPaths && looksLikeExtensionlessAssetPath(value);
|
|
142
|
-
}
|
|
143
|
-
function extractAsciiStrings(data) {
|
|
144
|
-
const strings = [];
|
|
145
|
-
let current = "";
|
|
146
|
-
for (const byte of data) if (byte >= 32 && byte <= 126) current += String.fromCharCode(byte);
|
|
147
|
-
else {
|
|
148
|
-
if (current.length >= 4) strings.push(current);
|
|
149
|
-
current = "";
|
|
150
|
-
}
|
|
151
|
-
if (current.length >= 4) strings.push(current);
|
|
152
|
-
return strings;
|
|
153
|
-
}
|
|
154
|
-
function discoverAssetReferences(data, searchExtensions, includeExtensionlessAssetPaths = false) {
|
|
155
|
-
const out = /* @__PURE__ */ new Set();
|
|
156
|
-
for (const text of extractAsciiStrings(data)) {
|
|
157
|
-
const whole = trimAssetReference(text);
|
|
158
|
-
if (whole && looksLikeAssetReference(whole, searchExtensions, includeExtensionlessAssetPaths, true)) out.add(whole);
|
|
159
|
-
for (const match of text.matchAll(/@([^@\n\r]+)@/g)) {
|
|
160
|
-
const ref = trimAssetReference(match[1] ?? "");
|
|
161
|
-
if (ref && looksLikeAssetReference(ref, searchExtensions, includeExtensionlessAssetPaths, false)) out.add(ref);
|
|
162
|
-
}
|
|
163
|
-
for (const match of text.matchAll(/["']([^"'\n\r]+\.(?:usd|usda|usdc|usdz|png|jpe?g|webp|ktx2|exr|hdr|mdl))["']/gi)) {
|
|
164
|
-
const ref = trimAssetReference(match[1] ?? "");
|
|
165
|
-
if (ref && looksLikeAssetReference(ref, searchExtensions, includeExtensionlessAssetPaths, false)) out.add(ref);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return [...out];
|
|
169
|
-
}
|
|
170
|
-
function discoverAssetSearchRoots(data, searchRoots) {
|
|
171
|
-
const out = /* @__PURE__ */ new Set();
|
|
172
|
-
const rootSet = new Set(searchRoots);
|
|
173
|
-
for (const text of extractAsciiStrings(data)) {
|
|
174
|
-
const ref = trimAssetReference(text);
|
|
175
|
-
if (!ref) continue;
|
|
176
|
-
const segment = firstPathSegment(ref);
|
|
177
|
-
if (rootSet.has(segment) && normalizeFsRelativePath(ref).includes("/")) out.add(segment);
|
|
178
|
-
}
|
|
179
|
-
return [...out];
|
|
180
|
-
}
|
|
181
|
-
function buildExtensionVariants(path, searchExtensions) {
|
|
182
|
-
const normalized = normalizeFsRelativePath(path);
|
|
183
|
-
if (!normalized) return [];
|
|
184
|
-
if (extensionOf(normalized)) return [normalized];
|
|
185
|
-
return [...searchExtensions.map((extension) => `${normalized}${extension}`), normalized];
|
|
186
|
-
}
|
|
187
|
-
function buildReferencePathVariants(relativePath) {
|
|
188
|
-
const normalized = normalizeFsRelativePath(relativePath);
|
|
189
|
-
if (!normalized) return [];
|
|
190
|
-
return [{
|
|
191
|
-
path: normalized,
|
|
192
|
-
aliases: [normalized]
|
|
193
|
-
}];
|
|
194
|
-
}
|
|
195
|
-
function unique(values) {
|
|
196
|
-
return [...new Set(values)];
|
|
197
|
-
}
|
|
198
|
-
function uniqueFileCount(files) {
|
|
199
|
-
return new Set(Object.values(files)).size;
|
|
200
|
-
}
|
|
201
|
-
function firstPathSegment(path) {
|
|
202
|
-
return normalizeFsRelativePath(path).split("/")[0] ?? "";
|
|
203
|
-
}
|
|
204
|
-
function normalizeSearchRoots(roots) {
|
|
205
|
-
return unique((roots ?? DEFAULT_ASSET_SEARCH_ROOTS).map((root) => normalizeFsRelativePath(root)).filter(Boolean));
|
|
206
|
-
}
|
|
207
|
-
function inferReferencedSearchRoots(refs, searchRoots) {
|
|
208
|
-
const rootSet = new Set(searchRoots);
|
|
209
|
-
return unique(refs.map((ref) => firstPathSegment(ref)).filter((segment) => rootSet.has(segment)));
|
|
210
|
-
}
|
|
211
|
-
function buildFetchAttempts(ref, sourceUrl, sourceRelativePath, searchExtensions, rootSourceUrl, searchRoots) {
|
|
212
|
-
const sourceDir = dirname(sourceRelativePath);
|
|
213
|
-
const attempts = [];
|
|
214
|
-
const seen = /* @__PURE__ */ new Set();
|
|
215
|
-
const normalizedRef = normalizeFsRelativePath(ref);
|
|
216
|
-
const isDotRelative = /^\.{1,2}\//.test(ref);
|
|
217
|
-
const candidates = [];
|
|
218
|
-
function addCandidate(fsPath, fetchPath, baseUrl, aliases = []) {
|
|
219
|
-
const normalizedFsPath = normalizeFsRelativePath(fsPath);
|
|
220
|
-
if (!normalizedFsPath) return;
|
|
221
|
-
candidates.push({
|
|
222
|
-
fsPath: normalizedFsPath,
|
|
223
|
-
fetchPath,
|
|
224
|
-
baseUrl,
|
|
225
|
-
aliases: unique([
|
|
226
|
-
normalizedRef,
|
|
227
|
-
normalizedFsPath,
|
|
228
|
-
...aliases
|
|
229
|
-
].filter(Boolean))
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
if (!isDotRelative) {
|
|
233
|
-
for (const root of searchRoots) if (normalizedRef !== root && !normalizedRef.startsWith(`${root}/`)) addCandidate(`${root}/${normalizedRef}`, `${root}/${normalizedRef}`, rootSourceUrl);
|
|
234
|
-
}
|
|
235
|
-
addCandidate(joinRelativePath(sourceDir, ref), ref, sourceUrl);
|
|
236
|
-
if (!isDotRelative && sourceDir) addCandidate(normalizedRef, normalizedRef, rootSourceUrl);
|
|
237
|
-
for (const candidate of candidates) for (const variant of buildReferencePathVariants(candidate.fsPath)) {
|
|
238
|
-
const fsAliases = new Set([...candidate.aliases, ...variant.aliases]);
|
|
239
|
-
for (const pathWithExtension of buildExtensionVariants(variant.path, searchExtensions)) {
|
|
240
|
-
const extension = extensionOf(pathWithExtension);
|
|
241
|
-
fsAliases.add(pathWithExtension);
|
|
242
|
-
const fetchPath = extensionOf(candidate.fetchPath) ? candidate.fetchPath : `${candidate.fetchPath}${extension}`;
|
|
243
|
-
try {
|
|
244
|
-
const url = new URL(fetchPath, candidate.baseUrl).href;
|
|
245
|
-
if (seen.has(url)) continue;
|
|
246
|
-
seen.add(url);
|
|
247
|
-
attempts.push({
|
|
248
|
-
url,
|
|
249
|
-
fsPaths: [...fsAliases]
|
|
250
|
-
});
|
|
251
|
-
} catch {}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
return attempts;
|
|
255
|
-
}
|
|
256
|
-
async function fetchBinary(url) {
|
|
257
|
-
try {
|
|
258
|
-
const response = await fetch(url);
|
|
259
|
-
if (!response.ok) return null;
|
|
260
|
-
return new Uint8Array(await response.arrayBuffer());
|
|
261
|
-
} catch {
|
|
262
|
-
return null;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
async function autoResolveAssetFiles(rootData, options) {
|
|
266
|
-
const sourcePath = options.sourcePath ?? "";
|
|
267
|
-
if (options.autoResolveAssets === false || !sourcePath) return {};
|
|
268
|
-
const sourceUrl = toFetchableUrl(sourcePath);
|
|
269
|
-
if (!sourceUrl) return {};
|
|
270
|
-
const searchExtensions = options.assetSearchExtensions ?? DEFAULT_ASSET_SEARCH_EXTENSIONS;
|
|
271
|
-
const configuredSearchRoots = normalizeSearchRoots(options.assetSearchRoots);
|
|
272
|
-
const maxFiles = options.maxAssetReferences ?? DEFAULT_MAX_ASSET_REFERENCES;
|
|
273
|
-
const maxDepth = options.maxAssetReferenceDepth ?? DEFAULT_MAX_ASSET_REFERENCE_DEPTH;
|
|
274
|
-
const rootRelativePath = normalizeFsRelativePath(options.fileName ?? fileNameForSource$1(sourcePath));
|
|
275
|
-
const files = {};
|
|
276
|
-
const fetchedUrls = /* @__PURE__ */ new Set();
|
|
277
|
-
const queued = /* @__PURE__ */ new Set();
|
|
278
|
-
const rootRefs = discoverAssetReferences(rootData, searchExtensions, true);
|
|
279
|
-
const inferredSearchRoots = unique([...inferReferencedSearchRoots(rootRefs, configuredSearchRoots), ...discoverAssetSearchRoots(rootData, configuredSearchRoots)]);
|
|
280
|
-
const queue = rootRefs.map((ref) => ({
|
|
281
|
-
ref,
|
|
282
|
-
sourceUrl,
|
|
283
|
-
rootSourceUrl: sourceUrl,
|
|
284
|
-
sourceRelativePath: rootRelativePath,
|
|
285
|
-
searchRoots: inferredSearchRoots,
|
|
286
|
-
depth: 0
|
|
287
|
-
}));
|
|
288
|
-
for (const item of queue) queued.add(`${item.sourceUrl}\n${item.ref}`);
|
|
289
|
-
while (queue.length > 0 && uniqueFileCount(files) < maxFiles) {
|
|
290
|
-
const item = queue.shift();
|
|
291
|
-
if (!item || item.depth > maxDepth) continue;
|
|
292
|
-
for (const attempt of buildFetchAttempts(item.ref, item.sourceUrl, item.sourceRelativePath, searchExtensions, item.rootSourceUrl, item.searchRoots)) {
|
|
293
|
-
if (fetchedUrls.has(attempt.url)) continue;
|
|
294
|
-
fetchedUrls.add(attempt.url);
|
|
295
|
-
const data = await fetchBinary(attempt.url);
|
|
296
|
-
if (!data) continue;
|
|
297
|
-
for (const fsPath of attempt.fsPaths) files[fsPath] = data;
|
|
298
|
-
if (item.depth < maxDepth) {
|
|
299
|
-
const sourceRelativePath = attempt.fsPaths.find((path) => extensionOf(path)) ?? attempt.fsPaths[0];
|
|
300
|
-
if (sourceRelativePath) for (const ref of discoverAssetReferences(data, searchExtensions, !isUsdCrate(data))) {
|
|
301
|
-
const queueKey = `${attempt.url}\n${ref}`;
|
|
302
|
-
if (queued.has(queueKey)) continue;
|
|
303
|
-
queued.add(queueKey);
|
|
304
|
-
const nestedSearchRoots = unique([...item.searchRoots, ...inferReferencedSearchRoots([sourceRelativePath], configuredSearchRoots)]);
|
|
305
|
-
queue.push({
|
|
306
|
-
ref,
|
|
307
|
-
sourceUrl: attempt.url,
|
|
308
|
-
rootSourceUrl: item.rootSourceUrl,
|
|
309
|
-
sourceRelativePath,
|
|
310
|
-
searchRoots: nestedSearchRoots,
|
|
311
|
-
depth: item.depth + 1
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
break;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
return files;
|
|
319
|
-
}
|
|
320
|
-
function isTextureAssetReference(value) {
|
|
321
|
-
if (/^(blob|data):/i.test(value)) return false;
|
|
322
|
-
if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(value)) return false;
|
|
323
|
-
if (value.startsWith("/")) return false;
|
|
324
|
-
return [
|
|
325
|
-
".png",
|
|
326
|
-
".jpg",
|
|
327
|
-
".jpeg",
|
|
328
|
-
".webp"
|
|
329
|
-
].includes(extensionOf(value));
|
|
330
|
-
}
|
|
331
|
-
function collectTextureAssetReferences(value, refs = /* @__PURE__ */ new Set()) {
|
|
332
|
-
if (!value) return refs;
|
|
333
|
-
if (Array.isArray(value)) {
|
|
334
|
-
for (const item of value) collectTextureAssetReferences(item, refs);
|
|
335
|
-
return refs;
|
|
336
|
-
}
|
|
337
|
-
if (typeof value !== "object") return refs;
|
|
338
|
-
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);
|
|
341
|
-
return refs;
|
|
342
|
-
}
|
|
343
|
-
async function autoResolveTextureFiles(metadata, existingFiles, options) {
|
|
344
|
-
const sourcePath = options.sourcePath ?? "";
|
|
345
|
-
if (options.autoResolveAssets === false || !sourcePath) return {};
|
|
346
|
-
const sourceUrl = toFetchableUrl(sourcePath);
|
|
347
|
-
if (!sourceUrl) return {};
|
|
348
|
-
const searchExtensions = options.assetSearchExtensions ?? DEFAULT_ASSET_SEARCH_EXTENSIONS;
|
|
349
|
-
const configuredSearchRoots = normalizeSearchRoots(options.assetSearchRoots);
|
|
350
|
-
const textureRefs = [...collectTextureAssetReferences(metadata)];
|
|
351
|
-
const searchRoots = unique([...inferReferencedSearchRoots(Object.keys(existingFiles), configuredSearchRoots), ...inferReferencedSearchRoots(textureRefs, configuredSearchRoots)]);
|
|
352
|
-
const maxFiles = options.maxAssetReferences ?? DEFAULT_MAX_ASSET_REFERENCES;
|
|
353
|
-
const remainingFiles = Math.max(maxFiles - uniqueFileCount(existingFiles), 0);
|
|
354
|
-
if (remainingFiles === 0) return {};
|
|
355
|
-
const rootRelativePath = normalizeFsRelativePath(options.fileName ?? fileNameForSource$1(sourcePath));
|
|
356
|
-
const files = {};
|
|
357
|
-
const fetchedUrls = /* @__PURE__ */ new Set();
|
|
358
|
-
let resolvedFiles = 0;
|
|
359
|
-
for (const ref of textureRefs) {
|
|
360
|
-
if (resolvedFiles >= remainingFiles) break;
|
|
361
|
-
for (const attempt of buildFetchAttempts(ref, sourceUrl, rootRelativePath, searchExtensions, sourceUrl, searchRoots)) {
|
|
362
|
-
if (attempt.fsPaths.some((path) => existingFiles[path] || files[path])) break;
|
|
363
|
-
if (fetchedUrls.has(attempt.url)) continue;
|
|
364
|
-
fetchedUrls.add(attempt.url);
|
|
365
|
-
const data = await fetchBinary(attempt.url);
|
|
366
|
-
if (!data) continue;
|
|
367
|
-
for (const fsPath of attempt.fsPaths) files[fsPath] = data;
|
|
368
|
-
resolvedFiles += 1;
|
|
369
|
-
break;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
return files;
|
|
373
|
-
}
|
|
374
|
-
function readZipEntryName(data, start, length) {
|
|
375
|
-
return new TextDecoder().decode(data.subarray(start, start + length));
|
|
376
|
-
}
|
|
377
|
-
function extractStoredZipEntries(data) {
|
|
378
|
-
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
379
|
-
const entries = /* @__PURE__ */ new Map();
|
|
380
|
-
let offset = 0;
|
|
381
|
-
while (offset + 30 <= data.byteLength) {
|
|
382
|
-
if (view.getUint32(offset, true) !== 67324752) break;
|
|
383
|
-
const method = view.getUint16(offset + 8, true);
|
|
384
|
-
const compressedSize = view.getUint32(offset + 18, true);
|
|
385
|
-
const fileNameLength = view.getUint16(offset + 26, true);
|
|
386
|
-
const extraLength = view.getUint16(offset + 28, true);
|
|
387
|
-
const nameStart = offset + 30;
|
|
388
|
-
const dataStart = nameStart + fileNameLength + extraLength;
|
|
389
|
-
const dataEnd = dataStart + compressedSize;
|
|
390
|
-
if (dataEnd > data.byteLength) break;
|
|
391
|
-
const name = normalizeFsRelativePath(readZipEntryName(data, nameStart, fileNameLength));
|
|
392
|
-
if (name && method === 0) entries.set(name, data.slice(dataStart, dataEnd));
|
|
393
|
-
offset = dataEnd;
|
|
394
|
-
}
|
|
395
|
-
return entries;
|
|
396
|
-
}
|
|
397
|
-
function createTextureResolverFromEntries(entries) {
|
|
398
|
-
if (typeof Blob === "undefined" || typeof URL === "undefined" || typeof URL.createObjectURL !== "function") return null;
|
|
399
|
-
const imageEntries = new Map([...entries].filter(([path]) => [
|
|
400
|
-
".png",
|
|
401
|
-
".jpg",
|
|
402
|
-
".jpeg",
|
|
403
|
-
".webp"
|
|
404
|
-
].includes(extensionOf(path))));
|
|
405
|
-
if (imageEntries.size === 0) return null;
|
|
406
|
-
const byBaseName = /* @__PURE__ */ new Map();
|
|
407
|
-
for (const path of imageEntries.keys()) {
|
|
408
|
-
const name = baseName(path);
|
|
409
|
-
byBaseName.set(name, byBaseName.has(name) ? null : path);
|
|
410
|
-
}
|
|
411
|
-
const urls = /* @__PURE__ */ new Map();
|
|
412
|
-
const urlForEntry = (path) => {
|
|
413
|
-
const entry = imageEntries.get(path);
|
|
414
|
-
if (!entry) return null;
|
|
415
|
-
let url = urls.get(path);
|
|
416
|
-
if (!url) {
|
|
417
|
-
url = URL.createObjectURL(new Blob([toArrayBuffer(entry)], { type: contentTypeForPath(path) }));
|
|
418
|
-
urls.set(path, url);
|
|
419
|
-
}
|
|
420
|
-
return url;
|
|
421
|
-
};
|
|
422
|
-
const resolvePath = (value) => {
|
|
423
|
-
if (!value) return null;
|
|
424
|
-
const normalized = normalizeFsRelativePath(value.split(/[?#]/)[0] ?? value);
|
|
425
|
-
if (!normalized) return null;
|
|
426
|
-
if (imageEntries.has(normalized)) return urlForEntry(normalized);
|
|
427
|
-
const suffixMatches = [...imageEntries.keys()].filter((path) => path.endsWith(`/${normalized}`));
|
|
428
|
-
if (suffixMatches.length === 1 && suffixMatches[0]) return urlForEntry(suffixMatches[0]);
|
|
429
|
-
const virtualFsMatches = [...imageEntries.keys()].filter((path) => normalized.endsWith(`/${path}`));
|
|
430
|
-
if (virtualFsMatches.length === 1 && virtualFsMatches[0]) return urlForEntry(virtualFsMatches[0]);
|
|
431
|
-
const uniqueBaseName = byBaseName.get(baseName(normalized));
|
|
432
|
-
return uniqueBaseName ? urlForEntry(uniqueBaseName) : null;
|
|
433
|
-
};
|
|
434
|
-
return {
|
|
435
|
-
urls,
|
|
436
|
-
resolve(asset) {
|
|
437
|
-
return resolvePath(asset.resolvedPath) ?? resolvePath(asset.path) ?? resolvePath(asset.url) ?? null;
|
|
438
|
-
}
|
|
439
|
-
};
|
|
440
|
-
}
|
|
441
|
-
function createPackageTextureResolver(data) {
|
|
442
|
-
return createTextureResolverFromEntries(extractStoredZipEntries(data));
|
|
443
|
-
}
|
|
444
|
-
//#endregion
|
|
4
|
+
import { autoResolveAssetFiles, autoResolveTextureFiles, createPackageTextureResolver, createTextureResolverFromEntries, findPackageRootLayer } from "@openusd-wasm/utils";
|
|
445
5
|
//#region src/metadata.ts
|
|
446
6
|
const MATERIAL_INPUT_SUFFIXES = [
|
|
447
7
|
"diffuseColor",
|
|
@@ -458,6 +18,9 @@ const MATERIAL_INPUT_SUFFIXES = [
|
|
|
458
18
|
"file",
|
|
459
19
|
"wrapS",
|
|
460
20
|
"wrapT",
|
|
21
|
+
"st",
|
|
22
|
+
"in",
|
|
23
|
+
"varname",
|
|
461
24
|
"scale",
|
|
462
25
|
"translation",
|
|
463
26
|
"rotation"
|
|
@@ -476,6 +39,13 @@ function dispose$1(value) {
|
|
|
476
39
|
function disposeAll(values) {
|
|
477
40
|
for (let i = values.length - 1; i >= 0; --i) dispose$1(values[i]);
|
|
478
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
|
+
}
|
|
479
49
|
function isValid$1(value) {
|
|
480
50
|
if (!value) return false;
|
|
481
51
|
if (typeof value.IsValid === "function") return Boolean(value.IsValid());
|
|
@@ -533,170 +103,24 @@ function toVector4(value) {
|
|
|
533
103
|
}
|
|
534
104
|
return null;
|
|
535
105
|
}
|
|
536
|
-
function identityMatrix() {
|
|
537
|
-
return [
|
|
538
|
-
1,
|
|
539
|
-
0,
|
|
540
|
-
0,
|
|
541
|
-
0,
|
|
542
|
-
0,
|
|
543
|
-
1,
|
|
544
|
-
0,
|
|
545
|
-
0,
|
|
546
|
-
0,
|
|
547
|
-
0,
|
|
548
|
-
1,
|
|
549
|
-
0,
|
|
550
|
-
0,
|
|
551
|
-
0,
|
|
552
|
-
0,
|
|
553
|
-
1
|
|
554
|
-
];
|
|
555
|
-
}
|
|
556
|
-
function multiplyMatrices(a, b) {
|
|
557
|
-
const out = new Array(16).fill(0);
|
|
558
|
-
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);
|
|
559
|
-
return out;
|
|
560
|
-
}
|
|
561
106
|
function matricesNearlyEqual(a, b) {
|
|
562
107
|
if (!a || !b || a.length < 16 || b.length < 16) return false;
|
|
563
108
|
return a.every((value, index) => Math.abs(value - (b[index] ?? 0)) < 1e-8);
|
|
564
109
|
}
|
|
565
|
-
function matrixFromXformOp(opName, value) {
|
|
566
|
-
const numbers = toNumberArray(value);
|
|
567
|
-
if (numbers.length === 0) return null;
|
|
568
|
-
if (opName.startsWith("xformOp:transform")) return numbers.length >= 16 ? numbers.slice(0, 16) : null;
|
|
569
|
-
if (opName.startsWith("xformOp:translate")) return [
|
|
570
|
-
1,
|
|
571
|
-
0,
|
|
572
|
-
0,
|
|
573
|
-
0,
|
|
574
|
-
0,
|
|
575
|
-
1,
|
|
576
|
-
0,
|
|
577
|
-
0,
|
|
578
|
-
0,
|
|
579
|
-
0,
|
|
580
|
-
1,
|
|
581
|
-
0,
|
|
582
|
-
numbers[0] ?? 0,
|
|
583
|
-
numbers[1] ?? 0,
|
|
584
|
-
numbers[2] ?? 0,
|
|
585
|
-
1
|
|
586
|
-
];
|
|
587
|
-
if (opName.startsWith("xformOp:scale")) return [
|
|
588
|
-
numbers[0] ?? 1,
|
|
589
|
-
0,
|
|
590
|
-
0,
|
|
591
|
-
0,
|
|
592
|
-
0,
|
|
593
|
-
numbers[1] ?? numbers[0] ?? 1,
|
|
594
|
-
0,
|
|
595
|
-
0,
|
|
596
|
-
0,
|
|
597
|
-
0,
|
|
598
|
-
numbers[2] ?? numbers[0] ?? 1,
|
|
599
|
-
0,
|
|
600
|
-
0,
|
|
601
|
-
0,
|
|
602
|
-
0,
|
|
603
|
-
1
|
|
604
|
-
];
|
|
605
|
-
if (opName.startsWith("xformOp:rotate")) return rotationMatrixFromXformOp(opName, numbers);
|
|
606
|
-
return null;
|
|
607
|
-
}
|
|
608
|
-
function rotationMatrixFromXformOp(opName, degrees) {
|
|
609
|
-
const rotateX = (degree) => {
|
|
610
|
-
const radians = degree * Math.PI / 180;
|
|
611
|
-
const cos = Math.cos(radians);
|
|
612
|
-
const sin = Math.sin(radians);
|
|
613
|
-
return [
|
|
614
|
-
1,
|
|
615
|
-
0,
|
|
616
|
-
0,
|
|
617
|
-
0,
|
|
618
|
-
0,
|
|
619
|
-
cos,
|
|
620
|
-
sin,
|
|
621
|
-
0,
|
|
622
|
-
0,
|
|
623
|
-
-sin,
|
|
624
|
-
cos,
|
|
625
|
-
0,
|
|
626
|
-
0,
|
|
627
|
-
0,
|
|
628
|
-
0,
|
|
629
|
-
1
|
|
630
|
-
];
|
|
631
|
-
};
|
|
632
|
-
const rotateY = (degree) => {
|
|
633
|
-
const radians = degree * Math.PI / 180;
|
|
634
|
-
const cos = Math.cos(radians);
|
|
635
|
-
const sin = Math.sin(radians);
|
|
636
|
-
return [
|
|
637
|
-
cos,
|
|
638
|
-
0,
|
|
639
|
-
-sin,
|
|
640
|
-
0,
|
|
641
|
-
0,
|
|
642
|
-
1,
|
|
643
|
-
0,
|
|
644
|
-
0,
|
|
645
|
-
sin,
|
|
646
|
-
0,
|
|
647
|
-
cos,
|
|
648
|
-
0,
|
|
649
|
-
0,
|
|
650
|
-
0,
|
|
651
|
-
0,
|
|
652
|
-
1
|
|
653
|
-
];
|
|
654
|
-
};
|
|
655
|
-
const rotateZ = (degree) => {
|
|
656
|
-
const radians = degree * Math.PI / 180;
|
|
657
|
-
const cos = Math.cos(radians);
|
|
658
|
-
const sin = Math.sin(radians);
|
|
659
|
-
return [
|
|
660
|
-
cos,
|
|
661
|
-
sin,
|
|
662
|
-
0,
|
|
663
|
-
0,
|
|
664
|
-
-sin,
|
|
665
|
-
cos,
|
|
666
|
-
0,
|
|
667
|
-
0,
|
|
668
|
-
0,
|
|
669
|
-
0,
|
|
670
|
-
1,
|
|
671
|
-
0,
|
|
672
|
-
0,
|
|
673
|
-
0,
|
|
674
|
-
0,
|
|
675
|
-
1
|
|
676
|
-
];
|
|
677
|
-
};
|
|
678
|
-
const suffix = opName.split(":")[1] ?? "";
|
|
679
|
-
if (suffix === "rotateX") return rotateX(degrees[0] ?? 0);
|
|
680
|
-
if (suffix === "rotateY") return rotateY(degrees[0] ?? 0);
|
|
681
|
-
if (suffix === "rotateZ") return rotateZ(degrees[0] ?? 0);
|
|
682
|
-
const axes = suffix.replace(/^rotate/, "").split("");
|
|
683
|
-
if (axes.length === 0) return null;
|
|
684
|
-
return axes.reduce((matrix, axis, index) => {
|
|
685
|
-
const degree = degrees[index] ?? 0;
|
|
686
|
-
const next = axis === "X" ? rotateX(degree) : axis === "Y" ? rotateY(degree) : axis === "Z" ? rotateZ(degree) : null;
|
|
687
|
-
return next ? multiplyMatrices(matrix, next) : matrix;
|
|
688
|
-
}, identityMatrix());
|
|
689
|
-
}
|
|
690
110
|
function attr(prim, name, time, defaultValue = null) {
|
|
691
111
|
const attribute = prim.GetAttribute(name);
|
|
692
112
|
try {
|
|
693
|
-
|
|
694
|
-
const value = attribute.Get(time);
|
|
695
|
-
return value === null || value === void 0 ? defaultValue : normalizeValue(value);
|
|
113
|
+
return attributeValue(attribute, time, defaultValue);
|
|
696
114
|
} finally {
|
|
697
115
|
dispose$1(attribute);
|
|
698
116
|
}
|
|
699
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
|
+
}
|
|
700
124
|
function attrMetadata(prim, name, key, defaultValue = null) {
|
|
701
125
|
const attribute = prim.GetAttribute(name);
|
|
702
126
|
try {
|
|
@@ -707,20 +131,64 @@ function attrMetadata(prim, name, key, defaultValue = null) {
|
|
|
707
131
|
dispose$1(attribute);
|
|
708
132
|
}
|
|
709
133
|
}
|
|
710
|
-
function
|
|
711
|
-
|
|
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]();
|
|
712
154
|
try {
|
|
713
|
-
|
|
714
|
-
const targets = relationship.GetTargets();
|
|
715
|
-
return Array.isArray(targets) ? targets.map(String) : [];
|
|
155
|
+
return relationshipTargetPaths(relationship);
|
|
716
156
|
} finally {
|
|
717
157
|
dispose$1(relationship);
|
|
718
158
|
}
|
|
719
159
|
}
|
|
720
|
-
function
|
|
721
|
-
const
|
|
722
|
-
if (!
|
|
723
|
-
|
|
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
|
+
}
|
|
724
192
|
}
|
|
725
193
|
function primChildren(prim) {
|
|
726
194
|
const children = prim.GetChildren();
|
|
@@ -734,24 +202,37 @@ function primAtPath(pxr, stage, path) {
|
|
|
734
202
|
dispose$1(sdfPath);
|
|
735
203
|
}
|
|
736
204
|
}
|
|
737
|
-
function materialBinding(prim) {
|
|
738
|
-
|
|
739
|
-
let ownsCurrent = false;
|
|
205
|
+
function materialBinding(pxr, prim) {
|
|
206
|
+
const binding = new pxr.UsdShade.MaterialBindingAPI(prim);
|
|
740
207
|
try {
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
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);
|
|
748
230
|
}
|
|
749
|
-
return null;
|
|
750
231
|
} finally {
|
|
751
|
-
|
|
232
|
+
dispose$1(binding);
|
|
752
233
|
}
|
|
753
234
|
}
|
|
754
|
-
function localTransformForPrim(pxr, prim) {
|
|
235
|
+
function localTransformForPrim(pxr, prim, time) {
|
|
755
236
|
if (!prim.IsA("Xformable")) return {
|
|
756
237
|
localMatrix: null,
|
|
757
238
|
resetsXformStack: false
|
|
@@ -762,7 +243,7 @@ function localTransformForPrim(pxr, prim) {
|
|
|
762
243
|
localMatrix: null,
|
|
763
244
|
resetsXformStack: false
|
|
764
245
|
};
|
|
765
|
-
const transform = xformable.GetLocalTransformation();
|
|
246
|
+
const transform = xformable.GetLocalTransformation(time);
|
|
766
247
|
return {
|
|
767
248
|
localMatrix: toNumberArray(transform?.matrix),
|
|
768
249
|
resetsXformStack: Boolean(transform?.resetsXformStack)
|
|
@@ -782,7 +263,7 @@ function parentPathForPrim(prim) {
|
|
|
782
263
|
}
|
|
783
264
|
function getModelView(pxr, prims, time) {
|
|
784
265
|
return { prims: prims.map((prim) => {
|
|
785
|
-
const transform = localTransformForPrim(pxr, prim);
|
|
266
|
+
const transform = localTransformForPrim(pxr, prim, time);
|
|
786
267
|
return {
|
|
787
268
|
path: String(prim.GetPath()),
|
|
788
269
|
parentPath: parentPathForPrim(prim),
|
|
@@ -831,13 +312,27 @@ function asFloat(value, fallback = 0) {
|
|
|
831
312
|
const number = asFiniteNumber(value);
|
|
832
313
|
return number === null ? fallback : number;
|
|
833
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
|
+
}
|
|
834
329
|
function shaderInputConnectionPath(shader, inputName) {
|
|
835
|
-
const
|
|
330
|
+
const input = shader.GetInput(inputName);
|
|
836
331
|
try {
|
|
837
|
-
if (!isValid$1(
|
|
838
|
-
return
|
|
332
|
+
if (!isValid$1(input)) return null;
|
|
333
|
+
return inputSourcePrimPath(input);
|
|
839
334
|
} finally {
|
|
840
|
-
dispose$1(
|
|
335
|
+
dispose$1(input);
|
|
841
336
|
}
|
|
842
337
|
}
|
|
843
338
|
function shaderChildByPath(material, path) {
|
|
@@ -850,29 +345,41 @@ function shaderChildByPath(material, path) {
|
|
|
850
345
|
}
|
|
851
346
|
}
|
|
852
347
|
function primvarNameForTextureShader(pxr, stage, material, textureShader, time) {
|
|
853
|
-
const stSourcePath = shaderInputConnectionPath(textureShader, "
|
|
348
|
+
const stSourcePath = shaderInputConnectionPath(textureShader, "st");
|
|
854
349
|
if (!stSourcePath) return null;
|
|
855
350
|
const stSource = shaderChildByPath(material, stSourcePath) ?? primAtPath(pxr, stage, stSourcePath);
|
|
856
351
|
try {
|
|
857
352
|
if (!isValid$1(stSource)) return null;
|
|
858
|
-
const
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
const nestedSourcePath = shaderInputConnectionPath(stSource, "inputs:in") ?? shaderInputConnectionPath(stSource, "inputs:st");
|
|
865
|
-
if (!nestedSourcePath) return null;
|
|
866
|
-
const nestedSource = shaderChildByPath(material, nestedSourcePath) ?? primAtPath(pxr, stage, nestedSourcePath);
|
|
867
|
-
try {
|
|
868
|
-
if (!isValid$1(nestedSource) || attr(nestedSource, "info:id", time) !== "UsdPrimvarReader_float2") return null;
|
|
869
|
-
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);
|
|
870
359
|
return typeof varname === "string" && varname ? varname : null;
|
|
871
|
-
} finally {
|
|
872
|
-
dispose$1(nestedSource);
|
|
873
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);
|
|
874
382
|
}
|
|
875
|
-
return null;
|
|
876
383
|
} finally {
|
|
877
384
|
dispose$1(stSource);
|
|
878
385
|
}
|
|
@@ -884,10 +391,16 @@ function texturePrimvarForMaterial(pxr, stage, materialPath, time) {
|
|
|
884
391
|
if (!isValid$1(material)) return "primvars:st";
|
|
885
392
|
const children = primChildren(material);
|
|
886
393
|
try {
|
|
887
|
-
for (const
|
|
888
|
-
if (
|
|
889
|
-
const
|
|
890
|
-
|
|
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
|
+
}
|
|
891
404
|
}
|
|
892
405
|
} finally {
|
|
893
406
|
disposeAll(children);
|
|
@@ -904,30 +417,36 @@ function textureTransformForMaterial(pxr, stage, materialPath, time) {
|
|
|
904
417
|
if (!isValid$1(material)) return null;
|
|
905
418
|
const children = primChildren(material);
|
|
906
419
|
try {
|
|
907
|
-
for (const
|
|
908
|
-
if (
|
|
909
|
-
const
|
|
420
|
+
for (const child of children) {
|
|
421
|
+
if (child.GetTypeName() !== "Shader") continue;
|
|
422
|
+
const shader = new pxr.UsdShade.Shader(child);
|
|
910
423
|
try {
|
|
911
|
-
if (!isValid$1(
|
|
912
|
-
const sourcePath =
|
|
424
|
+
if (!isValid$1(shader) || shaderId(shader) !== "UsdUVTexture") continue;
|
|
425
|
+
const sourcePath = shaderInputConnectionPath(shader, "st");
|
|
913
426
|
if (!sourcePath) return null;
|
|
914
427
|
const transform = primAtPath(pxr, stage, sourcePath);
|
|
915
428
|
try {
|
|
916
|
-
if (!isValid$1(transform)
|
|
917
|
-
const
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
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
|
+
}
|
|
926
445
|
} finally {
|
|
927
446
|
dispose$1(transform);
|
|
928
447
|
}
|
|
929
448
|
} finally {
|
|
930
|
-
dispose$1(
|
|
449
|
+
dispose$1(shader);
|
|
931
450
|
}
|
|
932
451
|
}
|
|
933
452
|
} finally {
|
|
@@ -963,7 +482,7 @@ function triangulateMesh(pxr, stage, prim, time) {
|
|
|
963
482
|
const faceIndices = toNumberArray(attr(prim, "faceVertexIndices", time, []));
|
|
964
483
|
const normals = toArray(attr(prim, "normals", time, []));
|
|
965
484
|
const normalInterpolation = String(attrMetadata(prim, "normals", "interpolation", attr(prim, "normals:interpolation", time, "")) || "") || null;
|
|
966
|
-
const boundMaterial = materialBinding(prim);
|
|
485
|
+
const boundMaterial = materialBinding(pxr, prim);
|
|
967
486
|
const uv = meshPrimvar(prim, texturePrimvarForMaterial(pxr, stage, boundMaterial, time), time);
|
|
968
487
|
const colors = toArray(attr(prim, "primvars:displayColor", time, []));
|
|
969
488
|
const opacities = toArray(attr(prim, "primvars:displayOpacity", time, []));
|
|
@@ -1022,178 +541,244 @@ function getModelElements(pxr, stage, prims, time) {
|
|
|
1022
541
|
elements.push({
|
|
1023
542
|
path: String(prim.GetPath()),
|
|
1024
543
|
doubleSided: Boolean(attr(prim, "doubleSided", time, false)),
|
|
1025
|
-
material: materialBinding(prim),
|
|
544
|
+
material: materialBinding(pxr, prim),
|
|
1026
545
|
geometry: triangulateMesh(pxr, stage, prim, time)
|
|
1027
546
|
});
|
|
1028
547
|
}
|
|
1029
548
|
return elements;
|
|
1030
549
|
}
|
|
1031
|
-
function
|
|
550
|
+
function collectShadeInputs(connectable, time) {
|
|
1032
551
|
const inputs = {};
|
|
1033
|
-
const
|
|
552
|
+
const shadeInputs = connectable.GetInputs();
|
|
1034
553
|
try {
|
|
1035
|
-
for (const
|
|
1036
|
-
const
|
|
1037
|
-
if (!
|
|
1038
|
-
|
|
1039
|
-
const value =
|
|
1040
|
-
const connections =
|
|
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();
|
|
1041
560
|
if (value !== null && value !== void 0) inputs[name] = normalizeValue(value);
|
|
1042
|
-
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
|
+
}
|
|
1043
566
|
}
|
|
1044
567
|
} finally {
|
|
1045
|
-
disposeAll(
|
|
568
|
+
disposeAll(shadeInputs);
|
|
569
|
+
}
|
|
570
|
+
return inputs;
|
|
571
|
+
}
|
|
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
|
+
}
|
|
1046
587
|
}
|
|
1047
588
|
return inputs;
|
|
1048
589
|
}
|
|
1049
|
-
function getModelMaterials(prims, time) {
|
|
590
|
+
function getModelMaterials(pxr, prims, time) {
|
|
1050
591
|
const materials = [];
|
|
1051
592
|
for (const prim of prims) {
|
|
1052
593
|
if (prim.GetTypeName() !== "Material") continue;
|
|
594
|
+
const material = new pxr.UsdShade.Material(prim);
|
|
1053
595
|
const children = primChildren(prim);
|
|
1054
596
|
const shaders = [];
|
|
1055
597
|
try {
|
|
598
|
+
if (!isValid$1(material)) continue;
|
|
1056
599
|
for (const child of children) {
|
|
1057
600
|
if (child.GetTypeName() !== "Shader") continue;
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
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
|
+
}
|
|
1067
619
|
}
|
|
620
|
+
materials.push({
|
|
621
|
+
path: String(prim.GetPath()),
|
|
622
|
+
inputs: collectShadeInputs(material, time),
|
|
623
|
+
shaders
|
|
624
|
+
});
|
|
1068
625
|
} finally {
|
|
1069
626
|
disposeAll(children);
|
|
627
|
+
dispose$1(material);
|
|
1070
628
|
}
|
|
1071
|
-
materials.push({
|
|
1072
|
-
path: String(prim.GetPath()),
|
|
1073
|
-
inputs: collectShaderInputs(prim, time),
|
|
1074
|
-
shaders
|
|
1075
|
-
});
|
|
1076
629
|
}
|
|
1077
630
|
return materials;
|
|
1078
631
|
}
|
|
1079
|
-
function driveForNamespace(prim, namespace, time) {
|
|
632
|
+
function driveForNamespace(pxr, prim, namespace, time) {
|
|
633
|
+
const driveAPI = new pxr.UsdPhysics.DriveAPI(prim, namespace);
|
|
1080
634
|
const drive = {
|
|
1081
|
-
targetPosition:
|
|
1082
|
-
targetVelocity:
|
|
1083
|
-
stiffness:
|
|
1084
|
-
damping:
|
|
1085
|
-
maxForce:
|
|
635
|
+
targetPosition: null,
|
|
636
|
+
targetVelocity: null,
|
|
637
|
+
stiffness: null,
|
|
638
|
+
damping: null,
|
|
639
|
+
maxForce: null
|
|
1086
640
|
};
|
|
1087
|
-
|
|
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
|
+
}
|
|
1088
652
|
}
|
|
1089
653
|
function jointTypeForPrim(typeName) {
|
|
1090
654
|
if (JOINT_TYPES[typeName]) return JOINT_TYPES[typeName];
|
|
1091
655
|
if (typeName.startsWith("Physics") && typeName.endsWith("Joint")) return typeName.slice(7, -5).toLowerCase() || "joint";
|
|
1092
656
|
return null;
|
|
1093
657
|
}
|
|
1094
|
-
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) {
|
|
1095
704
|
const joints = [];
|
|
1096
705
|
for (const prim of prims) {
|
|
1097
706
|
const typeName = String(prim.GetTypeName());
|
|
1098
707
|
const jointType = jointTypeForPrim(typeName);
|
|
1099
708
|
if (!jointType) continue;
|
|
1100
|
-
const
|
|
1101
|
-
|
|
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);
|
|
1102
716
|
const drives = {};
|
|
1103
717
|
if (angularDrive) drives.angular = angularDrive;
|
|
1104
718
|
if (linearDrive) drives.linear = linearDrive;
|
|
1105
|
-
const body0 =
|
|
1106
|
-
const body1 =
|
|
719
|
+
const body0 = schemaRelationshipTargets(joint, "GetBody0Rel");
|
|
720
|
+
const body1 = schemaRelationshipTargets(joint, "GetBody1Rel");
|
|
1107
721
|
const drive = jointType === "prismatic" ? linearDrive ?? angularDrive : angularDrive ?? linearDrive;
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
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
|
+
}
|
|
1142
759
|
}
|
|
1143
760
|
return joints;
|
|
1144
761
|
}
|
|
1145
|
-
function stageTimingFromLayer(rootLayer) {
|
|
1146
|
-
const text = String(rootLayer.ExportToString?.() ?? "");
|
|
1147
|
-
const numberFor = (name) => {
|
|
1148
|
-
const match = new RegExp(`${name}\\s*=\\s*(-?\\d+(?:\\.\\d+)?)`).exec(text);
|
|
1149
|
-
if (!match?.[1]) return null;
|
|
1150
|
-
const value = Number(match[1]);
|
|
1151
|
-
return Number.isFinite(value) ? value : null;
|
|
1152
|
-
};
|
|
1153
|
-
return {
|
|
1154
|
-
startTimeCode: numberFor("startTimeCode"),
|
|
1155
|
-
endTimeCode: numberFor("endTimeCode"),
|
|
1156
|
-
timeCodesPerSecond: numberFor("timeCodesPerSecond") ?? 24
|
|
1157
|
-
};
|
|
1158
|
-
}
|
|
1159
762
|
function getStageInfo(pxr, stage, options) {
|
|
1160
763
|
const defaultPrim = stage.GetDefaultPrim();
|
|
1161
|
-
const rootLayer = stage.GetRootLayer();
|
|
1162
764
|
try {
|
|
1163
|
-
const timing = stageTimingFromLayer(rootLayer);
|
|
1164
765
|
return {
|
|
1165
766
|
sourcePath: options.sourcePath,
|
|
1166
767
|
rootLayerIdentifier: options.rootLayerIdentifier,
|
|
1167
768
|
defaultPrim: isValid$1(defaultPrim) ? String(defaultPrim.GetPath()) : null,
|
|
1168
769
|
upAxis: String(pxr.UsdGeom.GetStageUpAxis(stage)),
|
|
1169
|
-
|
|
770
|
+
startTimeCode: stage.GetStartTimeCode(),
|
|
771
|
+
endTimeCode: stage.GetEndTimeCode(),
|
|
772
|
+
timeCodesPerSecond: stage.GetTimeCodesPerSecond()
|
|
1170
773
|
};
|
|
1171
774
|
} finally {
|
|
1172
|
-
dispose$1(rootLayer);
|
|
1173
775
|
dispose$1(defaultPrim);
|
|
1174
776
|
}
|
|
1175
777
|
}
|
|
1176
|
-
function localMatrixFromXformOps(prim, time) {
|
|
1177
|
-
const opOrder = toArray(attr(prim, "xformOpOrder", time, [])).map(String);
|
|
1178
|
-
if (opOrder.length === 0) return null;
|
|
1179
|
-
let matrix = identityMatrix();
|
|
1180
|
-
let foundOp = false;
|
|
1181
|
-
for (const opName of opOrder) {
|
|
1182
|
-
if (opName.startsWith("!")) {
|
|
1183
|
-
matrix = identityMatrix();
|
|
1184
|
-
continue;
|
|
1185
|
-
}
|
|
1186
|
-
const opMatrix = matrixFromXformOp(opName, attr(prim, opName, time));
|
|
1187
|
-
if (!opMatrix) continue;
|
|
1188
|
-
matrix = multiplyMatrices(matrix, opMatrix);
|
|
1189
|
-
foundOp = true;
|
|
1190
|
-
}
|
|
1191
|
-
return foundOp ? matrix : null;
|
|
1192
|
-
}
|
|
1193
778
|
function sampleLocalMatrix(pxr, prim, frame) {
|
|
1194
779
|
const time = new pxr.Usd.TimeCode(frame);
|
|
1195
780
|
try {
|
|
1196
|
-
return
|
|
781
|
+
return localTransformForPrim(pxr, prim, time).localMatrix;
|
|
1197
782
|
} finally {
|
|
1198
783
|
dispose$1(time);
|
|
1199
784
|
}
|
|
@@ -1210,10 +795,10 @@ function animationSampleFrames(start, end) {
|
|
|
1210
795
|
});
|
|
1211
796
|
}
|
|
1212
797
|
function getModelAnimations(pxr, prims, stageInfo) {
|
|
1213
|
-
const start = stageInfo.startTimeCode
|
|
1214
|
-
const end = stageInfo.endTimeCode
|
|
1215
|
-
const timeCodesPerSecond = stageInfo.timeCodesPerSecond
|
|
1216
|
-
if (
|
|
798
|
+
const start = stageInfo.startTimeCode;
|
|
799
|
+
const end = stageInfo.endTimeCode;
|
|
800
|
+
const timeCodesPerSecond = stageInfo.timeCodesPerSecond;
|
|
801
|
+
if (end <= start) return [];
|
|
1217
802
|
const frames = animationSampleFrames(start, end);
|
|
1218
803
|
if (frames.length < 2) return [];
|
|
1219
804
|
const transforms = [];
|
|
@@ -1260,8 +845,8 @@ function extractUSDModelData(pxr, stage, options = {}) {
|
|
|
1260
845
|
stage: stageInfo,
|
|
1261
846
|
view: getModelView(pxr, prims, time),
|
|
1262
847
|
elements: getModelElements(pxr, stage, prims, time),
|
|
1263
|
-
materials: getModelMaterials(prims, time),
|
|
1264
|
-
joints: getModelJoints(prims, time),
|
|
848
|
+
materials: getModelMaterials(pxr, prims, time),
|
|
849
|
+
joints: getModelJoints(pxr, prims, time),
|
|
1265
850
|
animations: getModelAnimations(pxr, prims, stageInfo)
|
|
1266
851
|
};
|
|
1267
852
|
} finally {
|
|
@@ -1566,13 +1151,19 @@ function deleteFileIfExists(pxr, path) {
|
|
|
1566
1151
|
if (pxr.FS.exists(path)) pxr.FS.deleteFile(path);
|
|
1567
1152
|
} catch {}
|
|
1568
1153
|
}
|
|
1569
|
-
|
|
1570
|
-
const directory = joinFsPath(
|
|
1154
|
+
function createUSDInputDirectory(pxr, workingDirectory) {
|
|
1155
|
+
const directory = joinFsPath(workingDirectory, String(++nextLoadId));
|
|
1571
1156
|
pxr.FS.createDir(directory);
|
|
1572
|
-
|
|
1157
|
+
return directory;
|
|
1158
|
+
}
|
|
1159
|
+
async function writeUSDFiles(pxr, directory, files) {
|
|
1160
|
+
for (const [relativePath, file] of Object.entries(files ?? {})) {
|
|
1573
1161
|
const filePath = joinFsPath(directory, relativePath);
|
|
1574
1162
|
pxr.FS.writeFile(filePath, await sourceToWritableData(file));
|
|
1575
1163
|
}
|
|
1164
|
+
}
|
|
1165
|
+
async function writeUSDInput(pxr, directory, input, options) {
|
|
1166
|
+
await writeUSDFiles(pxr, directory, options.files);
|
|
1576
1167
|
const path = joinFsPath(directory, sanitizeFileName(options.fileName));
|
|
1577
1168
|
pxr.FS.writeFile(path, input);
|
|
1578
1169
|
return path;
|
|
@@ -1655,15 +1246,19 @@ var USDLoader = class extends Loader {
|
|
|
1655
1246
|
const extension = extensionForPath(mergedOptions.fileName);
|
|
1656
1247
|
const writableData = await sourceToWritableData(input);
|
|
1657
1248
|
const packageTextureResolver = extension === "usdz" && writableData instanceof Uint8Array ? createPackageTextureResolver(writableData) : null;
|
|
1658
|
-
|
|
1659
|
-
const
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
}
|
|
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
|
|
1665
1255
|
});
|
|
1666
|
-
|
|
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);
|
|
1667
1262
|
try {
|
|
1668
1263
|
const metadata = extractUSDModelData(pxr, stage, {
|
|
1669
1264
|
sourcePath: mergedOptions.sourcePath,
|
|
@@ -1719,7 +1314,7 @@ function limitsForJoint(joint) {
|
|
|
1719
1314
|
}
|
|
1720
1315
|
function initialValueForJoint(joint) {
|
|
1721
1316
|
const { lower, upper } = limitsForJoint(joint);
|
|
1722
|
-
return clamp(joint.drive?.targetPosition ??
|
|
1317
|
+
return clamp(joint.drive?.targetPosition ?? 0, lower, upper);
|
|
1723
1318
|
}
|
|
1724
1319
|
function isManipulableJoint(joint) {
|
|
1725
1320
|
return joint.enabled && (joint.jointType === "revolute" || joint.jointType === "prismatic");
|
|
@@ -1785,7 +1380,12 @@ function jointValueKey(model, joint) {
|
|
|
1785
1380
|
return `${model.root.uuid}:${joint.path}`;
|
|
1786
1381
|
}
|
|
1787
1382
|
function localAxisForJoint(joint) {
|
|
1788
|
-
|
|
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());
|
|
1789
1389
|
}
|
|
1790
1390
|
function localPivotForJoint(joint) {
|
|
1791
1391
|
return new THREE.Vector3(joint.localPos0[0] ?? 0, joint.localPos0[1] ?? 0, joint.localPos0[2] ?? 0);
|