u-space 0.0.31 → 0.0.33
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/dist/index.cjs +3 -3
- package/dist/index.js +1174 -938
- package/dist/modelDecodeProtocol-CC2tkS8h.js +405 -0
- package/dist/modelDecodeProtocol-pgjndTph.cjs +1 -0
- package/dist/plugins/u-manager/index.cjs +1 -1
- package/dist/plugins/u-manager/index.js +73 -53
- package/dist/src/loaders/ModelLoaderManager.d.ts +13 -1
- package/dist/src/loaders/modelPersistentCache.d.ts +35 -0
- package/dist/src/objects/Model.d.ts +4 -0
- package/dist/src/worker/decodeGltfModel.d.ts +7 -1
- package/dist/src/worker/modelDecodeProtocol.d.ts +2 -0
- package/dist/worker/model-decoder.cjs +1 -1
- package/dist/worker/model-decoder.js +231 -205
- package/docs/api-effects.md +66 -2
- package/docs/api-objects.md +11 -2
- package/docs/changelog.md +18 -0
- package/docs/examples-guide.md +24 -10
- package/docs/getting-started.md +97 -93
- package/docs/index.md +1 -1
- package/docs/mcp.md +13 -2
- package/package.json +1 -1
- package/dist/modelDecodeProtocol-D1Apm9iG.cjs +0 -1
- package/dist/modelDecodeProtocol-wDB7ksYw.js +0 -56
|
@@ -1,95 +1,87 @@
|
|
|
1
1
|
import { g as F } from "../getTransferables-DrzSmiCR.js";
|
|
2
|
-
import { c as
|
|
3
|
-
import {
|
|
4
|
-
const
|
|
2
|
+
import { c as U } from "../workerImageUtils-mQD3TQ1N.js";
|
|
3
|
+
import { l as E, U as v, d as S, M as C, v as B } from "../modelDecodeProtocol-CC2tkS8h.js";
|
|
4
|
+
const R = "SBMG----", V = 1179937895, D = 1313821514, G = 5130562, k = new TextDecoder();
|
|
5
5
|
function g(e) {
|
|
6
|
-
throw new
|
|
6
|
+
throw new v(e);
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
let l = !
|
|
11
|
-
if (
|
|
8
|
+
function O(e, t, n, s = e, a = !1) {
|
|
9
|
+
const i = e.startsWith("data:") || e.startsWith("blob:");
|
|
10
|
+
let l = !a;
|
|
11
|
+
if (a && !i)
|
|
12
12
|
try {
|
|
13
|
-
const
|
|
14
|
-
l = (
|
|
13
|
+
const d = new URL(e), f = new URL(s);
|
|
14
|
+
l = (d.protocol === "http:" || d.protocol === "https:") && d.origin === f.origin;
|
|
15
15
|
} catch {
|
|
16
16
|
l = !1;
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
signal:
|
|
18
|
+
return i ? { signal: n, persistent: !1 } : {
|
|
19
|
+
signal: n,
|
|
20
|
+
persistent: t.persistent,
|
|
21
|
+
cacheMode: t.cacheMode,
|
|
22
|
+
cacheKey: t.cacheKey,
|
|
20
23
|
headers: l ? t.headers : void 0,
|
|
21
24
|
credentials: l ? t.credentials : "omit"
|
|
22
|
-
}
|
|
23
|
-
if (!h.ok)
|
|
24
|
-
throw new Error(`Failed to load model resource ${e}: ${h.status} ${h.statusText}`);
|
|
25
|
-
return h;
|
|
25
|
+
};
|
|
26
26
|
}
|
|
27
|
-
async function T(e, t, s,
|
|
28
|
-
const
|
|
27
|
+
async function T(e, t, n, s, a, i, l, d) {
|
|
28
|
+
const f = N(e, t), u = i ? await i.resolve(f, a) : { url: f, complete() {
|
|
29
29
|
} };
|
|
30
30
|
try {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
} catch (n) {
|
|
45
|
-
if (s.aborted) throw n;
|
|
46
|
-
console.warn(`[ModelDecodeWorker] Failed to read Cache Storage for ${e}:`, n);
|
|
47
|
-
}
|
|
48
|
-
const i = await k(e, t, s);
|
|
49
|
-
if (o)
|
|
50
|
-
try {
|
|
51
|
-
await o.put(e, i.clone());
|
|
52
|
-
} catch (n) {
|
|
53
|
-
if (s.aborted) throw n;
|
|
54
|
-
console.warn(`[ModelDecodeWorker] Failed to write Cache Storage for ${e}:`, n);
|
|
31
|
+
const r = O(
|
|
32
|
+
u.url,
|
|
33
|
+
s,
|
|
34
|
+
a,
|
|
35
|
+
n,
|
|
36
|
+
!0
|
|
37
|
+
), o = await E(u.url, r);
|
|
38
|
+
o.fromCache && l.push({
|
|
39
|
+
url: u.url,
|
|
40
|
+
options: {
|
|
41
|
+
headers: r.headers,
|
|
42
|
+
credentials: r.credentials,
|
|
43
|
+
cacheKey: r.cacheKey
|
|
55
44
|
}
|
|
56
|
-
|
|
45
|
+
});
|
|
46
|
+
const c = await d(o);
|
|
47
|
+
return u.complete(), c;
|
|
48
|
+
} catch (r) {
|
|
49
|
+
throw u.complete(r), r;
|
|
57
50
|
}
|
|
58
|
-
return (await k(e, t, s)).arrayBuffer();
|
|
59
51
|
}
|
|
60
|
-
function
|
|
61
|
-
if (e.byteLength < 8 ||
|
|
62
|
-
const
|
|
63
|
-
for (let
|
|
64
|
-
const
|
|
65
|
-
|
|
52
|
+
function $(e) {
|
|
53
|
+
if (e.byteLength < 8 || k.decode(new Uint8Array(e, 0, 8)) !== R) return e;
|
|
54
|
+
const n = new Uint8Array(e.byteLength - 8), s = new Uint8Array(e, 8);
|
|
55
|
+
for (let a = 0; a < s.length; a++) {
|
|
56
|
+
const i = s[a];
|
|
57
|
+
n[a] = i >> 4 & 15 | i << 4 & 240;
|
|
66
58
|
}
|
|
67
|
-
return
|
|
59
|
+
return n.buffer;
|
|
68
60
|
}
|
|
69
|
-
function
|
|
61
|
+
function I(e) {
|
|
70
62
|
const t = new DataView(e);
|
|
71
|
-
if (e.byteLength >= 12 && t.getUint32(0, !0) ===
|
|
72
|
-
const
|
|
73
|
-
if (
|
|
74
|
-
throw new Error(`Invalid GLB length: expected ${
|
|
75
|
-
let
|
|
76
|
-
const
|
|
77
|
-
for (;
|
|
78
|
-
const l = t.getUint32(
|
|
79
|
-
if (
|
|
80
|
-
const f = e.slice(
|
|
81
|
-
|
|
63
|
+
if (e.byteLength >= 12 && t.getUint32(0, !0) === V) {
|
|
64
|
+
const n = t.getUint32(8, !0);
|
|
65
|
+
if (n > e.byteLength)
|
|
66
|
+
throw new Error(`Invalid GLB length: expected ${n}, received ${e.byteLength}.`);
|
|
67
|
+
let s = 12, a;
|
|
68
|
+
const i = [];
|
|
69
|
+
for (; s + 8 <= n; ) {
|
|
70
|
+
const l = t.getUint32(s, !0), d = t.getUint32(s + 4, !0);
|
|
71
|
+
if (s += 8, s + l > n) throw new Error("Invalid GLB chunk length.");
|
|
72
|
+
const f = e.slice(s, s + l);
|
|
73
|
+
d === D ? a = JSON.parse(k.decode(f).replace(/\u0000+$/u, "")) : d === G && i.push(f), s += l;
|
|
82
74
|
}
|
|
83
|
-
if (!
|
|
84
|
-
return { document:
|
|
75
|
+
if (!a) throw new Error("GLB does not contain a JSON chunk.");
|
|
76
|
+
return { document: a, binaryChunks: i };
|
|
85
77
|
}
|
|
86
78
|
return {
|
|
87
|
-
document: JSON.parse(
|
|
79
|
+
document: JSON.parse(k.decode(e).replace(/^\uFEFF/u, "")),
|
|
88
80
|
binaryChunks: []
|
|
89
81
|
};
|
|
90
82
|
}
|
|
91
|
-
function
|
|
92
|
-
e.asset?.version?.startsWith("2") || g("Only glTF 2.x static models are supported by the decode worker."), (e.extensionsRequired?.length || e.extensionsUsed?.length) && g("glTF extensions are not supported by the decode worker."), e.animations?.length && g("Animated glTF models must use the regular loader."), e.skins?.length && g("Skinned glTF models must use the regular loader."), e.cameras?.length && g("glTF cameras must use the regular loader."),
|
|
83
|
+
function K(e) {
|
|
84
|
+
e.asset?.version?.startsWith("2") || g("Only glTF 2.x static models are supported by the decode worker."), (e.extensionsRequired?.length || e.extensionsUsed?.length) && g("glTF extensions are not supported by the decode worker."), e.animations?.length && g("Animated glTF models must use the regular loader."), e.skins?.length && g("Skinned glTF models must use the regular loader."), e.cameras?.length && g("glTF cameras must use the regular loader."), B(e);
|
|
93
85
|
for (const t of e.accessors ?? [])
|
|
94
86
|
t.sparse && g("Sparse glTF accessors must use the regular loader."), t.bufferView === void 0 && g("Accessors without a bufferView must use the regular loader."), ["SCALAR", "VEC2", "VEC3", "VEC4"].includes(t.type) || g(`Accessor type ${t.type} must use the regular loader.`), [5120, 5121, 5122, 5123, 5125, 5126].includes(t.componentType) || g(`Accessor component type ${t.componentType} must use the regular loader.`);
|
|
95
87
|
for (const t of e.bufferViews ?? [])
|
|
@@ -97,8 +89,8 @@ function I(e) {
|
|
|
97
89
|
for (const t of e.nodes ?? [])
|
|
98
90
|
(t.skin !== void 0 || t.weights?.length || t.camera !== void 0) && g("Skinned, morphed, or camera glTF nodes must use the regular loader."), t.extensions && Object.keys(t.extensions).length > 0 && g("Extended glTF nodes must use the regular loader.");
|
|
99
91
|
for (const t of e.meshes ?? [])
|
|
100
|
-
for (const
|
|
101
|
-
(
|
|
92
|
+
for (const n of t.primitives)
|
|
93
|
+
(n.mode ?? 4) !== 4 && g("Only triangle glTF primitives are supported."), n.targets?.length && g("Morph targets must use the regular loader."), n.extensions && Object.keys(n.extensions).length > 0 && g("Extended glTF primitives must use the regular loader.");
|
|
102
94
|
for (const t of e.materials ?? [])
|
|
103
95
|
t.extensions && Object.keys(t.extensions).length > 0 && g("Extended glTF materials must use the regular loader.");
|
|
104
96
|
for (const t of e.textures ?? [])
|
|
@@ -107,233 +99,267 @@ function I(e) {
|
|
|
107
99
|
function N(e, t) {
|
|
108
100
|
return e.startsWith("data:") || e.startsWith("blob:") ? e : new URL(e, t).href;
|
|
109
101
|
}
|
|
110
|
-
async function _(e, t, s,
|
|
111
|
-
const
|
|
112
|
-
for (const
|
|
113
|
-
let
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
102
|
+
async function _(e, t, n, s, a, i, l, d = []) {
|
|
103
|
+
const f = [...t], u = [];
|
|
104
|
+
for (const r of e.buffers ?? []) {
|
|
105
|
+
let o;
|
|
106
|
+
if (r.uri)
|
|
107
|
+
o = await T(
|
|
108
|
+
r.uri,
|
|
109
|
+
n,
|
|
117
110
|
s,
|
|
118
|
-
|
|
111
|
+
a,
|
|
119
112
|
i,
|
|
120
|
-
n,
|
|
121
113
|
l,
|
|
122
|
-
|
|
114
|
+
d,
|
|
115
|
+
(c) => c.buffer
|
|
123
116
|
);
|
|
124
117
|
else {
|
|
125
|
-
const
|
|
126
|
-
if (!
|
|
127
|
-
|
|
118
|
+
const c = f.shift();
|
|
119
|
+
if (!c) throw new Error("glTF buffer is missing its GLB binary chunk.");
|
|
120
|
+
o = c;
|
|
128
121
|
}
|
|
129
|
-
if (
|
|
130
|
-
throw new Error(`glTF buffer is truncated: expected ${
|
|
131
|
-
|
|
122
|
+
if (o.byteLength < r.byteLength)
|
|
123
|
+
throw new Error(`glTF buffer is truncated: expected ${r.byteLength}, received ${o.byteLength}.`);
|
|
124
|
+
u.push(o), Reflect.deleteProperty(r, "uri");
|
|
132
125
|
}
|
|
133
|
-
return
|
|
126
|
+
return u;
|
|
134
127
|
}
|
|
135
|
-
function
|
|
136
|
-
const
|
|
137
|
-
if (!
|
|
138
|
-
const
|
|
139
|
-
if (!
|
|
140
|
-
const l =
|
|
141
|
-
return new Blob([new Uint8Array(
|
|
142
|
-
type:
|
|
128
|
+
function j(e, t, n, s) {
|
|
129
|
+
const a = e.bufferViews?.[n];
|
|
130
|
+
if (!a) throw new Error(`glTF image references missing bufferView ${n}.`);
|
|
131
|
+
const i = t[a.buffer];
|
|
132
|
+
if (!i) throw new Error(`glTF image references missing buffer ${a.buffer}.`);
|
|
133
|
+
const l = a.byteOffset ?? 0;
|
|
134
|
+
return new Blob([new Uint8Array(i, l, a.byteLength)], {
|
|
135
|
+
type: s ?? "application/octet-stream"
|
|
143
136
|
});
|
|
144
137
|
}
|
|
145
|
-
async function
|
|
146
|
-
const
|
|
138
|
+
async function P(e, t, n, s, a, i, l, d = []) {
|
|
139
|
+
const f = [], u = [];
|
|
147
140
|
try {
|
|
148
|
-
for (const
|
|
149
|
-
let
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
141
|
+
for (const r of e.images ?? []) {
|
|
142
|
+
let o;
|
|
143
|
+
if (r.uri)
|
|
144
|
+
o = await T(
|
|
145
|
+
r.uri,
|
|
146
|
+
n,
|
|
153
147
|
s,
|
|
154
|
-
|
|
148
|
+
a,
|
|
155
149
|
i,
|
|
156
|
-
n,
|
|
157
150
|
l,
|
|
158
|
-
|
|
151
|
+
d,
|
|
152
|
+
(p) => new Blob([p.buffer], {
|
|
153
|
+
type: p.headers.get("content-type") ?? "application/octet-stream"
|
|
154
|
+
})
|
|
159
155
|
);
|
|
160
|
-
else if (
|
|
161
|
-
|
|
156
|
+
else if (r.bufferView !== void 0)
|
|
157
|
+
o = j(e, t, r.bufferView, r.mimeType);
|
|
162
158
|
else
|
|
163
159
|
throw new Error("glTF image is missing both uri and bufferView.");
|
|
164
|
-
if (
|
|
165
|
-
const
|
|
166
|
-
if (
|
|
167
|
-
const
|
|
168
|
-
|
|
160
|
+
if (i.aborted) throw i.reason ?? new DOMException("Aborted", "AbortError");
|
|
161
|
+
const c = await globalThis.crypto.subtle.digest("SHA-256", await o.arrayBuffer());
|
|
162
|
+
if (i.aborted) throw i.reason ?? new DOMException("Aborted", "AbortError");
|
|
163
|
+
const h = Array.from(new Uint8Array(c), (p) => p.toString(16).padStart(2, "0")).join("");
|
|
164
|
+
u.push(`${o.type}:${o.size}:${h}`), f.push(await U(o, { imageOrientation: "flipY" })), Reflect.deleteProperty(r, "uri");
|
|
169
165
|
}
|
|
170
|
-
return { images:
|
|
171
|
-
} catch (
|
|
172
|
-
throw
|
|
166
|
+
return { images: f, imageKeys: u };
|
|
167
|
+
} catch (r) {
|
|
168
|
+
throw f.forEach((o) => o.close()), r;
|
|
173
169
|
}
|
|
174
170
|
}
|
|
175
|
-
async function
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
h,
|
|
171
|
+
async function A(e, t, n = {}, s = new AbortController().signal, a, i = []) {
|
|
172
|
+
const l = $(t), { document: d, binaryChunks: f } = I(l);
|
|
173
|
+
K(d);
|
|
174
|
+
const u = n.resourceBaseUrl ?? e, r = await _(
|
|
175
|
+
d,
|
|
181
176
|
f,
|
|
177
|
+
u,
|
|
182
178
|
e,
|
|
179
|
+
n,
|
|
183
180
|
s,
|
|
184
|
-
|
|
181
|
+
a,
|
|
185
182
|
i
|
|
186
|
-
), { images:
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
183
|
+
), { images: o, imageKeys: c } = await P(
|
|
184
|
+
d,
|
|
185
|
+
r,
|
|
186
|
+
u,
|
|
190
187
|
e,
|
|
188
|
+
n,
|
|
191
189
|
s,
|
|
192
|
-
|
|
190
|
+
a,
|
|
193
191
|
i
|
|
194
192
|
);
|
|
195
193
|
return {
|
|
196
|
-
protocolVersion:
|
|
194
|
+
protocolVersion: C,
|
|
197
195
|
kind: "gltf-static",
|
|
198
196
|
url: e,
|
|
199
|
-
document:
|
|
200
|
-
buffers:
|
|
201
|
-
images:
|
|
202
|
-
imageKeys:
|
|
197
|
+
document: d,
|
|
198
|
+
buffers: r,
|
|
199
|
+
images: o,
|
|
200
|
+
imageKeys: c
|
|
203
201
|
};
|
|
204
202
|
}
|
|
205
|
-
async function q(e, t = {},
|
|
206
|
-
const
|
|
207
|
-
|
|
203
|
+
async function q(e, t = {}, n = new AbortController().signal, s) {
|
|
204
|
+
const a = O(e, t, n), i = [], l = await E(e, a);
|
|
205
|
+
l.fromCache && i.push({
|
|
206
|
+
url: e,
|
|
207
|
+
options: {
|
|
208
|
+
headers: a.headers,
|
|
209
|
+
credentials: a.credentials,
|
|
210
|
+
cacheKey: a.cacheKey
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
try {
|
|
214
|
+
return await A(
|
|
215
|
+
e,
|
|
216
|
+
l.buffer,
|
|
217
|
+
t,
|
|
218
|
+
n,
|
|
219
|
+
s,
|
|
220
|
+
i
|
|
221
|
+
);
|
|
222
|
+
} catch (d) {
|
|
223
|
+
if (n.aborted || d instanceof v || i.length === 0) throw d;
|
|
224
|
+
await Promise.all(i.map((u) => S(u.url, u.options)));
|
|
225
|
+
const f = await E(e, a);
|
|
226
|
+
return A(
|
|
227
|
+
e,
|
|
228
|
+
f.buffer,
|
|
229
|
+
t,
|
|
230
|
+
n,
|
|
231
|
+
s
|
|
232
|
+
);
|
|
233
|
+
}
|
|
208
234
|
}
|
|
209
|
-
function
|
|
235
|
+
function M(e) {
|
|
210
236
|
return e instanceof Error ? { message: e.message, name: e.name, stack: e.stack } : { message: String(e) };
|
|
211
237
|
}
|
|
212
238
|
function z(e = globalThis) {
|
|
213
|
-
const t = [],
|
|
214
|
-
let
|
|
215
|
-
const l = (r) => new Promise((
|
|
216
|
-
r.acknowledge =
|
|
217
|
-
}),
|
|
218
|
-
for (const
|
|
219
|
-
|
|
239
|
+
const t = [], n = /* @__PURE__ */ new Set();
|
|
240
|
+
let s = null, a = !1, i = !1;
|
|
241
|
+
const l = (r) => new Promise((o) => {
|
|
242
|
+
r.acknowledge = o;
|
|
243
|
+
}), d = (r, o) => {
|
|
244
|
+
for (const c of r.resources.values())
|
|
245
|
+
c.cleanup(), c.reject(o);
|
|
220
246
|
r.resources.clear();
|
|
221
247
|
}, f = (r) => ({
|
|
222
|
-
async resolve(
|
|
223
|
-
if (
|
|
224
|
-
const
|
|
225
|
-
const
|
|
226
|
-
r.resources.delete(
|
|
227
|
-
}, y = () =>
|
|
228
|
-
r.resources.set(
|
|
248
|
+
async resolve(o, c) {
|
|
249
|
+
if (c.aborted) throw c.reason ?? new DOMException("Aborted", "AbortError");
|
|
250
|
+
const h = r.nextResourceId++, p = await new Promise((m, b) => {
|
|
251
|
+
const L = () => {
|
|
252
|
+
r.resources.delete(h), b(c.reason ?? new DOMException("Aborted", "AbortError"));
|
|
253
|
+
}, y = () => c.removeEventListener("abort", L);
|
|
254
|
+
r.resources.set(h, {
|
|
229
255
|
resolve(w) {
|
|
230
|
-
y(), r.resources.delete(
|
|
256
|
+
y(), r.resources.delete(h), m(w);
|
|
231
257
|
},
|
|
232
258
|
reject(w) {
|
|
233
|
-
y(), r.resources.delete(
|
|
259
|
+
y(), r.resources.delete(h), b(w);
|
|
234
260
|
},
|
|
235
261
|
cleanup: y
|
|
236
|
-
}),
|
|
262
|
+
}), c.addEventListener("abort", L, { once: !0 });
|
|
237
263
|
try {
|
|
238
|
-
e.postMessage({ type: "resolve-resource", id: r.id, resourceId:
|
|
264
|
+
e.postMessage({ type: "resolve-resource", id: r.id, resourceId: h, url: o });
|
|
239
265
|
} catch (w) {
|
|
240
|
-
y(), r.resources.delete(
|
|
266
|
+
y(), r.resources.delete(h), b(w instanceof Error ? w : new Error(String(w)));
|
|
241
267
|
}
|
|
242
268
|
});
|
|
243
|
-
let
|
|
269
|
+
let x = !1;
|
|
244
270
|
return {
|
|
245
|
-
url:
|
|
246
|
-
complete(
|
|
247
|
-
|
|
271
|
+
url: p,
|
|
272
|
+
complete(m) {
|
|
273
|
+
x || (x = !0, e.postMessage({
|
|
248
274
|
type: "resource-complete",
|
|
249
275
|
id: r.id,
|
|
250
|
-
resourceId:
|
|
251
|
-
ok:
|
|
252
|
-
error:
|
|
276
|
+
resourceId: h,
|
|
277
|
+
ok: m === void 0,
|
|
278
|
+
error: m === void 0 ? void 0 : M(m)
|
|
253
279
|
}));
|
|
254
280
|
}
|
|
255
281
|
};
|
|
256
282
|
}
|
|
257
|
-
}),
|
|
258
|
-
if (!(
|
|
259
|
-
|
|
283
|
+
}), u = async () => {
|
|
284
|
+
if (!(a || i)) {
|
|
285
|
+
a = !0;
|
|
260
286
|
try {
|
|
261
|
-
for (; !
|
|
287
|
+
for (; !i && t.length > 0; ) {
|
|
262
288
|
const r = t.shift();
|
|
263
|
-
if (
|
|
264
|
-
const
|
|
289
|
+
if (n.delete(r.id)) continue;
|
|
290
|
+
const o = {
|
|
265
291
|
id: r.id,
|
|
266
292
|
controller: new AbortController(),
|
|
267
293
|
nextResourceId: 1,
|
|
268
294
|
resources: /* @__PURE__ */ new Map()
|
|
269
295
|
};
|
|
270
|
-
|
|
296
|
+
s = o;
|
|
271
297
|
try {
|
|
272
|
-
const
|
|
298
|
+
const c = await q(
|
|
273
299
|
r.url,
|
|
274
300
|
r.options,
|
|
275
|
-
|
|
276
|
-
f(
|
|
301
|
+
o.controller.signal,
|
|
302
|
+
f(o)
|
|
277
303
|
);
|
|
278
|
-
if (
|
|
279
|
-
|
|
304
|
+
if (n.delete(r.id) || i) {
|
|
305
|
+
c.images.forEach((h) => h.close());
|
|
280
306
|
continue;
|
|
281
307
|
}
|
|
282
308
|
try {
|
|
283
309
|
e.postMessage(
|
|
284
|
-
{ type: "decoded", id: r.id, packet:
|
|
285
|
-
F(
|
|
310
|
+
{ type: "decoded", id: r.id, packet: c },
|
|
311
|
+
F(c)
|
|
286
312
|
);
|
|
287
|
-
} catch (
|
|
288
|
-
throw
|
|
313
|
+
} catch (h) {
|
|
314
|
+
throw c.images.forEach((p) => p.close()), h;
|
|
289
315
|
}
|
|
290
|
-
await l(
|
|
291
|
-
} catch (
|
|
292
|
-
const
|
|
293
|
-
if (
|
|
294
|
-
|
|
316
|
+
await l(o);
|
|
317
|
+
} catch (c) {
|
|
318
|
+
const h = n.delete(r.id);
|
|
319
|
+
if (o.controller.signal.aborted || h || i) continue;
|
|
320
|
+
c instanceof v ? e.postMessage({ type: "unsupported", id: r.id, reason: c.message }) : e.postMessage({ type: "error", id: r.id, error: M(c) });
|
|
295
321
|
} finally {
|
|
296
|
-
|
|
322
|
+
d(o, new DOMException("Model decode request ended.", "AbortError")), n.delete(r.id), s === o && (s = null);
|
|
297
323
|
}
|
|
298
324
|
}
|
|
299
325
|
} finally {
|
|
300
|
-
|
|
326
|
+
a = !1, !i && t.length > 0 && u();
|
|
301
327
|
}
|
|
302
328
|
}
|
|
303
329
|
};
|
|
304
330
|
e.addEventListener("message", (r) => {
|
|
305
|
-
const
|
|
306
|
-
if (
|
|
307
|
-
if (
|
|
308
|
-
t.push(
|
|
331
|
+
const o = r.data;
|
|
332
|
+
if (o.type === "decode") {
|
|
333
|
+
if (i) return;
|
|
334
|
+
t.push(o), u();
|
|
309
335
|
return;
|
|
310
336
|
}
|
|
311
|
-
if (
|
|
312
|
-
|
|
337
|
+
if (o.type === "cancel") {
|
|
338
|
+
n.add(o.id), s?.id === o.id && (s.controller.abort(), s.acknowledge?.());
|
|
313
339
|
return;
|
|
314
340
|
}
|
|
315
|
-
if (
|
|
316
|
-
|
|
341
|
+
if (o.type === "ack") {
|
|
342
|
+
s?.id === o.id && s.acknowledge?.();
|
|
317
343
|
return;
|
|
318
344
|
}
|
|
319
|
-
if (
|
|
320
|
-
if (
|
|
321
|
-
const
|
|
322
|
-
if (!
|
|
323
|
-
if (
|
|
324
|
-
|
|
345
|
+
if (o.type === "resource-resolved") {
|
|
346
|
+
if (s?.id !== o.id) return;
|
|
347
|
+
const c = s.resources.get(o.resourceId);
|
|
348
|
+
if (!c) return;
|
|
349
|
+
if (o.url !== void 0)
|
|
350
|
+
c.resolve(o.url);
|
|
325
351
|
else {
|
|
326
|
-
const
|
|
327
|
-
|
|
352
|
+
const h = new Error(o.error?.message ?? "Failed to resolve model resource URL.");
|
|
353
|
+
h.name = o.error?.name ?? "Error", h.stack = o.error?.stack, c.reject(h);
|
|
328
354
|
}
|
|
329
355
|
return;
|
|
330
356
|
}
|
|
331
|
-
|
|
357
|
+
o.type === "dispose" && (i = !0, t.length = 0, s?.controller.abort(), s?.acknowledge?.(), e.postMessage({ type: "disposed" }), e.close());
|
|
332
358
|
});
|
|
333
359
|
}
|
|
334
360
|
export {
|
|
335
|
-
|
|
336
|
-
|
|
361
|
+
C as MODEL_DECODE_PROTOCOL_VERSION,
|
|
362
|
+
v as UnsupportedModelDecodeError,
|
|
337
363
|
z as installModelDecodeWorker,
|
|
338
|
-
|
|
364
|
+
B as validateDecodedGltfNodeGraph
|
|
339
365
|
};
|
package/docs/api-effects.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Effects API
|
|
2
2
|
|
|
3
|
-
`u-space` 提供了两个基于 Three.js 着色语言(TSL/WebGPU 节点)的静态特效工具:`MaterialEffects` 用于为对象应用高亮、呼吸等材质特效,`TSLEffects`
|
|
3
|
+
`u-space` 提供了两个基于 Three.js 着色语言(TSL/WebGPU 节点)的静态特效工具:`MaterialEffects` 用于为对象应用高亮、呼吸等材质特效,`TSLEffects` 用于生成动态颜色节点模式和可组合的 Outline 输出效果。
|
|
4
4
|
|
|
5
5
|
## `MaterialEffects`
|
|
6
6
|
|
|
@@ -123,7 +123,71 @@ await MaterialEffects.fadeIn(myModel, { duration: 500 });
|
|
|
123
123
|
|
|
124
124
|
## `TSLEffects`
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
静态工厂类。`flow()`、`breathe()` 和 `fluid()` 返回可赋给 `NodeMaterial.colorNode` 的 TSL 颜色节点;`outline()` 返回接入 `RenderPipeline` 的输出效果。持续动画需要 `viewer.frameloop = 'always'`。
|
|
127
|
+
|
|
128
|
+
### `TSLEffects.outline(options?)`
|
|
129
|
+
|
|
130
|
+
创建基于 Three.js `OutlineNode` 的屏幕空间描边效果。它不会修改对象材质,而是通过 `RenderPipeline.addOutputEffect()` 叠加在默认渲染结果上,因此可以与内置 Bloom、SSGI、SSR 以及其他 output effects 组合。
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { TSLEffects } from 'u-space';
|
|
134
|
+
|
|
135
|
+
const outline = TSLEffects.outline({
|
|
136
|
+
selectedObjects: [model],
|
|
137
|
+
edgeStrength: 3,
|
|
138
|
+
edgeThickness: 1.5,
|
|
139
|
+
edgeGlow: 0,
|
|
140
|
+
visibleEdgeColor: 0x00e5ff,
|
|
141
|
+
hiddenEdgeColor: 0xff4d6d,
|
|
142
|
+
downSampleRatio: 2,
|
|
143
|
+
instanceBoundsProxy: true,
|
|
144
|
+
instanceBoundsPadding: 0.05,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
viewer.renderPipeline.addOutputEffect(outline);
|
|
148
|
+
|
|
149
|
+
// 替换当前描边对象,不需要重建后处理链。
|
|
150
|
+
outline.setSelectedObjects([anotherObject]);
|
|
151
|
+
|
|
152
|
+
// 运行时更新样式与 InstanceObject bounds proxy 参数。
|
|
153
|
+
outline.update({ edgeStrength: 4, edgeGlow: 0.25 });
|
|
154
|
+
viewer.render();
|
|
155
|
+
|
|
156
|
+
// 销毁前先从 RenderPipeline 移除。
|
|
157
|
+
viewer.renderPipeline.removeOutputEffect(outline);
|
|
158
|
+
outline.dispose();
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### `TSLOutlineOptions`
|
|
162
|
+
|
|
163
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
164
|
+
| :--- | :--- | :--- | :--- |
|
|
165
|
+
| `selectedObjects` | `readonly Object3D[]` | `[]` | 初始描边对象。普通 Mesh、Group 与核心 `InstanceObject` 均可传入。 |
|
|
166
|
+
| `edgeStrength` | `number` | `3` | 边缘颜色强度。 |
|
|
167
|
+
| `edgeThickness` | `number` | `1` | 边缘厚度。 |
|
|
168
|
+
| `edgeGlow` | `number` | `0` | 描边向外扩散的发光强度。 |
|
|
169
|
+
| `visibleEdgeColor` | `ColorRepresentation` | `0xffffff` | 可见边缘颜色。 |
|
|
170
|
+
| `hiddenEdgeColor` | `ColorRepresentation` | `0x4e3636` | 被遮挡边缘颜色。 |
|
|
171
|
+
| `downSampleRatio` | `number` | `2` | Outline pass 降采样比例;非有限值或 `<= 0` 时恢复为 `2`。值越大成本越低,但边缘精度也越低。 |
|
|
172
|
+
| `instanceBoundsProxy` | `boolean` | `true` | `InstanceObject` 没有可直接描边的渲染子树时,是否用世界包围盒代理生成轮廓。 |
|
|
173
|
+
| `instanceBoundsPadding` | `number` | `0` | bounds proxy 每个方向额外扩张的世界单位。 |
|
|
174
|
+
| `instanceBoundsMinSize` | `number` | `0.001` | bounds proxy 每个轴向的最小尺寸,避免退化包围盒无法描边。 |
|
|
175
|
+
|
|
176
|
+
#### 返回的 `TSLOutlineEffect`
|
|
177
|
+
|
|
178
|
+
| 成员 | 说明 |
|
|
179
|
+
| :--- | :--- |
|
|
180
|
+
| `selectedObjects` | 当前逻辑选择对象的只读快照。 |
|
|
181
|
+
| `outlineNode` | 当前内部 `OutlineNode`;在 RenderPipeline 首次构建前为 `null`,Scene 或 Camera 变化后可能被替换。 |
|
|
182
|
+
| `setSelectedObjects(objects)` | 替换当前选择并返回自身,便于链式调用。空数组会清除描边。 |
|
|
183
|
+
| `update(options)` | 更新除 `selectedObjects` 外的全部样式和 bounds proxy 选项,并返回自身。 |
|
|
184
|
+
| `dispose()` | 释放内部 OutlineNode、代理 Geometry/Material 和 dirty 订阅。调用前应先 `removeOutputEffect()`。 |
|
|
185
|
+
|
|
186
|
+
对于 `InstanceObject`,效果会优先描边 `getInstanceRenderObject()` 返回的可渲染对象;如果逻辑对象自身包含 Mesh/Sprite,则直接使用该对象;只有两者都不可用时才根据 `getInstanceBoundingBox()` 创建不可见 bounds proxy。代理会监听 `onInstanceRenderDirty()`,在实例显隐、变换或包围盒变化后同步,而且不会参与拾取、颜色输出或阴影。
|
|
187
|
+
|
|
188
|
+
> 如果业务设置了自定义 `viewer.renderPipeline.setOutputComposer()`,RenderPipeline 会按自定义 composer 语义跳过所有 output effects,Outline 也不会显示。更新选择或参数后,`frameloop = 'demand'` 的 Viewer 需要调用 `viewer.render()` 或 `viewer.invalidate()` 请求新帧。
|
|
189
|
+
|
|
190
|
+
[在线示例](https://u-space-phi.vercel.app/examples/test_outline.html)
|
|
127
191
|
|
|
128
192
|
### `TSLEffects.flow(parameters?)`
|
|
129
193
|
|