@nebula-spatial/viewer 0.4.2 → 0.4.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/CHANGELOG.md +24 -0
- package/FBX-MATERIAL-CONVERSION.md +97 -0
- package/README.md +115 -9
- package/dist/assets/types.d.ts +16 -0
- package/dist/{index-C9CW-EyW.js → index-BDo6voB2.js} +618 -524
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mjcf-visual--X39MVO9.js +63 -0
- package/dist/session-1duLyM88.js +964 -0
- package/dist/session-DhZXy40-.js +653 -0
- package/dist/{stage-D-Q_zul6.js → stage-BKqg5vNe.js} +137 -134
- package/dist/urdf-session-C_LAfkkM.js +439 -0
- package/dist/usd-session-zyj46Bcg.js +1192 -0
- package/package.json +2 -1
- package/dist/session-B-qVl3Yy.js +0 -761
- package/dist/session-B2SfkK9o.js +0 -266
- package/dist/usd-session-DCuV_H-Y.js +0 -538
|
@@ -0,0 +1,964 @@
|
|
|
1
|
+
import { DataTexture as N, LinearMipmapLinearFilter as oe, LinearFilter as ae, LoadingManager as ie, Loader as le, Texture as X, TextureLoader as ce, LinearSRGBColorSpace as G, SRGBColorSpace as ue, RGBAFormat as K, UnsignedByteType as J, NoColorSpace as fe, Mesh as pe, MeshPhysicalMaterial as Q, MeshPhongMaterial as k, MeshLambertMaterial as de, Color as _, Quaternion as Z, Vector3 as ee, Group as he, Box3 as me } from "three";
|
|
2
|
+
import { DRACOLoader as ge } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
3
|
+
import { GLTFLoader as ye } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
4
|
+
import { S as we, d as Y } from "./stage-BKqg5vNe.js";
|
|
5
|
+
import { TGALoader as be } from "three/examples/jsm/loaders/TGALoader.js";
|
|
6
|
+
import { FBXLoader as xe } from "three/examples/jsm/loaders/FBXLoader.js";
|
|
7
|
+
import { unzlibSync as Ee } from "three/examples/jsm/libs/fflate.module.js";
|
|
8
|
+
const Me = 16 * 1024 * 1024;
|
|
9
|
+
function te(e, t) {
|
|
10
|
+
if (!e || !t || e * t > Me) throw new Error("Invalid or oversized image dimensions (maximum 16M pixels).");
|
|
11
|
+
}
|
|
12
|
+
function B(e, t, n) {
|
|
13
|
+
if (t < 0 || n < 0 || t + n > e.length) throw new Error("Truncated image payload.");
|
|
14
|
+
}
|
|
15
|
+
function ve(e) {
|
|
16
|
+
const t = new Uint8Array(e);
|
|
17
|
+
B(t, 0, 18);
|
|
18
|
+
const n = new DataView(e), s = t[2], r = t[16], c = n.getUint16(12, !0), i = n.getUint16(14, !0);
|
|
19
|
+
if (te(c, i), t[1] !== 0 || ![2, 3, 10, 11].includes(s) || !([3, 11].includes(s) ? [8, 16] : [24, 32]).includes(r) || t[17] & 192)
|
|
20
|
+
throw new Error("Unsupported TGA: require non-interleaved 24/32-bit true-color or 8/16-bit grayscale.");
|
|
21
|
+
let p = 18 + t[0];
|
|
22
|
+
B(t, 18, t[0]);
|
|
23
|
+
const d = r / 8, y = c * i;
|
|
24
|
+
if (s === 2 || s === 3) B(t, p, y * d);
|
|
25
|
+
else {
|
|
26
|
+
let o = 0;
|
|
27
|
+
for (; o < y; ) {
|
|
28
|
+
B(t, p, 1);
|
|
29
|
+
const a = t[p++], l = (a & 127) + 1;
|
|
30
|
+
if (o + l > y) throw new Error("Invalid TGA RLE packet length.");
|
|
31
|
+
const u = (a & 128 ? 1 : l) * d;
|
|
32
|
+
B(t, p, u), p += u, o += l;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return { data: new be().parse(e).data, width: c, height: i };
|
|
36
|
+
}
|
|
37
|
+
function q(e) {
|
|
38
|
+
const t = e >>> 11 & 31, n = e >>> 5 & 63, s = e & 31;
|
|
39
|
+
return [t << 3 | t >>> 2, n << 2 | n >>> 4, s << 3 | s >>> 2, 255];
|
|
40
|
+
}
|
|
41
|
+
function Se(e) {
|
|
42
|
+
const t = new Uint8Array(e);
|
|
43
|
+
B(t, 0, 128);
|
|
44
|
+
const n = new DataView(e), s = (l) => n.getUint32(l, !0);
|
|
45
|
+
if (s(0) !== 542327876 || s(4) !== 124 || s(76) !== 32) throw new Error("Invalid DDS header.");
|
|
46
|
+
const r = s(16), c = s(12);
|
|
47
|
+
if (te(r, c), s(112) & 2162176 || s(24) > 1) throw new Error("DDS cubemap/volume textures are unsupported.");
|
|
48
|
+
const i = s(80), p = String.fromCharCode(...t.subarray(84, 88)), d = (i & 4) !== 0;
|
|
49
|
+
if (d && !["DXT1", "DXT3", "DXT5"].includes(p)) throw new Error(`Unsupported DDS FourCC: ${p}. Require DXT1/DXT3/DXT5.`);
|
|
50
|
+
const y = new Uint8Array(r * c * 4);
|
|
51
|
+
if (!d) {
|
|
52
|
+
const l = s(88), u = s(92), w = s(96), f = s(100), M = s(104);
|
|
53
|
+
if (!(i & 64) || ![24, 32].includes(l) || w !== 65280 || !(u === 16711680 && f === 255 || u === 255 && f === 16711680) || (l === 24 ? M !== 0 : M !== 0 && M !== 4278190080)) throw new Error("Unsupported DDS RGB bit masks.");
|
|
54
|
+
const S = l / 8, b = s(8) & 8 ? s(20) : r * S;
|
|
55
|
+
if (b < r * S) throw new Error("Invalid DDS row pitch.");
|
|
56
|
+
B(t, 128, b * c);
|
|
57
|
+
for (let v = 0; v < c; v++) for (let D = 0; D < r; D++) {
|
|
58
|
+
const R = 128 + v * b + D * S, T = (v * r + D) * 4;
|
|
59
|
+
y[T] = t[R + (u === 255 ? 0 : 2)], y[T + 1] = t[R + 1], y[T + 2] = t[R + (f === 255 ? 0 : 2)], y[T + 3] = M && i & 1 ? t[R + 3] : 255;
|
|
60
|
+
}
|
|
61
|
+
return { data: y, width: r, height: c };
|
|
62
|
+
}
|
|
63
|
+
const m = p === "DXT1" ? 8 : 16, o = Math.ceil(r / 4), a = Math.ceil(c / 4);
|
|
64
|
+
B(t, 128, o * a * m);
|
|
65
|
+
for (let l = 0; l < a; l++) for (let u = 0; u < o; u++) {
|
|
66
|
+
const w = 128 + (l * o + u) * m, f = w + (m === 8 ? 0 : 8), M = n.getUint16(f, !0), S = n.getUint16(f + 2, !0), b = [q(M), q(S)], v = p !== "DXT1" || M > S;
|
|
67
|
+
b.push([0, 1, 2].map((T) => Math.floor(v ? (2 * b[0][T] + b[1][T]) / 3 : (b[0][T] + b[1][T]) / 2)).concat(255)), b.push(v ? [0, 1, 2].map((T) => Math.floor((b[0][T] + 2 * b[1][T]) / 3)).concat(255) : [0, 0, 0, 0]);
|
|
68
|
+
const D = s(f + 4), R = [t[w], t[w + 1]];
|
|
69
|
+
if (p === "DXT5") {
|
|
70
|
+
const T = R[0] > R[1] ? 6 : 4;
|
|
71
|
+
for (let g = 1; g <= T; g++) R.push(Math.floor(((T + 1 - g) * R[0] + g * R[1]) / (T + 1)));
|
|
72
|
+
T === 4 && R.push(0, 255);
|
|
73
|
+
}
|
|
74
|
+
for (let T = 0; T < 16; T++) {
|
|
75
|
+
const g = u * 4 + T % 4, x = l * 4 + Math.floor(T / 4);
|
|
76
|
+
if (g >= r || x >= c) continue;
|
|
77
|
+
const E = b[D >>> 2 * T & 3], A = (x * r + g) * 4;
|
|
78
|
+
if (y.set(E, A), p === "DXT3" && (y[A + 3] = (t[w + Math.floor(T / 2)] >>> T % 2 * 4 & 15) * 17), p === "DXT5") {
|
|
79
|
+
const I = T * 3, h = w + 2 + Math.floor(I / 8), U = t[h] | (h + 1 < w + 8 ? t[h + 1] : 0) << 8;
|
|
80
|
+
y[A + 3] = R[U >>> I % 8 & 7];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return { data: y, width: r, height: c };
|
|
85
|
+
}
|
|
86
|
+
function Te(e, t) {
|
|
87
|
+
const n = t === "tga" ? ve(e) : Se(e), s = new Uint8Array(n.data.length), r = n.width * 4;
|
|
88
|
+
for (let i = 0; i < n.height; i++) s.set(n.data.subarray(i * r, (i + 1) * r), (n.height - 1 - i) * r);
|
|
89
|
+
const c = new N(s, n.width, n.height);
|
|
90
|
+
return c.flipY = !1, c.generateMipmaps = !0, c.minFilter = oe, c.magFilter = ae, c.needsUpdate = !0, c;
|
|
91
|
+
}
|
|
92
|
+
async function Ae(e, t, n) {
|
|
93
|
+
t.signal.throwIfAborted();
|
|
94
|
+
const s = new AbortController(), r = s.signal, c = () => s.abort(t.signal.reason);
|
|
95
|
+
t.signal.addEventListener("abort", c, { once: !0 });
|
|
96
|
+
const i = (u, w) => new Promise((f, M) => {
|
|
97
|
+
let S = !1;
|
|
98
|
+
const b = () => {
|
|
99
|
+
S || (S = !0, M(r.reason));
|
|
100
|
+
};
|
|
101
|
+
r.aborted ? b() : r.addEventListener("abort", b, { once: !0 }), u.then((v) => {
|
|
102
|
+
r.removeEventListener("abort", b), S ? w == null || w(v) : (S = !0, f(v));
|
|
103
|
+
}, (v) => {
|
|
104
|
+
r.removeEventListener("abort", b), S || (S = !0, M(v));
|
|
105
|
+
});
|
|
106
|
+
}), p = [], d = /* @__PURE__ */ new Set(), y = /* @__PURE__ */ new Set(), m = new ie(), o = async (u) => {
|
|
107
|
+
var D;
|
|
108
|
+
if (/^(blob:|data:)/i.test(u))
|
|
109
|
+
return u.startsWith("blob:") && y.add(u), u;
|
|
110
|
+
const w = [...new Set([...n.textures.values()].map((R) => R.path).filter(Boolean))], f = (R) => R.replaceAll("\\", "/").replace(/^\.\//, ""), M = f(u);
|
|
111
|
+
let S = w.filter((R) => f(R) === M);
|
|
112
|
+
if (S.length || (S = w.filter((R) => f(R).split("/").pop() === M.split("/").pop())), S.length > 1) throw new Error(`FBX texture path is ambiguous: ${u}`);
|
|
113
|
+
const b = f(S[0] ?? u), v = t.original;
|
|
114
|
+
if (typeof v == "object" && v !== null && "kind" in v && v.kind === "files") {
|
|
115
|
+
const R = ((D = t.entryPath) == null ? void 0 : D.replace(/[^/]*$/, "")) ?? "", T = (E) => {
|
|
116
|
+
const A = [];
|
|
117
|
+
for (const I of f(E).split("/"))
|
|
118
|
+
I === ".." ? A.pop() : I && I !== "." && A.push(I);
|
|
119
|
+
return A.join("/");
|
|
120
|
+
}, g = v.files.filter((E) => T(E.path) === T(R + b));
|
|
121
|
+
if (g.length === 1) return t.resolve(g[0].path);
|
|
122
|
+
const x = v.files.filter((E) => T(E.path).split("/").pop() === b.split("/").pop());
|
|
123
|
+
if (x.length === 1) return t.resolve(x[0].path);
|
|
124
|
+
if (x.length > 1) throw new Error(`FBX texture path is ambiguous: ${b}`);
|
|
125
|
+
if (!t.hasResourceResolver) throw new Error(`FBX texture is missing from the selected files: ${b}`);
|
|
126
|
+
}
|
|
127
|
+
if (/^[A-Za-z]:\//.test(b) && !t.hasResourceResolver) throw new Error(`FBX texture uses an unavailable local path: ${b}`);
|
|
128
|
+
if (!t.baseUrl && !t.hasResourceResolver && !/^https?:/i.test(b)) throw new Error(`FBX external texture requires a file package or baseUrl: ${b}`);
|
|
129
|
+
return t.resolve(b);
|
|
130
|
+
};
|
|
131
|
+
class a extends le {
|
|
132
|
+
constructor(w) {
|
|
133
|
+
super(m), this.binaryFormat = w;
|
|
134
|
+
}
|
|
135
|
+
load(w, f, M, S) {
|
|
136
|
+
const b = this.binaryFormat ? new N() : new X();
|
|
137
|
+
d.add(b);
|
|
138
|
+
const v = (async () => {
|
|
139
|
+
const D = await i(o(w));
|
|
140
|
+
r.throwIfAborted();
|
|
141
|
+
const R = await fetch(D, { signal: r });
|
|
142
|
+
if (!R.ok) throw new Error(`FBX texture request failed (${R.status}): ${w}`);
|
|
143
|
+
if (this.binaryFormat) {
|
|
144
|
+
const g = await R.arrayBuffer();
|
|
145
|
+
r.throwIfAborted();
|
|
146
|
+
let x;
|
|
147
|
+
try {
|
|
148
|
+
x = Te(g, this.binaryFormat);
|
|
149
|
+
} catch (E) {
|
|
150
|
+
throw new Error(`FBX texture decode failed (${this.binaryFormat}): ${w}: ${String(E)}`, { cause: E });
|
|
151
|
+
}
|
|
152
|
+
b.image = x.image, b.flipY = x.flipY, b.generateMipmaps = x.generateMipmaps, b.minFilter = x.minFilter, b.magFilter = x.magFilter, b.format = x.format, b.type = x.type, x.dispose(), b.needsUpdate = !0, f == null || f(b);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const T = URL.createObjectURL(await R.blob());
|
|
156
|
+
try {
|
|
157
|
+
const g = new ce().loadAsync(T).catch((E) => {
|
|
158
|
+
const A = E instanceof Error ? `: ${E.message}` : "";
|
|
159
|
+
throw new Error(`FBX texture decode failed: ${w}${A}`, { cause: E });
|
|
160
|
+
}), x = await i(g, (E) => {
|
|
161
|
+
E.dispose();
|
|
162
|
+
});
|
|
163
|
+
b.image = x.image, x.dispose(), r.throwIfAborted(), b.needsUpdate = !0, f == null || f(b);
|
|
164
|
+
} finally {
|
|
165
|
+
URL.revokeObjectURL(T);
|
|
166
|
+
}
|
|
167
|
+
})().catch((D) => {
|
|
168
|
+
throw s.abort(D), S == null || S(D), D;
|
|
169
|
+
});
|
|
170
|
+
return v.catch(() => {
|
|
171
|
+
}), p.push(v), b;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
m.addHandler(/\.tga$/i, new a("tga")), m.addHandler(/\.dds$/i, new a("dds")), m.addHandler(/.*/, new a());
|
|
175
|
+
let l;
|
|
176
|
+
try {
|
|
177
|
+
return l = new xe(m).parse(e, ""), await Promise.all(p), t.signal.throwIfAborted(), { root: l, textures: d };
|
|
178
|
+
} catch (u) {
|
|
179
|
+
if (s.abort(u), await Promise.allSettled(p), l) {
|
|
180
|
+
const { disposeModelResources: w } = await import("./stage-BKqg5vNe.js").then((f) => f.r);
|
|
181
|
+
w(l, d);
|
|
182
|
+
} else for (const w of d) w.dispose();
|
|
183
|
+
throw u;
|
|
184
|
+
} finally {
|
|
185
|
+
t.signal.removeEventListener("abort", c);
|
|
186
|
+
for (const u of y) URL.revokeObjectURL(u);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const P = "Kaydara FBX Binary \0", Ue = /(?:^|[\r\n])\s*P:\s*"UpAxis"\s*,\s*"int"\s*,\s*"Integer"\s*,\s*""\s*,\s*(-?\d+)/i, Fe = /(?:^|[\r\n])\s*P:\s*"UpAxisSign"\s*,\s*"int"\s*,\s*"Integer"\s*,\s*""\s*,\s*(-?\d+)/i;
|
|
190
|
+
function Re(e) {
|
|
191
|
+
try {
|
|
192
|
+
const t = new Uint8Array(e), n = Ie(t) ? Oe(e) : De(new TextDecoder().decode(t));
|
|
193
|
+
return !n || n.sign !== 1 ? null : n.axis === 1 ? "y" : n.axis === 2 ? "z" : null;
|
|
194
|
+
} catch {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function Ie(e) {
|
|
199
|
+
if (e.byteLength < P.length) return !1;
|
|
200
|
+
for (let t = 0; t < P.length; t += 1)
|
|
201
|
+
if (e[t] !== P.charCodeAt(t)) return !1;
|
|
202
|
+
return !0;
|
|
203
|
+
}
|
|
204
|
+
function De(e) {
|
|
205
|
+
var r, c;
|
|
206
|
+
const t = Number.parseInt(((r = Ue.exec(e)) == null ? void 0 : r[1]) ?? "", 10);
|
|
207
|
+
if (!Number.isInteger(t)) return null;
|
|
208
|
+
const n = (c = Fe.exec(e)) == null ? void 0 : c[1], s = n === void 0 ? 1 : Number.parseInt(n, 10);
|
|
209
|
+
return Number.isInteger(s) ? { axis: t, sign: s } : null;
|
|
210
|
+
}
|
|
211
|
+
function Oe(e) {
|
|
212
|
+
const t = new DataView(e);
|
|
213
|
+
if (t.byteLength < 27) return null;
|
|
214
|
+
const n = t.getUint32(23, !0) >= 7500;
|
|
215
|
+
let s = 27;
|
|
216
|
+
for (; s < t.byteLength; ) {
|
|
217
|
+
const r = C(t, s, n, !1);
|
|
218
|
+
if (!r) break;
|
|
219
|
+
if (r.name === "GlobalSettings") return ne(t, r.childrenOffset, r.endOffset, n);
|
|
220
|
+
s = r.endOffset;
|
|
221
|
+
}
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
function ne(e, t, n, s) {
|
|
225
|
+
let r = t, c = null, i = 1;
|
|
226
|
+
for (; r < n; ) {
|
|
227
|
+
const p = C(e, r, s, !0);
|
|
228
|
+
if (!p) break;
|
|
229
|
+
if (p.name === "P") {
|
|
230
|
+
const [d, , , , y] = p.properties;
|
|
231
|
+
d === "UpAxis" && typeof y == "number" && (c = y), d === "UpAxisSign" && typeof y == "number" && (i = y);
|
|
232
|
+
}
|
|
233
|
+
if (p.childrenOffset < p.endOffset) {
|
|
234
|
+
const d = ne(e, p.childrenOffset, p.endOffset, s);
|
|
235
|
+
d && (c ?? (c = d.axis), i = d.sign);
|
|
236
|
+
}
|
|
237
|
+
r = p.endOffset;
|
|
238
|
+
}
|
|
239
|
+
return c === null ? null : { axis: c, sign: i };
|
|
240
|
+
}
|
|
241
|
+
function C(e, t, n, s) {
|
|
242
|
+
const r = n ? 25 : 13;
|
|
243
|
+
if (t + r > e.byteLength) return null;
|
|
244
|
+
const c = $(e, t, n), i = $(e, t + (n ? 8 : 4), n), p = $(e, t + (n ? 16 : 8), n), d = e.getUint8(t + (n ? 24 : 12));
|
|
245
|
+
if (c === 0) return null;
|
|
246
|
+
const y = t + r, m = y + d, o = m + p;
|
|
247
|
+
if (c <= t || c > e.byteLength || o > c) throw new Error("Invalid FBX node bounds.");
|
|
248
|
+
const a = new TextDecoder().decode(new Uint8Array(e.buffer, e.byteOffset + y, d)), l = [];
|
|
249
|
+
if (s) {
|
|
250
|
+
let u = m;
|
|
251
|
+
for (let w = 0; w < i; w += 1) {
|
|
252
|
+
const f = Be(e, u);
|
|
253
|
+
if (l.push(f.value), u = f.nextOffset, u > o) return null;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return { name: a, endOffset: c, childrenOffset: o, properties: l };
|
|
257
|
+
}
|
|
258
|
+
function $(e, t, n) {
|
|
259
|
+
if (!n) return e.getUint32(t, !0);
|
|
260
|
+
const s = e.getBigUint64(t, !0);
|
|
261
|
+
if (s > BigInt(Number.MAX_SAFE_INTEGER)) throw new Error("FBX offset exceeds the safe integer range.");
|
|
262
|
+
return Number(s);
|
|
263
|
+
}
|
|
264
|
+
function Be(e, t) {
|
|
265
|
+
const n = String.fromCharCode(e.getUint8(t));
|
|
266
|
+
switch (n) {
|
|
267
|
+
case "Y":
|
|
268
|
+
return { value: e.getInt16(t + 1, !0), nextOffset: t + 3 };
|
|
269
|
+
case "C":
|
|
270
|
+
return { value: e.getUint8(t + 1) !== 0, nextOffset: t + 2 };
|
|
271
|
+
case "I":
|
|
272
|
+
return { value: e.getInt32(t + 1, !0), nextOffset: t + 5 };
|
|
273
|
+
case "F":
|
|
274
|
+
return { value: e.getFloat32(t + 1, !0), nextOffset: t + 5 };
|
|
275
|
+
case "D":
|
|
276
|
+
return { value: e.getFloat64(t + 1, !0), nextOffset: t + 9 };
|
|
277
|
+
case "L":
|
|
278
|
+
return { value: Number(e.getBigInt64(t + 1, !0)), nextOffset: t + 9 };
|
|
279
|
+
case "S":
|
|
280
|
+
case "R": {
|
|
281
|
+
const s = e.getUint32(t + 1, !0), r = t + 5, c = new Uint8Array(e.buffer, e.byteOffset + r, s);
|
|
282
|
+
return { value: n === "S" ? new TextDecoder().decode(c) : c, nextOffset: r + s };
|
|
283
|
+
}
|
|
284
|
+
case "f":
|
|
285
|
+
case "d":
|
|
286
|
+
case "l":
|
|
287
|
+
case "i":
|
|
288
|
+
case "b":
|
|
289
|
+
case "c": {
|
|
290
|
+
const s = e.getUint32(t + 9, !0);
|
|
291
|
+
return { value: null, nextOffset: t + 13 + s };
|
|
292
|
+
}
|
|
293
|
+
default:
|
|
294
|
+
throw new Error(`Unsupported FBX property type: ${n}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const L = /* @__PURE__ */ new Set(["Definitions", "ObjectType", "PropertyTemplate", "Objects", "Material", "Properties70", "Connections", "Texture", "Video", "Geometry", "LayerElementUV", "LayeredTexture", "BlendModes", "Alphas"]), re = /* @__PURE__ */ new Set(["P", "C", "RelativeFilename", "FileName", "Filename", "ShadingModel", "UVSet", "Scaling", "Translation", "Rotation", "RotationPivot", "ScalingPivot", "Name", "UV", "a"]);
|
|
298
|
+
function _e(e) {
|
|
299
|
+
var S, b, v, D, R, T;
|
|
300
|
+
const t = new Uint8Array(e), s = new TextDecoder().decode(t.subarray(0, 21)) === "Kaydara FBX Binary \0" ? Ce(e) : Xe(new TextDecoder().decode(t)), r = (g) => {
|
|
301
|
+
var x;
|
|
302
|
+
return new Map(
|
|
303
|
+
(((x = g == null ? void 0 : g.children.find((E) => E.name === "Properties70")) == null ? void 0 : x.children) ?? []).filter((E) => E.name === "P" && typeof E.values[0] == "string").map((E) => [E.values[0], E.values.slice(4)])
|
|
304
|
+
);
|
|
305
|
+
}, c = s.find((g) => g.name === "Definitions"), i = c == null ? void 0 : c.children.find((g) => g.name === "ObjectType" && g.values[0] === "Material"), p = (i == null ? void 0 : i.children.filter((g) => g.name === "PropertyTemplate")) ?? [], d = ((S = s.find((g) => g.name === "Connections")) == null ? void 0 : S.children.filter((g) => g.name === "C")) ?? [], y = ((b = s.find((g) => g.name === "Objects")) == null ? void 0 : b.children) ?? [], m = /* @__PURE__ */ new Map(), o = (g, x) => {
|
|
306
|
+
var E;
|
|
307
|
+
return (E = g == null ? void 0 : g.children.find((A) => A.name === x)) == null ? void 0 : E.values[0];
|
|
308
|
+
};
|
|
309
|
+
for (const g of y.filter((x) => x.name === "Texture")) {
|
|
310
|
+
const x = Number(g.values[0]), E = (v = d.find((F) => F.values[0] === "OO" && F.values[2] === x)) == null ? void 0 : v.values[1], A = y.find((F) => F.name === "Video" && F.values[0] === E), I = String(o(A, "RelativeFilename") || o(g, "RelativeFilename") || o(A, "Filename") || o(g, "FileName") || ""), h = r(g);
|
|
311
|
+
for (const F of ["Scaling", "Translation", "Rotation", "RotationPivot", "ScalingPivot"]) {
|
|
312
|
+
const O = (D = g.children.find((se) => se.name === F)) == null ? void 0 : D.values;
|
|
313
|
+
O && h.set(F, O);
|
|
314
|
+
}
|
|
315
|
+
const U = o(g, "UVSet") ?? ((R = h.get("UVSet")) == null ? void 0 : R[0]);
|
|
316
|
+
m.set(x, { id: x, path: I, values: h, uvSet: typeof U == "string" ? U : null });
|
|
317
|
+
}
|
|
318
|
+
const a = /* @__PURE__ */ new Map(), l = (g, x) => {
|
|
319
|
+
var I;
|
|
320
|
+
const E = g.children.find((h) => h.name === x), A = ((I = E == null ? void 0 : E.children.find((h) => h.name === "a")) == null ? void 0 : I.values) ?? (E == null ? void 0 : E.values) ?? [];
|
|
321
|
+
if (A.some((h) => typeof h != "number" || !Number.isFinite(h))) throw new Error(`Invalid FBX layered ${x}.`);
|
|
322
|
+
return A;
|
|
323
|
+
};
|
|
324
|
+
for (const g of y.filter((x) => x.name === "LayeredTexture")) {
|
|
325
|
+
const x = Number(g.values[0]);
|
|
326
|
+
if (!Number.isSafeInteger(x)) throw new Error("Invalid FBX layered texture ID.");
|
|
327
|
+
a.set(x, {
|
|
328
|
+
id: x,
|
|
329
|
+
name: String(g.values[1] ?? ""),
|
|
330
|
+
textureIds: d.filter((E) => E.values[0] === "OO" && E.values[2] === x).map((E) => Number(E.values[1])),
|
|
331
|
+
blendModes: l(g, "BlendModes"),
|
|
332
|
+
alphas: l(g, "Alphas")
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
const u = /* @__PURE__ */ new Map();
|
|
336
|
+
for (const g of ((T = s.find((x) => x.name === "Objects")) == null ? void 0 : T.children) ?? []) {
|
|
337
|
+
if (g.name !== "Material") continue;
|
|
338
|
+
const x = g.values[0];
|
|
339
|
+
if (typeof x != "number" || !Number.isSafeInteger(x)) throw new Error("Invalid FBX material ID.");
|
|
340
|
+
const E = r(g), A = d.filter((F) => F.values[0] === "OP" && F.values[2] === x).map((F) => String(F.values[3])), I = d.filter((F) => F.values[0] === "OP" && F.values[2] === x).map((F) => ({ id: Number(F.values[1]), role: String(F.values[3]) })), h = String(o(g, "ShadingModel") ?? "phong").toLowerCase(), U = r(p.find((F) => String(F.values[0]).toLowerCase() === `fbxsurface${h}`));
|
|
341
|
+
u.set(x, {
|
|
342
|
+
textureConnections: I,
|
|
343
|
+
shadingModel: h,
|
|
344
|
+
id: x,
|
|
345
|
+
name: String(g.values[1] ?? ""),
|
|
346
|
+
ownValues: E,
|
|
347
|
+
values: new Map([...U, ...E]),
|
|
348
|
+
textureRoles: A
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
const w = /* @__PURE__ */ new Map();
|
|
352
|
+
for (const g of d) {
|
|
353
|
+
const [x, E, A] = g.values;
|
|
354
|
+
if (x !== "OO" || typeof E != "number" || typeof A != "number" || !u.has(E)) continue;
|
|
355
|
+
const I = w.get(A) ?? [];
|
|
356
|
+
I.push(E), w.set(A, I);
|
|
357
|
+
}
|
|
358
|
+
const f = /* @__PURE__ */ new Map();
|
|
359
|
+
for (const g of y.filter((x) => x.name === "Geometry")) {
|
|
360
|
+
const x = new Map(g.children.filter((A) => A.name === "LayerElementUV").map((A) => [Number(A.values[0]), A])), E = [];
|
|
361
|
+
for (let A = 0; x.has(A); A++) {
|
|
362
|
+
const I = x.get(A);
|
|
363
|
+
I.children.some((h) => h.name === "UV") && E.push(String(o(I, "Name") ?? ""));
|
|
364
|
+
}
|
|
365
|
+
f.set(Number(g.values[0]), E);
|
|
366
|
+
}
|
|
367
|
+
const M = /* @__PURE__ */ new Map();
|
|
368
|
+
for (const g of d) {
|
|
369
|
+
const [x, E, A] = g.values;
|
|
370
|
+
x === "OO" && typeof E == "number" && typeof A == "number" && f.has(E) && M.set(A, f.get(E));
|
|
371
|
+
}
|
|
372
|
+
return { materials: u, modelMaterials: w, textures: m, modelUvSets: M, layeredTextures: a };
|
|
373
|
+
}
|
|
374
|
+
function Ce(e) {
|
|
375
|
+
const t = new DataView(e);
|
|
376
|
+
if (t.byteLength < 27) throw new Error("Truncated FBX header.");
|
|
377
|
+
const n = t.getUint32(23, !0) >= 7500, s = (r, c, i) => {
|
|
378
|
+
if (i > 16) throw new Error("Excessive FBX metadata nesting.");
|
|
379
|
+
const p = [];
|
|
380
|
+
let d = r;
|
|
381
|
+
for (; d < c; ) {
|
|
382
|
+
const y = C(t, d, n, !1);
|
|
383
|
+
if (!y) break;
|
|
384
|
+
if (y.endOffset > c) throw new Error("FBX child extends past its parent.");
|
|
385
|
+
if (L.has(y.name) || re.has(y.name)) {
|
|
386
|
+
const m = C(t, d, n, y.name !== "UV");
|
|
387
|
+
p.push({ name: m.name, values: ["BlendModes", "Alphas"].includes(m.name) ? Le(t, d, n, m.childrenOffset) : [...m.properties], children: L.has(m.name) ? s(m.childrenOffset, m.endOffset, i + 1) : [] });
|
|
388
|
+
}
|
|
389
|
+
d = y.endOffset;
|
|
390
|
+
}
|
|
391
|
+
return p;
|
|
392
|
+
};
|
|
393
|
+
return s(27, t.byteLength, 0);
|
|
394
|
+
}
|
|
395
|
+
function Xe(e) {
|
|
396
|
+
const t = /"(?:\\.|[^"\\])*"|;[^\r\n]*|\r?\n|[^\S\r\n]+|[{}:,]|[^\s{}:,;]+/g;
|
|
397
|
+
let n = null;
|
|
398
|
+
const s = () => {
|
|
399
|
+
var i;
|
|
400
|
+
if (n !== null) {
|
|
401
|
+
const p = n;
|
|
402
|
+
return n = null, p;
|
|
403
|
+
}
|
|
404
|
+
for (; ; ) {
|
|
405
|
+
const p = ((i = t.exec(e)) == null ? void 0 : i[0]) ?? null;
|
|
406
|
+
if (p === null) return null;
|
|
407
|
+
if (!(p.startsWith(";") || /^[^\S\r\n]+$/.test(p)))
|
|
408
|
+
return p;
|
|
409
|
+
}
|
|
410
|
+
}, r = (i) => i.startsWith('"') ? i.slice(1, -1).replace(/\\(["\\])/g, "$1") : Number.isFinite(Number(i)) ? Number(i) : i, c = (i) => {
|
|
411
|
+
if (i > 16) throw new Error("Excessive FBX metadata nesting.");
|
|
412
|
+
const p = [];
|
|
413
|
+
for (; ; ) {
|
|
414
|
+
const d = s();
|
|
415
|
+
if (d === null) {
|
|
416
|
+
if (i) throw new Error("Unclosed FBX block.");
|
|
417
|
+
return p;
|
|
418
|
+
}
|
|
419
|
+
if (d === "}") {
|
|
420
|
+
if (!i) throw new Error("Unexpected FBX closing brace.");
|
|
421
|
+
return p;
|
|
422
|
+
}
|
|
423
|
+
if (d === `
|
|
424
|
+
` || d === `\r
|
|
425
|
+
`) continue;
|
|
426
|
+
if (s() !== ":") throw new Error("Malformed ASCII FBX metadata.");
|
|
427
|
+
const y = L.has(d) || re.has(d), m = [];
|
|
428
|
+
let o = [];
|
|
429
|
+
for (; ; ) {
|
|
430
|
+
const a = s();
|
|
431
|
+
if (a === null || a === `
|
|
432
|
+
` || a === `\r
|
|
433
|
+
`) break;
|
|
434
|
+
if (a === "}") {
|
|
435
|
+
n = a;
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
if (a === "{") {
|
|
439
|
+
if (L.has(d)) o = c(i + 1);
|
|
440
|
+
else {
|
|
441
|
+
let l = 1;
|
|
442
|
+
for (; l; ) {
|
|
443
|
+
const u = s();
|
|
444
|
+
if (u === null) throw new Error("Unclosed FBX block.");
|
|
445
|
+
u === "{" && l++, u === "}" && l--;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
y && a !== "," && m.push(r(a));
|
|
451
|
+
}
|
|
452
|
+
y && p.push({ name: d, values: m, children: o });
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
return c(0);
|
|
456
|
+
}
|
|
457
|
+
function Le(e, t, n, s) {
|
|
458
|
+
const r = n ? 25 : 13;
|
|
459
|
+
let c = t + r + e.getUint8(t + r - 1);
|
|
460
|
+
if (c === s) return [];
|
|
461
|
+
const i = String.fromCharCode(e.getUint8(c));
|
|
462
|
+
if (!["i", "d", "f"].includes(i)) return [...C(e, t, n, !0).properties];
|
|
463
|
+
if (c + 13 > s) throw new Error("Truncated FBX layered array header.");
|
|
464
|
+
const p = e.getUint32(c + 1, !0), d = e.getUint32(c + 5, !0), y = e.getUint32(c + 9, !0), m = i === "d" ? 8 : 4;
|
|
465
|
+
if (p > 4096 || c + 13 + y !== s || ![0, 1].includes(d)) throw new Error("Invalid FBX layered array bounds.");
|
|
466
|
+
const o = new Uint8Array(e.buffer, e.byteOffset + c + 13, y), a = d === 1 ? Ee(o, { out: new Uint8Array(p * m) }) : o;
|
|
467
|
+
if (a.length !== p * m) throw new Error("Invalid FBX layered array size.");
|
|
468
|
+
const l = new DataView(a.buffer, a.byteOffset, a.byteLength);
|
|
469
|
+
return Array.from({ length: p }, (u, w) => i === "i" ? l.getInt32(w * m, !0) : i === "d" ? l.getFloat64(w * m, !0) : l.getFloat32(w * m, !0));
|
|
470
|
+
}
|
|
471
|
+
const j = (e) => e <= 0.04045 ? e / 12.92 : ((e + 0.055) / 1.055) ** 2.4, Ne = (e) => e <= 31308e-7 ? e * 12.92 : 1.055 * e ** (1 / 2.4) - 0.055, Pe = /* @__PURE__ */ new Set([0, 1, 2, 4, 5]), $e = 4 * 1024 * 1024;
|
|
472
|
+
function z(e) {
|
|
473
|
+
const t = e.image, n = (t == null ? void 0 : t.naturalWidth) || (t == null ? void 0 : t.width), s = (t == null ? void 0 : t.naturalHeight) || (t == null ? void 0 : t.height);
|
|
474
|
+
if (!n || !s || n * s > $e) throw new Error("missing image or image exceeds 4M pixels");
|
|
475
|
+
let r;
|
|
476
|
+
if (t.data) {
|
|
477
|
+
if (e.format !== K || e.type !== J || !(t.data instanceof Uint8Array) || t.data.length !== n * s * 4) throw new Error("require RGBA8 source");
|
|
478
|
+
r = t.data;
|
|
479
|
+
} else {
|
|
480
|
+
const i = document.createElement("canvas");
|
|
481
|
+
i.width = n, i.height = s;
|
|
482
|
+
const p = i.getContext("2d", { willReadFrequently: !0 });
|
|
483
|
+
if (!p) throw new Error("canvas readback unavailable");
|
|
484
|
+
p.drawImage(e.image, 0, 0), r = p.getImageData(0, 0, n, s).data;
|
|
485
|
+
}
|
|
486
|
+
const c = new Uint8Array(n * s * 4);
|
|
487
|
+
for (let i = 0; i < s; i++) for (let p = 0; p < n * 4; p++) c[(e.flipY ? s - i - 1 : i) * n * 4 + p] = r[i * n * 4 + p];
|
|
488
|
+
return { data: c, width: n, height: s };
|
|
489
|
+
}
|
|
490
|
+
function Ve(e, t, n) {
|
|
491
|
+
if (e.issues.some((o) => o.code !== "LAYERED_TEXTURE_NOT_COMPOSITED")) throw new Error("incompatible layer graph or coordinates");
|
|
492
|
+
if (e.layers.length < 1 || e.layers.length > 8) throw new Error("require 1–8 layers");
|
|
493
|
+
if (!e.layers.every((o) => o.blendMode !== null && Pe.has(o.blendMode))) throw new Error("unsupported blend mode");
|
|
494
|
+
const s = e.layers.map((o) => {
|
|
495
|
+
const a = [...n].find((l) => l.ID === o.textureId);
|
|
496
|
+
if (!a) throw new Error(`missing decoded texture ${o.textureId}`);
|
|
497
|
+
return a;
|
|
498
|
+
}), r = s[0], c = (o) => JSON.stringify([
|
|
499
|
+
o.wrapS,
|
|
500
|
+
o.wrapT,
|
|
501
|
+
o.minFilter,
|
|
502
|
+
o.magFilter,
|
|
503
|
+
o.anisotropy,
|
|
504
|
+
o.channel,
|
|
505
|
+
o.mapping,
|
|
506
|
+
o.matrixAutoUpdate,
|
|
507
|
+
o.offset.toArray(),
|
|
508
|
+
o.repeat.toArray(),
|
|
509
|
+
o.center.toArray(),
|
|
510
|
+
o.rotation,
|
|
511
|
+
o.matrix.elements
|
|
512
|
+
]);
|
|
513
|
+
if (s.some((o) => c(o) !== c(r))) throw new Error("incompatible sampling state");
|
|
514
|
+
if (e.layers.some((o) => !t.textures.has(o.textureId))) throw new Error("missing source metadata");
|
|
515
|
+
const i = z(r), p = i.width * i.height;
|
|
516
|
+
if (e.layers[0].alpha !== 1 || i.data.some((o, a) => a % 4 === 3 && o !== 255)) throw new Error("base layer must be fully opaque with weight 1");
|
|
517
|
+
const d = new Float32Array(p * 3);
|
|
518
|
+
for (let o = 0; o < p; o++) for (let a = 0; a < 3; a++) d[o * 3 + a] = r.colorSpace === G ? i.data[o * 4 + a] / 255 : j(i.data[o * 4 + a] / 255);
|
|
519
|
+
for (let o = 1; o < s.length; o++) {
|
|
520
|
+
const a = s[o], l = z(a), u = e.layers[o];
|
|
521
|
+
if (l.width !== i.width || l.height !== i.height) throw new Error("layer dimensions differ");
|
|
522
|
+
for (let w = 0; w < p; w++) {
|
|
523
|
+
const f = u.alpha * l.data[w * 4 + 3] / 255;
|
|
524
|
+
for (let M = 0; M < 3; M++) {
|
|
525
|
+
const S = d[w * 3 + M], b = l.data[w * 4 + M] / 255, v = a.colorSpace === G ? b : j(b), D = u.blendMode === 1 ? Math.min(1, S + v) : u.blendMode === 2 ? S * v : v;
|
|
526
|
+
d[w * 3 + M] = S + (D - S) * f;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
const y = new Uint8Array(p * 4);
|
|
531
|
+
for (let o = 0; o < p; o++) y[o * 4 + 3] = 255;
|
|
532
|
+
for (let o = 0; o < p; o++) for (let a = 0; a < 3; a++) y[o * 4 + a] = Math.round(255 * Math.min(1, Math.max(0, Ne(d[o * 3 + a]))));
|
|
533
|
+
const m = new N(y, i.width, i.height);
|
|
534
|
+
return m.colorSpace = ue, m.generateMipmaps = r.generateMipmaps, m.wrapS = r.wrapS, m.wrapT = r.wrapT, m.minFilter = r.minFilter, m.magFilter = r.magFilter, m.anisotropy = r.anisotropy, m.offset.copy(r.offset), m.repeat.copy(r.repeat), m.center.copy(r.center), m.rotation = r.rotation, m.matrix.copy(r.matrix), m.matrixAutoUpdate = r.matrixAutoUpdate, m.channel = r.channel, m.mapping = r.mapping, m.userData.fbxLayerBaseId = e.layers[0].textureId, m.needsUpdate = !0, m;
|
|
535
|
+
}
|
|
536
|
+
function Ge(e, t) {
|
|
537
|
+
return e.textureConnections.flatMap((n) => {
|
|
538
|
+
var o;
|
|
539
|
+
const s = (o = t.layeredTextures) == null ? void 0 : o.get(n.id);
|
|
540
|
+
if (!s) return [];
|
|
541
|
+
const r = [], c = (a, l) => r.push({ status: "unsupported", code: a, source: `layered:${s.id}:${l}`, target: n.role });
|
|
542
|
+
c("LAYERED_TEXTURE_NOT_COMPOSITED", "preview uses loader fallback; layers have not been composited");
|
|
543
|
+
const i = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set(), d = [], y = (a, l) => {
|
|
544
|
+
var w;
|
|
545
|
+
if (i.has(a)) {
|
|
546
|
+
c("LAYERED_TEXTURE_CYCLE", String(a));
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
if (l > 32 || p.size >= 4096) {
|
|
550
|
+
c("LAYERED_TEXTURE_GRAPH_LIMIT", String(a));
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
if (p.has(a)) return;
|
|
554
|
+
const u = (w = t.layeredTextures) == null ? void 0 : w.get(a);
|
|
555
|
+
if (!u) {
|
|
556
|
+
t.textures.has(a) ? d.push(a) : c("LAYERED_TEXTURE_MISSING_SOURCE", String(a)), p.add(a);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
l && c("LAYERED_TEXTURE_NESTED", String(a)), u.textureIds.length || c("LAYERED_TEXTURE_EMPTY", String(a)), (u.blendModes.length !== u.textureIds.length || u.alphas.length !== u.textureIds.length) && c("LAYERED_TEXTURE_METADATA_MISMATCH", `${a}:sources=${u.textureIds.length},modes=${u.blendModes.length},alphas=${u.alphas.length}`), u.blendModes.some((f) => !Number.isInteger(f) || f < 0) && c("LAYERED_TEXTURE_INVALID_MODE", String(a)), u.alphas.some((f) => !Number.isFinite(f) || f < 0 || f > 1) && c("LAYERED_TEXTURE_INVALID_ALPHA", String(a)), i.add(a);
|
|
560
|
+
for (const f of u.textureIds) y(f, l + 1);
|
|
561
|
+
i.delete(a), p.add(a);
|
|
562
|
+
};
|
|
563
|
+
return y(s.id, 0), new Set(d.map((a) => {
|
|
564
|
+
const l = t.textures.get(a);
|
|
565
|
+
return JSON.stringify([l.uvSet ?? "default", ...["Translation", "Scaling", "Rotation", "RotationPivot", "ScalingPivot"].map((u) => l.values.get(u) ?? null)]);
|
|
566
|
+
})).size > 1 && c("LAYERED_TEXTURE_COORDINATES_DIFFER", "UV sets or transforms differ; direct pixel blending is unsafe"), [{ id: s.id, role: n.role, layers: s.textureIds.map((a, l) => ({ textureId: a, blendMode: s.blendModes[l] ?? null, alpha: s.alphas[l] ?? null })), issues: r }];
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
const ke = {
|
|
570
|
+
DiffuseColor: "map",
|
|
571
|
+
"Maya|TEX_color_map": "map",
|
|
572
|
+
NormalMap: "normalMap",
|
|
573
|
+
"Maya|TEX_normal_map": "normalMap",
|
|
574
|
+
Bump: "bumpMap",
|
|
575
|
+
EmissiveColor: "emissiveMap",
|
|
576
|
+
DisplacementColor: "displacementMap",
|
|
577
|
+
"Maya|TEX_ao_map": "aoMap",
|
|
578
|
+
ReflectionFactor: "metalnessMap",
|
|
579
|
+
ReflectionColor: "metalnessMap",
|
|
580
|
+
ShininessExponent: "roughnessMap",
|
|
581
|
+
SpecularFactor: "specularIntensityMap",
|
|
582
|
+
SpecularColor: "specularIntensityMap",
|
|
583
|
+
TransparentColor: "alphaMap",
|
|
584
|
+
TransparencyFactor: "alphaMap"
|
|
585
|
+
};
|
|
586
|
+
function Ye(e, t, n, s, r, c) {
|
|
587
|
+
var a;
|
|
588
|
+
const i = (a = s.modelUvSets) == null ? void 0 : a.get(e.ID ?? NaN), p = [], d = [], y = /* @__PURE__ */ new Set();
|
|
589
|
+
for (const l of n.textureConnections) {
|
|
590
|
+
const u = ke[l.role], w = u ? t[u] : void 0, f = s.textures.get(l.id) ?? (w instanceof X ? s.textures.get(w.userData.fbxLayerBaseId) : void 0);
|
|
591
|
+
if (!u || !f || y.has(u)) continue;
|
|
592
|
+
y.add(u);
|
|
593
|
+
const M = t[u];
|
|
594
|
+
if (!(M instanceof X)) continue;
|
|
595
|
+
const S = (I, h) => d.push({ status: "unsupported", code: I, source: `texture:${l.id}:${h}`, target: String(u) });
|
|
596
|
+
let b = 0;
|
|
597
|
+
if (f.uvSet) {
|
|
598
|
+
const I = (i == null ? void 0 : i.flatMap((h, U) => h === f.uvSet ? [U] : [])) ?? [];
|
|
599
|
+
if (I.length === 1) b = I[0];
|
|
600
|
+
else if (I.length > 1 || f.uvSet !== "default") {
|
|
601
|
+
S("UV_SET_UNRESOLVED", `UVSet:${f.uvSet}:${I.length > 1 ? "ambiguous" : "missing"}`);
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
if (b > 3 || !e.geometry.hasAttribute(b === 0 ? "uv" : `uv${b}`)) {
|
|
606
|
+
S("UV_CHANNEL_UNAVAILABLE", `channel:${b}`);
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
const v = (I, h) => {
|
|
610
|
+
const U = f.values.get(I);
|
|
611
|
+
return U ? U.length < 2 || !U.every((F) => typeof F == "number" && Number.isFinite(F)) ? (S("TEXTURE_TRANSFORM_INVALID", I), h) : U : h;
|
|
612
|
+
}, D = v("Translation", [M.offset.x, M.offset.y, 0]), R = v("Scaling", [M.repeat.x, M.repeat.y, 1]), T = v("Rotation", [0, 0, 0]), g = v("RotationPivot", [0, 0, 0]), x = v("ScalingPivot", [0, 0, 0]), E = T[0] !== 0 || T[1] !== 0 || g.some((I) => I !== 0) || x.some((I) => I !== 0);
|
|
613
|
+
E && S("TEXTURE_TRANSFORM_UNSUPPORTED", "3D-rotation-or-pivot"), (D[2] || R[2] !== void 0 && R[2] !== 1) && S("TEXTURE_TRANSFORM_UNSUPPORTED", "3D-translation-or-scale");
|
|
614
|
+
const A = E ? 0 : -(T[2] ?? 0) * Math.PI / 180;
|
|
615
|
+
A && d.push({ status: "approximate", code: "TEXTURE_ROTATION_PROFILE", source: `texture:${l.id}:Rotation`, target: "T * Rccw * S; origin pivot" }), (b !== M.channel || D[0] !== M.offset.x || D[1] !== M.offset.y || R[0] !== M.repeat.x || R[1] !== M.repeat.y || A !== M.rotation) && p.push({ slot: u, source: M, channel: b, offset: D, scale: R, rotation: A });
|
|
616
|
+
}
|
|
617
|
+
if (!p.length && !d.length) return t;
|
|
618
|
+
const m = t.clone();
|
|
619
|
+
r(m);
|
|
620
|
+
const o = m.userData.fbxConversionReport;
|
|
621
|
+
o.issues.push(...d);
|
|
622
|
+
for (const l of p) {
|
|
623
|
+
const u = l.source.clone();
|
|
624
|
+
c(u), u.channel = l.channel, u.offset.set(l.offset[0], l.offset[1]), u.repeat.set(l.scale[0], l.scale[1]), u.center.set(0, 0), u.rotation = l.rotation;
|
|
625
|
+
const w = -l.rotation, f = Math.cos(w), M = Math.sin(w);
|
|
626
|
+
u.matrixAutoUpdate = !1, u.matrix.set(
|
|
627
|
+
f * l.scale[0],
|
|
628
|
+
-M * l.scale[1],
|
|
629
|
+
l.offset[0],
|
|
630
|
+
M * l.scale[0],
|
|
631
|
+
f * l.scale[1],
|
|
632
|
+
l.offset[1],
|
|
633
|
+
0,
|
|
634
|
+
0,
|
|
635
|
+
1
|
|
636
|
+
), m[l.slot] = u, o.mappings.push({ source: `${l.slot}:UV`, target: `uv${l.channel || ""}`, rule: "geometry UV name binding; T * Rccw * S" });
|
|
637
|
+
}
|
|
638
|
+
return m.needsUpdate = !0, m;
|
|
639
|
+
}
|
|
640
|
+
function qe(e, t) {
|
|
641
|
+
return Math.min(1, Math.max(0, e));
|
|
642
|
+
}
|
|
643
|
+
function je(e, t, n, s, r = "r", c = !1) {
|
|
644
|
+
if (!Number.isInteger(t) || !Number.isInteger(n) || t <= 0 || n <= 0 || e.length !== t * n * 4)
|
|
645
|
+
throw new Error("Invalid FBX scalar RGBA dimensions.");
|
|
646
|
+
const i = new Uint8Array(e.length), p = { r: 0, g: 1, b: 2, a: 3 }[r];
|
|
647
|
+
for (let d = 0; d < n; d++) for (let y = 0; y < t; y++) {
|
|
648
|
+
const m = (d * t + y) * 4, o = ((c ? n - d - 1 : d) * t + y) * 4, a = Math.round(255 * qe(e[m + p] / 255));
|
|
649
|
+
i.fill(a, o, o + 4);
|
|
650
|
+
}
|
|
651
|
+
return i;
|
|
652
|
+
}
|
|
653
|
+
function ze(e, t) {
|
|
654
|
+
const n = e.image;
|
|
655
|
+
if (!n) throw new Error("FBX scalar texture has no decoded image.");
|
|
656
|
+
const s = n.naturalWidth || n.width, r = n.naturalHeight || n.height;
|
|
657
|
+
if (!s || !r) throw new Error("FBX scalar texture has no decoded image.");
|
|
658
|
+
let c;
|
|
659
|
+
if (n.data) {
|
|
660
|
+
if (!(n.data instanceof Uint8Array || n.data instanceof Uint8ClampedArray) || e.format !== K || e.type !== J)
|
|
661
|
+
throw new Error("FBX scalar conversion requires 8-bit RGBA pixels.");
|
|
662
|
+
c = n.data;
|
|
663
|
+
} else {
|
|
664
|
+
const p = document.createElement("canvas");
|
|
665
|
+
p.width = s, p.height = r;
|
|
666
|
+
const d = p.getContext("2d", { willReadFrequently: !0 });
|
|
667
|
+
if (!d) throw new Error("FBX scalar texture conversion requires a 2D canvas.");
|
|
668
|
+
d.drawImage(n, 0, 0), c = d.getImageData(0, 0, s, r).data;
|
|
669
|
+
}
|
|
670
|
+
const i = new N(je(c, s, r, t, "r", e.flipY), s, r);
|
|
671
|
+
return i.wrapS = e.wrapS, i.wrapT = e.wrapT, i.offset.copy(e.offset), i.repeat.copy(e.repeat), i.center.copy(e.center), i.rotation = e.rotation, i.matrix.copy(e.matrix), i.matrixAutoUpdate = e.matrixAutoUpdate, i.channel = e.channel, i.magFilter = e.magFilter, i.minFilter = e.minFilter, i.generateMipmaps = e.generateMipmaps, i.anisotropy = e.anisotropy, i.colorSpace = fe, i.needsUpdate = !0, i;
|
|
672
|
+
}
|
|
673
|
+
function He(e, t, n) {
|
|
674
|
+
const s = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set(), d = [];
|
|
675
|
+
try {
|
|
676
|
+
e.traverse((a) => {
|
|
677
|
+
if (!(a instanceof pe)) return;
|
|
678
|
+
const l = t == null ? void 0 : t.modelMaterials.get(a.ID ?? NaN), u = (f) => l ? t == null ? void 0 : t.materials.get(l[f]) : void 0, w = (f, M) => {
|
|
679
|
+
const S = u(M), b = We(f, s, S, n, t, r, c);
|
|
680
|
+
return b instanceof Q && S && t ? Ye(a, b, S, t, (v) => i.add(v), (v) => p.add(v)) : b;
|
|
681
|
+
};
|
|
682
|
+
d.push({ mesh: a, material: Array.isArray(a.material) ? a.material.map(w) : w(a.material, 0) });
|
|
683
|
+
});
|
|
684
|
+
} catch (a) {
|
|
685
|
+
for (const [l, u] of s) l !== u && u.dispose();
|
|
686
|
+
for (const l of r.values()) l.dispose();
|
|
687
|
+
for (const l of i) l.dispose();
|
|
688
|
+
for (const l of p) l.dispose();
|
|
689
|
+
for (const l of c.values()) l.dispose();
|
|
690
|
+
throw a;
|
|
691
|
+
}
|
|
692
|
+
for (const { mesh: a, material: l } of d) a.material = l;
|
|
693
|
+
const y = new Set(d.flatMap((a) => Array.isArray(a.material) ? a.material : [a.material]));
|
|
694
|
+
for (const [a, l] of s)
|
|
695
|
+
a !== l && (a.dispose(), y.has(l) || l.dispose());
|
|
696
|
+
const m = /* @__PURE__ */ new Set();
|
|
697
|
+
for (const a of y) for (const l of Object.values(a)) l instanceof X && m.add(l);
|
|
698
|
+
for (const a of r.values()) m.has(a) || a.dispose();
|
|
699
|
+
for (const a of c.values()) m.has(a) || a.dispose();
|
|
700
|
+
const o = [...y].flatMap((a) => a.userData.fbxConversionReport ? [a.userData.fbxConversionReport] : []);
|
|
701
|
+
return e.userData.fbxConversionReports = o, o;
|
|
702
|
+
}
|
|
703
|
+
function We(e, t, n, s, r, c = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map()) {
|
|
704
|
+
var E, A, I;
|
|
705
|
+
const p = t.get(e);
|
|
706
|
+
if (p) return p;
|
|
707
|
+
if (!(e instanceof k) && !(e instanceof de))
|
|
708
|
+
return t.set(e, e), e;
|
|
709
|
+
const d = e instanceof k ? e : null, y = (h, U) => {
|
|
710
|
+
var O;
|
|
711
|
+
const F = (O = n == null ? void 0 : n.values.get(h)) == null ? void 0 : O[0];
|
|
712
|
+
return typeof F == "number" && Number.isFinite(F) ? F : U;
|
|
713
|
+
}, m = (h, U) => {
|
|
714
|
+
const F = n == null ? void 0 : n.values.get(h);
|
|
715
|
+
return F && F.length >= 3 && F.slice(0, 3).every((O) => typeof O == "number" && Number.isFinite(O)) ? new _().setRGB(F[0], F[1], F[2]) : U.clone();
|
|
716
|
+
}, o = (h) => Math.min(1, Math.max(0, h)), a = o(y("SpecularFactor", 0.25) * 2), l = Math.sqrt(0.08 * a), u = (1 + l) / (1 - l);
|
|
717
|
+
let w = e.opacity;
|
|
718
|
+
if (n && (w = 1 - y("TransparencyFactor", 0), w === 0 || w === 1)) {
|
|
719
|
+
const h = (E = n.ownValues.get("Opacity")) == null ? void 0 : E[0];
|
|
720
|
+
w = typeof h == "number" && Number.isFinite(h) ? h : 1 - m("TransparentColor", new _(0)).r;
|
|
721
|
+
}
|
|
722
|
+
const f = new Q({
|
|
723
|
+
name: e.name,
|
|
724
|
+
// FBX diffuse textures supply the base color (as in Blender's importer),
|
|
725
|
+
// not an additional tint. Multiplying the atlas by DiffuseColor can turn
|
|
726
|
+
// blue atlas regions black when the material's constant color is red.
|
|
727
|
+
color: e.map ? new _(16777215) : m("DiffuseColor", n ? new _(1, 1, 1) : e.color),
|
|
728
|
+
map: e.map,
|
|
729
|
+
emissive: e.emissiveMap ? new _(16777215) : m("EmissiveColor", n ? new _(0) : e.emissive),
|
|
730
|
+
emissiveMap: e.emissiveMap,
|
|
731
|
+
emissiveIntensity: y("EmissiveFactor", n ? 1 : e.emissiveIntensity),
|
|
732
|
+
normalMap: e.normalMap,
|
|
733
|
+
normalMapType: e.normalMapType,
|
|
734
|
+
normalScale: e.normalScale.clone().setScalar(y("BumpFactor", 1)),
|
|
735
|
+
bumpMap: e.bumpMap,
|
|
736
|
+
bumpScale: e.bumpScale,
|
|
737
|
+
displacementMap: e.displacementMap,
|
|
738
|
+
displacementScale: e.displacementScale,
|
|
739
|
+
displacementBias: e.displacementBias,
|
|
740
|
+
aoMap: e.aoMap,
|
|
741
|
+
aoMapIntensity: e.aoMapIntensity,
|
|
742
|
+
alphaMap: e.alphaMap,
|
|
743
|
+
opacity: o(w),
|
|
744
|
+
transparent: e.transparent || w < 1,
|
|
745
|
+
alphaTest: e.alphaTest,
|
|
746
|
+
side: e.side,
|
|
747
|
+
depthTest: e.depthTest,
|
|
748
|
+
depthWrite: e.depthWrite,
|
|
749
|
+
vertexColors: e.vertexColors,
|
|
750
|
+
wireframe: e.wireframe,
|
|
751
|
+
flatShading: e.flatShading,
|
|
752
|
+
metalness: o(y("ReflectionFactor", 0)),
|
|
753
|
+
ior: u,
|
|
754
|
+
specularIntensity: 1,
|
|
755
|
+
// Match Blender's empirical FBX Shininess -> Principled roughness mapping.
|
|
756
|
+
// This is an importer convention, not an exact BRDF conversion.
|
|
757
|
+
roughness: n || d ? o(1 - Math.sqrt(Math.max(0, y("Shininess", n ? 20 : d.shininess))) / 10) : 1
|
|
758
|
+
});
|
|
759
|
+
t.set(e, f);
|
|
760
|
+
const M = (h) => {
|
|
761
|
+
let U = c.get(h);
|
|
762
|
+
return U || (U = ze(h, "identity"), c.set(h, U)), U;
|
|
763
|
+
}, S = n && r ? Ge(n, r) : [], b = [];
|
|
764
|
+
for (const h of S)
|
|
765
|
+
if (!(!["DiffuseColor", "EmissiveColor"].includes(h.role) || !r || !s) && n.textureConnections.filter((U) => U.role === h.role).length === 1)
|
|
766
|
+
try {
|
|
767
|
+
let U = i.get(h.id);
|
|
768
|
+
U || (U = Ve(h, r, s), i.set(h.id, U)), h.role === "DiffuseColor" ? (f.map = U, f.color.setRGB(1, 1, 1)) : (f.emissiveMap = U, f.emissive.setRGB(1, 1, 1)), h.issues = [], b.push(h.id);
|
|
769
|
+
} catch (U) {
|
|
770
|
+
h.issues.push({ status: "unsupported", code: "LAYERED_TEXTURE_BAKE_REJECTED", source: `layered:${h.id}:${U instanceof Error ? U.message : String(U)}`, target: h.role });
|
|
771
|
+
}
|
|
772
|
+
const v = /* @__PURE__ */ new Set(), D = [], R = /* @__PURE__ */ new Set(), T = {
|
|
773
|
+
ReflectionFactor: "metalnessMap",
|
|
774
|
+
ReflectionColor: "metalnessMap",
|
|
775
|
+
ShininessExponent: "roughnessMap",
|
|
776
|
+
SpecularFactor: "specularIntensityMap",
|
|
777
|
+
SpecularColor: "specularIntensityMap",
|
|
778
|
+
TransparentColor: "alphaMap",
|
|
779
|
+
TransparencyFactor: "alphaMap"
|
|
780
|
+
};
|
|
781
|
+
for (const h of (n == null ? void 0 : n.textureConnections) ?? []) {
|
|
782
|
+
if ((A = r == null ? void 0 : r.layeredTextures) != null && A.has(h.id)) continue;
|
|
783
|
+
const U = [...s ?? []].find((O) => O.ID === h.id);
|
|
784
|
+
if (!U) {
|
|
785
|
+
D.push(`texture:${h.id}:unresolved:${h.role}`);
|
|
786
|
+
continue;
|
|
787
|
+
}
|
|
788
|
+
const F = T[h.role];
|
|
789
|
+
if (F && R.has(F)) {
|
|
790
|
+
D.push(`conflicting-input:${h.role}:${F}`);
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
switch (F && R.add(F), h.role) {
|
|
794
|
+
case "ReflectionFactor":
|
|
795
|
+
case "ReflectionColor":
|
|
796
|
+
f.metalnessMap = M(U), f.metalness = 1, v.add(h.role);
|
|
797
|
+
break;
|
|
798
|
+
case "ShininessExponent":
|
|
799
|
+
f.roughnessMap = M(U), f.roughness = 1, v.add(h.role);
|
|
800
|
+
break;
|
|
801
|
+
case "SpecularFactor":
|
|
802
|
+
case "SpecularColor":
|
|
803
|
+
f.specularIntensityMap = M(U), f.ior = (1 + Math.sqrt(0.08)) / (1 - Math.sqrt(0.08)), f.specularIntensity = 1, v.add(h.role);
|
|
804
|
+
break;
|
|
805
|
+
case "TransparentColor":
|
|
806
|
+
case "TransparencyFactor":
|
|
807
|
+
f.alphaMap = M(U), f.opacity = 1, f.transparent = !0, v.add(h.role);
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
f.userData = { ...e.userData, fbxMaterialId: n == null ? void 0 : n.id };
|
|
812
|
+
const g = (n == null ? void 0 : n.textureRoles.filter((h) => ![
|
|
813
|
+
"DiffuseColor",
|
|
814
|
+
"Maya|TEX_color_map",
|
|
815
|
+
"NormalMap",
|
|
816
|
+
"Maya|TEX_normal_map",
|
|
817
|
+
"Bump",
|
|
818
|
+
"EmissiveColor",
|
|
819
|
+
"DisplacementColor",
|
|
820
|
+
"TransparentColor",
|
|
821
|
+
"TransparencyFactor",
|
|
822
|
+
"Maya|TEX_ao_map"
|
|
823
|
+
].includes(h) && !v.has(h))) ?? [];
|
|
824
|
+
g.push(...D);
|
|
825
|
+
for (const h of (n == null ? void 0 : n.textureConnections) ?? [])
|
|
826
|
+
!(r == null ? void 0 : r.textures.get(h.id)) && !((I = r == null ? void 0 : r.layeredTextures) != null && I.has(h.id)) && g.push(`texture:${h.id}:layered-or-unknown`);
|
|
827
|
+
n && !["phong", "lambert"].includes(n.shadingModel) && g.push(`shader:${n.shadingModel}`), g.length && (f.userData.fbxUnsupportedTextureRoles = g, console.warn(`[viewer] FBX material ${e.name}: unsupported texture semantics: ${g.join(", ")}`));
|
|
828
|
+
const x = {
|
|
829
|
+
layerStacks: S,
|
|
830
|
+
strategy: "blender-compatible-v1",
|
|
831
|
+
materialId: n == null ? void 0 : n.id,
|
|
832
|
+
materialName: e.name,
|
|
833
|
+
mappings: [
|
|
834
|
+
{ source: "DiffuseColor", target: "color/map", rule: "texture replaces constant; raw constant RGB otherwise" },
|
|
835
|
+
{ source: "Shininess", target: "roughness", rule: "clamp(1-sqrt(max(0,s))/10); empirical approximation" },
|
|
836
|
+
{ source: "ReflectionFactor", target: "metalness", rule: "clamp(value); importer convention" },
|
|
837
|
+
{ source: "SpecularFactor", target: "ior", rule: "match normal-incidence F0 only" },
|
|
838
|
+
...[...v].map((h) => ({ source: h, target: T[h], rule: "raw R; identity; replaces scalar constant" }))
|
|
839
|
+
],
|
|
840
|
+
issues: [
|
|
841
|
+
...S.flatMap((h) => h.issues),
|
|
842
|
+
...b.map((h) => ({ status: "approximate", code: "LAYERED_TEXTURE_BAKED", source: `layered:${h}:linear-color-v1; opaque base; first connection bottom`, target: "RGBA8 color texture" })),
|
|
843
|
+
{ status: "approximate", code: "PHONG_TO_PBR", source: (n == null ? void 0 : n.shadingModel) ?? e.type, target: "MeshPhysicalMaterial" },
|
|
844
|
+
...g.map((h) => ({ status: "unsupported", code: "UNSUPPORTED_SEMANTICS", source: h }))
|
|
845
|
+
]
|
|
846
|
+
};
|
|
847
|
+
return f.userData.fbxConversionReport = x, f.visible = e.visible, f.toneMapped = e.toneMapped, f.clippingPlanes = e.clippingPlanes, f.clipIntersection = e.clipIntersection, f.clipShadows = e.clipShadows, f.polygonOffset = e.polygonOffset, f.polygonOffsetFactor = e.polygonOffsetFactor, f.polygonOffsetUnits = e.polygonOffsetUnits, f.dithering = e.dithering, f.needsUpdate = !0, t.set(e, f), f;
|
|
848
|
+
}
|
|
849
|
+
const Ke = new Z().setFromAxisAngle(new ee(1, 0, 0), Math.PI / 2), Je = new Z();
|
|
850
|
+
function H(e) {
|
|
851
|
+
return e === "fbx" ? "y" : "z";
|
|
852
|
+
}
|
|
853
|
+
function Qe(e) {
|
|
854
|
+
return e === "y" ? Ke : Je;
|
|
855
|
+
}
|
|
856
|
+
function W(e, t) {
|
|
857
|
+
const n = Qe(t);
|
|
858
|
+
return n.equals(e.quaternion) ? !1 : (e.quaternion.copy(n), e.updateMatrixWorld(!0), !0);
|
|
859
|
+
}
|
|
860
|
+
function it(e, t) {
|
|
861
|
+
let n = !1, s = null, r = null, c = "z", i, p = null, d;
|
|
862
|
+
const y = () => {
|
|
863
|
+
n = !0;
|
|
864
|
+
}, m = (async () => {
|
|
865
|
+
c = t.options.upAxis ?? H(t.format);
|
|
866
|
+
let o = null;
|
|
867
|
+
try {
|
|
868
|
+
if (n || t.signal.aborted) throw V();
|
|
869
|
+
const a = e.url ?? await e.resolve(e.entryPath ?? "");
|
|
870
|
+
if (o = new he(), o.name = "viewer-model-root", t.format === "fbx") {
|
|
871
|
+
const u = await fetch(a, { signal: t.signal });
|
|
872
|
+
if (!u.ok) throw new Error(`FBX request failed: ${u.status} ${u.statusText}`);
|
|
873
|
+
const w = await u.arrayBuffer();
|
|
874
|
+
c = t.options.upAxis ?? Re(w) ?? H(t.format);
|
|
875
|
+
const f = _e(w), M = await Ae(w, e, f);
|
|
876
|
+
d = M.textures, o.add(M.root);
|
|
877
|
+
const b = He(o, f, d).flatMap((v) => v.issues.filter((D) => D.status === "unsupported" || D.code === "TEXTURE_ROTATION_PROFILE" || D.code === "LAYERED_TEXTURE_BAKED").map((D) => `${v.materialName || v.materialId || "material"}: ${D.source}`));
|
|
878
|
+
b.length && (p = {
|
|
879
|
+
code: "W_FBX_MATERIAL_APPROXIMATED",
|
|
880
|
+
stage: "material-conversion",
|
|
881
|
+
message: `FBX 材质存在未支持或按兼容规则近似处理的语义:${[...new Set(b)].join("、")}。当前为近似预览。`
|
|
882
|
+
});
|
|
883
|
+
} else {
|
|
884
|
+
const u = new ge(), w = new ye();
|
|
885
|
+
try {
|
|
886
|
+
t.options.dracoDecoderPath && u.setDecoderPath(t.options.dracoDecoderPath), w.setDRACOLoader(u);
|
|
887
|
+
const f = await w.loadAsync(a), M = f.scenes.filter((S) => S !== f.scene);
|
|
888
|
+
if (o.add(f.scene), n || t.signal.aborted) {
|
|
889
|
+
for (const S of M) o.add(S);
|
|
890
|
+
throw V();
|
|
891
|
+
}
|
|
892
|
+
} finally {
|
|
893
|
+
u.dispose();
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
if (n || t.signal.aborted) throw V();
|
|
897
|
+
W(o, c), Ze(o);
|
|
898
|
+
const l = new we(o, t.options.simulationTheme, void 0, "model");
|
|
899
|
+
s = o, r = l, o = null;
|
|
900
|
+
} finally {
|
|
901
|
+
o && (Y(o, d), d = void 0);
|
|
902
|
+
}
|
|
903
|
+
})();
|
|
904
|
+
return m.catch(() => {
|
|
905
|
+
}), {
|
|
906
|
+
id: `model-${Math.random().toString(36).slice(2)}`,
|
|
907
|
+
opened: m,
|
|
908
|
+
get warning() {
|
|
909
|
+
return p;
|
|
910
|
+
},
|
|
911
|
+
get root() {
|
|
912
|
+
return (r == null ? void 0 : r.root) ?? null;
|
|
913
|
+
},
|
|
914
|
+
getFitBounds() {
|
|
915
|
+
return (r == null ? void 0 : r.getModelBounds()) ?? null;
|
|
916
|
+
},
|
|
917
|
+
beforeRender(o, a, l) {
|
|
918
|
+
return r == null ? void 0 : r.beforeRender(o, a, l);
|
|
919
|
+
},
|
|
920
|
+
capabilities: { canPlay: !1, canPause: !1, canReset: !1, hasPhysics: !1, canReorientUpAxis: !0, canToggleGround: !0 },
|
|
921
|
+
// Session presentation overrides are only consulted for `interactionMode`
|
|
922
|
+
// and `fitPolicy`; the UI group comes from the loader descriptor. Keep the
|
|
923
|
+
// two in sync so the override never reads as a contradictory value.
|
|
924
|
+
presentation: { preferredViewMode: "3d", interactionMode: "object", uiProfile: "model", fitPolicy: "fit-on-ready" },
|
|
925
|
+
getUpAxis() {
|
|
926
|
+
return s ? c : null;
|
|
927
|
+
},
|
|
928
|
+
setTheme(o) {
|
|
929
|
+
r == null || r.setTheme(o);
|
|
930
|
+
},
|
|
931
|
+
setGroundVisible(o) {
|
|
932
|
+
r == null || r.setGroundVisible(o);
|
|
933
|
+
},
|
|
934
|
+
getGroundVisible() {
|
|
935
|
+
return (r == null ? void 0 : r.getGroundVisible()) ?? !0;
|
|
936
|
+
},
|
|
937
|
+
setUpAxis(o) {
|
|
938
|
+
if (n || !s || !r || !W(s, o)) return;
|
|
939
|
+
c = o, r.reseatGround();
|
|
940
|
+
const a = r.getModelBounds();
|
|
941
|
+
t.requestRender(), t.fit(a, { padding: 1.15 });
|
|
942
|
+
},
|
|
943
|
+
beginDispose: y,
|
|
944
|
+
dispose() {
|
|
945
|
+
return y(), i ?? (i = m.catch(() => {
|
|
946
|
+
}).then(() => {
|
|
947
|
+
r == null || r.dispose(), r = null, s && Y(s, d), s = null, d = void 0;
|
|
948
|
+
})), i;
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
function Ze(e) {
|
|
953
|
+
e.updateMatrixWorld(!0);
|
|
954
|
+
const t = new me().setFromObject(e);
|
|
955
|
+
if (t.isEmpty()) throw new Error("模型不包含可显示的几何内容。");
|
|
956
|
+
const n = t.getSize(new ee()), s = Math.max(n.x, n.y, n.z);
|
|
957
|
+
if (!Number.isFinite(s) || s <= 0) throw new Error("模型尺寸无效。");
|
|
958
|
+
}
|
|
959
|
+
function V() {
|
|
960
|
+
return Object.assign(new Error("Model load aborted."), { name: "AbortError", code: "E_ABORTED" });
|
|
961
|
+
}
|
|
962
|
+
export {
|
|
963
|
+
it as createModelSession
|
|
964
|
+
};
|