@needle-tools/gltf-progressive 2.1.0-alpha.4 → 2.1.0-alpha.5
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 +52 -52
- package/gltf-progressive.min.js +6 -6
- package/gltf-progressive.umd.cjs +5 -5
- package/lib/lods_manager.js +10 -4
- 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.5] - 2025-01-30
|
|
8
|
+
- Add: initial support for Orthographic cameras
|
|
9
|
+
|
|
7
10
|
## [2.1.0-alpha.4] - 2025-01-29
|
|
8
11
|
- Fix: LOD not loading if the max texture resolution is too small
|
|
9
12
|
|
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
|
|
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 Pe, 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";
|
|
@@ -142,7 +142,7 @@ if (L) {
|
|
|
142
142
|
}));
|
|
143
143
|
});
|
|
144
144
|
}
|
|
145
|
-
function
|
|
145
|
+
function Ee(o, e, t) {
|
|
146
146
|
var n;
|
|
147
147
|
if (!L)
|
|
148
148
|
return;
|
|
@@ -278,7 +278,7 @@ const v = class {
|
|
|
278
278
|
const a = r.index || 0;
|
|
279
279
|
i = i[a];
|
|
280
280
|
}
|
|
281
|
-
return e["LOD:requested level"] === t && (delete e["LOD:requested level"], i && n != i && ((i == null ? void 0 : i.isBufferGeometry) ? (e.geometry = i, L &&
|
|
281
|
+
return e["LOD:requested level"] === t && (delete e["LOD:requested level"], i && n != i && ((i == null ? void 0 : i.isBufferGeometry) ? (e.geometry = i, L && Ee(e, "geometry", r.url)) : L && console.error("Invalid LOD geometry", i))), i;
|
|
282
282
|
}).catch((i) => (console.error("Error loading mesh LOD", e, i), null));
|
|
283
283
|
} else
|
|
284
284
|
L && console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh", e);
|
|
@@ -355,7 +355,7 @@ const v = class {
|
|
|
355
355
|
}
|
|
356
356
|
if (L && n && s) {
|
|
357
357
|
const i = this.getAssignedLODInformation(e);
|
|
358
|
-
i &&
|
|
358
|
+
i && Ee(s, n, i.url);
|
|
359
359
|
}
|
|
360
360
|
}
|
|
361
361
|
return r;
|
|
@@ -413,9 +413,9 @@ const v = class {
|
|
|
413
413
|
}
|
|
414
414
|
if (i || (i = v.lodInfos.get(r)), i) {
|
|
415
415
|
if (t > 0) {
|
|
416
|
-
let
|
|
416
|
+
let D = !1;
|
|
417
417
|
const w = Array.isArray(i.lods);
|
|
418
|
-
if (w && t >= i.lods.length ?
|
|
418
|
+
if (w && t >= i.lods.length ? D = !0 : w || (D = !0), D)
|
|
419
419
|
return this.lowresCache.get(r);
|
|
420
420
|
}
|
|
421
421
|
const g = Array.isArray(i.lods) ? (a = i.lods[t]) == null ? void 0 : a.path : i.lods;
|
|
@@ -425,12 +425,12 @@ const v = class {
|
|
|
425
425
|
if (p.endsWith(".glb") || p.endsWith(".gltf")) {
|
|
426
426
|
if (!i.guid)
|
|
427
427
|
return console.warn("missing pointer for glb/gltf texture", i), null;
|
|
428
|
-
const
|
|
428
|
+
const D = p + "_" + i.guid, w = this.previouslyLoaded.get(D);
|
|
429
429
|
if (w !== void 0) {
|
|
430
|
-
s && console.log(`LOD ${t} was already loading/loaded: ${
|
|
430
|
+
s && console.log(`LOD ${t} was already loading/loaded: ${D}`);
|
|
431
431
|
let h = await w.catch((F) => (console.error(`Error loading LOD ${t} from ${p}
|
|
432
432
|
`, F), null)), R = !1;
|
|
433
|
-
if (h == null || (h instanceof se && e instanceof se ? (l = h.image) != null && l.data || (u = h.source) != null && u.data ? h = this.copySettings(e, h) : (R = !0, this.previouslyLoaded.delete(
|
|
433
|
+
if (h == null || (h instanceof se && e instanceof se ? (l = h.image) != null && l.data || (u = h.source) != null && u.data ? h = this.copySettings(e, h) : (R = !0, this.previouslyLoaded.delete(D)) : h instanceof ge && e instanceof ge && ((c = h.attributes.position) != null && c.array || (R = !0, this.previouslyLoaded.delete(D)))), !R)
|
|
434
434
|
return h;
|
|
435
435
|
}
|
|
436
436
|
const x = i, $ = new Promise(async (h, R) => {
|
|
@@ -462,7 +462,7 @@ const v = class {
|
|
|
462
462
|
}
|
|
463
463
|
if (b) {
|
|
464
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,
|
|
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, D), e instanceof se && (f = this.copySettings(e, f)), f && (f.guid = x.guid), h(f);
|
|
466
466
|
} else
|
|
467
467
|
L && console.warn("Could not find texture with guid", x.guid, A.parser.json);
|
|
468
468
|
}
|
|
@@ -480,15 +480,15 @@ const v = class {
|
|
|
480
480
|
}
|
|
481
481
|
if (b) {
|
|
482
482
|
const f = await N.getDependency("mesh", S), y = x;
|
|
483
|
-
if (s && console.log(`Loaded Mesh "${f.name}"`, p, S, f,
|
|
483
|
+
if (s && console.log(`Loaded Mesh "${f.name}"`, p, S, f, D), 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
488
|
for (let T = 0; T < f.children.length; T++) {
|
|
489
|
-
const
|
|
490
|
-
if (
|
|
491
|
-
const X =
|
|
489
|
+
const P = f.children[T];
|
|
490
|
+
if (P.isMesh === !0) {
|
|
491
|
+
const X = P.geometry;
|
|
492
492
|
v.assignLODInformation(n.url, X, r, t, T, y.density), O.push(X);
|
|
493
493
|
}
|
|
494
494
|
}
|
|
@@ -499,7 +499,7 @@ const v = class {
|
|
|
499
499
|
}
|
|
500
500
|
return h(null);
|
|
501
501
|
});
|
|
502
|
-
return this.previouslyLoaded.set(
|
|
502
|
+
return this.previouslyLoaded.set(D, $), await $;
|
|
503
503
|
} else if (e instanceof se) {
|
|
504
504
|
s && console.log("Load texture from uri: " + p);
|
|
505
505
|
const w = await new Ke().loadAsync(p);
|
|
@@ -574,7 +574,7 @@ class ut {
|
|
|
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
576
|
var C, W, ye, j, ee, me, q;
|
|
577
|
-
const
|
|
577
|
+
const E = class {
|
|
578
578
|
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
579
579
|
constructor(e, t) {
|
|
580
580
|
d(this, "context");
|
|
@@ -612,8 +612,8 @@ const P = class {
|
|
|
612
612
|
d(this, "_fpsBuffer", [60, 60, 60, 60, 60]);
|
|
613
613
|
// private testIfLODLevelsAreAvailable() {
|
|
614
614
|
d(this, "_sphere", new Je());
|
|
615
|
-
d(this, "_tempBox", new
|
|
616
|
-
d(this, "_tempBox2", new
|
|
615
|
+
d(this, "_tempBox", new Pe());
|
|
616
|
+
d(this, "_tempBox2", new Pe());
|
|
617
617
|
d(this, "tempMatrix", new Ae());
|
|
618
618
|
d(this, "_tempWorldPosition", new z());
|
|
619
619
|
d(this, "_tempBoxSize", new z());
|
|
@@ -639,7 +639,7 @@ const P = class {
|
|
|
639
639
|
static get(e, t) {
|
|
640
640
|
if (e[we])
|
|
641
641
|
return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), e[we];
|
|
642
|
-
const s = new
|
|
642
|
+
const s = new E(e, {
|
|
643
643
|
engine: "unknown",
|
|
644
644
|
...t
|
|
645
645
|
});
|
|
@@ -720,8 +720,8 @@ const P = class {
|
|
|
720
720
|
}
|
|
721
721
|
if (I === "color" && c.material && !c.object.progressive_debug_color) {
|
|
722
722
|
c.object.progressive_debug_color = !0;
|
|
723
|
-
const p = Math.random() * 16777215,
|
|
724
|
-
c.object.material =
|
|
723
|
+
const p = Math.random() * 16777215, D = new He({ color: p });
|
|
724
|
+
c.object.material = D;
|
|
725
725
|
}
|
|
726
726
|
const g = c.object;
|
|
727
727
|
(g instanceof Q || g.isMesh) && this.updateLODs(e, t, g, r);
|
|
@@ -807,8 +807,8 @@ const P = class {
|
|
|
807
807
|
let a = 10 + 1, l = !1;
|
|
808
808
|
if (I && t["DEBUG:LOD"] != null)
|
|
809
809
|
return t["DEBUG:LOD"];
|
|
810
|
-
const u = _.getMeshLODInformation(t.geometry), c = u == null ? void 0 : u.lods, g = c && c.length > 0, p = _.getMaterialMinMaxLODsCount(t.material),
|
|
811
|
-
if (!g && !
|
|
810
|
+
const u = _.getMeshLODInformation(t.geometry), c = u == null ? void 0 : u.lods, g = c && c.length > 0, p = _.getMaterialMinMaxLODsCount(t.material), D = (p == null ? void 0 : p.min_count) != 1 / 0 && p.min_count > 0 && p.max_count > 0;
|
|
811
|
+
if (!g && !D) {
|
|
812
812
|
r.mesh_lod = 0, r.texture_lod = 0;
|
|
813
813
|
return;
|
|
814
814
|
}
|
|
@@ -816,17 +816,17 @@ const P = class {
|
|
|
816
816
|
const w = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
|
|
817
817
|
let x = t.geometry.boundingBox;
|
|
818
818
|
if (t.type === "SkinnedMesh") {
|
|
819
|
-
const
|
|
820
|
-
if (!
|
|
821
|
-
|
|
819
|
+
const M = t;
|
|
820
|
+
if (!M.boundingBox)
|
|
821
|
+
M.computeBoundingBox();
|
|
822
822
|
else if (s.frames % 30 === 0) {
|
|
823
|
-
const h = ce(
|
|
824
|
-
h && (
|
|
823
|
+
const h = ce(M), R = M.geometry;
|
|
824
|
+
h && (M.geometry = h), M.computeBoundingBox(), M.geometry = R;
|
|
825
825
|
}
|
|
826
|
-
x =
|
|
826
|
+
x = M.boundingBox;
|
|
827
827
|
}
|
|
828
|
-
if (x
|
|
829
|
-
const
|
|
828
|
+
if (x) {
|
|
829
|
+
const M = e;
|
|
830
830
|
if (t.geometry.attributes.color && t.geometry.attributes.color.count < 100 && t.geometry.boundingSphere) {
|
|
831
831
|
this._sphere.copy(t.geometry.boundingSphere), this._sphere.applyMatrix4(t.matrixWorld);
|
|
832
832
|
const f = e.getWorldPosition(this._tempWorldPosition);
|
|
@@ -835,31 +835,31 @@ const P = class {
|
|
|
835
835
|
return;
|
|
836
836
|
}
|
|
837
837
|
}
|
|
838
|
-
if (this._tempBox.copy(x), this._tempBox.applyMatrix4(t.matrixWorld),
|
|
838
|
+
if (this._tempBox.copy(x), this._tempBox.applyMatrix4(t.matrixWorld), M.isPerspectiveCamera && E.isInside(this._tempBox, this.projectionScreenMatrix)) {
|
|
839
839
|
r.mesh_lod = 0, r.texture_lod = 0;
|
|
840
840
|
return;
|
|
841
841
|
}
|
|
842
|
-
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled &&
|
|
842
|
+
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && M.isPerspectiveCamera && M.fov > 70) {
|
|
843
843
|
const f = this._tempBox.min, y = this._tempBox.max;
|
|
844
|
-
let O = f.x, T = f.y,
|
|
844
|
+
let O = f.x, T = f.y, P = 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, T = (T - de) * ue + de,
|
|
847
|
-
const ze = O < 0 &&
|
|
846
|
+
O = (O - fe) * ue + fe, T = (T - de) * ue + de, P = (P - fe) * ue + fe, X = (X - de) * ue + de;
|
|
847
|
+
const ze = O < 0 && P > 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;
|
|
851
851
|
const h = this._tempBox.getSize(this._tempBoxSize);
|
|
852
|
-
h.multiplyScalar(0.5), screen.availHeight > 0 && w > 0 && h.multiplyScalar(w / screen.availHeight), h.x *=
|
|
852
|
+
h.multiplyScalar(0.5), screen.availHeight > 0 && w > 0 && h.multiplyScalar(w / screen.availHeight), e.isPerspectiveCamera ? h.x *= e.aspect : e.isOrthographicCamera;
|
|
853
853
|
const R = e.matrixWorldInverse, F = this._tempBox2;
|
|
854
854
|
F.copy(x), F.applyMatrix4(t.matrixWorld), F.applyMatrix4(R);
|
|
855
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 &&
|
|
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 && E.debugDrawLine) {
|
|
857
857
|
const f = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
858
858
|
f.invert();
|
|
859
|
-
const y =
|
|
860
|
-
y.copy(this._tempBox.min), O.copy(this._tempBox.max), O.x = y.x, T.copy(this._tempBox.max), T.y = y.y,
|
|
861
|
-
const X = (y.z +
|
|
862
|
-
y.z = O.z = T.z =
|
|
859
|
+
const y = E.corner0, O = E.corner1, T = E.corner2, P = E.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, P.copy(this._tempBox.max);
|
|
861
|
+
const X = (y.z + P.z) * 0.5;
|
|
862
|
+
y.z = O.z = T.z = P.z = X, y.applyMatrix4(f), O.applyMatrix4(f), T.applyMatrix4(f), P.applyMatrix4(f), E.debugDrawLine(y, O, 255), E.debugDrawLine(y, T, 255), E.debugDrawLine(O, P, 255), E.debugDrawLine(T, P, 255);
|
|
863
863
|
}
|
|
864
864
|
let S = 999;
|
|
865
865
|
if (c && s.lastScreenCoverage > 0) {
|
|
@@ -875,8 +875,8 @@ const P = class {
|
|
|
875
875
|
const h = c == null ? void 0 : c[r.mesh_lod];
|
|
876
876
|
h && console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (${h.density.toFixed(0)}) - ${t.name}`);
|
|
877
877
|
}
|
|
878
|
-
if (
|
|
879
|
-
const
|
|
878
|
+
if (D) {
|
|
879
|
+
const M = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
|
|
880
880
|
if (s.lastLodLevel_Texture < 0) {
|
|
881
881
|
if (r.texture_lod = p.max_count - 1, I) {
|
|
882
882
|
const h = p.lods[p.max_count - 1];
|
|
@@ -890,7 +890,7 @@ const P = class {
|
|
|
890
890
|
let A = !1;
|
|
891
891
|
for (let N = p.lods.length - 1; N >= 0; N--) {
|
|
892
892
|
let S = p.lods[N];
|
|
893
|
-
if (!(
|
|
893
|
+
if (!(M && S.max_height >= 2048) && !(nt() && S.max_height > 4096) && (S.max_height > k || !A && N === 0)) {
|
|
894
894
|
if (A = !0, r.texture_lod = N, r.texture_lod < s.lastLodLevel_Texture) {
|
|
895
895
|
const b = S.max_height;
|
|
896
896
|
I && console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${b}px
|
|
@@ -905,7 +905,7 @@ ${t.name}`);
|
|
|
905
905
|
r.texture_lod = 0;
|
|
906
906
|
}
|
|
907
907
|
};
|
|
908
|
-
let B =
|
|
908
|
+
let B = E;
|
|
909
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.
|
|
910
910
|
*/
|
|
911
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());
|
|
@@ -1017,19 +1017,19 @@ class pt {
|
|
|
1017
1017
|
return;
|
|
1018
1018
|
l[he] = !0, l.userData && (l.userData.LOD = -1);
|
|
1019
1019
|
const u = Object.keys(l);
|
|
1020
|
-
for (let
|
|
1021
|
-
const w = u[
|
|
1020
|
+
for (let D = 0; D < u.length; D++) {
|
|
1021
|
+
const w = u[D], x = l[w];
|
|
1022
1022
|
if ((x == null ? void 0 : x.isTexture) === !0) {
|
|
1023
1023
|
const $ = (g = (c = x.userData) == null ? void 0 : c.associations) == null ? void 0 : g.textures;
|
|
1024
1024
|
if ($ == null)
|
|
1025
1025
|
continue;
|
|
1026
|
-
const
|
|
1027
|
-
if (!
|
|
1026
|
+
const M = s.parser.json.textures[$];
|
|
1027
|
+
if (!M) {
|
|
1028
1028
|
console.warn("Texture data not found for texture index " + $);
|
|
1029
1029
|
continue;
|
|
1030
1030
|
}
|
|
1031
|
-
if ((p =
|
|
1032
|
-
const h =
|
|
1031
|
+
if ((p = M == null ? void 0 : M.extensions) != null && p[V]) {
|
|
1032
|
+
const h = M.extensions[V];
|
|
1033
1033
|
h && r && _.registerTexture(r, x, h.lods.length, $, h);
|
|
1034
1034
|
}
|
|
1035
1035
|
}
|
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 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(
|
|
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,
|
|
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)},x=(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(()=>{Pe()});function st(t){Y=t}function rt(t){te=t}let X,ue,H;function Pe(){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 ve(t){return Pe(),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 ye(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 Ie=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,Ie?.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",L=se("debugprogressive"),De=Symbol("needle-progressive-texture"),ne=new Map,we=new Set;if(L){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 Ce(t,e,s){var o;if(!L)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}),L&&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(L==="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,L&&Ce(t,"geometry",r.url)):L&&console.error("Invalid LOD geometry",n))),n}).catch(n=>(console.error("Error loading mesh LOD",t,n),null))}else L&&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(L&&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 L==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,s,n,r),null}s[o]=r}if(L&&o&&s){const n=this.getAssignedLODInformation(t);n&&Ce(s,o,n.url)}}return r}else L=="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 L&&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){L&&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=L=="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 v=!1;const A=Array.isArray(a.lods);if(A&&e>=a.lods.length?v=!0:A||(v=!0),v)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 L&&!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 v=g+"_"+a.guid,A=this.previouslyLoaded.get(v);if(A!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${v}`);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(v)):d instanceof le&&t instanceof le&&((n=d.attributes.position)!=null&&n.array||(O=!0,this.previouslyLoaded.delete(v)))),!O)return d}const D=a,y=new Promise(async(d,O)=>{const b=new me;ye(b),L&&(await new Promise(p=>setTimeout(p,1e3)),i&&console.warn("Start loading (delayed) "+g,D.guid));let I=g;if(D&&Array.isArray(D.lods)){const p=D.lods[e];p.hash&&(I+="?v="+p.hash)}const _=await b.loadAsync(I).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,v),t instanceof ee&&(h=this.copySettings(t,h)),h&&(h.guid=D.guid),d(h)}else L&&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,v),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 L&&console.warn("Could not find mesh with guid",D.guid,_.parser.json)}return d(null)});return this.previouslyLoaded.set(v,y),await y}else if(t instanceof ee){i&&console.log("Load texture from uri: "+g);const v=await new qe().loadAsync(g);return v?(v.guid=a.guid,v.flipY=!1,v.needsUpdate=!0,v.colorSpace=t.colorSpace,i&&console.log(a,v)):L&&console.warn("failed loading",g),v}}else L&&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(),L&&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 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
|
|
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(L&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,r),!e){L&&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;L&&console.log("> Progressive: register mesh",r,s.name,n,s.uuid,s);const l=s.geometry;if(!l){L&&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"),C={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 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 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(x(this,F))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;G(this,F,this.renderer.render);const e=this;ve(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,x(e,Z)+1),G(e,oe,x(e,_e).getDelta()),G(e,de,x(e,de)+x(e,oe)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/x(e,oe)),G(e,U,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),B&&x(e,Z)%200===0&&console.log("FPS",Math.round(x(e,U)),"Interval:",x(e,E)));const n=t++;x(e,F).call(this,s,o),e.onAfterRender(s,o,n)}}disable(){x(this,F)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=x(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"?x(this,U)<40&&x(this,E)<10?(G(this,E,x(this,E)+1),B&&console.warn("\u2193 Reducing LOD updates",x(this,E),x(this,U).toFixed(0))):x(this,U)>=60&&x(this,E)>1&&(G(this,E,x(this,E)-1),B&&console.warn("\u2191 Increasing LOD updates",x(this,E),x(this,U).toFixed(0))):G(this,E,this.updateInterval),x(this,E)>0&&x(this,Z)%x(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,v=new He({color:g});a.object.material=v}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,C),C.mesh_lod=Math.round(C.mesh_lod),C.texture_lod=Math.round(C.texture_lod),C.mesh_lod>=0&&this.loadProgressiveMeshes(s,C.mesh_lod);let l=C.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,C);i.lastLodLevel_Mesh=C.mesh_lod,i.lastLodLevel_Texture=C.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),v=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!f&&!v){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 y=e;if(!y.boundingBox)y.computeBoundingBox();else if(s.frames%30===0){const d=J(y),O=y.geometry;d&&(y.geometry=d),y.computeBoundingBox(),y.geometry=O}D=y.boundingBox}if(D){const y=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),y.isPerspectiveCamera&&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&&y.isPerspectiveCamera&&y.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),t.isPerspectiveCamera?d.x*=t.aspect:t.isOrthographicCamera;const O=t.matrixWorldInverse,b=this._tempBox2;b.copy(D),b.applyMatrix4(e.matrixWorld),b.applyMatrix4(O);const I=b.getSize(this._tempBox2Size),_=Math.max(I.x,I.y);if(Math.max(d.x,d.y)!=0&&_!=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,B&&P.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const p=P.corner0,h=P.corner1,M=P.corner2,S=P.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),P.debugDrawLine(p,h,255),P.debugDrawLine(p,M,255),P.debugDrawLine(h,S,255),P.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 y=a?.[r.mesh_lod];y&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} \u2192 ${r.mesh_lod} (${y.density.toFixed(0)}) - ${e.name}`)}if(v){const y="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 I=!1;for(let _=g.lods.length-1;_>=0;_--){let k=g.lods[_];if(!(y&&k.max_height>=2048)&&!(it()&&k.max_height>4096)&&(k.max_height>b||!I&&_===0)){if(I=!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 R=P;E=new WeakMap,F=new WeakMap,_e=new WeakMap,Z=new WeakMap,oe=new WeakMap,de=new WeakMap,U=new WeakMap,c(R,"debugDrawLine"),c(R,"corner0",new W),c(R,"corner1",new W),c(R,"corner2",new W),c(R,"corner3",new W),c(R,"_tempPtInside",new W);class 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 Re=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=R.get(e,{engine:"model-viewer"});return R.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 v=Object.keys(u);for(let A=0;A<v.length;A++){const D=v[A],y=u[D];if(y?.isTexture===!0){const d=(f=(a=y.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,y,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[Re]==!0)return;s[Re]=!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){ve(e),ye(s),Le(s,{progressive:!0,...o?.hints}),s.register(n=>new T(n,t));const r=R.get(e);return o?.enableLODsManager!==!1&&r.enable(),r}if(Se(),!at){const t={gltfProgressive:{useNeedleProgressive:We,LODsManager:R,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,R as LODsManager,T as NEEDLE_progressive,pe as VERSION,ye as addDracoAndKTX2Loaders,Le as configureLoader,ve 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 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(
|
|
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
|
|
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 w=!1;const v=Array.isArray(i.lods);if(v&&t>=i.lods.length?w=!0:v||(w=!0),w)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 w=y+"_"+i.guid,v=this.previouslyLoaded.get(w);if(v!==void 0){s&&console.log(`LOD ${t} was already loading/loaded: ${w}`);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(w)):h instanceof p.BufferGeometry&&e instanceof p.BufferGeometry&&((c=h.attributes.position)!=null&&c.array||(k=!0,this.previouslyLoaded.delete(w)))),!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 m=f==null?void 0:f.extensions[U];if(m!=null&&m.guid&&m.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,w),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 m=f==null?void 0:f.extensions[U];if(m!=null&&m.guid&&m.guid===M.guid){T=!0;break}}b++}if(T){const f=await z.getDependency("mesh",b),m=M;if(s&&console.log(`Loaded Mesh "${f.name}"`,y,b,f,w),f.isMesh===!0){const S=f.geometry;return _.assignLODInformation(o.url,S,r,t,void 0,m.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,m.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(w,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[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
|
|
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,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(L(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,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,q,t._fpsBuffer.reduce((a,l)=>a+l)/t._fpsBuffer.length),G&&L(t,Q)%200===0&&console.log("FPS",Math.round(L(t,q)),"Interval:",L(t,B)));const i=e++;L(t,W).call(this,s,o),t.onAfterRender(s,o,i)}}disable(){L(this,W)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=L(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"?L(this,q)<40&&L(this,B)<10?(N(this,B,L(this,B)+1),G&&console.warn("↓ Reducing LOD updates",L(this,B),L(this,q).toFixed(0))):L(this,q)>=60&&L(this,B)>1&&(N(this,B,L(this,B)-1),G&&console.warn("↑ Increasing LOD updates",L(this,B),L(this,q).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,w=new p.MeshStandardMaterial({color:y});c.object.material=w}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),w=(y==null?void 0:y.min_count)!=1/0&&y.min_count>0&&y.max_count>0;if(!g&&!w){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 D=t;if(!D.boundingBox)D.computeBoundingBox();else if(s.frames%30===0){const h=te(D),k=D.geometry;h&&(D.geometry=h),D.computeBoundingBox(),D.geometry=k}M=D.boundingBox}if(M){const D=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),D.isPerspectiveCamera&&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&&D.isPerspectiveCamera&&D.fov>70){const f=this._tempBox.min,m=this._tempBox.max;let S=f.x,A=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,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(m.x)),Ne=A<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),e.isPerspectiveCamera?h.x*=e.aspect:e.isOrthographicCamera;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 m=C.corner0,S=C.corner1,A=C.corner2,P=C.corner3;m.copy(this._tempBox.min),S.copy(this._tempBox.max),S.x=m.x,A.copy(this._tempBox.max),A.y=m.y,P.copy(this._tempBox.max);const X=(m.z+P.z)*.5;m.z=S.z=A.z=P.z=X,m.applyMatrix4(f),S.applyMatrix4(f),A.applyMatrix4(f),P.applyMatrix4(f),C.debugDrawLine(m,S,255),C.debugDrawLine(m,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(w){const D="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(!(D&&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
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
|
-
`,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
|
|
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 w=0;w<u.length;w++){const v=u[w],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 D=s.parser.json.textures[V];if(!D){console.warn("Texture data not found for texture index "+V);continue}if((y=D==null?void 0:D.extensions)!=null&&y[U]){const h=D.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
|
@@ -456,7 +456,7 @@ export class LODsManager {
|
|
|
456
456
|
}
|
|
457
457
|
boundingBox = skinnedMesh.boundingBox;
|
|
458
458
|
}
|
|
459
|
-
if (boundingBox
|
|
459
|
+
if (boundingBox) {
|
|
460
460
|
const cam = camera;
|
|
461
461
|
// hack: if the mesh has vertex colors, has less than 100 vertices we always select the highest LOD
|
|
462
462
|
if (mesh.geometry.attributes.color && mesh.geometry.attributes.color.count < 100) {
|
|
@@ -481,7 +481,7 @@ export class LODsManager {
|
|
|
481
481
|
// High distortions would lead to lower LOD levels.
|
|
482
482
|
// "Centrality" of the calculated screen-space bounding box could be a factor here –
|
|
483
483
|
// what's the distance of the bounding box to the center of the screen?
|
|
484
|
-
if (LODsManager.isInside(this._tempBox, this.projectionScreenMatrix)) {
|
|
484
|
+
if (cam.isPerspectiveCamera && LODsManager.isInside(this._tempBox, this.projectionScreenMatrix)) {
|
|
485
485
|
result.mesh_lod = 0;
|
|
486
486
|
result.texture_lod = 0;
|
|
487
487
|
return;
|
|
@@ -489,7 +489,7 @@ export class LODsManager {
|
|
|
489
489
|
this._tempBox.applyMatrix4(this.projectionScreenMatrix);
|
|
490
490
|
// TODO might need to be adjusted for cameras that are rendered during an XR session but are
|
|
491
491
|
// actually not XR cameras (e.g. a render texture)
|
|
492
|
-
if (this.renderer.xr.enabled && cam.fov > 70) {
|
|
492
|
+
if (this.renderer.xr.enabled && (cam.isPerspectiveCamera) && cam.fov > 70) {
|
|
493
493
|
// calculate centrality of the bounding box - how close is it to the screen center
|
|
494
494
|
const min = this._tempBox.min;
|
|
495
495
|
const max = this._tempBox.max;
|
|
@@ -522,7 +522,13 @@ export class LODsManager {
|
|
|
522
522
|
if (canvasHeight > 0)
|
|
523
523
|
boxSize.multiplyScalar(canvasHeight / screen.availHeight);
|
|
524
524
|
}
|
|
525
|
-
|
|
525
|
+
if (camera.isPerspectiveCamera) {
|
|
526
|
+
boxSize.x *= camera.aspect;
|
|
527
|
+
}
|
|
528
|
+
else if (camera.isOrthographicCamera) {
|
|
529
|
+
// const cam = camera as OrthographicCamera;
|
|
530
|
+
// boxSize.x *= cam.zoom * .01;
|
|
531
|
+
}
|
|
526
532
|
const matView = camera.matrixWorldInverse;
|
|
527
533
|
const box2 = this._tempBox2;
|
|
528
534
|
box2.copy(boundingBox);
|
package/lib/version.js
CHANGED
package/package.json
CHANGED