@needle-tools/gltf-progressive 2.1.0-alpha.3 → 2.1.0-alpha.4
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/gltf-progressive.js +74 -73
- package/gltf-progressive.min.js +6 -6
- package/gltf-progressive.umd.cjs +5 -5
- package/lib/lods_manager.js +3 -1
- 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
|
+
## [2.1.0-alpha.4] - 2025-01-29
|
|
8
|
+
- Fix: LOD not loading if the max texture resolution is too small
|
|
9
|
+
|
|
7
10
|
## [2.1.0-alpha.3] - 2025-01-21
|
|
8
11
|
- Change: Load Draco and KTX loaders as soon as possible
|
|
9
12
|
- Fix: Make `GET` request to draco endpoint with 1 byte range instead of HEAD request. The HEAD request did return the whole draco loader.
|
package/gltf-progressive.js
CHANGED
|
@@ -9,7 +9,7 @@ var m = (o, e, t) => (Te(o, e, "read from private field"), t ? t.call(o) : e.get
|
|
|
9
9
|
throw TypeError("Cannot add the same private member more than once");
|
|
10
10
|
e instanceof WeakSet ? e.add(o) : e.set(o, t);
|
|
11
11
|
}, U = (o, e, t, s) => (Te(o, e, "write to private field"), s ? s.call(o, t) : e.set(o, t), t);
|
|
12
|
-
import { BufferGeometry as ge, Mesh as Q, Material as Xe, Texture as se, TextureLoader as Ke, Matrix4 as Ae, Clock as Ye, MeshStandardMaterial as He, Sphere as Je, Box3 as Ee, Vector3 as
|
|
12
|
+
import { BufferGeometry as ge, Mesh as Q, Material as Xe, Texture as se, TextureLoader as Ke, Matrix4 as Ae, Clock as Ye, MeshStandardMaterial as He, Sphere as Je, Box3 as Ee, Vector3 as z } from "three";
|
|
13
13
|
import { GLTFLoader as be } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
14
14
|
import { MeshoptDecoder as Qe } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
15
15
|
import { DRACOLoader as Ze } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
@@ -118,7 +118,7 @@ function ct(o) {
|
|
|
118
118
|
e.setAttribute(t, o.getAttribute(t));
|
|
119
119
|
return e.setIndex(o.getIndex()), e;
|
|
120
120
|
}
|
|
121
|
-
const Y = new Array(),
|
|
121
|
+
const Y = new Array(), V = "NEEDLE_progressive", L = le("debugprogressive"), De = Symbol("needle-progressive-texture"), oe = /* @__PURE__ */ new Map(), Se = /* @__PURE__ */ new Set();
|
|
122
122
|
if (L) {
|
|
123
123
|
let o = function() {
|
|
124
124
|
e += 1, console.log("Toggle LOD level", e, oe), oe.forEach((n, r) => {
|
|
@@ -159,7 +159,7 @@ const v = class {
|
|
|
159
159
|
var s, n;
|
|
160
160
|
if (this._isLoadingMesh)
|
|
161
161
|
return null;
|
|
162
|
-
const t = (n = (s = this.parser.json.meshes[e]) == null ? void 0 : s.extensions) == null ? void 0 : n[
|
|
162
|
+
const t = (n = (s = this.parser.json.meshes[e]) == null ? void 0 : s.extensions) == null ? void 0 : n[V];
|
|
163
163
|
return t ? (this._isLoadingMesh = !0, this.parser.getDependency("mesh", e).then((r) => {
|
|
164
164
|
var i;
|
|
165
165
|
return this._isLoadingMesh = !1, r && v.registerMesh(this.url, t.guid, r, (i = t.lods) == null ? void 0 : i.length, void 0, t), r;
|
|
@@ -169,7 +169,7 @@ const v = class {
|
|
|
169
169
|
}
|
|
170
170
|
/** The name of the extension */
|
|
171
171
|
get name() {
|
|
172
|
-
return
|
|
172
|
+
return V;
|
|
173
173
|
}
|
|
174
174
|
static getMeshLODInformation(e) {
|
|
175
175
|
const t = this.getAssignedLODInformation(e);
|
|
@@ -369,7 +369,7 @@ const v = class {
|
|
|
369
369
|
return L && console.log("AFTER", this.url, e), (t = this.parser.json.textures) == null || t.forEach((n, r) => {
|
|
370
370
|
var i;
|
|
371
371
|
if (n != null && n.extensions) {
|
|
372
|
-
const a = n == null ? void 0 : n.extensions[
|
|
372
|
+
const a = n == null ? void 0 : n.extensions[V];
|
|
373
373
|
if (a) {
|
|
374
374
|
if (!a.lods) {
|
|
375
375
|
L && console.warn("Texture has no LODs", a);
|
|
@@ -389,7 +389,7 @@ const v = class {
|
|
|
389
389
|
}
|
|
390
390
|
}), (s = this.parser.json.meshes) == null || s.forEach((n, r) => {
|
|
391
391
|
if (n != null && n.extensions) {
|
|
392
|
-
const i = n == null ? void 0 : n.extensions[
|
|
392
|
+
const i = n == null ? void 0 : n.extensions[V];
|
|
393
393
|
if (i && i.lods) {
|
|
394
394
|
for (const a of this.parser.associations.keys())
|
|
395
395
|
if (a.isMesh) {
|
|
@@ -435,67 +435,67 @@ const v = class {
|
|
|
435
435
|
}
|
|
436
436
|
const x = i, $ = new Promise(async (h, R) => {
|
|
437
437
|
const F = new be();
|
|
438
|
-
$e(F), L && (await new Promise((
|
|
438
|
+
$e(F), L && (await new Promise((b) => setTimeout(b, 1e3)), s && console.warn("Start loading (delayed) " + p, x.guid));
|
|
439
439
|
let k = p;
|
|
440
440
|
if (x && Array.isArray(x.lods)) {
|
|
441
|
-
const
|
|
442
|
-
|
|
441
|
+
const b = x.lods[t];
|
|
442
|
+
b.hash && (k += "?v=" + b.hash);
|
|
443
443
|
}
|
|
444
|
-
const
|
|
445
|
-
`,
|
|
446
|
-
if (!
|
|
444
|
+
const A = await F.loadAsync(k).catch((b) => (console.error(`Error loading LOD ${t} from ${p}
|
|
445
|
+
`, b), null));
|
|
446
|
+
if (!A)
|
|
447
447
|
return null;
|
|
448
|
-
const
|
|
448
|
+
const N = A.parser;
|
|
449
449
|
s && console.log("Loading finished " + p, x.guid);
|
|
450
|
-
let
|
|
451
|
-
if (
|
|
452
|
-
let
|
|
453
|
-
for (const f of
|
|
450
|
+
let S = 0;
|
|
451
|
+
if (A.parser.json.textures) {
|
|
452
|
+
let b = !1;
|
|
453
|
+
for (const f of A.parser.json.textures) {
|
|
454
454
|
if (f != null && f.extensions) {
|
|
455
|
-
const y = f == null ? void 0 : f.extensions[
|
|
455
|
+
const y = f == null ? void 0 : f.extensions[V];
|
|
456
456
|
if (y != null && y.guid && y.guid === x.guid) {
|
|
457
|
-
|
|
457
|
+
b = !0;
|
|
458
458
|
break;
|
|
459
459
|
}
|
|
460
460
|
}
|
|
461
|
-
|
|
461
|
+
S++;
|
|
462
462
|
}
|
|
463
|
-
if (
|
|
464
|
-
let f = await
|
|
465
|
-
return f && v.assignLODInformation(n.url, f, r, t, void 0, void 0), s && console.log('change "' + e.name + '" → "' + f.name + '"', p,
|
|
463
|
+
if (b) {
|
|
464
|
+
let f = await N.getDependency("texture", S);
|
|
465
|
+
return f && v.assignLODInformation(n.url, f, r, t, void 0, void 0), s && console.log('change "' + e.name + '" → "' + f.name + '"', p, S, f, M), e instanceof se && (f = this.copySettings(e, f)), f && (f.guid = x.guid), h(f);
|
|
466
466
|
} else
|
|
467
|
-
L && console.warn("Could not find texture with guid", x.guid,
|
|
467
|
+
L && console.warn("Could not find texture with guid", x.guid, A.parser.json);
|
|
468
468
|
}
|
|
469
|
-
if (
|
|
470
|
-
let
|
|
471
|
-
for (const f of
|
|
469
|
+
if (S = 0, A.parser.json.meshes) {
|
|
470
|
+
let b = !1;
|
|
471
|
+
for (const f of A.parser.json.meshes) {
|
|
472
472
|
if (f != null && f.extensions) {
|
|
473
|
-
const y = f == null ? void 0 : f.extensions[
|
|
473
|
+
const y = f == null ? void 0 : f.extensions[V];
|
|
474
474
|
if (y != null && y.guid && y.guid === x.guid) {
|
|
475
|
-
|
|
475
|
+
b = !0;
|
|
476
476
|
break;
|
|
477
477
|
}
|
|
478
478
|
}
|
|
479
|
-
|
|
479
|
+
S++;
|
|
480
480
|
}
|
|
481
|
-
if (
|
|
482
|
-
const f = await
|
|
483
|
-
if (s && console.log(`Loaded Mesh "${f.name}"`, p,
|
|
481
|
+
if (b) {
|
|
482
|
+
const f = await N.getDependency("mesh", S), y = x;
|
|
483
|
+
if (s && console.log(`Loaded Mesh "${f.name}"`, p, S, f, M), f.isMesh === !0) {
|
|
484
484
|
const O = f.geometry;
|
|
485
485
|
return v.assignLODInformation(n.url, O, r, t, void 0, y.density), h(O);
|
|
486
486
|
} else {
|
|
487
487
|
const O = new Array();
|
|
488
|
-
for (let
|
|
489
|
-
const E = f.children[
|
|
488
|
+
for (let T = 0; T < f.children.length; T++) {
|
|
489
|
+
const E = f.children[T];
|
|
490
490
|
if (E.isMesh === !0) {
|
|
491
491
|
const X = E.geometry;
|
|
492
|
-
v.assignLODInformation(n.url, X, r, t,
|
|
492
|
+
v.assignLODInformation(n.url, X, r, t, T, y.density), O.push(X);
|
|
493
493
|
}
|
|
494
494
|
}
|
|
495
495
|
return h(O);
|
|
496
496
|
}
|
|
497
497
|
} else
|
|
498
|
-
L && console.warn("Could not find mesh with guid", x.guid,
|
|
498
|
+
L && console.warn("Could not find mesh with guid", x.guid, A.parser.json);
|
|
499
499
|
}
|
|
500
500
|
return h(null);
|
|
501
501
|
});
|
|
@@ -573,7 +573,7 @@ class ut {
|
|
|
573
573
|
}
|
|
574
574
|
}
|
|
575
575
|
const I = le("debugprogressive"), ft = le("noprogressive"), we = Symbol("Needle:LODSManager"), ve = Symbol("Needle:LODState"), Z = Symbol("Needle:CurrentLOD"), G = { mesh_lod: -1, texture_lod: -1 };
|
|
576
|
-
var C,
|
|
576
|
+
var C, W, ye, j, ee, me, q;
|
|
577
577
|
const P = class {
|
|
578
578
|
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
579
579
|
constructor(e, t) {
|
|
@@ -603,21 +603,21 @@ const P = class {
|
|
|
603
603
|
*/
|
|
604
604
|
d(this, "manual", !1);
|
|
605
605
|
d(this, "_lodchangedlisteners", []);
|
|
606
|
-
K(this,
|
|
606
|
+
K(this, W, void 0);
|
|
607
607
|
K(this, ye, new Ye());
|
|
608
608
|
K(this, j, 0);
|
|
609
609
|
K(this, ee, 0);
|
|
610
610
|
K(this, me, 0);
|
|
611
|
-
K(this,
|
|
611
|
+
K(this, q, 0);
|
|
612
612
|
d(this, "_fpsBuffer", [60, 60, 60, 60, 60]);
|
|
613
613
|
// private testIfLODLevelsAreAvailable() {
|
|
614
614
|
d(this, "_sphere", new Je());
|
|
615
615
|
d(this, "_tempBox", new Ee());
|
|
616
616
|
d(this, "_tempBox2", new Ee());
|
|
617
617
|
d(this, "tempMatrix", new Ae());
|
|
618
|
-
d(this, "_tempWorldPosition", new
|
|
619
|
-
d(this, "_tempBoxSize", new
|
|
620
|
-
d(this, "_tempBox2Size", new
|
|
618
|
+
d(this, "_tempWorldPosition", new z());
|
|
619
|
+
d(this, "_tempBoxSize", new z());
|
|
620
|
+
d(this, "_tempBox2Size", new z());
|
|
621
621
|
this.renderer = e, this.context = { ...t };
|
|
622
622
|
}
|
|
623
623
|
/** @internal */
|
|
@@ -662,21 +662,21 @@ const P = class {
|
|
|
662
662
|
* Enable the LODsManager. This will replace the render method of the renderer with a method that updates the LODs.
|
|
663
663
|
*/
|
|
664
664
|
enable() {
|
|
665
|
-
if (m(this,
|
|
665
|
+
if (m(this, W))
|
|
666
666
|
return;
|
|
667
667
|
console.debug("[gltf-progressive] Enabling LODsManager for renderer");
|
|
668
668
|
let e = 0;
|
|
669
|
-
U(this,
|
|
669
|
+
U(this, W, this.renderer.render);
|
|
670
670
|
const t = this;
|
|
671
671
|
Ge(this.renderer), this.renderer.render = function(s, n) {
|
|
672
672
|
const r = t.renderer.getRenderTarget();
|
|
673
|
-
(r == null || "isXRRenderTarget" in r && r.isXRRenderTarget) && (e = 0, U(t, j, m(t, j) + 1), U(t, ee, m(t, ye).getDelta()), U(t, me, m(t, me) + m(t, ee)), t._fpsBuffer.shift(), t._fpsBuffer.push(1 / m(t, ee)), U(t,
|
|
673
|
+
(r == null || "isXRRenderTarget" in r && r.isXRRenderTarget) && (e = 0, U(t, j, m(t, j) + 1), U(t, ee, m(t, ye).getDelta()), U(t, me, m(t, me) + m(t, ee)), t._fpsBuffer.shift(), t._fpsBuffer.push(1 / m(t, ee)), U(t, q, t._fpsBuffer.reduce((a, l) => a + l) / t._fpsBuffer.length), I && m(t, j) % 200 === 0 && console.log("FPS", Math.round(m(t, q)), "Interval:", m(t, C)));
|
|
674
674
|
const i = e++;
|
|
675
|
-
m(t,
|
|
675
|
+
m(t, W).call(this, s, n), t.onAfterRender(s, n, i);
|
|
676
676
|
};
|
|
677
677
|
}
|
|
678
678
|
disable() {
|
|
679
|
-
m(this,
|
|
679
|
+
m(this, W) && (console.debug("[gltf-progressive] Disabling LODsManager for renderer"), this.renderer.render = m(this, W), U(this, W, void 0));
|
|
680
680
|
}
|
|
681
681
|
update(e, t) {
|
|
682
682
|
this.internalUpdate(e, t);
|
|
@@ -691,7 +691,7 @@ const P = class {
|
|
|
691
691
|
(a.name === "EffectMaterial" || a.name === "CopyShader") && (i = !1);
|
|
692
692
|
}
|
|
693
693
|
if ((t.parent && t.parent.type === "CubeCamera" || s >= 1 && t.type === "OrthographicCamera") && (i = !1), i) {
|
|
694
|
-
if (ft || (this.updateInterval === "auto" ? m(this,
|
|
694
|
+
if (ft || (this.updateInterval === "auto" ? m(this, q) < 40 && m(this, C) < 10 ? (U(this, C, m(this, C) + 1), I && console.warn("↓ Reducing LOD updates", m(this, C), m(this, q).toFixed(0))) : m(this, q) >= 60 && m(this, C) > 1 && (U(this, C, m(this, C) - 1), I && console.warn("↑ Increasing LOD updates", m(this, C), m(this, q).toFixed(0))) : U(this, C, this.updateInterval), m(this, C) > 0 && m(this, j) % m(this, C) != 0))
|
|
695
695
|
return;
|
|
696
696
|
this.internalUpdate(e, t);
|
|
697
697
|
}
|
|
@@ -841,10 +841,10 @@ const P = class {
|
|
|
841
841
|
}
|
|
842
842
|
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && D.fov > 70) {
|
|
843
843
|
const f = this._tempBox.min, y = this._tempBox.max;
|
|
844
|
-
let O = f.x,
|
|
844
|
+
let O = f.x, T = f.y, E = y.x, X = y.y;
|
|
845
845
|
const ue = 2, Le = 1.5, fe = (f.x + y.x) * 0.5, de = (f.y + y.y) * 0.5;
|
|
846
|
-
O = (O - fe) * ue + fe,
|
|
847
|
-
const ze = O < 0 && E > 0 ? 0 : Math.min(Math.abs(f.x), Math.abs(y.x)), Ve =
|
|
846
|
+
O = (O - fe) * ue + fe, T = (T - de) * ue + de, E = (E - fe) * ue + fe, X = (X - de) * ue + de;
|
|
847
|
+
const ze = O < 0 && E > 0 ? 0 : Math.min(Math.abs(f.x), Math.abs(y.x)), Ve = T < 0 && X > 0 ? 0 : Math.min(Math.abs(f.y), Math.abs(y.y)), xe = Math.max(ze, Ve);
|
|
848
848
|
s.lastCentrality = (Le - xe) * (Le - xe) * (Le - xe);
|
|
849
849
|
} else
|
|
850
850
|
s.lastCentrality = 1;
|
|
@@ -852,24 +852,24 @@ const P = class {
|
|
|
852
852
|
h.multiplyScalar(0.5), screen.availHeight > 0 && w > 0 && h.multiplyScalar(w / screen.availHeight), h.x *= D.aspect;
|
|
853
853
|
const R = e.matrixWorldInverse, F = this._tempBox2;
|
|
854
854
|
F.copy(x), F.applyMatrix4(t.matrixWorld), F.applyMatrix4(R);
|
|
855
|
-
const k = F.getSize(this._tempBox2Size),
|
|
856
|
-
if (Math.max(h.x, h.y) != 0 &&
|
|
855
|
+
const k = F.getSize(this._tempBox2Size), A = Math.max(k.x, k.y);
|
|
856
|
+
if (Math.max(h.x, h.y) != 0 && A != 0 && (h.z = k.z / Math.max(k.x, k.y) * Math.max(h.x, h.y)), s.lastScreenCoverage = Math.max(h.x, h.y, h.z), s.lastScreenspaceVolume.copy(h), s.lastScreenCoverage *= s.lastCentrality, I && P.debugDrawLine) {
|
|
857
857
|
const f = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
858
858
|
f.invert();
|
|
859
|
-
const y = P.corner0, O = P.corner1,
|
|
860
|
-
y.copy(this._tempBox.min), O.copy(this._tempBox.max), O.x = y.x,
|
|
859
|
+
const y = P.corner0, O = P.corner1, T = P.corner2, E = P.corner3;
|
|
860
|
+
y.copy(this._tempBox.min), O.copy(this._tempBox.max), O.x = y.x, T.copy(this._tempBox.max), T.y = y.y, E.copy(this._tempBox.max);
|
|
861
861
|
const X = (y.z + E.z) * 0.5;
|
|
862
|
-
y.z = O.z =
|
|
862
|
+
y.z = O.z = T.z = E.z = X, y.applyMatrix4(f), O.applyMatrix4(f), T.applyMatrix4(f), E.applyMatrix4(f), P.debugDrawLine(y, O, 255), P.debugDrawLine(y, T, 255), P.debugDrawLine(O, E, 255), P.debugDrawLine(T, E, 255);
|
|
863
863
|
}
|
|
864
|
-
let
|
|
864
|
+
let S = 999;
|
|
865
865
|
if (c && s.lastScreenCoverage > 0) {
|
|
866
866
|
for (let f = 0; f < c.length; f++)
|
|
867
867
|
if (c[f].density / s.lastScreenCoverage < n) {
|
|
868
|
-
|
|
868
|
+
S = f;
|
|
869
869
|
break;
|
|
870
870
|
}
|
|
871
871
|
}
|
|
872
|
-
|
|
872
|
+
S < a && (a = S, l = !0);
|
|
873
873
|
}
|
|
874
874
|
if (l ? r.mesh_lod = a : r.mesh_lod = s.lastLodLevel_Mesh, I && r.mesh_lod != s.lastLodLevel_Mesh) {
|
|
875
875
|
const h = c == null ? void 0 : c[r.mesh_lod];
|
|
@@ -887,12 +887,13 @@ const P = class {
|
|
|
887
887
|
let R = s.lastScreenCoverage * 4;
|
|
888
888
|
(($ = this.context) == null ? void 0 : $.engine) === "model-viewer" && (R *= 1.5);
|
|
889
889
|
const k = w / window.devicePixelRatio * R;
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
890
|
+
let A = !1;
|
|
891
|
+
for (let N = p.lods.length - 1; N >= 0; N--) {
|
|
892
|
+
let S = p.lods[N];
|
|
893
|
+
if (!(D && S.max_height >= 2048) && !(nt() && S.max_height > 4096) && (S.max_height > k || !A && N === 0)) {
|
|
894
|
+
if (A = !0, r.texture_lod = N, r.texture_lod < s.lastLodLevel_Texture) {
|
|
895
|
+
const b = S.max_height;
|
|
896
|
+
I && console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${b}px
|
|
896
897
|
Screensize: ${k.toFixed(0)}px, Coverage: ${(100 * s.lastScreenCoverage).toFixed(2)}%, Volume ${h.toFixed(1)}
|
|
897
898
|
${t.name}`);
|
|
898
899
|
}
|
|
@@ -905,16 +906,16 @@ ${t.name}`);
|
|
|
905
906
|
}
|
|
906
907
|
};
|
|
907
908
|
let B = P;
|
|
908
|
-
C = new WeakMap(),
|
|
909
|
+
C = new WeakMap(), W = new WeakMap(), ye = new WeakMap(), j = new WeakMap(), ee = new WeakMap(), me = 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.
|
|
909
910
|
*/
|
|
910
|
-
d(B, "debugDrawLine"), d(B, "corner0", new
|
|
911
|
+
d(B, "debugDrawLine"), d(B, "corner0", new z()), d(B, "corner1", new z()), d(B, "corner2", new z()), d(B, "corner3", new z()), d(B, "_tempPtInside", new z());
|
|
911
912
|
class dt {
|
|
912
913
|
constructor() {
|
|
913
914
|
d(this, "frames", 0);
|
|
914
915
|
d(this, "lastLodLevel_Mesh", -1);
|
|
915
916
|
d(this, "lastLodLevel_Texture", -1);
|
|
916
917
|
d(this, "lastScreenCoverage", 0);
|
|
917
|
-
d(this, "lastScreenspaceVolume", new
|
|
918
|
+
d(this, "lastScreenspaceVolume", new z());
|
|
918
919
|
d(this, "lastCentrality", 0);
|
|
919
920
|
}
|
|
920
921
|
}
|
|
@@ -1027,8 +1028,8 @@ class pt {
|
|
|
1027
1028
|
console.warn("Texture data not found for texture index " + $);
|
|
1028
1029
|
continue;
|
|
1029
1030
|
}
|
|
1030
|
-
if ((p = D == null ? void 0 : D.extensions) != null && p[
|
|
1031
|
-
const h = D.extensions[
|
|
1031
|
+
if ((p = D == null ? void 0 : D.extensions) != null && p[V]) {
|
|
1032
|
+
const h = D.extensions[V];
|
|
1032
1033
|
h && r && _.registerTexture(r, x, h.lods.length, $, h);
|
|
1033
1034
|
}
|
|
1034
1035
|
}
|
|
@@ -1050,7 +1051,7 @@ class pt {
|
|
|
1050
1051
|
const s = this.tryGetCurrentModelViewer(e), n = this.getUrl(s);
|
|
1051
1052
|
if (!n)
|
|
1052
1053
|
return;
|
|
1053
|
-
const r = (a = (i = t.userData) == null ? void 0 : i.gltfExtensions) == null ? void 0 : a[
|
|
1054
|
+
const r = (a = (i = t.userData) == null ? void 0 : i.gltfExtensions) == null ? void 0 : a[V];
|
|
1054
1055
|
if (r && n) {
|
|
1055
1056
|
const l = t.uuid;
|
|
1056
1057
|
_.registerMesh(n, l, t, 0, r.lods.length, r);
|
|
@@ -1083,7 +1084,7 @@ if (!ot) {
|
|
|
1083
1084
|
globalThis.Needle[e] = o[e];
|
|
1084
1085
|
}
|
|
1085
1086
|
export {
|
|
1086
|
-
|
|
1087
|
+
V as EXTENSION_NAME,
|
|
1087
1088
|
B as LODsManager,
|
|
1088
1089
|
_ as NEEDLE_progressive,
|
|
1089
1090
|
ke as VERSION,
|
package/gltf-progressive.min.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var Ue=Object.defineProperty,ze=(t,e,s)=>e in t?Ue(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s,c=(t,e,s)=>(ze(t,typeof e!="symbol"?e+"":e,s),s),Te=(t,e,s)=>{if(!e.has(t))throw TypeError("Cannot "+s)},v=(t,e,s)=>(Te(t,e,"read from private field"),s?s.call(t):e.get(t)),V=(t,e,s)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,s)},G=(t,e,s,o)=>(Te(t,e,"write to private field"),o?o.call(t,s):e.set(t,s),s);import{BufferGeometry as le,Mesh as q,Material as Ve,Texture as ee,TextureLoader as qe,Matrix4 as Ee,Clock as Xe,MeshStandardMaterial as He,Sphere as Ke,Box3 as Ae,Vector3 as N}from"three";import{GLTFLoader as me}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as Ye}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Je}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Qe}from"three/examples/jsm/loaders/KTX2Loader.js";const pe="";globalThis.GLTF_PROGRESSIVE_VERSION=pe,console.debug(`[gltf-progressive] version ${pe}`);let Y="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",te="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ze=Y,et=te,tt=new URL(Y+"draco_decoder.js");fetch(tt,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(t=>{Y===Ze&&(Y="./include/draco/"),te===et&&(te="./include/ktx2/")}).finally(()=>{Ie()});function st(t){Y=t}function rt(t){te=t}let X,ue,H;function Ie(){X||(X=new Je,X.setDecoderPath(Y),X.setDecoderConfig({type:"js"}),X.preload()),H||(H=new Qe,H.setTranscoderPath(te),H.init()),ue||(ue=Ye)}function ye(t){return Ie(),t?H.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:X,ktx2Loader:H,meshoptDecoder:ue}}function ve(t){t.dracoLoader||t.setDRACOLoader(X),t.ktx2Loader||t.setKTX2Loader(H),t.meshoptDecoder||t.setMeshoptDecoder(ue)}const xe=new WeakMap;function Le(t,e){let s=xe.get(t);s?s=Object.assign(s,e):s=e,xe.set(t,s)}const Pe=me.prototype.load;function nt(...t){const e=xe.get(this);let s=t[0];const o=new URL(s,window.location.href);if(o.hostname.endsWith("needle.tools")){const r=e?.progressive!==void 0?e.progressive:!0,n=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${n}`:this.requestHeader.Accept=`*/*;usecase=${n}`,s=o.toString()}return t[0]=s,Pe?.call(this,...t)}me.prototype.load=nt,se("debugprogressive");function se(t){if(typeof window>"u")return!1;const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function ot(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const s=t.lastIndexOf("/");if(s>=0){const o=t.substring(0,s+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}let ce;function it(){return ce!==void 0||(ce=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),se("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ce)),ce}const at=typeof window>"u"&&typeof document>"u",Me=Symbol("needle:raycast-mesh");function J(t){return t?.[Me]instanceof le?t[Me]:null}function ke(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!J(t)){const s=lt(e);s.userData={isRaycastMesh:!0},t[Me]=s}}function Be(t=!0){if(t){if(re)return;const e=re=q.prototype.raycast;q.prototype.raycast=function(s,o){const r=this,n=J(r);let i;n&&r.isMesh&&(i=r.geometry,r.geometry=n),e.call(this,s,o),i&&(r.geometry=i)}}else{if(!re)return;q.prototype.raycast=re,re=null}}let re=null;function lt(t){const e=new le;for(const s in t.attributes)e.setAttribute(s,t.getAttribute(s));return e.setIndex(t.getIndex()),e}const $=new Array,j="NEEDLE_progressive",x=se("debugprogressive"),De=Symbol("needle-progressive-texture"),ne=new Map,we=new Set;if(x){let t=function(){e+=1,console.log("Toggle LOD level",e,ne),ne.forEach((r,n)=>{for(const i of r.keys){const l=n[i];if(l!=null){if(l.isBufferGeometry===!0){const u=S.getMeshLODInformation(l),a=u?Math.min(e,u.lods.length):0;n["DEBUG:LOD"]=e,S.assignMeshLOD(n,a),u&&(s=Math.max(s,u.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,S.assignTextureLOD(n,e);break}}}}),e>=s&&(e=-1)},e=-1,s=2,o=!1;window.addEventListener("keyup",r=>{r.key==="p"&&t(),r.key==="w"&&(o=!o,we&&we.forEach(n=>{n.name!="BackgroundCubeMaterial"&&n.glyphMap==null&&"wireframe"in n&&(n.wireframe=o)}))})}function Re(t,e,s){var o;if(!x)return;ne.has(t)||ne.set(t,{keys:[],sourceId:s});const r=ne.get(t);((o=r?.keys)==null?void 0:o.includes(e))==!1&&r.keys.push(e)}const w=class{constructor(t,e){c(this,"parser"),c(this,"url"),c(this,"_isLoadingMesh"),c(this,"loadMesh",s=>{var o,r;if(this._isLoadingMesh)return null;const n=(r=(o=this.parser.json.meshes[s])==null?void 0:o.extensions)==null?void 0:r[j];return n?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",s).then(i=>{var l;return this._isLoadingMesh=!1,i&&w.registerMesh(this.url,n.guid,i,(l=n.lods)==null?void 0:l.length,void 0,n),i})):null}),x&&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 s=this,o="LODS:minmax",r=t[o];if(r!=null)return r;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[o]=e,e}if(x==="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&&n(u,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const l=t[i];l?.isTexture===!0&&n(l,e)}return t[o]=e,e;function n(i,l){const u=s.getAssignedLODInformation(i);if(u){const a=s.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 f=0;f<a.lods.length;f++){const g=a.lods[f];g.width&&(l.lods[f]=l.lods[f]||{min_height:1/0,max_height:0},l.lods[f].min_height=Math.min(l.lods[f].min_height,g.height),l.lods[f].max_height=Math.max(l.lods[f].max_height,g.height))}}}}}static hasLODLevelAvailable(t,e){var s;if(Array.isArray(t)){for(const n of t)if(this.hasLODLevelAvailable(n,e))return!0;return!1}if(t.isMaterial===!0){for(const n of Object.keys(t)){const i=t[n];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const n of t.children)if(n.isMesh===!0&&this.hasLODLevelAvailable(n,e))return!0}let o,r;if(t.isMesh?o=t.geometry:(t.isBufferGeometry||t.isTexture)&&(o=t),o&&(s=o?.userData)!=null&&s.LODS){const n=o.userData.LODS;if(r=this.lodInfos.get(n.key),e===void 0)return r!=null;if(r)return Array.isArray(r.lods)?e<r.lods.length:e===0}return!1}static assignMeshLOD(t,e){var s;if(!t)return Promise.resolve(null);if(t instanceof q||t.isMesh===!0){const o=t.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const n of $)(s=n.onBeforeGetLODMesh)==null||s.call(n,t,e);return t["LOD:requested level"]=e,w.getOrLoadLOD(o,e).then(n=>{if(Array.isArray(n)){const i=r.index||0;n=n[i]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],n&&o!=n&&(n?.isBufferGeometry?(t.geometry=n,x&&Re(t,"geometry",r.url)):x&&console.error("Invalid LOD geometry",n))),n}).catch(n=>(console.error("Error loading mesh LOD",t,n),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.isMesh===!0){const s=t;if(Array.isArray(s.material)){const o=new Array;for(const r of s.material){const n=this.assignTextureLOD(r,e);o.push(n)}return Promise.all(o).then(r=>{const n=new Array;for(const i of r)Array.isArray(i)&&n.push(...i);return n})}else return this.assignTextureLOD(s.material,e)}if(t instanceof Ve||t.isMaterial===!0){const s=t,o=[],r=new Array;if(x&&we.add(s),s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const n=s;for(const i of Object.keys(n.uniforms)){const l=n.uniforms[i].value;if(l?.isTexture===!0){const u=this.assignTextureLODForSlot(l,e,s,i).then(a=>(a&&n.uniforms[i].value!=a&&(n.uniforms[i].value=a,n.uniformsNeedUpdate=!0),a));o.push(u),r.push(i)}}}else for(const n of Object.keys(s)){const i=s[n];if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,s,n);o.push(l),r.push(n)}}return Promise.all(o).then(n=>{const i=new Array;for(let l=0;l<n.length;l++){const u=n[l],a=r[l];u&&u.isTexture===!0?i.push({material:s,slot:a,texture:u,level:e}):i.push({material:s,slot:a,texture:null,level:e})}return i})}if(t instanceof ee||t.isTexture===!0){const s=t;return this.assignTextureLODForSlot(s,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,s,o){return t?.isTexture!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):w.getOrLoadLOD(t,e).then(r=>{if(Array.isArray(r))return null;if(r?.isTexture===!0){if(r!=t){if(s&&o){const n=s[o];if(n){const i=this.getAssignedLODInformation(n);if(i&&i?.level<e)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,s,n,r),null}s[o]=r}if(x&&o&&s){const n=this.getAssignedLODInformation(t);n&&Re(s,o,n.url)}}return r}else x=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(r=>(console.error("Error loading LOD",t,r),null))}afterRoot(t){var e,s;return x&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,r)=>{var n;if(o!=null&&o.extensions){const i=o?.extensions[j];if(i){if(!i.lods){x&&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===r&&(l=!0,w.registerTexture(this.url,u,(n=i.lods)==null?void 0:n.length,r,i))}l||this.parser.getDependency("texture",r).then(u=>{var a;u&&w.registerTexture(this.url,u,(a=i.lods)==null?void 0:a.length,r,i)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const n=o?.extensions[j];if(n&&n.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l?.meshes===r&&w.registerMesh(this.url,n.guid,i,n.lods.length,l.primitives,n)}}}}),null}static async getOrLoadLOD(t,e){var s,o,r,n;const i=x=="verbose",l=t.userData.LODS;if(!l)return null;const u=l?.key;let a;if(t.isTexture===!0){const f=t;f.source&&f.source[De]&&(a=f.source[De])}if(a||(a=w.lodInfos.get(u)),a){if(e>0){let p=!1;const A=Array.isArray(a.lods);if(A&&e>=a.lods.length?p=!0:A||(p=!0),p)return this.lowresCache.get(u)}const f=Array.isArray(a.lods)?(s=a.lods[e])==null?void 0:s.path:a.lods;if(!f)return x&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const g=ot(l.url,f);if(g.endsWith(".glb")||g.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const p=g+"_"+a.guid,A=this.previouslyLoaded.get(p);if(A!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${p}`);let d=await A.catch(b=>(console.error(`Error loading LOD ${e} from ${g}
|
|
2
|
-
`,b),null)),O=!1;if(d==null||(d instanceof ee&&t instanceof ee?(o=d.image)!=null&&o.data||(r=d.source)!=null&&r.data?d=this.copySettings(t,d):(O=!0,this.previouslyLoaded.delete(
|
|
3
|
-
`,
|
|
1
|
+
var Ue=Object.defineProperty,ze=(t,e,s)=>e in t?Ue(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s,c=(t,e,s)=>(ze(t,typeof e!="symbol"?e+"":e,s),s),Te=(t,e,s)=>{if(!e.has(t))throw TypeError("Cannot "+s)},v=(t,e,s)=>(Te(t,e,"read from private field"),s?s.call(t):e.get(t)),V=(t,e,s)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,s)},G=(t,e,s,o)=>(Te(t,e,"write to private field"),o?o.call(t,s):e.set(t,s),s);import{BufferGeometry as le,Mesh as q,Material as Ve,Texture as ee,TextureLoader as qe,Matrix4 as Ee,Clock as Xe,MeshStandardMaterial as He,Sphere as Ke,Box3 as Ae,Vector3 as W}from"three";import{GLTFLoader as me}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as Ye}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Je}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Qe}from"three/examples/jsm/loaders/KTX2Loader.js";const pe="";globalThis.GLTF_PROGRESSIVE_VERSION=pe,console.debug(`[gltf-progressive] version ${pe}`);let Y="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",te="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ze=Y,et=te,tt=new URL(Y+"draco_decoder.js");fetch(tt,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(t=>{Y===Ze&&(Y="./include/draco/"),te===et&&(te="./include/ktx2/")}).finally(()=>{Ie()});function st(t){Y=t}function rt(t){te=t}let X,ue,H;function Ie(){X||(X=new Je,X.setDecoderPath(Y),X.setDecoderConfig({type:"js"}),X.preload()),H||(H=new Qe,H.setTranscoderPath(te),H.init()),ue||(ue=Ye)}function ye(t){return Ie(),t?H.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:X,ktx2Loader:H,meshoptDecoder:ue}}function ve(t){t.dracoLoader||t.setDRACOLoader(X),t.ktx2Loader||t.setKTX2Loader(H),t.meshoptDecoder||t.setMeshoptDecoder(ue)}const xe=new WeakMap;function Le(t,e){let s=xe.get(t);s?s=Object.assign(s,e):s=e,xe.set(t,s)}const Pe=me.prototype.load;function nt(...t){const e=xe.get(this);let s=t[0];const o=new URL(s,window.location.href);if(o.hostname.endsWith("needle.tools")){const r=e?.progressive!==void 0?e.progressive:!0,n=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${n}`:this.requestHeader.Accept=`*/*;usecase=${n}`,s=o.toString()}return t[0]=s,Pe?.call(this,...t)}me.prototype.load=nt,se("debugprogressive");function se(t){if(typeof window>"u")return!1;const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function ot(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const s=t.lastIndexOf("/");if(s>=0){const o=t.substring(0,s+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}let ce;function it(){return ce!==void 0||(ce=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),se("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ce)),ce}const at=typeof window>"u"&&typeof document>"u",Me=Symbol("needle:raycast-mesh");function J(t){return t?.[Me]instanceof le?t[Me]:null}function ke(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!J(t)){const s=lt(e);s.userData={isRaycastMesh:!0},t[Me]=s}}function Be(t=!0){if(t){if(re)return;const e=re=q.prototype.raycast;q.prototype.raycast=function(s,o){const r=this,n=J(r);let i;n&&r.isMesh&&(i=r.geometry,r.geometry=n),e.call(this,s,o),i&&(r.geometry=i)}}else{if(!re)return;q.prototype.raycast=re,re=null}}let re=null;function lt(t){const e=new le;for(const s in t.attributes)e.setAttribute(s,t.getAttribute(s));return e.setIndex(t.getIndex()),e}const $=new Array,N="NEEDLE_progressive",x=se("debugprogressive"),De=Symbol("needle-progressive-texture"),ne=new Map,we=new Set;if(x){let t=function(){e+=1,console.log("Toggle LOD level",e,ne),ne.forEach((r,n)=>{for(const i of r.keys){const l=n[i];if(l!=null){if(l.isBufferGeometry===!0){const u=T.getMeshLODInformation(l),a=u?Math.min(e,u.lods.length):0;n["DEBUG:LOD"]=e,T.assignMeshLOD(n,a),u&&(s=Math.max(s,u.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,T.assignTextureLOD(n,e);break}}}}),e>=s&&(e=-1)},e=-1,s=2,o=!1;window.addEventListener("keyup",r=>{r.key==="p"&&t(),r.key==="w"&&(o=!o,we&&we.forEach(n=>{n.name!="BackgroundCubeMaterial"&&n.glyphMap==null&&"wireframe"in n&&(n.wireframe=o)}))})}function Re(t,e,s){var o;if(!x)return;ne.has(t)||ne.set(t,{keys:[],sourceId:s});const r=ne.get(t);((o=r?.keys)==null?void 0:o.includes(e))==!1&&r.keys.push(e)}const w=class{constructor(t,e){c(this,"parser"),c(this,"url"),c(this,"_isLoadingMesh"),c(this,"loadMesh",s=>{var o,r;if(this._isLoadingMesh)return null;const n=(r=(o=this.parser.json.meshes[s])==null?void 0:o.extensions)==null?void 0:r[N];return n?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",s).then(i=>{var l;return this._isLoadingMesh=!1,i&&w.registerMesh(this.url,n.guid,i,(l=n.lods)==null?void 0:l.length,void 0,n),i})):null}),x&&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 s=this,o="LODS:minmax",r=t[o];if(r!=null)return r;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[o]=e,e}if(x==="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&&n(u,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const l=t[i];l?.isTexture===!0&&n(l,e)}return t[o]=e,e;function n(i,l){const u=s.getAssignedLODInformation(i);if(u){const a=s.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 f=0;f<a.lods.length;f++){const g=a.lods[f];g.width&&(l.lods[f]=l.lods[f]||{min_height:1/0,max_height:0},l.lods[f].min_height=Math.min(l.lods[f].min_height,g.height),l.lods[f].max_height=Math.max(l.lods[f].max_height,g.height))}}}}}static hasLODLevelAvailable(t,e){var s;if(Array.isArray(t)){for(const n of t)if(this.hasLODLevelAvailable(n,e))return!0;return!1}if(t.isMaterial===!0){for(const n of Object.keys(t)){const i=t[n];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const n of t.children)if(n.isMesh===!0&&this.hasLODLevelAvailable(n,e))return!0}let o,r;if(t.isMesh?o=t.geometry:(t.isBufferGeometry||t.isTexture)&&(o=t),o&&(s=o?.userData)!=null&&s.LODS){const n=o.userData.LODS;if(r=this.lodInfos.get(n.key),e===void 0)return r!=null;if(r)return Array.isArray(r.lods)?e<r.lods.length:e===0}return!1}static assignMeshLOD(t,e){var s;if(!t)return Promise.resolve(null);if(t instanceof q||t.isMesh===!0){const o=t.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const n of $)(s=n.onBeforeGetLODMesh)==null||s.call(n,t,e);return t["LOD:requested level"]=e,w.getOrLoadLOD(o,e).then(n=>{if(Array.isArray(n)){const i=r.index||0;n=n[i]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],n&&o!=n&&(n?.isBufferGeometry?(t.geometry=n,x&&Re(t,"geometry",r.url)):x&&console.error("Invalid LOD geometry",n))),n}).catch(n=>(console.error("Error loading mesh LOD",t,n),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.isMesh===!0){const s=t;if(Array.isArray(s.material)){const o=new Array;for(const r of s.material){const n=this.assignTextureLOD(r,e);o.push(n)}return Promise.all(o).then(r=>{const n=new Array;for(const i of r)Array.isArray(i)&&n.push(...i);return n})}else return this.assignTextureLOD(s.material,e)}if(t instanceof Ve||t.isMaterial===!0){const s=t,o=[],r=new Array;if(x&&we.add(s),s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const n=s;for(const i of Object.keys(n.uniforms)){const l=n.uniforms[i].value;if(l?.isTexture===!0){const u=this.assignTextureLODForSlot(l,e,s,i).then(a=>(a&&n.uniforms[i].value!=a&&(n.uniforms[i].value=a,n.uniformsNeedUpdate=!0),a));o.push(u),r.push(i)}}}else for(const n of Object.keys(s)){const i=s[n];if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,s,n);o.push(l),r.push(n)}}return Promise.all(o).then(n=>{const i=new Array;for(let l=0;l<n.length;l++){const u=n[l],a=r[l];u&&u.isTexture===!0?i.push({material:s,slot:a,texture:u,level:e}):i.push({material:s,slot:a,texture:null,level:e})}return i})}if(t instanceof ee||t.isTexture===!0){const s=t;return this.assignTextureLODForSlot(s,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,s,o){return t?.isTexture!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):w.getOrLoadLOD(t,e).then(r=>{if(Array.isArray(r))return null;if(r?.isTexture===!0){if(r!=t){if(s&&o){const n=s[o];if(n){const i=this.getAssignedLODInformation(n);if(i&&i?.level<e)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,s,n,r),null}s[o]=r}if(x&&o&&s){const n=this.getAssignedLODInformation(t);n&&Re(s,o,n.url)}}return r}else x=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(r=>(console.error("Error loading LOD",t,r),null))}afterRoot(t){var e,s;return x&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,r)=>{var n;if(o!=null&&o.extensions){const i=o?.extensions[N];if(i){if(!i.lods){x&&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===r&&(l=!0,w.registerTexture(this.url,u,(n=i.lods)==null?void 0:n.length,r,i))}l||this.parser.getDependency("texture",r).then(u=>{var a;u&&w.registerTexture(this.url,u,(a=i.lods)==null?void 0:a.length,r,i)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const n=o?.extensions[N];if(n&&n.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l?.meshes===r&&w.registerMesh(this.url,n.guid,i,n.lods.length,l.primitives,n)}}}}),null}static async getOrLoadLOD(t,e){var s,o,r,n;const i=x=="verbose",l=t.userData.LODS;if(!l)return null;const u=l?.key;let a;if(t.isTexture===!0){const f=t;f.source&&f.source[De]&&(a=f.source[De])}if(a||(a=w.lodInfos.get(u)),a){if(e>0){let y=!1;const A=Array.isArray(a.lods);if(A&&e>=a.lods.length?y=!0:A||(y=!0),y)return this.lowresCache.get(u)}const f=Array.isArray(a.lods)?(s=a.lods[e])==null?void 0:s.path:a.lods;if(!f)return x&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const g=ot(l.url,f);if(g.endsWith(".glb")||g.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const y=g+"_"+a.guid,A=this.previouslyLoaded.get(y);if(A!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${y}`);let d=await A.catch(b=>(console.error(`Error loading LOD ${e} from ${g}
|
|
2
|
+
`,b),null)),O=!1;if(d==null||(d instanceof ee&&t instanceof ee?(o=d.image)!=null&&o.data||(r=d.source)!=null&&r.data?d=this.copySettings(t,d):(O=!0,this.previouslyLoaded.delete(y)):d instanceof le&&t instanceof le&&((n=d.attributes.position)!=null&&n.array||(O=!0,this.previouslyLoaded.delete(y)))),!O)return d}const D=a,L=new Promise(async(d,O)=>{const b=new me;ve(b),x&&(await new Promise(p=>setTimeout(p,1e3)),i&&console.warn("Start loading (delayed) "+g,D.guid));let P=g;if(D&&Array.isArray(D.lods)){const p=D.lods[e];p.hash&&(P+="?v="+p.hash)}const _=await b.loadAsync(P).catch(p=>(console.error(`Error loading LOD ${e} from ${g}
|
|
3
|
+
`,p),null));if(!_)return null;const k=_.parser;i&&console.log("Loading finished "+g,D.guid);let m=0;if(_.parser.json.textures){let p=!1;for(const h of _.parser.json.textures){if(h!=null&&h.extensions){const M=h?.extensions[N];if(M!=null&&M.guid&&M.guid===D.guid){p=!0;break}}m++}if(p){let h=await k.getDependency("texture",m);return h&&w.assignLODInformation(l.url,h,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',g,m,h,y),t instanceof ee&&(h=this.copySettings(t,h)),h&&(h.guid=D.guid),d(h)}else x&&console.warn("Could not find texture with guid",D.guid,_.parser.json)}if(m=0,_.parser.json.meshes){let p=!1;for(const h of _.parser.json.meshes){if(h!=null&&h.extensions){const M=h?.extensions[N];if(M!=null&&M.guid&&M.guid===D.guid){p=!0;break}}m++}if(p){const h=await k.getDependency("mesh",m),M=D;if(i&&console.log(`Loaded Mesh "${h.name}"`,g,m,h,y),h.isMesh===!0){const S=h.geometry;return w.assignLODInformation(l.url,S,u,e,void 0,M.density),d(S)}else{const S=new Array;for(let j=0;j<h.children.length;j++){const z=h.children[j];if(z.isMesh===!0){const K=z.geometry;w.assignLODInformation(l.url,K,u,e,j,M.density),S.push(K)}}return d(S)}}else x&&console.warn("Could not find mesh with guid",D.guid,_.parser.json)}return d(null)});return this.previouslyLoaded.set(y,L),await L}else if(t instanceof ee){i&&console.log("Load texture from uri: "+g);const y=await new qe().loadAsync(g);return y?(y.guid=a.guid,y.flipY=!1,y.needsUpdate=!0,y.colorSpace=t.colorSpace,i&&console.log(a,y)):x&&console.warn("failed loading",g),y}}else x&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,s,o,r,n){if(!e)return;e.userData||(e.userData={});const i=new ut(t,s,o,r,n);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(),x&&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 S=w;c(S,"registerTexture",(t,e,s,o,r)=>{if(x&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,r),!e){x&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[De]=r);const n=r.guid;w.assignLODInformation(t,e,n,s,o,void 0),w.lodInfos.set(n,r),w.lowresCache.set(n,e)}),c(S,"registerMesh",(t,e,s,o,r,n)=>{var i;x&&console.log("> Progressive: register mesh",r,s.name,n,s.uuid,s);const l=s.geometry;if(!l){x&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),w.assignLODInformation(t,l,e,o,r,n.density),w.lodInfos.set(e,n);let u=w.lowresCache.get(e);u?u.push(s.geometry):u=[s.geometry],w.lowresCache.set(e,u),o>0&&!J(s)&&ke(s,l);for(const a of $)(i=a.onRegisteredNewMesh)==null||i.call(a,s,n)}),c(S,"lodInfos",new Map),c(S,"previouslyLoaded",new Map),c(S,"lowresCache",new Map);class ut{constructor(e,s,o,r,n){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=s,this.level=o,r!=null&&(this.index=r),n!=null&&(this.density=n)}}const k=se("debugprogressive"),ct=se("noprogressive"),Oe=Symbol("Needle:LODSManager"),be=Symbol("Needle:LODState"),Q=Symbol("Needle:CurrentLOD"),B={mesh_lod:-1,texture_lod:-1};var E,F,_e,Z,oe,de,U;const P=class{constructor(t,e){c(this,"context"),c(this,"renderer"),c(this,"projectionScreenMatrix",new Ee),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval","auto"),V(this,E,1),c(this,"pause",!1),c(this,"manual",!1),c(this,"_lodchangedlisteners",[]),V(this,F,void 0),V(this,_e,new Xe),V(this,Z,0),V(this,oe,0),V(this,de,0),V(this,U,0),c(this,"_fpsBuffer",[60,60,60,60,60]),c(this,"_sphere",new Ke),c(this,"_tempBox",new Ae),c(this,"_tempBox2",new Ae),c(this,"tempMatrix",new Ee),c(this,"_tempWorldPosition",new N),c(this,"_tempBoxSize",new N),c(this,"_tempBox2Size",new N),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[be]}static addPlugin(t){$.push(t)}static removePlugin(t){const e=$.indexOf(t);e>=0&&$.splice(e,1)}static get(t,e){if(t[Oe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[Oe];const s=new P(t,{engine:"unknown",...e});return t[Oe]=s,s}get plugins(){return $}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(v(this,F))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;G(this,F,this.renderer.render);const e=this;ye(this.renderer),this.renderer.render=function(s,o){const r=e.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(t=0,G(e,Z,v(e,Z)+1),G(e,oe,v(e,_e).getDelta()),G(e,de,v(e,de)+v(e,oe)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/v(e,oe)),G(e,U,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),k&&v(e,Z)%200===0&&console.log("FPS",Math.round(v(e,U)),"Interval:",v(e,E)));const n=t++;v(e,F).call(this,s,o),e.onAfterRender(s,o,n)}}disable(){v(this,F)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=v(this,F),G(this,F,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,s){if(this.pause)return;const o=this.renderer.renderLists.get(t,0).opaque;let r=!0;if(o.length===1){const n=o[0].material;(n.name==="EffectMaterial"||n.name==="CopyShader")&&(r=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(r=!1),r){if(ct||(this.updateInterval==="auto"?v(this,U)<40&&v(this,E)<10?(G(this,E,v(this,E)+1),k&&console.warn("\u2193 Reducing LOD updates",v(this,E),v(this,U).toFixed(0))):v(this,U)>=60&&v(this,E)>1&&(G(this,E,v(this,E)-1),k&&console.warn("\u2191 Increasing LOD updates",v(this,E),v(this,U).toFixed(0))):G(this,E,this.updateInterval),v(this,E)>0&&v(this,Z)%v(this,E)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var s,o;const r=this.renderer.renderLists.get(t,0),n=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const i=this.targetTriangleDensity;for(const a of n){if(a.material&&(((s=a.geometry)==null?void 0:s.type)==="BoxGeometry"||((o=a.geometry)==null?void 0:o.type)==="BufferGeometry")&&(a.material.name==="SphericalGaussianBlur"||a.material.name=="BackgroundCubeMaterial"||a.material.name==="CubemapFromEquirect"||a.material.name==="EquirectangularToCubeUV")){k&&(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(k==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const g=Math.random()*16777215,p=new He({color:g});a.object.material=p}const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}const l=r.transparent;for(const a of l){const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}const u=r.transmissive;for(const a of u){const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}}updateLODs(t,e,s,o){var r,n;s.userData||(s.userData={});let i=s[be];if(i||(i=new dt,s[be]=i),i.frames++<2)return;for(const u of $)(r=u.onBeforeUpdateLOD)==null||r.call(u,this.renderer,t,e,s);this.calculateLodLevel(e,s,i,o,B),B.mesh_lod=Math.round(B.mesh_lod),B.texture_lod=Math.round(B.texture_lod),B.mesh_lod>=0&&this.loadProgressiveMeshes(s,B.mesh_lod);let l=B.texture_lod;if(s.material&&l>=0){const u=s["DEBUG:LOD"];u!=null&&(l=u),this.loadProgressiveTextures(s.material,l)}for(const u of $)(n=u.onAfterUpdatedLOD)==null||n.call(u,this.renderer,t,e,s,B);i.lastLodLevel_Mesh=B.mesh_lod,i.lastLodLevel_Texture=B.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}let s=!1;(t[Q]===void 0||e<t[Q])&&(s=!0),s&&(t[Q]=e,S.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(r=>r({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[Q]!==e){t[Q]=e;const s=t.geometry;return S.assignMeshLOD(t,e).then(o=>(o&&t[Q]==e&&s!=t.geometry&&this._lodchangedlisteners.forEach(r=>r({type:"mesh",level:e,object:t})),o))}return Promise.resolve(null)}static isInside(t,e){const s=t.min,o=t.max,r=(s.x+o.x)*.5,n=(s.y+o.y)*.5;return this._tempPtInside.set(r,n,s.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,s,o,r){var n;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let i=10+1,l=!1;if(k&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=S.getMeshLODInformation(e.geometry),a=u?.lods,f=a&&a.length>0,g=S.getMaterialMinMaxLODsCount(e.material),p=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!f&&!p){r.mesh_lod=0,r.texture_lod=0;return}f||(l=!0,i=0);const A=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let D=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const L=e;if(!L.boundingBox)L.computeBoundingBox();else if(s.frames%30===0){const d=J(L),O=L.geometry;d&&(L.geometry=d),L.computeBoundingBox(),L.geometry=O}D=L.boundingBox}if(D&&t.isPerspectiveCamera){const L=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)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(D),this._tempBox.applyMatrix4(e.matrixWorld),P.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&L.fov>70){const y=this._tempBox.min,m=this._tempBox.max;let h=y.x,M=y.y,_=m.x,C=m.y;const z=2,K=1.5,ie=(y.x+m.x)*.5,ae=(y.y+m.y)*.5;h=(h-ie)*z+ie,M=(M-ae)*z+ae,_=(_-ie)*z+ie,C=(C-ae)*z+ae;const $e=h<0&&_>0?0:Math.min(Math.abs(y.x),Math.abs(m.x)),Fe=M<0&&C>0?0:Math.min(Math.abs(y.y),Math.abs(m.y)),ge=Math.max($e,Fe);s.lastCentrality=(K-ge)*(K-ge)*(K-ge)}else s.lastCentrality=1;const d=this._tempBox.getSize(this._tempBoxSize);d.multiplyScalar(.5),screen.availHeight>0&&A>0&&d.multiplyScalar(A/screen.availHeight),d.x*=L.aspect;const O=t.matrixWorldInverse,b=this._tempBox2;b.copy(D),b.applyMatrix4(e.matrixWorld),b.applyMatrix4(O);const I=b.getSize(this._tempBox2Size),T=Math.max(I.x,I.y);if(Math.max(d.x,d.y)!=0&&T!=0&&(d.z=I.z/Math.max(I.x,I.y)*Math.max(d.x,d.y)),s.lastScreenCoverage=Math.max(d.x,d.y,d.z),s.lastScreenspaceVolume.copy(d),s.lastScreenCoverage*=s.lastCentrality,k&&P.debugDrawLine){const y=this.tempMatrix.copy(this.projectionScreenMatrix);y.invert();const m=P.corner0,h=P.corner1,M=P.corner2,_=P.corner3;m.copy(this._tempBox.min),h.copy(this._tempBox.max),h.x=m.x,M.copy(this._tempBox.max),M.y=m.y,_.copy(this._tempBox.max);const C=(m.z+_.z)*.5;m.z=h.z=M.z=_.z=C,m.applyMatrix4(y),h.applyMatrix4(y),M.applyMatrix4(y),_.applyMatrix4(y),P.debugDrawLine(m,h,255),P.debugDrawLine(m,M,255),P.debugDrawLine(h,_,255),P.debugDrawLine(M,_,255)}let W=999;if(a&&s.lastScreenCoverage>0){for(let y=0;y<a.length;y++)if(a[y].density/s.lastScreenCoverage<o){W=y;break}}W<i&&(i=W,l=!0)}if(l?r.mesh_lod=i:r.mesh_lod=s.lastLodLevel_Mesh,k&&r.mesh_lod!=s.lastLodLevel_Mesh){const L=a?.[r.mesh_lod];L&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} \u2192 ${r.mesh_lod} (${L.density.toFixed(0)}) - ${e.name}`)}if(p){const L="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=g.max_count-1,k){const d=g.lods[g.max_count-1];k&&console.log(`First Texture LOD ${r.texture_lod} (${d.max_height}px) - ${e.name}`)}}else{const d=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let O=s.lastScreenCoverage*4;((n=this.context)==null?void 0:n.engine)==="model-viewer"&&(O*=1.5);const b=A/window.devicePixelRatio*O;for(let I=g.lods.length-1;I>=0;I--){let T=g.lods[I];if(!(L&&T.max_height>=2048)&&!(it()&&T.max_height>4096)&&T.max_height>b){if(r.texture_lod=I,r.texture_lod<s.lastLodLevel_Texture){const W=T.max_height;k&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} \u2192 ${r.texture_lod} = ${W}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 T=w;c(T,"registerTexture",(t,e,s,o,r)=>{if(x&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,r),!e){x&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[De]=r);const n=r.guid;w.assignLODInformation(t,e,n,s,o,void 0),w.lodInfos.set(n,r),w.lowresCache.set(n,e)}),c(T,"registerMesh",(t,e,s,o,r,n)=>{var i;x&&console.log("> Progressive: register mesh",r,s.name,n,s.uuid,s);const l=s.geometry;if(!l){x&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),w.assignLODInformation(t,l,e,o,r,n.density),w.lodInfos.set(e,n);let u=w.lowresCache.get(e);u?u.push(s.geometry):u=[s.geometry],w.lowresCache.set(e,u),o>0&&!J(s)&&ke(s,l);for(const a of $)(i=a.onRegisteredNewMesh)==null||i.call(a,s,n)}),c(T,"lodInfos",new Map),c(T,"previouslyLoaded",new Map),c(T,"lowresCache",new Map);class ut{constructor(e,s,o,r,n){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=s,this.level=o,r!=null&&(this.index=r),n!=null&&(this.density=n)}}const B=se("debugprogressive"),ct=se("noprogressive"),Oe=Symbol("Needle:LODSManager"),be=Symbol("Needle:LODState"),Q=Symbol("Needle:CurrentLOD"),R={mesh_lod:-1,texture_lod:-1};var E,F,_e,Z,oe,de,U;const I=class{constructor(t,e){c(this,"context"),c(this,"renderer"),c(this,"projectionScreenMatrix",new Ee),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval","auto"),V(this,E,1),c(this,"pause",!1),c(this,"manual",!1),c(this,"_lodchangedlisteners",[]),V(this,F,void 0),V(this,_e,new Xe),V(this,Z,0),V(this,oe,0),V(this,de,0),V(this,U,0),c(this,"_fpsBuffer",[60,60,60,60,60]),c(this,"_sphere",new Ke),c(this,"_tempBox",new Ae),c(this,"_tempBox2",new Ae),c(this,"tempMatrix",new Ee),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[be]}static addPlugin(t){$.push(t)}static removePlugin(t){const e=$.indexOf(t);e>=0&&$.splice(e,1)}static get(t,e){if(t[Oe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[Oe];const s=new I(t,{engine:"unknown",...e});return t[Oe]=s,s}get plugins(){return $}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(v(this,F))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;G(this,F,this.renderer.render);const e=this;ye(this.renderer),this.renderer.render=function(s,o){const r=e.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(t=0,G(e,Z,v(e,Z)+1),G(e,oe,v(e,_e).getDelta()),G(e,de,v(e,de)+v(e,oe)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/v(e,oe)),G(e,U,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),B&&v(e,Z)%200===0&&console.log("FPS",Math.round(v(e,U)),"Interval:",v(e,E)));const n=t++;v(e,F).call(this,s,o),e.onAfterRender(s,o,n)}}disable(){v(this,F)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=v(this,F),G(this,F,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,s){if(this.pause)return;const o=this.renderer.renderLists.get(t,0).opaque;let r=!0;if(o.length===1){const n=o[0].material;(n.name==="EffectMaterial"||n.name==="CopyShader")&&(r=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(r=!1),r){if(ct||(this.updateInterval==="auto"?v(this,U)<40&&v(this,E)<10?(G(this,E,v(this,E)+1),B&&console.warn("\u2193 Reducing LOD updates",v(this,E),v(this,U).toFixed(0))):v(this,U)>=60&&v(this,E)>1&&(G(this,E,v(this,E)-1),B&&console.warn("\u2191 Increasing LOD updates",v(this,E),v(this,U).toFixed(0))):G(this,E,this.updateInterval),v(this,E)>0&&v(this,Z)%v(this,E)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var s,o;const r=this.renderer.renderLists.get(t,0),n=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const i=this.targetTriangleDensity;for(const a of n){if(a.material&&(((s=a.geometry)==null?void 0:s.type)==="BoxGeometry"||((o=a.geometry)==null?void 0:o.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 g=Math.random()*16777215,y=new He({color:g});a.object.material=y}const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}const l=r.transparent;for(const a of l){const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}const u=r.transmissive;for(const a of u){const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}}updateLODs(t,e,s,o){var r,n;s.userData||(s.userData={});let i=s[be];if(i||(i=new dt,s[be]=i),i.frames++<2)return;for(const u of $)(r=u.onBeforeUpdateLOD)==null||r.call(u,this.renderer,t,e,s);this.calculateLodLevel(e,s,i,o,R),R.mesh_lod=Math.round(R.mesh_lod),R.texture_lod=Math.round(R.texture_lod),R.mesh_lod>=0&&this.loadProgressiveMeshes(s,R.mesh_lod);let l=R.texture_lod;if(s.material&&l>=0){const u=s["DEBUG:LOD"];u!=null&&(l=u),this.loadProgressiveTextures(s.material,l)}for(const u of $)(n=u.onAfterUpdatedLOD)==null||n.call(u,this.renderer,t,e,s,R);i.lastLodLevel_Mesh=R.mesh_lod,i.lastLodLevel_Texture=R.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}let s=!1;(t[Q]===void 0||e<t[Q])&&(s=!0),s&&(t[Q]=e,T.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(r=>r({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[Q]!==e){t[Q]=e;const s=t.geometry;return T.assignMeshLOD(t,e).then(o=>(o&&t[Q]==e&&s!=t.geometry&&this._lodchangedlisteners.forEach(r=>r({type:"mesh",level:e,object:t})),o))}return Promise.resolve(null)}static isInside(t,e){const s=t.min,o=t.max,r=(s.x+o.x)*.5,n=(s.y+o.y)*.5;return this._tempPtInside.set(r,n,s.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,s,o,r){var n;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let i=10+1,l=!1;if(B&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=T.getMeshLODInformation(e.geometry),a=u?.lods,f=a&&a.length>0,g=T.getMaterialMinMaxLODsCount(e.material),y=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!f&&!y){r.mesh_lod=0,r.texture_lod=0;return}f||(l=!0,i=0);const A=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let D=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const L=e;if(!L.boundingBox)L.computeBoundingBox();else if(s.frames%30===0){const d=J(L),O=L.geometry;d&&(L.geometry=d),L.computeBoundingBox(),L.geometry=O}D=L.boundingBox}if(D&&t.isPerspectiveCamera){const L=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)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(D),this._tempBox.applyMatrix4(e.matrixWorld),I.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&L.fov>70){const m=this._tempBox.min,p=this._tempBox.max;let h=m.x,M=m.y,S=p.x,j=p.y;const z=2,K=1.5,ie=(m.x+p.x)*.5,ae=(m.y+p.y)*.5;h=(h-ie)*z+ie,M=(M-ae)*z+ae,S=(S-ie)*z+ie,j=(j-ae)*z+ae;const $e=h<0&&S>0?0:Math.min(Math.abs(m.x),Math.abs(p.x)),Fe=M<0&&j>0?0:Math.min(Math.abs(m.y),Math.abs(p.y)),ge=Math.max($e,Fe);s.lastCentrality=(K-ge)*(K-ge)*(K-ge)}else s.lastCentrality=1;const d=this._tempBox.getSize(this._tempBoxSize);d.multiplyScalar(.5),screen.availHeight>0&&A>0&&d.multiplyScalar(A/screen.availHeight),d.x*=L.aspect;const O=t.matrixWorldInverse,b=this._tempBox2;b.copy(D),b.applyMatrix4(e.matrixWorld),b.applyMatrix4(O);const P=b.getSize(this._tempBox2Size),_=Math.max(P.x,P.y);if(Math.max(d.x,d.y)!=0&&_!=0&&(d.z=P.z/Math.max(P.x,P.y)*Math.max(d.x,d.y)),s.lastScreenCoverage=Math.max(d.x,d.y,d.z),s.lastScreenspaceVolume.copy(d),s.lastScreenCoverage*=s.lastCentrality,B&&I.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const p=I.corner0,h=I.corner1,M=I.corner2,S=I.corner3;p.copy(this._tempBox.min),h.copy(this._tempBox.max),h.x=p.x,M.copy(this._tempBox.max),M.y=p.y,S.copy(this._tempBox.max);const j=(p.z+S.z)*.5;p.z=h.z=M.z=S.z=j,p.applyMatrix4(m),h.applyMatrix4(m),M.applyMatrix4(m),S.applyMatrix4(m),I.debugDrawLine(p,h,255),I.debugDrawLine(p,M,255),I.debugDrawLine(h,S,255),I.debugDrawLine(M,S,255)}let k=999;if(a&&s.lastScreenCoverage>0){for(let m=0;m<a.length;m++)if(a[m].density/s.lastScreenCoverage<o){k=m;break}}k<i&&(i=k,l=!0)}if(l?r.mesh_lod=i:r.mesh_lod=s.lastLodLevel_Mesh,B&&r.mesh_lod!=s.lastLodLevel_Mesh){const L=a?.[r.mesh_lod];L&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} \u2192 ${r.mesh_lod} (${L.density.toFixed(0)}) - ${e.name}`)}if(y){const L="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=g.max_count-1,B){const d=g.lods[g.max_count-1];B&&console.log(`First Texture LOD ${r.texture_lod} (${d.max_height}px) - ${e.name}`)}}else{const d=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let O=s.lastScreenCoverage*4;((n=this.context)==null?void 0:n.engine)==="model-viewer"&&(O*=1.5);const b=A/window.devicePixelRatio*O;let P=!1;for(let _=g.lods.length-1;_>=0;_--){let k=g.lods[_];if(!(L&&k.max_height>=2048)&&!(it()&&k.max_height>4096)&&(k.max_height>b||!P&&_===0)){if(P=!0,r.texture_lod=_,r.texture_lod<s.lastLodLevel_Texture){const m=k.max_height;B&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} \u2192 ${r.texture_lod} = ${m}px
|
|
6
6
|
Screensize: ${b.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${d.toFixed(1)}
|
|
7
|
-
${e.name}`)}break}}}}else r.texture_lod=0}};let
|
|
8
|
-
`,t.getAttribute("src"));let e=null,s=null,o=null;for(let r=t;r!=null;r=Object.getPrototypeOf(r)){const n=Object.getOwnPropertySymbols(r),i=n.find(a=>a.toString()=="Symbol(renderer)"),l=n.find(a=>a.toString()=="Symbol(scene)"),u=n.find(a=>a.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=t[i].threeRenderer),!s&&l!=null&&(s=t[l]),!o&&u!=null&&(o=t[u])}if(e&&s){let r=function(){if(o){let i=0,l=setInterval(()=>{if(i++>5){clearInterval(l);return}o?.call(t)},300)}};console.debug("[gltf-progressive] setup model-viewer");const n=
|
|
7
|
+
${e.name}`)}break}}}}else r.texture_lod=0}};let C=I;E=new WeakMap,F=new WeakMap,_e=new WeakMap,Z=new WeakMap,oe=new WeakMap,de=new WeakMap,U=new WeakMap,c(C,"debugDrawLine"),c(C,"corner0",new W),c(C,"corner1",new W),c(C,"corner2",new W),c(C,"corner3",new W),c(C,"_tempPtInside",new W);class dt{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 Ce=Symbol("NEEDLE_mesh_lod"),he=Symbol("NEEDLE_texture_lod");let fe=null;function Se(){const t=ht();t&&(t.mapURLs(function(e){return je(),e}),je(),fe?.disconnect(),fe=new MutationObserver(e=>{e.forEach(s=>{s.addedNodes.forEach(o=>{o instanceof HTMLElement&&o.tagName.toLowerCase()==="model-viewer"&&Ge(o)})})}),fe.observe(document,{childList:!0,subtree:!0}))}function ht(){return typeof customElements>"u"?null:customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Se()}),null)}function je(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(t=>{Ge(t)})}const Ne=new WeakSet;let ft=0;function Ge(t){if(!t||Ne.has(t))return null;Ne.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++ft+`
|
|
8
|
+
`,t.getAttribute("src"));let e=null,s=null,o=null;for(let r=t;r!=null;r=Object.getPrototypeOf(r)){const n=Object.getOwnPropertySymbols(r),i=n.find(a=>a.toString()=="Symbol(renderer)"),l=n.find(a=>a.toString()=="Symbol(scene)"),u=n.find(a=>a.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=t[i].threeRenderer),!s&&l!=null&&(s=t[l]),!o&&u!=null&&(o=t[u])}if(e&&s){let r=function(){if(o){let i=0,l=setInterval(()=>{if(i++>5){clearInterval(l);return}o?.call(t)},300)}};console.debug("[gltf-progressive] setup model-viewer");const n=C.get(e,{engine:"model-viewer"});return C.addPlugin(new gt),n.enable(),n.addEventListener("changed",()=>{o?.call(t)}),t.addEventListener("model-visibility",i=>{i.detail.visible&&o?.call(t)}),t.addEventListener("load",()=>{r()}),()=>{n.disable()}}return null}class gt{constructor(){c(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,s,o,r){this.tryParseMeshLOD(s,r),this.tryParseTextureLOD(s,r)}getUrl(e){if(!e)return null;let s=e.getAttribute("src");return s||(s=e.src),s||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),s}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,s){if(s[he]==!0)return;s[he]=!0;const o=this.tryGetCurrentGLTF(e),r=this.tryGetCurrentModelViewer(e),n=this.getUrl(r);if(n&&o&&s.material){let i=function(u){var a,f,g;if(u[he]==!0)return;u[he]=!0,u.userData&&(u.userData.LOD=-1);const y=Object.keys(u);for(let A=0;A<y.length;A++){const D=y[A],L=u[D];if(L?.isTexture===!0){const d=(f=(a=L.userData)==null?void 0:a.associations)==null?void 0:f.textures;if(d==null)continue;const O=o.parser.json.textures[d];if(!O){console.warn("Texture data not found for texture index "+d);continue}if((g=O?.extensions)!=null&&g[N]){const b=O.extensions[N];b&&n&&T.registerTexture(n,L,b.lods.length,d,b)}}}};const l=s.material;if(Array.isArray(l))for(const u of l)i(u);else i(l)}}tryParseMeshLOD(e,s){var o,r;if(s[Ce]==!0)return;s[Ce]=!0;const n=this.tryGetCurrentModelViewer(e),i=this.getUrl(n);if(!i)return;const l=(r=(o=s.userData)==null?void 0:o.gltfExtensions)==null?void 0:r[N];if(l&&i){const u=s.uuid;T.registerMesh(i,u,s,0,l.lods.length,l)}}}function We(t,e,s,o){ye(e),ve(s),Le(s,{progressive:!0,...o?.hints}),s.register(n=>new T(n,t));const r=C.get(e);return o?.enableLODsManager!==!1&&r.enable(),r}if(Se(),!at){const t={gltfProgressive:{useNeedleProgressive:We,LODsManager:C,configureLoader:Le,getRaycastMesh:J,useRaycastMeshes:Be}};if(!globalThis.Needle)globalThis.Needle=t;else for(const e in t)globalThis.Needle[e]=t[e]}export{N as EXTENSION_NAME,C as LODsManager,T as NEEDLE_progressive,pe as VERSION,ve as addDracoAndKTX2Loaders,Le as configureLoader,ye as createLoaders,J as getRaycastMesh,Se as patchModelViewer,ke as registerRaycastMesh,st as setDracoDecoderLocation,rt as setKTX2TranscoderLocation,We as useNeedleProgressive,Be as useRaycastMeshes};
|
package/gltf-progressive.umd.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"use strict";var Ue=Object.defineProperty;var ze=(n,e,t)=>e in n?Ue(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var d=(n,e,t)=>(ze(n,typeof e!="symbol"?e+"":e,t),t),Ee=(n,e,t)=>{if(!e.has(n))throw TypeError("Cannot "+t)};var L=(n,e,t)=>(Ee(n,e,"read from private field"),t?t.call(n):e.get(n)),K=(n,e,t)=>{if(e.has(n))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(n):e.set(n,t)},N=(n,e,t,s)=>(Ee(n,e,"write to private field"),s?s.call(n,t):e.set(n,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("three"),_e=require("three/examples/jsm/loaders/GLTFLoader.js"),We=require("three/examples/jsm/libs/meshopt_decoder.module.js"),qe=require("three/examples/jsm/loaders/DRACOLoader.js"),Xe=require("three/examples/jsm/loaders/KTX2Loader.js"),Oe="";globalThis.GLTF_PROGRESSIVE_VERSION=Oe;console.debug(`[gltf-progressive] version ${Oe}`);let ee="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",ne="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ke=ee,Ye=ne,He=new URL(ee+"draco_decoder.js");fetch(He,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(n=>{ee===Ke&&(ee="./include/draco/"),ne===Ye&&(ne="./include/ktx2/")}).finally(()=>{ke()});function je(n){ee=n}function Je(n){ne=n}let H,de,j;function ke(){H||(H=new qe.DRACOLoader,H.setDecoderPath(ee),H.setDecoderConfig({type:"js"}),H.preload()),j||(j=new Xe.KTX2Loader,j.setTranscoderPath(ne),j.init()),de||(de=We.MeshoptDecoder)}function Se(n){return ke(),n?j.detectSupport(n):n!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:H,ktx2Loader:j,meshoptDecoder:de}}function be(n){n.dracoLoader||n.setDRACOLoader(H),n.ktx2Loader||n.setKTX2Loader(j),n.meshoptDecoder||n.setMeshoptDecoder(de)}const De=new WeakMap;function Te(n,e){let t=De.get(n);t?t=Object.assign(t,e):t=e,De.set(n,t)}const me=_e.GLTFLoader.prototype.load;function Qe(...n){const e=De.get(this);let t=n[0];const s=new URL(t,window.location.href);if(s.hostname.endsWith("needle.tools")){const r=(e==null?void 0:e.progressive)!==void 0?e.progressive:!0,i=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${i}`:this.requestHeader.Accept=`*/*;usecase=${i}`,t=s.toString()}return n[0]=t,me==null?void 0:me.call(this,...n)}_e.GLTFLoader.prototype.load=Qe;ae("debugprogressive");function ae(n){if(typeof window>"u")return!1;const t=new URL(window.location.href).searchParams.get(n);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function Ze(n,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||n===void 0)return e;const t=n.lastIndexOf("/");if(t>=0){const s=n.substring(0,t+1);for(;s.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return s+e}return e}let se;function et(){return se!==void 0||(se=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ae("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",se)),se}const tt=typeof window>"u"&&typeof document>"u",we=Symbol("needle:raycast-mesh");function te(n){return(n==null?void 0:n[we])instanceof p.BufferGeometry?n[we]:null}function Ie(n,e){if((n.type==="Mesh"||n.type==="SkinnedMesh")&&!te(n)){const s=st(e);s.userData={isRaycastMesh:!0},n[we]=s}}function Ge(n=!0){if(n){if(re)return;const e=re=p.Mesh.prototype.raycast;p.Mesh.prototype.raycast=function(t,s){const o=this,r=te(o);let i;r&&o.isMesh&&(i=o.geometry,o.geometry=r),e.call(this,t,s),i&&(o.geometry=i)}}else{if(!re)return;p.Mesh.prototype.raycast=re,re=null}}let re=null;function st(n){const e=new p.BufferGeometry;for(const t in n.attributes)e.setAttribute(t,n.getAttribute(t));return e.setIndex(n.getIndex()),e}const Y=new Array,U="NEEDLE_progressive",x=ae("debugprogressive"),Le=Symbol("needle-progressive-texture"),oe=new Map,ve=new Set;if(x){let n=function(){e+=1,console.log("Toggle LOD level",e,oe),oe.forEach((o,r)=>{for(const i of o.keys){const a=r[i];if(a!=null){if(a.isBufferGeometry===!0){const l=O.getMeshLODInformation(a),u=l?Math.min(e,l.lods.length):0;r["DEBUG:LOD"]=e,O.assignMeshLOD(r,u),l&&(t=Math.max(t,l.lods.length-1))}else if(r.isMaterial===!0){r["DEBUG:LOD"]=e,O.assignTextureLOD(r,e);break}}}}),e>=t&&(e=-1)},e=-1,t=2,s=!1;window.addEventListener("keyup",o=>{o.key==="p"&&n(),o.key==="w"&&(s=!s,ve&&ve.forEach(r=>{r.name!="BackgroundCubeMaterial"&&r.glyphMap==null&&"wireframe"in r&&(r.wireframe=s)}))})}function Pe(n,e,t){var o;if(!x)return;oe.has(n)||oe.set(n,{keys:[],sourceId:t});const s=oe.get(n);((o=s==null?void 0:s.keys)==null?void 0:o.includes(e))==!1&&s.keys.push(e)}const _=class{constructor(e,t){d(this,"parser");d(this,"url");d(this,"_isLoadingMesh");d(this,"loadMesh",e=>{var s,o;if(this._isLoadingMesh)return null;const t=(o=(s=this.parser.json.meshes[e])==null?void 0:s.extensions)==null?void 0:o[U];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(r=>{var i;return this._isLoadingMesh=!1,r&&_.registerMesh(this.url,t.guid,r,(i=t.lods)==null?void 0:i.length,void 0,t),r})):null});x&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return U}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static getMaterialMinMaxLODsCount(e,t){const s=this,o="LODS:minmax",r=e[o];if(r!=null)return r;if(t||(t={min_count:1/0,max_count:0,lods:[]}),Array.isArray(e)){for(const a of e)this.getMaterialMinMaxLODsCount(a,t);return e[o]=t,t}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const a=e;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;(u==null?void 0:u.isTexture)===!0&&i(u,t)}}else if(e.isMaterial)for(const a of Object.keys(e)){const l=e[a];(l==null?void 0:l.isTexture)===!0&&i(l,t)}return e[o]=t,t;function i(a,l){const u=s.getAssignedLODInformation(a);if(u){const c=s.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 g=0;g<c.lods.length;g++){const y=c.lods[g];y.width&&(l.lods[g]=l.lods[g]||{min_height:1/0,max_height:0},l.lods[g].min_height=Math.min(l.lods[g].min_height,y.height),l.lods[g].max_height=Math.max(l.lods[g].max_height,y.height))}}}}}static hasLODLevelAvailable(e,t){var r;if(Array.isArray(e)){for(const i of e)if(this.hasLODLevelAvailable(i,t))return!0;return!1}if(e.isMaterial===!0){for(const i of Object.keys(e)){const a=e[i];if(a&&a.isTexture&&this.hasLODLevelAvailable(a,t))return!0}return!1}else if(e.isGroup===!0){for(const i of e.children)if(i.isMesh===!0&&this.hasLODLevelAvailable(i,t))return!0}let s,o;if(e.isMesh?s=e.geometry:(e.isBufferGeometry||e.isTexture)&&(s=e),s&&(r=s==null?void 0:s.userData)!=null&&r.LODS){const i=s.userData.LODS;if(o=this.lodInfos.get(i.key),t===void 0)return o!=null;if(o)return Array.isArray(o.lods)?t<o.lods.length:t===0}return!1}static assignMeshLOD(e,t){var s;if(!e)return Promise.resolve(null);if(e instanceof p.Mesh||e.isMesh===!0){const o=e.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const i of Y)(s=i.onBeforeGetLODMesh)==null||s.call(i,e,t);return e["LOD:requested level"]=t,_.getOrLoadLOD(o,t).then(i=>{if(Array.isArray(i)){const a=r.index||0;i=i[a]}return e["LOD:requested level"]===t&&(delete e["LOD:requested level"],i&&o!=i&&((i==null?void 0:i.isBufferGeometry)?(e.geometry=i,x&&Pe(e,"geometry",r.url)):x&&console.error("Invalid LOD geometry",i))),i}).catch(i=>(console.error("Error loading mesh LOD",e,i),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e.isMesh===!0){const s=e;if(Array.isArray(s.material)){const o=new Array;for(const r of s.material){const i=this.assignTextureLOD(r,t);o.push(i)}return Promise.all(o).then(r=>{const i=new Array;for(const a of r)Array.isArray(a)&&i.push(...a);return i})}else return this.assignTextureLOD(s.material,t)}if(e instanceof p.Material||e.isMaterial===!0){const s=e,o=[],r=new Array;if(x&&ve.add(s),s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const i=s;for(const a of Object.keys(i.uniforms)){const l=i.uniforms[a].value;if((l==null?void 0:l.isTexture)===!0){const u=this.assignTextureLODForSlot(l,t,s,a).then(c=>(c&&i.uniforms[a].value!=c&&(i.uniforms[a].value=c,i.uniformsNeedUpdate=!0),c));o.push(u),r.push(a)}}}else for(const i of Object.keys(s)){const a=s[i];if((a==null?void 0:a.isTexture)===!0){const l=this.assignTextureLODForSlot(a,t,s,i);o.push(l),r.push(i)}}return Promise.all(o).then(i=>{const a=new Array;for(let l=0;l<i.length;l++){const u=i[l],c=r[l];u&&u.isTexture===!0?a.push({material:s,slot:c,texture:u,level:t}):a.push({material:s,slot:c,texture:null,level:t})}return a})}if(e instanceof p.Texture||e.isTexture===!0){const s=e;return this.assignTextureLODForSlot(s,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,s,o){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(e):_.getOrLoadLOD(e,t).then(r=>{if(Array.isArray(r))return null;if((r==null?void 0:r.isTexture)===!0){if(r!=e){if(s&&o){const i=s[o];if(i){const a=this.getAssignedLODInformation(i);if(a&&(a==null?void 0:a.level)<t)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",a.level,t,s,i,r),null}s[o]=r}if(x&&o&&s){const i=this.getAssignedLODInformation(e);i&&Pe(s,o,i.url)}}return r}else x=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(r=>(console.error("Error loading LOD",e,r),null))}afterRoot(e){var t,s;return x&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((o,r)=>{var i;if(o!=null&&o.extensions){const a=o==null?void 0:o.extensions[U];if(a){if(!a.lods){x&&console.warn("Texture has no LODs",a);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)===r&&(l=!0,_.registerTexture(this.url,u,(i=a.lods)==null?void 0:i.length,r,a))}l||this.parser.getDependency("texture",r).then(u=>{var c;u&&_.registerTexture(this.url,u,(c=a.lods)==null?void 0:c.length,r,a)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const i=o==null?void 0:o.extensions[U];if(i&&i.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const l=this.parser.associations.get(a);(l==null?void 0:l.meshes)===r&&_.registerMesh(this.url,i.guid,a,i.lods.length,l.primitives,i)}}}}),null}static async getOrLoadLOD(e,t){var a,l,u,c;const s=x=="verbose",o=e.userData.LODS;if(!o)return null;const r=o==null?void 0:o.key;let i;if(e.isTexture===!0){const g=e;g.source&&g.source[Le]&&(i=g.source[Le])}if(i||(i=_.lodInfos.get(r)),i){if(t>0){let D=!1;const v=Array.isArray(i.lods);if(v&&t>=i.lods.length?D=!0:v||(D=!0),D)return this.lowresCache.get(r)}const g=Array.isArray(i.lods)?(a=i.lods[t])==null?void 0:a.path:i.lods;if(!g)return x&&!i["missing:uri"]&&(i["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,i)),null;const y=Ze(o.url,g);if(y.endsWith(".glb")||y.endsWith(".gltf")){if(!i.guid)return console.warn("missing pointer for glb/gltf texture",i),null;const D=y+"_"+i.guid,v=this.previouslyLoaded.get(D);if(v!==void 0){s&&console.log(`LOD ${t} was already loading/loaded: ${D}`);let h=await v.catch($=>(console.error(`Error loading LOD ${t} from ${y}
|
|
2
|
-
`,$),null)),k=!1;if(h==null||(h instanceof p.Texture&&e instanceof p.Texture?(l=h.image)!=null&&l.data||(u=h.source)!=null&&u.data?h=this.copySettings(e,h):(k=!0,this.previouslyLoaded.delete(D)):h instanceof p.BufferGeometry&&e instanceof p.BufferGeometry&&((c=h.attributes.position)!=null&&c.array||(k=!0,this.previouslyLoaded.delete(D)))),!k)return h}const M=i,V=new Promise(async(h,k)=>{const $=new _e.GLTFLoader;be($),x&&(await new Promise(
|
|
3
|
-
`,
|
|
1
|
+
"use strict";var Ue=Object.defineProperty;var ze=(n,e,t)=>e in n?Ue(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var d=(n,e,t)=>(ze(n,typeof e!="symbol"?e+"":e,t),t),Ee=(n,e,t)=>{if(!e.has(n))throw TypeError("Cannot "+t)};var m=(n,e,t)=>(Ee(n,e,"read from private field"),t?t.call(n):e.get(n)),K=(n,e,t)=>{if(e.has(n))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(n):e.set(n,t)},N=(n,e,t,s)=>(Ee(n,e,"write to private field"),s?s.call(n,t):e.set(n,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("three"),_e=require("three/examples/jsm/loaders/GLTFLoader.js"),We=require("three/examples/jsm/libs/meshopt_decoder.module.js"),qe=require("three/examples/jsm/loaders/DRACOLoader.js"),Xe=require("three/examples/jsm/loaders/KTX2Loader.js"),Oe="";globalThis.GLTF_PROGRESSIVE_VERSION=Oe;console.debug(`[gltf-progressive] version ${Oe}`);let ee="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",ne="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ke=ee,Ye=ne,He=new URL(ee+"draco_decoder.js");fetch(He,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(n=>{ee===Ke&&(ee="./include/draco/"),ne===Ye&&(ne="./include/ktx2/")}).finally(()=>{ke()});function je(n){ee=n}function Je(n){ne=n}let H,de,j;function ke(){H||(H=new qe.DRACOLoader,H.setDecoderPath(ee),H.setDecoderConfig({type:"js"}),H.preload()),j||(j=new Xe.KTX2Loader,j.setTranscoderPath(ne),j.init()),de||(de=We.MeshoptDecoder)}function Se(n){return ke(),n?j.detectSupport(n):n!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:H,ktx2Loader:j,meshoptDecoder:de}}function be(n){n.dracoLoader||n.setDRACOLoader(H),n.ktx2Loader||n.setKTX2Loader(j),n.meshoptDecoder||n.setMeshoptDecoder(de)}const De=new WeakMap;function Te(n,e){let t=De.get(n);t?t=Object.assign(t,e):t=e,De.set(n,t)}const Le=_e.GLTFLoader.prototype.load;function Qe(...n){const e=De.get(this);let t=n[0];const s=new URL(t,window.location.href);if(s.hostname.endsWith("needle.tools")){const r=(e==null?void 0:e.progressive)!==void 0?e.progressive:!0,i=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${i}`:this.requestHeader.Accept=`*/*;usecase=${i}`,t=s.toString()}return n[0]=t,Le==null?void 0:Le.call(this,...n)}_e.GLTFLoader.prototype.load=Qe;ae("debugprogressive");function ae(n){if(typeof window>"u")return!1;const t=new URL(window.location.href).searchParams.get(n);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function Ze(n,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||n===void 0)return e;const t=n.lastIndexOf("/");if(t>=0){const s=n.substring(0,t+1);for(;s.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return s+e}return e}let se;function et(){return se!==void 0||(se=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ae("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",se)),se}const tt=typeof window>"u"&&typeof document>"u",we=Symbol("needle:raycast-mesh");function te(n){return(n==null?void 0:n[we])instanceof p.BufferGeometry?n[we]:null}function Ie(n,e){if((n.type==="Mesh"||n.type==="SkinnedMesh")&&!te(n)){const s=st(e);s.userData={isRaycastMesh:!0},n[we]=s}}function Ge(n=!0){if(n){if(re)return;const e=re=p.Mesh.prototype.raycast;p.Mesh.prototype.raycast=function(t,s){const o=this,r=te(o);let i;r&&o.isMesh&&(i=o.geometry,o.geometry=r),e.call(this,t,s),i&&(o.geometry=i)}}else{if(!re)return;p.Mesh.prototype.raycast=re,re=null}}let re=null;function st(n){const e=new p.BufferGeometry;for(const t in n.attributes)e.setAttribute(t,n.getAttribute(t));return e.setIndex(n.getIndex()),e}const Y=new Array,U="NEEDLE_progressive",x=ae("debugprogressive"),me=Symbol("needle-progressive-texture"),oe=new Map,ve=new Set;if(x){let n=function(){e+=1,console.log("Toggle LOD level",e,oe),oe.forEach((o,r)=>{for(const i of o.keys){const a=r[i];if(a!=null){if(a.isBufferGeometry===!0){const l=O.getMeshLODInformation(a),u=l?Math.min(e,l.lods.length):0;r["DEBUG:LOD"]=e,O.assignMeshLOD(r,u),l&&(t=Math.max(t,l.lods.length-1))}else if(r.isMaterial===!0){r["DEBUG:LOD"]=e,O.assignTextureLOD(r,e);break}}}}),e>=t&&(e=-1)},e=-1,t=2,s=!1;window.addEventListener("keyup",o=>{o.key==="p"&&n(),o.key==="w"&&(s=!s,ve&&ve.forEach(r=>{r.name!="BackgroundCubeMaterial"&&r.glyphMap==null&&"wireframe"in r&&(r.wireframe=s)}))})}function Pe(n,e,t){var o;if(!x)return;oe.has(n)||oe.set(n,{keys:[],sourceId:t});const s=oe.get(n);((o=s==null?void 0:s.keys)==null?void 0:o.includes(e))==!1&&s.keys.push(e)}const _=class{constructor(e,t){d(this,"parser");d(this,"url");d(this,"_isLoadingMesh");d(this,"loadMesh",e=>{var s,o;if(this._isLoadingMesh)return null;const t=(o=(s=this.parser.json.meshes[e])==null?void 0:s.extensions)==null?void 0:o[U];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(r=>{var i;return this._isLoadingMesh=!1,r&&_.registerMesh(this.url,t.guid,r,(i=t.lods)==null?void 0:i.length,void 0,t),r})):null});x&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return U}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static getMaterialMinMaxLODsCount(e,t){const s=this,o="LODS:minmax",r=e[o];if(r!=null)return r;if(t||(t={min_count:1/0,max_count:0,lods:[]}),Array.isArray(e)){for(const a of e)this.getMaterialMinMaxLODsCount(a,t);return e[o]=t,t}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const a=e;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;(u==null?void 0:u.isTexture)===!0&&i(u,t)}}else if(e.isMaterial)for(const a of Object.keys(e)){const l=e[a];(l==null?void 0:l.isTexture)===!0&&i(l,t)}return e[o]=t,t;function i(a,l){const u=s.getAssignedLODInformation(a);if(u){const c=s.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 g=0;g<c.lods.length;g++){const y=c.lods[g];y.width&&(l.lods[g]=l.lods[g]||{min_height:1/0,max_height:0},l.lods[g].min_height=Math.min(l.lods[g].min_height,y.height),l.lods[g].max_height=Math.max(l.lods[g].max_height,y.height))}}}}}static hasLODLevelAvailable(e,t){var r;if(Array.isArray(e)){for(const i of e)if(this.hasLODLevelAvailable(i,t))return!0;return!1}if(e.isMaterial===!0){for(const i of Object.keys(e)){const a=e[i];if(a&&a.isTexture&&this.hasLODLevelAvailable(a,t))return!0}return!1}else if(e.isGroup===!0){for(const i of e.children)if(i.isMesh===!0&&this.hasLODLevelAvailable(i,t))return!0}let s,o;if(e.isMesh?s=e.geometry:(e.isBufferGeometry||e.isTexture)&&(s=e),s&&(r=s==null?void 0:s.userData)!=null&&r.LODS){const i=s.userData.LODS;if(o=this.lodInfos.get(i.key),t===void 0)return o!=null;if(o)return Array.isArray(o.lods)?t<o.lods.length:t===0}return!1}static assignMeshLOD(e,t){var s;if(!e)return Promise.resolve(null);if(e instanceof p.Mesh||e.isMesh===!0){const o=e.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const i of Y)(s=i.onBeforeGetLODMesh)==null||s.call(i,e,t);return e["LOD:requested level"]=t,_.getOrLoadLOD(o,t).then(i=>{if(Array.isArray(i)){const a=r.index||0;i=i[a]}return e["LOD:requested level"]===t&&(delete e["LOD:requested level"],i&&o!=i&&((i==null?void 0:i.isBufferGeometry)?(e.geometry=i,x&&Pe(e,"geometry",r.url)):x&&console.error("Invalid LOD geometry",i))),i}).catch(i=>(console.error("Error loading mesh LOD",e,i),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e.isMesh===!0){const s=e;if(Array.isArray(s.material)){const o=new Array;for(const r of s.material){const i=this.assignTextureLOD(r,t);o.push(i)}return Promise.all(o).then(r=>{const i=new Array;for(const a of r)Array.isArray(a)&&i.push(...a);return i})}else return this.assignTextureLOD(s.material,t)}if(e instanceof p.Material||e.isMaterial===!0){const s=e,o=[],r=new Array;if(x&&ve.add(s),s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const i=s;for(const a of Object.keys(i.uniforms)){const l=i.uniforms[a].value;if((l==null?void 0:l.isTexture)===!0){const u=this.assignTextureLODForSlot(l,t,s,a).then(c=>(c&&i.uniforms[a].value!=c&&(i.uniforms[a].value=c,i.uniformsNeedUpdate=!0),c));o.push(u),r.push(a)}}}else for(const i of Object.keys(s)){const a=s[i];if((a==null?void 0:a.isTexture)===!0){const l=this.assignTextureLODForSlot(a,t,s,i);o.push(l),r.push(i)}}return Promise.all(o).then(i=>{const a=new Array;for(let l=0;l<i.length;l++){const u=i[l],c=r[l];u&&u.isTexture===!0?a.push({material:s,slot:c,texture:u,level:t}):a.push({material:s,slot:c,texture:null,level:t})}return a})}if(e instanceof p.Texture||e.isTexture===!0){const s=e;return this.assignTextureLODForSlot(s,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,s,o){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(e):_.getOrLoadLOD(e,t).then(r=>{if(Array.isArray(r))return null;if((r==null?void 0:r.isTexture)===!0){if(r!=e){if(s&&o){const i=s[o];if(i){const a=this.getAssignedLODInformation(i);if(a&&(a==null?void 0:a.level)<t)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",a.level,t,s,i,r),null}s[o]=r}if(x&&o&&s){const i=this.getAssignedLODInformation(e);i&&Pe(s,o,i.url)}}return r}else x=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(r=>(console.error("Error loading LOD",e,r),null))}afterRoot(e){var t,s;return x&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((o,r)=>{var i;if(o!=null&&o.extensions){const a=o==null?void 0:o.extensions[U];if(a){if(!a.lods){x&&console.warn("Texture has no LODs",a);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)===r&&(l=!0,_.registerTexture(this.url,u,(i=a.lods)==null?void 0:i.length,r,a))}l||this.parser.getDependency("texture",r).then(u=>{var c;u&&_.registerTexture(this.url,u,(c=a.lods)==null?void 0:c.length,r,a)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const i=o==null?void 0:o.extensions[U];if(i&&i.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const l=this.parser.associations.get(a);(l==null?void 0:l.meshes)===r&&_.registerMesh(this.url,i.guid,a,i.lods.length,l.primitives,i)}}}}),null}static async getOrLoadLOD(e,t){var a,l,u,c;const s=x=="verbose",o=e.userData.LODS;if(!o)return null;const r=o==null?void 0:o.key;let i;if(e.isTexture===!0){const g=e;g.source&&g.source[me]&&(i=g.source[me])}if(i||(i=_.lodInfos.get(r)),i){if(t>0){let D=!1;const v=Array.isArray(i.lods);if(v&&t>=i.lods.length?D=!0:v||(D=!0),D)return this.lowresCache.get(r)}const g=Array.isArray(i.lods)?(a=i.lods[t])==null?void 0:a.path:i.lods;if(!g)return x&&!i["missing:uri"]&&(i["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,i)),null;const y=Ze(o.url,g);if(y.endsWith(".glb")||y.endsWith(".gltf")){if(!i.guid)return console.warn("missing pointer for glb/gltf texture",i),null;const D=y+"_"+i.guid,v=this.previouslyLoaded.get(D);if(v!==void 0){s&&console.log(`LOD ${t} was already loading/loaded: ${D}`);let h=await v.catch($=>(console.error(`Error loading LOD ${t} from ${y}
|
|
2
|
+
`,$),null)),k=!1;if(h==null||(h instanceof p.Texture&&e instanceof p.Texture?(l=h.image)!=null&&l.data||(u=h.source)!=null&&u.data?h=this.copySettings(e,h):(k=!0,this.previouslyLoaded.delete(D)):h instanceof p.BufferGeometry&&e instanceof p.BufferGeometry&&((c=h.attributes.position)!=null&&c.array||(k=!0,this.previouslyLoaded.delete(D)))),!k)return h}const M=i,V=new Promise(async(h,k)=>{const $=new _e.GLTFLoader;be($),x&&(await new Promise(T=>setTimeout(T,1e3)),s&&console.warn("Start loading (delayed) "+y,M.guid));let I=y;if(M&&Array.isArray(M.lods)){const T=M.lods[t];T.hash&&(I+="?v="+T.hash)}const E=await $.loadAsync(I).catch(T=>(console.error(`Error loading LOD ${t} from ${y}
|
|
3
|
+
`,T),null));if(!E)return null;const z=E.parser;s&&console.log("Loading finished "+y,M.guid);let b=0;if(E.parser.json.textures){let T=!1;for(const f of E.parser.json.textures){if(f!=null&&f.extensions){const L=f==null?void 0:f.extensions[U];if(L!=null&&L.guid&&L.guid===M.guid){T=!0;break}}b++}if(T){let f=await z.getDependency("texture",b);return f&&_.assignLODInformation(o.url,f,r,t,void 0,void 0),s&&console.log('change "'+e.name+'" → "'+f.name+'"',y,b,f,D),e instanceof p.Texture&&(f=this.copySettings(e,f)),f&&(f.guid=M.guid),h(f)}else x&&console.warn("Could not find texture with guid",M.guid,E.parser.json)}if(b=0,E.parser.json.meshes){let T=!1;for(const f of E.parser.json.meshes){if(f!=null&&f.extensions){const L=f==null?void 0:f.extensions[U];if(L!=null&&L.guid&&L.guid===M.guid){T=!0;break}}b++}if(T){const f=await z.getDependency("mesh",b),L=M;if(s&&console.log(`Loaded Mesh "${f.name}"`,y,b,f,D),f.isMesh===!0){const S=f.geometry;return _.assignLODInformation(o.url,S,r,t,void 0,L.density),h(S)}else{const S=new Array;for(let A=0;A<f.children.length;A++){const P=f.children[A];if(P.isMesh===!0){const X=P.geometry;_.assignLODInformation(o.url,X,r,t,A,L.density),S.push(X)}}return h(S)}}else x&&console.warn("Could not find mesh with guid",M.guid,E.parser.json)}return h(null)});return this.previouslyLoaded.set(D,V),await V}else if(e instanceof p.Texture){s&&console.log("Load texture from uri: "+y);const v=await new p.TextureLoader().loadAsync(y);return v?(v.guid=i.guid,v.flipY=!1,v.needsUpdate=!0,v.colorSpace=e.colorSpace,s&&console.log(i,v)):x&&console.warn("failed loading",y),v}}else x&&console.warn(`Can not load LOD ${t}: no LOD info found for "${r}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,s,o,r,i){if(!t)return;t.userData||(t.userData={});const a=new rt(e,s,o,r,i);t.userData.LODS=a}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){return t=t.clone(),x&&console.warn(`Copying texture settings
|
|
4
4
|
`,e.uuid,`
|
|
5
|
-
`,t.uuid),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.mipmaps||(t.generateMipmaps=e.generateMipmaps),t}};let O=_;d(O,"registerTexture",(e,t,s,o,r)=>{if(x&&console.log("> Progressive: register texture",o,t.name,t.uuid,t,r),!t){x&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[Le]=r);const i=r.guid;_.assignLODInformation(e,t,i,s,o,void 0),_.lodInfos.set(i,r),_.lowresCache.set(i,t)}),d(O,"registerMesh",(e,t,s,o,r,i)=>{var u;x&&console.log("> Progressive: register mesh",r,s.name,i,s.uuid,s);const a=s.geometry;if(!a){x&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),_.assignLODInformation(e,a,t,o,r,i.density),_.lodInfos.set(t,i);let l=_.lowresCache.get(t);l?l.push(s.geometry):l=[s.geometry],_.lowresCache.set(t,l),o>0&&!te(s)&&Ie(s,a);for(const c of Y)(u=c.onRegisteredNewMesh)==null||u.call(c,s,i)}),d(O,"lodInfos",new Map),d(O,"previouslyLoaded",new Map),d(O,"lowresCache",new Map);class rt{constructor(e,t,s,o,r){d(this,"url");d(this,"key");d(this,"level");d(this,"index");d(this,"density");this.url=e,this.key=t,this.level=s,o!=null&&(this.index=o),r!=null&&(this.density=r)}}const G=ae("debugprogressive"),it=ae("noprogressive"),xe=Symbol("Needle:LODSManager"),Me=Symbol("Needle:LODState"),J=Symbol("Needle:CurrentLOD"),F={mesh_lod:-1,texture_lod:-1};var B,z,he,Q,Z,ge,W;const C=class{constructor(e,t){d(this,"context");d(this,"renderer");d(this,"projectionScreenMatrix",new p.Matrix4);d(this,"targetTriangleDensity",2e5);d(this,"updateInterval","auto");K(this,B,1);d(this,"pause",!1);d(this,"manual",!1);d(this,"_lodchangedlisteners",[]);K(this,z,void 0);K(this,he,new p.Clock);K(this,Q,0);K(this,Z,0);K(this,ge,0);K(this,W,0);d(this,"_fpsBuffer",[60,60,60,60,60]);d(this,"_sphere",new p.Sphere);d(this,"_tempBox",new p.Box3);d(this,"_tempBox2",new p.Box3);d(this,"tempMatrix",new p.Matrix4);d(this,"_tempWorldPosition",new p.Vector3);d(this,"_tempBoxSize",new p.Vector3);d(this,"_tempBox2Size",new p.Vector3);this.renderer=e,this.context={...t}}static getObjectLODState(e){return e[Me]}static addPlugin(e){Y.push(e)}static removePlugin(e){const t=Y.indexOf(e);t>=0&&Y.splice(t,1)}static get(e,t){if(e[xe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),e[xe];const s=new C(e,{engine:"unknown",...t});return e[xe]=s,s}get plugins(){return Y}addEventListener(e,t){e==="changed"&&this._lodchangedlisteners.push(t)}removeEventListener(e,t){if(e==="changed"){const s=this._lodchangedlisteners.indexOf(t);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(L(this,z))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let e=0;N(this,z,this.renderer.render);const t=this;Se(this.renderer),this.renderer.render=function(s,o){const r=t.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(e=0,N(t,Q,L(t,Q)+1),N(t,Z,L(t,he).getDelta()),N(t,ge,L(t,ge)+L(t,Z)),t._fpsBuffer.shift(),t._fpsBuffer.push(1/L(t,Z)),N(t,W,t._fpsBuffer.reduce((a,l)=>a+l)/t._fpsBuffer.length),G&&L(t,Q)%200===0&&console.log("FPS",Math.round(L(t,W)),"Interval:",L(t,B)));const i=e++;L(t,z).call(this,s,o),t.onAfterRender(s,o,i)}}disable(){L(this,z)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=L(this,z),N(this,z,void 0))}update(e,t){this.internalUpdate(e,t)}onAfterRender(e,t,s){if(this.pause)return;const r=this.renderer.renderLists.get(e,0).opaque;let i=!0;if(r.length===1){const a=r[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(i=!1)}if((t.parent&&t.parent.type==="CubeCamera"||s>=1&&t.type==="OrthographicCamera")&&(i=!1),i){if(it||(this.updateInterval==="auto"?L(this,W)<40&&L(this,B)<10?(N(this,B,L(this,B)+1),G&&console.warn("↓ Reducing LOD updates",L(this,B),L(this,W).toFixed(0))):L(this,W)>=60&&L(this,B)>1&&(N(this,B,L(this,B)-1),G&&console.warn("↑ Increasing LOD updates",L(this,B),L(this,W).toFixed(0))):N(this,B,this.updateInterval),L(this,B)>0&&L(this,Q)%L(this,B)!=0))return;this.internalUpdate(e,t)}}internalUpdate(e,t){var l,u;const s=this.renderer.renderLists.get(e,0),o=s.opaque;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse);const r=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 y=Math.random()*16777215,D=new p.MeshStandardMaterial({color:y});c.object.material=D}const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}const i=s.transparent;for(const c of i){const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}const a=s.transmissive;for(const c of a){const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}}updateLODs(e,t,s,o){var a,l;s.userData||(s.userData={});let r=s[Me];if(r||(r=new ot,s[Me]=r),r.frames++<2)return;for(const u of Y)(a=u.onBeforeUpdateLOD)==null||a.call(u,this.renderer,e,t,s);this.calculateLodLevel(t,s,r,o,F),F.mesh_lod=Math.round(F.mesh_lod),F.texture_lod=Math.round(F.texture_lod),F.mesh_lod>=0&&this.loadProgressiveMeshes(s,F.mesh_lod);let i=F.texture_lod;if(s.material&&i>=0){const u=s["DEBUG:LOD"];u!=null&&(i=u),this.loadProgressiveTextures(s.material,i)}for(const u of Y)(l=u.onAfterUpdatedLOD)==null||l.call(u,this.renderer,e,t,s,F);r.lastLodLevel_Mesh=F.mesh_lod,r.lastLodLevel_Texture=F.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const o of e)this.loadProgressiveTextures(o,t);return}let s=!1;(e[J]===void 0||t<e[J])&&(s=!0),s&&(e[J]=t,O.assignTextureLOD(e,t).then(o=>{this._lodchangedlisteners.forEach(r=>r({type:"texture",level:t,object:e}))}))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e[J]!==t){e[J]=t;const s=e.geometry;return O.assignMeshLOD(e,t).then(o=>(o&&e[J]==t&&s!=e.geometry&&this._lodchangedlisteners.forEach(r=>r({type:"mesh",level:t,object:e})),o))}return Promise.resolve(null)}static isInside(e,t){const s=e.min,o=e.max,r=(s.x+o.x)*.5,i=(s.y+o.y)*.5;return this._tempPtInside.set(r,i,s.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,s,o,r){var V;if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}let a=10+1,l=!1;if(G&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const u=O.getMeshLODInformation(t.geometry),c=u==null?void 0:u.lods,g=c&&c.length>0,y=O.getMaterialMinMaxLODsCount(t.material),D=(y==null?void 0:y.min_count)!=1/0&&y.min_count>0&&y.max_count>0;if(!g&&!D){r.mesh_lod=0,r.texture_lod=0;return}g||(l=!0,a=0);const v=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let M=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const w=t;if(!w.boundingBox)w.computeBoundingBox();else if(s.frames%30===0){const h=te(w),k=w.geometry;h&&(w.geometry=h),w.computeBoundingBox(),w.geometry=k}M=w.boundingBox}if(M&&e.isPerspectiveCamera){const w=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const f=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(f)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(M),this._tempBox.applyMatrix4(t.matrixWorld),C.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&w.fov>70){const f=this._tempBox.min,m=this._tempBox.max;let S=f.x,T=f.y,P=m.x,X=m.y;const le=2,pe=1.5,ce=(f.x+m.x)*.5,ue=(f.y+m.y)*.5;S=(S-ce)*le+ce,T=(T-ue)*le+ue,P=(P-ce)*le+ce,X=(X-ue)*le+ue;const $e=S<0&&P>0?0:Math.min(Math.abs(f.x),Math.abs(m.x)),Ne=T<0&&X>0?0:Math.min(Math.abs(f.y),Math.abs(m.y)),ye=Math.max($e,Ne);s.lastCentrality=(pe-ye)*(pe-ye)*(pe-ye)}else s.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&v>0&&h.multiplyScalar(v/screen.availHeight),h.x*=w.aspect;const k=e.matrixWorldInverse,$=this._tempBox2;$.copy(M),$.applyMatrix4(t.matrixWorld),$.applyMatrix4(k);const I=$.getSize(this._tempBox2Size),b=Math.max(I.x,I.y);if(Math.max(h.x,h.y)!=0&&b!=0&&(h.z=I.z/Math.max(I.x,I.y)*Math.max(h.x,h.y)),s.lastScreenCoverage=Math.max(h.x,h.y,h.z),s.lastScreenspaceVolume.copy(h),s.lastScreenCoverage*=s.lastCentrality,G&&C.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const m=C.corner0,S=C.corner1,T=C.corner2,P=C.corner3;m.copy(this._tempBox.min),S.copy(this._tempBox.max),S.x=m.x,T.copy(this._tempBox.max),T.y=m.y,P.copy(this._tempBox.max);const X=(m.z+P.z)*.5;m.z=S.z=T.z=P.z=X,m.applyMatrix4(f),S.applyMatrix4(f),T.applyMatrix4(f),P.applyMatrix4(f),C.debugDrawLine(m,S,255),C.debugDrawLine(m,T,255),C.debugDrawLine(S,P,255),C.debugDrawLine(T,P,255)}let A=999;if(c&&s.lastScreenCoverage>0){for(let f=0;f<c.length;f++)if(c[f].density/s.lastScreenCoverage<o){A=f;break}}A<a&&(a=A,l=!0)}if(l?r.mesh_lod=a:r.mesh_lod=s.lastLodLevel_Mesh,G&&r.mesh_lod!=s.lastLodLevel_Mesh){const h=c==null?void 0:c[r.mesh_lod];h&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (${h.density.toFixed(0)}) - ${t.name}`)}if(D){const w="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=y.max_count-1,G){const h=y.lods[y.max_count-1];G&&console.log(`First Texture LOD ${r.texture_lod} (${h.max_height}px) - ${t.name}`)}}else{const h=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let k=s.lastScreenCoverage*4;((V=this.context)==null?void 0:V.engine)==="model-viewer"&&(k*=1.5);const I=v/window.devicePixelRatio*k;for(let b=y.lods.length-1;b>=0;b--){let q=y.lods[b];if(!(w&&q.max_height>=2048)&&!(et()&&q.max_height>4096)&&q.max_height>I){if(r.texture_lod=b,r.texture_lod<s.lastLodLevel_Texture){const A=q.max_height;G&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${A}px
|
|
5
|
+
`,t.uuid),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.mipmaps||(t.generateMipmaps=e.generateMipmaps),t}};let O=_;d(O,"registerTexture",(e,t,s,o,r)=>{if(x&&console.log("> Progressive: register texture",o,t.name,t.uuid,t,r),!t){x&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[me]=r);const i=r.guid;_.assignLODInformation(e,t,i,s,o,void 0),_.lodInfos.set(i,r),_.lowresCache.set(i,t)}),d(O,"registerMesh",(e,t,s,o,r,i)=>{var u;x&&console.log("> Progressive: register mesh",r,s.name,i,s.uuid,s);const a=s.geometry;if(!a){x&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),_.assignLODInformation(e,a,t,o,r,i.density),_.lodInfos.set(t,i);let l=_.lowresCache.get(t);l?l.push(s.geometry):l=[s.geometry],_.lowresCache.set(t,l),o>0&&!te(s)&&Ie(s,a);for(const c of Y)(u=c.onRegisteredNewMesh)==null||u.call(c,s,i)}),d(O,"lodInfos",new Map),d(O,"previouslyLoaded",new Map),d(O,"lowresCache",new Map);class rt{constructor(e,t,s,o,r){d(this,"url");d(this,"key");d(this,"level");d(this,"index");d(this,"density");this.url=e,this.key=t,this.level=s,o!=null&&(this.index=o),r!=null&&(this.density=r)}}const G=ae("debugprogressive"),it=ae("noprogressive"),xe=Symbol("Needle:LODSManager"),Me=Symbol("Needle:LODState"),J=Symbol("Needle:CurrentLOD"),F={mesh_lod:-1,texture_lod:-1};var B,W,he,Q,Z,ge,q;const C=class{constructor(e,t){d(this,"context");d(this,"renderer");d(this,"projectionScreenMatrix",new p.Matrix4);d(this,"targetTriangleDensity",2e5);d(this,"updateInterval","auto");K(this,B,1);d(this,"pause",!1);d(this,"manual",!1);d(this,"_lodchangedlisteners",[]);K(this,W,void 0);K(this,he,new p.Clock);K(this,Q,0);K(this,Z,0);K(this,ge,0);K(this,q,0);d(this,"_fpsBuffer",[60,60,60,60,60]);d(this,"_sphere",new p.Sphere);d(this,"_tempBox",new p.Box3);d(this,"_tempBox2",new p.Box3);d(this,"tempMatrix",new p.Matrix4);d(this,"_tempWorldPosition",new p.Vector3);d(this,"_tempBoxSize",new p.Vector3);d(this,"_tempBox2Size",new p.Vector3);this.renderer=e,this.context={...t}}static getObjectLODState(e){return e[Me]}static addPlugin(e){Y.push(e)}static removePlugin(e){const t=Y.indexOf(e);t>=0&&Y.splice(t,1)}static get(e,t){if(e[xe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),e[xe];const s=new C(e,{engine:"unknown",...t});return e[xe]=s,s}get plugins(){return Y}addEventListener(e,t){e==="changed"&&this._lodchangedlisteners.push(t)}removeEventListener(e,t){if(e==="changed"){const s=this._lodchangedlisteners.indexOf(t);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(m(this,W))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let e=0;N(this,W,this.renderer.render);const t=this;Se(this.renderer),this.renderer.render=function(s,o){const r=t.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(e=0,N(t,Q,m(t,Q)+1),N(t,Z,m(t,he).getDelta()),N(t,ge,m(t,ge)+m(t,Z)),t._fpsBuffer.shift(),t._fpsBuffer.push(1/m(t,Z)),N(t,q,t._fpsBuffer.reduce((a,l)=>a+l)/t._fpsBuffer.length),G&&m(t,Q)%200===0&&console.log("FPS",Math.round(m(t,q)),"Interval:",m(t,B)));const i=e++;m(t,W).call(this,s,o),t.onAfterRender(s,o,i)}}disable(){m(this,W)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=m(this,W),N(this,W,void 0))}update(e,t){this.internalUpdate(e,t)}onAfterRender(e,t,s){if(this.pause)return;const r=this.renderer.renderLists.get(e,0).opaque;let i=!0;if(r.length===1){const a=r[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(i=!1)}if((t.parent&&t.parent.type==="CubeCamera"||s>=1&&t.type==="OrthographicCamera")&&(i=!1),i){if(it||(this.updateInterval==="auto"?m(this,q)<40&&m(this,B)<10?(N(this,B,m(this,B)+1),G&&console.warn("↓ Reducing LOD updates",m(this,B),m(this,q).toFixed(0))):m(this,q)>=60&&m(this,B)>1&&(N(this,B,m(this,B)-1),G&&console.warn("↑ Increasing LOD updates",m(this,B),m(this,q).toFixed(0))):N(this,B,this.updateInterval),m(this,B)>0&&m(this,Q)%m(this,B)!=0))return;this.internalUpdate(e,t)}}internalUpdate(e,t){var l,u;const s=this.renderer.renderLists.get(e,0),o=s.opaque;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse);const r=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 y=Math.random()*16777215,D=new p.MeshStandardMaterial({color:y});c.object.material=D}const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}const i=s.transparent;for(const c of i){const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}const a=s.transmissive;for(const c of a){const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}}updateLODs(e,t,s,o){var a,l;s.userData||(s.userData={});let r=s[Me];if(r||(r=new ot,s[Me]=r),r.frames++<2)return;for(const u of Y)(a=u.onBeforeUpdateLOD)==null||a.call(u,this.renderer,e,t,s);this.calculateLodLevel(t,s,r,o,F),F.mesh_lod=Math.round(F.mesh_lod),F.texture_lod=Math.round(F.texture_lod),F.mesh_lod>=0&&this.loadProgressiveMeshes(s,F.mesh_lod);let i=F.texture_lod;if(s.material&&i>=0){const u=s["DEBUG:LOD"];u!=null&&(i=u),this.loadProgressiveTextures(s.material,i)}for(const u of Y)(l=u.onAfterUpdatedLOD)==null||l.call(u,this.renderer,e,t,s,F);r.lastLodLevel_Mesh=F.mesh_lod,r.lastLodLevel_Texture=F.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const o of e)this.loadProgressiveTextures(o,t);return}let s=!1;(e[J]===void 0||t<e[J])&&(s=!0),s&&(e[J]=t,O.assignTextureLOD(e,t).then(o=>{this._lodchangedlisteners.forEach(r=>r({type:"texture",level:t,object:e}))}))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e[J]!==t){e[J]=t;const s=e.geometry;return O.assignMeshLOD(e,t).then(o=>(o&&e[J]==t&&s!=e.geometry&&this._lodchangedlisteners.forEach(r=>r({type:"mesh",level:t,object:e})),o))}return Promise.resolve(null)}static isInside(e,t){const s=e.min,o=e.max,r=(s.x+o.x)*.5,i=(s.y+o.y)*.5;return this._tempPtInside.set(r,i,s.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,s,o,r){var V;if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}let a=10+1,l=!1;if(G&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const u=O.getMeshLODInformation(t.geometry),c=u==null?void 0:u.lods,g=c&&c.length>0,y=O.getMaterialMinMaxLODsCount(t.material),D=(y==null?void 0:y.min_count)!=1/0&&y.min_count>0&&y.max_count>0;if(!g&&!D){r.mesh_lod=0,r.texture_lod=0;return}g||(l=!0,a=0);const v=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let M=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const w=t;if(!w.boundingBox)w.computeBoundingBox();else if(s.frames%30===0){const h=te(w),k=w.geometry;h&&(w.geometry=h),w.computeBoundingBox(),w.geometry=k}M=w.boundingBox}if(M&&e.isPerspectiveCamera){const w=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const f=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(f)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(M),this._tempBox.applyMatrix4(t.matrixWorld),C.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&w.fov>70){const f=this._tempBox.min,L=this._tempBox.max;let S=f.x,A=f.y,P=L.x,X=L.y;const le=2,pe=1.5,ce=(f.x+L.x)*.5,ue=(f.y+L.y)*.5;S=(S-ce)*le+ce,A=(A-ue)*le+ue,P=(P-ce)*le+ce,X=(X-ue)*le+ue;const $e=S<0&&P>0?0:Math.min(Math.abs(f.x),Math.abs(L.x)),Ne=A<0&&X>0?0:Math.min(Math.abs(f.y),Math.abs(L.y)),ye=Math.max($e,Ne);s.lastCentrality=(pe-ye)*(pe-ye)*(pe-ye)}else s.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&v>0&&h.multiplyScalar(v/screen.availHeight),h.x*=w.aspect;const k=e.matrixWorldInverse,$=this._tempBox2;$.copy(M),$.applyMatrix4(t.matrixWorld),$.applyMatrix4(k);const I=$.getSize(this._tempBox2Size),E=Math.max(I.x,I.y);if(Math.max(h.x,h.y)!=0&&E!=0&&(h.z=I.z/Math.max(I.x,I.y)*Math.max(h.x,h.y)),s.lastScreenCoverage=Math.max(h.x,h.y,h.z),s.lastScreenspaceVolume.copy(h),s.lastScreenCoverage*=s.lastCentrality,G&&C.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const L=C.corner0,S=C.corner1,A=C.corner2,P=C.corner3;L.copy(this._tempBox.min),S.copy(this._tempBox.max),S.x=L.x,A.copy(this._tempBox.max),A.y=L.y,P.copy(this._tempBox.max);const X=(L.z+P.z)*.5;L.z=S.z=A.z=P.z=X,L.applyMatrix4(f),S.applyMatrix4(f),A.applyMatrix4(f),P.applyMatrix4(f),C.debugDrawLine(L,S,255),C.debugDrawLine(L,A,255),C.debugDrawLine(S,P,255),C.debugDrawLine(A,P,255)}let b=999;if(c&&s.lastScreenCoverage>0){for(let f=0;f<c.length;f++)if(c[f].density/s.lastScreenCoverage<o){b=f;break}}b<a&&(a=b,l=!0)}if(l?r.mesh_lod=a:r.mesh_lod=s.lastLodLevel_Mesh,G&&r.mesh_lod!=s.lastLodLevel_Mesh){const h=c==null?void 0:c[r.mesh_lod];h&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (${h.density.toFixed(0)}) - ${t.name}`)}if(D){const w="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=y.max_count-1,G){const h=y.lods[y.max_count-1];G&&console.log(`First Texture LOD ${r.texture_lod} (${h.max_height}px) - ${t.name}`)}}else{const h=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let k=s.lastScreenCoverage*4;((V=this.context)==null?void 0:V.engine)==="model-viewer"&&(k*=1.5);const I=v/window.devicePixelRatio*k;let E=!1;for(let z=y.lods.length-1;z>=0;z--){let b=y.lods[z];if(!(w&&b.max_height>=2048)&&!(et()&&b.max_height>4096)&&(b.max_height>I||!E&&z===0)){if(E=!0,r.texture_lod=z,r.texture_lod<s.lastLodLevel_Texture){const T=b.max_height;G&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${T}px
|
|
6
6
|
Screensize: ${I.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${h.toFixed(1)}
|
|
7
|
-
${t.name}`)}break}}}}else r.texture_lod=0}};let R=C;B=new WeakMap,
|
|
7
|
+
${t.name}`)}break}}}}else r.texture_lod=0}};let R=C;B=new WeakMap,W=new WeakMap,he=new WeakMap,Q=new WeakMap,Z=new WeakMap,ge=new WeakMap,q=new WeakMap,d(R,"debugDrawLine"),d(R,"corner0",new p.Vector3),d(R,"corner1",new p.Vector3),d(R,"corner2",new p.Vector3),d(R,"corner3",new p.Vector3),d(R,"_tempPtInside",new p.Vector3);class ot{constructor(){d(this,"frames",0);d(this,"lastLodLevel_Mesh",-1);d(this,"lastLodLevel_Texture",-1);d(this,"lastScreenCoverage",0);d(this,"lastScreenspaceVolume",new p.Vector3);d(this,"lastCentrality",0)}}const Ce=Symbol("NEEDLE_mesh_lod"),fe=Symbol("NEEDLE_texture_lod");let ie=null;function Ae(){const n=nt();n&&(n.mapURLs(function(e){return Be(),e}),Be(),ie==null||ie.disconnect(),ie=new MutationObserver(e=>{e.forEach(t=>{t.addedNodes.forEach(s=>{s instanceof HTMLElement&&s.tagName.toLowerCase()==="model-viewer"&&Fe(s)})})}),ie.observe(document,{childList:!0,subtree:!0}))}function nt(){if(typeof customElements>"u")return null;const n=customElements.get("model-viewer");return n||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ae()}),null)}function Be(){if(typeof document>"u")return;document.querySelectorAll("model-viewer").forEach(e=>{Fe(e)})}const Re=new WeakSet;let at=0;function Fe(n){if(!n||Re.has(n))return null;Re.add(n),console.debug("[gltf-progressive] found new model-viewer..."+ ++at+`
|
|
8
8
|
`,n.getAttribute("src"));let e=null,t=null,s=null;for(let o=n;o!=null;o=Object.getPrototypeOf(o)){const r=Object.getOwnPropertySymbols(o),i=r.find(u=>u.toString()=="Symbol(renderer)"),a=r.find(u=>u.toString()=="Symbol(scene)"),l=r.find(u=>u.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=n[i].threeRenderer),!t&&a!=null&&(t=n[a]),!s&&l!=null&&(s=n[l])}if(e&&t){let o=function(){if(s){let i=0,a=setInterval(()=>{if(i++>5){clearInterval(a);return}s==null||s.call(n)},300)}};console.debug("[gltf-progressive] setup model-viewer");const r=R.get(e,{engine:"model-viewer"});return R.addPlugin(new lt),r.enable(),r.addEventListener("changed",()=>{s==null||s.call(n)}),n.addEventListener("model-visibility",i=>{i.detail.visible&&(s==null||s.call(n))}),n.addEventListener("load",()=>{o()}),()=>{r.disable()}}return null}class lt{constructor(){d(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,t,s,o){this.tryParseMeshLOD(t,o),this.tryParseTextureLOD(t,o)}getUrl(e){if(!e)return null;let t=e.getAttribute("src");return t||(t=e.src),t||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),t}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,t){if(t[fe]==!0)return;t[fe]=!0;const s=this.tryGetCurrentGLTF(e),o=this.tryGetCurrentModelViewer(e),r=this.getUrl(o);if(r&&s&&t.material){let i=function(l){var c,g,y;if(l[fe]==!0)return;l[fe]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let D=0;D<u.length;D++){const v=u[D],M=l[v];if((M==null?void 0:M.isTexture)===!0){const V=(g=(c=M.userData)==null?void 0:c.associations)==null?void 0:g.textures;if(V==null)continue;const w=s.parser.json.textures[V];if(!w){console.warn("Texture data not found for texture index "+V);continue}if((y=w==null?void 0:w.extensions)!=null&&y[U]){const h=w.extensions[U];h&&r&&O.registerTexture(r,M,h.lods.length,V,h)}}}};const a=t.material;if(Array.isArray(a))for(const l of a)i(l);else i(a)}}tryParseMeshLOD(e,t){var i,a;if(t[Ce]==!0)return;t[Ce]=!0;const s=this.tryGetCurrentModelViewer(e),o=this.getUrl(s);if(!o)return;const r=(a=(i=t.userData)==null?void 0:i.gltfExtensions)==null?void 0:a[U];if(r&&o){const l=t.uuid;O.registerMesh(o,l,t,0,r.lods.length,r)}}}function Ve(n,e,t,s){Se(e),be(t),Te(t,{progressive:!0,...s==null?void 0:s.hints}),t.register(r=>new O(r,n));const o=R.get(e);return(s==null?void 0:s.enableLODsManager)!==!1&&o.enable(),o}Ae();if(!tt){const n={gltfProgressive:{useNeedleProgressive:Ve,LODsManager:R,configureLoader:Te,getRaycastMesh:te,useRaycastMeshes:Ge}};if(!globalThis.Needle)globalThis.Needle=n;else for(const e in n)globalThis.Needle[e]=n[e]}exports.EXTENSION_NAME=U;exports.LODsManager=R;exports.NEEDLE_progressive=O;exports.VERSION=Oe;exports.addDracoAndKTX2Loaders=be;exports.configureLoader=Te;exports.createLoaders=Se;exports.getRaycastMesh=te;exports.patchModelViewer=Ae;exports.registerRaycastMesh=Ie;exports.setDracoDecoderLocation=je;exports.setKTX2TranscoderLocation=Je;exports.useNeedleProgressive=Ve;exports.useRaycastMeshes=Ge;
|
package/lib/lods_manager.js
CHANGED
|
@@ -618,6 +618,7 @@ export class LODsManager {
|
|
|
618
618
|
}
|
|
619
619
|
const screenSize = canvasHeight / window.devicePixelRatio;
|
|
620
620
|
const pixelSizeOnScreen = screenSize * factor;
|
|
621
|
+
let foundLod = false;
|
|
621
622
|
for (let i = texture_lods_minmax.lods.length - 1; i >= 0; i--) {
|
|
622
623
|
let lod = texture_lods_minmax.lods[i];
|
|
623
624
|
if (saveDataEnabled && lod.max_height >= 2048) {
|
|
@@ -625,7 +626,8 @@ export class LODsManager {
|
|
|
625
626
|
}
|
|
626
627
|
if (isMobileDevice() && lod.max_height > 4096)
|
|
627
628
|
continue; // skip 8k textures on mobile devices (for now)
|
|
628
|
-
if (lod.max_height > pixelSizeOnScreen) {
|
|
629
|
+
if (lod.max_height > pixelSizeOnScreen || (!foundLod && i === 0)) {
|
|
630
|
+
foundLod = true;
|
|
629
631
|
result.texture_lod = i;
|
|
630
632
|
if (result.texture_lod < state.lastLodLevel_Texture) {
|
|
631
633
|
const lod_pixel_height = lod.max_height;
|
package/lib/version.js
CHANGED
package/package.json
CHANGED