@voluma/vlam 0.2.1 → 0.2.2
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 +1 -1
- package/dist/formats/lcc.js +320 -292
- package/dist/formats/lcc.js.map +1 -1
- package/dist/formats/rad.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +528 -493
- package/dist/index.js.map +1 -1
- package/dist/lod-source.d.ts +7 -0
- package/dist/{splat-budget-PSojLJPO.js → splat-budget-DXew_86c.js} +64 -57
- package/dist/splat-budget-DXew_86c.js.map +1 -0
- package/dist/splat-budget.d.ts +24 -4
- package/dist/{splat-mesh-types-8QDjTbZO.js → splat-mesh-types-CTN_duw2.js} +2 -2
- package/dist/{splat-mesh-types-8QDjTbZO.js.map → splat-mesh-types-CTN_duw2.js.map} +1 -1
- package/dist/streamed-splat-mesh.d.ts +40 -25
- package/package.json +1 -1
- package/dist/splat-budget-PSojLJPO.js.map +0 -1
package/dist/formats/lcc.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
var dt = Object.defineProperty;
|
|
2
|
-
var
|
|
3
|
-
var A = (e, t, n) =>
|
|
4
|
-
import { w as
|
|
2
|
+
var gt = (e, t, n) => t in e ? dt(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
|
|
3
|
+
var A = (e, t, n) => gt(e, typeof t != "symbol" ? t + "" : t, n);
|
|
4
|
+
import { w as wt } from "../splat-data-BZM5dhhx.js";
|
|
5
5
|
import { a as mt, r as pt } from "../sh-pack-D5wAe5gg.js";
|
|
6
6
|
import * as E from "three/webgpu";
|
|
7
|
-
import { M as Ct, L as yt } from "../splat-mesh-types-
|
|
8
|
-
import { t as ct, a as
|
|
9
|
-
import { w as
|
|
10
|
-
import { p as
|
|
11
|
-
const
|
|
7
|
+
import { M as Ct, L as yt } from "../splat-mesh-types-CTN_duw2.js";
|
|
8
|
+
import { t as ct, a as W } from "../loading-wLo8vRbA.js";
|
|
9
|
+
import { w as z } from "../logging-BfPdd7NJ.js";
|
|
10
|
+
import { p as xt, a as vt, b as bt, c as k, d as j } from "../ply-header-BwgExCn-.js";
|
|
11
|
+
const F = 32, O = 64, K = 1 << 24;
|
|
12
12
|
function Lt(e) {
|
|
13
13
|
return e === 1 ? 3 : e === 2 ? 8 : 15;
|
|
14
14
|
}
|
|
@@ -24,56 +24,56 @@ function Et(e) {
|
|
|
24
24
|
const s = t.totalLevel;
|
|
25
25
|
if (!Number.isSafeInteger(s) || s < 1)
|
|
26
26
|
throw new Error(`LCC manifest declares an invalid totalLevel: ${String(s)}.`);
|
|
27
|
-
const i = s,
|
|
28
|
-
if (
|
|
27
|
+
const i = s, l = t.indexDataSize, c = 4 + i * 16;
|
|
28
|
+
if (l !== c)
|
|
29
29
|
throw new Error(
|
|
30
|
-
`LCC manifest indexDataSize is ${String(
|
|
30
|
+
`LCC manifest indexDataSize is ${String(l)}, but ${i} levels imply ${c}.`
|
|
31
31
|
);
|
|
32
|
-
const
|
|
33
|
-
if (!Array.isArray(
|
|
32
|
+
const a = t.splats;
|
|
33
|
+
if (!Array.isArray(a) || a.length !== i)
|
|
34
34
|
throw new Error(`LCC manifest "splats" must list one count per level (${i}).`);
|
|
35
|
-
for (const
|
|
36
|
-
if (!Number.isSafeInteger(
|
|
37
|
-
throw new Error(`LCC manifest "splats" contains an invalid count: ${String(
|
|
38
|
-
const
|
|
39
|
-
if (!Number.isSafeInteger(
|
|
40
|
-
throw new Error(`LCC manifest declares an invalid totalSplats: ${String(
|
|
41
|
-
const
|
|
42
|
-
if (
|
|
35
|
+
for (const g of a)
|
|
36
|
+
if (!Number.isSafeInteger(g) || g < 0)
|
|
37
|
+
throw new Error(`LCC manifest "splats" contains an invalid count: ${String(g)}.`);
|
|
38
|
+
const r = t.totalSplats;
|
|
39
|
+
if (!Number.isSafeInteger(r) || r < 0)
|
|
40
|
+
throw new Error(`LCC manifest declares an invalid totalSplats: ${String(r)}.`);
|
|
41
|
+
const u = J(t, "cellLengthX"), f = J(t, "cellLengthY");
|
|
42
|
+
if (u <= 0 || f <= 0)
|
|
43
43
|
throw new Error("LCC manifest cell lengths must be positive.");
|
|
44
44
|
const h = St(t), d = t.shift;
|
|
45
|
-
if (Array.isArray(d) && d.some((
|
|
45
|
+
if (Array.isArray(d) && d.some((g) => g !== 0))
|
|
46
46
|
throw new Error(
|
|
47
47
|
`LCC manifest "shift" is non-zero (${JSON.stringify(d)}), which is not supported.`
|
|
48
48
|
);
|
|
49
49
|
const m = t.scale;
|
|
50
|
-
if (Array.isArray(m) && m.some((
|
|
50
|
+
if (Array.isArray(m) && m.some((g) => g !== 1))
|
|
51
51
|
throw new Error(
|
|
52
52
|
`LCC manifest "scale" is non-identity (${JSON.stringify(m)}), which is not supported.`
|
|
53
53
|
);
|
|
54
|
-
const p = t.boundingBox, $ =
|
|
55
|
-
if (!Array.isArray(
|
|
54
|
+
const p = t.boundingBox, $ = P(p == null ? void 0 : p.min, "boundingBox.min"), b = P(p == null ? void 0 : p.max, "boundingBox.max"), w = t.attributes;
|
|
55
|
+
if (!Array.isArray(w)) throw new Error('LCC manifest is missing "attributes".');
|
|
56
56
|
const C = /* @__PURE__ */ new Map();
|
|
57
|
-
for (const
|
|
58
|
-
typeof (
|
|
59
|
-
min:
|
|
60
|
-
max:
|
|
57
|
+
for (const g of w)
|
|
58
|
+
typeof (g == null ? void 0 : g.name) == "string" && (!Array.isArray(g.min) || g.min.length < 3 || C.set(g.name, {
|
|
59
|
+
min: P(g.min, `attributes.${g.name}.min`),
|
|
60
|
+
max: P(g.max, `attributes.${g.name}.max`)
|
|
61
61
|
}));
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
if (!
|
|
65
|
-
return
|
|
62
|
+
const v = (g) => {
|
|
63
|
+
const x = C.get(g);
|
|
64
|
+
if (!x) throw new Error(`LCC manifest is missing the "${g}" attribute range.`);
|
|
65
|
+
return x;
|
|
66
66
|
}, y = C.get("shcoef") ?? Y, L = $t(t.fileType, y);
|
|
67
67
|
return {
|
|
68
|
-
totalSplats:
|
|
68
|
+
totalSplats: r,
|
|
69
69
|
totalLevel: i,
|
|
70
|
-
cellLengthX:
|
|
70
|
+
cellLengthX: u,
|
|
71
71
|
cellLengthY: f,
|
|
72
72
|
indexDataSize: c,
|
|
73
|
-
splats:
|
|
73
|
+
splats: a,
|
|
74
74
|
bounds: { min: $, max: b },
|
|
75
75
|
fileType: L,
|
|
76
|
-
scale:
|
|
76
|
+
scale: v("scale"),
|
|
77
77
|
// A Portable capture has no SH at all; keep a benign range so the type
|
|
78
78
|
// stays total rather than sprinkling optionality through the loader.
|
|
79
79
|
shcoef: y,
|
|
@@ -87,7 +87,7 @@ function St(e) {
|
|
|
87
87
|
if (!Array.isArray(t) || !t.some((o) => o !== 0)) return;
|
|
88
88
|
const n = e.epsg;
|
|
89
89
|
return {
|
|
90
|
-
origin:
|
|
90
|
+
origin: P(t, "offset"),
|
|
91
91
|
epsg: Number.isSafeInteger(n) && n > 0 ? n : void 0
|
|
92
92
|
};
|
|
93
93
|
}
|
|
@@ -109,95 +109,95 @@ function Mt(e, t) {
|
|
|
109
109
|
`LCC index.bin is ${e.byteLength} bytes, not a multiple of indexDataSize ${n}.`
|
|
110
110
|
);
|
|
111
111
|
const s = new DataView(e), i = [];
|
|
112
|
-
for (let
|
|
112
|
+
for (let l = 0; l < e.byteLength; l += n) {
|
|
113
113
|
const c = [];
|
|
114
|
-
for (let
|
|
115
|
-
const
|
|
114
|
+
for (let a = 0; a < o; a++) {
|
|
115
|
+
const r = l + 4 + a * 16, u = s.getUint32(r, !0), f = s.getBigUint64(r + 4, !0);
|
|
116
116
|
if (f > BigInt(Number.MAX_SAFE_INTEGER))
|
|
117
117
|
throw new Error(
|
|
118
118
|
`LCC index.bin has a byte offset beyond Number.MAX_SAFE_INTEGER: ${f}.`
|
|
119
119
|
);
|
|
120
|
-
const h = s.getUint32(
|
|
121
|
-
if (h !==
|
|
120
|
+
const h = s.getUint32(r + 12, !0);
|
|
121
|
+
if (h !== u * F)
|
|
122
122
|
throw new Error(
|
|
123
|
-
`LCC index.bin level ${
|
|
123
|
+
`LCC index.bin level ${a} declares ${u} splats but ${h} bytes (expected ${u * F}).`
|
|
124
124
|
);
|
|
125
|
-
c.push({ count:
|
|
125
|
+
c.push({ count: u, byteOffset: Number(f), byteSize: h });
|
|
126
126
|
}
|
|
127
127
|
i.push({
|
|
128
|
-
cellX: s.getUint16(
|
|
129
|
-
cellY: s.getUint16(
|
|
128
|
+
cellX: s.getUint16(l, !0),
|
|
129
|
+
cellY: s.getUint16(l + 2, !0),
|
|
130
130
|
levels: c
|
|
131
131
|
});
|
|
132
132
|
}
|
|
133
133
|
return i;
|
|
134
134
|
}
|
|
135
|
-
function
|
|
135
|
+
function Ft(e) {
|
|
136
136
|
const t = e >>> 30 & 3, n = [0, 0, 0, 0];
|
|
137
137
|
let o = 0;
|
|
138
138
|
for (let i = 0; i < 4; i++) {
|
|
139
139
|
if (i === t) continue;
|
|
140
|
-
const
|
|
141
|
-
n[i] = (
|
|
140
|
+
const l = e >>> 10 * o & 1023;
|
|
141
|
+
n[i] = (l - 511) * Tt, o++;
|
|
142
142
|
}
|
|
143
143
|
const s = n[0] ** 2 + n[1] ** 2 + n[2] ** 2 + n[3] ** 2;
|
|
144
144
|
return n[t] = Math.sqrt(Math.max(0, 1 - s)), [n[3], n[0], n[1], n[2]];
|
|
145
145
|
}
|
|
146
146
|
const Tt = 1 / (511 * Math.SQRT2);
|
|
147
147
|
async function re(e, t, n, o) {
|
|
148
|
-
var
|
|
148
|
+
var v;
|
|
149
149
|
const s = t.stride;
|
|
150
|
-
if (s !==
|
|
150
|
+
if (s !== F && s !== F + O)
|
|
151
151
|
throw new Error(`LCC chunk declares an unsupported ${s}-byte record.`);
|
|
152
|
-
if (((
|
|
152
|
+
if (((v = t.sh) == null ? void 0 : v.source) === "inline" && s === F)
|
|
153
153
|
throw new Error("LCC chunk asks for inline SH but its records have no room for it.");
|
|
154
154
|
if (e.byteLength % s !== 0)
|
|
155
155
|
throw new Error(
|
|
156
156
|
`LCC chunk is ${e.byteLength} bytes, not a multiple of the ${s}-byte record.`
|
|
157
157
|
);
|
|
158
158
|
const i = e.byteLength / s;
|
|
159
|
-
if (i >
|
|
159
|
+
if (i > K)
|
|
160
160
|
throw new Error(
|
|
161
|
-
`LCC chunk holds ${i} splats, above the supported maximum of ${
|
|
161
|
+
`LCC chunk holds ${i} splats, above the supported maximum of ${K}.`
|
|
162
162
|
);
|
|
163
|
-
const
|
|
163
|
+
const l = new DataView(e), c = new Float32Array(i * 3), a = new Uint8Array(i * 4), r = new Float32Array(i * 6), u = new Uint8Array(e), { min: f, max: h } = t.scale, d = f[0], m = f[1], p = f[2], $ = h[0] - f[0], b = h[1] - f[1], w = h[2] - f[2];
|
|
164
164
|
for (let y = 0; y < i; y++) {
|
|
165
165
|
o && (y & 65535) === 0 && y > 0 && (await new Promise((S) => setTimeout(S, 0)), o.throwIfAborted());
|
|
166
166
|
const L = y * s;
|
|
167
|
-
c[y * 3 + 0] =
|
|
168
|
-
const [
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
c[y * 3 + 0] = l.getFloat32(L, !0), c[y * 3 + 1] = l.getFloat32(L + 4, !0), c[y * 3 + 2] = l.getFloat32(L + 8, !0), a[y * 4 + 0] = u[L + 12], a[y * 4 + 1] = u[L + 13], a[y * 4 + 2] = u[L + 14], a[y * 4 + 3] = u[L + 15];
|
|
168
|
+
const [g, x, U, M] = Ft(l.getUint32(L + 22, !0));
|
|
169
|
+
wt(
|
|
170
|
+
r,
|
|
171
171
|
y,
|
|
172
|
-
d + $ * (
|
|
173
|
-
m + b * (
|
|
174
|
-
p +
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
172
|
+
d + $ * (l.getUint16(L + 16, !0) / 65535),
|
|
173
|
+
m + b * (l.getUint16(L + 18, !0) / 65535),
|
|
174
|
+
p + w * (l.getUint16(L + 20, !0) / 65535),
|
|
175
|
+
g,
|
|
176
|
+
x,
|
|
177
|
+
U,
|
|
178
178
|
M
|
|
179
179
|
);
|
|
180
180
|
}
|
|
181
181
|
o == null || o.throwIfAborted();
|
|
182
|
-
const C = t.sh ?
|
|
182
|
+
const C = t.sh ? Ut(e, n, t.sh, i, s) : void 0;
|
|
183
183
|
return {
|
|
184
184
|
count: i,
|
|
185
185
|
positions: c,
|
|
186
|
-
colors:
|
|
187
|
-
covariances:
|
|
186
|
+
colors: a,
|
|
187
|
+
covariances: r,
|
|
188
188
|
...C ? { shPacked: C } : {}
|
|
189
189
|
};
|
|
190
190
|
}
|
|
191
|
-
function
|
|
192
|
-
const i = Lt(n.bands),
|
|
191
|
+
function Ut(e, t, n, o, s) {
|
|
192
|
+
const i = Lt(n.bands), l = new Uint32Array(o * i);
|
|
193
193
|
if (n.source === "inline") {
|
|
194
|
-
const
|
|
195
|
-
for (let
|
|
196
|
-
const f =
|
|
194
|
+
const r = new DataView(e);
|
|
195
|
+
for (let u = 0; u < o; u++) {
|
|
196
|
+
const f = u * s + F;
|
|
197
197
|
for (let h = 0; h < i; h++)
|
|
198
|
-
|
|
198
|
+
l[u * i + h] = r.getUint32(f + h * 4, !0);
|
|
199
199
|
}
|
|
200
|
-
return
|
|
200
|
+
return Z(l, n);
|
|
201
201
|
}
|
|
202
202
|
if (!t) throw new Error("LCC chunk expected shcoef.bin bytes but none were fetched.");
|
|
203
203
|
const c = o * O;
|
|
@@ -205,15 +205,15 @@ function Ft(e, t, n, o, s) {
|
|
|
205
205
|
throw new Error(
|
|
206
206
|
`LCC shcoef.bin range is ${t.byteLength} bytes; expected ${c} for ${o} splats.`
|
|
207
207
|
);
|
|
208
|
-
const
|
|
209
|
-
for (let
|
|
210
|
-
const
|
|
208
|
+
const a = new DataView(t);
|
|
209
|
+
for (let r = 0; r < o; r++) {
|
|
210
|
+
const u = r * O;
|
|
211
211
|
for (let f = 0; f < i; f++)
|
|
212
|
-
r
|
|
212
|
+
l[r * i + f] = a.getUint32(u + f * 4, !0);
|
|
213
213
|
}
|
|
214
|
-
return
|
|
214
|
+
return Z(l, n);
|
|
215
215
|
}
|
|
216
|
-
function
|
|
216
|
+
function Z(e, t) {
|
|
217
217
|
const n = t.requantizeTo;
|
|
218
218
|
if (!n || mt(t.range, n))
|
|
219
219
|
return { bands: t.bands, packed: e, range: t.range };
|
|
@@ -221,13 +221,13 @@ function K(e, t) {
|
|
|
221
221
|
e[o] = pt(e[o], t.range, n);
|
|
222
222
|
return { bands: t.bands, packed: e, range: n };
|
|
223
223
|
}
|
|
224
|
-
function
|
|
224
|
+
function J(e, t) {
|
|
225
225
|
const n = e[t];
|
|
226
226
|
if (typeof n != "number" || !Number.isFinite(n))
|
|
227
227
|
throw new Error(`LCC manifest field "${t}" is not a finite number.`);
|
|
228
228
|
return n;
|
|
229
229
|
}
|
|
230
|
-
function
|
|
230
|
+
function P(e, t) {
|
|
231
231
|
if (!Array.isArray(e) || e.length < 3)
|
|
232
232
|
throw new Error(`LCC manifest "${t}" must have three numbers.`);
|
|
233
233
|
return e.slice(0, 3).map((o) => {
|
|
@@ -236,54 +236,54 @@ function N(e, t) {
|
|
|
236
236
|
return o;
|
|
237
237
|
});
|
|
238
238
|
}
|
|
239
|
-
function
|
|
239
|
+
function H() {
|
|
240
240
|
return new E.Matrix4().set(-1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1);
|
|
241
241
|
}
|
|
242
242
|
function le(e) {
|
|
243
|
-
e.matrix.copy(
|
|
243
|
+
e.matrix.copy(H()), e.matrix.decompose(e.position, e.quaternion, e.scale), e.matrixWorldNeedsUpdate = !0;
|
|
244
244
|
}
|
|
245
245
|
const Bt = 128e3;
|
|
246
246
|
async function ce(e, t, n) {
|
|
247
|
-
const o = Et(e), s = (
|
|
248
|
-
const
|
|
249
|
-
if (
|
|
250
|
-
return
|
|
251
|
-
}, i = s("data.bin"),
|
|
252
|
-
await
|
|
247
|
+
const o = Et(e), s = (g) => {
|
|
248
|
+
const x = t.resolve(g);
|
|
249
|
+
if (x === null) throw new Error(`LCC dataset is missing "${g}".`);
|
|
250
|
+
return x;
|
|
251
|
+
}, i = s("data.bin"), l = t.resolve("environment.bin"), c = Mt(
|
|
252
|
+
await _t(s("index.bin"), n, "manifest"),
|
|
253
253
|
o
|
|
254
254
|
);
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
let
|
|
255
|
+
Pt(c, o);
|
|
256
|
+
const a = o.fileType === "Quality" ? Ct : 0, r = n.shBands ?? a, u = Math.min(r, a), f = u === 0 ? void 0 : u, h = f === void 0 ? null : s("shcoef.bin"), d = [], m = [], p = (g, x) => (d.push(g), m.push(x), d.length - 1), $ = [], b = /* @__PURE__ */ new Set();
|
|
257
|
+
let w = 0;
|
|
258
258
|
const C = o.totalLevel;
|
|
259
|
-
for (let
|
|
260
|
-
const
|
|
261
|
-
let
|
|
259
|
+
for (let g = 0; g < c.length; g++) {
|
|
260
|
+
const x = c[g];
|
|
261
|
+
let U = 0;
|
|
262
262
|
for (let S = 0; S < C; S++) {
|
|
263
|
-
const T =
|
|
263
|
+
const T = x.levels[S].count;
|
|
264
264
|
if (T > 0) {
|
|
265
|
-
|
|
265
|
+
U = T;
|
|
266
266
|
break;
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
|
-
const M = Math.max(1, Math.ceil(
|
|
269
|
+
const M = Math.max(1, Math.ceil(U / Bt));
|
|
270
270
|
for (let S = 0; S < M; S++) {
|
|
271
271
|
const T = new Array(C).fill(
|
|
272
272
|
void 0
|
|
273
273
|
);
|
|
274
|
-
let B = -1,
|
|
275
|
-
for (let
|
|
276
|
-
const
|
|
277
|
-
if (
|
|
278
|
-
const
|
|
279
|
-
if (
|
|
280
|
-
const ft = `${i}#c${
|
|
274
|
+
let B = -1, G = 0;
|
|
275
|
+
for (let I = 0; I < C; I++) {
|
|
276
|
+
const R = x.levels[I];
|
|
277
|
+
if (R.count === 0) continue;
|
|
278
|
+
const N = Math.floor(S * R.count / M), _ = Math.floor((S + 1) * R.count / M);
|
|
279
|
+
if (_ === N) continue;
|
|
280
|
+
const ft = `${i}#c${x.cellX}_${x.cellY}-l${I}${M > 1 ? `.${S}` : ""}`, Q = p(ft, {
|
|
281
281
|
format: "lcc-bin",
|
|
282
282
|
lcc: {
|
|
283
283
|
kind: "splats",
|
|
284
|
-
start:
|
|
285
|
-
length: (
|
|
286
|
-
stride:
|
|
284
|
+
start: R.byteOffset + N * F,
|
|
285
|
+
length: (_ - N) * F,
|
|
286
|
+
stride: F,
|
|
287
287
|
scale: o.scale,
|
|
288
288
|
...f === void 0 ? {} : {
|
|
289
289
|
sh: {
|
|
@@ -298,22 +298,22 @@ async function ce(e, t, n) {
|
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
});
|
|
301
|
-
T[
|
|
301
|
+
T[I] = { file: Q, offset: 0, count: _ - N }, B = Q, G = _ - N;
|
|
302
302
|
}
|
|
303
|
-
B >= 0 && (b.add(B),
|
|
303
|
+
B >= 0 && (b.add(B), w += G), $.push({ bounds: Nt(x, o), lods: T, budgetGroup: g });
|
|
304
304
|
}
|
|
305
305
|
}
|
|
306
|
-
const
|
|
307
|
-
if (
|
|
308
|
-
const
|
|
306
|
+
const v = await Rt(t, o);
|
|
307
|
+
if (v > 0 && l !== null) {
|
|
308
|
+
const g = at(o), x = p(`${l}#env`, {
|
|
309
309
|
format: "lcc-bin",
|
|
310
310
|
lcc: {
|
|
311
311
|
kind: "environment",
|
|
312
312
|
start: 0,
|
|
313
|
-
length:
|
|
313
|
+
length: v * g,
|
|
314
314
|
// From `fileType`, never from whether SH is enabled: a Quality
|
|
315
315
|
// environment record is 96 bytes even when its SH is being skipped.
|
|
316
|
-
stride:
|
|
316
|
+
stride: g,
|
|
317
317
|
scale: o.envScale,
|
|
318
318
|
...f === void 0 ? {} : {
|
|
319
319
|
sh: {
|
|
@@ -328,9 +328,9 @@ async function ce(e, t, n) {
|
|
|
328
328
|
}
|
|
329
329
|
}
|
|
330
330
|
});
|
|
331
|
-
b.add(
|
|
331
|
+
b.add(x), w += v, $.push({
|
|
332
332
|
bounds: V(o),
|
|
333
|
-
lods: [{ file:
|
|
333
|
+
lods: [{ file: x, offset: 0, count: v }]
|
|
334
334
|
});
|
|
335
335
|
}
|
|
336
336
|
const y = {
|
|
@@ -341,7 +341,7 @@ async function ce(e, t, n) {
|
|
|
341
341
|
counts: o.splats.slice(0, C),
|
|
342
342
|
lodLevels: C,
|
|
343
343
|
bounds: V(o)
|
|
344
|
-
}, L = await
|
|
344
|
+
}, L = await It(t);
|
|
345
345
|
return {
|
|
346
346
|
// Classic LCC cells are broad XY tiles. Keep their priority independent of
|
|
347
347
|
// frustum crossings so an orbit does not demote a sharp tile as it leaves
|
|
@@ -373,19 +373,19 @@ async function ce(e, t, n) {
|
|
|
373
373
|
bounds: V(o),
|
|
374
374
|
pinnedFiles: b,
|
|
375
375
|
// Worst case is every cell resident at its finest level, plus the sky.
|
|
376
|
-
maxResidentSplats: (o.splats[0] ?? n.budget) +
|
|
376
|
+
maxResidentSplats: (o.splats[0] ?? n.budget) + v,
|
|
377
377
|
// Full coarse coverage is each cell's coarsest level plus the sky - the
|
|
378
378
|
// budget floor below which even the substitute levels cannot all fit.
|
|
379
|
-
minimumCoverageSplats: Math.max(1,
|
|
379
|
+
minimumCoverageSplats: Math.max(1, w),
|
|
380
380
|
// Same Z-up frame as .lcc2; bounds stay source-local and matrixWorld
|
|
381
381
|
// handles the conversion.
|
|
382
|
-
formatTransform:
|
|
382
|
+
formatTransform: H(),
|
|
383
383
|
// Optional classic-LCC collision mesh file. One descriptor for the whole
|
|
384
384
|
// `.lci`; `loadCollisionMeshes` expands it into per-cell triangle tiles.
|
|
385
385
|
...L !== null ? { collision: { meshes: [{ url: L }] } } : {}
|
|
386
386
|
};
|
|
387
387
|
}
|
|
388
|
-
async function
|
|
388
|
+
async function It(e) {
|
|
389
389
|
for (const t of ["collision.lci", "Collision.lci"]) {
|
|
390
390
|
const n = await e.size(t);
|
|
391
391
|
if (n !== null && Number.isSafeInteger(n) && n > 0)
|
|
@@ -394,9 +394,9 @@ async function Pt(e) {
|
|
|
394
394
|
return null;
|
|
395
395
|
}
|
|
396
396
|
function at(e) {
|
|
397
|
-
return e.fileType === "Quality" ?
|
|
397
|
+
return e.fileType === "Quality" ? F + O : F;
|
|
398
398
|
}
|
|
399
|
-
function
|
|
399
|
+
function Nt(e, t) {
|
|
400
400
|
const { min: n, max: o } = t.bounds, s = n[0] + e.cellX * t.cellLengthX, i = n[1] + e.cellY * t.cellLengthY;
|
|
401
401
|
return new E.Box3(
|
|
402
402
|
new E.Vector3(Math.min(s, o[0]), Math.min(i, o[1]), n[2]),
|
|
@@ -414,18 +414,18 @@ function V(e) {
|
|
|
414
414
|
new E.Vector3(n[0], n[1], n[2])
|
|
415
415
|
);
|
|
416
416
|
}
|
|
417
|
-
function
|
|
417
|
+
function Pt(e, t) {
|
|
418
418
|
for (let n = 0; n < t.totalLevel; n++) {
|
|
419
419
|
let o = 0;
|
|
420
420
|
for (const c of e) o += c.levels[n].count;
|
|
421
|
-
const s = t.splats[n], i = s - o,
|
|
422
|
-
if (i < 0 || i >
|
|
421
|
+
const s = t.splats[n], i = s - o, l = Math.max(4, Math.ceil(s * 1e-3));
|
|
422
|
+
if (i < 0 || i > l)
|
|
423
423
|
throw new Error(
|
|
424
424
|
`LCC index.bin level ${n} totals ${o} splats, but the manifest declares ${String(t.splats[n])}.`
|
|
425
425
|
);
|
|
426
426
|
}
|
|
427
427
|
}
|
|
428
|
-
async function
|
|
428
|
+
async function Rt(e, t) {
|
|
429
429
|
const n = await e.size("environment.bin");
|
|
430
430
|
if (n === null || !Number.isSafeInteger(n) || n <= 0) return 0;
|
|
431
431
|
const o = at(t);
|
|
@@ -435,54 +435,54 @@ async function _t(e, t) {
|
|
|
435
435
|
);
|
|
436
436
|
return n / o;
|
|
437
437
|
}
|
|
438
|
-
async function
|
|
438
|
+
async function _t(e, t, n) {
|
|
439
439
|
let o;
|
|
440
440
|
try {
|
|
441
441
|
o = await fetch(e, ct(t.request, t.signal));
|
|
442
442
|
} catch (s) {
|
|
443
|
-
throw
|
|
443
|
+
throw W(s, { phase: n, url: e });
|
|
444
444
|
}
|
|
445
445
|
if (!o.ok)
|
|
446
|
-
throw
|
|
446
|
+
throw W(new Error(`Failed to load ${e}: HTTP ${o.status}`), {
|
|
447
447
|
phase: n,
|
|
448
448
|
url: e,
|
|
449
449
|
status: o.status
|
|
450
450
|
});
|
|
451
451
|
return o.arrayBuffer();
|
|
452
452
|
}
|
|
453
|
-
const
|
|
453
|
+
const Dt = 3, zt = 0.1, tt = 0.1, Ot = 500;
|
|
454
454
|
function ae(e, t, n, o = 0) {
|
|
455
455
|
var $, b;
|
|
456
|
-
const s = e, i = s.root.splatFiles.map((
|
|
457
|
-
const C = t.resolve(
|
|
458
|
-
if (C === null) throw new Error(`LCC2 dataset is missing the tile "${
|
|
456
|
+
const s = e, i = s.root.splatFiles.map((w) => {
|
|
457
|
+
const C = t.resolve(w);
|
|
458
|
+
if (C === null) throw new Error(`LCC2 dataset is missing the tile "${w}".`);
|
|
459
459
|
return C;
|
|
460
|
-
}),
|
|
461
|
-
let
|
|
462
|
-
const
|
|
460
|
+
}), l = [], c = [];
|
|
461
|
+
let a = 0;
|
|
462
|
+
const r = (w, C) => {
|
|
463
463
|
var M;
|
|
464
|
-
const
|
|
465
|
-
if (!
|
|
466
|
-
const y =
|
|
467
|
-
|
|
468
|
-
const L =
|
|
469
|
-
if (
|
|
470
|
-
c[
|
|
464
|
+
const v = (M = w.data) == null ? void 0 : M["3dgs"];
|
|
465
|
+
if (!v) throw new Error("LCC2 node is missing 3dgs data.");
|
|
466
|
+
const y = l.length;
|
|
467
|
+
l.push(null);
|
|
468
|
+
const L = a, g = [], x = w.child ? Object.values(w.child) : [];
|
|
469
|
+
if (x.length === 0)
|
|
470
|
+
c[a] = y, a++;
|
|
471
471
|
else
|
|
472
|
-
for (const S of
|
|
473
|
-
const
|
|
474
|
-
return
|
|
475
|
-
file:
|
|
476
|
-
offset:
|
|
477
|
-
count:
|
|
478
|
-
bounds:
|
|
472
|
+
for (const S of x) g.push(r(S, C + 1));
|
|
473
|
+
const U = x.length === 0 ? L + 1 : a;
|
|
474
|
+
return l[y] = {
|
|
475
|
+
file: v.name,
|
|
476
|
+
offset: v.start,
|
|
477
|
+
count: v.count,
|
|
478
|
+
bounds: q(w.boundingBox),
|
|
479
479
|
level: s.totalLevels - C,
|
|
480
|
-
children:
|
|
480
|
+
children: g,
|
|
481
481
|
leafStart: L,
|
|
482
|
-
leafEnd:
|
|
482
|
+
leafEnd: U
|
|
483
483
|
}, y;
|
|
484
|
-
},
|
|
485
|
-
d !== void 0 && m === void 0 &&
|
|
484
|
+
}, u = Object.values(s.root.child ?? {}).map((w) => r(w, 1)), f = new Yt(l, u, c, s.totalLevels - 1, n), h = new Set(u.map((w) => l[w].file)), d = (b = ($ = s.root.data) == null ? void 0 : $.env) == null ? void 0 : b.name, m = d !== void 0 && i[d] !== void 0 ? { file: d } : void 0;
|
|
485
|
+
d !== void 0 && m === void 0 && z(`LCC2 root references env tile #${d}, which the manifest does not list.`), m && h.add(m.file);
|
|
486
486
|
const p = o >= 1 ? o : void 0;
|
|
487
487
|
return {
|
|
488
488
|
source: f,
|
|
@@ -495,46 +495,46 @@ function ae(e, t, n, o = 0) {
|
|
|
495
495
|
format: "sog",
|
|
496
496
|
...p ? { sog: { packShBands: p } } : {}
|
|
497
497
|
})),
|
|
498
|
-
bounds:
|
|
498
|
+
bounds: q(s.root.boundingBox),
|
|
499
499
|
pinnedFiles: h,
|
|
500
500
|
maxResidentSplats: s.lodSplats[0] ?? n.budget,
|
|
501
501
|
minimumCoverageSplats: Math.max(
|
|
502
502
|
1,
|
|
503
|
-
|
|
503
|
+
u.reduce((w, C) => w + l[C].count, 0)
|
|
504
504
|
),
|
|
505
505
|
...kt(s, t),
|
|
506
506
|
...m ? { environment: m } : {},
|
|
507
507
|
...p ? { shBands: p } : {},
|
|
508
508
|
// Match the established XGRIDS LCC and Spark viewer coordinate frame.
|
|
509
509
|
// Bounds remain source-local and matrixWorld handles the conversion.
|
|
510
|
-
formatTransform:
|
|
510
|
+
formatTransform: H()
|
|
511
511
|
};
|
|
512
512
|
}
|
|
513
513
|
function kt(e, t) {
|
|
514
514
|
const n = e.root.meshFiles;
|
|
515
515
|
if (!n || n.length === 0) return {};
|
|
516
516
|
const o = /* @__PURE__ */ new Map(), s = (c) => {
|
|
517
|
-
var
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
for (const
|
|
517
|
+
var r;
|
|
518
|
+
const a = (r = c.data) == null ? void 0 : r.mesh;
|
|
519
|
+
a && !o.has(a.name) && o.set(a.name, q(c.boundingBox));
|
|
520
|
+
for (const u of Object.values(c.child ?? {})) s(u);
|
|
521
521
|
};
|
|
522
522
|
s(e.root);
|
|
523
|
-
const i = o.size > 0 ? [...o].map(([c,
|
|
524
|
-
for (const { file: c, bounds:
|
|
525
|
-
const
|
|
526
|
-
if (
|
|
527
|
-
|
|
523
|
+
const i = o.size > 0 ? [...o].map(([c, a]) => ({ file: c, bounds: a })) : n.map((c, a) => ({ file: a })), l = [];
|
|
524
|
+
for (const { file: c, bounds: a } of i) {
|
|
525
|
+
const r = n[c];
|
|
526
|
+
if (r === void 0) {
|
|
527
|
+
z(`LCC2 node references mesh file ${c}, which the manifest does not list.`);
|
|
528
528
|
continue;
|
|
529
529
|
}
|
|
530
|
-
const
|
|
531
|
-
if (
|
|
532
|
-
|
|
530
|
+
const u = t.resolve(r);
|
|
531
|
+
if (u === null) {
|
|
532
|
+
z(`LCC2 dataset is missing the collision mesh "${r}"; skipping it.`);
|
|
533
533
|
continue;
|
|
534
534
|
}
|
|
535
|
-
|
|
535
|
+
l.push({ url: u, ...a ? { bounds: a } : {} });
|
|
536
536
|
}
|
|
537
|
-
return
|
|
537
|
+
return l.length > 0 ? { collision: { meshes: l } } : {};
|
|
538
538
|
}
|
|
539
539
|
class Yt {
|
|
540
540
|
constructor(t, n, o, s, i) {
|
|
@@ -556,69 +556,97 @@ class Yt {
|
|
|
556
556
|
A(this, "scratchBox", new E.Box3());
|
|
557
557
|
A(this, "scratchSize", new E.Vector3());
|
|
558
558
|
this.nodes = t, this.rootChildren = n, this.cellNodes = o, this.coarsest = s, this.budget = i.budget, this.lodBaseDistance = i.lodBaseDistance, this.lodMultiplier = i.lodMultiplier;
|
|
559
|
-
const
|
|
560
|
-
this.cellFinestLevel = new Int32Array(
|
|
561
|
-
for (let c = 0; c <
|
|
559
|
+
const l = o.length;
|
|
560
|
+
this.cellFinestLevel = new Int32Array(l), this.cellLevel = new Int32Array(l).fill(s), this.changedAt = new Float64Array(l);
|
|
561
|
+
for (let c = 0; c < l; c++)
|
|
562
562
|
this.cellFinestLevel[c] = t[o[c]].level;
|
|
563
|
-
this.cellRootChild = new Uint32Array(
|
|
564
|
-
const
|
|
565
|
-
for (let
|
|
563
|
+
this.cellRootChild = new Uint32Array(l), n.forEach((c, a) => {
|
|
564
|
+
const r = t[c];
|
|
565
|
+
for (let u = r.leafStart; u < r.leafEnd; u++) this.cellRootChild[u] = a;
|
|
566
566
|
});
|
|
567
567
|
}
|
|
568
568
|
computeDesiredRuns(t, n, o) {
|
|
569
|
-
const s = this.updateCellLevels(t, n, o), i = Int32Array.from(this.cellLevel),
|
|
570
|
-
let c =
|
|
571
|
-
const
|
|
569
|
+
const s = this.updateCellLevels(t, n, o), i = Int32Array.from(this.cellLevel), l = this.rootChildren.map((h) => this.subtreeCutTotal(h, i));
|
|
570
|
+
let c = l.reduce((h, d) => h + d, 0);
|
|
571
|
+
const a = (h, d) => {
|
|
572
572
|
i[h] = i[h] + d;
|
|
573
573
|
const m = this.cellRootChild[h], p = this.subtreeCutTotal(this.rootChildren[m], i);
|
|
574
|
-
c += p -
|
|
575
|
-
},
|
|
574
|
+
c += p - l[m], l[m] = p;
|
|
575
|
+
}, r = [...this.cellNodes.keys()].sort(
|
|
576
576
|
(h, d) => s[d] - s[h]
|
|
577
577
|
);
|
|
578
|
-
for (let h = 0; h <
|
|
579
|
-
const d =
|
|
580
|
-
i[d] < this.coarsest ?
|
|
578
|
+
for (let h = 0; h < r.length && c > this.budget; ) {
|
|
579
|
+
const d = r[h];
|
|
580
|
+
i[d] < this.coarsest ? a(d, 1) : h++;
|
|
581
581
|
}
|
|
582
|
-
const
|
|
583
|
-
for (let h =
|
|
584
|
-
const d =
|
|
582
|
+
const u = this.budget * 0.85;
|
|
583
|
+
for (let h = r.length - 1; h >= 0 && c < u; ) {
|
|
584
|
+
const d = r[h];
|
|
585
585
|
if (i[d] > this.cellFinestLevel[d]) {
|
|
586
|
-
if (
|
|
587
|
-
|
|
586
|
+
if (a(d, -1), c > this.budget) {
|
|
587
|
+
a(d, 1);
|
|
588
588
|
break;
|
|
589
589
|
}
|
|
590
590
|
} else
|
|
591
591
|
h--;
|
|
592
592
|
}
|
|
593
593
|
const f = [];
|
|
594
|
-
return this.collectCut(i, (h) => f.push(
|
|
594
|
+
return this.collectCut(i, (h) => f.push(X(this.nodes[h]))), f;
|
|
595
595
|
}
|
|
596
596
|
coarsestRunsFor(t, n) {
|
|
597
597
|
const o = [];
|
|
598
598
|
for (const s of this.rootChildren) {
|
|
599
599
|
const i = this.nodes[s];
|
|
600
|
-
i.leafStart < n && i.leafEnd > t && o.push(
|
|
600
|
+
i.leafStart < n && i.leafEnd > t && o.push(X(i));
|
|
601
601
|
}
|
|
602
602
|
return o;
|
|
603
603
|
}
|
|
604
|
+
/**
|
|
605
|
+
* Coarsest root-child runs covering in-view finest cells. An empty frustum
|
|
606
|
+
* falls back to the nearest cell's root child so a skyward start still paints
|
|
607
|
+
* something rather than releasing an empty hold.
|
|
608
|
+
*/
|
|
609
|
+
coverageRunsFor(t, n) {
|
|
610
|
+
const o = this.cellNodes.length;
|
|
611
|
+
if (o === 0) return [];
|
|
612
|
+
const s = new Uint8Array(this.rootChildren.length);
|
|
613
|
+
let i = !1, l = 0, c = Number.POSITIVE_INFINITY;
|
|
614
|
+
for (let r = 0; r < o; r++) {
|
|
615
|
+
const f = this.nodes[this.cellNodes[r]].bounds.distanceToPoint(t);
|
|
616
|
+
f < c && (c = f, l = r), this.cellIntersectsFrustum(n, r) && (s[this.cellRootChild[r]] = 1, i = !0);
|
|
617
|
+
}
|
|
618
|
+
i || (s[this.cellRootChild[l]] = 1);
|
|
619
|
+
const a = [];
|
|
620
|
+
for (let r = 0; r < this.rootChildren.length; r++)
|
|
621
|
+
s[r] === 1 && a.push(X(this.nodes[this.rootChildren[r]]));
|
|
622
|
+
return a;
|
|
623
|
+
}
|
|
624
|
+
/** Finest-cell AABB expanded by {@link FRUSTUM_MARGIN}, written into scratch. */
|
|
625
|
+
expandCellBox(t) {
|
|
626
|
+
const n = this.nodes[this.cellNodes[t]];
|
|
627
|
+
return this.scratchBox.copy(n.bounds), n.bounds.getSize(this.scratchSize), this.scratchBox.expandByScalar(this.scratchSize.length() * zt), this.scratchBox;
|
|
628
|
+
}
|
|
629
|
+
cellIntersectsFrustum(t, n) {
|
|
630
|
+
return t.intersectsBox(this.expandCellBox(n));
|
|
631
|
+
}
|
|
604
632
|
/** Distance (frustum-penalized) to each finest cell's node bounds. */
|
|
605
633
|
cellDistanceOf(t, n, o) {
|
|
606
|
-
const
|
|
607
|
-
return this.
|
|
634
|
+
const i = this.nodes[this.cellNodes[o]].bounds.distanceToPoint(t);
|
|
635
|
+
return this.cellIntersectsFrustum(n, o) ? i : i * Dt;
|
|
608
636
|
}
|
|
609
637
|
/** Advances each cell's dwelled level toward the distance target. */
|
|
610
638
|
updateCellLevels(t, n, o) {
|
|
611
|
-
const { lodBaseDistance: s, lodMultiplier: i } = this,
|
|
639
|
+
const { lodBaseDistance: s, lodMultiplier: i } = this, l = new Float64Array(this.cellNodes.length);
|
|
612
640
|
for (let c = 0; c < this.cellNodes.length; c++) {
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
const
|
|
616
|
-
let
|
|
617
|
-
for (;
|
|
618
|
-
for (;
|
|
619
|
-
|
|
641
|
+
const a = this.cellDistanceOf(t, n, c);
|
|
642
|
+
l[c] = a;
|
|
643
|
+
const r = this.cellFinestLevel[c];
|
|
644
|
+
let u = Math.min(this.coarsest, Math.max(r, this.cellLevel[c]));
|
|
645
|
+
for (; u < this.coarsest && a > s * i ** u * (1 + tt); ) u++;
|
|
646
|
+
for (; u > r && a <= s * i ** (u - 1) * (1 - tt); ) u--;
|
|
647
|
+
u !== this.cellLevel[c] && o - this.changedAt[c] >= Ot && (this.cellLevel[c] = u, this.changedAt[c] = o);
|
|
620
648
|
}
|
|
621
|
-
return
|
|
649
|
+
return l;
|
|
622
650
|
}
|
|
623
651
|
/** Splat total of one subtree's cut for the given per-cell levels. */
|
|
624
652
|
subtreeCutTotal(t, n) {
|
|
@@ -641,19 +669,19 @@ class Yt {
|
|
|
641
669
|
const s = this.nodes[t];
|
|
642
670
|
if (s.children.length > 0) {
|
|
643
671
|
let i = this.coarsest;
|
|
644
|
-
for (let
|
|
645
|
-
const c = n[
|
|
672
|
+
for (let l = s.leafStart; l < s.leafEnd; l++) {
|
|
673
|
+
const c = n[l];
|
|
646
674
|
c < i && (i = c);
|
|
647
675
|
}
|
|
648
676
|
if (i < s.level) {
|
|
649
|
-
for (const
|
|
677
|
+
for (const l of s.children) this.visitCut(l, n, o);
|
|
650
678
|
return;
|
|
651
679
|
}
|
|
652
680
|
}
|
|
653
681
|
o(t);
|
|
654
682
|
}
|
|
655
683
|
}
|
|
656
|
-
function
|
|
684
|
+
function X(e) {
|
|
657
685
|
return {
|
|
658
686
|
file: e.file,
|
|
659
687
|
level: e.level,
|
|
@@ -663,7 +691,7 @@ function tt(e) {
|
|
|
663
691
|
leafEnd: e.leafEnd
|
|
664
692
|
};
|
|
665
693
|
}
|
|
666
|
-
function
|
|
694
|
+
function q(e) {
|
|
667
695
|
return new E.Box3(
|
|
668
696
|
new E.Vector3(e.min[0], e.min[1], e.min[2]),
|
|
669
697
|
new E.Vector3(e.max[0], e.max[1], e.max[2])
|
|
@@ -671,9 +699,9 @@ function X(e) {
|
|
|
671
699
|
}
|
|
672
700
|
const et = ["vertex_indices", "vertex_index"];
|
|
673
701
|
function Vt(e) {
|
|
674
|
-
const t =
|
|
702
|
+
const t = xt(e), n = t.element("vertex");
|
|
675
703
|
if (!n) throw new Error('Not a mesh PLY: no "vertex" element.');
|
|
676
|
-
|
|
704
|
+
vt(n, ["x", "y", "z"], ["float", "float32"], "Mesh PLY vertex"), bt(n, e.byteLength);
|
|
677
705
|
const o = Xt(e, n), s = t.element("face");
|
|
678
706
|
if (!s) throw new Error('Not a mesh PLY: no "face" element.');
|
|
679
707
|
const i = qt(e, s, n.count);
|
|
@@ -685,12 +713,12 @@ function Vt(e) {
|
|
|
685
713
|
};
|
|
686
714
|
}
|
|
687
715
|
function Xt(e, t) {
|
|
688
|
-
const n = new DataView(e, t.offset), o = k(t, "x"), s = k(t, "y"), i = k(t, "z"),
|
|
716
|
+
const n = new DataView(e, t.offset), o = k(t, "x"), s = k(t, "y"), i = k(t, "z"), l = new Float32Array(t.count * 3);
|
|
689
717
|
for (let c = 0; c < t.count; c++) {
|
|
690
|
-
const
|
|
691
|
-
|
|
718
|
+
const a = c * t.stride;
|
|
719
|
+
l[c * 3] = n.getFloat32(a + o, !0), l[c * 3 + 1] = n.getFloat32(a + s, !0), l[c * 3 + 2] = n.getFloat32(a + i, !0);
|
|
692
720
|
}
|
|
693
|
-
return
|
|
721
|
+
return l;
|
|
694
722
|
}
|
|
695
723
|
function qt(e, t, n) {
|
|
696
724
|
if (t.count === 0) return new Uint32Array(0);
|
|
@@ -707,31 +735,31 @@ function qt(e, t, n) {
|
|
|
707
735
|
throw new Error(
|
|
708
736
|
`Mesh PLY "face" element is missing an index list (${et.join(" or ")}).`
|
|
709
737
|
);
|
|
710
|
-
const i =
|
|
711
|
-
let
|
|
738
|
+
const i = j(s.countType), l = j(s.itemType), c = new DataView(e), a = e.byteLength;
|
|
739
|
+
let r = new Uint32Array(t.count * 3), u = 0, f = t.offset;
|
|
712
740
|
for (let h = 0; h < t.count; h++) {
|
|
713
|
-
if (f + i >
|
|
741
|
+
if (f + i > a) throw new Error(nt(h));
|
|
714
742
|
const d = ot(c, f, s.countType, i);
|
|
715
743
|
if (d < 0)
|
|
716
744
|
throw new Error(`Mesh PLY face ${h} declares a negative vertex count (${d}).`);
|
|
717
|
-
if (f += i, f + d *
|
|
745
|
+
if (f += i, f + d * l > a) throw new Error(nt(h));
|
|
718
746
|
const m = Math.max(0, d - 2);
|
|
719
|
-
if (
|
|
720
|
-
const b = new Uint32Array(Math.max(
|
|
721
|
-
b.set(
|
|
747
|
+
if (u + m * 3 > r.length) {
|
|
748
|
+
const b = new Uint32Array(Math.max(r.length * 2, u + m * 3));
|
|
749
|
+
b.set(r.subarray(0, u)), r = b;
|
|
722
750
|
}
|
|
723
751
|
let p = 0, $ = 0;
|
|
724
752
|
for (let b = 0; b < d; b++) {
|
|
725
|
-
const
|
|
726
|
-
if (
|
|
753
|
+
const w = ot(c, f + b * l, s.itemType, l);
|
|
754
|
+
if (w < 0 || w >= n)
|
|
727
755
|
throw new Error(
|
|
728
|
-
`Mesh PLY face ${h} references vertex ${
|
|
756
|
+
`Mesh PLY face ${h} references vertex ${w}, but the file has ${n}.`
|
|
729
757
|
);
|
|
730
|
-
b === 0 ? p =
|
|
758
|
+
b === 0 ? p = w : b >= 2 && (r[u++] = p, r[u++] = $, r[u++] = w), $ = w;
|
|
731
759
|
}
|
|
732
|
-
f += d *
|
|
760
|
+
f += d * l;
|
|
733
761
|
}
|
|
734
|
-
return
|
|
762
|
+
return u === r.length ? r : r.slice(0, u);
|
|
735
763
|
}
|
|
736
764
|
function nt(e) {
|
|
737
765
|
return `Truncated PLY file: the "face" element ends inside face ${e}.`;
|
|
@@ -760,11 +788,11 @@ function ot(e, t, n, o) {
|
|
|
760
788
|
throw new Error(`Unsupported PLY index type: "${n}" (${o} bytes).`);
|
|
761
789
|
}
|
|
762
790
|
}
|
|
763
|
-
const Ht = 1819045731, st = 2,
|
|
791
|
+
const Ht = 1819045731, st = 2, D = 48, it = 40, ut = 3, ht = 3, rt = ut * 4, Gt = ht * 4;
|
|
764
792
|
function Qt(e) {
|
|
765
|
-
if (e.byteLength <
|
|
793
|
+
if (e.byteLength < D)
|
|
766
794
|
throw new Error(
|
|
767
|
-
`collision.lci is truncated: ${e.byteLength} bytes, need at least ${
|
|
795
|
+
`collision.lci is truncated: ${e.byteLength} bytes, need at least ${D}.`
|
|
768
796
|
);
|
|
769
797
|
const t = new DataView(e), n = t.getUint32(0, !0);
|
|
770
798
|
if (n !== Ht)
|
|
@@ -780,63 +808,63 @@ function Qt(e) {
|
|
|
780
808
|
t.getFloat32(12, !0),
|
|
781
809
|
t.getFloat32(16, !0),
|
|
782
810
|
t.getFloat32(20, !0)
|
|
783
|
-
),
|
|
811
|
+
), l = new E.Vector3(
|
|
784
812
|
t.getFloat32(24, !0),
|
|
785
813
|
t.getFloat32(28, !0),
|
|
786
814
|
t.getFloat32(32, !0)
|
|
787
|
-
), c = t.getFloat32(36, !0),
|
|
788
|
-
if (s !==
|
|
815
|
+
), c = t.getFloat32(36, !0), a = t.getFloat32(40, !0), r = t.getUint32(44, !0), u = D + r * it;
|
|
816
|
+
if (s !== u)
|
|
789
817
|
throw new Error(
|
|
790
|
-
`collision.lci headerLen ${s} does not match ${
|
|
818
|
+
`collision.lci headerLen ${s} does not match ${r} mesh headers (expected ${u}).`
|
|
791
819
|
);
|
|
792
820
|
if (e.byteLength < s)
|
|
793
821
|
throw new Error(
|
|
794
822
|
`collision.lci is truncated: header claims ${s} bytes, file has ${e.byteLength}.`
|
|
795
823
|
);
|
|
796
|
-
if (!(c > 0) || !(
|
|
824
|
+
if (!(c > 0) || !(a > 0))
|
|
797
825
|
throw new Error(
|
|
798
|
-
`collision.lci cell lengths must be positive (got ${c} × ${
|
|
826
|
+
`collision.lci cell lengths must be positive (got ${c} × ${a}).`
|
|
799
827
|
);
|
|
800
|
-
const f = new E.Box3(i.clone(),
|
|
828
|
+
const f = new E.Box3(i.clone(), l.clone()), h = [];
|
|
801
829
|
let d = s;
|
|
802
|
-
for (let m = 0; m <
|
|
803
|
-
const p =
|
|
804
|
-
if (!Number.isSafeInteger(
|
|
830
|
+
for (let m = 0; m < r; m++) {
|
|
831
|
+
const p = D + m * it, $ = t.getUint32(p, !0), b = t.getUint32(p + 4, !0), w = Number(t.getBigUint64(p + 8, !0)), C = Number(t.getBigUint64(p + 16, !0)), v = t.getUint32(p + 24, !0), y = t.getUint32(p + 28, !0), L = t.getUint32(p + 32, !0);
|
|
832
|
+
if (!Number.isSafeInteger(w) || !Number.isSafeInteger(C))
|
|
805
833
|
throw new Error(`collision.lci mesh ${m} has an unsafe data offset/size.`);
|
|
806
|
-
if (
|
|
834
|
+
if (w !== d)
|
|
807
835
|
throw new Error(
|
|
808
|
-
`collision.lci mesh ${m} data offset ${
|
|
836
|
+
`collision.lci mesh ${m} data offset ${w} is not contiguous (expected ${d}).`
|
|
809
837
|
);
|
|
810
|
-
if (
|
|
838
|
+
if (v * rt + y * Gt + L !== C)
|
|
811
839
|
throw new Error(
|
|
812
|
-
`collision.lci mesh ${m} size ${C} != ${
|
|
840
|
+
`collision.lci mesh ${m} size ${C} != ${v}*12 + ${y}*12 + BVH ${L}.`
|
|
813
841
|
);
|
|
814
|
-
const
|
|
815
|
-
if (
|
|
842
|
+
const x = w + C;
|
|
843
|
+
if (x > e.byteLength)
|
|
816
844
|
throw new Error(
|
|
817
|
-
`collision.lci mesh ${m} extends to byte ${
|
|
845
|
+
`collision.lci mesh ${m} extends to byte ${x}, past file length ${e.byteLength}.`
|
|
818
846
|
);
|
|
819
|
-
const
|
|
847
|
+
const U = new Float32Array(e, w, v * ut), M = w + v * rt, S = new Uint32Array(e, M, y * ht);
|
|
820
848
|
for (let T = 0; T < S.length; T++) {
|
|
821
849
|
const B = S[T];
|
|
822
|
-
if (B >=
|
|
850
|
+
if (B >= v)
|
|
823
851
|
throw new Error(
|
|
824
|
-
`collision.lci mesh ${m} face index ${B} is out of range (vertexCount ${
|
|
852
|
+
`collision.lci mesh ${m} face index ${B} is out of range (vertexCount ${v}).`
|
|
825
853
|
);
|
|
826
854
|
}
|
|
827
855
|
h.push({
|
|
828
856
|
cellX: $,
|
|
829
857
|
cellY: b,
|
|
830
858
|
data: {
|
|
831
|
-
vertexCount:
|
|
859
|
+
vertexCount: v,
|
|
832
860
|
triangleCount: y,
|
|
833
861
|
// Copy so the returned arrays outlive a transferred/detached buffer
|
|
834
862
|
// and are not views into the BVH-adjacent region.
|
|
835
|
-
positions:
|
|
863
|
+
positions: U.slice(),
|
|
836
864
|
indices: S.slice()
|
|
837
865
|
},
|
|
838
|
-
bounds: Wt($, b, c,
|
|
839
|
-
}), d =
|
|
866
|
+
bounds: Wt($, b, c, a, f)
|
|
867
|
+
}), d = x;
|
|
840
868
|
}
|
|
841
869
|
if (d !== e.byteLength)
|
|
842
870
|
throw new Error(
|
|
@@ -846,17 +874,17 @@ function Qt(e) {
|
|
|
846
874
|
version: o,
|
|
847
875
|
bounds: f,
|
|
848
876
|
cellLengthX: c,
|
|
849
|
-
cellLengthY:
|
|
877
|
+
cellLengthY: a,
|
|
850
878
|
tiles: h
|
|
851
879
|
};
|
|
852
880
|
}
|
|
853
881
|
function Wt(e, t, n, o, s) {
|
|
854
|
-
const i = s.min.x + e * n,
|
|
882
|
+
const i = s.min.x + e * n, l = s.min.y + t * o;
|
|
855
883
|
return new E.Box3(
|
|
856
|
-
new E.Vector3(Math.min(i, s.max.x), Math.min(
|
|
884
|
+
new E.Vector3(Math.min(i, s.max.x), Math.min(l, s.max.y), s.min.z),
|
|
857
885
|
new E.Vector3(
|
|
858
886
|
Math.min(i + n, s.max.x),
|
|
859
|
-
Math.min(
|
|
887
|
+
Math.min(l + o, s.max.y),
|
|
860
888
|
s.max.z
|
|
861
889
|
)
|
|
862
890
|
);
|
|
@@ -869,7 +897,7 @@ async function ue(e, t = {}) {
|
|
|
869
897
|
(s = t.signal) == null || s.throwIfAborted();
|
|
870
898
|
const o = [];
|
|
871
899
|
for (const i of n)
|
|
872
|
-
i.status === "fulfilled" ? o.push(...i.value) :
|
|
900
|
+
i.status === "fulfilled" ? o.push(...i.value) : z("Skipping a collision mesh that failed to load:", i.reason);
|
|
873
901
|
return o;
|
|
874
902
|
}
|
|
875
903
|
async function jt(e, t) {
|
|
@@ -878,10 +906,10 @@ async function jt(e, t) {
|
|
|
878
906
|
throw new Error(`HTTP ${n.status} for collision mesh ${e.url}`);
|
|
879
907
|
const o = await n.arrayBuffer();
|
|
880
908
|
if (Kt(e.url))
|
|
881
|
-
return Qt(o).tiles.map((
|
|
882
|
-
url: `${e.url}#c${
|
|
883
|
-
data:
|
|
884
|
-
bounds:
|
|
909
|
+
return Qt(o).tiles.map((l) => ({
|
|
910
|
+
url: `${e.url}#c${l.cellX}_${l.cellY}`,
|
|
911
|
+
data: l.data,
|
|
912
|
+
bounds: l.bounds
|
|
885
913
|
}));
|
|
886
914
|
const s = Vt(o);
|
|
887
915
|
return [
|
|
@@ -901,22 +929,22 @@ function Kt(e) {
|
|
|
901
929
|
}
|
|
902
930
|
function he(e, t) {
|
|
903
931
|
Zt(e);
|
|
904
|
-
const { positions: n, indices: o, vertexCount: s, triangleCount: i } = e,
|
|
905
|
-
for (let
|
|
906
|
-
r
|
|
907
|
-
n[
|
|
908
|
-
n[
|
|
909
|
-
n[
|
|
932
|
+
const { positions: n, indices: o, vertexCount: s, triangleCount: i } = e, l = new Uint8Array(s);
|
|
933
|
+
for (let r = 0; r < s; r++)
|
|
934
|
+
l[r] = t.containsPoint(
|
|
935
|
+
n[r * 3],
|
|
936
|
+
n[r * 3 + 1],
|
|
937
|
+
n[r * 3 + 2]
|
|
910
938
|
) ? 1 : 0;
|
|
911
939
|
const c = new Uint8Array(i);
|
|
912
|
-
let
|
|
913
|
-
for (let
|
|
914
|
-
const
|
|
915
|
-
(
|
|
940
|
+
let a = 0;
|
|
941
|
+
for (let r = 0; r < i; r++) {
|
|
942
|
+
const u = o[r * 3], f = o[r * 3 + 1], h = o[r * 3 + 2];
|
|
943
|
+
(l[u] === 1 || l[f] === 1 || l[h] === 1) && (c[r] = 1, a++);
|
|
916
944
|
}
|
|
917
945
|
return {
|
|
918
|
-
inside: lt(e, c, 1,
|
|
919
|
-
outside: lt(e, c, 0, i -
|
|
946
|
+
inside: lt(e, c, 1, a),
|
|
947
|
+
outside: lt(e, c, 0, i - a)
|
|
920
948
|
};
|
|
921
949
|
}
|
|
922
950
|
function Zt(e) {
|
|
@@ -938,26 +966,26 @@ function Zt(e) {
|
|
|
938
966
|
}
|
|
939
967
|
function lt(e, t, n, o) {
|
|
940
968
|
const s = new Int32Array(e.vertexCount).fill(-1), i = new Uint32Array(o * 3);
|
|
941
|
-
let
|
|
942
|
-
for (let
|
|
943
|
-
if (t[
|
|
944
|
-
for (let
|
|
945
|
-
const f = e.indices[
|
|
969
|
+
let l = 0, c = 0;
|
|
970
|
+
for (let r = 0; r < e.triangleCount; r++)
|
|
971
|
+
if (t[r] === n)
|
|
972
|
+
for (let u = 0; u < 3; u++) {
|
|
973
|
+
const f = e.indices[r * 3 + u];
|
|
946
974
|
let h = s[f];
|
|
947
|
-
h < 0 && (h =
|
|
975
|
+
h < 0 && (h = l++, s[f] = h), i[c++] = h;
|
|
948
976
|
}
|
|
949
|
-
const
|
|
950
|
-
for (let
|
|
951
|
-
const
|
|
952
|
-
|
|
977
|
+
const a = new Float32Array(l * 3);
|
|
978
|
+
for (let r = 0; r < e.vertexCount; r++) {
|
|
979
|
+
const u = s[r];
|
|
980
|
+
u < 0 || (a[u * 3] = e.positions[r * 3], a[u * 3 + 1] = e.positions[r * 3 + 1], a[u * 3 + 2] = e.positions[r * 3 + 2]);
|
|
953
981
|
}
|
|
954
|
-
return { vertexCount:
|
|
982
|
+
return { vertexCount: l, triangleCount: o, positions: a, indices: i };
|
|
955
983
|
}
|
|
956
984
|
export {
|
|
957
985
|
le as applyLcc2ToThreeTransform,
|
|
958
986
|
ae as buildLcc2Scene,
|
|
959
987
|
ce as buildLccScene,
|
|
960
|
-
|
|
988
|
+
H as createLcc2ToThreeMatrix,
|
|
961
989
|
ue as loadCollisionMeshTiles,
|
|
962
990
|
Qt as parseCollisionLci,
|
|
963
991
|
re as parseLccChunk,
|