three-usd-robot 0.11.0 → 0.13.0
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 +32 -280
- package/dist/MeshBinding-B_8RhuQE.d.ts +288 -0
- package/dist/{ThreeUsdRobot-BxnCluuK.d.ts → ThreeUsdRobot-X1zbpRZo.d.ts} +38 -8
- package/dist/{ThreeUsdRobotLoader-C-E9uwEe.d.ts → ThreeUsdRobotLoader-u3d1yoLM.d.ts} +11 -3
- package/dist/{buildKinematicTree-BCySuZZn.d.ts → buildKinematicTree-Q9JOjAjM.d.ts} +17 -3
- package/dist/bytes-CxGRGry_.d.ts +14 -0
- package/dist/{chunk-BCRRXGNB.js → chunk-5ZPHZ5ZH.js} +81 -6
- package/dist/chunk-5ZPHZ5ZH.js.map +1 -0
- package/dist/{chunk-AXPMXEQC.js → chunk-FUVHAORT.js} +77 -717
- package/dist/chunk-FUVHAORT.js.map +1 -0
- package/dist/{chunk-5SVRTKS4.js → chunk-GRJGPHLW.js} +18 -11
- package/dist/chunk-GRJGPHLW.js.map +1 -0
- package/dist/chunk-JGIVJXBU.js +54 -0
- package/dist/chunk-JGIVJXBU.js.map +1 -0
- package/dist/{chunk-ENWFOYHU.js → chunk-JN2QPDB3.js} +101 -14
- package/dist/chunk-JN2QPDB3.js.map +1 -0
- package/dist/chunk-PPPRB6KE.js +963 -0
- package/dist/chunk-PPPRB6KE.js.map +1 -0
- package/dist/{chunk-LDO5FKQS.js → chunk-YGJ23CG3.js} +4 -53
- package/dist/chunk-YGJ23CG3.js.map +1 -0
- package/dist/core.d.ts +8 -65
- package/dist/core.js +5 -3
- package/dist/extras.d.ts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/helpers.js +3 -2
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.ts +22 -263
- package/dist/index.js +35 -9
- package/dist/index.js.map +1 -1
- package/dist/nodes.d.ts +49 -0
- package/dist/nodes.js +439 -0
- package/dist/nodes.js.map +1 -0
- package/dist/parseMdl-vfzBGoMr.d.ts +87 -0
- package/dist/react.d.ts +6 -4
- package/dist/react.js +6 -4
- package/dist/react.js.map +1 -1
- package/package.json +6 -2
- package/dist/bytes-MOJ2oN-u.d.ts +0 -42
- package/dist/chunk-5SVRTKS4.js.map +0 -1
- package/dist/chunk-AXPMXEQC.js.map +0 -1
- package/dist/chunk-BCRRXGNB.js.map +0 -1
- package/dist/chunk-ENWFOYHU.js.map +0 -1
- package/dist/chunk-LDO5FKQS.js.map +0 -1
|
@@ -0,0 +1,963 @@
|
|
|
1
|
+
import { AssetPath } from './chunk-JGIVJXBU.js';
|
|
2
|
+
|
|
3
|
+
// src/usd/AssetResolver.ts
|
|
4
|
+
var DefaultAssetResolver = class {
|
|
5
|
+
resolve(assetPath, baseUrl) {
|
|
6
|
+
try {
|
|
7
|
+
return new URL(assetPath, baseUrl || void 0).href;
|
|
8
|
+
} catch {
|
|
9
|
+
return joinPosix(baseUrl, assetPath);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
async fetchText(url) {
|
|
13
|
+
const res = await fetch(url);
|
|
14
|
+
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
15
|
+
return res.text();
|
|
16
|
+
}
|
|
17
|
+
async fetchBytes(url) {
|
|
18
|
+
const res = await fetch(url);
|
|
19
|
+
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
20
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
function createMemoryResolver(files) {
|
|
24
|
+
const decoder = new TextDecoder();
|
|
25
|
+
const encoder = new TextEncoder();
|
|
26
|
+
return {
|
|
27
|
+
resolve(assetPath, baseUrl) {
|
|
28
|
+
return joinPosix(baseUrl, assetPath);
|
|
29
|
+
},
|
|
30
|
+
fetchText(url) {
|
|
31
|
+
const v = files[url];
|
|
32
|
+
if (v === void 0) return Promise.reject(new Error(`asset not found: ${url}`));
|
|
33
|
+
return Promise.resolve(typeof v === "string" ? v : decoder.decode(v));
|
|
34
|
+
},
|
|
35
|
+
fetchBytes(url) {
|
|
36
|
+
const v = files[url];
|
|
37
|
+
if (v === void 0) return Promise.reject(new Error(`asset not found: ${url}`));
|
|
38
|
+
return Promise.resolve(typeof v === "string" ? encoder.encode(v) : v);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function joinPosix(baseUrl, rel) {
|
|
43
|
+
if (rel.startsWith("/")) return normalizePosix(rel);
|
|
44
|
+
const dir = baseUrl.slice(0, baseUrl.lastIndexOf("/") + 1);
|
|
45
|
+
return normalizePosix(dir + rel);
|
|
46
|
+
}
|
|
47
|
+
function normalizePosix(path) {
|
|
48
|
+
const isAbsolute = path.startsWith("/");
|
|
49
|
+
const out = [];
|
|
50
|
+
for (const part of path.split("/")) {
|
|
51
|
+
if (part === "" || part === ".") continue;
|
|
52
|
+
if (part === "..") out.pop();
|
|
53
|
+
else out.push(part);
|
|
54
|
+
}
|
|
55
|
+
return (isAbsolute ? "/" : "") + out.join("/");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/usd/mdl/parseMdl.ts
|
|
59
|
+
function isMdlTexture(value) {
|
|
60
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && "assetPath" in value;
|
|
61
|
+
}
|
|
62
|
+
function parseMdl(text) {
|
|
63
|
+
const src = stripNoise(text);
|
|
64
|
+
const materials = /* @__PURE__ */ new Map();
|
|
65
|
+
const declRe = /\bexport\s+material\s+([A-Za-z_]\w*)\s*\(/g;
|
|
66
|
+
let match = declRe.exec(src);
|
|
67
|
+
while (match) {
|
|
68
|
+
const open = match.index + match[0].length - 1;
|
|
69
|
+
const close = matchParen(src, open);
|
|
70
|
+
if (close === -1) break;
|
|
71
|
+
const decl = {
|
|
72
|
+
name: match[1],
|
|
73
|
+
defaults: parseParamDefaults(src.slice(open + 1, close - 1)),
|
|
74
|
+
args: /* @__PURE__ */ new Map()
|
|
75
|
+
};
|
|
76
|
+
let next = close;
|
|
77
|
+
let i = close;
|
|
78
|
+
while (i < src.length && /\s/.test(src[i])) i++;
|
|
79
|
+
if (src[i] === "=") {
|
|
80
|
+
const end = statementEnd(src, i + 1);
|
|
81
|
+
const body = parseWrapperBody(src.slice(i + 1, end));
|
|
82
|
+
if (body.base) decl.base = body.base;
|
|
83
|
+
decl.args = body.args;
|
|
84
|
+
next = end;
|
|
85
|
+
}
|
|
86
|
+
materials.set(decl.name, decl);
|
|
87
|
+
declRe.lastIndex = next;
|
|
88
|
+
match = declRe.exec(src);
|
|
89
|
+
}
|
|
90
|
+
return { materials };
|
|
91
|
+
}
|
|
92
|
+
var NUMBER_RE = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?[fFdD]?$/;
|
|
93
|
+
var CALL_RE = /^(?:::)?([A-Za-z_]\w*(?:::[A-Za-z_]\w*)*)\s*\(/;
|
|
94
|
+
var VECTOR_RE = /^(?:color|(?:float|double|int)([234]))$/;
|
|
95
|
+
var IDENTIFIER_RE = /^[A-Za-z_]\w*$/;
|
|
96
|
+
function parseMdlLiteral(src) {
|
|
97
|
+
const s = src.trim();
|
|
98
|
+
if (s === "true") return true;
|
|
99
|
+
if (s === "false") return false;
|
|
100
|
+
if (NUMBER_RE.test(s)) return Number.parseFloat(s.replace(/[fFdD]$/, ""));
|
|
101
|
+
if (s.startsWith('"')) {
|
|
102
|
+
if (skipString(s, 0) !== s.length) return void 0;
|
|
103
|
+
return s.slice(1, -1).replace(/\\(.)/g, "$1");
|
|
104
|
+
}
|
|
105
|
+
const call = CALL_RE.exec(s);
|
|
106
|
+
if (!call) return void 0;
|
|
107
|
+
const open = call[0].length - 1;
|
|
108
|
+
if (matchParen(s, open) !== s.length) return void 0;
|
|
109
|
+
const name = call[1].split("::").pop();
|
|
110
|
+
const args = splitTopLevel(s.slice(open + 1, s.length - 1), ",").map((a) => a.trim()).filter((a) => a.length > 0);
|
|
111
|
+
if (name === "texture_2d") {
|
|
112
|
+
const path = args[0] === void 0 ? void 0 : parseMdlLiteral(args[0]);
|
|
113
|
+
if (typeof path !== "string" || path.length === 0) return void 0;
|
|
114
|
+
const texture = { assetPath: path };
|
|
115
|
+
const gamma = args.slice(1).join(",");
|
|
116
|
+
if (gamma.includes("gamma_srgb")) texture.sourceColorSpace = "sRGB";
|
|
117
|
+
else if (gamma.includes("gamma_linear")) texture.sourceColorSpace = "raw";
|
|
118
|
+
return texture;
|
|
119
|
+
}
|
|
120
|
+
const vector = VECTOR_RE.exec(name);
|
|
121
|
+
if (vector) {
|
|
122
|
+
const width = vector[1] ? Number(vector[1]) : 3;
|
|
123
|
+
const values = args.map((a) => parseMdlLiteral(a));
|
|
124
|
+
if (values.length === 0 || !values.every((v) => typeof v === "number")) return void 0;
|
|
125
|
+
if (values.length === 1) return new Array(width).fill(values[0]);
|
|
126
|
+
return values.length === width ? values : void 0;
|
|
127
|
+
}
|
|
128
|
+
return void 0;
|
|
129
|
+
}
|
|
130
|
+
function parseParamDefaults(src) {
|
|
131
|
+
const defaults = /* @__PURE__ */ new Map();
|
|
132
|
+
const body = src.trim();
|
|
133
|
+
if (body === "" || body === "*") return defaults;
|
|
134
|
+
for (const param of splitTopLevel(src, ",")) {
|
|
135
|
+
const assign = topLevelAssign(param);
|
|
136
|
+
if (assign === -1) continue;
|
|
137
|
+
const name = param.slice(0, assign).trim().split(/\s+/).pop();
|
|
138
|
+
if (!name || !IDENTIFIER_RE.test(name)) continue;
|
|
139
|
+
const value = parseMdlLiteral(param.slice(assign + 1));
|
|
140
|
+
if (value !== void 0) defaults.set(name, value);
|
|
141
|
+
}
|
|
142
|
+
return defaults;
|
|
143
|
+
}
|
|
144
|
+
function parseWrapperBody(src) {
|
|
145
|
+
const args = /* @__PURE__ */ new Map();
|
|
146
|
+
const body = src.trim();
|
|
147
|
+
const call = CALL_RE.exec(body);
|
|
148
|
+
if (!call) return { args };
|
|
149
|
+
const open = call[0].length - 1;
|
|
150
|
+
if (matchParen(body, open) !== body.length) return { args };
|
|
151
|
+
const base = call[1].split("::").pop();
|
|
152
|
+
if (base === "material") return { args };
|
|
153
|
+
for (const arg of splitTopLevel(body.slice(open + 1, body.length - 1), ",")) {
|
|
154
|
+
const colon = topLevelColon(arg);
|
|
155
|
+
if (colon === -1) continue;
|
|
156
|
+
const name = arg.slice(0, colon).trim();
|
|
157
|
+
if (!IDENTIFIER_RE.test(name)) continue;
|
|
158
|
+
const value = parseMdlLiteral(arg.slice(colon + 1));
|
|
159
|
+
if (value !== void 0) args.set(name, value);
|
|
160
|
+
}
|
|
161
|
+
return { base, args };
|
|
162
|
+
}
|
|
163
|
+
function stripNoise(src) {
|
|
164
|
+
let out = "";
|
|
165
|
+
let i = 0;
|
|
166
|
+
while (i < src.length) {
|
|
167
|
+
const c = src[i];
|
|
168
|
+
if (c === '"') {
|
|
169
|
+
const end = skipString(src, i);
|
|
170
|
+
out += src.slice(i, end);
|
|
171
|
+
i = end;
|
|
172
|
+
} else if (c === "/" && src[i + 1] === "/") {
|
|
173
|
+
while (i < src.length && src[i] !== "\n") i++;
|
|
174
|
+
} else if (c === "/" && src[i + 1] === "*") {
|
|
175
|
+
const end = src.indexOf("*/", i + 2);
|
|
176
|
+
i = end === -1 ? src.length : end + 2;
|
|
177
|
+
out += " ";
|
|
178
|
+
} else if (c === "[" && src[i + 1] === "[") {
|
|
179
|
+
i = skipAnnotation(src, i);
|
|
180
|
+
out += " ";
|
|
181
|
+
} else {
|
|
182
|
+
out += c;
|
|
183
|
+
i++;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return out;
|
|
187
|
+
}
|
|
188
|
+
function skipString(src, i) {
|
|
189
|
+
let j = i + 1;
|
|
190
|
+
while (j < src.length) {
|
|
191
|
+
if (src[j] === "\\") j += 2;
|
|
192
|
+
else if (src[j] === '"') return j + 1;
|
|
193
|
+
else j++;
|
|
194
|
+
}
|
|
195
|
+
return j;
|
|
196
|
+
}
|
|
197
|
+
function skipAnnotation(src, i) {
|
|
198
|
+
let depth = 0;
|
|
199
|
+
let j = i;
|
|
200
|
+
while (j < src.length) {
|
|
201
|
+
if (src[j] === '"') {
|
|
202
|
+
j = skipString(src, j);
|
|
203
|
+
} else if (src[j] === "[" && src[j + 1] === "[") {
|
|
204
|
+
depth++;
|
|
205
|
+
j += 2;
|
|
206
|
+
} else if (src[j] === "]" && src[j + 1] === "]") {
|
|
207
|
+
depth--;
|
|
208
|
+
j += 2;
|
|
209
|
+
if (depth === 0) return j;
|
|
210
|
+
} else {
|
|
211
|
+
j++;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return j;
|
|
215
|
+
}
|
|
216
|
+
function matchParen(src, open) {
|
|
217
|
+
let depth = 0;
|
|
218
|
+
let i = open;
|
|
219
|
+
while (i < src.length) {
|
|
220
|
+
const c = src[i];
|
|
221
|
+
if (c === '"') {
|
|
222
|
+
i = skipString(src, i);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (c === "(") depth++;
|
|
226
|
+
else if (c === ")") {
|
|
227
|
+
depth--;
|
|
228
|
+
if (depth === 0) return i + 1;
|
|
229
|
+
}
|
|
230
|
+
i++;
|
|
231
|
+
}
|
|
232
|
+
return -1;
|
|
233
|
+
}
|
|
234
|
+
function isOpener(c) {
|
|
235
|
+
return c === "(" || c === "[" || c === "{";
|
|
236
|
+
}
|
|
237
|
+
function isCloser(c) {
|
|
238
|
+
return c === ")" || c === "]" || c === "}";
|
|
239
|
+
}
|
|
240
|
+
function splitTopLevel(src, separator) {
|
|
241
|
+
const parts = [];
|
|
242
|
+
let depth = 0;
|
|
243
|
+
let start = 0;
|
|
244
|
+
let i = 0;
|
|
245
|
+
while (i < src.length) {
|
|
246
|
+
const c = src[i];
|
|
247
|
+
if (c === '"') {
|
|
248
|
+
i = skipString(src, i);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (isOpener(c)) depth++;
|
|
252
|
+
else if (isCloser(c)) depth--;
|
|
253
|
+
else if (c === separator && depth === 0) {
|
|
254
|
+
parts.push(src.slice(start, i));
|
|
255
|
+
start = i + 1;
|
|
256
|
+
}
|
|
257
|
+
i++;
|
|
258
|
+
}
|
|
259
|
+
parts.push(src.slice(start));
|
|
260
|
+
return parts;
|
|
261
|
+
}
|
|
262
|
+
function statementEnd(src, from) {
|
|
263
|
+
let depth = 0;
|
|
264
|
+
let i = from;
|
|
265
|
+
while (i < src.length) {
|
|
266
|
+
const c = src[i];
|
|
267
|
+
if (c === '"') {
|
|
268
|
+
i = skipString(src, i);
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
if (isOpener(c)) depth++;
|
|
272
|
+
else if (isCloser(c)) depth--;
|
|
273
|
+
else if (c === ";" && depth === 0) return i;
|
|
274
|
+
i++;
|
|
275
|
+
}
|
|
276
|
+
return src.length;
|
|
277
|
+
}
|
|
278
|
+
function topLevelAssign(src) {
|
|
279
|
+
let depth = 0;
|
|
280
|
+
let i = 0;
|
|
281
|
+
while (i < src.length) {
|
|
282
|
+
const c = src[i];
|
|
283
|
+
if (c === '"') {
|
|
284
|
+
i = skipString(src, i);
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
if (isOpener(c)) depth++;
|
|
288
|
+
else if (isCloser(c)) depth--;
|
|
289
|
+
else if (c === "=" && depth === 0 && src[i + 1] !== "=" && !"<>!=".includes(src[i - 1] ?? "")) {
|
|
290
|
+
return i;
|
|
291
|
+
}
|
|
292
|
+
i++;
|
|
293
|
+
}
|
|
294
|
+
return -1;
|
|
295
|
+
}
|
|
296
|
+
function topLevelColon(src) {
|
|
297
|
+
let depth = 0;
|
|
298
|
+
let i = 0;
|
|
299
|
+
while (i < src.length) {
|
|
300
|
+
const c = src[i];
|
|
301
|
+
if (c === '"') {
|
|
302
|
+
i = skipString(src, i);
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
if (isOpener(c)) depth++;
|
|
306
|
+
else if (isCloser(c)) depth--;
|
|
307
|
+
else if (c === ":" && depth === 0) {
|
|
308
|
+
if (src[i + 1] === ":") {
|
|
309
|
+
i += 2;
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
return i;
|
|
313
|
+
}
|
|
314
|
+
i++;
|
|
315
|
+
}
|
|
316
|
+
return -1;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/three/MaterialXBinding.ts
|
|
320
|
+
var MTLX_STANDARD_SURFACE = "ND_standard_surface_surfaceshader";
|
|
321
|
+
var MTLX_USD_PREVIEW_SURFACE = "ND_UsdPreviewSurface_surfaceshader";
|
|
322
|
+
var DEFAULT_BASE_COLOR = [0.8, 0.8, 0.8];
|
|
323
|
+
function readStandardSurface(shader, result, onWarn) {
|
|
324
|
+
const input = (name) => resolveMtlxInput(shader, name, onWarn);
|
|
325
|
+
const base = numberOf(input("base"));
|
|
326
|
+
const baseColor = input("base_color");
|
|
327
|
+
if (baseColor?.kind === "texture") {
|
|
328
|
+
result.colorTexture = baseColor.texture;
|
|
329
|
+
if (base !== void 0) result.color = [base, base, base];
|
|
330
|
+
} else {
|
|
331
|
+
const color = colorOf(baseColor) ?? (base !== void 0 ? DEFAULT_BASE_COLOR : void 0);
|
|
332
|
+
if (color) {
|
|
333
|
+
const weight = base ?? 1;
|
|
334
|
+
result.color = [color[0] * weight, color[1] * weight, color[2] * weight];
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const metalness = input("metalness");
|
|
338
|
+
if (metalness?.kind === "texture") result.metalnessTexture = metalness.texture;
|
|
339
|
+
const metalnessValue = numberOf(metalness);
|
|
340
|
+
if (metalnessValue !== void 0) result.metalness = metalnessValue;
|
|
341
|
+
const roughness = input("specular_roughness");
|
|
342
|
+
if (roughness?.kind === "texture") result.roughnessTexture = roughness.texture;
|
|
343
|
+
const roughnessValue = numberOf(roughness);
|
|
344
|
+
if (roughnessValue !== void 0) result.roughness = roughnessValue;
|
|
345
|
+
const ior = numberOf(input("specular_IOR"));
|
|
346
|
+
if (ior !== void 0) result.ior = ior;
|
|
347
|
+
const transmission = numberOf(input("transmission"));
|
|
348
|
+
if (transmission !== void 0) result.transmission = transmission;
|
|
349
|
+
const coat = numberOf(input("coat"));
|
|
350
|
+
if (coat !== void 0) {
|
|
351
|
+
result.clearcoat = coat;
|
|
352
|
+
const coatRoughness = numberOf(input("coat_roughness"));
|
|
353
|
+
if (coatRoughness !== void 0) result.clearcoatRoughness = coatRoughness;
|
|
354
|
+
}
|
|
355
|
+
const emission = numberOf(input("emission"));
|
|
356
|
+
if (emission !== void 0 && emission > 0) {
|
|
357
|
+
const emissionColor = input("emission_color");
|
|
358
|
+
if (emissionColor?.kind === "texture") result.emissiveTexture = emissionColor.texture;
|
|
359
|
+
result.emissiveColor = colorOf(emissionColor) ?? [1, 1, 1];
|
|
360
|
+
result.emissiveIntensity = emission;
|
|
361
|
+
}
|
|
362
|
+
const opacity = input("opacity");
|
|
363
|
+
if (opacity?.kind === "texture") result.opacityTexture = opacity.texture;
|
|
364
|
+
const opacityValue = numberOf(opacity) ?? mean3(colorOf(opacity));
|
|
365
|
+
if (opacityValue !== void 0) result.opacity = opacityValue;
|
|
366
|
+
const normal = input("normal");
|
|
367
|
+
if (normal?.kind === "texture") result.normalTexture = normal.texture;
|
|
368
|
+
}
|
|
369
|
+
function resolveMtlxInput(shader, name, onWarn) {
|
|
370
|
+
return followMtlxInput(shader, name, name, onWarn, 0);
|
|
371
|
+
}
|
|
372
|
+
function followMtlxInput(prim, name, channel, onWarn, depth) {
|
|
373
|
+
const attr = prim.GetAttribute(`inputs:${name}`);
|
|
374
|
+
const connection = attr.GetConnections()[0];
|
|
375
|
+
if (connection) {
|
|
376
|
+
const source = prim.GetStage().GetPrimAtPath(connection.split(".")[0]);
|
|
377
|
+
return source ? resolveMtlxNode(source, channel, onWarn, depth + 1) : void 0;
|
|
378
|
+
}
|
|
379
|
+
const value = attr.Get();
|
|
380
|
+
return value === void 0 ? void 0 : { kind: "value", value };
|
|
381
|
+
}
|
|
382
|
+
var MAX_NODE_DEPTH = 8;
|
|
383
|
+
function resolveMtlxNode(node, channel, onWarn, depth) {
|
|
384
|
+
const id = node.GetAttribute("info:id").Get();
|
|
385
|
+
if (typeof id !== "string" || depth > MAX_NODE_DEPTH) {
|
|
386
|
+
onWarn?.(`${node.GetPath()}: unresolvable MaterialX node; skipping the "${channel}" channel`);
|
|
387
|
+
return void 0;
|
|
388
|
+
}
|
|
389
|
+
if (id.startsWith("ND_image_") || id.startsWith("ND_tiledimage_")) {
|
|
390
|
+
const texture = readMtlxImage(node, id.startsWith("ND_tiledimage_"));
|
|
391
|
+
return texture ? { kind: "texture", texture } : void 0;
|
|
392
|
+
}
|
|
393
|
+
if (id.startsWith("ND_normalmap")) {
|
|
394
|
+
const resolved = followMtlxInput(node, "in", channel, onWarn, depth);
|
|
395
|
+
if (resolved?.kind !== "texture") return resolved;
|
|
396
|
+
const scale = node.GetAttribute("inputs:scale").Get();
|
|
397
|
+
if (typeof scale === "number") {
|
|
398
|
+
resolved.texture.scale = [2 * scale, 2 * scale, 2 * scale, 1];
|
|
399
|
+
}
|
|
400
|
+
return resolved;
|
|
401
|
+
}
|
|
402
|
+
if (id.startsWith("ND_constant_")) {
|
|
403
|
+
const value = node.GetAttribute("inputs:value").Get();
|
|
404
|
+
return value === void 0 ? void 0 : { kind: "value", value };
|
|
405
|
+
}
|
|
406
|
+
if (id.startsWith("ND_dot_")) {
|
|
407
|
+
return followMtlxInput(node, "in", channel, onWarn, depth);
|
|
408
|
+
}
|
|
409
|
+
if (id.startsWith("ND_convert_")) {
|
|
410
|
+
const resolved = followMtlxInput(node, "in", channel, onWarn, depth);
|
|
411
|
+
if (resolved?.kind !== "value") return resolved;
|
|
412
|
+
return { kind: "value", value: convertMtlxValue(resolved.value, id) };
|
|
413
|
+
}
|
|
414
|
+
if (id.startsWith("ND_multiply_")) {
|
|
415
|
+
const in1 = operand(node, "in1", void 0, channel, onWarn, depth);
|
|
416
|
+
const in2 = operand(node, "in2", [1], channel, onWarn, depth);
|
|
417
|
+
const value = in1 && in2 ? broadcast([in1, in2], ([a, b]) => a * b) : void 0;
|
|
418
|
+
return value ? { kind: "value", value: scalarize(value) } : void 0;
|
|
419
|
+
}
|
|
420
|
+
if (id.startsWith("ND_mix_")) {
|
|
421
|
+
const bg = operand(node, "bg", [0], channel, onWarn, depth);
|
|
422
|
+
const fg = operand(node, "fg", [0], channel, onWarn, depth);
|
|
423
|
+
const mix = operand(node, "mix", [0], channel, onWarn, depth);
|
|
424
|
+
const value = bg && fg && mix ? broadcast([fg, bg, mix], ([f, b, m]) => f * m + b * (1 - m)) : void 0;
|
|
425
|
+
return value ? { kind: "value", value: scalarize(value) } : void 0;
|
|
426
|
+
}
|
|
427
|
+
onWarn?.(
|
|
428
|
+
`${node.GetPath()}: MaterialX node "${id}" needs graph execution; skipping the "${channel}" channel`
|
|
429
|
+
);
|
|
430
|
+
return void 0;
|
|
431
|
+
}
|
|
432
|
+
var MTLX_WRAP = {
|
|
433
|
+
periodic: "repeat",
|
|
434
|
+
clamp: "clamp",
|
|
435
|
+
mirror: "mirror",
|
|
436
|
+
constant: "black"
|
|
437
|
+
// no border-color sampling in three — clamp-to-black is closest
|
|
438
|
+
};
|
|
439
|
+
function readMtlxImage(node, tiled) {
|
|
440
|
+
const file = node.GetAttribute("inputs:file").Get();
|
|
441
|
+
if (!(file instanceof AssetPath) || !file.path) return void 0;
|
|
442
|
+
const texture = { path: file.path };
|
|
443
|
+
if (tiled) {
|
|
444
|
+
texture.wrapS = "repeat";
|
|
445
|
+
texture.wrapT = "repeat";
|
|
446
|
+
const transform = {};
|
|
447
|
+
const tiling = vec2Of(node.GetAttribute("inputs:uvtiling").Get());
|
|
448
|
+
if (tiling) transform.scale = tiling;
|
|
449
|
+
const offset = vec2Of(node.GetAttribute("inputs:uvoffset").Get());
|
|
450
|
+
if (offset) transform.translation = offset;
|
|
451
|
+
if (transform.scale || transform.translation) texture.transform = transform;
|
|
452
|
+
} else {
|
|
453
|
+
const uaddress = node.GetAttribute("inputs:uaddressmode").Get();
|
|
454
|
+
const wrapS = typeof uaddress === "string" ? MTLX_WRAP[uaddress] : void 0;
|
|
455
|
+
if (wrapS) texture.wrapS = wrapS;
|
|
456
|
+
const vaddress = node.GetAttribute("inputs:vaddressmode").Get();
|
|
457
|
+
const wrapT = typeof vaddress === "string" ? MTLX_WRAP[vaddress] : void 0;
|
|
458
|
+
if (wrapT) texture.wrapT = wrapT;
|
|
459
|
+
}
|
|
460
|
+
readMtlxTexcoord(node, texture);
|
|
461
|
+
return texture;
|
|
462
|
+
}
|
|
463
|
+
function readMtlxTexcoord(node, texture) {
|
|
464
|
+
const connection = node.GetAttribute("inputs:texcoord").GetConnections()[0];
|
|
465
|
+
if (!connection) return;
|
|
466
|
+
const source = node.GetStage().GetPrimAtPath(connection.split(".")[0]);
|
|
467
|
+
const id = source?.GetAttribute("info:id").Get();
|
|
468
|
+
if (!source || typeof id !== "string") return;
|
|
469
|
+
if (id.startsWith("ND_texcoord_")) {
|
|
470
|
+
const index = source.GetAttribute("inputs:index").Get();
|
|
471
|
+
if (typeof index === "number" && index > 0) texture.uvChannel = index;
|
|
472
|
+
} else if (id.startsWith("ND_geompropvalue_")) {
|
|
473
|
+
const geomprop = source.GetAttribute("inputs:geomprop").Get();
|
|
474
|
+
if (typeof geomprop === "string" && geomprop.length > 0) texture.uvSet = geomprop;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
function operand(node, name, fallback, channel, onWarn, depth) {
|
|
478
|
+
const attr = node.GetAttribute(`inputs:${name}`);
|
|
479
|
+
if (!attr.GetConnections()[0]) {
|
|
480
|
+
const value = attr.Get();
|
|
481
|
+
return value === void 0 ? fallback : numsOf(value);
|
|
482
|
+
}
|
|
483
|
+
const resolved = followMtlxInput(node, name, channel, onWarn, depth);
|
|
484
|
+
if (resolved?.kind === "value") return numsOf(resolved.value);
|
|
485
|
+
if (resolved?.kind === "texture") {
|
|
486
|
+
onWarn?.(
|
|
487
|
+
`${node.GetPath()}: constant folding cannot take a textured "${name}"; skipping the "${channel}" channel`
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
return void 0;
|
|
491
|
+
}
|
|
492
|
+
var MTLX_TYPE_SIZE = {
|
|
493
|
+
float: 1,
|
|
494
|
+
integer: 1,
|
|
495
|
+
boolean: 1,
|
|
496
|
+
vector2: 2,
|
|
497
|
+
color3: 3,
|
|
498
|
+
vector3: 3,
|
|
499
|
+
color4: 4,
|
|
500
|
+
vector4: 4
|
|
501
|
+
};
|
|
502
|
+
function convertMtlxValue(value, id) {
|
|
503
|
+
const target = id.split("_").pop() ?? "";
|
|
504
|
+
const size = MTLX_TYPE_SIZE[target];
|
|
505
|
+
const nums = numsOf(value);
|
|
506
|
+
if (!size || !nums) return value;
|
|
507
|
+
if (size === 1) return nums[0];
|
|
508
|
+
return Array.from(
|
|
509
|
+
{ length: size },
|
|
510
|
+
(_, i) => i < nums.length ? nums[i] : nums.length === 1 ? nums[0] : target === "color4" && i === 3 ? 1 : 0
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
function broadcast(operands, op) {
|
|
514
|
+
const length = Math.max(...operands.map((o) => o.length));
|
|
515
|
+
if (operands.some((o) => o.length !== 1 && o.length !== length)) return void 0;
|
|
516
|
+
return Array.from({ length }, (_, i) => op(operands.map((o) => o.length === 1 ? o[0] : o[i])));
|
|
517
|
+
}
|
|
518
|
+
function scalarize(value) {
|
|
519
|
+
return value.length === 1 ? value[0] : value;
|
|
520
|
+
}
|
|
521
|
+
function numsOf(value) {
|
|
522
|
+
if (typeof value === "number") return [value];
|
|
523
|
+
if (Array.isArray(value) && value.length > 0 && value.every((n) => typeof n === "number")) {
|
|
524
|
+
return value;
|
|
525
|
+
}
|
|
526
|
+
return void 0;
|
|
527
|
+
}
|
|
528
|
+
function numberOf(resolved) {
|
|
529
|
+
if (resolved?.kind !== "value") return void 0;
|
|
530
|
+
const v = resolved.value;
|
|
531
|
+
if (typeof v === "number") return v;
|
|
532
|
+
if (Array.isArray(v) && v.length === 1 && typeof v[0] === "number") return v[0];
|
|
533
|
+
return void 0;
|
|
534
|
+
}
|
|
535
|
+
function colorOf(resolved) {
|
|
536
|
+
if (resolved?.kind !== "value") return void 0;
|
|
537
|
+
const v = resolved.value;
|
|
538
|
+
if (typeof v === "number") return [v, v, v];
|
|
539
|
+
if (Array.isArray(v) && v.length >= 3 && v.every((n) => typeof n === "number")) {
|
|
540
|
+
return [v[0], v[1], v[2]];
|
|
541
|
+
}
|
|
542
|
+
return void 0;
|
|
543
|
+
}
|
|
544
|
+
function mean3(v) {
|
|
545
|
+
return v ? (v[0] + v[1] + v[2]) / 3 : void 0;
|
|
546
|
+
}
|
|
547
|
+
function vec2Of(value) {
|
|
548
|
+
return Array.isArray(value) && value.length >= 2 && typeof value[0] === "number" && typeof value[1] === "number" ? [value[0], value[1]] : void 0;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// src/three/MaterialBinding.ts
|
|
552
|
+
var DIFFUSE_INPUTS = [
|
|
553
|
+
"diffuseColor",
|
|
554
|
+
// UsdPreviewSurface
|
|
555
|
+
"diffuse_color_constant",
|
|
556
|
+
// OmniPBR
|
|
557
|
+
"diffuse_tint",
|
|
558
|
+
"base_color",
|
|
559
|
+
"baseColor"
|
|
560
|
+
];
|
|
561
|
+
var OPACITY_INPUTS = ["opacity", "opacity_constant"];
|
|
562
|
+
var OPACITY_THRESHOLD_INPUTS = ["opacityThreshold", "opacity_threshold"];
|
|
563
|
+
var METALLIC_INPUTS = ["metallic", "metallic_constant"];
|
|
564
|
+
var ROUGHNESS_INPUTS = ["roughness", "reflection_roughness_constant"];
|
|
565
|
+
var EMISSIVE_INPUTS = ["emissiveColor", "emissive_color"];
|
|
566
|
+
var SURFACE_OUTPUTS = ["outputs:surface", "outputs:mdl:surface", "outputs:mtlx:surface"];
|
|
567
|
+
var TEXTURE_LOOKUPS = {
|
|
568
|
+
color: {
|
|
569
|
+
surface: ["diffuseColor"],
|
|
570
|
+
direct: ["diffuse_texture", "diffuse_color_texture", "glass_color_texture"]
|
|
571
|
+
},
|
|
572
|
+
opacity: {
|
|
573
|
+
surface: ["opacity"],
|
|
574
|
+
direct: ["opacity_texture", "opacity_color_texture"]
|
|
575
|
+
},
|
|
576
|
+
normal: {
|
|
577
|
+
surface: ["normal"],
|
|
578
|
+
direct: ["normalmap_texture", "normal_texture", "normal_map_texture"]
|
|
579
|
+
},
|
|
580
|
+
roughness: {
|
|
581
|
+
surface: ["roughness"],
|
|
582
|
+
direct: ["reflectionroughness_texture", "roughness_texture"]
|
|
583
|
+
},
|
|
584
|
+
metalness: {
|
|
585
|
+
surface: ["metallic"],
|
|
586
|
+
direct: ["metallic_texture"]
|
|
587
|
+
},
|
|
588
|
+
occlusion: {
|
|
589
|
+
surface: ["occlusion"],
|
|
590
|
+
direct: ["ao_texture", "occlusion_texture"]
|
|
591
|
+
},
|
|
592
|
+
emissive: {
|
|
593
|
+
surface: ["emissiveColor"],
|
|
594
|
+
direct: ["emissive_color_texture", "emissive_mask_texture"]
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
function resolveBoundMaterial(stage, prim, options = {}) {
|
|
598
|
+
const materialPath = findBinding(prim);
|
|
599
|
+
if (!materialPath) return void 0;
|
|
600
|
+
const material = stage.GetPrimAtPath(materialPath);
|
|
601
|
+
if (!material) return void 0;
|
|
602
|
+
const shader = findSurfaceShader(material);
|
|
603
|
+
if (!shader) return void 0;
|
|
604
|
+
const infoId = shader.GetAttribute("info:id").Get();
|
|
605
|
+
if (typeof infoId === "string" && infoId.startsWith("ND_")) {
|
|
606
|
+
if (infoId === MTLX_STANDARD_SURFACE) {
|
|
607
|
+
const result2 = { name: material.GetName() };
|
|
608
|
+
readStandardSurface(shader, result2, options.onWarn);
|
|
609
|
+
return result2;
|
|
610
|
+
}
|
|
611
|
+
if (infoId !== MTLX_USD_PREVIEW_SURFACE) {
|
|
612
|
+
options.onWarn?.(
|
|
613
|
+
`${material.GetPath()}: unknown MaterialX surface shader "${infoId}"; applying the best-effort UsdPreviewSurface mapping`
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
const mdlSource = readMdlShaderSource(shader, options.mdl);
|
|
618
|
+
if (mdlSource && !mdlSource.family) {
|
|
619
|
+
options.onWarn?.(
|
|
620
|
+
`${material.GetPath()}: unknown MDL material "${mdlSource.id}" (${mdlSource.assetPath}); applying the best-effort OmniPBR mapping`
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
const sv = { shader };
|
|
624
|
+
if (mdlSource?.values) sv.mdl = mdlSource.values;
|
|
625
|
+
if (mdlSource) sv.mdlAssetPath = mdlSource.assetPath;
|
|
626
|
+
const result = { name: material.GetName() };
|
|
627
|
+
const color = firstColor(sv, DIFFUSE_INPUTS);
|
|
628
|
+
if (color) result.color = color;
|
|
629
|
+
const opacity = firstNumber(sv, OPACITY_INPUTS);
|
|
630
|
+
if (opacity !== void 0) result.opacity = opacity;
|
|
631
|
+
const opacityThreshold = firstNumber(sv, OPACITY_THRESHOLD_INPUTS);
|
|
632
|
+
if (opacityThreshold !== void 0) result.opacityThreshold = opacityThreshold;
|
|
633
|
+
const metalness = firstNumber(sv, METALLIC_INPUTS);
|
|
634
|
+
if (metalness !== void 0) result.metalness = metalness;
|
|
635
|
+
const roughness = firstNumber(sv, ROUGHNESS_INPUTS);
|
|
636
|
+
if (roughness !== void 0) result.roughness = roughness;
|
|
637
|
+
const emissive = firstColor(sv, EMISSIVE_INPUTS);
|
|
638
|
+
if (emissive && svBoolean(sv, "enable_emission") !== false) {
|
|
639
|
+
result.emissiveColor = emissive;
|
|
640
|
+
const intensity = svNumber(sv, "emissive_intensity");
|
|
641
|
+
if (intensity !== void 0) result.emissiveIntensity = intensity;
|
|
642
|
+
}
|
|
643
|
+
const ior = svNumber(sv, "ior");
|
|
644
|
+
if (ior !== void 0) result.ior = ior;
|
|
645
|
+
const clearcoat = svNumber(sv, "clearcoat");
|
|
646
|
+
if (clearcoat !== void 0) result.clearcoat = clearcoat;
|
|
647
|
+
const clearcoatRoughness = svNumber(sv, "clearcoatRoughness");
|
|
648
|
+
if (clearcoatRoughness !== void 0) result.clearcoatRoughness = clearcoatRoughness;
|
|
649
|
+
if (svNumber(sv, "useSpecularWorkflow") === 1) {
|
|
650
|
+
const specular = svColor(sv, "specularColor");
|
|
651
|
+
if (specular) result.specularColor = specular;
|
|
652
|
+
}
|
|
653
|
+
const colorTex = findTexture(sv, TEXTURE_LOOKUPS.color);
|
|
654
|
+
if (colorTex !== void 0) result.colorTexture = colorTex;
|
|
655
|
+
const opacityTex = findTexture(sv, TEXTURE_LOOKUPS.opacity);
|
|
656
|
+
if (opacityTex !== void 0) result.opacityTexture = opacityTex;
|
|
657
|
+
const normal = findTexture(sv, TEXTURE_LOOKUPS.normal);
|
|
658
|
+
if (normal !== void 0) result.normalTexture = normal;
|
|
659
|
+
const roughTex = findTexture(sv, TEXTURE_LOOKUPS.roughness);
|
|
660
|
+
if (roughTex !== void 0) result.roughnessTexture = roughTex;
|
|
661
|
+
const metalTex = findTexture(sv, TEXTURE_LOOKUPS.metalness);
|
|
662
|
+
if (metalTex !== void 0) result.metalnessTexture = metalTex;
|
|
663
|
+
const aoTex = findTexture(sv, TEXTURE_LOOKUPS.occlusion);
|
|
664
|
+
if (aoTex !== void 0) result.occlusionTexture = aoTex;
|
|
665
|
+
const emissiveTex = findTexture(sv, TEXTURE_LOOKUPS.emissive);
|
|
666
|
+
if (emissiveTex !== void 0) result.emissiveTexture = emissiveTex;
|
|
667
|
+
const orm = directTexture(sv, "ORM_texture") ?? mdlValueTexture(sv, "ORM_texture");
|
|
668
|
+
if (svBoolean(sv, "enable_ORM_texture") === true && orm) {
|
|
669
|
+
result.occlusionTexture = { ...orm, outputChannel: "r" };
|
|
670
|
+
result.roughnessTexture = { ...orm, outputChannel: "g" };
|
|
671
|
+
result.metalnessTexture = { ...orm, outputChannel: "b" };
|
|
672
|
+
}
|
|
673
|
+
switch (mdlSource?.family) {
|
|
674
|
+
case "glass":
|
|
675
|
+
readOmniGlass(sv, result);
|
|
676
|
+
break;
|
|
677
|
+
case "clearcoat":
|
|
678
|
+
readOmniClearCoat(sv, result);
|
|
679
|
+
break;
|
|
680
|
+
case "surface":
|
|
681
|
+
readOmniSurface(sv, result);
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
return result;
|
|
685
|
+
}
|
|
686
|
+
function findBoundSurfaceShader(stage, prim) {
|
|
687
|
+
const materialPath = findBinding(prim);
|
|
688
|
+
if (!materialPath) return void 0;
|
|
689
|
+
const material = stage.GetPrimAtPath(materialPath);
|
|
690
|
+
if (!material) return void 0;
|
|
691
|
+
return findSurfaceShader(material);
|
|
692
|
+
}
|
|
693
|
+
function classifyOmniMdl(name) {
|
|
694
|
+
if (!name) return void 0;
|
|
695
|
+
if (name.startsWith("OmniGlass")) return "glass";
|
|
696
|
+
if (name.startsWith("OmniPBR_ClearCoat")) return "clearcoat";
|
|
697
|
+
if (name.startsWith("OmniPBR")) return "pbr";
|
|
698
|
+
if (name.startsWith("OmniSurface")) return "surface";
|
|
699
|
+
return void 0;
|
|
700
|
+
}
|
|
701
|
+
function readMdlShaderSource(shader, provider) {
|
|
702
|
+
const asset = shader.GetAttribute("info:mdl:sourceAsset").Get();
|
|
703
|
+
if (!(asset instanceof AssetPath) || !asset.path) return void 0;
|
|
704
|
+
const sub = shader.GetAttribute("info:mdl:sourceAsset:subIdentifier").Get();
|
|
705
|
+
const stem = (asset.path.split("/").pop() ?? "").replace(/\.mdl$/i, "");
|
|
706
|
+
const id = typeof sub === "string" && sub.length > 0 ? sub : stem;
|
|
707
|
+
const decl = provider?.(asset.path)?.materials.get(id);
|
|
708
|
+
const family = classifyOmniMdl(decl?.base) ?? classifyOmniMdl(id) ?? classifyOmniMdl(stem);
|
|
709
|
+
const source = { assetPath: asset.path, id };
|
|
710
|
+
if (family) source.family = family;
|
|
711
|
+
if (decl && (decl.defaults.size > 0 || decl.args.size > 0)) {
|
|
712
|
+
source.values = new Map([...decl.defaults, ...decl.args]);
|
|
713
|
+
}
|
|
714
|
+
return source;
|
|
715
|
+
}
|
|
716
|
+
function readOmniGlass(sv, result) {
|
|
717
|
+
result.transmission = 1;
|
|
718
|
+
result.metalness = 0;
|
|
719
|
+
result.color = svColor(sv, "glass_color") ?? [1, 1, 1];
|
|
720
|
+
result.ior = svNumber(sv, "glass_ior") ?? 1.491;
|
|
721
|
+
result.roughness = svNumber(sv, "frosting_roughness") ?? 0;
|
|
722
|
+
const depth = svNumber(sv, "depth");
|
|
723
|
+
if (svBoolean(sv, "thin_walled") !== true && depth !== void 0) result.thickness = depth;
|
|
724
|
+
const cutout = svNumber(sv, "cutout_opacity");
|
|
725
|
+
if (cutout !== void 0 && cutout < 1) result.opacity = cutout;
|
|
726
|
+
}
|
|
727
|
+
function readOmniClearCoat(sv, result) {
|
|
728
|
+
if (svBoolean(sv, "enable_clearcoat") === false) return;
|
|
729
|
+
result.clearcoat = 1;
|
|
730
|
+
const roughness = svNumber(sv, "clearcoat_reflection_roughness");
|
|
731
|
+
if (roughness !== void 0) result.clearcoatRoughness = roughness;
|
|
732
|
+
const normal = directTexture(sv, "clearcoat_normalmap_texture") ?? mdlValueTexture(sv, "clearcoat_normalmap_texture");
|
|
733
|
+
if (normal && svBoolean(sv, "enable_clearcoat_normalmap_texture") !== false) {
|
|
734
|
+
result.clearcoatNormalTexture = normal;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
function readOmniSurface(sv, result) {
|
|
738
|
+
const color = svColor(sv, "diffuse_reflection_color");
|
|
739
|
+
if (color) result.color = color;
|
|
740
|
+
const metalness = svNumber(sv, "metalness");
|
|
741
|
+
if (metalness !== void 0) result.metalness = metalness;
|
|
742
|
+
const roughness = svNumber(sv, "specular_reflection_roughness");
|
|
743
|
+
if (roughness !== void 0) result.roughness = roughness;
|
|
744
|
+
const ior = svNumber(sv, "specular_reflection_ior");
|
|
745
|
+
if (ior !== void 0) result.ior = ior;
|
|
746
|
+
const coat = svNumber(sv, "coat_weight");
|
|
747
|
+
if (coat !== void 0 && coat > 0) {
|
|
748
|
+
result.clearcoat = coat;
|
|
749
|
+
const coatRoughness = svNumber(sv, "coat_roughness");
|
|
750
|
+
if (coatRoughness !== void 0) result.clearcoatRoughness = coatRoughness;
|
|
751
|
+
}
|
|
752
|
+
const emissionWeight = svNumber(sv, "emission_weight");
|
|
753
|
+
const emissionColor = svColor(sv, "emission_color");
|
|
754
|
+
if (emissionWeight !== void 0 && emissionWeight > 0 && emissionColor) {
|
|
755
|
+
result.emissiveColor = emissionColor;
|
|
756
|
+
result.emissiveIntensity = emissionWeight;
|
|
757
|
+
}
|
|
758
|
+
if (svBoolean(sv, "enable_opacity") === true) {
|
|
759
|
+
const opacity = svNumber(sv, "geometry_opacity");
|
|
760
|
+
if (opacity !== void 0) result.opacity = opacity;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
function authored(sv, name) {
|
|
764
|
+
return sv.shader.GetAttribute(`inputs:${name}`).Get();
|
|
765
|
+
}
|
|
766
|
+
function asNumber(v) {
|
|
767
|
+
return typeof v === "number" ? v : void 0;
|
|
768
|
+
}
|
|
769
|
+
function asBoolean(v) {
|
|
770
|
+
return typeof v === "boolean" ? v : void 0;
|
|
771
|
+
}
|
|
772
|
+
function asVec(v, length) {
|
|
773
|
+
if (Array.isArray(v) && v.length >= length && v.every((n) => typeof n === "number")) {
|
|
774
|
+
return v.slice(0, length);
|
|
775
|
+
}
|
|
776
|
+
return void 0;
|
|
777
|
+
}
|
|
778
|
+
function svNumber(sv, name) {
|
|
779
|
+
return asNumber(authored(sv, name)) ?? asNumber(sv.mdl?.get(name));
|
|
780
|
+
}
|
|
781
|
+
function svBoolean(sv, name) {
|
|
782
|
+
return asBoolean(authored(sv, name)) ?? asBoolean(sv.mdl?.get(name));
|
|
783
|
+
}
|
|
784
|
+
function svColor(sv, name) {
|
|
785
|
+
const v = asVec(authored(sv, name), 3) ?? asVec(sv.mdl?.get(name), 3);
|
|
786
|
+
return v ? v : void 0;
|
|
787
|
+
}
|
|
788
|
+
function svVec2(sv, name) {
|
|
789
|
+
const v = asVec(authored(sv, name), 2) ?? asVec(sv.mdl?.get(name), 2);
|
|
790
|
+
return v ? v : void 0;
|
|
791
|
+
}
|
|
792
|
+
function firstNumber(sv, names) {
|
|
793
|
+
for (const name of names) {
|
|
794
|
+
const v = asNumber(authored(sv, name));
|
|
795
|
+
if (v !== void 0) return v;
|
|
796
|
+
}
|
|
797
|
+
for (const name of names) {
|
|
798
|
+
const v = asNumber(sv.mdl?.get(name));
|
|
799
|
+
if (v !== void 0) return v;
|
|
800
|
+
}
|
|
801
|
+
return void 0;
|
|
802
|
+
}
|
|
803
|
+
function firstColor(sv, names) {
|
|
804
|
+
for (const name of names) {
|
|
805
|
+
const v = asVec(authored(sv, name), 3);
|
|
806
|
+
if (v) return v;
|
|
807
|
+
}
|
|
808
|
+
for (const name of names) {
|
|
809
|
+
const v = asVec(sv.mdl?.get(name), 3);
|
|
810
|
+
if (v) return v;
|
|
811
|
+
}
|
|
812
|
+
return void 0;
|
|
813
|
+
}
|
|
814
|
+
function directTexture(sv, name) {
|
|
815
|
+
const v = authored(sv, name);
|
|
816
|
+
if (v instanceof AssetPath && v.path) return withMdlTransform(sv, { path: v.path });
|
|
817
|
+
return void 0;
|
|
818
|
+
}
|
|
819
|
+
function mdlValueTexture(sv, name) {
|
|
820
|
+
const v = sv.mdl?.get(name);
|
|
821
|
+
if (!isMdlTexture(v)) return void 0;
|
|
822
|
+
const texture = { path: resolveMdlRelative(sv.mdlAssetPath, v.assetPath) };
|
|
823
|
+
if (v.sourceColorSpace) texture.sourceColorSpace = v.sourceColorSpace;
|
|
824
|
+
return withMdlTransform(sv, texture);
|
|
825
|
+
}
|
|
826
|
+
function resolveMdlRelative(modulePath, path) {
|
|
827
|
+
if (!modulePath || path.startsWith("/") || /^[a-z][a-z0-9+.-]*:/i.test(path)) return path;
|
|
828
|
+
return joinPosix(modulePath, path);
|
|
829
|
+
}
|
|
830
|
+
function withMdlTransform(sv, texture) {
|
|
831
|
+
const transform = mdlTextureTransform(sv);
|
|
832
|
+
return transform ? { ...texture, transform } : texture;
|
|
833
|
+
}
|
|
834
|
+
function findTexture(sv, lookup) {
|
|
835
|
+
for (const name of lookup.direct) {
|
|
836
|
+
const texture = directTexture(sv, name);
|
|
837
|
+
if (texture) return texture;
|
|
838
|
+
}
|
|
839
|
+
for (const name of lookup.surface) {
|
|
840
|
+
const conn = sv.shader.GetAttribute(`inputs:${name}`).GetConnections()[0];
|
|
841
|
+
if (!conn) continue;
|
|
842
|
+
const texPrim = sv.shader.GetStage().GetPrimAtPath(conn.split(".")[0]);
|
|
843
|
+
if (!texPrim) continue;
|
|
844
|
+
const file = texPrim.GetAttribute("inputs:file").Get();
|
|
845
|
+
if (file instanceof AssetPath && file.path) {
|
|
846
|
+
const tex = readUvTexture(texPrim, file.path);
|
|
847
|
+
const channel = outputChannelOf(conn);
|
|
848
|
+
if (channel) tex.outputChannel = channel;
|
|
849
|
+
return tex;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
for (const name of lookup.direct) {
|
|
853
|
+
const texture = mdlValueTexture(sv, name);
|
|
854
|
+
if (texture) return texture;
|
|
855
|
+
}
|
|
856
|
+
return void 0;
|
|
857
|
+
}
|
|
858
|
+
function outputChannelOf(connection) {
|
|
859
|
+
const m = /\.outputs:(\w+)$/.exec(connection);
|
|
860
|
+
switch (m?.[1]) {
|
|
861
|
+
case "r":
|
|
862
|
+
case "g":
|
|
863
|
+
case "b":
|
|
864
|
+
case "a":
|
|
865
|
+
return m[1];
|
|
866
|
+
case "rgb":
|
|
867
|
+
case "rgba":
|
|
868
|
+
return "rgb";
|
|
869
|
+
default:
|
|
870
|
+
return void 0;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
function mdlTextureTransform(sv) {
|
|
874
|
+
const transform = {};
|
|
875
|
+
const translation = svVec2(sv, "texture_translate");
|
|
876
|
+
if (translation) transform.translation = translation;
|
|
877
|
+
const scale = svVec2(sv, "texture_scale");
|
|
878
|
+
if (scale) transform.scale = scale;
|
|
879
|
+
const rotation = svNumber(sv, "texture_rotate");
|
|
880
|
+
if (rotation !== void 0) transform.rotation = rotation;
|
|
881
|
+
return Object.keys(transform).length > 0 ? transform : void 0;
|
|
882
|
+
}
|
|
883
|
+
var WRAP_VALUES = /* @__PURE__ */ new Set(["repeat", "clamp", "mirror", "black"]);
|
|
884
|
+
function readUvTexture(texPrim, path) {
|
|
885
|
+
const tex = { path };
|
|
886
|
+
const wrapS = texPrim.GetAttribute("inputs:wrapS").Get();
|
|
887
|
+
if (typeof wrapS === "string" && WRAP_VALUES.has(wrapS)) tex.wrapS = wrapS;
|
|
888
|
+
const wrapT = texPrim.GetAttribute("inputs:wrapT").Get();
|
|
889
|
+
if (typeof wrapT === "string" && WRAP_VALUES.has(wrapT)) tex.wrapT = wrapT;
|
|
890
|
+
const scale = numArray(texPrim, "inputs:scale", 4);
|
|
891
|
+
if (scale) tex.scale = scale;
|
|
892
|
+
const bias = numArray(texPrim, "inputs:bias", 4);
|
|
893
|
+
if (bias) tex.bias = bias;
|
|
894
|
+
const sourceColorSpace = texPrim.GetAttribute("inputs:sourceColorSpace").Get();
|
|
895
|
+
if (sourceColorSpace === "raw" || sourceColorSpace === "sRGB" || sourceColorSpace === "auto") {
|
|
896
|
+
tex.sourceColorSpace = sourceColorSpace;
|
|
897
|
+
}
|
|
898
|
+
const st = readStChain(texPrim);
|
|
899
|
+
if (st.transform) tex.transform = st.transform;
|
|
900
|
+
if (st.uvSet) tex.uvSet = st.uvSet;
|
|
901
|
+
return tex;
|
|
902
|
+
}
|
|
903
|
+
function connectedPrim(prim, input) {
|
|
904
|
+
const conn = prim.GetAttribute(input).GetConnections()[0];
|
|
905
|
+
if (!conn) return null;
|
|
906
|
+
return prim.GetStage().GetPrimAtPath(conn.split(".")[0]);
|
|
907
|
+
}
|
|
908
|
+
var TRANSFORM2D_IDS = /* @__PURE__ */ new Set(["UsdTransform2d", "ND_UsdTransform2d"]);
|
|
909
|
+
var PRIMVAR_READER_IDS = /* @__PURE__ */ new Set(["UsdPrimvarReader_float2", "ND_UsdPrimvarReader_vector2"]);
|
|
910
|
+
function readStChain(texPrim) {
|
|
911
|
+
const out = {};
|
|
912
|
+
let node = connectedPrim(texPrim, "inputs:st");
|
|
913
|
+
if (node && TRANSFORM2D_IDS.has(node.GetAttribute("info:id").Get())) {
|
|
914
|
+
const transform = {};
|
|
915
|
+
const translation = numArray(node, "inputs:translation", 2);
|
|
916
|
+
if (translation) transform.translation = translation;
|
|
917
|
+
const scale = numArray(node, "inputs:scale", 2);
|
|
918
|
+
if (scale) transform.scale = scale;
|
|
919
|
+
const rotation = node.GetAttribute("inputs:rotation").Get();
|
|
920
|
+
if (typeof rotation === "number") transform.rotation = rotation;
|
|
921
|
+
if (Object.keys(transform).length > 0) out.transform = transform;
|
|
922
|
+
node = connectedPrim(node, "inputs:in");
|
|
923
|
+
}
|
|
924
|
+
if (node && PRIMVAR_READER_IDS.has(node.GetAttribute("info:id").Get())) {
|
|
925
|
+
const varname = node.GetAttribute("inputs:varname").Get();
|
|
926
|
+
if (typeof varname === "string" && varname.length > 0) out.uvSet = varname;
|
|
927
|
+
}
|
|
928
|
+
return out;
|
|
929
|
+
}
|
|
930
|
+
function numArray(prim, name, length) {
|
|
931
|
+
return asVec(prim.GetAttribute(name).Get(), length);
|
|
932
|
+
}
|
|
933
|
+
function findBinding(prim) {
|
|
934
|
+
let chosen;
|
|
935
|
+
let p = prim;
|
|
936
|
+
while (p) {
|
|
937
|
+
for (const name of ["material:binding:preview", "material:binding"]) {
|
|
938
|
+
const rel = p.GetRelationship(name);
|
|
939
|
+
const target = rel.GetTargets()[0];
|
|
940
|
+
if (!target) continue;
|
|
941
|
+
const stronger = rel.GetMetadata("bindMaterialAs") === "strongerThanDescendants";
|
|
942
|
+
if (chosen === void 0 || stronger) chosen = target;
|
|
943
|
+
break;
|
|
944
|
+
}
|
|
945
|
+
p = p.GetParent();
|
|
946
|
+
}
|
|
947
|
+
return chosen;
|
|
948
|
+
}
|
|
949
|
+
function findSurfaceShader(material) {
|
|
950
|
+
for (const out of SURFACE_OUTPUTS) {
|
|
951
|
+
const conn = material.GetAttribute(out).GetConnections()[0];
|
|
952
|
+
if (conn) {
|
|
953
|
+
const shaderPath = conn.split(".")[0];
|
|
954
|
+
const shader = material.GetStage().GetPrimAtPath(shaderPath);
|
|
955
|
+
if (shader) return shader;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return material.GetChildren().find((c) => c.GetTypeName() === "Shader") ?? void 0;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
export { DefaultAssetResolver, MTLX_STANDARD_SURFACE, createMemoryResolver, findBoundSurfaceShader, isMdlTexture, joinPosix, parseMdl, parseMdlLiteral, readMtlxImage, resolveBoundMaterial };
|
|
962
|
+
//# sourceMappingURL=chunk-PPPRB6KE.js.map
|
|
963
|
+
//# sourceMappingURL=chunk-PPPRB6KE.js.map
|