@needle-tools/gltf-progressive 1.2.4-beta.1 → 1.2.5-beta
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 +3 -0
- package/README.md +1 -0
- package/gltf-progressive.js +166 -154
- package/gltf-progressive.min.js +6 -6
- package/gltf-progressive.umd.cjs +7 -7
- package/lib/lods_manager.d.ts +1 -0
- package/lib/lods_manager.js +21 -2
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,9 @@ All notable changes to this package will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [1.2.5-beta] - 2023-07-09
|
|
8
|
+
- Change: Update skinned mesh bounding box every 30 frames using the lowres mesh version
|
|
9
|
+
|
|
7
10
|
## [1.2.4-beta.1] - 2023-07-09
|
|
8
11
|
- Add: LODsManager `manual` property which can be used to manually update the LODs in the scene by calling `LODsManager.update(scene, camera)`
|
|
9
12
|
- Fix: updating LODs in WebXR
|
package/README.md
CHANGED
|
@@ -17,6 +17,7 @@ Examples are in the `/examples` directory. Live versions can be found in the lin
|
|
|
17
17
|
- \<model-viewer\>
|
|
18
18
|
- [single \<model-viewer> element](https://engine.needle.tools/demos/gltf-progressive/modelviewer)
|
|
19
19
|
- [multiple \<model-viewer> elements](https://engine.needle.tools/demos/gltf-progressive/modelviewer-multiple)
|
|
20
|
+
- [Needle Engine](https://stackblitz.com/edit/needle-engine-gltf-progressive?file=src%2Fmain.ts)
|
|
20
21
|
|
|
21
22
|
**Interactive Examples**:
|
|
22
23
|
- [Stackblitz](https://stackblitz.com/@marwie/collections/gltf-progressive)
|
package/gltf-progressive.js
CHANGED
|
@@ -4,11 +4,11 @@ var f = (a, t, e) => (ze(a, typeof t != "symbol" ? t + "" : t, e), e), Se = (a,
|
|
|
4
4
|
if (!t.has(a))
|
|
5
5
|
throw TypeError("Cannot " + e);
|
|
6
6
|
};
|
|
7
|
-
var
|
|
7
|
+
var x = (a, t, e) => (Se(a, t, "read from private field"), e ? e.call(a) : t.get(a)), K = (a, t, e) => {
|
|
8
8
|
if (t.has(a))
|
|
9
9
|
throw TypeError("Cannot add the same private member more than once");
|
|
10
10
|
t instanceof WeakSet ? t.add(a) : t.set(a, e);
|
|
11
|
-
},
|
|
11
|
+
}, $ = (a, t, e, r) => (Se(a, t, "write to private field"), r ? r.call(a, e) : t.set(a, e), e);
|
|
12
12
|
import { BufferGeometry as he, Mesh as H, Material as Ve, Texture as re, TextureLoader as Ne, Matrix4 as be, Frustum as We, Clock as qe, MeshStandardMaterial as Xe, Sphere as Ke, Box3 as Te, Vector3 as V } from "three";
|
|
13
13
|
import { GLTFLoader as Ye } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
14
14
|
import { MeshoptDecoder as He } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
@@ -17,19 +17,19 @@ import { KTX2Loader as Qe } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
|
17
17
|
const Be = "";
|
|
18
18
|
globalThis.GLTF_PROGRESSIVE_VERSION = Be;
|
|
19
19
|
console.debug(`[gltf-progressive] version ${Be}`);
|
|
20
|
-
let ge = "https://www.gstatic.com/draco/versioned/decoders/1.4.1/",
|
|
20
|
+
let ge = "https://www.gstatic.com/draco/versioned/decoders/1.4.1/", _e = "https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";
|
|
21
21
|
fetch(ge + "draco_decoder.js", { method: "head" }).catch((a) => {
|
|
22
|
-
ge = "./include/draco/",
|
|
22
|
+
ge = "./include/draco/", _e = "./include/ktx2/";
|
|
23
23
|
});
|
|
24
24
|
function gt(a) {
|
|
25
25
|
ge = a;
|
|
26
26
|
}
|
|
27
27
|
function pt(a) {
|
|
28
|
-
|
|
28
|
+
_e = a;
|
|
29
29
|
}
|
|
30
30
|
let Q, de, Z;
|
|
31
31
|
function Ie(a) {
|
|
32
|
-
return Q || (Q = new Je(), Q.setDecoderPath(ge), Q.setDecoderConfig({ type: "js" })), Z || (Z = new Qe(), Z.setTranscoderPath(
|
|
32
|
+
return Q || (Q = new Je(), Q.setDecoderPath(ge), Q.setDecoderConfig({ type: "js" })), Z || (Z = new Qe(), Z.setTranscoderPath(_e)), de || (de = He), a ? Z.detectSupport(a) : a !== null && console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"), { dracoLoader: Q, ktx2Loader: Z, meshoptDecoder: de };
|
|
33
33
|
}
|
|
34
34
|
function ke(a) {
|
|
35
35
|
a.dracoLoader || a.setDRACOLoader(Q), a.ktx2Loader || a.setKTX2Loader(Z), a.meshoptDecoder || a.setMeshoptDecoder(de);
|
|
@@ -55,14 +55,14 @@ let se;
|
|
|
55
55
|
function je() {
|
|
56
56
|
return se !== void 0 || (se = /iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent), ae("debugprogressive") && console.log("[glTF Progressive]: isMobileDevice", se)), se;
|
|
57
57
|
}
|
|
58
|
-
const
|
|
59
|
-
function
|
|
60
|
-
return (a == null ? void 0 : a[
|
|
58
|
+
const ve = Symbol("needle:raycast-mesh");
|
|
59
|
+
function me(a) {
|
|
60
|
+
return (a == null ? void 0 : a[ve]) instanceof he ? a[ve] : null;
|
|
61
61
|
}
|
|
62
62
|
function et(a, t) {
|
|
63
|
-
if ((a.type === "Mesh" || a.type === "SkinnedMesh") && !
|
|
63
|
+
if ((a.type === "Mesh" || a.type === "SkinnedMesh") && !me(a)) {
|
|
64
64
|
const r = tt(t);
|
|
65
|
-
r.userData = { isRaycastMesh: !0 }, a[
|
|
65
|
+
r.userData = { isRaycastMesh: !0 }, a[ve] = r;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
function yt(a = !0) {
|
|
@@ -71,7 +71,7 @@ function yt(a = !0) {
|
|
|
71
71
|
return;
|
|
72
72
|
const t = ie = H.prototype.raycast;
|
|
73
73
|
H.prototype.raycast = function(e, r) {
|
|
74
|
-
const n = this, s =
|
|
74
|
+
const n = this, s = me(n);
|
|
75
75
|
let i;
|
|
76
76
|
s && n.isMesh && (i = n.geometry, n.geometry = s), t.call(this, e, r), i && (n.geometry = i);
|
|
77
77
|
};
|
|
@@ -88,8 +88,8 @@ function tt(a) {
|
|
|
88
88
|
t.setAttribute(e, a.getAttribute(e));
|
|
89
89
|
return t.setIndex(a.getIndex()), t;
|
|
90
90
|
}
|
|
91
|
-
const Y = new Array(), N = "NEEDLE_progressive",
|
|
92
|
-
if (
|
|
91
|
+
const Y = new Array(), N = "NEEDLE_progressive", L = ae("debugprogressive"), Me = Symbol("needle-progressive-texture"), oe = /* @__PURE__ */ new Map(), Oe = /* @__PURE__ */ new Set();
|
|
92
|
+
if (L) {
|
|
93
93
|
let a = function() {
|
|
94
94
|
t += 1, console.log("Toggle LOD level", t, oe), oe.forEach((n, s) => {
|
|
95
95
|
for (const i of n.keys) {
|
|
@@ -107,14 +107,14 @@ if (x) {
|
|
|
107
107
|
}), t >= e && (t = -1);
|
|
108
108
|
}, t = -1, e = 2, r = !1;
|
|
109
109
|
window.addEventListener("keyup", (n) => {
|
|
110
|
-
n.key === "p" && a(), n.key === "w" && (r = !r,
|
|
110
|
+
n.key === "p" && a(), n.key === "w" && (r = !r, Oe && Oe.forEach((s) => {
|
|
111
111
|
s.name != "BackgroundCubeMaterial" && s.glyphMap == null && "wireframe" in s && (s.wireframe = r);
|
|
112
112
|
}));
|
|
113
113
|
});
|
|
114
114
|
}
|
|
115
115
|
function Ae(a, t, e) {
|
|
116
116
|
var n;
|
|
117
|
-
if (!
|
|
117
|
+
if (!L)
|
|
118
118
|
return;
|
|
119
119
|
oe.has(a) || oe.set(a, { keys: [], sourceId: e });
|
|
120
120
|
const r = oe.get(a);
|
|
@@ -135,7 +135,7 @@ const O = class {
|
|
|
135
135
|
return this._isLoadingMesh = !1, s && O.registerMesh(this.url, e.guid, s, (i = e.lods) == null ? void 0 : i.length, void 0, e), s;
|
|
136
136
|
})) : null;
|
|
137
137
|
});
|
|
138
|
-
|
|
138
|
+
L && console.log("Progressive extension registered for", e), this.parser = t, this.url = e;
|
|
139
139
|
}
|
|
140
140
|
/** The name of the extension */
|
|
141
141
|
get name() {
|
|
@@ -158,7 +158,7 @@ const O = class {
|
|
|
158
158
|
this.getMaterialMinMaxLODsCount(o, e);
|
|
159
159
|
return t[n] = e, e;
|
|
160
160
|
}
|
|
161
|
-
if (
|
|
161
|
+
if (L === "verbose" && console.log("getMaterialMinMaxLODsCount", t), t.type === "ShaderMaterial" || t.type === "RawShaderMaterial") {
|
|
162
162
|
const o = t;
|
|
163
163
|
for (const l of Object.keys(o.uniforms)) {
|
|
164
164
|
const u = o.uniforms[l].value;
|
|
@@ -249,12 +249,12 @@ const O = class {
|
|
|
249
249
|
const o = s.index || 0;
|
|
250
250
|
i = i[o];
|
|
251
251
|
}
|
|
252
|
-
i && n != i && ((i == null ? void 0 : i.isBufferGeometry) ? (t.geometry = i,
|
|
252
|
+
i && n != i && ((i == null ? void 0 : i.isBufferGeometry) ? (t.geometry = i, L && Ae(t, "geometry", s.url)) : L && console.error("Invalid LOD geometry", i));
|
|
253
253
|
}
|
|
254
254
|
return i;
|
|
255
255
|
}).catch((i) => (console.error("Error loading mesh LOD", t, i), null));
|
|
256
256
|
} else
|
|
257
|
-
|
|
257
|
+
L && console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh", t);
|
|
258
258
|
return Promise.resolve(null);
|
|
259
259
|
}
|
|
260
260
|
/** Load a different resolution of a texture (if available)
|
|
@@ -269,7 +269,7 @@ const O = class {
|
|
|
269
269
|
return Promise.resolve(null);
|
|
270
270
|
if (t instanceof Ve || t.isMaterial === !0) {
|
|
271
271
|
const r = t, n = [], s = new Array();
|
|
272
|
-
if (
|
|
272
|
+
if (L && Oe.add(r), r.uniforms && r.isRawShaderMaterial || r.isShaderMaterial === !0) {
|
|
273
273
|
const i = r;
|
|
274
274
|
for (const o of Object.keys(i.uniforms)) {
|
|
275
275
|
const l = i.uniforms[o].value;
|
|
@@ -312,30 +312,30 @@ const O = class {
|
|
|
312
312
|
if (i) {
|
|
313
313
|
const o = this.getAssignedLODInformation(i);
|
|
314
314
|
if (o && (o == null ? void 0 : o.level) < e)
|
|
315
|
-
return
|
|
315
|
+
return L === "verbose" && console.warn("Assigned texture level is already higher: ", o.level, e, r, i, s), null;
|
|
316
316
|
}
|
|
317
317
|
r[n] = s;
|
|
318
318
|
}
|
|
319
|
-
if (
|
|
319
|
+
if (L && n && r) {
|
|
320
320
|
const i = this.getAssignedLODInformation(t);
|
|
321
321
|
i && Ae(r, n, i.url);
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
324
|
return s;
|
|
325
325
|
} else
|
|
326
|
-
|
|
326
|
+
L == "verbose" && console.warn("No LOD found for", t, e);
|
|
327
327
|
return null;
|
|
328
328
|
}).catch((s) => (console.error("Error loading LOD", t, s), null));
|
|
329
329
|
}
|
|
330
330
|
afterRoot(t) {
|
|
331
331
|
var e, r;
|
|
332
|
-
return
|
|
332
|
+
return L && console.log("AFTER", this.url, t), (e = this.parser.json.textures) == null || e.forEach((n, s) => {
|
|
333
333
|
var i;
|
|
334
334
|
if (n != null && n.extensions) {
|
|
335
335
|
const o = n == null ? void 0 : n.extensions[N];
|
|
336
336
|
if (o) {
|
|
337
337
|
if (!o.lods) {
|
|
338
|
-
|
|
338
|
+
L && console.warn("Texture has no LODs", o);
|
|
339
339
|
return;
|
|
340
340
|
}
|
|
341
341
|
let l = !1;
|
|
@@ -365,14 +365,14 @@ const O = class {
|
|
|
365
365
|
}
|
|
366
366
|
static async getOrLoadLOD(t, e) {
|
|
367
367
|
var o, l, u, c;
|
|
368
|
-
const r =
|
|
368
|
+
const r = L == "verbose", n = t.userData.LODS;
|
|
369
369
|
if (!n)
|
|
370
370
|
return null;
|
|
371
371
|
const s = n == null ? void 0 : n.key;
|
|
372
372
|
let i;
|
|
373
373
|
if (t.isTexture === !0) {
|
|
374
374
|
const d = t;
|
|
375
|
-
d.source && d.source[
|
|
375
|
+
d.source && d.source[Me] && (i = d.source[Me]);
|
|
376
376
|
}
|
|
377
377
|
if (i || (i = O.lodInfos.get(s)), i) {
|
|
378
378
|
if (e > 0) {
|
|
@@ -383,7 +383,7 @@ const O = class {
|
|
|
383
383
|
}
|
|
384
384
|
const d = Array.isArray(i.lods) ? (o = i.lods[e]) == null ? void 0 : o.path : i.lods;
|
|
385
385
|
if (!d)
|
|
386
|
-
return
|
|
386
|
+
return L && !i["missing:uri"] && (i["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + e, i)), null;
|
|
387
387
|
const h = Ze(n.url, d);
|
|
388
388
|
if (h.endsWith(".glb") || h.endsWith(".gltf")) {
|
|
389
389
|
if (!i.guid)
|
|
@@ -391,20 +391,20 @@ const O = class {
|
|
|
391
391
|
const w = h + "_" + i.guid, v = this.previouslyLoaded.get(w);
|
|
392
392
|
if (v !== void 0) {
|
|
393
393
|
r && console.log(`LOD ${e} was already loading/loaded: ${w}`);
|
|
394
|
-
let
|
|
395
|
-
`,
|
|
396
|
-
if (
|
|
397
|
-
return
|
|
394
|
+
let g = await v.catch((I) => (console.error(`Error loading LOD ${e} from ${h}
|
|
395
|
+
`, I), null)), m = !1;
|
|
396
|
+
if (g == null || (g instanceof re && t instanceof re ? (l = g.image) != null && l.data || (u = g.source) != null && u.data ? g = this.copySettings(t, g) : (m = !0, this.previouslyLoaded.delete(w)) : g instanceof he && t instanceof he && ((c = g.attributes.position) != null && c.array || (m = !0, this.previouslyLoaded.delete(w)))), !m)
|
|
397
|
+
return g;
|
|
398
398
|
}
|
|
399
|
-
const M = i,
|
|
400
|
-
const
|
|
401
|
-
ke(
|
|
399
|
+
const M = i, F = new Promise(async (g, m) => {
|
|
400
|
+
const I = new Ye();
|
|
401
|
+
ke(I), L && (await new Promise((_) => setTimeout(_, 1e3)), r && console.warn("Start loading (delayed) " + h, M.guid));
|
|
402
402
|
let X = h;
|
|
403
403
|
if (M && Array.isArray(M.lods)) {
|
|
404
404
|
const _ = M.lods[e];
|
|
405
405
|
_.hash && (X += "?v=" + _.hash);
|
|
406
406
|
}
|
|
407
|
-
const S = await
|
|
407
|
+
const S = await I.loadAsync(X).catch((_) => (console.error(`Error loading LOD ${e} from ${h}
|
|
408
408
|
`, _), null));
|
|
409
409
|
if (!S)
|
|
410
410
|
return null;
|
|
@@ -413,10 +413,10 @@ const O = class {
|
|
|
413
413
|
let A = 0;
|
|
414
414
|
if (S.parser.json.textures) {
|
|
415
415
|
let _ = !1;
|
|
416
|
-
for (const
|
|
417
|
-
if (
|
|
418
|
-
const
|
|
419
|
-
if (
|
|
416
|
+
for (const y of S.parser.json.textures) {
|
|
417
|
+
if (y != null && y.extensions) {
|
|
418
|
+
const p = y == null ? void 0 : y.extensions[N];
|
|
419
|
+
if (p != null && p.guid && p.guid === M.guid) {
|
|
420
420
|
_ = !0;
|
|
421
421
|
break;
|
|
422
422
|
}
|
|
@@ -424,17 +424,17 @@ const O = class {
|
|
|
424
424
|
A++;
|
|
425
425
|
}
|
|
426
426
|
if (_) {
|
|
427
|
-
let
|
|
428
|
-
return
|
|
427
|
+
let y = await z.getDependency("texture", A);
|
|
428
|
+
return y && O.assignLODInformation(n.url, y, s, e, void 0, void 0), r && console.log('change "' + t.name + '" → "' + y.name + '"', h, A, y, w), t instanceof re && (y = this.copySettings(t, y)), y && (y.guid = M.guid), g(y);
|
|
429
429
|
} else
|
|
430
|
-
|
|
430
|
+
L && console.warn("Could not find texture with guid", M.guid, S.parser.json);
|
|
431
431
|
}
|
|
432
432
|
if (A = 0, S.parser.json.meshes) {
|
|
433
433
|
let _ = !1;
|
|
434
|
-
for (const
|
|
435
|
-
if (
|
|
436
|
-
const
|
|
437
|
-
if (
|
|
434
|
+
for (const y of S.parser.json.meshes) {
|
|
435
|
+
if (y != null && y.extensions) {
|
|
436
|
+
const p = y == null ? void 0 : y.extensions[N];
|
|
437
|
+
if (p != null && p.guid && p.guid === M.guid) {
|
|
438
438
|
_ = !0;
|
|
439
439
|
break;
|
|
440
440
|
}
|
|
@@ -442,34 +442,34 @@ const O = class {
|
|
|
442
442
|
A++;
|
|
443
443
|
}
|
|
444
444
|
if (_) {
|
|
445
|
-
const
|
|
446
|
-
if (r && console.log(`Loaded Mesh "${
|
|
447
|
-
const D =
|
|
448
|
-
return O.assignLODInformation(n.url, D, s, e, void 0,
|
|
445
|
+
const y = await z.getDependency("mesh", A), p = M;
|
|
446
|
+
if (r && console.log(`Loaded Mesh "${y.name}"`, h, A, y, w), y.isMesh === !0) {
|
|
447
|
+
const D = y.geometry;
|
|
448
|
+
return O.assignLODInformation(n.url, D, s, e, void 0, p.density), g(D);
|
|
449
449
|
} else {
|
|
450
450
|
const D = new Array();
|
|
451
|
-
for (let T = 0; T <
|
|
452
|
-
const
|
|
453
|
-
if (
|
|
454
|
-
const
|
|
455
|
-
O.assignLODInformation(n.url,
|
|
451
|
+
for (let T = 0; T < y.children.length; T++) {
|
|
452
|
+
const E = y.children[T];
|
|
453
|
+
if (E.isMesh === !0) {
|
|
454
|
+
const P = E.geometry;
|
|
455
|
+
O.assignLODInformation(n.url, P, s, e, T, p.density), D.push(P);
|
|
456
456
|
}
|
|
457
457
|
}
|
|
458
|
-
return
|
|
458
|
+
return g(D);
|
|
459
459
|
}
|
|
460
460
|
} else
|
|
461
|
-
|
|
461
|
+
L && console.warn("Could not find mesh with guid", M.guid, S.parser.json);
|
|
462
462
|
}
|
|
463
|
-
return
|
|
463
|
+
return g(null);
|
|
464
464
|
});
|
|
465
|
-
return this.previouslyLoaded.set(w,
|
|
465
|
+
return this.previouslyLoaded.set(w, F), await F;
|
|
466
466
|
} else if (t instanceof re) {
|
|
467
467
|
r && console.log("Load texture from uri: " + h);
|
|
468
468
|
const v = await new Ne().loadAsync(h);
|
|
469
|
-
return v ? (v.guid = i.guid, v.flipY = !1, v.needsUpdate = !0, v.colorSpace = t.colorSpace, r && console.log(i, v)) :
|
|
469
|
+
return v ? (v.guid = i.guid, v.flipY = !1, v.needsUpdate = !0, v.colorSpace = t.colorSpace, r && console.log(i, v)) : L && console.warn("failed loading", h), v;
|
|
470
470
|
}
|
|
471
471
|
} else
|
|
472
|
-
|
|
472
|
+
L && console.warn(`Can not load LOD ${e}: no LOD info found for "${s}" ${t.name}`, t.type);
|
|
473
473
|
return null;
|
|
474
474
|
}
|
|
475
475
|
static assignLODInformation(t, e, r, n, s, i) {
|
|
@@ -485,7 +485,7 @@ const O = class {
|
|
|
485
485
|
}
|
|
486
486
|
// private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
|
|
487
487
|
static copySettings(t, e) {
|
|
488
|
-
return e = e.clone(),
|
|
488
|
+
return e = e.clone(), L && console.warn(`Copying texture settings
|
|
489
489
|
`, t.uuid, `
|
|
490
490
|
`, e.uuid), e.offset = t.offset, e.repeat = t.repeat, e.colorSpace = t.colorSpace, e.magFilter = t.magFilter, e.minFilter = t.minFilter, e.wrapS = t.wrapS, e.wrapT = t.wrapT, e.flipY = t.flipY, e.anisotropy = t.anisotropy, e.mipmaps || (e.generateMipmaps = t.generateMipmaps), e;
|
|
491
491
|
}
|
|
@@ -495,11 +495,11 @@ let b = O;
|
|
|
495
495
|
* Register a texture with LOD information
|
|
496
496
|
*/
|
|
497
497
|
f(b, "registerTexture", (t, e, r, n, s) => {
|
|
498
|
-
if (
|
|
499
|
-
|
|
498
|
+
if (L && console.log("> Progressive: register texture", n, e.name, e.uuid, e, s), !e) {
|
|
499
|
+
L && console.error("gltf-progressive: Register texture without texture");
|
|
500
500
|
return;
|
|
501
501
|
}
|
|
502
|
-
e.source && (e.source[
|
|
502
|
+
e.source && (e.source[Me] = s);
|
|
503
503
|
const i = s.guid;
|
|
504
504
|
O.assignLODInformation(t, e, i, r, n, void 0), O.lodInfos.set(i, s), O.lowresCache.set(i, e);
|
|
505
505
|
}), /**
|
|
@@ -507,15 +507,15 @@ f(b, "registerTexture", (t, e, r, n, s) => {
|
|
|
507
507
|
*/
|
|
508
508
|
f(b, "registerMesh", (t, e, r, n, s, i) => {
|
|
509
509
|
var u;
|
|
510
|
-
|
|
510
|
+
L && console.log("> Progressive: register mesh", s, r.name, i, r.uuid, r);
|
|
511
511
|
const o = r.geometry;
|
|
512
512
|
if (!o) {
|
|
513
|
-
|
|
513
|
+
L && console.warn("gltf-progressive: Register mesh without geometry");
|
|
514
514
|
return;
|
|
515
515
|
}
|
|
516
516
|
o.userData || (o.userData = {}), O.assignLODInformation(t, o, e, n, s, i.density), O.lodInfos.set(e, i);
|
|
517
517
|
let l = O.lowresCache.get(e);
|
|
518
|
-
l ? l.push(r.geometry) : l = [r.geometry], O.lowresCache.set(e, l), n > 0 && !
|
|
518
|
+
l ? l.push(r.geometry) : l = [r.geometry], O.lowresCache.set(e, l), n > 0 && !me(r) && et(r, o);
|
|
519
519
|
for (const c of Y)
|
|
520
520
|
(u = c.onRegisteredNewMesh) == null || u.call(c, r, i);
|
|
521
521
|
}), /** A map of key = asset uuid and value = LOD information */
|
|
@@ -535,7 +535,7 @@ class rt {
|
|
|
535
535
|
this.url = t, this.key = e, this.level = r, n != null && (this.index = n), s != null && (this.density = s);
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
|
-
const
|
|
538
|
+
const k = ae("debugprogressive"), st = ae("noprogressive"), De = Symbol("Needle:LODSManager"), we = Symbol("Needle:LODState"), J = Symbol("Needle:CurrentLOD"), R = { mesh_lod: -1, texture_lod: -1 };
|
|
539
539
|
var B, W, pe, j, ee, ye, q;
|
|
540
540
|
const C = class {
|
|
541
541
|
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
@@ -586,7 +586,7 @@ const C = class {
|
|
|
586
586
|
}
|
|
587
587
|
/** @internal */
|
|
588
588
|
static getObjectLODState(t) {
|
|
589
|
-
return t[
|
|
589
|
+
return t[we];
|
|
590
590
|
}
|
|
591
591
|
static addPlugin(t) {
|
|
592
592
|
Y.push(t);
|
|
@@ -601,13 +601,13 @@ const C = class {
|
|
|
601
601
|
* @returns The LODsManager instance.
|
|
602
602
|
*/
|
|
603
603
|
static get(t, e) {
|
|
604
|
-
if (t[
|
|
605
|
-
return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), t[
|
|
604
|
+
if (t[De])
|
|
605
|
+
return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), t[De];
|
|
606
606
|
const r = new C(t, {
|
|
607
607
|
engine: "unknown",
|
|
608
608
|
...e
|
|
609
609
|
});
|
|
610
|
-
return t[
|
|
610
|
+
return t[De] = r, r;
|
|
611
611
|
}
|
|
612
612
|
/** @deprecated use static `LODsManager.addPlugin()` method. This getter will be removed in later versions */
|
|
613
613
|
get plugins() {
|
|
@@ -616,25 +616,31 @@ const C = class {
|
|
|
616
616
|
addEventListener(t, e) {
|
|
617
617
|
t === "changed" && this._lodchangedlisteners.push(e);
|
|
618
618
|
}
|
|
619
|
+
removeEventListener(t, e) {
|
|
620
|
+
if (t === "changed") {
|
|
621
|
+
const r = this._lodchangedlisteners.indexOf(e);
|
|
622
|
+
r >= 0 && this._lodchangedlisteners.splice(r, 1);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
619
625
|
/**
|
|
620
626
|
* Enable the LODsManager. This will replace the render method of the renderer with a method that updates the LODs.
|
|
621
627
|
*/
|
|
622
628
|
enable() {
|
|
623
|
-
if (
|
|
629
|
+
if (x(this, W))
|
|
624
630
|
return;
|
|
625
631
|
console.debug("[gltf-progressive] Enabling LODsManager for renderer");
|
|
626
632
|
let t = 0;
|
|
627
|
-
|
|
633
|
+
$(this, W, this.renderer.render);
|
|
628
634
|
const e = this;
|
|
629
635
|
Ie(this.renderer), this.renderer.render = function(r, n) {
|
|
630
636
|
const s = e.renderer.getRenderTarget();
|
|
631
|
-
(s == null || "isXRRenderTarget" in s && s.isXRRenderTarget) && (t = 0,
|
|
637
|
+
(s == null || "isXRRenderTarget" in s && s.isXRRenderTarget) && (t = 0, $(e, j, x(e, j) + 1), $(e, ee, x(e, pe).getDelta()), $(e, ye, x(e, ye) + x(e, ee)), e._fpsBuffer.shift(), e._fpsBuffer.push(1 / x(e, ee)), $(e, q, e._fpsBuffer.reduce((o, l) => o + l) / e._fpsBuffer.length), k && x(e, j) % 30 === 0 && console.log("FPS", Math.round(x(e, q)), "Interval:", x(e, B)));
|
|
632
638
|
const i = t++;
|
|
633
|
-
|
|
639
|
+
x(e, W).call(this, r, n), e.onAfterRender(r, n, i);
|
|
634
640
|
};
|
|
635
641
|
}
|
|
636
642
|
disable() {
|
|
637
|
-
|
|
643
|
+
x(this, W) && (this.renderer.render = x(this, W), $(this, W, void 0));
|
|
638
644
|
}
|
|
639
645
|
update(t, e) {
|
|
640
646
|
this.internalUpdate(t, e);
|
|
@@ -649,7 +655,7 @@ const C = class {
|
|
|
649
655
|
(o.name === "EffectMaterial" || o.name === "CopyShader") && (i = !1);
|
|
650
656
|
}
|
|
651
657
|
if ((e.parent && e.parent.type === "CubeCamera" || r >= 1 && e.type === "OrthographicCamera") && (i = !1), i) {
|
|
652
|
-
if (st || (this.updateInterval === "auto" ?
|
|
658
|
+
if (st || (this.updateInterval === "auto" ? x(this, q) < 40 && x(this, B) < 10 ? ($(this, B, x(this, B) + 1), k && console.warn("↓ Reducing LOD updates", x(this, B), x(this, q).toFixed(0))) : x(this, q) >= 60 && x(this, B) > 1 && ($(this, B, x(this, B) - 1), k && console.warn("↑ Increasing LOD updates", x(this, B), x(this, q).toFixed(0))) : $(this, B, this.updateInterval), x(this, B) > 0 && x(this, j) % x(this, B) != 0))
|
|
653
659
|
return;
|
|
654
660
|
this.internalUpdate(t, e);
|
|
655
661
|
}
|
|
@@ -664,7 +670,7 @@ const C = class {
|
|
|
664
670
|
const s = this.targetTriangleDensity;
|
|
665
671
|
for (const c of n) {
|
|
666
672
|
if (c.material && (((l = c.geometry) == null ? void 0 : l.type) === "BoxGeometry" || ((u = c.geometry) == null ? void 0 : u.type) === "BufferGeometry") && (c.material.name === "SphericalGaussianBlur" || c.material.name == "BackgroundCubeMaterial" || c.material.name === "CubemapFromEquirect" || c.material.name === "EquirectangularToCubeUV")) {
|
|
667
|
-
|
|
673
|
+
k && (c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] || (c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] = !0, console.warn("Ignoring skybox or BLIT object", c, c.material.name, c.material.type)));
|
|
668
674
|
continue;
|
|
669
675
|
}
|
|
670
676
|
switch (c.material.type) {
|
|
@@ -676,7 +682,7 @@ const C = class {
|
|
|
676
682
|
case "MeshDepthMaterial":
|
|
677
683
|
continue;
|
|
678
684
|
}
|
|
679
|
-
if (
|
|
685
|
+
if (k === "color" && c.material && !c.object.progressive_debug_color) {
|
|
680
686
|
c.object.progressive_debug_color = !0;
|
|
681
687
|
const h = Math.random() * 16777215, w = new Xe({ color: h });
|
|
682
688
|
c.object.material = w;
|
|
@@ -699,20 +705,20 @@ const C = class {
|
|
|
699
705
|
updateLODs(t, e, r, n) {
|
|
700
706
|
var o, l;
|
|
701
707
|
r.userData || (r.userData = {});
|
|
702
|
-
let s = r[
|
|
703
|
-
if (s || (s = new it(), r[
|
|
708
|
+
let s = r[we];
|
|
709
|
+
if (s || (s = new it(), r[we] = s), s.frames++ < 2)
|
|
704
710
|
return;
|
|
705
711
|
for (const u of Y)
|
|
706
712
|
(o = u.onBeforeUpdateLOD) == null || o.call(u, this.renderer, t, e, r);
|
|
707
|
-
this.calculateLodLevel(e, r, s, n,
|
|
708
|
-
let i =
|
|
713
|
+
this.calculateLodLevel(e, r, s, n, R), R.mesh_lod = Math.round(R.mesh_lod), R.texture_lod = Math.round(R.texture_lod), R.mesh_lod >= 0 && this.loadProgressiveMeshes(r, R.mesh_lod);
|
|
714
|
+
let i = R.texture_lod;
|
|
709
715
|
if (r.material && i >= 0) {
|
|
710
716
|
const u = r["DEBUG:LOD"];
|
|
711
717
|
u != null && (i = u), this.loadProgressiveTextures(r.material, i);
|
|
712
718
|
}
|
|
713
719
|
for (const u of Y)
|
|
714
|
-
(l = u.onAfterUpdatedLOD) == null || l.call(u, this.renderer, t, e, r,
|
|
715
|
-
s.lastLodLevel_Mesh =
|
|
720
|
+
(l = u.onAfterUpdatedLOD) == null || l.call(u, this.renderer, t, e, r, R);
|
|
721
|
+
s.lastLodLevel_Mesh = R.mesh_lod, s.lastLodLevel_Texture = R.texture_lod;
|
|
716
722
|
}
|
|
717
723
|
/** Load progressive textures for the given material
|
|
718
724
|
* @param material the material to load the textures for
|
|
@@ -753,7 +759,7 @@ const C = class {
|
|
|
753
759
|
return this._tempPtInside.set(s, i, r.z).applyMatrix4(e).z < 0;
|
|
754
760
|
}
|
|
755
761
|
calculateLodLevel(t, e, r, n, s) {
|
|
756
|
-
var
|
|
762
|
+
var F, U;
|
|
757
763
|
if (!e) {
|
|
758
764
|
s.mesh_lod = -1, s.texture_lod = -1;
|
|
759
765
|
return;
|
|
@@ -763,29 +769,35 @@ const C = class {
|
|
|
763
769
|
return;
|
|
764
770
|
}
|
|
765
771
|
let o = 10 + 1, l = !1;
|
|
766
|
-
if (
|
|
772
|
+
if (k && e["DEBUG:LOD"] != null)
|
|
767
773
|
return e["DEBUG:LOD"];
|
|
768
774
|
const u = b.getMeshLODInformation(e.geometry), c = u == null ? void 0 : u.lods, d = c && c.length > 0, h = b.getMaterialMinMaxLODsCount(e.material), w = (h == null ? void 0 : h.min_count) != 1 / 0 && h.min_count > 0 && h.max_count > 0;
|
|
769
775
|
if (!d && !w) {
|
|
770
776
|
s.mesh_lod = 0, s.texture_lod = 0;
|
|
771
777
|
return;
|
|
772
778
|
}
|
|
773
|
-
if (d || (l = !0, o = 0), !((
|
|
774
|
-
s.mesh_lod =
|
|
779
|
+
if (d || (l = !0, o = 0), !((F = this.cameraFrustrum) != null && F.intersectsObject(e))) {
|
|
780
|
+
s.mesh_lod = 100, s.texture_lod = 100;
|
|
775
781
|
return;
|
|
776
782
|
}
|
|
777
783
|
const v = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
|
|
778
784
|
let M = e.geometry.boundingBox;
|
|
779
785
|
if (e.type === "SkinnedMesh") {
|
|
780
|
-
const
|
|
781
|
-
|
|
786
|
+
const g = e;
|
|
787
|
+
if (!g.boundingBox)
|
|
788
|
+
g.computeBoundingBox();
|
|
789
|
+
else if (r.frames % 30 === 0) {
|
|
790
|
+
const m = me(g), I = g.geometry;
|
|
791
|
+
m && (g.geometry = m), g.computeBoundingBox(), g.geometry = I;
|
|
792
|
+
}
|
|
793
|
+
M = g.boundingBox;
|
|
782
794
|
}
|
|
783
795
|
if (M && t.isPerspectiveCamera) {
|
|
784
|
-
const
|
|
796
|
+
const g = t;
|
|
785
797
|
if (e.geometry.attributes.color && e.geometry.attributes.color.count < 100 && e.geometry.boundingSphere) {
|
|
786
798
|
this._sphere.copy(e.geometry.boundingSphere), this._sphere.applyMatrix4(e.matrixWorld);
|
|
787
|
-
const
|
|
788
|
-
if (this._sphere.containsPoint(
|
|
799
|
+
const p = t.getWorldPosition(this._tempWorldPosition);
|
|
800
|
+
if (this._sphere.containsPoint(p)) {
|
|
789
801
|
s.mesh_lod = 0, s.texture_lod = 0;
|
|
790
802
|
return;
|
|
791
803
|
}
|
|
@@ -794,61 +806,61 @@ const C = class {
|
|
|
794
806
|
s.mesh_lod = 0, s.texture_lod = 0;
|
|
795
807
|
return;
|
|
796
808
|
}
|
|
797
|
-
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled &&
|
|
798
|
-
const
|
|
799
|
-
let T =
|
|
800
|
-
const le = 2,
|
|
801
|
-
T = (T - ce) * le + ce,
|
|
802
|
-
const Fe = T < 0 &&
|
|
803
|
-
r.lastCentrality = (
|
|
809
|
+
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && g.fov > 70) {
|
|
810
|
+
const p = this._tempBox.min, D = this._tempBox.max;
|
|
811
|
+
let T = p.x, E = p.y, P = D.x, te = D.y;
|
|
812
|
+
const le = 2, xe = 1.5, ce = (p.x + D.x) * 0.5, ue = (p.y + D.y) * 0.5;
|
|
813
|
+
T = (T - ce) * le + ce, E = (E - ue) * le + ue, P = (P - ce) * le + ce, te = (te - ue) * le + ue;
|
|
814
|
+
const Fe = T < 0 && P > 0 ? 0 : Math.min(Math.abs(p.x), Math.abs(D.x)), $e = E < 0 && te > 0 ? 0 : Math.min(Math.abs(p.y), Math.abs(D.y)), Le = Math.max(Fe, $e);
|
|
815
|
+
r.lastCentrality = (xe - Le) * (xe - Le) * (xe - Le);
|
|
804
816
|
} else
|
|
805
817
|
r.lastCentrality = 1;
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
const
|
|
809
|
-
X.copy(M), X.applyMatrix4(e.matrixWorld), X.applyMatrix4(
|
|
818
|
+
const m = this._tempBox.getSize(this._tempBoxSize);
|
|
819
|
+
m.multiplyScalar(0.5), screen.availHeight > 0 && v > 0 && m.multiplyScalar(v / screen.availHeight), m.x *= g.aspect;
|
|
820
|
+
const I = t.matrixWorldInverse, X = this._tempBox2;
|
|
821
|
+
X.copy(M), X.applyMatrix4(e.matrixWorld), X.applyMatrix4(I);
|
|
810
822
|
const S = X.getSize(this._tempBox2Size), z = Math.max(S.x, S.y);
|
|
811
|
-
if (Math.max(
|
|
812
|
-
const
|
|
813
|
-
|
|
814
|
-
const D = C.corner0, T = C.corner1,
|
|
815
|
-
D.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = D.x,
|
|
816
|
-
const te = (D.z +
|
|
817
|
-
D.z = T.z =
|
|
823
|
+
if (Math.max(m.x, m.y) != 0 && z != 0 && (m.z = S.z / Math.max(S.x, S.y) * Math.max(m.x, m.y)), r.lastScreenCoverage = Math.max(m.x, m.y, m.z), r.lastScreenspaceVolume.copy(m), r.lastScreenCoverage *= r.lastCentrality, k && C.debugDrawLine) {
|
|
824
|
+
const p = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
825
|
+
p.invert();
|
|
826
|
+
const D = C.corner0, T = C.corner1, E = C.corner2, P = C.corner3;
|
|
827
|
+
D.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = D.x, E.copy(this._tempBox.max), E.y = D.y, P.copy(this._tempBox.max);
|
|
828
|
+
const te = (D.z + P.z) * 0.5;
|
|
829
|
+
D.z = T.z = E.z = P.z = te, D.applyMatrix4(p), T.applyMatrix4(p), E.applyMatrix4(p), P.applyMatrix4(p), C.debugDrawLine(D, T, 255), C.debugDrawLine(D, E, 255), C.debugDrawLine(T, P, 255), C.debugDrawLine(E, P, 255);
|
|
818
830
|
}
|
|
819
831
|
let _ = 999;
|
|
820
832
|
if (c && r.lastScreenCoverage > 0) {
|
|
821
|
-
for (let
|
|
822
|
-
if (c[
|
|
823
|
-
_ =
|
|
833
|
+
for (let p = 0; p < c.length; p++)
|
|
834
|
+
if (c[p].density / r.lastScreenCoverage < n) {
|
|
835
|
+
_ = p;
|
|
824
836
|
break;
|
|
825
837
|
}
|
|
826
838
|
}
|
|
827
839
|
_ < o && (o = _, l = !0);
|
|
828
840
|
}
|
|
829
|
-
if (l ? s.mesh_lod = o : s.mesh_lod = r.lastLodLevel_Mesh,
|
|
830
|
-
const
|
|
831
|
-
|
|
841
|
+
if (l ? s.mesh_lod = o : s.mesh_lod = r.lastLodLevel_Mesh, k && s.mesh_lod != r.lastLodLevel_Mesh) {
|
|
842
|
+
const m = c == null ? void 0 : c[s.mesh_lod];
|
|
843
|
+
m && console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${s.mesh_lod} (${m.density.toFixed(0)}) - ${e.name}`);
|
|
832
844
|
}
|
|
833
845
|
if (w) {
|
|
834
|
-
const
|
|
846
|
+
const g = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
|
|
835
847
|
if (r.lastLodLevel_Texture < 0) {
|
|
836
|
-
if (s.texture_lod = h.max_count - 1,
|
|
837
|
-
const
|
|
838
|
-
|
|
848
|
+
if (s.texture_lod = h.max_count - 1, k) {
|
|
849
|
+
const m = h.lods[h.max_count - 1];
|
|
850
|
+
k && console.log(`First Texture LOD ${s.texture_lod} (${m.max_height}px) - ${e.name}`);
|
|
839
851
|
}
|
|
840
852
|
} else {
|
|
841
|
-
const
|
|
842
|
-
let
|
|
843
|
-
((
|
|
844
|
-
const S = v / window.devicePixelRatio *
|
|
853
|
+
const m = r.lastScreenspaceVolume.x + r.lastScreenspaceVolume.y + r.lastScreenspaceVolume.z;
|
|
854
|
+
let I = r.lastScreenCoverage * 2;
|
|
855
|
+
((U = this.context) == null ? void 0 : U.engine) === "model-viewer" && (I *= 2);
|
|
856
|
+
const S = v / window.devicePixelRatio * I;
|
|
845
857
|
for (let z = h.lods.length - 1; z >= 0; z--) {
|
|
846
858
|
let A = h.lods[z];
|
|
847
|
-
if (!(
|
|
859
|
+
if (!(g && A.max_height >= 2048) && !(je() && A.max_height > 4096) && A.max_height > S) {
|
|
848
860
|
if (s.texture_lod = z, s.texture_lod < r.lastLodLevel_Texture) {
|
|
849
861
|
const _ = A.max_height;
|
|
850
|
-
|
|
851
|
-
Screensize: ${S.toFixed(0)}px, Coverage: ${(100 * r.lastScreenCoverage).toFixed(2)}%, Volume ${
|
|
862
|
+
k && console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${s.texture_lod} = ${_}px
|
|
863
|
+
Screensize: ${S.toFixed(0)}px, Coverage: ${(100 * r.lastScreenCoverage).toFixed(2)}%, Volume ${m.toFixed(1)}
|
|
852
864
|
${e.name}`);
|
|
853
865
|
}
|
|
854
866
|
break;
|
|
@@ -859,10 +871,10 @@ ${e.name}`);
|
|
|
859
871
|
s.texture_lod = 0;
|
|
860
872
|
}
|
|
861
873
|
};
|
|
862
|
-
let
|
|
874
|
+
let G = C;
|
|
863
875
|
B = new WeakMap(), W = new WeakMap(), pe = new WeakMap(), j = new WeakMap(), ee = new WeakMap(), ye = new WeakMap(), q = new WeakMap(), /** Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
|
|
864
876
|
*/
|
|
865
|
-
f(
|
|
877
|
+
f(G, "debugDrawLine"), f(G, "corner0", new V()), f(G, "corner1", new V()), f(G, "corner2", new V()), f(G, "corner3", new V()), f(G, "_tempPtInside", new V());
|
|
866
878
|
class it {
|
|
867
879
|
constructor() {
|
|
868
880
|
f(this, "frames", 0);
|
|
@@ -873,13 +885,13 @@ class it {
|
|
|
873
885
|
f(this, "lastCentrality", 0);
|
|
874
886
|
}
|
|
875
887
|
}
|
|
876
|
-
const
|
|
888
|
+
const Ee = Symbol("NEEDLE_mesh_lod"), fe = Symbol("NEEDLE_texture_lod");
|
|
877
889
|
let ne = null;
|
|
878
890
|
function Re() {
|
|
879
891
|
const a = nt();
|
|
880
892
|
a && (a.mapURLs(function(t) {
|
|
881
|
-
return
|
|
882
|
-
}),
|
|
893
|
+
return Pe(), t;
|
|
894
|
+
}), Pe(), ne == null || ne.disconnect(), ne = new MutationObserver((t) => {
|
|
883
895
|
t.forEach((e) => {
|
|
884
896
|
e.addedNodes.forEach((r) => {
|
|
885
897
|
r instanceof HTMLElement && r.tagName.toLowerCase() === "model-viewer" && Ge(r);
|
|
@@ -893,7 +905,7 @@ function nt() {
|
|
|
893
905
|
console.debug("[gltf-progressive] model-viewer defined"), Re();
|
|
894
906
|
}), null);
|
|
895
907
|
}
|
|
896
|
-
function
|
|
908
|
+
function Pe() {
|
|
897
909
|
document.querySelectorAll("model-viewer").forEach((t) => {
|
|
898
910
|
Ge(t);
|
|
899
911
|
});
|
|
@@ -923,8 +935,8 @@ function Ge(a) {
|
|
|
923
935
|
}
|
|
924
936
|
};
|
|
925
937
|
console.debug("[gltf-progressive] setup model-viewer");
|
|
926
|
-
const s =
|
|
927
|
-
return
|
|
938
|
+
const s = G.get(t, { engine: "model-viewer" });
|
|
939
|
+
return G.addPlugin(new at()), s.enable(), s.addEventListener("changed", () => {
|
|
928
940
|
r == null || r.call(a);
|
|
929
941
|
}), a.addEventListener("model-visibility", (i) => {
|
|
930
942
|
i.detail.visible && (r == null || r.call(a));
|
|
@@ -970,17 +982,17 @@ class at {
|
|
|
970
982
|
for (let w = 0; w < u.length; w++) {
|
|
971
983
|
const v = u[w], M = l[v];
|
|
972
984
|
if ((M == null ? void 0 : M.isTexture) === !0) {
|
|
973
|
-
const
|
|
974
|
-
if (
|
|
985
|
+
const F = (d = (c = M.userData) == null ? void 0 : c.associations) == null ? void 0 : d.textures;
|
|
986
|
+
if (F == null)
|
|
975
987
|
continue;
|
|
976
|
-
const
|
|
977
|
-
if (
|
|
978
|
-
console.warn("Texture data not found for texture index " +
|
|
988
|
+
const U = r.parser.json.textures[F];
|
|
989
|
+
if (!U) {
|
|
990
|
+
console.warn("Texture data not found for texture index " + F);
|
|
979
991
|
continue;
|
|
980
992
|
}
|
|
981
|
-
if ((h =
|
|
982
|
-
const
|
|
983
|
-
|
|
993
|
+
if ((h = U == null ? void 0 : U.extensions) != null && h[N]) {
|
|
994
|
+
const g = U.extensions[N];
|
|
995
|
+
g && s && b.registerTexture(s, M, g.lods.length, F, g);
|
|
984
996
|
}
|
|
985
997
|
}
|
|
986
998
|
}
|
|
@@ -995,9 +1007,9 @@ class at {
|
|
|
995
1007
|
}
|
|
996
1008
|
tryParseMeshLOD(t, e) {
|
|
997
1009
|
var i, o;
|
|
998
|
-
if (e[
|
|
1010
|
+
if (e[Ee] == !0)
|
|
999
1011
|
return;
|
|
1000
|
-
e[
|
|
1012
|
+
e[Ee] = !0;
|
|
1001
1013
|
const r = this.tryGetCurrentModelViewer(t), n = this.getUrl(r);
|
|
1002
1014
|
if (!n)
|
|
1003
1015
|
return;
|
|
@@ -1010,18 +1022,18 @@ class at {
|
|
|
1010
1022
|
}
|
|
1011
1023
|
function mt(a, t, e, r) {
|
|
1012
1024
|
Ie(t), ke(e), e.register((s) => new b(s, a));
|
|
1013
|
-
const n =
|
|
1025
|
+
const n = G.get(t);
|
|
1014
1026
|
return (r == null ? void 0 : r.enableLODsManager) !== !1 && n.enable(), n;
|
|
1015
1027
|
}
|
|
1016
1028
|
Re();
|
|
1017
1029
|
export {
|
|
1018
1030
|
N as EXTENSION_NAME,
|
|
1019
|
-
|
|
1031
|
+
G as LODsManager,
|
|
1020
1032
|
b as NEEDLE_progressive,
|
|
1021
1033
|
Be as VERSION,
|
|
1022
1034
|
ke as addDracoAndKTX2Loaders,
|
|
1023
1035
|
Ie as createLoaders,
|
|
1024
|
-
|
|
1036
|
+
me as getRaycastMesh,
|
|
1025
1037
|
Re as patchModelViewer,
|
|
1026
1038
|
et as registerRaycastMesh,
|
|
1027
1039
|
gt as setDracoDecoderLocation,
|
package/gltf-progressive.min.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var Re=Object.defineProperty,Ge=(t,e,r)=>e in t?Re(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,c=(t,e,r)=>(Ge(t,typeof e!="symbol"?e+"":e,r),r),be=(t,e,r)=>{if(!e.has(t))throw TypeError("Cannot "+r)},x=(t,e,r)=>(be(t,e,"read from private field"),r?r.call(t):e.get(t)),q=(t,e,r)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,r)},F=(t,e,r,n)=>(be(t,e,"write to private field"),n?n.call(t,r):e.set(t,r),r);import{BufferGeometry as ne,Mesh as X,Material as Fe,Texture as Q,TextureLoader as We,Matrix4 as Se,Frustum as Ne,Clock as $e,MeshStandardMaterial as Ue,Sphere as ze,Box3 as Te,Vector3 as W}from"three";import{GLTFLoader as Ve}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as qe}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Xe}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Ke}from"three/examples/jsm/loaders/KTX2Loader.js";const me="";globalThis.GLTF_PROGRESSIVE_VERSION=me,console.debug(`[gltf-progressive] version ${me}`);let ie="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",pe="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(ie+"draco_decoder.js",{method:"head"}).catch(t=>{ie="./include/draco/",pe="./include/ktx2/"});function He(t){ie=t}function Ye(t){pe=t}let K,le,H;function ve(t){return K||(K=new Xe,K.setDecoderPath(ie),K.setDecoderConfig({type:"js"})),H||(H=new Ke,H.setTranscoderPath(pe)),le||(le=qe),t?H.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:K,ktx2Loader:H,meshoptDecoder:le}}function xe(t){t.dracoLoader||t.setDRACOLoader(K),t.ktx2Loader||t.setKTX2Loader(H),t.meshoptDecoder||t.setMeshoptDecoder(le)}Z("debugprogressive");function Z(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Je(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const r=t.lastIndexOf("/");if(r>=0){const n=t.substring(0,r+1);for(;n.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return n+e}return e}let ae;function Qe(){return ae!==void 0||(ae=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),Z("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ae)),ae}const ye=Symbol("needle:raycast-mesh");function ue(t){return t?.[ye]instanceof ne?t[ye]:null}function Ee(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!ue(t)){const r=et(e);r.userData={isRaycastMesh:!0},t[ye]=r}}function Ze(t=!0){if(t){if(ee)return;const e=ee=X.prototype.raycast;X.prototype.raycast=function(r,n){const s=this,o=ue(s);let i;o&&s.isMesh&&(i=s.geometry,s.geometry=o),e.call(this,r,n),i&&(s.geometry=i)}}else{if(!ee)return;X.prototype.raycast=ee,ee=null}}let ee=null;function et(t){const e=new ne;for(const r in t.attributes)e.setAttribute(r,t.getAttribute(r));return e.setIndex(t.getIndex()),e}const $=new Array,j="NEEDLE_progressive",y=Z("debugprogressive"),Le=Symbol("needle-progressive-texture"),te=new Map,Me=new Set;if(y){let t=function(){e+=1,console.log("Toggle LOD level",e,te),te.forEach((s,o)=>{for(const i of s.keys){const l=o[i];if(l!=null){if(l.isBufferGeometry===!0){const u=O.getMeshLODInformation(l),a=u?Math.min(e,u.lods.length):0;o["DEBUG:LOD"]=e,O.assignMeshLOD(o,a),u&&(r=Math.max(r,u.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,O.assignTextureLOD(o,e);break}}}}),e>=r&&(e=-1)},e=-1,r=2,n=!1;window.addEventListener("keyup",s=>{s.key==="p"&&t(),s.key==="w"&&(n=!n,Me&&Me.forEach(o=>{o.name!="BackgroundCubeMaterial"&&o.glyphMap==null&&"wireframe"in o&&(o.wireframe=n)}))})}function Ae(t,e,r){var n;if(!y)return;te.has(t)||te.set(t,{keys:[],sourceId:r});const s=te.get(t);((n=s?.keys)==null?void 0:n.includes(e))==!1&&s.keys.push(e)}const D=class{constructor(t,e){c(this,"parser"),c(this,"url"),c(this,"_isLoadingMesh"),c(this,"loadMesh",r=>{var n,s;if(this._isLoadingMesh)return null;const o=(s=(n=this.parser.json.meshes[r])==null?void 0:n.extensions)==null?void 0:s[j];return o?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",r).then(i=>{var l;return this._isLoadingMesh=!1,i&&D.registerMesh(this.url,o.guid,i,(l=o.lods)==null?void 0:l.length,void 0,o),i})):null}),y&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return j}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const r=this,n="LODS:minmax",s=t[n];if(s!=null)return s;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const i of t)this.getMaterialMinMaxLODsCount(i,e);return t[n]=e,e}if(y==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const l of Object.keys(i.uniforms)){const u=i.uniforms[l].value;u?.isTexture===!0&&o(u,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const l=t[i];l?.isTexture===!0&&o(l,e)}return t[n]=e,e;function o(i,l){const u=r.getAssignedLODInformation(i);if(u){const a=r.lodInfos.get(u.key);if(a&&a.lods){l.min_count=Math.min(l.min_count,a.lods.length),l.max_count=Math.max(l.max_count,a.lods.length);for(let h=0;h<a.lods.length;h++){const v=a.lods[h];v.width&&(l.lods[h]=l.lods[h]||{min_height:1/0,max_height:0},l.lods[h].min_height=Math.min(l.lods[h].min_height,v.height),l.lods[h].max_height=Math.max(l.lods[h].max_height,v.height))}}}}}static hasLODLevelAvailable(t,e){var r;if(Array.isArray(t)){for(const o of t)if(this.hasLODLevelAvailable(o,e))return!0;return!1}if(t.isMaterial===!0){for(const o of Object.keys(t)){const i=t[o];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const o of t.children)if(o.isMesh===!0&&this.hasLODLevelAvailable(o,e))return!0}let n,s;if(t.isMesh?n=t.geometry:(t.isBufferGeometry||t.isTexture)&&(n=t),n&&(r=n?.userData)!=null&&r.LODS){const o=n.userData.LODS;if(s=this.lodInfos.get(o.key),e===void 0)return s!=null;if(s)return Array.isArray(s.lods)?e<s.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof X||t.isMesh===!0){const n=t.geometry,s=this.getAssignedLODInformation(n);if(!s)return Promise.resolve(null);for(const o of $)(r=o.onBeforeGetLODMesh)==null||r.call(o,t,e);return t["LOD:requested level"]=e,D.getOrLoadLOD(n,e).then(o=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(o)){const i=s.index||0;o=o[i]}o&&n!=o&&(o?.isBufferGeometry?(t.geometry=o,y&&Ae(t,"geometry",s.url)):y&&console.error("Invalid LOD geometry",o))}return o}).catch(o=>(console.error("Error loading mesh LOD",t,o),null))}else y&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof Fe||t.isMaterial===!0){const r=t,n=[],s=new Array;if(y&&Me.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const o=r;for(const i of Object.keys(o.uniforms)){const l=o.uniforms[i].value;if(l?.isTexture===!0){const u=this.assignTextureLODForSlot(l,e,r,i);n.push(u),s.push(i)}}}else for(const o of Object.keys(r)){const i=r[o];if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,r,o);n.push(l),s.push(o)}}return Promise.all(n).then(o=>{const i=new Array;for(let l=0;l<o.length;l++){const u=o[l],a=s[l];u&&u.isTexture===!0?i.push({material:r,slot:a,texture:u,level:e}):i.push({material:r,slot:a,texture:null,level:e})}return i})}if(t instanceof Q||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,n){return t?.isTexture!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):D.getOrLoadLOD(t,e).then(s=>{if(Array.isArray(s))return null;if(s?.isTexture===!0){if(s!=t){if(r&&n){const o=r[n];if(o){const i=this.getAssignedLODInformation(o);if(i&&i?.level<e)return y==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,r,o,s),null}r[n]=s}if(y&&n&&r){const o=this.getAssignedLODInformation(t);o&&Ae(r,n,o.url)}}return s}else y=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(s=>(console.error("Error loading LOD",t,s),null))}afterRoot(t){var e,r;return y&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((n,s)=>{var o;if(n!=null&&n.extensions){const i=n?.extensions[j];if(i){if(!i.lods){y&&console.warn("Texture has no LODs",i);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const a=this.parser.associations.get(u);a?.textures===s&&(l=!0,D.registerTexture(this.url,u,(o=i.lods)==null?void 0:o.length,s,i))}l||this.parser.getDependency("texture",s).then(u=>{var a;u&&D.registerTexture(this.url,u,(a=i.lods)==null?void 0:a.length,s,i)})}}}),(r=this.parser.json.meshes)==null||r.forEach((n,s)=>{if(n!=null&&n.extensions){const o=n?.extensions[j];if(o&&o.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l?.meshes===s&&D.registerMesh(this.url,o.guid,i,o.lods.length,l.primitives,o)}}}}),null}static async getOrLoadLOD(t,e){var r,n,s,o;const i=y=="verbose",l=t.userData.LODS;if(!l)return null;const u=l?.key;let a;if(t.isTexture===!0){const h=t;h.source&&h.source[Le]&&(a=h.source[Le])}if(a||(a=D.lodInfos.get(u)),a){if(e>0){let g=!1;const A=Array.isArray(a.lods);if(A&&e>=a.lods.length?g=!0:A||(g=!0),g)return this.lowresCache.get(u)}const h=Array.isArray(a.lods)?(r=a.lods[e])==null?void 0:r.path:a.lods;if(!h)return y&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const v=Je(l.url,h);if(v.endsWith(".glb")||v.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const g=v+"_"+a.guid,A=this.previouslyLoaded.get(g);if(A!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${g}`);let m=await A.catch(T=>(console.error(`Error loading LOD ${e} from ${v}
|
|
2
|
-
`,
|
|
3
|
-
`,
|
|
1
|
+
var Re=Object.defineProperty,Fe=(t,e,r)=>e in t?Re(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,c=(t,e,r)=>(Fe(t,typeof e!="symbol"?e+"":e,r),r),be=(t,e,r)=>{if(!e.has(t))throw TypeError("Cannot "+r)},x=(t,e,r)=>(be(t,e,"read from private field"),r?r.call(t):e.get(t)),q=(t,e,r)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,r)},G=(t,e,r,n)=>(be(t,e,"write to private field"),n?n.call(t,r):e.set(t,r),r);import{BufferGeometry as ie,Mesh as X,Material as Ge,Texture as Q,TextureLoader as We,Matrix4 as Se,Frustum as Ne,Clock as $e,MeshStandardMaterial as Ue,Sphere as ze,Box3 as Te,Vector3 as W}from"three";import{GLTFLoader as Ve}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as qe}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Xe}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Ke}from"three/examples/jsm/loaders/KTX2Loader.js";const me="";globalThis.GLTF_PROGRESSIVE_VERSION=me,console.debug(`[gltf-progressive] version ${me}`);let le="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",pe="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(le+"draco_decoder.js",{method:"head"}).catch(t=>{le="./include/draco/",pe="./include/ktx2/"});function He(t){le=t}function Ye(t){pe=t}let K,ae,H;function ve(t){return K||(K=new Xe,K.setDecoderPath(le),K.setDecoderConfig({type:"js"})),H||(H=new Ke,H.setTranscoderPath(pe)),ae||(ae=qe),t?H.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:K,ktx2Loader:H,meshoptDecoder:ae}}function xe(t){t.dracoLoader||t.setDRACOLoader(K),t.ktx2Loader||t.setKTX2Loader(H),t.meshoptDecoder||t.setMeshoptDecoder(ae)}Z("debugprogressive");function Z(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Je(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const r=t.lastIndexOf("/");if(r>=0){const n=t.substring(0,r+1);for(;n.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return n+e}return e}let ue;function Qe(){return ue!==void 0||(ue=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),Z("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ue)),ue}const ye=Symbol("needle:raycast-mesh");function ee(t){return t?.[ye]instanceof ie?t[ye]:null}function Ee(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!ee(t)){const r=et(e);r.userData={isRaycastMesh:!0},t[ye]=r}}function Ze(t=!0){if(t){if(te)return;const e=te=X.prototype.raycast;X.prototype.raycast=function(r,n){const s=this,o=ee(s);let i;o&&s.isMesh&&(i=s.geometry,s.geometry=o),e.call(this,r,n),i&&(s.geometry=i)}}else{if(!te)return;X.prototype.raycast=te,te=null}}let te=null;function et(t){const e=new ie;for(const r in t.attributes)e.setAttribute(r,t.getAttribute(r));return e.setIndex(t.getIndex()),e}const $=new Array,j="NEEDLE_progressive",y=Z("debugprogressive"),Le=Symbol("needle-progressive-texture"),re=new Map,Me=new Set;if(y){let t=function(){e+=1,console.log("Toggle LOD level",e,re),re.forEach((s,o)=>{for(const i of s.keys){const l=o[i];if(l!=null){if(l.isBufferGeometry===!0){const u=O.getMeshLODInformation(l),a=u?Math.min(e,u.lods.length):0;o["DEBUG:LOD"]=e,O.assignMeshLOD(o,a),u&&(r=Math.max(r,u.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,O.assignTextureLOD(o,e);break}}}}),e>=r&&(e=-1)},e=-1,r=2,n=!1;window.addEventListener("keyup",s=>{s.key==="p"&&t(),s.key==="w"&&(n=!n,Me&&Me.forEach(o=>{o.name!="BackgroundCubeMaterial"&&o.glyphMap==null&&"wireframe"in o&&(o.wireframe=n)}))})}function Ae(t,e,r){var n;if(!y)return;re.has(t)||re.set(t,{keys:[],sourceId:r});const s=re.get(t);((n=s?.keys)==null?void 0:n.includes(e))==!1&&s.keys.push(e)}const D=class{constructor(t,e){c(this,"parser"),c(this,"url"),c(this,"_isLoadingMesh"),c(this,"loadMesh",r=>{var n,s;if(this._isLoadingMesh)return null;const o=(s=(n=this.parser.json.meshes[r])==null?void 0:n.extensions)==null?void 0:s[j];return o?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",r).then(i=>{var l;return this._isLoadingMesh=!1,i&&D.registerMesh(this.url,o.guid,i,(l=o.lods)==null?void 0:l.length,void 0,o),i})):null}),y&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return j}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const r=this,n="LODS:minmax",s=t[n];if(s!=null)return s;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const i of t)this.getMaterialMinMaxLODsCount(i,e);return t[n]=e,e}if(y==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const l of Object.keys(i.uniforms)){const u=i.uniforms[l].value;u?.isTexture===!0&&o(u,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const l=t[i];l?.isTexture===!0&&o(l,e)}return t[n]=e,e;function o(i,l){const u=r.getAssignedLODInformation(i);if(u){const a=r.lodInfos.get(u.key);if(a&&a.lods){l.min_count=Math.min(l.min_count,a.lods.length),l.max_count=Math.max(l.max_count,a.lods.length);for(let h=0;h<a.lods.length;h++){const v=a.lods[h];v.width&&(l.lods[h]=l.lods[h]||{min_height:1/0,max_height:0},l.lods[h].min_height=Math.min(l.lods[h].min_height,v.height),l.lods[h].max_height=Math.max(l.lods[h].max_height,v.height))}}}}}static hasLODLevelAvailable(t,e){var r;if(Array.isArray(t)){for(const o of t)if(this.hasLODLevelAvailable(o,e))return!0;return!1}if(t.isMaterial===!0){for(const o of Object.keys(t)){const i=t[o];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const o of t.children)if(o.isMesh===!0&&this.hasLODLevelAvailable(o,e))return!0}let n,s;if(t.isMesh?n=t.geometry:(t.isBufferGeometry||t.isTexture)&&(n=t),n&&(r=n?.userData)!=null&&r.LODS){const o=n.userData.LODS;if(s=this.lodInfos.get(o.key),e===void 0)return s!=null;if(s)return Array.isArray(s.lods)?e<s.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof X||t.isMesh===!0){const n=t.geometry,s=this.getAssignedLODInformation(n);if(!s)return Promise.resolve(null);for(const o of $)(r=o.onBeforeGetLODMesh)==null||r.call(o,t,e);return t["LOD:requested level"]=e,D.getOrLoadLOD(n,e).then(o=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(o)){const i=s.index||0;o=o[i]}o&&n!=o&&(o?.isBufferGeometry?(t.geometry=o,y&&Ae(t,"geometry",s.url)):y&&console.error("Invalid LOD geometry",o))}return o}).catch(o=>(console.error("Error loading mesh LOD",t,o),null))}else y&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof Ge||t.isMaterial===!0){const r=t,n=[],s=new Array;if(y&&Me.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const o=r;for(const i of Object.keys(o.uniforms)){const l=o.uniforms[i].value;if(l?.isTexture===!0){const u=this.assignTextureLODForSlot(l,e,r,i);n.push(u),s.push(i)}}}else for(const o of Object.keys(r)){const i=r[o];if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,r,o);n.push(l),s.push(o)}}return Promise.all(n).then(o=>{const i=new Array;for(let l=0;l<o.length;l++){const u=o[l],a=s[l];u&&u.isTexture===!0?i.push({material:r,slot:a,texture:u,level:e}):i.push({material:r,slot:a,texture:null,level:e})}return i})}if(t instanceof Q||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,n){return t?.isTexture!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):D.getOrLoadLOD(t,e).then(s=>{if(Array.isArray(s))return null;if(s?.isTexture===!0){if(s!=t){if(r&&n){const o=r[n];if(o){const i=this.getAssignedLODInformation(o);if(i&&i?.level<e)return y==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,r,o,s),null}r[n]=s}if(y&&n&&r){const o=this.getAssignedLODInformation(t);o&&Ae(r,n,o.url)}}return s}else y=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(s=>(console.error("Error loading LOD",t,s),null))}afterRoot(t){var e,r;return y&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((n,s)=>{var o;if(n!=null&&n.extensions){const i=n?.extensions[j];if(i){if(!i.lods){y&&console.warn("Texture has no LODs",i);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const a=this.parser.associations.get(u);a?.textures===s&&(l=!0,D.registerTexture(this.url,u,(o=i.lods)==null?void 0:o.length,s,i))}l||this.parser.getDependency("texture",s).then(u=>{var a;u&&D.registerTexture(this.url,u,(a=i.lods)==null?void 0:a.length,s,i)})}}}),(r=this.parser.json.meshes)==null||r.forEach((n,s)=>{if(n!=null&&n.extensions){const o=n?.extensions[j];if(o&&o.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l?.meshes===s&&D.registerMesh(this.url,o.guid,i,o.lods.length,l.primitives,o)}}}}),null}static async getOrLoadLOD(t,e){var r,n,s,o;const i=y=="verbose",l=t.userData.LODS;if(!l)return null;const u=l?.key;let a;if(t.isTexture===!0){const h=t;h.source&&h.source[Le]&&(a=h.source[Le])}if(a||(a=D.lodInfos.get(u)),a){if(e>0){let f=!1;const A=Array.isArray(a.lods);if(A&&e>=a.lods.length?f=!0:A||(f=!0),f)return this.lowresCache.get(u)}const h=Array.isArray(a.lods)?(r=a.lods[e])==null?void 0:r.path:a.lods;if(!h)return y&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const v=Je(l.url,h);if(v.endsWith(".glb")||v.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const f=v+"_"+a.guid,A=this.previouslyLoaded.get(f);if(A!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${f}`);let g=await A.catch(b=>(console.error(`Error loading LOD ${e} from ${v}
|
|
2
|
+
`,b),null)),p=!1;if(g==null||(g instanceof Q&&t instanceof Q?(n=g.image)!=null&&n.data||(s=g.source)!=null&&s.data?g=this.copySettings(t,g):(p=!0,this.previouslyLoaded.delete(f)):g instanceof ie&&t instanceof ie&&((o=g.attributes.position)!=null&&o.array||(p=!0,this.previouslyLoaded.delete(f)))),!p)return g}const w=a,I=new Promise(async(g,p)=>{const b=new Ve;xe(b),y&&(await new Promise(m=>setTimeout(m,1e3)),i&&console.warn("Start loading (delayed) "+v,w.guid));let C=v;if(w&&Array.isArray(w.lods)){const m=w.lods[e];m.hash&&(C+="?v="+m.hash)}const M=await b.loadAsync(C).catch(m=>(console.error(`Error loading LOD ${e} from ${v}
|
|
3
|
+
`,m),null));if(!M)return null;const F=M.parser;i&&console.log("Loading finished "+v,w.guid);let E=0;if(M.parser.json.textures){let m=!1;for(const d of M.parser.json.textures){if(d!=null&&d.extensions){const L=d?.extensions[j];if(L!=null&&L.guid&&L.guid===w.guid){m=!0;break}}E++}if(m){let d=await F.getDependency("texture",E);return d&&D.assignLODInformation(l.url,d,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+d.name+'"',v,E,d,f),t instanceof Q&&(d=this.copySettings(t,d)),d&&(d.guid=w.guid),g(d)}else y&&console.warn("Could not find texture with guid",w.guid,M.parser.json)}if(E=0,M.parser.json.meshes){let m=!1;for(const d of M.parser.json.meshes){if(d!=null&&d.extensions){const L=d?.extensions[j];if(L!=null&&L.guid&&L.guid===w.guid){m=!0;break}}E++}if(m){const d=await F.getDependency("mesh",E),L=w;if(i&&console.log(`Loaded Mesh "${d.name}"`,v,E,d,f),d.isMesh===!0){const _=d.geometry;return D.assignLODInformation(l.url,_,u,e,void 0,L.density),g(_)}else{const _=new Array;for(let S=0;S<d.children.length;S++){const N=d.children[S];if(N.isMesh===!0){const V=N.geometry;D.assignLODInformation(l.url,V,u,e,S,L.density),_.push(V)}}return g(_)}}else y&&console.warn("Could not find mesh with guid",w.guid,M.parser.json)}return g(null)});return this.previouslyLoaded.set(f,I),await I}else if(t instanceof Q){i&&console.log("Load texture from uri: "+v);const f=await new We().loadAsync(v);return f?(f.guid=a.guid,f.flipY=!1,f.needsUpdate=!0,f.colorSpace=t.colorSpace,i&&console.log(a,f)):y&&console.warn("failed loading",v),f}}else y&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,n,s,o){if(!e)return;e.userData||(e.userData={});const i=new tt(t,r,n,s,o);e.userData.LODS=i}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),y&&console.warn(`Copying texture settings
|
|
4
4
|
`,t.uuid,`
|
|
5
|
-
`,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let O=D;c(O,"registerTexture",(t,e,r,n,s)=>{if(y&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,s),!e){y&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[Le]=s);const o=s.guid;D.assignLODInformation(t,e,o,r,n,void 0),D.lodInfos.set(o,s),D.lowresCache.set(o,e)}),c(O,"registerMesh",(t,e,r,n,s,o)=>{var i;y&&console.log("> Progressive: register mesh",s,r.name,o,r.uuid,r);const l=r.geometry;if(!l){y&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),D.assignLODInformation(t,l,e,n,s,o.density),D.lodInfos.set(e,o);let u=D.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],D.lowresCache.set(e,u),n>0&&!ue(r)&&Ee(r,l);for(const a of $)(i=a.onRegisteredNewMesh)==null||i.call(a,r,o)}),c(O,"lodInfos",new Map),c(O,"previouslyLoaded",new Map),c(O,"lowresCache",new Map);class tt{constructor(e,r,n,s,o){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=r,this.level=n,s!=null&&(this.index=s),o!=null&&(this.density=o)}}const B=Z("debugprogressive"),rt=Z("noprogressive"),De=Symbol("Needle:LODSManager"),we=Symbol("Needle:LODState"),Y=Symbol("Needle:CurrentLOD"),k={mesh_lod:-1,texture_lod:-1};var S,U,_e,J,re,ce,z;const P=class{constructor(t,e){c(this,"context"),c(this,"renderer"),c(this,"projectionScreenMatrix",new Se),c(this,"cameraFrustrum",new Ne),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval","auto"),q(this,S,1),c(this,"pause",!1),c(this,"manual",!1),c(this,"_lodchangedlisteners",[]),q(this,U,void 0),q(this,_e,new $e),q(this,J,0),q(this,re,0),q(this,ce,0),q(this,z,0),c(this,"_fpsBuffer",[60,60,60,60,60]),c(this,"_sphere",new ze),c(this,"_tempBox",new Te),c(this,"_tempBox2",new Te),c(this,"tempMatrix",new Se),c(this,"_tempWorldPosition",new W),c(this,"_tempBoxSize",new W),c(this,"_tempBox2Size",new W),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[we]}static addPlugin(t){$.push(t)}static removePlugin(t){const e=$.indexOf(t);e>=0&&$.splice(e,1)}static get(t,e){if(t[De])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[De];const r=new P(t,{engine:"unknown",...e});return t[De]=r,r}get plugins(){return $}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}enable(){if(x(this,U))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;F(this,U,this.renderer.render);const e=this;ve(this.renderer),this.renderer.render=function(r,n){const s=e.renderer.getRenderTarget();(s==null||"isXRRenderTarget"in s&&s.isXRRenderTarget)&&(t=0,F(e,J,x(e,J)+1),F(e,re,x(e,_e).getDelta()),F(e,ce,x(e,ce)+x(e,re)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/x(e,re)),F(e,z,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),B&&x(e,J)%30===0&&console.log("FPS",Math.round(x(e,z)),"Interval:",x(e,S)));const o=t++;x(e,U).call(this,r,n),e.onAfterRender(r,n,o)}}disable(){x(this,U)&&(this.renderer.render=x(this,U),F(this,U,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,r){if(this.pause)return;const n=this.renderer.renderLists.get(t,0).opaque;let s=!0;if(n.length===1){const o=n[0].material;(o.name==="EffectMaterial"||o.name==="CopyShader")&&(s=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(s=!1),s){if(rt||(this.updateInterval==="auto"?x(this,z)<40&&x(this,S)<10?(F(this,S,x(this,S)+1),B&&console.warn("\u2193 Reducing LOD updates",x(this,S),x(this,z).toFixed(0))):x(this,z)>=60&&x(this,S)>1&&(F(this,S,x(this,S)-1),B&&console.warn("\u2191 Increasing LOD updates",x(this,S),x(this,z).toFixed(0))):F(this,S,this.updateInterval),x(this,S)>0&&x(this,J)%x(this,S)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var r,n;const s=this.renderer.renderLists.get(t,0),o=s.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const i=this.targetTriangleDensity;for(const a of o){if(a.material&&(((r=a.geometry)==null?void 0:r.type)==="BoxGeometry"||((n=a.geometry)==null?void 0:n.type)==="BufferGeometry")&&(a.material.name==="SphericalGaussianBlur"||a.material.name=="BackgroundCubeMaterial"||a.material.name==="CubemapFromEquirect"||a.material.name==="EquirectangularToCubeUV")){B&&(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",a,a.material.name,a.material.type)));continue}switch(a.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(B==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const v=Math.random()*16777215,g=new Ue({color:v});a.object.material=g}const h=a.object;(h instanceof X||h.isMesh)&&this.updateLODs(t,e,h,i)}const l=s.transparent;for(const a of l){const h=a.object;(h instanceof X||h.isMesh)&&this.updateLODs(t,e,h,i)}const u=s.transmissive;for(const a of u){const h=a.object;(h instanceof X||h.isMesh)&&this.updateLODs(t,e,h,i)}}updateLODs(t,e,r,n){var s,o;r.userData||(r.userData={});let i=r[we];if(i||(i=new st,r[we]=i),i.frames++<2)return;for(const u of $)(s=u.onBeforeUpdateLOD)==null||s.call(u,this.renderer,t,e,r);this.calculateLodLevel(e,r,i,n,k),k.mesh_lod=Math.round(k.mesh_lod),k.texture_lod=Math.round(k.texture_lod),k.mesh_lod>=0&&this.loadProgressiveMeshes(r,k.mesh_lod);let l=k.texture_lod;if(r.material&&l>=0){const u=r["DEBUG:LOD"];u!=null&&(l=u),this.loadProgressiveTextures(r.material,l)}for(const u of $)(o=u.onAfterUpdatedLOD)==null||o.call(u,this.renderer,t,e,r,k);i.lastLodLevel_Mesh=k.mesh_lod,i.lastLodLevel_Texture=k.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const n of t)this.loadProgressiveTextures(n,e);return}let r=!1;(t[Y]===void 0||e<t[Y])&&(r=!0),r&&(t[Y]=e,O.assignTextureLOD(t,e).then(n=>{this._lodchangedlisteners.forEach(s=>s({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[Y]!==e){t[Y]=e;const r=t.geometry;return O.assignMeshLOD(t,e).then(n=>(n&&t[Y]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(s=>s({type:"mesh",level:e,object:t})),n))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,n=t.max,s=(r.x+n.x)*.5,o=(r.y+n.y)*.5;return this._tempPtInside.set(s,o,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,n,s){var o,i;if(!e){s.mesh_lod=-1,s.texture_lod=-1;return}if(!t){s.mesh_lod=-1,s.texture_lod=-1;return}let l=10+1,u=!1;if(B&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=O.getMeshLODInformation(e.geometry),h=a?.lods,v=h&&h.length>0,g=O.getMaterialMinMaxLODsCount(e.material),A=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!v&&!A){s.mesh_lod=0,s.texture_lod=0;return}if(v||(u=!0,l=0),!((o=this.cameraFrustrum)!=null&&o.intersectsObject(e))){s.mesh_lod=99,s.texture_lod=99;return}const w=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let I=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const m=e;m.boundingBox||m.computeBoundingBox(),I=m.boundingBox}if(I&&t.isPerspectiveCamera){const m=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const f=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(f)){s.mesh_lod=0,s.texture_lod=0;return}}if(this._tempBox.copy(I),this._tempBox.applyMatrix4(e.matrixWorld),P.isInside(this._tempBox,this.projectionScreenMatrix)){s.mesh_lod=0,s.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&m.fov>70){const f=this._tempBox.min,d=this._tempBox.max;let L=f.x,_=f.y,b=d.x,N=d.y;const V=2,ge=1.5,se=(f.x+d.x)*.5,oe=(f.y+d.y)*.5;L=(L-se)*V+se,_=(_-oe)*V+oe,b=(b-se)*V+se,N=(N-oe)*V+oe;const Ce=L<0&&b>0?0:Math.min(Math.abs(f.x),Math.abs(d.x)),je=_<0&&N>0?0:Math.min(Math.abs(f.y),Math.abs(d.y)),fe=Math.max(Ce,je);r.lastCentrality=(ge-fe)*(ge-fe)*(ge-fe)}else r.lastCentrality=1;const p=this._tempBox.getSize(this._tempBoxSize);p.multiplyScalar(.5),screen.availHeight>0&&w>0&&p.multiplyScalar(w/screen.availHeight),p.x*=m.aspect;const T=t.matrixWorldInverse,C=this._tempBox2;C.copy(I),C.applyMatrix4(e.matrixWorld),C.applyMatrix4(T);const M=C.getSize(this._tempBox2Size),G=Math.max(M.x,M.y);if(Math.max(p.x,p.y)!=0&&G!=0&&(p.z=M.z/Math.max(M.x,M.y)*Math.max(p.x,p.y)),r.lastScreenCoverage=Math.max(p.x,p.y,p.z),r.lastScreenspaceVolume.copy(p),r.lastScreenCoverage*=r.lastCentrality,B&&P.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const d=P.corner0,L=P.corner1,_=P.corner2,b=P.corner3;d.copy(this._tempBox.min),L.copy(this._tempBox.max),L.x=d.x,_.copy(this._tempBox.max),_.y=d.y,b.copy(this._tempBox.max);const N=(d.z+b.z)*.5;d.z=L.z=_.z=b.z=N,d.applyMatrix4(f),L.applyMatrix4(f),_.applyMatrix4(f),b.applyMatrix4(f),P.debugDrawLine(d,L,255),P.debugDrawLine(d,_,255),P.debugDrawLine(L,b,255),P.debugDrawLine(_,b,255)}let E=999;if(h&&r.lastScreenCoverage>0){for(let f=0;f<h.length;f++)if(h[f].density/r.lastScreenCoverage<n){E=f;break}}E<l&&(l=E,u=!0)}if(u?s.mesh_lod=l:s.mesh_lod=r.lastLodLevel_Mesh,B&&s.mesh_lod!=r.lastLodLevel_Mesh){const m=h?.[s.mesh_lod];m&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${s.mesh_lod} (${m.density.toFixed(0)}) - ${e.name}`)}if(A){const m="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(s.texture_lod=g.max_count-1,B){const p=g.lods[g.max_count-1];B&&console.log(`First Texture LOD ${s.texture_lod} (${p.max_height}px) - ${e.name}`)}}else{const p=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let T=r.lastScreenCoverage*2;((i=this.context)==null?void 0:i.engine)==="model-viewer"&&(T*=2);const C=w/window.devicePixelRatio*T;for(let M=g.lods.length-1;M>=0;M--){let G=g.lods[M];if(!(m&&G.max_height>=2048)&&!(Qe()&&G.max_height>4096)&&G.max_height>C){if(s.texture_lod=M,s.texture_lod<r.lastLodLevel_Texture){const E=G.max_height;B&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${s.texture_lod} = ${E}px
|
|
5
|
+
`,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let O=D;c(O,"registerTexture",(t,e,r,n,s)=>{if(y&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,s),!e){y&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[Le]=s);const o=s.guid;D.assignLODInformation(t,e,o,r,n,void 0),D.lodInfos.set(o,s),D.lowresCache.set(o,e)}),c(O,"registerMesh",(t,e,r,n,s,o)=>{var i;y&&console.log("> Progressive: register mesh",s,r.name,o,r.uuid,r);const l=r.geometry;if(!l){y&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),D.assignLODInformation(t,l,e,n,s,o.density),D.lodInfos.set(e,o);let u=D.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],D.lowresCache.set(e,u),n>0&&!ee(r)&&Ee(r,l);for(const a of $)(i=a.onRegisteredNewMesh)==null||i.call(a,r,o)}),c(O,"lodInfos",new Map),c(O,"previouslyLoaded",new Map),c(O,"lowresCache",new Map);class tt{constructor(e,r,n,s,o){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=r,this.level=n,s!=null&&(this.index=s),o!=null&&(this.density=o)}}const B=Z("debugprogressive"),rt=Z("noprogressive"),De=Symbol("Needle:LODSManager"),we=Symbol("Needle:LODState"),Y=Symbol("Needle:CurrentLOD"),k={mesh_lod:-1,texture_lod:-1};var T,U,_e,J,se,ce,z;const P=class{constructor(t,e){c(this,"context"),c(this,"renderer"),c(this,"projectionScreenMatrix",new Se),c(this,"cameraFrustrum",new Ne),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval","auto"),q(this,T,1),c(this,"pause",!1),c(this,"manual",!1),c(this,"_lodchangedlisteners",[]),q(this,U,void 0),q(this,_e,new $e),q(this,J,0),q(this,se,0),q(this,ce,0),q(this,z,0),c(this,"_fpsBuffer",[60,60,60,60,60]),c(this,"_sphere",new ze),c(this,"_tempBox",new Te),c(this,"_tempBox2",new Te),c(this,"tempMatrix",new Se),c(this,"_tempWorldPosition",new W),c(this,"_tempBoxSize",new W),c(this,"_tempBox2Size",new W),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[we]}static addPlugin(t){$.push(t)}static removePlugin(t){const e=$.indexOf(t);e>=0&&$.splice(e,1)}static get(t,e){if(t[De])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[De];const r=new P(t,{engine:"unknown",...e});return t[De]=r,r}get plugins(){return $}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const r=this._lodchangedlisteners.indexOf(e);r>=0&&this._lodchangedlisteners.splice(r,1)}}enable(){if(x(this,U))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;G(this,U,this.renderer.render);const e=this;ve(this.renderer),this.renderer.render=function(r,n){const s=e.renderer.getRenderTarget();(s==null||"isXRRenderTarget"in s&&s.isXRRenderTarget)&&(t=0,G(e,J,x(e,J)+1),G(e,se,x(e,_e).getDelta()),G(e,ce,x(e,ce)+x(e,se)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/x(e,se)),G(e,z,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),B&&x(e,J)%30===0&&console.log("FPS",Math.round(x(e,z)),"Interval:",x(e,T)));const o=t++;x(e,U).call(this,r,n),e.onAfterRender(r,n,o)}}disable(){x(this,U)&&(this.renderer.render=x(this,U),G(this,U,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,r){if(this.pause)return;const n=this.renderer.renderLists.get(t,0).opaque;let s=!0;if(n.length===1){const o=n[0].material;(o.name==="EffectMaterial"||o.name==="CopyShader")&&(s=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(s=!1),s){if(rt||(this.updateInterval==="auto"?x(this,z)<40&&x(this,T)<10?(G(this,T,x(this,T)+1),B&&console.warn("\u2193 Reducing LOD updates",x(this,T),x(this,z).toFixed(0))):x(this,z)>=60&&x(this,T)>1&&(G(this,T,x(this,T)-1),B&&console.warn("\u2191 Increasing LOD updates",x(this,T),x(this,z).toFixed(0))):G(this,T,this.updateInterval),x(this,T)>0&&x(this,J)%x(this,T)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var r,n;const s=this.renderer.renderLists.get(t,0),o=s.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const i=this.targetTriangleDensity;for(const a of o){if(a.material&&(((r=a.geometry)==null?void 0:r.type)==="BoxGeometry"||((n=a.geometry)==null?void 0:n.type)==="BufferGeometry")&&(a.material.name==="SphericalGaussianBlur"||a.material.name=="BackgroundCubeMaterial"||a.material.name==="CubemapFromEquirect"||a.material.name==="EquirectangularToCubeUV")){B&&(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",a,a.material.name,a.material.type)));continue}switch(a.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(B==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const v=Math.random()*16777215,f=new Ue({color:v});a.object.material=f}const h=a.object;(h instanceof X||h.isMesh)&&this.updateLODs(t,e,h,i)}const l=s.transparent;for(const a of l){const h=a.object;(h instanceof X||h.isMesh)&&this.updateLODs(t,e,h,i)}const u=s.transmissive;for(const a of u){const h=a.object;(h instanceof X||h.isMesh)&&this.updateLODs(t,e,h,i)}}updateLODs(t,e,r,n){var s,o;r.userData||(r.userData={});let i=r[we];if(i||(i=new st,r[we]=i),i.frames++<2)return;for(const u of $)(s=u.onBeforeUpdateLOD)==null||s.call(u,this.renderer,t,e,r);this.calculateLodLevel(e,r,i,n,k),k.mesh_lod=Math.round(k.mesh_lod),k.texture_lod=Math.round(k.texture_lod),k.mesh_lod>=0&&this.loadProgressiveMeshes(r,k.mesh_lod);let l=k.texture_lod;if(r.material&&l>=0){const u=r["DEBUG:LOD"];u!=null&&(l=u),this.loadProgressiveTextures(r.material,l)}for(const u of $)(o=u.onAfterUpdatedLOD)==null||o.call(u,this.renderer,t,e,r,k);i.lastLodLevel_Mesh=k.mesh_lod,i.lastLodLevel_Texture=k.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const n of t)this.loadProgressiveTextures(n,e);return}let r=!1;(t[Y]===void 0||e<t[Y])&&(r=!0),r&&(t[Y]=e,O.assignTextureLOD(t,e).then(n=>{this._lodchangedlisteners.forEach(s=>s({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[Y]!==e){t[Y]=e;const r=t.geometry;return O.assignMeshLOD(t,e).then(n=>(n&&t[Y]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(s=>s({type:"mesh",level:e,object:t})),n))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,n=t.max,s=(r.x+n.x)*.5,o=(r.y+n.y)*.5;return this._tempPtInside.set(s,o,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,n,s){var o,i;if(!e){s.mesh_lod=-1,s.texture_lod=-1;return}if(!t){s.mesh_lod=-1,s.texture_lod=-1;return}let l=10+1,u=!1;if(B&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=O.getMeshLODInformation(e.geometry),h=a?.lods,v=h&&h.length>0,f=O.getMaterialMinMaxLODsCount(e.material),A=f?.min_count!=1/0&&f.min_count>0&&f.max_count>0;if(!v&&!A){s.mesh_lod=0,s.texture_lod=0;return}if(v||(u=!0,l=0),!((o=this.cameraFrustrum)!=null&&o.intersectsObject(e))){s.mesh_lod=100,s.texture_lod=100;return}const w=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let I=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const g=e;if(!g.boundingBox)g.computeBoundingBox();else if(r.frames%30===0){const p=ee(g),b=g.geometry;p&&(g.geometry=p),g.computeBoundingBox(),g.geometry=b}I=g.boundingBox}if(I&&t.isPerspectiveCamera){const g=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const m=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(m)){s.mesh_lod=0,s.texture_lod=0;return}}if(this._tempBox.copy(I),this._tempBox.applyMatrix4(e.matrixWorld),P.isInside(this._tempBox,this.projectionScreenMatrix)){s.mesh_lod=0,s.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&g.fov>70){const m=this._tempBox.min,d=this._tempBox.max;let L=m.x,_=m.y,S=d.x,N=d.y;const V=2,ge=1.5,oe=(m.x+d.x)*.5,ne=(m.y+d.y)*.5;L=(L-oe)*V+oe,_=(_-ne)*V+ne,S=(S-oe)*V+oe,N=(N-ne)*V+ne;const Ce=L<0&&S>0?0:Math.min(Math.abs(m.x),Math.abs(d.x)),je=_<0&&N>0?0:Math.min(Math.abs(m.y),Math.abs(d.y)),fe=Math.max(Ce,je);r.lastCentrality=(ge-fe)*(ge-fe)*(ge-fe)}else r.lastCentrality=1;const p=this._tempBox.getSize(this._tempBoxSize);p.multiplyScalar(.5),screen.availHeight>0&&w>0&&p.multiplyScalar(w/screen.availHeight),p.x*=g.aspect;const b=t.matrixWorldInverse,C=this._tempBox2;C.copy(I),C.applyMatrix4(e.matrixWorld),C.applyMatrix4(b);const M=C.getSize(this._tempBox2Size),F=Math.max(M.x,M.y);if(Math.max(p.x,p.y)!=0&&F!=0&&(p.z=M.z/Math.max(M.x,M.y)*Math.max(p.x,p.y)),r.lastScreenCoverage=Math.max(p.x,p.y,p.z),r.lastScreenspaceVolume.copy(p),r.lastScreenCoverage*=r.lastCentrality,B&&P.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const d=P.corner0,L=P.corner1,_=P.corner2,S=P.corner3;d.copy(this._tempBox.min),L.copy(this._tempBox.max),L.x=d.x,_.copy(this._tempBox.max),_.y=d.y,S.copy(this._tempBox.max);const N=(d.z+S.z)*.5;d.z=L.z=_.z=S.z=N,d.applyMatrix4(m),L.applyMatrix4(m),_.applyMatrix4(m),S.applyMatrix4(m),P.debugDrawLine(d,L,255),P.debugDrawLine(d,_,255),P.debugDrawLine(L,S,255),P.debugDrawLine(_,S,255)}let E=999;if(h&&r.lastScreenCoverage>0){for(let m=0;m<h.length;m++)if(h[m].density/r.lastScreenCoverage<n){E=m;break}}E<l&&(l=E,u=!0)}if(u?s.mesh_lod=l:s.mesh_lod=r.lastLodLevel_Mesh,B&&s.mesh_lod!=r.lastLodLevel_Mesh){const g=h?.[s.mesh_lod];g&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${s.mesh_lod} (${g.density.toFixed(0)}) - ${e.name}`)}if(A){const g="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(s.texture_lod=f.max_count-1,B){const p=f.lods[f.max_count-1];B&&console.log(`First Texture LOD ${s.texture_lod} (${p.max_height}px) - ${e.name}`)}}else{const p=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let b=r.lastScreenCoverage*2;((i=this.context)==null?void 0:i.engine)==="model-viewer"&&(b*=2);const C=w/window.devicePixelRatio*b;for(let M=f.lods.length-1;M>=0;M--){let F=f.lods[M];if(!(g&&F.max_height>=2048)&&!(Qe()&&F.max_height>4096)&&F.max_height>C){if(s.texture_lod=M,s.texture_lod<r.lastLodLevel_Texture){const E=F.max_height;B&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${s.texture_lod} = ${E}px
|
|
6
6
|
Screensize: ${C.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${p.toFixed(1)}
|
|
7
|
-
${e.name}`)}break}}}}else s.texture_lod=0}};let R=P;
|
|
8
|
-
`,t.getAttribute("src"));let e=null,r=null,n=null;for(let s=t;s!=null;s=Object.getPrototypeOf(s)){const o=Object.getOwnPropertySymbols(s),i=o.find(a=>a.toString()=="Symbol(renderer)"),l=o.find(a=>a.toString()=="Symbol(scene)"),u=o.find(a=>a.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=t[i].threeRenderer),!r&&l!=null&&(r=t[l]),!n&&u!=null&&(n=t[u])}if(e&&r){let s=function(){if(n){let i=0,l=setInterval(()=>{if(i++>5){clearInterval(l);return}n?.call(t)},300)}};console.debug("[gltf-progressive] setup model-viewer");const o=R.get(e,{engine:"model-viewer"});return R.addPlugin(new it),o.enable(),o.addEventListener("changed",()=>{n?.call(t)}),t.addEventListener("model-visibility",i=>{i.detail.visible&&n?.call(t)}),t.addEventListener("load",()=>{s()}),()=>{o.disable()}}return null}class it{constructor(){c(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,r,n,s){this.tryParseMeshLOD(r,s),this.tryParseTextureLOD(r,s)}getUrl(e){if(!e)return null;let r=e.getAttribute("src");return r||(r=e.src),r||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),r}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,r){if(r[de]==!0)return;r[de]=!0;const n=this.tryGetCurrentGLTF(e),s=this.tryGetCurrentModelViewer(e),o=this.getUrl(s);if(o&&n&&r.material){let i=function(u){var a,h,v;if(u[de]==!0)return;u[de]=!0,u.userData&&(u.userData.LOD=-1);const
|
|
7
|
+
${e.name}`)}break}}}}else s.texture_lod=0}};let R=P;T=new WeakMap,U=new WeakMap,_e=new WeakMap,J=new WeakMap,se=new WeakMap,ce=new WeakMap,z=new WeakMap,c(R,"debugDrawLine"),c(R,"corner0",new W),c(R,"corner1",new W),c(R,"corner2",new W),c(R,"corner3",new W),c(R,"_tempPtInside",new W);class st{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",-1),c(this,"lastLodLevel_Texture",-1),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new W),c(this,"lastCentrality",0)}}const Ie=Symbol("NEEDLE_mesh_lod"),de=Symbol("NEEDLE_texture_lod");let he=null;function Oe(){const t=ot();t&&(t.mapURLs(function(e){return Pe(),e}),Pe(),he?.disconnect(),he=new MutationObserver(e=>{e.forEach(r=>{r.addedNodes.forEach(n=>{n instanceof HTMLElement&&n.tagName.toLowerCase()==="model-viewer"&&ke(n)})})}),he.observe(document,{childList:!0,subtree:!0}))}function ot(){return customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Oe()}),null)}function Pe(){document.querySelectorAll("model-viewer").forEach(t=>{ke(t)})}const Be=new WeakSet;let nt=0;function ke(t){if(!t||Be.has(t))return null;Be.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++nt+`
|
|
8
|
+
`,t.getAttribute("src"));let e=null,r=null,n=null;for(let s=t;s!=null;s=Object.getPrototypeOf(s)){const o=Object.getOwnPropertySymbols(s),i=o.find(a=>a.toString()=="Symbol(renderer)"),l=o.find(a=>a.toString()=="Symbol(scene)"),u=o.find(a=>a.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=t[i].threeRenderer),!r&&l!=null&&(r=t[l]),!n&&u!=null&&(n=t[u])}if(e&&r){let s=function(){if(n){let i=0,l=setInterval(()=>{if(i++>5){clearInterval(l);return}n?.call(t)},300)}};console.debug("[gltf-progressive] setup model-viewer");const o=R.get(e,{engine:"model-viewer"});return R.addPlugin(new it),o.enable(),o.addEventListener("changed",()=>{n?.call(t)}),t.addEventListener("model-visibility",i=>{i.detail.visible&&n?.call(t)}),t.addEventListener("load",()=>{s()}),()=>{o.disable()}}return null}class it{constructor(){c(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,r,n,s){this.tryParseMeshLOD(r,s),this.tryParseTextureLOD(r,s)}getUrl(e){if(!e)return null;let r=e.getAttribute("src");return r||(r=e.src),r||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),r}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,r){if(r[de]==!0)return;r[de]=!0;const n=this.tryGetCurrentGLTF(e),s=this.tryGetCurrentModelViewer(e),o=this.getUrl(s);if(o&&n&&r.material){let i=function(u){var a,h,v;if(u[de]==!0)return;u[de]=!0,u.userData&&(u.userData.LOD=-1);const f=Object.keys(u);for(let A=0;A<f.length;A++){const w=f[A],I=u[w];if(I?.isTexture===!0){const g=(h=(a=I.userData)==null?void 0:a.associations)==null?void 0:h.textures;if(g==null)continue;const p=n.parser.json.textures[g];if(!p){console.warn("Texture data not found for texture index "+g);continue}if((v=p?.extensions)!=null&&v[j]){const b=p.extensions[j];b&&o&&O.registerTexture(o,I,b.lods.length,g,b)}}}};const l=r.material;if(Array.isArray(l))for(const u of l)i(u);else i(l)}}tryParseMeshLOD(e,r){var n,s;if(r[Ie]==!0)return;r[Ie]=!0;const o=this.tryGetCurrentModelViewer(e),i=this.getUrl(o);if(!i)return;const l=(s=(n=r.userData)==null?void 0:n.gltfExtensions)==null?void 0:s[j];if(l&&i){const u=r.uuid;O.registerMesh(i,u,r,0,l.lods.length,l)}}}function lt(t,e,r,n){ve(e),xe(r),r.register(o=>new O(o,t));const s=R.get(e);return n?.enableLODsManager!==!1&&s.enable(),s}Oe();export{j as EXTENSION_NAME,R as LODsManager,O as NEEDLE_progressive,me as VERSION,xe as addDracoAndKTX2Loaders,ve as createLoaders,ee as getRaycastMesh,Oe as patchModelViewer,Ee as registerRaycastMesh,He as setDracoDecoderLocation,Ye as setKTX2TranscoderLocation,lt as useNeedleProgressive,Ze as useRaycastMeshes};
|
package/gltf-progressive.umd.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"use strict";var ke=Object.defineProperty;var Ge=(a,t,e)=>t in a?ke(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var f=(a,t,e)=>(Ge(a,typeof t!="symbol"?t+"":t,e),e),be=(a,t,e)=>{if(!t.has(a))throw TypeError("Cannot "+e)};var L=(a,t,e)=>(be(a,t,"read from private field"),e?e.call(a):t.get(a)),K=(a,t,e)=>{if(t.has(a))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(a):t.set(a,e)},V=(a,t,e,r)=>(be(a,t,"write to private field"),r?r.call(a,e):t.set(a,e),e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("three"),Fe=require("three/examples/jsm/loaders/GLTFLoader.js"),Ve=require("three/examples/jsm/libs/meshopt_decoder.module.js"),$e=require("three/examples/jsm/loaders/DRACOLoader.js"),Ne=require("three/examples/jsm/loaders/KTX2Loader.js"),we="";globalThis.GLTF_PROGRESSIVE_VERSION=we;console.debug(`[gltf-progressive] version ${we}`);let fe="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ve="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(fe+"draco_decoder.js",{method:"head"}).catch(a=>{fe="./include/draco/",ve="./include/ktx2/"});function Ue(a){fe=a}function ze(a){ve=a}let j,ue,J;function _e(a){return j||(j=new $e.DRACOLoader,j.setDecoderPath(fe),j.setDecoderConfig({type:"js"})),J||(J=new Ne.KTX2Loader,J.setTranscoderPath(ve)),ue||(ue=Ve.MeshoptDecoder),a?J.detectSupport(a):a!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:j,ktx2Loader:J,meshoptDecoder:ue}}function Oe(a){a.dracoLoader||a.setDRACOLoader(j),a.ktx2Loader||a.setKTX2Loader(J),a.meshoptDecoder||a.setMeshoptDecoder(ue)}oe("debugprogressive");function oe(a){const e=new URL(window.location.href).searchParams.get(a);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function We(a,t){if(t===void 0||t.startsWith("./")||t.startsWith("http")||a===void 0)return t;const e=a.lastIndexOf("/");if(e>=0){const r=a.substring(0,e+1);for(;r.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return r+t}return t}let te;function qe(){return te!==void 0||(te=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),oe("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",te)),te}const Me=Symbol("needle:raycast-mesh");function ge(a){return(a==null?void 0:a[Me])instanceof d.BufferGeometry?a[Me]:null}function Ce(a,t){if((a.type==="Mesh"||a.type==="SkinnedMesh")&&!ge(a)){const r=Ke(t);r.userData={isRaycastMesh:!0},a[Me]=r}}function Xe(a=!0){if(a){if(re)return;const t=re=d.Mesh.prototype.raycast;d.Mesh.prototype.raycast=function(e,r){const o=this,s=ge(o);let i;s&&o.isMesh&&(i=o.geometry,o.geometry=s),t.call(this,e,r),i&&(o.geometry=i)}}else{if(!re)return;d.Mesh.prototype.raycast=re,re=null}}let re=null;function Ke(a){const t=new d.BufferGeometry;for(const e in a.attributes)t.setAttribute(e,a.getAttribute(e));return t.setIndex(a.getIndex()),t}const Y=new Array,$="NEEDLE_progressive",x=oe("debugprogressive"),me=Symbol("needle-progressive-texture"),ie=new Map,De=new Set;if(x){let a=function(){t+=1,console.log("Toggle LOD level",t,ie),ie.forEach((o,s)=>{for(const i of o.keys){const n=s[i];if(n!=null){if(n.isBufferGeometry===!0){const l=b.getMeshLODInformation(n),u=l?Math.min(t,l.lods.length):0;s["DEBUG:LOD"]=t,b.assignMeshLOD(s,u),l&&(e=Math.max(e,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=t,b.assignTextureLOD(s,t);break}}}}),t>=e&&(t=-1)},t=-1,e=2,r=!1;window.addEventListener("keyup",o=>{o.key==="p"&&a(),o.key==="w"&&(r=!r,De&&De.forEach(s=>{s.name!="BackgroundCubeMaterial"&&s.glyphMap==null&&"wireframe"in s&&(s.wireframe=r)}))})}function Te(a,t,e){var o;if(!x)return;ie.has(a)||ie.set(a,{keys:[],sourceId:e});const r=ie.get(a);((o=r==null?void 0:r.keys)==null?void 0:o.includes(t))==!1&&r.keys.push(t)}const O=class{constructor(t,e){f(this,"parser");f(this,"url");f(this,"_isLoadingMesh");f(this,"loadMesh",t=>{var r,o;if(this._isLoadingMesh)return null;const e=(o=(r=this.parser.json.meshes[t])==null?void 0:r.extensions)==null?void 0:o[$];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(s=>{var i;return this._isLoadingMesh=!1,s&&O.registerMesh(this.url,e.guid,s,(i=e.lods)==null?void 0:i.length,void 0,e),s})):null});x&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return $}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const r=this,o="LODS:minmax",s=t[o];if(s!=null)return s;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const n of t)this.getMaterialMinMaxLODsCount(n,e);return t[o]=e,e}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const n=t;for(const l of Object.keys(n.uniforms)){const u=n.uniforms[l].value;(u==null?void 0:u.isTexture)===!0&&i(u,e)}}else if(t.isMaterial)for(const n of Object.keys(t)){const l=t[n];(l==null?void 0:l.isTexture)===!0&&i(l,e)}return t[o]=e,e;function i(n,l){const u=r.getAssignedLODInformation(n);if(u){const c=r.lodInfos.get(u.key);if(c&&c.lods){l.min_count=Math.min(l.min_count,c.lods.length),l.max_count=Math.max(l.max_count,c.lods.length);for(let h=0;h<c.lods.length;h++){const g=c.lods[h];g.width&&(l.lods[h]=l.lods[h]||{min_height:1/0,max_height:0},l.lods[h].min_height=Math.min(l.lods[h].min_height,g.height),l.lods[h].max_height=Math.max(l.lods[h].max_height,g.height))}}}}}static hasLODLevelAvailable(t,e){var s;if(Array.isArray(t)){for(const i of t)if(this.hasLODLevelAvailable(i,e))return!0;return!1}if(t.isMaterial===!0){for(const i of Object.keys(t)){const n=t[i];if(n&&n.isTexture&&this.hasLODLevelAvailable(n,e))return!0}return!1}else if(t.isGroup===!0){for(const i of t.children)if(i.isMesh===!0&&this.hasLODLevelAvailable(i,e))return!0}let r,o;if(t.isMesh?r=t.geometry:(t.isBufferGeometry||t.isTexture)&&(r=t),r&&(s=r==null?void 0:r.userData)!=null&&s.LODS){const i=r.userData.LODS;if(o=this.lodInfos.get(i.key),e===void 0)return o!=null;if(o)return Array.isArray(o.lods)?e<o.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof d.Mesh||t.isMesh===!0){const o=t.geometry,s=this.getAssignedLODInformation(o);if(!s)return Promise.resolve(null);for(const i of Y)(r=i.onBeforeGetLODMesh)==null||r.call(i,t,e);return t["LOD:requested level"]=e,O.getOrLoadLOD(o,e).then(i=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(i)){const n=s.index||0;i=i[n]}i&&o!=i&&((i==null?void 0:i.isBufferGeometry)?(t.geometry=i,x&&Te(t,"geometry",s.url)):x&&console.error("Invalid LOD geometry",i))}return i}).catch(i=>(console.error("Error loading mesh LOD",t,i),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof d.Material||t.isMaterial===!0){const r=t,o=[],s=new Array;if(x&&De.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const i=r;for(const n of Object.keys(i.uniforms)){const l=i.uniforms[n].value;if((l==null?void 0:l.isTexture)===!0){const u=this.assignTextureLODForSlot(l,e,r,n);o.push(u),s.push(n)}}}else for(const i of Object.keys(r)){const n=r[i];if((n==null?void 0:n.isTexture)===!0){const l=this.assignTextureLODForSlot(n,e,r,i);o.push(l),s.push(i)}}return Promise.all(o).then(i=>{const n=new Array;for(let l=0;l<i.length;l++){const u=i[l],c=s[l];u&&u.isTexture===!0?n.push({material:r,slot:c,texture:u,level:e}):n.push({material:r,slot:c,texture:null,level:e})}return n})}if(t instanceof d.Texture||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,o){return(t==null?void 0:t.isTexture)!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):O.getOrLoadLOD(t,e).then(s=>{if(Array.isArray(s))return null;if((s==null?void 0:s.isTexture)===!0){if(s!=t){if(r&&o){const i=r[o];if(i){const n=this.getAssignedLODInformation(i);if(n&&(n==null?void 0:n.level)<e)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,e,r,i,s),null}r[o]=s}if(x&&o&&r){const i=this.getAssignedLODInformation(t);i&&Te(r,o,i.url)}}return s}else x=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(s=>(console.error("Error loading LOD",t,s),null))}afterRoot(t){var e,r;return x&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,s)=>{var i;if(o!=null&&o.extensions){const n=o==null?void 0:o.extensions[$];if(n){if(!n.lods){x&&console.warn("Texture has no LODs",n);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const c=this.parser.associations.get(u);(c==null?void 0:c.textures)===s&&(l=!0,O.registerTexture(this.url,u,(i=n.lods)==null?void 0:i.length,s,n))}l||this.parser.getDependency("texture",s).then(u=>{var c;u&&O.registerTexture(this.url,u,(c=n.lods)==null?void 0:c.length,s,n)})}}}),(r=this.parser.json.meshes)==null||r.forEach((o,s)=>{if(o!=null&&o.extensions){const i=o==null?void 0:o.extensions[$];if(i&&i.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const l=this.parser.associations.get(n);(l==null?void 0:l.meshes)===s&&O.registerMesh(this.url,i.guid,n,i.lods.length,l.primitives,i)}}}}),null}static async getOrLoadLOD(t,e){var n,l,u,c;const r=x=="verbose",o=t.userData.LODS;if(!o)return null;const s=o==null?void 0:o.key;let i;if(t.isTexture===!0){const h=t;h.source&&h.source[me]&&(i=h.source[me])}if(i||(i=O.lodInfos.get(s)),i){if(e>0){let v=!1;const _=Array.isArray(i.lods);if(_&&e>=i.lods.length?v=!0:_||(v=!0),v)return this.lowresCache.get(s)}const h=Array.isArray(i.lods)?(n=i.lods[e])==null?void 0:n.path:i.lods;if(!h)return x&&!i["missing:uri"]&&(i["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,i)),null;const g=We(o.url,h);if(g.endsWith(".glb")||g.endsWith(".gltf")){if(!i.guid)return console.warn("missing pointer for glb/gltf texture",i),null;const v=g+"_"+i.guid,_=this.previouslyLoaded.get(v);if(_!==void 0){r&&console.log(`LOD ${e} was already loading/loaded: ${v}`);let m=await _.catch(U=>(console.error(`Error loading LOD ${e} from ${g}
|
|
2
|
-
`,
|
|
3
|
-
`,S),null));if(!T)return null;const z=T.parser;r&&console.log("Loading finished "+g,D.guid);let E=0;if(T.parser.json.textures){let S=!1;for(const
|
|
1
|
+
"use strict";var ke=Object.defineProperty;var Ge=(a,t,e)=>t in a?ke(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var f=(a,t,e)=>(Ge(a,typeof t!="symbol"?t+"":t,e),e),be=(a,t,e)=>{if(!t.has(a))throw TypeError("Cannot "+e)};var L=(a,t,e)=>(be(a,t,"read from private field"),e?e.call(a):t.get(a)),K=(a,t,e)=>{if(t.has(a))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(a):t.set(a,e)},$=(a,t,e,r)=>(be(a,t,"write to private field"),r?r.call(a,e):t.set(a,e),e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("three"),Fe=require("three/examples/jsm/loaders/GLTFLoader.js"),Ve=require("three/examples/jsm/libs/meshopt_decoder.module.js"),$e=require("three/examples/jsm/loaders/DRACOLoader.js"),Ne=require("three/examples/jsm/loaders/KTX2Loader.js"),we="";globalThis.GLTF_PROGRESSIVE_VERSION=we;console.debug(`[gltf-progressive] version ${we}`);let de="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ve="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(de+"draco_decoder.js",{method:"head"}).catch(a=>{de="./include/draco/",ve="./include/ktx2/"});function Ue(a){de=a}function ze(a){ve=a}let j,fe,J;function _e(a){return j||(j=new $e.DRACOLoader,j.setDecoderPath(de),j.setDecoderConfig({type:"js"})),J||(J=new Ne.KTX2Loader,J.setTranscoderPath(ve)),fe||(fe=Ve.MeshoptDecoder),a?J.detectSupport(a):a!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:j,ktx2Loader:J,meshoptDecoder:fe}}function Oe(a){a.dracoLoader||a.setDRACOLoader(j),a.ktx2Loader||a.setKTX2Loader(J),a.meshoptDecoder||a.setMeshoptDecoder(fe)}oe("debugprogressive");function oe(a){const e=new URL(window.location.href).searchParams.get(a);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function We(a,t){if(t===void 0||t.startsWith("./")||t.startsWith("http")||a===void 0)return t;const e=a.lastIndexOf("/");if(e>=0){const r=a.substring(0,e+1);for(;r.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return r+t}return t}let te;function qe(){return te!==void 0||(te=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),oe("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",te)),te}const Me=Symbol("needle:raycast-mesh");function ne(a){return(a==null?void 0:a[Me])instanceof d.BufferGeometry?a[Me]:null}function Ce(a,t){if((a.type==="Mesh"||a.type==="SkinnedMesh")&&!ne(a)){const r=Ke(t);r.userData={isRaycastMesh:!0},a[Me]=r}}function Xe(a=!0){if(a){if(re)return;const t=re=d.Mesh.prototype.raycast;d.Mesh.prototype.raycast=function(e,r){const o=this,s=ne(o);let i;s&&o.isMesh&&(i=o.geometry,o.geometry=s),t.call(this,e,r),i&&(o.geometry=i)}}else{if(!re)return;d.Mesh.prototype.raycast=re,re=null}}let re=null;function Ke(a){const t=new d.BufferGeometry;for(const e in a.attributes)t.setAttribute(e,a.getAttribute(e));return t.setIndex(a.getIndex()),t}const Y=new Array,N="NEEDLE_progressive",M=oe("debugprogressive"),me=Symbol("needle-progressive-texture"),ie=new Map,De=new Set;if(M){let a=function(){t+=1,console.log("Toggle LOD level",t,ie),ie.forEach((o,s)=>{for(const i of o.keys){const n=s[i];if(n!=null){if(n.isBufferGeometry===!0){const l=b.getMeshLODInformation(n),u=l?Math.min(t,l.lods.length):0;s["DEBUG:LOD"]=t,b.assignMeshLOD(s,u),l&&(e=Math.max(e,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=t,b.assignTextureLOD(s,t);break}}}}),t>=e&&(t=-1)},t=-1,e=2,r=!1;window.addEventListener("keyup",o=>{o.key==="p"&&a(),o.key==="w"&&(r=!r,De&&De.forEach(s=>{s.name!="BackgroundCubeMaterial"&&s.glyphMap==null&&"wireframe"in s&&(s.wireframe=r)}))})}function Te(a,t,e){var o;if(!M)return;ie.has(a)||ie.set(a,{keys:[],sourceId:e});const r=ie.get(a);((o=r==null?void 0:r.keys)==null?void 0:o.includes(t))==!1&&r.keys.push(t)}const O=class{constructor(t,e){f(this,"parser");f(this,"url");f(this,"_isLoadingMesh");f(this,"loadMesh",t=>{var r,o;if(this._isLoadingMesh)return null;const e=(o=(r=this.parser.json.meshes[t])==null?void 0:r.extensions)==null?void 0:o[N];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(s=>{var i;return this._isLoadingMesh=!1,s&&O.registerMesh(this.url,e.guid,s,(i=e.lods)==null?void 0:i.length,void 0,e),s})):null});M&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return N}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const r=this,o="LODS:minmax",s=t[o];if(s!=null)return s;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const n of t)this.getMaterialMinMaxLODsCount(n,e);return t[o]=e,e}if(M==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const n=t;for(const l of Object.keys(n.uniforms)){const u=n.uniforms[l].value;(u==null?void 0:u.isTexture)===!0&&i(u,e)}}else if(t.isMaterial)for(const n of Object.keys(t)){const l=t[n];(l==null?void 0:l.isTexture)===!0&&i(l,e)}return t[o]=e,e;function i(n,l){const u=r.getAssignedLODInformation(n);if(u){const c=r.lodInfos.get(u.key);if(c&&c.lods){l.min_count=Math.min(l.min_count,c.lods.length),l.max_count=Math.max(l.max_count,c.lods.length);for(let h=0;h<c.lods.length;h++){const g=c.lods[h];g.width&&(l.lods[h]=l.lods[h]||{min_height:1/0,max_height:0},l.lods[h].min_height=Math.min(l.lods[h].min_height,g.height),l.lods[h].max_height=Math.max(l.lods[h].max_height,g.height))}}}}}static hasLODLevelAvailable(t,e){var s;if(Array.isArray(t)){for(const i of t)if(this.hasLODLevelAvailable(i,e))return!0;return!1}if(t.isMaterial===!0){for(const i of Object.keys(t)){const n=t[i];if(n&&n.isTexture&&this.hasLODLevelAvailable(n,e))return!0}return!1}else if(t.isGroup===!0){for(const i of t.children)if(i.isMesh===!0&&this.hasLODLevelAvailable(i,e))return!0}let r,o;if(t.isMesh?r=t.geometry:(t.isBufferGeometry||t.isTexture)&&(r=t),r&&(s=r==null?void 0:r.userData)!=null&&s.LODS){const i=r.userData.LODS;if(o=this.lodInfos.get(i.key),e===void 0)return o!=null;if(o)return Array.isArray(o.lods)?e<o.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof d.Mesh||t.isMesh===!0){const o=t.geometry,s=this.getAssignedLODInformation(o);if(!s)return Promise.resolve(null);for(const i of Y)(r=i.onBeforeGetLODMesh)==null||r.call(i,t,e);return t["LOD:requested level"]=e,O.getOrLoadLOD(o,e).then(i=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(i)){const n=s.index||0;i=i[n]}i&&o!=i&&((i==null?void 0:i.isBufferGeometry)?(t.geometry=i,M&&Te(t,"geometry",s.url)):M&&console.error("Invalid LOD geometry",i))}return i}).catch(i=>(console.error("Error loading mesh LOD",t,i),null))}else M&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof d.Material||t.isMaterial===!0){const r=t,o=[],s=new Array;if(M&&De.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const i=r;for(const n of Object.keys(i.uniforms)){const l=i.uniforms[n].value;if((l==null?void 0:l.isTexture)===!0){const u=this.assignTextureLODForSlot(l,e,r,n);o.push(u),s.push(n)}}}else for(const i of Object.keys(r)){const n=r[i];if((n==null?void 0:n.isTexture)===!0){const l=this.assignTextureLODForSlot(n,e,r,i);o.push(l),s.push(i)}}return Promise.all(o).then(i=>{const n=new Array;for(let l=0;l<i.length;l++){const u=i[l],c=s[l];u&&u.isTexture===!0?n.push({material:r,slot:c,texture:u,level:e}):n.push({material:r,slot:c,texture:null,level:e})}return n})}if(t instanceof d.Texture||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,o){return(t==null?void 0:t.isTexture)!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):O.getOrLoadLOD(t,e).then(s=>{if(Array.isArray(s))return null;if((s==null?void 0:s.isTexture)===!0){if(s!=t){if(r&&o){const i=r[o];if(i){const n=this.getAssignedLODInformation(i);if(n&&(n==null?void 0:n.level)<e)return M==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,e,r,i,s),null}r[o]=s}if(M&&o&&r){const i=this.getAssignedLODInformation(t);i&&Te(r,o,i.url)}}return s}else M=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(s=>(console.error("Error loading LOD",t,s),null))}afterRoot(t){var e,r;return M&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,s)=>{var i;if(o!=null&&o.extensions){const n=o==null?void 0:o.extensions[N];if(n){if(!n.lods){M&&console.warn("Texture has no LODs",n);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const c=this.parser.associations.get(u);(c==null?void 0:c.textures)===s&&(l=!0,O.registerTexture(this.url,u,(i=n.lods)==null?void 0:i.length,s,n))}l||this.parser.getDependency("texture",s).then(u=>{var c;u&&O.registerTexture(this.url,u,(c=n.lods)==null?void 0:c.length,s,n)})}}}),(r=this.parser.json.meshes)==null||r.forEach((o,s)=>{if(o!=null&&o.extensions){const i=o==null?void 0:o.extensions[N];if(i&&i.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const l=this.parser.associations.get(n);(l==null?void 0:l.meshes)===s&&O.registerMesh(this.url,i.guid,n,i.lods.length,l.primitives,i)}}}}),null}static async getOrLoadLOD(t,e){var n,l,u,c;const r=M=="verbose",o=t.userData.LODS;if(!o)return null;const s=o==null?void 0:o.key;let i;if(t.isTexture===!0){const h=t;h.source&&h.source[me]&&(i=h.source[me])}if(i||(i=O.lodInfos.get(s)),i){if(e>0){let v=!1;const _=Array.isArray(i.lods);if(_&&e>=i.lods.length?v=!0:_||(v=!0),v)return this.lowresCache.get(s)}const h=Array.isArray(i.lods)?(n=i.lods[e])==null?void 0:n.path:i.lods;if(!h)return M&&!i["missing:uri"]&&(i["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,i)),null;const g=We(o.url,h);if(g.endsWith(".glb")||g.endsWith(".gltf")){if(!i.guid)return console.warn("missing pointer for glb/gltf texture",i),null;const v=g+"_"+i.guid,_=this.previouslyLoaded.get(v);if(_!==void 0){r&&console.log(`LOD ${e} was already loading/loaded: ${v}`);let p=await _.catch(k=>(console.error(`Error loading LOD ${e} from ${g}
|
|
2
|
+
`,k),null)),x=!1;if(p==null||(p instanceof d.Texture&&t instanceof d.Texture?(l=p.image)!=null&&l.data||(u=p.source)!=null&&u.data?p=this.copySettings(t,p):(x=!0,this.previouslyLoaded.delete(v)):p instanceof d.BufferGeometry&&t instanceof d.BufferGeometry&&((c=p.attributes.position)!=null&&c.array||(x=!0,this.previouslyLoaded.delete(v)))),!x)return p}const D=i,V=new Promise(async(p,x)=>{const k=new Fe.GLTFLoader;Oe(k),M&&(await new Promise(S=>setTimeout(S,1e3)),r&&console.warn("Start loading (delayed) "+g,D.guid));let X=g;if(D&&Array.isArray(D.lods)){const S=D.lods[e];S.hash&&(X+="?v="+S.hash)}const T=await k.loadAsync(X).catch(S=>(console.error(`Error loading LOD ${e} from ${g}
|
|
3
|
+
`,S),null));if(!T)return null;const z=T.parser;r&&console.log("Loading finished "+g,D.guid);let E=0;if(T.parser.json.textures){let S=!1;for(const m of T.parser.json.textures){if(m!=null&&m.extensions){const y=m==null?void 0:m.extensions[N];if(y!=null&&y.guid&&y.guid===D.guid){S=!0;break}}E++}if(S){let m=await z.getDependency("texture",E);return m&&O.assignLODInformation(o.url,m,s,e,void 0,void 0),r&&console.log('change "'+t.name+'" → "'+m.name+'"',g,E,m,v),t instanceof d.Texture&&(m=this.copySettings(t,m)),m&&(m.guid=D.guid),p(m)}else M&&console.warn("Could not find texture with guid",D.guid,T.parser.json)}if(E=0,T.parser.json.meshes){let S=!1;for(const m of T.parser.json.meshes){if(m!=null&&m.extensions){const y=m==null?void 0:m.extensions[N];if(y!=null&&y.guid&&y.guid===D.guid){S=!0;break}}E++}if(S){const m=await z.getDependency("mesh",E),y=D;if(r&&console.log(`Loaded Mesh "${m.name}"`,g,E,m,v),m.isMesh===!0){const w=m.geometry;return O.assignLODInformation(o.url,w,s,e,void 0,y.density),p(w)}else{const w=new Array;for(let A=0;A<m.children.length;A++){const P=m.children[A];if(P.isMesh===!0){const C=P.geometry;O.assignLODInformation(o.url,C,s,e,A,y.density),w.push(C)}}return p(w)}}else M&&console.warn("Could not find mesh with guid",D.guid,T.parser.json)}return p(null)});return this.previouslyLoaded.set(v,V),await V}else if(t instanceof d.Texture){r&&console.log("Load texture from uri: "+g);const _=await new d.TextureLoader().loadAsync(g);return _?(_.guid=i.guid,_.flipY=!1,_.needsUpdate=!0,_.colorSpace=t.colorSpace,r&&console.log(i,_)):M&&console.warn("failed loading",g),_}}else M&&console.warn(`Can not load LOD ${e}: no LOD info found for "${s}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,o,s,i){if(!e)return;e.userData||(e.userData={});const n=new Ye(t,r,o,s,i);e.userData.LODS=n}static getAssignedLODInformation(t){var e;return((e=t==null?void 0:t.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),M&&console.warn(`Copying texture settings
|
|
4
4
|
`,t.uuid,`
|
|
5
|
-
`,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let b=O;f(b,"registerTexture",(t,e,r,o,s)=>{if(x&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,s),!e){x&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[me]=s);const i=s.guid;O.assignLODInformation(t,e,i,r,o,void 0),O.lodInfos.set(i,s),O.lowresCache.set(i,e)}),f(b,"registerMesh",(t,e,r,o,s,i)=>{var u;x&&console.log("> Progressive: register mesh",s,r.name,i,r.uuid,r);const n=r.geometry;if(!n){x&&console.warn("gltf-progressive: Register mesh without geometry");return}n.userData||(n.userData={}),O.assignLODInformation(t,n,e,o,s,i.density),O.lodInfos.set(e,i);let l=O.lowresCache.get(e);l?l.push(r.geometry):l=[r.geometry],O.lowresCache.set(e,l),o>0&&!ge(r)&&Ce(r,n);for(const c of Y)(u=c.onRegisteredNewMesh)==null||u.call(c,r,i)}),f(b,"lodInfos",new Map),f(b,"previouslyLoaded",new Map),f(b,"lowresCache",new Map);class Ye{constructor(t,e,r,o,s){f(this,"url");f(this,"key");f(this,"level");f(this,"index");f(this,"density");this.url=t,this.key=e,this.level=r,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const k=oe("debugprogressive"),He=oe("noprogressive"),Le=Symbol("Needle:LODSManager"),xe=Symbol("Needle:LODState"),H=Symbol("Needle:CurrentLOD"),G={mesh_lod:-1,texture_lod:-1};var I,W,de,Q,Z,he,q;const B=class{constructor(t,e){f(this,"context");f(this,"renderer");f(this,"projectionScreenMatrix",new d.Matrix4);f(this,"cameraFrustrum",new d.Frustum);f(this,"targetTriangleDensity",2e5);f(this,"updateInterval","auto");K(this,I,1);f(this,"pause",!1);f(this,"manual",!1);f(this,"_lodchangedlisteners",[]);K(this,W,void 0);K(this,de,new d.Clock);K(this,Q,0);K(this,Z,0);K(this,he,0);K(this,q,0);f(this,"_fpsBuffer",[60,60,60,60,60]);f(this,"_sphere",new d.Sphere);f(this,"_tempBox",new d.Box3);f(this,"_tempBox2",new d.Box3);f(this,"tempMatrix",new d.Matrix4);f(this,"_tempWorldPosition",new d.Vector3);f(this,"_tempBoxSize",new d.Vector3);f(this,"_tempBox2Size",new d.Vector3);this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[xe]}static addPlugin(t){Y.push(t)}static removePlugin(t){const e=Y.indexOf(t);e>=0&&Y.splice(e,1)}static get(t,e){if(t[Le])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[Le];const r=new B(t,{engine:"unknown",...e});return t[Le]=r,r}get plugins(){return Y}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}enable(){if(L(this,W))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;V(this,W,this.renderer.render);const e=this;_e(this.renderer),this.renderer.render=function(r,o){const s=e.renderer.getRenderTarget();(s==null||"isXRRenderTarget"in s&&s.isXRRenderTarget)&&(t=0,V(e,Q,L(e,Q)+1),V(e,Z,L(e,de).getDelta()),V(e,he,L(e,he)+L(e,Z)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/L(e,Z)),V(e,q,e._fpsBuffer.reduce((n,l)=>n+l)/e._fpsBuffer.length),k&&L(e,Q)%30===0&&console.log("FPS",Math.round(L(e,q)),"Interval:",L(e,I)));const i=t++;L(e,W).call(this,r,o),e.onAfterRender(r,o,i)}}disable(){L(this,W)&&(this.renderer.render=L(this,W),V(this,W,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,r){if(this.pause)return;const s=this.renderer.renderLists.get(t,0).opaque;let i=!0;if(s.length===1){const n=s[0].material;(n.name==="EffectMaterial"||n.name==="CopyShader")&&(i=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(i=!1),i){if(He||(this.updateInterval==="auto"?L(this,q)<40&&L(this,I)<10?(V(this,I,L(this,I)+1),k&&console.warn("↓ Reducing LOD updates",L(this,I),L(this,q).toFixed(0))):L(this,q)>=60&&L(this,I)>1&&(V(this,I,L(this,I)-1),k&&console.warn("↑ Increasing LOD updates",L(this,I),L(this,q).toFixed(0))):V(this,I,this.updateInterval),L(this,I)>0&&L(this,Q)%L(this,I)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var l,u;const r=this.renderer.renderLists.get(t,0),o=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const s=this.targetTriangleDensity;for(const c of o){if(c.material&&(((l=c.geometry)==null?void 0:l.type)==="BoxGeometry"||((u=c.geometry)==null?void 0:u.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){k&&(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",c,c.material.name,c.material.type)));continue}switch(c.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(k==="color"&&c.material&&!c.object.progressive_debug_color){c.object.progressive_debug_color=!0;const g=Math.random()*16777215,v=new d.MeshStandardMaterial({color:g});c.object.material=v}const h=c.object;(h instanceof d.Mesh||h.isMesh)&&this.updateLODs(t,e,h,s)}const i=r.transparent;for(const c of i){const h=c.object;(h instanceof d.Mesh||h.isMesh)&&this.updateLODs(t,e,h,s)}const n=r.transmissive;for(const c of n){const h=c.object;(h instanceof d.Mesh||h.isMesh)&&this.updateLODs(t,e,h,s)}}updateLODs(t,e,r,o){var n,l;r.userData||(r.userData={});let s=r[xe];if(s||(s=new je,r[xe]=s),s.frames++<2)return;for(const u of Y)(n=u.onBeforeUpdateLOD)==null||n.call(u,this.renderer,t,e,r);this.calculateLodLevel(e,r,s,o,G),G.mesh_lod=Math.round(G.mesh_lod),G.texture_lod=Math.round(G.texture_lod),G.mesh_lod>=0&&this.loadProgressiveMeshes(r,G.mesh_lod);let i=G.texture_lod;if(r.material&&i>=0){const u=r["DEBUG:LOD"];u!=null&&(i=u),this.loadProgressiveTextures(r.material,i)}for(const u of Y)(l=u.onAfterUpdatedLOD)==null||l.call(u,this.renderer,t,e,r,G);s.lastLodLevel_Mesh=G.mesh_lod,s.lastLodLevel_Texture=G.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}let r=!1;(t[H]===void 0||e<t[H])&&(r=!0),r&&(t[H]=e,b.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(s=>s({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[H]!==e){t[H]=e;const r=t.geometry;return b.assignMeshLOD(t,e).then(o=>(o&&t[H]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(s=>s({type:"mesh",level:e,object:t})),o))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,o=t.max,s=(r.x+o.x)*.5,i=(r.y+o.y)*.5;return this._tempPtInside.set(s,i,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,o,s){var F,N;if(!e){s.mesh_lod=-1,s.texture_lod=-1;return}if(!t){s.mesh_lod=-1,s.texture_lod=-1;return}let n=10+1,l=!1;if(k&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=b.getMeshLODInformation(e.geometry),c=u==null?void 0:u.lods,h=c&&c.length>0,g=b.getMaterialMinMaxLODsCount(e.material),v=(g==null?void 0:g.min_count)!=1/0&&g.min_count>0&&g.max_count>0;if(!h&&!v){s.mesh_lod=0,s.texture_lod=0;return}if(h||(l=!0,n=0),!((F=this.cameraFrustrum)!=null&&F.intersectsObject(e))){s.mesh_lod=99,s.texture_lod=99;return}const _=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let D=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const m=e;m.boundingBox||m.computeBoundingBox(),D=m.boundingBox}if(D&&t.isPerspectiveCamera){const m=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const p=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(p)){s.mesh_lod=0,s.texture_lod=0;return}}if(this._tempBox.copy(D),this._tempBox.applyMatrix4(e.matrixWorld),B.isInside(this._tempBox,this.projectionScreenMatrix)){s.mesh_lod=0,s.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&m.fov>70){const p=this._tempBox.min,w=this._tempBox.max;let A=p.x,P=p.y,C=w.x,ee=w.y;const ne=2,pe=1.5,ae=(p.x+w.x)*.5,le=(p.y+w.y)*.5;A=(A-ae)*ne+ae,P=(P-le)*ne+le,C=(C-ae)*ne+ae,ee=(ee-le)*ne+le;const Ie=A<0&&C>0?0:Math.min(Math.abs(p.x),Math.abs(w.x)),Re=P<0&&ee>0?0:Math.min(Math.abs(p.y),Math.abs(w.y)),ye=Math.max(Ie,Re);r.lastCentrality=(pe-ye)*(pe-ye)*(pe-ye)}else r.lastCentrality=1;const M=this._tempBox.getSize(this._tempBoxSize);M.multiplyScalar(.5),screen.availHeight>0&&_>0&&M.multiplyScalar(_/screen.availHeight),M.x*=m.aspect;const U=t.matrixWorldInverse,X=this._tempBox2;X.copy(D),X.applyMatrix4(e.matrixWorld),X.applyMatrix4(U);const T=X.getSize(this._tempBox2Size),z=Math.max(T.x,T.y);if(Math.max(M.x,M.y)!=0&&z!=0&&(M.z=T.z/Math.max(T.x,T.y)*Math.max(M.x,M.y)),r.lastScreenCoverage=Math.max(M.x,M.y,M.z),r.lastScreenspaceVolume.copy(M),r.lastScreenCoverage*=r.lastCentrality,k&&B.debugDrawLine){const p=this.tempMatrix.copy(this.projectionScreenMatrix);p.invert();const w=B.corner0,A=B.corner1,P=B.corner2,C=B.corner3;w.copy(this._tempBox.min),A.copy(this._tempBox.max),A.x=w.x,P.copy(this._tempBox.max),P.y=w.y,C.copy(this._tempBox.max);const ee=(w.z+C.z)*.5;w.z=A.z=P.z=C.z=ee,w.applyMatrix4(p),A.applyMatrix4(p),P.applyMatrix4(p),C.applyMatrix4(p),B.debugDrawLine(w,A,255),B.debugDrawLine(w,P,255),B.debugDrawLine(A,C,255),B.debugDrawLine(P,C,255)}let S=999;if(c&&r.lastScreenCoverage>0){for(let p=0;p<c.length;p++)if(c[p].density/r.lastScreenCoverage<o){S=p;break}}S<n&&(n=S,l=!0)}if(l?s.mesh_lod=n:s.mesh_lod=r.lastLodLevel_Mesh,k&&s.mesh_lod!=r.lastLodLevel_Mesh){const M=c==null?void 0:c[s.mesh_lod];M&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${s.mesh_lod} (${M.density.toFixed(0)}) - ${e.name}`)}if(v){const m="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(s.texture_lod=g.max_count-1,k){const M=g.lods[g.max_count-1];k&&console.log(`First Texture LOD ${s.texture_lod} (${M.max_height}px) - ${e.name}`)}}else{const M=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let U=r.lastScreenCoverage*2;((N=this.context)==null?void 0:N.engine)==="model-viewer"&&(U*=2);const T=_/window.devicePixelRatio*U;for(let z=g.lods.length-1;z>=0;z--){let E=g.lods[z];if(!(m&&E.max_height>=2048)&&!(qe()&&E.max_height>4096)&&E.max_height>T){if(s.texture_lod=z,s.texture_lod<r.lastLodLevel_Texture){const S=E.max_height;k&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${s.texture_lod} = ${S}px
|
|
6
|
-
Screensize: ${T.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${
|
|
7
|
-
${e.name}`)}break}}}}else s.texture_lod=0}};let R=B;I=new WeakMap,W=new WeakMap,
|
|
8
|
-
`,a.getAttribute("src"));let t=null,e=null,r=null;for(let o=a;o!=null;o=Object.getPrototypeOf(o)){const s=Object.getOwnPropertySymbols(o),i=s.find(u=>u.toString()=="Symbol(renderer)"),n=s.find(u=>u.toString()=="Symbol(scene)"),l=s.find(u=>u.toString()=="Symbol(needsRender)");!t&&i!=null&&(t=a[i].threeRenderer),!e&&n!=null&&(e=a[n]),!r&&l!=null&&(r=a[l])}if(t&&e){let o=function(){if(r){let i=0,n=setInterval(()=>{if(i++>5){clearInterval(n);return}r==null||r.call(a)},300)}};console.debug("[gltf-progressive] setup model-viewer");const s=R.get(t,{engine:"model-viewer"});return R.addPlugin(new Ze),s.enable(),s.addEventListener("changed",()=>{r==null||r.call(a)}),a.addEventListener("model-visibility",i=>{i.detail.visible&&(r==null||r.call(a))}),a.addEventListener("load",()=>{o()}),()=>{s.disable()}}return null}class Ze{constructor(){f(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(t,e,r,o){this.tryParseMeshLOD(e,o),this.tryParseTextureLOD(e,o)}getUrl(t){if(!t)return null;let e=t.getAttribute("src");return e||(e=t.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",t),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(t){return t._currentGLTF}tryGetCurrentModelViewer(t){return t.element}tryParseTextureLOD(t,e){if(e[
|
|
5
|
+
`,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let b=O;f(b,"registerTexture",(t,e,r,o,s)=>{if(M&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,s),!e){M&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[me]=s);const i=s.guid;O.assignLODInformation(t,e,i,r,o,void 0),O.lodInfos.set(i,s),O.lowresCache.set(i,e)}),f(b,"registerMesh",(t,e,r,o,s,i)=>{var u;M&&console.log("> Progressive: register mesh",s,r.name,i,r.uuid,r);const n=r.geometry;if(!n){M&&console.warn("gltf-progressive: Register mesh without geometry");return}n.userData||(n.userData={}),O.assignLODInformation(t,n,e,o,s,i.density),O.lodInfos.set(e,i);let l=O.lowresCache.get(e);l?l.push(r.geometry):l=[r.geometry],O.lowresCache.set(e,l),o>0&&!ne(r)&&Ce(r,n);for(const c of Y)(u=c.onRegisteredNewMesh)==null||u.call(c,r,i)}),f(b,"lodInfos",new Map),f(b,"previouslyLoaded",new Map),f(b,"lowresCache",new Map);class Ye{constructor(t,e,r,o,s){f(this,"url");f(this,"key");f(this,"level");f(this,"index");f(this,"density");this.url=t,this.key=e,this.level=r,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const G=oe("debugprogressive"),He=oe("noprogressive"),xe=Symbol("Needle:LODSManager"),Le=Symbol("Needle:LODState"),H=Symbol("Needle:CurrentLOD"),F={mesh_lod:-1,texture_lod:-1};var I,W,he,Q,Z,ge,q;const B=class{constructor(t,e){f(this,"context");f(this,"renderer");f(this,"projectionScreenMatrix",new d.Matrix4);f(this,"cameraFrustrum",new d.Frustum);f(this,"targetTriangleDensity",2e5);f(this,"updateInterval","auto");K(this,I,1);f(this,"pause",!1);f(this,"manual",!1);f(this,"_lodchangedlisteners",[]);K(this,W,void 0);K(this,he,new d.Clock);K(this,Q,0);K(this,Z,0);K(this,ge,0);K(this,q,0);f(this,"_fpsBuffer",[60,60,60,60,60]);f(this,"_sphere",new d.Sphere);f(this,"_tempBox",new d.Box3);f(this,"_tempBox2",new d.Box3);f(this,"tempMatrix",new d.Matrix4);f(this,"_tempWorldPosition",new d.Vector3);f(this,"_tempBoxSize",new d.Vector3);f(this,"_tempBox2Size",new d.Vector3);this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[Le]}static addPlugin(t){Y.push(t)}static removePlugin(t){const e=Y.indexOf(t);e>=0&&Y.splice(e,1)}static get(t,e){if(t[xe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[xe];const r=new B(t,{engine:"unknown",...e});return t[xe]=r,r}get plugins(){return Y}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const r=this._lodchangedlisteners.indexOf(e);r>=0&&this._lodchangedlisteners.splice(r,1)}}enable(){if(L(this,W))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;$(this,W,this.renderer.render);const e=this;_e(this.renderer),this.renderer.render=function(r,o){const s=e.renderer.getRenderTarget();(s==null||"isXRRenderTarget"in s&&s.isXRRenderTarget)&&(t=0,$(e,Q,L(e,Q)+1),$(e,Z,L(e,he).getDelta()),$(e,ge,L(e,ge)+L(e,Z)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/L(e,Z)),$(e,q,e._fpsBuffer.reduce((n,l)=>n+l)/e._fpsBuffer.length),G&&L(e,Q)%30===0&&console.log("FPS",Math.round(L(e,q)),"Interval:",L(e,I)));const i=t++;L(e,W).call(this,r,o),e.onAfterRender(r,o,i)}}disable(){L(this,W)&&(this.renderer.render=L(this,W),$(this,W,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,r){if(this.pause)return;const s=this.renderer.renderLists.get(t,0).opaque;let i=!0;if(s.length===1){const n=s[0].material;(n.name==="EffectMaterial"||n.name==="CopyShader")&&(i=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(i=!1),i){if(He||(this.updateInterval==="auto"?L(this,q)<40&&L(this,I)<10?($(this,I,L(this,I)+1),G&&console.warn("↓ Reducing LOD updates",L(this,I),L(this,q).toFixed(0))):L(this,q)>=60&&L(this,I)>1&&($(this,I,L(this,I)-1),G&&console.warn("↑ Increasing LOD updates",L(this,I),L(this,q).toFixed(0))):$(this,I,this.updateInterval),L(this,I)>0&&L(this,Q)%L(this,I)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var l,u;const r=this.renderer.renderLists.get(t,0),o=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const s=this.targetTriangleDensity;for(const c of o){if(c.material&&(((l=c.geometry)==null?void 0:l.type)==="BoxGeometry"||((u=c.geometry)==null?void 0:u.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){G&&(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",c,c.material.name,c.material.type)));continue}switch(c.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(G==="color"&&c.material&&!c.object.progressive_debug_color){c.object.progressive_debug_color=!0;const g=Math.random()*16777215,v=new d.MeshStandardMaterial({color:g});c.object.material=v}const h=c.object;(h instanceof d.Mesh||h.isMesh)&&this.updateLODs(t,e,h,s)}const i=r.transparent;for(const c of i){const h=c.object;(h instanceof d.Mesh||h.isMesh)&&this.updateLODs(t,e,h,s)}const n=r.transmissive;for(const c of n){const h=c.object;(h instanceof d.Mesh||h.isMesh)&&this.updateLODs(t,e,h,s)}}updateLODs(t,e,r,o){var n,l;r.userData||(r.userData={});let s=r[Le];if(s||(s=new je,r[Le]=s),s.frames++<2)return;for(const u of Y)(n=u.onBeforeUpdateLOD)==null||n.call(u,this.renderer,t,e,r);this.calculateLodLevel(e,r,s,o,F),F.mesh_lod=Math.round(F.mesh_lod),F.texture_lod=Math.round(F.texture_lod),F.mesh_lod>=0&&this.loadProgressiveMeshes(r,F.mesh_lod);let i=F.texture_lod;if(r.material&&i>=0){const u=r["DEBUG:LOD"];u!=null&&(i=u),this.loadProgressiveTextures(r.material,i)}for(const u of Y)(l=u.onAfterUpdatedLOD)==null||l.call(u,this.renderer,t,e,r,F);s.lastLodLevel_Mesh=F.mesh_lod,s.lastLodLevel_Texture=F.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}let r=!1;(t[H]===void 0||e<t[H])&&(r=!0),r&&(t[H]=e,b.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(s=>s({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[H]!==e){t[H]=e;const r=t.geometry;return b.assignMeshLOD(t,e).then(o=>(o&&t[H]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(s=>s({type:"mesh",level:e,object:t})),o))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,o=t.max,s=(r.x+o.x)*.5,i=(r.y+o.y)*.5;return this._tempPtInside.set(s,i,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,o,s){var V,U;if(!e){s.mesh_lod=-1,s.texture_lod=-1;return}if(!t){s.mesh_lod=-1,s.texture_lod=-1;return}let n=10+1,l=!1;if(G&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=b.getMeshLODInformation(e.geometry),c=u==null?void 0:u.lods,h=c&&c.length>0,g=b.getMaterialMinMaxLODsCount(e.material),v=(g==null?void 0:g.min_count)!=1/0&&g.min_count>0&&g.max_count>0;if(!h&&!v){s.mesh_lod=0,s.texture_lod=0;return}if(h||(l=!0,n=0),!((V=this.cameraFrustrum)!=null&&V.intersectsObject(e))){s.mesh_lod=100,s.texture_lod=100;return}const _=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let D=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const p=e;if(!p.boundingBox)p.computeBoundingBox();else if(r.frames%30===0){const x=ne(p),k=p.geometry;x&&(p.geometry=x),p.computeBoundingBox(),p.geometry=k}D=p.boundingBox}if(D&&t.isPerspectiveCamera){const p=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const y=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(y)){s.mesh_lod=0,s.texture_lod=0;return}}if(this._tempBox.copy(D),this._tempBox.applyMatrix4(e.matrixWorld),B.isInside(this._tempBox,this.projectionScreenMatrix)){s.mesh_lod=0,s.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&p.fov>70){const y=this._tempBox.min,w=this._tempBox.max;let A=y.x,P=y.y,C=w.x,ee=w.y;const ae=2,pe=1.5,le=(y.x+w.x)*.5,ce=(y.y+w.y)*.5;A=(A-le)*ae+le,P=(P-ce)*ae+ce,C=(C-le)*ae+le,ee=(ee-ce)*ae+ce;const Ie=A<0&&C>0?0:Math.min(Math.abs(y.x),Math.abs(w.x)),Re=P<0&&ee>0?0:Math.min(Math.abs(y.y),Math.abs(w.y)),ye=Math.max(Ie,Re);r.lastCentrality=(pe-ye)*(pe-ye)*(pe-ye)}else r.lastCentrality=1;const x=this._tempBox.getSize(this._tempBoxSize);x.multiplyScalar(.5),screen.availHeight>0&&_>0&&x.multiplyScalar(_/screen.availHeight),x.x*=p.aspect;const k=t.matrixWorldInverse,X=this._tempBox2;X.copy(D),X.applyMatrix4(e.matrixWorld),X.applyMatrix4(k);const T=X.getSize(this._tempBox2Size),z=Math.max(T.x,T.y);if(Math.max(x.x,x.y)!=0&&z!=0&&(x.z=T.z/Math.max(T.x,T.y)*Math.max(x.x,x.y)),r.lastScreenCoverage=Math.max(x.x,x.y,x.z),r.lastScreenspaceVolume.copy(x),r.lastScreenCoverage*=r.lastCentrality,G&&B.debugDrawLine){const y=this.tempMatrix.copy(this.projectionScreenMatrix);y.invert();const w=B.corner0,A=B.corner1,P=B.corner2,C=B.corner3;w.copy(this._tempBox.min),A.copy(this._tempBox.max),A.x=w.x,P.copy(this._tempBox.max),P.y=w.y,C.copy(this._tempBox.max);const ee=(w.z+C.z)*.5;w.z=A.z=P.z=C.z=ee,w.applyMatrix4(y),A.applyMatrix4(y),P.applyMatrix4(y),C.applyMatrix4(y),B.debugDrawLine(w,A,255),B.debugDrawLine(w,P,255),B.debugDrawLine(A,C,255),B.debugDrawLine(P,C,255)}let S=999;if(c&&r.lastScreenCoverage>0){for(let y=0;y<c.length;y++)if(c[y].density/r.lastScreenCoverage<o){S=y;break}}S<n&&(n=S,l=!0)}if(l?s.mesh_lod=n:s.mesh_lod=r.lastLodLevel_Mesh,G&&s.mesh_lod!=r.lastLodLevel_Mesh){const x=c==null?void 0:c[s.mesh_lod];x&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${s.mesh_lod} (${x.density.toFixed(0)}) - ${e.name}`)}if(v){const p="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(s.texture_lod=g.max_count-1,G){const x=g.lods[g.max_count-1];G&&console.log(`First Texture LOD ${s.texture_lod} (${x.max_height}px) - ${e.name}`)}}else{const x=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let k=r.lastScreenCoverage*2;((U=this.context)==null?void 0:U.engine)==="model-viewer"&&(k*=2);const T=_/window.devicePixelRatio*k;for(let z=g.lods.length-1;z>=0;z--){let E=g.lods[z];if(!(p&&E.max_height>=2048)&&!(qe()&&E.max_height>4096)&&E.max_height>T){if(s.texture_lod=z,s.texture_lod<r.lastLodLevel_Texture){const S=E.max_height;G&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${s.texture_lod} = ${S}px
|
|
6
|
+
Screensize: ${T.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${x.toFixed(1)}
|
|
7
|
+
${e.name}`)}break}}}}else s.texture_lod=0}};let R=B;I=new WeakMap,W=new WeakMap,he=new WeakMap,Q=new WeakMap,Z=new WeakMap,ge=new WeakMap,q=new WeakMap,f(R,"debugDrawLine"),f(R,"corner0",new d.Vector3),f(R,"corner1",new d.Vector3),f(R,"corner2",new d.Vector3),f(R,"corner3",new d.Vector3),f(R,"_tempPtInside",new d.Vector3);class je{constructor(){f(this,"frames",0);f(this,"lastLodLevel_Mesh",-1);f(this,"lastLodLevel_Texture",-1);f(this,"lastScreenCoverage",0);f(this,"lastScreenspaceVolume",new d.Vector3);f(this,"lastCentrality",0)}}const Ae=Symbol("NEEDLE_mesh_lod"),ue=Symbol("NEEDLE_texture_lod");let se=null;function Se(){const a=Je();a&&(a.mapURLs(function(t){return Ee(),t}),Ee(),se==null||se.disconnect(),se=new MutationObserver(t=>{t.forEach(e=>{e.addedNodes.forEach(r=>{r instanceof HTMLElement&&r.tagName.toLowerCase()==="model-viewer"&&Be(r)})})}),se.observe(document,{childList:!0,subtree:!0}))}function Je(){const a=customElements.get("model-viewer");return a||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Se()}),null)}function Ee(){document.querySelectorAll("model-viewer").forEach(t=>{Be(t)})}const Pe=new WeakSet;let Qe=0;function Be(a){if(!a||Pe.has(a))return null;Pe.add(a),console.debug("[gltf-progressive] found new model-viewer..."+ ++Qe+`
|
|
8
|
+
`,a.getAttribute("src"));let t=null,e=null,r=null;for(let o=a;o!=null;o=Object.getPrototypeOf(o)){const s=Object.getOwnPropertySymbols(o),i=s.find(u=>u.toString()=="Symbol(renderer)"),n=s.find(u=>u.toString()=="Symbol(scene)"),l=s.find(u=>u.toString()=="Symbol(needsRender)");!t&&i!=null&&(t=a[i].threeRenderer),!e&&n!=null&&(e=a[n]),!r&&l!=null&&(r=a[l])}if(t&&e){let o=function(){if(r){let i=0,n=setInterval(()=>{if(i++>5){clearInterval(n);return}r==null||r.call(a)},300)}};console.debug("[gltf-progressive] setup model-viewer");const s=R.get(t,{engine:"model-viewer"});return R.addPlugin(new Ze),s.enable(),s.addEventListener("changed",()=>{r==null||r.call(a)}),a.addEventListener("model-visibility",i=>{i.detail.visible&&(r==null||r.call(a))}),a.addEventListener("load",()=>{o()}),()=>{s.disable()}}return null}class Ze{constructor(){f(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(t,e,r,o){this.tryParseMeshLOD(e,o),this.tryParseTextureLOD(e,o)}getUrl(t){if(!t)return null;let e=t.getAttribute("src");return e||(e=t.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",t),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(t){return t._currentGLTF}tryGetCurrentModelViewer(t){return t.element}tryParseTextureLOD(t,e){if(e[ue]==!0)return;e[ue]=!0;const r=this.tryGetCurrentGLTF(t),o=this.tryGetCurrentModelViewer(t),s=this.getUrl(o);if(s&&r&&e.material){let i=function(l){var c,h,g;if(l[ue]==!0)return;l[ue]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let v=0;v<u.length;v++){const _=u[v],D=l[_];if((D==null?void 0:D.isTexture)===!0){const V=(h=(c=D.userData)==null?void 0:c.associations)==null?void 0:h.textures;if(V==null)continue;const U=r.parser.json.textures[V];if(!U){console.warn("Texture data not found for texture index "+V);continue}if((g=U==null?void 0:U.extensions)!=null&&g[N]){const p=U.extensions[N];p&&s&&b.registerTexture(s,D,p.lods.length,V,p)}}}};const n=e.material;if(Array.isArray(n))for(const l of n)i(l);else i(n)}}tryParseMeshLOD(t,e){var i,n;if(e[Ae]==!0)return;e[Ae]=!0;const r=this.tryGetCurrentModelViewer(t),o=this.getUrl(r);if(!o)return;const s=(n=(i=e.userData)==null?void 0:i.gltfExtensions)==null?void 0:n[N];if(s&&o){const l=e.uuid;b.registerMesh(o,l,e,0,s.lods.length,s)}}}function et(a,t,e,r){_e(t),Oe(e),e.register(s=>new b(s,a));const o=R.get(t);return(r==null?void 0:r.enableLODsManager)!==!1&&o.enable(),o}Se();exports.EXTENSION_NAME=N;exports.LODsManager=R;exports.NEEDLE_progressive=b;exports.VERSION=we;exports.addDracoAndKTX2Loaders=Oe;exports.createLoaders=_e;exports.getRaycastMesh=ne;exports.patchModelViewer=Se;exports.registerRaycastMesh=Ce;exports.setDracoDecoderLocation=Ue;exports.setKTX2TranscoderLocation=ze;exports.useNeedleProgressive=et;exports.useRaycastMeshes=Xe;
|
package/lib/lods_manager.d.ts
CHANGED
|
@@ -85,6 +85,7 @@ export declare class LODsManager {
|
|
|
85
85
|
manual: boolean;
|
|
86
86
|
private readonly _lodchangedlisteners;
|
|
87
87
|
addEventListener(evt: "changed", listener: LODChangedEventListener): void;
|
|
88
|
+
removeEventListener(evt: "changed", listener: LODChangedEventListener): void;
|
|
88
89
|
private constructor();
|
|
89
90
|
private _fpsBuffer;
|
|
90
91
|
/**
|
package/lib/lods_manager.js
CHANGED
|
@@ -3,6 +3,7 @@ import { NEEDLE_progressive } from "./extension.js";
|
|
|
3
3
|
import { createLoaders } from "./loaders.js";
|
|
4
4
|
import { getParam, isMobileDevice } from "./utils.internal.js";
|
|
5
5
|
import { plugins } from "./plugins/plugin.js";
|
|
6
|
+
import { getRaycastMesh } from "./utils.js";
|
|
6
7
|
const debugProgressiveLoading = getParam("debugprogressive");
|
|
7
8
|
const suppressProgressiveLoading = getParam("noprogressive");
|
|
8
9
|
const $lodsManager = Symbol("Needle:LODSManager");
|
|
@@ -105,6 +106,13 @@ export class LODsManager {
|
|
|
105
106
|
this._lodchangedlisteners.push(listener);
|
|
106
107
|
}
|
|
107
108
|
}
|
|
109
|
+
removeEventListener(evt, listener) {
|
|
110
|
+
if (evt === "changed") {
|
|
111
|
+
const index = this._lodchangedlisteners.indexOf(listener);
|
|
112
|
+
if (index >= 0)
|
|
113
|
+
this._lodchangedlisteners.splice(index, 1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
108
116
|
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
109
117
|
constructor(renderer, context) {
|
|
110
118
|
this.renderer = renderer;
|
|
@@ -431,8 +439,8 @@ export class LODsManager {
|
|
|
431
439
|
}
|
|
432
440
|
if (!this.cameraFrustrum?.intersectsObject(mesh)) {
|
|
433
441
|
// the object is not visible by the camera
|
|
434
|
-
result.mesh_lod =
|
|
435
|
-
result.texture_lod =
|
|
442
|
+
result.mesh_lod = 100;
|
|
443
|
+
result.texture_lod = 100;
|
|
436
444
|
return;
|
|
437
445
|
}
|
|
438
446
|
const canvasHeight = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
|
|
@@ -442,6 +450,17 @@ export class LODsManager {
|
|
|
442
450
|
if (!skinnedMesh.boundingBox) {
|
|
443
451
|
skinnedMesh.computeBoundingBox();
|
|
444
452
|
}
|
|
453
|
+
// Fix: https://linear.app/needle/issue/NE-5264
|
|
454
|
+
else if (state.frames % 30 === 0) {
|
|
455
|
+
// use lowres geometry for bounding box calculation
|
|
456
|
+
const raycastmesh = getRaycastMesh(skinnedMesh);
|
|
457
|
+
const originalGeometry = skinnedMesh.geometry;
|
|
458
|
+
if (raycastmesh) {
|
|
459
|
+
skinnedMesh.geometry = raycastmesh;
|
|
460
|
+
}
|
|
461
|
+
skinnedMesh.computeBoundingBox();
|
|
462
|
+
skinnedMesh.geometry = originalGeometry;
|
|
463
|
+
}
|
|
445
464
|
boundingBox = skinnedMesh.boundingBox;
|
|
446
465
|
}
|
|
447
466
|
if (boundingBox && camera.isPerspectiveCamera) {
|
package/lib/version.js
CHANGED
package/package.json
CHANGED