@needle-tools/gltf-progressive 1.2.3-alpha.2 → 1.2.3-alpha.3
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 +162 -161
- package/gltf-progressive.min.js +7 -7
- package/gltf-progressive.umd.cjs +7 -7
- package/lib/lods_manager.js +5 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,9 @@ All notable changes to this package will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [1.2.3-alpha.3] - 2023-07-01
|
|
8
|
+
- Add: prevent loading highres textures when user has enabled data-save mode
|
|
9
|
+
|
|
7
10
|
## [1.2.3-alpha.2] - 2023-06-27
|
|
8
11
|
- Fix: error caused by parser associations containing `undefined` value
|
|
9
12
|
|
package/gltf-progressive.js
CHANGED
|
@@ -4,12 +4,12 @@ var d = (a, t, e) => (Ve(a, typeof t != "symbol" ? t + "" : t, e), e), Se = (a,
|
|
|
4
4
|
if (!t.has(a))
|
|
5
5
|
throw TypeError("Cannot " + e);
|
|
6
6
|
};
|
|
7
|
-
var m = (a, t, e) => (Se(a, t, "read from private field"), e ? e.call(a) : t.get(a)),
|
|
7
|
+
var m = (a, t, e) => (Se(a, t, "read from private field"), e ? e.call(a) : t.get(a)), X = (a, t, e) => {
|
|
8
8
|
if (t.has(a))
|
|
9
9
|
throw TypeError("Cannot add the same private member more than once");
|
|
10
10
|
t instanceof WeakSet ? t.add(a) : t.set(a, e);
|
|
11
|
-
},
|
|
12
|
-
import { BufferGeometry as de, Mesh as J, Material as Ne, Texture as ee, TextureLoader as Ue, Matrix4 as be, Frustum as We, Clock as Ke, MeshStandardMaterial as qe, Sphere as Xe, Box3 as Te, Vector3 as
|
|
11
|
+
}, F = (a, t, e, r) => (Se(a, t, "write to private field"), r ? r.call(a, e) : t.set(a, e), e);
|
|
12
|
+
import { BufferGeometry as de, Mesh as J, Material as Ne, Texture as ee, TextureLoader as Ue, Matrix4 as be, Frustum as We, Clock as Ke, MeshStandardMaterial as qe, Sphere as Xe, Box3 as Te, Vector3 as N } from "three";
|
|
13
13
|
import { GLTFLoader as Ye } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
14
14
|
import { MeshoptDecoder as He } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
15
15
|
import { DRACOLoader as Je } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
@@ -88,7 +88,7 @@ function tt(a) {
|
|
|
88
88
|
t.setAttribute(e, a.getAttribute(e));
|
|
89
89
|
return t.setIndex(a.getIndex()), t;
|
|
90
90
|
}
|
|
91
|
-
const
|
|
91
|
+
const Y = new Array(), U = "NEEDLE_progressive", L = ae("debugprogressive"), xe = Symbol("needle-progressive-texture"), ne = /* @__PURE__ */ new Map(), ve = /* @__PURE__ */ new Set();
|
|
92
92
|
if (L) {
|
|
93
93
|
let a = function() {
|
|
94
94
|
t += 1, console.log("Toggle LOD level", t, ne), ne.forEach((o, i) => {
|
|
@@ -96,10 +96,10 @@ if (L) {
|
|
|
96
96
|
const n = i[s];
|
|
97
97
|
if (n != null) {
|
|
98
98
|
if (n.isBufferGeometry === !0) {
|
|
99
|
-
const l =
|
|
100
|
-
i["DEBUG:LOD"] = t,
|
|
99
|
+
const l = b.getMeshLODInformation(n), f = l ? Math.min(t, l.lods.length) : 0;
|
|
100
|
+
i["DEBUG:LOD"] = t, b.assignMeshLOD(i, f), l && (e = Math.max(e, l.lods.length - 1));
|
|
101
101
|
} else if (i.isMaterial === !0) {
|
|
102
|
-
i["DEBUG:LOD"] = t,
|
|
102
|
+
i["DEBUG:LOD"] = t, b.assignTextureLOD(i, t);
|
|
103
103
|
break;
|
|
104
104
|
}
|
|
105
105
|
}
|
|
@@ -120,7 +120,7 @@ function Ae(a, t, e) {
|
|
|
120
120
|
const r = ne.get(a);
|
|
121
121
|
((o = r == null ? void 0 : r.keys) == null ? void 0 : o.includes(t)) == !1 && r.keys.push(t);
|
|
122
122
|
}
|
|
123
|
-
const
|
|
123
|
+
const _ = class {
|
|
124
124
|
constructor(t, e) {
|
|
125
125
|
d(this, "parser");
|
|
126
126
|
d(this, "url");
|
|
@@ -129,17 +129,17 @@ const O = class {
|
|
|
129
129
|
var r, o;
|
|
130
130
|
if (this._isLoadingMesh)
|
|
131
131
|
return null;
|
|
132
|
-
const e = (o = (r = this.parser.json.meshes[t]) == null ? void 0 : r.extensions) == null ? void 0 : o[
|
|
132
|
+
const e = (o = (r = this.parser.json.meshes[t]) == null ? void 0 : r.extensions) == null ? void 0 : o[U];
|
|
133
133
|
return e ? (this._isLoadingMesh = !0, this.parser.getDependency("mesh", t).then((i) => {
|
|
134
134
|
var s;
|
|
135
|
-
return this._isLoadingMesh = !1, i &&
|
|
135
|
+
return this._isLoadingMesh = !1, i && _.registerMesh(this.url, e.guid, i, (s = e.lods) == null ? void 0 : s.length, void 0, e), i;
|
|
136
136
|
})) : null;
|
|
137
137
|
});
|
|
138
138
|
L && console.log("Progressive extension registered for", e), this.parser = t, this.url = e;
|
|
139
139
|
}
|
|
140
140
|
/** The name of the extension */
|
|
141
141
|
get name() {
|
|
142
|
-
return
|
|
142
|
+
return U;
|
|
143
143
|
}
|
|
144
144
|
static getMeshLODInformation(t) {
|
|
145
145
|
const e = this.getAssignedLODInformation(t);
|
|
@@ -241,9 +241,9 @@ const O = class {
|
|
|
241
241
|
const o = t.geometry, i = this.getAssignedLODInformation(o);
|
|
242
242
|
if (!i)
|
|
243
243
|
return Promise.resolve(null);
|
|
244
|
-
for (const s of
|
|
244
|
+
for (const s of Y)
|
|
245
245
|
(r = s.onBeforeGetLODMesh) == null || r.call(s, t, e);
|
|
246
|
-
return t["LOD:requested level"] = e,
|
|
246
|
+
return t["LOD:requested level"] = e, _.getOrLoadLOD(o, e).then((s) => {
|
|
247
247
|
if (t["LOD:requested level"] === e) {
|
|
248
248
|
if (delete t["LOD:requested level"], Array.isArray(s)) {
|
|
249
249
|
const n = i.index || 0;
|
|
@@ -302,7 +302,7 @@ const O = class {
|
|
|
302
302
|
return Promise.resolve(null);
|
|
303
303
|
}
|
|
304
304
|
static assignTextureLODForSlot(t, e, r, o) {
|
|
305
|
-
return (t == null ? void 0 : t.isTexture) !== !0 ? Promise.resolve(null) : o === "glyphMap" ? Promise.resolve(t) :
|
|
305
|
+
return (t == null ? void 0 : t.isTexture) !== !0 ? Promise.resolve(null) : o === "glyphMap" ? Promise.resolve(t) : _.getOrLoadLOD(t, e).then((i) => {
|
|
306
306
|
if (Array.isArray(i))
|
|
307
307
|
return null;
|
|
308
308
|
if ((i == null ? void 0 : i.isTexture) === !0) {
|
|
@@ -332,7 +332,7 @@ const O = class {
|
|
|
332
332
|
return L && console.log("AFTER", this.url, t), (e = this.parser.json.textures) == null || e.forEach((o, i) => {
|
|
333
333
|
var s;
|
|
334
334
|
if (o != null && o.extensions) {
|
|
335
|
-
const n = o == null ? void 0 : o.extensions[
|
|
335
|
+
const n = o == null ? void 0 : o.extensions[U];
|
|
336
336
|
if (n) {
|
|
337
337
|
if (!n.lods) {
|
|
338
338
|
L && console.warn("Texture has no LODs", n);
|
|
@@ -342,22 +342,22 @@ const O = class {
|
|
|
342
342
|
for (const f of this.parser.associations.keys())
|
|
343
343
|
if (f.isTexture === !0) {
|
|
344
344
|
const c = this.parser.associations.get(f);
|
|
345
|
-
(c == null ? void 0 : c.textures) === i && (l = !0,
|
|
345
|
+
(c == null ? void 0 : c.textures) === i && (l = !0, _.registerTexture(this.url, f, (s = n.lods) == null ? void 0 : s.length, i, n));
|
|
346
346
|
}
|
|
347
347
|
l || this.parser.getDependency("texture", i).then((f) => {
|
|
348
348
|
var c;
|
|
349
|
-
f &&
|
|
349
|
+
f && _.registerTexture(this.url, f, (c = n.lods) == null ? void 0 : c.length, i, n);
|
|
350
350
|
});
|
|
351
351
|
}
|
|
352
352
|
}
|
|
353
353
|
}), (r = this.parser.json.meshes) == null || r.forEach((o, i) => {
|
|
354
354
|
if (o != null && o.extensions) {
|
|
355
|
-
const s = o == null ? void 0 : o.extensions[
|
|
355
|
+
const s = o == null ? void 0 : o.extensions[U];
|
|
356
356
|
if (s && s.lods) {
|
|
357
357
|
for (const n of this.parser.associations.keys())
|
|
358
358
|
if (n.isMesh) {
|
|
359
359
|
const l = this.parser.associations.get(n);
|
|
360
|
-
(l == null ? void 0 : l.meshes) === i &&
|
|
360
|
+
(l == null ? void 0 : l.meshes) === i && _.registerMesh(this.url, s.guid, n, s.lods.length, l.primitives, s);
|
|
361
361
|
}
|
|
362
362
|
}
|
|
363
363
|
}
|
|
@@ -374,7 +374,7 @@ const O = class {
|
|
|
374
374
|
const M = t;
|
|
375
375
|
M.source && M.source[xe] && (s = M.source[xe]);
|
|
376
376
|
}
|
|
377
|
-
if (s || (s =
|
|
377
|
+
if (s || (s = _.lodInfos.get(i)), s) {
|
|
378
378
|
if (e > 0) {
|
|
379
379
|
let y = !1;
|
|
380
380
|
const v = Array.isArray(s.lods);
|
|
@@ -391,78 +391,78 @@ const O = class {
|
|
|
391
391
|
const y = u + "_" + s.guid, v = this.previouslyLoaded.get(y);
|
|
392
392
|
if (v !== void 0) {
|
|
393
393
|
r && console.log(`LOD ${e} was already loading/loaded: ${y}`);
|
|
394
|
-
let p = await v.catch((
|
|
395
|
-
`,
|
|
394
|
+
let p = await v.catch((z) => (console.error(`Error loading LOD ${e} from ${u}
|
|
395
|
+
`, z), null)), D = !1;
|
|
396
396
|
if (p == null || (p instanceof ee && t instanceof ee ? (l = p.image) != null && l.data || (f = p.source) != null && f.data ? p = this.copySettings(t, p) : (D = !0, this.previouslyLoaded.delete(y)) : p instanceof de && t instanceof de && ((c = p.attributes.position) != null && c.array || (D = !0, this.previouslyLoaded.delete(y)))), !D)
|
|
397
397
|
return p;
|
|
398
398
|
}
|
|
399
|
-
const x = s,
|
|
400
|
-
const
|
|
401
|
-
Ie(
|
|
402
|
-
let
|
|
399
|
+
const x = s, G = new Promise(async (p, D) => {
|
|
400
|
+
const z = new Ye();
|
|
401
|
+
Ie(z), L && (await new Promise((O) => setTimeout(O, 1e3)), r && console.warn("Start loading (delayed) " + u, x.guid));
|
|
402
|
+
let q = u;
|
|
403
403
|
if (x && Array.isArray(x.lods)) {
|
|
404
|
-
const
|
|
405
|
-
|
|
404
|
+
const O = x.lods[e];
|
|
405
|
+
O.hash && (q += "?v=" + O.hash);
|
|
406
406
|
}
|
|
407
|
-
const
|
|
408
|
-
`,
|
|
409
|
-
if (!
|
|
407
|
+
const S = await z.loadAsync(q).catch((O) => (console.error(`Error loading LOD ${e} from ${u}
|
|
408
|
+
`, O), null));
|
|
409
|
+
if (!S)
|
|
410
410
|
return null;
|
|
411
|
-
const
|
|
411
|
+
const V = S.parser;
|
|
412
412
|
r && console.log("Loading finished " + u, x.guid);
|
|
413
|
-
let
|
|
414
|
-
if (
|
|
415
|
-
let
|
|
416
|
-
for (const g of
|
|
413
|
+
let A = 0;
|
|
414
|
+
if (S.parser.json.textures) {
|
|
415
|
+
let O = !1;
|
|
416
|
+
for (const g of S.parser.json.textures) {
|
|
417
417
|
if (g != null && g.extensions) {
|
|
418
|
-
const h = g == null ? void 0 : g.extensions[
|
|
418
|
+
const h = g == null ? void 0 : g.extensions[U];
|
|
419
419
|
if (h != null && h.guid && h.guid === x.guid) {
|
|
420
|
-
|
|
420
|
+
O = !0;
|
|
421
421
|
break;
|
|
422
422
|
}
|
|
423
423
|
}
|
|
424
|
-
|
|
424
|
+
A++;
|
|
425
425
|
}
|
|
426
|
-
if (
|
|
427
|
-
let g = await
|
|
428
|
-
return g &&
|
|
426
|
+
if (O) {
|
|
427
|
+
let g = await V.getDependency("texture", A);
|
|
428
|
+
return g && _.assignLODInformation(o.url, g, i, e, void 0, void 0), r && console.log('change "' + t.name + '" → "' + g.name + '"', u, A, g, y), t instanceof ee && (g = this.copySettings(t, g)), g && (g.guid = x.guid), p(g);
|
|
429
429
|
} else
|
|
430
|
-
L && console.warn("Could not find texture with guid", x.guid,
|
|
430
|
+
L && console.warn("Could not find texture with guid", x.guid, S.parser.json);
|
|
431
431
|
}
|
|
432
|
-
if (
|
|
433
|
-
let
|
|
434
|
-
for (const g of
|
|
432
|
+
if (A = 0, S.parser.json.meshes) {
|
|
433
|
+
let O = !1;
|
|
434
|
+
for (const g of S.parser.json.meshes) {
|
|
435
435
|
if (g != null && g.extensions) {
|
|
436
|
-
const h = g == null ? void 0 : g.extensions[
|
|
436
|
+
const h = g == null ? void 0 : g.extensions[U];
|
|
437
437
|
if (h != null && h.guid && h.guid === x.guid) {
|
|
438
|
-
|
|
438
|
+
O = !0;
|
|
439
439
|
break;
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
|
-
|
|
442
|
+
A++;
|
|
443
443
|
}
|
|
444
|
-
if (
|
|
445
|
-
const g = await
|
|
446
|
-
if (r && console.log(`Loaded Mesh "${g.name}"`, u,
|
|
444
|
+
if (O) {
|
|
445
|
+
const g = await V.getDependency("mesh", A), h = x;
|
|
446
|
+
if (r && console.log(`Loaded Mesh "${g.name}"`, u, A, g, y), g.isMesh === !0) {
|
|
447
447
|
const w = g.geometry;
|
|
448
|
-
return
|
|
448
|
+
return _.assignLODInformation(o.url, w, i, e, void 0, h.density), p(w);
|
|
449
449
|
} else {
|
|
450
450
|
const w = new Array();
|
|
451
451
|
for (let T = 0; T < g.children.length; T++) {
|
|
452
|
-
const
|
|
453
|
-
if (
|
|
454
|
-
const
|
|
455
|
-
|
|
452
|
+
const P = g.children[T];
|
|
453
|
+
if (P.isMesh === !0) {
|
|
454
|
+
const E = P.geometry;
|
|
455
|
+
_.assignLODInformation(o.url, E, i, e, T, h.density), w.push(E);
|
|
456
456
|
}
|
|
457
457
|
}
|
|
458
458
|
return p(w);
|
|
459
459
|
}
|
|
460
460
|
} else
|
|
461
|
-
L && console.warn("Could not find mesh with guid", x.guid,
|
|
461
|
+
L && console.warn("Could not find mesh with guid", x.guid, S.parser.json);
|
|
462
462
|
}
|
|
463
463
|
return p(null);
|
|
464
464
|
});
|
|
465
|
-
return this.previouslyLoaded.set(y,
|
|
465
|
+
return this.previouslyLoaded.set(y, G), await G;
|
|
466
466
|
} else if (t instanceof ee) {
|
|
467
467
|
r && console.log("Load texture from uri: " + u);
|
|
468
468
|
const v = await new Ue().loadAsync(u);
|
|
@@ -490,22 +490,22 @@ const O = class {
|
|
|
490
490
|
`, e.uuid), e.offset = t.offset, e.repeat = t.repeat, e.colorSpace = t.colorSpace, e.magFilter = t.magFilter, e.minFilter = t.minFilter, e.wrapS = t.wrapS, e.wrapT = t.wrapT, e.flipY = t.flipY, e.anisotropy = t.anisotropy, e.mipmaps || (e.generateMipmaps = t.generateMipmaps), e;
|
|
491
491
|
}
|
|
492
492
|
};
|
|
493
|
-
let
|
|
493
|
+
let b = _;
|
|
494
494
|
/**
|
|
495
495
|
* Register a texture with LOD information
|
|
496
496
|
*/
|
|
497
|
-
d(
|
|
497
|
+
d(b, "registerTexture", (t, e, r, o, i) => {
|
|
498
498
|
if (L && console.log("> Progressive: register texture", o, e.name, e.uuid, e, i), !e) {
|
|
499
499
|
L && console.error("gltf-progressive: Register texture without texture");
|
|
500
500
|
return;
|
|
501
501
|
}
|
|
502
502
|
e.source && (e.source[xe] = i);
|
|
503
503
|
const s = i.guid;
|
|
504
|
-
|
|
504
|
+
_.assignLODInformation(t, e, s, r, o, void 0), _.lodInfos.set(s, i), _.lowresCache.set(s, e);
|
|
505
505
|
}), /**
|
|
506
506
|
* Register a mesh with LOD information
|
|
507
507
|
*/
|
|
508
|
-
d(
|
|
508
|
+
d(b, "registerMesh", (t, e, r, o, i, s) => {
|
|
509
509
|
var f;
|
|
510
510
|
L && console.log("> Progressive: register mesh", i, r.name, s, r.uuid, r);
|
|
511
511
|
const n = r.geometry;
|
|
@@ -513,15 +513,15 @@ d(S, "registerMesh", (t, e, r, o, i, s) => {
|
|
|
513
513
|
L && console.warn("gltf-progressive: Register mesh without geometry");
|
|
514
514
|
return;
|
|
515
515
|
}
|
|
516
|
-
n.userData || (n.userData = {}),
|
|
517
|
-
let l =
|
|
518
|
-
l ? l.push(r.geometry) : l = [r.geometry],
|
|
519
|
-
for (const c of
|
|
516
|
+
n.userData || (n.userData = {}), _.assignLODInformation(t, n, e, o, i, s.density), _.lodInfos.set(e, s);
|
|
517
|
+
let l = _.lowresCache.get(e);
|
|
518
|
+
l ? l.push(r.geometry) : l = [r.geometry], _.lowresCache.set(e, l), o > 0 && !Oe(r) && et(r, n);
|
|
519
|
+
for (const c of Y)
|
|
520
520
|
(f = c.onRegisteredNewMesh) == null || f.call(c, r, s);
|
|
521
521
|
}), /** A map of key = asset uuid and value = LOD information */
|
|
522
|
-
d(
|
|
523
|
-
d(
|
|
524
|
-
d(
|
|
522
|
+
d(b, "lodInfos", /* @__PURE__ */ new Map()), /** cache of already loaded mesh lods */
|
|
523
|
+
d(b, "previouslyLoaded", /* @__PURE__ */ new Map()), /** this contains the geometry/textures that were originally loaded */
|
|
524
|
+
d(b, "lowresCache", /* @__PURE__ */ new Map());
|
|
525
525
|
class rt {
|
|
526
526
|
constructor(t, e, r, o, i) {
|
|
527
527
|
d(this, "url");
|
|
@@ -535,9 +535,9 @@ class rt {
|
|
|
535
535
|
this.url = t, this.key = e, this.level = r, o != null && (this.index = o), i != null && (this.density = i);
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
|
-
const
|
|
539
|
-
var
|
|
540
|
-
const
|
|
538
|
+
const k = ae("debugprogressive"), st = ae("noprogressive"), Le = Symbol("Needle:LODSManager"), Me = Symbol("Needle:LODState"), H = Symbol("Needle:CurrentLOD"), I = { mesh_lod: -1, texture_lod: -1 };
|
|
539
|
+
var B, W, ge, Q, Z, pe, K;
|
|
540
|
+
const C = class {
|
|
541
541
|
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
542
542
|
constructor(t, e) {
|
|
543
543
|
d(this, "context");
|
|
@@ -553,27 +553,27 @@ const E = class {
|
|
|
553
553
|
* The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 2, the LODs will be updated every second frame, etc.
|
|
554
554
|
*/
|
|
555
555
|
d(this, "updateInterval", "auto");
|
|
556
|
-
|
|
556
|
+
X(this, B, 1);
|
|
557
557
|
/**
|
|
558
558
|
* If set to true, the LODsManager will not update the LODs.
|
|
559
559
|
*/
|
|
560
560
|
d(this, "pause", !1);
|
|
561
561
|
d(this, "_lodchangedlisteners", []);
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
562
|
+
X(this, W, void 0);
|
|
563
|
+
X(this, ge, new Ke());
|
|
564
|
+
X(this, Q, 0);
|
|
565
|
+
X(this, Z, 0);
|
|
566
|
+
X(this, pe, 0);
|
|
567
|
+
X(this, K, 0);
|
|
568
568
|
d(this, "_fpsBuffer", [60, 60, 60, 60, 60]);
|
|
569
569
|
// private testIfLODLevelsAreAvailable() {
|
|
570
570
|
d(this, "_sphere", new Xe());
|
|
571
571
|
d(this, "_tempBox", new Te());
|
|
572
572
|
d(this, "_tempBox2", new Te());
|
|
573
573
|
d(this, "tempMatrix", new be());
|
|
574
|
-
d(this, "_tempWorldPosition", new
|
|
575
|
-
d(this, "_tempBoxSize", new
|
|
576
|
-
d(this, "_tempBox2Size", new
|
|
574
|
+
d(this, "_tempWorldPosition", new N());
|
|
575
|
+
d(this, "_tempBoxSize", new N());
|
|
576
|
+
d(this, "_tempBox2Size", new N());
|
|
577
577
|
this.renderer = t, this.context = { ...e };
|
|
578
578
|
}
|
|
579
579
|
/** @internal */
|
|
@@ -581,11 +581,11 @@ const E = class {
|
|
|
581
581
|
return t[Me];
|
|
582
582
|
}
|
|
583
583
|
static addPlugin(t) {
|
|
584
|
-
|
|
584
|
+
Y.push(t);
|
|
585
585
|
}
|
|
586
586
|
static removePlugin(t) {
|
|
587
|
-
const e =
|
|
588
|
-
e >= 0 &&
|
|
587
|
+
const e = Y.indexOf(t);
|
|
588
|
+
e >= 0 && Y.splice(e, 1);
|
|
589
589
|
}
|
|
590
590
|
/**
|
|
591
591
|
* Gets the LODsManager for the given renderer. If the LODsManager does not exist yet, it will be created.
|
|
@@ -595,7 +595,7 @@ const E = class {
|
|
|
595
595
|
static get(t, e) {
|
|
596
596
|
if (t[Le])
|
|
597
597
|
return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), t[Le];
|
|
598
|
-
const r = new
|
|
598
|
+
const r = new C(t, {
|
|
599
599
|
engine: "unknown",
|
|
600
600
|
...e
|
|
601
601
|
});
|
|
@@ -603,7 +603,7 @@ const E = class {
|
|
|
603
603
|
}
|
|
604
604
|
/** @deprecated use static `LODsManager.addPlugin()` method. This getter will be removed in later versions */
|
|
605
605
|
get plugins() {
|
|
606
|
-
return
|
|
606
|
+
return Y;
|
|
607
607
|
}
|
|
608
608
|
addEventListener(t, e) {
|
|
609
609
|
t === "changed" && this._lodchangedlisteners.push(e);
|
|
@@ -612,20 +612,20 @@ const E = class {
|
|
|
612
612
|
* Enable the LODsManager. This will replace the render method of the renderer with a method that updates the LODs.
|
|
613
613
|
*/
|
|
614
614
|
enable() {
|
|
615
|
-
if (m(this,
|
|
615
|
+
if (m(this, W))
|
|
616
616
|
return;
|
|
617
617
|
console.debug("[gltf-progressive] Enabling LODsManager for renderer");
|
|
618
618
|
let t = 0;
|
|
619
|
-
|
|
619
|
+
F(this, W, this.renderer.render);
|
|
620
620
|
const e = this;
|
|
621
621
|
ke(this.renderer), this.renderer.render = function(r, o) {
|
|
622
|
-
e.renderer.getRenderTarget() == null && (t = 0,
|
|
622
|
+
e.renderer.getRenderTarget() == null && (t = 0, F(e, Q, m(e, Q) + 1), F(e, Z, m(e, ge).getDelta()), F(e, pe, m(e, pe) + m(e, Z)), e._fpsBuffer.shift(), e._fpsBuffer.push(1 / m(e, Z)), F(e, K, e._fpsBuffer.reduce((l, f) => l + f) / e._fpsBuffer.length), k && m(e, Q) % 30 === 0 && console.log("FPS", Math.round(m(e, K)), "Interval:", m(e, B)));
|
|
623
623
|
const s = m(e, Q), n = t++;
|
|
624
|
-
e.onBeforeRender(r, o, n, s), m(e,
|
|
624
|
+
e.onBeforeRender(r, o, n, s), m(e, W).call(this, r, o), e.onAfterRender(r, o, n, s);
|
|
625
625
|
};
|
|
626
626
|
}
|
|
627
627
|
disable() {
|
|
628
|
-
m(this,
|
|
628
|
+
m(this, W) && (this.renderer.render = m(this, W), F(this, W, void 0));
|
|
629
629
|
}
|
|
630
630
|
onBeforeRender(t, e, r, o) {
|
|
631
631
|
}
|
|
@@ -640,13 +640,13 @@ const E = class {
|
|
|
640
640
|
(c.name === "EffectMaterial" || c.name === "CopyShader") && (n = !1);
|
|
641
641
|
}
|
|
642
642
|
if ((e.parent && e.parent.type === "CubeCamera" || r >= 1 && e.type === "OrthographicCamera") && (n = !1), n) {
|
|
643
|
-
if (st || (this.updateInterval === "auto" ? m(this,
|
|
643
|
+
if (st || (this.updateInterval === "auto" ? m(this, K) < 40 && m(this, B) < 10 ? (F(this, B, m(this, B) + 1), k && console.warn("↓ Reducing LOD updates", m(this, B), m(this, K).toFixed(0))) : m(this, K) >= 60 && m(this, B) > 1 && (F(this, B, m(this, B) - 1), k && console.warn("↑ Increasing LOD updates", m(this, B), m(this, K).toFixed(0))) : F(this, B, this.updateInterval), m(this, B) > 0 && o % m(this, B) != 0))
|
|
644
644
|
return;
|
|
645
645
|
this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix, e.matrixWorldInverse), this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix, this.renderer.coordinateSystem);
|
|
646
646
|
const c = this.targetTriangleDensity;
|
|
647
647
|
for (const u of s) {
|
|
648
648
|
if (u.material && (((l = u.geometry) == null ? void 0 : l.type) === "BoxGeometry" || ((f = u.geometry) == null ? void 0 : f.type) === "BufferGeometry") && (u.material.name === "SphericalGaussianBlur" || u.material.name == "BackgroundCubeMaterial" || u.material.name === "CubemapFromEquirect" || u.material.name === "EquirectangularToCubeUV")) {
|
|
649
|
-
|
|
649
|
+
k && (u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] || (u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] = !0, console.warn("Ignoring skybox or BLIT object", u, u.material.name, u.material.type)));
|
|
650
650
|
continue;
|
|
651
651
|
}
|
|
652
652
|
switch (u.material.type) {
|
|
@@ -658,7 +658,7 @@ const E = class {
|
|
|
658
658
|
case "MeshDepthMaterial":
|
|
659
659
|
continue;
|
|
660
660
|
}
|
|
661
|
-
if (
|
|
661
|
+
if (k === "color" && u.material && !u.object.progressive_debug_color) {
|
|
662
662
|
u.object.progressive_debug_color = !0;
|
|
663
663
|
const v = Math.random() * 16777215, x = new qe({ color: v });
|
|
664
664
|
u.object.material = x;
|
|
@@ -680,17 +680,17 @@ const E = class {
|
|
|
680
680
|
let s = r[Me];
|
|
681
681
|
if (s || (s = new it(), r[Me] = s), s.frames++ < 2)
|
|
682
682
|
return;
|
|
683
|
-
for (const c of
|
|
683
|
+
for (const c of Y)
|
|
684
684
|
(l = c.onBeforeUpdateLOD) == null || l.call(c, this.renderer, t, e, r);
|
|
685
|
-
this.calculateLodLevel(e, r, s, o,
|
|
686
|
-
let n =
|
|
685
|
+
this.calculateLodLevel(e, r, s, o, I), I.mesh_lod = Math.round(I.mesh_lod), I.texture_lod = Math.round(I.texture_lod), I.mesh_lod >= 0 && this.loadProgressiveMeshes(r, I.mesh_lod);
|
|
686
|
+
let n = I.texture_lod;
|
|
687
687
|
if (r.material && n >= 0) {
|
|
688
688
|
const c = r["DEBUG:LOD"];
|
|
689
689
|
c != null && (n = c), this.loadProgressiveTextures(r.material, n);
|
|
690
690
|
}
|
|
691
|
-
for (const c of
|
|
692
|
-
(f = c.onAfterUpdatedLOD) == null || f.call(c, this.renderer, t, e, r,
|
|
693
|
-
s.lastLodLevel_Mesh =
|
|
691
|
+
for (const c of Y)
|
|
692
|
+
(f = c.onAfterUpdatedLOD) == null || f.call(c, this.renderer, t, e, r, I);
|
|
693
|
+
s.lastLodLevel_Mesh = I.mesh_lod, s.lastLodLevel_Texture = I.texture_lod;
|
|
694
694
|
}
|
|
695
695
|
/** Load progressive textures for the given material
|
|
696
696
|
* @param material the material to load the textures for
|
|
@@ -706,7 +706,7 @@ const E = class {
|
|
|
706
706
|
return;
|
|
707
707
|
}
|
|
708
708
|
let r = !1;
|
|
709
|
-
(t[H] === void 0 || e < t[H]) && (r = !0), r && (t[H] = e,
|
|
709
|
+
(t[H] === void 0 || e < t[H]) && (r = !0), r && (t[H] = e, b.assignTextureLOD(t, e).then((o) => {
|
|
710
710
|
this._lodchangedlisteners.forEach((i) => i({ type: "texture", level: e, object: t }));
|
|
711
711
|
}));
|
|
712
712
|
}
|
|
@@ -722,7 +722,7 @@ const E = class {
|
|
|
722
722
|
if (t[H] !== e) {
|
|
723
723
|
t[H] = e;
|
|
724
724
|
const r = t.geometry;
|
|
725
|
-
return
|
|
725
|
+
return b.assignMeshLOD(t, e).then((o) => (o && t[H] == e && r != t.geometry && this._lodchangedlisteners.forEach((i) => i({ type: "mesh", level: e, object: t })), o));
|
|
726
726
|
}
|
|
727
727
|
return Promise.resolve(null);
|
|
728
728
|
}
|
|
@@ -731,7 +731,7 @@ const E = class {
|
|
|
731
731
|
return this._tempPtInside.set(i, s, r.z).applyMatrix4(e).z < 0;
|
|
732
732
|
}
|
|
733
733
|
calculateLodLevel(t, e, r, o, i) {
|
|
734
|
-
var
|
|
734
|
+
var G, $;
|
|
735
735
|
if (!e) {
|
|
736
736
|
i.mesh_lod = -1, i.texture_lod = -1;
|
|
737
737
|
return;
|
|
@@ -741,14 +741,14 @@ const E = class {
|
|
|
741
741
|
return;
|
|
742
742
|
}
|
|
743
743
|
let n = 10 + 1, l = !1;
|
|
744
|
-
if (
|
|
744
|
+
if (k && e["DEBUG:LOD"] != null)
|
|
745
745
|
return e["DEBUG:LOD"];
|
|
746
|
-
const f =
|
|
746
|
+
const f = b.getMeshLODInformation(e.geometry), c = f == null ? void 0 : f.lods, M = c && c.length > 0, u = b.getMaterialMinMaxLODsCount(e.material), y = (u == null ? void 0 : u.min_count) != 1 / 0 && u.min_count > 0 && u.max_count > 0;
|
|
747
747
|
if (!M && !y) {
|
|
748
748
|
i.mesh_lod = 0, i.texture_lod = 0;
|
|
749
749
|
return;
|
|
750
750
|
}
|
|
751
|
-
if (M || (l = !0, n = 0), !((
|
|
751
|
+
if (M || (l = !0, n = 0), !((G = this.cameraFrustrum) != null && G.intersectsObject(e))) {
|
|
752
752
|
i.mesh_lod = 99, i.texture_lod = 99;
|
|
753
753
|
return;
|
|
754
754
|
}
|
|
@@ -768,85 +768,86 @@ const E = class {
|
|
|
768
768
|
return;
|
|
769
769
|
}
|
|
770
770
|
}
|
|
771
|
-
if (this._tempBox.copy(x), this._tempBox.applyMatrix4(e.matrixWorld),
|
|
771
|
+
if (this._tempBox.copy(x), this._tempBox.applyMatrix4(e.matrixWorld), C.isInside(this._tempBox, this.projectionScreenMatrix)) {
|
|
772
772
|
i.mesh_lod = 0, i.texture_lod = 0;
|
|
773
773
|
return;
|
|
774
774
|
}
|
|
775
775
|
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && p.fov > 70) {
|
|
776
776
|
const h = this._tempBox.min, w = this._tempBox.max;
|
|
777
|
-
let T = h.x,
|
|
777
|
+
let T = h.x, P = h.y, E = w.x, j = w.y;
|
|
778
778
|
const le = 2, ye = 1.5, ce = (h.x + w.x) * 0.5, ue = (h.y + w.y) * 0.5;
|
|
779
|
-
T = (T - ce) * le + ce,
|
|
780
|
-
const Fe = T < 0 &&
|
|
779
|
+
T = (T - ce) * le + ce, P = (P - ue) * le + ue, E = (E - ce) * le + ce, j = (j - ue) * le + ue;
|
|
780
|
+
const Fe = T < 0 && E > 0 ? 0 : Math.min(Math.abs(h.x), Math.abs(w.x)), $e = P < 0 && j > 0 ? 0 : Math.min(Math.abs(h.y), Math.abs(w.y)), me = Math.max(Fe, $e);
|
|
781
781
|
r.lastCentrality = (ye - me) * (ye - me) * (ye - me);
|
|
782
782
|
} else
|
|
783
783
|
r.lastCentrality = 1;
|
|
784
784
|
const D = this._tempBox.getSize(this._tempBoxSize);
|
|
785
785
|
D.multiplyScalar(0.5), screen.availHeight > 0 && v > 0 && D.multiplyScalar(v / screen.availHeight), D.x *= p.aspect;
|
|
786
|
-
const
|
|
787
|
-
|
|
788
|
-
const
|
|
789
|
-
if (Math.max(D.x, D.y) != 0 &&
|
|
786
|
+
const z = t.matrixWorldInverse, q = this._tempBox2;
|
|
787
|
+
q.copy(x), q.applyMatrix4(e.matrixWorld), q.applyMatrix4(z);
|
|
788
|
+
const S = q.getSize(this._tempBox2Size), V = Math.max(S.x, S.y);
|
|
789
|
+
if (Math.max(D.x, D.y) != 0 && V != 0 && (D.z = S.z / Math.max(S.x, S.y) * Math.max(D.x, D.y)), r.lastScreenCoverage = Math.max(D.x, D.y, D.z), r.lastScreenspaceVolume.copy(D), r.lastScreenCoverage *= r.lastCentrality, k && C.debugDrawLine) {
|
|
790
790
|
const h = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
791
791
|
h.invert();
|
|
792
|
-
const w =
|
|
793
|
-
w.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = w.x,
|
|
794
|
-
const j = (w.z +
|
|
795
|
-
w.z = T.z =
|
|
792
|
+
const w = C.corner0, T = C.corner1, P = C.corner2, E = C.corner3;
|
|
793
|
+
w.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = w.x, P.copy(this._tempBox.max), P.y = w.y, E.copy(this._tempBox.max);
|
|
794
|
+
const j = (w.z + E.z) * 0.5;
|
|
795
|
+
w.z = T.z = P.z = E.z = j, w.applyMatrix4(h), T.applyMatrix4(h), P.applyMatrix4(h), E.applyMatrix4(h), C.debugDrawLine(w, T, 255), C.debugDrawLine(w, P, 255), C.debugDrawLine(T, E, 255), C.debugDrawLine(P, E, 255);
|
|
796
796
|
}
|
|
797
|
-
let
|
|
797
|
+
let O = 999;
|
|
798
798
|
if (c && r.lastScreenCoverage > 0) {
|
|
799
799
|
for (let h = 0; h < c.length; h++)
|
|
800
800
|
if (c[h].density / r.lastScreenCoverage < o) {
|
|
801
|
-
|
|
801
|
+
O = h;
|
|
802
802
|
break;
|
|
803
803
|
}
|
|
804
804
|
}
|
|
805
|
-
|
|
805
|
+
O < n && (n = O, l = !0);
|
|
806
806
|
}
|
|
807
|
-
if (l ? i.mesh_lod = n : i.mesh_lod = r.lastLodLevel_Mesh,
|
|
807
|
+
if (l ? i.mesh_lod = n : i.mesh_lod = r.lastLodLevel_Mesh, k && i.mesh_lod != r.lastLodLevel_Mesh) {
|
|
808
808
|
const D = c == null ? void 0 : c[i.mesh_lod];
|
|
809
809
|
D && console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${i.mesh_lod} (${D.density.toFixed(0)}) - ${e.name}`);
|
|
810
810
|
}
|
|
811
|
-
if (y)
|
|
811
|
+
if (y) {
|
|
812
|
+
const p = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
|
|
812
813
|
if (r.lastLodLevel_Texture < 0) {
|
|
813
|
-
if (i.texture_lod = u.max_count - 1,
|
|
814
|
-
const
|
|
815
|
-
|
|
814
|
+
if (i.texture_lod = u.max_count - 1, k) {
|
|
815
|
+
const D = u.lods[u.max_count - 1];
|
|
816
|
+
k && console.log(`First Texture LOD ${i.texture_lod} (${D.max_height}px) - ${e.name}`);
|
|
816
817
|
}
|
|
817
818
|
} else {
|
|
818
|
-
const
|
|
819
|
-
let
|
|
820
|
-
((
|
|
821
|
-
const
|
|
822
|
-
for (let
|
|
823
|
-
let
|
|
824
|
-
if (!(je() &&
|
|
825
|
-
if (i.texture_lod =
|
|
826
|
-
const
|
|
827
|
-
|
|
828
|
-
Screensize: ${
|
|
819
|
+
const D = r.lastScreenspaceVolume.x + r.lastScreenspaceVolume.y + r.lastScreenspaceVolume.z;
|
|
820
|
+
let z = r.lastScreenCoverage * 2;
|
|
821
|
+
(($ = this.context) == null ? void 0 : $.engine) === "model-viewer" && (z *= 2);
|
|
822
|
+
const S = v / window.devicePixelRatio * z;
|
|
823
|
+
for (let V = u.lods.length - 1; V >= 0; V--) {
|
|
824
|
+
let A = u.lods[V];
|
|
825
|
+
if (!(p && A.max_height >= 2048) && !(je() && A.max_height > 4096) && A.max_height > S) {
|
|
826
|
+
if (i.texture_lod = V, i.texture_lod < r.lastLodLevel_Texture) {
|
|
827
|
+
const O = A.max_height;
|
|
828
|
+
k && console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${i.texture_lod} = ${O}px
|
|
829
|
+
Screensize: ${S.toFixed(0)}px, Coverage: ${(100 * r.lastScreenCoverage).toFixed(2)}%, Volume ${D.toFixed(1)}
|
|
829
830
|
${e.name}`);
|
|
830
831
|
}
|
|
831
832
|
break;
|
|
832
833
|
}
|
|
833
834
|
}
|
|
834
835
|
}
|
|
835
|
-
else
|
|
836
|
+
} else
|
|
836
837
|
i.texture_lod = 0;
|
|
837
838
|
}
|
|
838
839
|
};
|
|
839
|
-
let
|
|
840
|
-
|
|
840
|
+
let R = C;
|
|
841
|
+
B = new WeakMap(), W = new WeakMap(), ge = new WeakMap(), Q = new WeakMap(), Z = new WeakMap(), pe = new WeakMap(), K = 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.
|
|
841
842
|
*/
|
|
842
|
-
d(
|
|
843
|
+
d(R, "debugDrawLine"), d(R, "corner0", new N()), d(R, "corner1", new N()), d(R, "corner2", new N()), d(R, "corner3", new N()), d(R, "_tempPtInside", new N());
|
|
843
844
|
class it {
|
|
844
845
|
constructor() {
|
|
845
846
|
d(this, "frames", 0);
|
|
846
847
|
d(this, "lastLodLevel_Mesh", -1);
|
|
847
848
|
d(this, "lastLodLevel_Texture", -1);
|
|
848
849
|
d(this, "lastScreenCoverage", 0);
|
|
849
|
-
d(this, "lastScreenspaceVolume", new
|
|
850
|
+
d(this, "lastScreenspaceVolume", new N());
|
|
850
851
|
d(this, "lastCentrality", 0);
|
|
851
852
|
}
|
|
852
853
|
}
|
|
@@ -900,8 +901,8 @@ function Ge(a) {
|
|
|
900
901
|
}
|
|
901
902
|
};
|
|
902
903
|
console.debug("[gltf-progressive] setup model-viewer");
|
|
903
|
-
const i =
|
|
904
|
-
return
|
|
904
|
+
const i = R.get(t, { engine: "model-viewer" });
|
|
905
|
+
return R.addPlugin(new at()), i.enable(), i.addEventListener("changed", () => {
|
|
905
906
|
r == null || r.call(a);
|
|
906
907
|
}), a.addEventListener("model-visibility", (s) => {
|
|
907
908
|
s.detail.visible && (r == null || r.call(a));
|
|
@@ -947,17 +948,17 @@ class at {
|
|
|
947
948
|
for (let y = 0; y < f.length; y++) {
|
|
948
949
|
const v = f[y], x = l[v];
|
|
949
950
|
if ((x == null ? void 0 : x.isTexture) === !0) {
|
|
950
|
-
const
|
|
951
|
-
if (
|
|
951
|
+
const G = (M = (c = x.userData) == null ? void 0 : c.associations) == null ? void 0 : M.textures;
|
|
952
|
+
if (G == null)
|
|
952
953
|
continue;
|
|
953
|
-
const
|
|
954
|
-
if (
|
|
955
|
-
console.warn("Texture data not found for texture index " +
|
|
954
|
+
const $ = r.parser.json.textures[G];
|
|
955
|
+
if (!$) {
|
|
956
|
+
console.warn("Texture data not found for texture index " + G);
|
|
956
957
|
continue;
|
|
957
958
|
}
|
|
958
|
-
if ((u =
|
|
959
|
-
const p =
|
|
960
|
-
p && i &&
|
|
959
|
+
if ((u = $ == null ? void 0 : $.extensions) != null && u[U]) {
|
|
960
|
+
const p = $.extensions[U];
|
|
961
|
+
p && i && b.registerTexture(i, x, p.lods.length, G, p);
|
|
961
962
|
}
|
|
962
963
|
}
|
|
963
964
|
}
|
|
@@ -978,23 +979,23 @@ class at {
|
|
|
978
979
|
const r = this.tryGetCurrentModelViewer(t), o = this.getUrl(r);
|
|
979
980
|
if (!o)
|
|
980
981
|
return;
|
|
981
|
-
const i = (n = (s = e.userData) == null ? void 0 : s.gltfExtensions) == null ? void 0 : n[
|
|
982
|
+
const i = (n = (s = e.userData) == null ? void 0 : s.gltfExtensions) == null ? void 0 : n[U];
|
|
982
983
|
if (i && o) {
|
|
983
984
|
const l = e.uuid;
|
|
984
|
-
|
|
985
|
+
b.registerMesh(o, l, e, 0, i.lods.length, i);
|
|
985
986
|
}
|
|
986
987
|
}
|
|
987
988
|
}
|
|
988
989
|
function mt(a, t, e, r) {
|
|
989
|
-
ke(t), Ie(e), e.register((i) => new
|
|
990
|
-
const o =
|
|
990
|
+
ke(t), Ie(e), e.register((i) => new b(i, a));
|
|
991
|
+
const o = R.get(t);
|
|
991
992
|
return (r == null ? void 0 : r.enableLODsManager) !== !1 && o.enable(), o;
|
|
992
993
|
}
|
|
993
994
|
Re();
|
|
994
995
|
export {
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
996
|
+
U as EXTENSION_NAME,
|
|
997
|
+
R as LODsManager,
|
|
998
|
+
b as NEEDLE_progressive,
|
|
998
999
|
Be as VERSION,
|
|
999
1000
|
Ie as addDracoAndKTX2Loaders,
|
|
1000
1001
|
ke as createLoaders,
|
package/gltf-progressive.min.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var Re=Object.defineProperty,Ge=(t,e,s)=>e in t?Re(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s,d=(t,e,s)=>(Ge(t,typeof e!="symbol"?e+"":e,s),s),Oe=(t,e,s)=>{if(!e.has(t))throw TypeError("Cannot "+s)},v=(t,e,s)=>(Oe(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)=>(Oe(t,e,"write to private field"),o?o.call(t,s):e.set(t,s),s);import{BufferGeometry as oe,Mesh as K,Material as Fe,Texture as Y,TextureLoader as We,Matrix4 as Se,Frustum as Ne,Clock as $e,MeshStandardMaterial as ze,Sphere as Ue,Box3 as Te,Vector3 as F}from"three";import{GLTFLoader as Ve}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as qe}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Ke}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Xe}from"three/examples/jsm/loaders/KTX2Loader.js";const ge="";globalThis.GLTF_PROGRESSIVE_VERSION=ge,console.debug(`[gltf-progressive] version ${ge}`);let ie="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",me="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(ie+"draco_decoder.js",{method:"head"}).catch(t=>{ie="./include/draco/",me="./include/ktx2/"});function He(t){ie=t}function Ye(t){me=t}let J,pe,Q;function xe(t){J||(J=new Ke,J.setDecoderPath(ie),J.setDecoderConfig({type:"js"})),Q||(Q=new Xe,Q.setTranscoderPath(me)),pe||(pe=qe),t?Q.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ve(t){t.dracoLoader||t.setDRACOLoader(J),t.ktx2Loader||t.setKTX2Loader(Q),t.meshoptDecoder||t.setMeshoptDecoder(pe)}Z("debugprogressive");function Z(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Je(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const 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 le;function Qe(){return le!==void 0||(le=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),Z("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",le)),le}const ye=Symbol("needle:raycast-mesh");function ae(t){return t?.[ye]instanceof oe?t[ye]:null}function Ee(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!ae(t)){const s=et(e);s.userData={isRaycastMesh:!0},t[ye]=s}}function Ze(t=!0){if(t){if(ee)return;const e=ee=K.prototype.raycast;K.prototype.raycast=function(s,o){const r=this,n=ae(r);let i;n&&r.isMesh&&(i=r.geometry,r.geometry=n),e.call(this,s,o),i&&(r.geometry=i)}}else{if(!ee)return;K.prototype.raycast=ee,ee=null}}let ee=null;function et(t){const e=new oe;for(const s in t.attributes)e.setAttribute(s,t.getAttribute(s));return e.setIndex(t.getIndex()),e}const N=new Array,j="NEEDLE_progressive",y=Z("debugprogressive"),Le=Symbol("needle-progressive-texture"),te=new Map,Me=new Set;if(y){let t=function(){e+=1,console.log("Toggle LOD level",e,te),te.forEach((r,n)=>{for(const i of r.keys){const l=n[i];if(l!=null){if(l.isBufferGeometry===!0){const u=b.getMeshLODInformation(l),a=u?Math.min(e,u.lods.length):0;n["DEBUG:LOD"]=e,b.assignMeshLOD(n,a),u&&(s=Math.max(s,u.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,b.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,Me&&Me.forEach(n=>{n.name!="BackgroundCubeMaterial"&&n.glyphMap==null&&"wireframe"in n&&(n.wireframe=o)}))})}function Ae(t,e,s){var o;if(!y)return;te.has(t)||te.set(t,{keys:[],sourceId:s});const r=te.get(t);((o=r?.keys)==null?void 0:o.includes(e))==!1&&r.keys.push(e)}const w=class{constructor(t,e){d(this,"parser"),d(this,"url"),d(this,"_isLoadingMesh"),d(this,"loadMesh",s=>{var o,r;if(this._isLoadingMesh)return null;const n=(r=(o=this.parser.json.meshes[s])==null?void 0:o.extensions)==null?void 0:r[j];return n?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",s).then(i=>{var l;return this._isLoadingMesh=!1,i&&w.registerMesh(this.url,n.guid,i,(l=n.lods)==null?void 0:l.length,void 0,n),i})):null}),y&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return j}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const 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(y==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const l of Object.keys(i.uniforms)){const u=i.uniforms[l].value;u?.isTexture===!0&&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 p=0;p<a.lods.length;p++){const c=a.lods[p];c.width&&(l.lods[p]=l.lods[p]||{min_height:1/0,max_height:0},l.lods[p].min_height=Math.min(l.lods[p].min_height,c.height),l.lods[p].max_height=Math.max(l.lods[p].max_height,c.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 K||t.isMesh===!0){const o=t.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const n of N)(s=n.onBeforeGetLODMesh)==null||s.call(n,t,e);return t["LOD:requested level"]=e,w.getOrLoadLOD(o,e).then(n=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(n)){const i=r.index||0;n=n[i]}n&&o!=n&&(n?.isBufferGeometry?(t.geometry=n,y&&Ae(t,"geometry",r.url)):y&&console.error("Invalid LOD geometry",n))}return n}).catch(n=>(console.error("Error loading mesh LOD",t,n),null))}else y&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof Fe||t.isMaterial===!0){const s=t,o=[],r=new Array;if(y&&Me.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);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 Y||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 y==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,s,n,r),null}s[o]=r}if(y&&o&&s){const n=this.getAssignedLODInformation(t);n&&Ae(s,o,n.url)}}return r}else y=="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 y&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,r)=>{var n;if(o!=null&&o.extensions){const i=o?.extensions[j];if(i){if(!i.lods){y&&console.warn("Texture has no LODs",i);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const a=this.parser.associations.get(u);a?.textures===r&&(l=!0,w.registerTexture(this.url,u,(n=i.lods)==null?void 0:n.length,r,i))}l||this.parser.getDependency("texture",r).then(u=>{var a;u&&w.registerTexture(this.url,u,(a=i.lods)==null?void 0:a.length,r,i)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const n=o?.extensions[j];if(n&&n.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l?.meshes===r&&w.registerMesh(this.url,n.guid,i,n.lods.length,l.primitives,n)}}}}),null}static async getOrLoadLOD(t,e){var s,o,r,n;const i=y=="verbose",l=t.userData.LODS;if(!l)return null;const u=l?.key;let a;if(t.isTexture===!0){const p=t;p.source&&p.source[Le]&&(a=p.source[Le])}if(a||(a=w.lodInfos.get(u)),a){if(e>0){let f=!1;const S=Array.isArray(a.lods);if(S&&e>=a.lods.length?f=!0:S||(f=!0),f)return this.lowresCache.get(u)}const p=Array.isArray(a.lods)?(s=a.lods[e])==null?void 0:s.path:a.lods;if(!p)return y&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const c=Je(l.url,p);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const f=c+"_"+a.guid,S=this.previouslyLoaded.get(f);if(S!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${f}`);let g=await S.catch(E=>(console.error(`Error loading LOD ${e} from ${c}
|
|
2
|
-
`,E),null)),x=!1;if(
|
|
3
|
-
`,
|
|
1
|
+
var Re=Object.defineProperty,Ge=(t,e,s)=>e in t?Re(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s,d=(t,e,s)=>(Ge(t,typeof e!="symbol"?e+"":e,s),s),be=(t,e,s)=>{if(!e.has(t))throw TypeError("Cannot "+s)},v=(t,e,s)=>(be(t,e,"read from private field"),s?s.call(t):e.get(t)),q=(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)},F=(t,e,s,o)=>(be(t,e,"write to private field"),o?o.call(t,s):e.set(t,s),s);import{BufferGeometry as oe,Mesh as X,Material as Fe,Texture as Y,TextureLoader as We,Matrix4 as Se,Frustum as Ne,Clock as $e,MeshStandardMaterial as ze,Sphere as Ve,Box3 as Te,Vector3 as W}from"three";import{GLTFLoader as Ue}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as qe}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Xe}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Ke}from"three/examples/jsm/loaders/KTX2Loader.js";const ge="";globalThis.GLTF_PROGRESSIVE_VERSION=ge,console.debug(`[gltf-progressive] version ${ge}`);let ie="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",me="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(ie+"draco_decoder.js",{method:"head"}).catch(t=>{ie="./include/draco/",me="./include/ktx2/"});function He(t){ie=t}function Ye(t){me=t}let J,pe,Q;function xe(t){J||(J=new Xe,J.setDecoderPath(ie),J.setDecoderConfig({type:"js"})),Q||(Q=new Ke,Q.setTranscoderPath(me)),pe||(pe=qe),t?Q.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ve(t){t.dracoLoader||t.setDRACOLoader(J),t.ktx2Loader||t.setKTX2Loader(Q),t.meshoptDecoder||t.setMeshoptDecoder(pe)}Z("debugprogressive");function Z(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Je(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const 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 le;function Qe(){return le!==void 0||(le=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),Z("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",le)),le}const ye=Symbol("needle:raycast-mesh");function ae(t){return t?.[ye]instanceof oe?t[ye]:null}function Ee(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!ae(t)){const s=et(e);s.userData={isRaycastMesh:!0},t[ye]=s}}function Ze(t=!0){if(t){if(ee)return;const e=ee=X.prototype.raycast;X.prototype.raycast=function(s,o){const r=this,n=ae(r);let i;n&&r.isMesh&&(i=r.geometry,r.geometry=n),e.call(this,s,o),i&&(r.geometry=i)}}else{if(!ee)return;X.prototype.raycast=ee,ee=null}}let ee=null;function et(t){const e=new oe;for(const s in t.attributes)e.setAttribute(s,t.getAttribute(s));return e.setIndex(t.getIndex()),e}const $=new Array,j="NEEDLE_progressive",y=Z("debugprogressive"),Le=Symbol("needle-progressive-texture"),te=new Map,Me=new Set;if(y){let t=function(){e+=1,console.log("Toggle LOD level",e,te),te.forEach((r,n)=>{for(const i of r.keys){const l=n[i];if(l!=null){if(l.isBufferGeometry===!0){const u=O.getMeshLODInformation(l),a=u?Math.min(e,u.lods.length):0;n["DEBUG:LOD"]=e,O.assignMeshLOD(n,a),u&&(s=Math.max(s,u.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,O.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,Me&&Me.forEach(n=>{n.name!="BackgroundCubeMaterial"&&n.glyphMap==null&&"wireframe"in n&&(n.wireframe=o)}))})}function Ae(t,e,s){var o;if(!y)return;te.has(t)||te.set(t,{keys:[],sourceId:s});const r=te.get(t);((o=r?.keys)==null?void 0:o.includes(e))==!1&&r.keys.push(e)}const w=class{constructor(t,e){d(this,"parser"),d(this,"url"),d(this,"_isLoadingMesh"),d(this,"loadMesh",s=>{var o,r;if(this._isLoadingMesh)return null;const n=(r=(o=this.parser.json.meshes[s])==null?void 0:o.extensions)==null?void 0:r[j];return n?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",s).then(i=>{var l;return this._isLoadingMesh=!1,i&&w.registerMesh(this.url,n.guid,i,(l=n.lods)==null?void 0:l.length,void 0,n),i})):null}),y&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return j}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const 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(y==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const l of Object.keys(i.uniforms)){const u=i.uniforms[l].value;u?.isTexture===!0&&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 p=0;p<a.lods.length;p++){const c=a.lods[p];c.width&&(l.lods[p]=l.lods[p]||{min_height:1/0,max_height:0},l.lods[p].min_height=Math.min(l.lods[p].min_height,c.height),l.lods[p].max_height=Math.max(l.lods[p].max_height,c.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 X||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(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(n)){const i=r.index||0;n=n[i]}n&&o!=n&&(n?.isBufferGeometry?(t.geometry=n,y&&Ae(t,"geometry",r.url)):y&&console.error("Invalid LOD geometry",n))}return n}).catch(n=>(console.error("Error loading mesh LOD",t,n),null))}else y&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof Fe||t.isMaterial===!0){const s=t,o=[],r=new Array;if(y&&Me.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);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 Y||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 y==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,s,n,r),null}s[o]=r}if(y&&o&&s){const n=this.getAssignedLODInformation(t);n&&Ae(s,o,n.url)}}return r}else y=="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 y&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,r)=>{var n;if(o!=null&&o.extensions){const i=o?.extensions[j];if(i){if(!i.lods){y&&console.warn("Texture has no LODs",i);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const a=this.parser.associations.get(u);a?.textures===r&&(l=!0,w.registerTexture(this.url,u,(n=i.lods)==null?void 0:n.length,r,i))}l||this.parser.getDependency("texture",r).then(u=>{var a;u&&w.registerTexture(this.url,u,(a=i.lods)==null?void 0:a.length,r,i)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const n=o?.extensions[j];if(n&&n.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l?.meshes===r&&w.registerMesh(this.url,n.guid,i,n.lods.length,l.primitives,n)}}}}),null}static async getOrLoadLOD(t,e){var s,o,r,n;const i=y=="verbose",l=t.userData.LODS;if(!l)return null;const u=l?.key;let a;if(t.isTexture===!0){const p=t;p.source&&p.source[Le]&&(a=p.source[Le])}if(a||(a=w.lodInfos.get(u)),a){if(e>0){let f=!1;const S=Array.isArray(a.lods);if(S&&e>=a.lods.length?f=!0:S||(f=!0),f)return this.lowresCache.get(u)}const p=Array.isArray(a.lods)?(s=a.lods[e])==null?void 0:s.path:a.lods;if(!p)return y&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const c=Je(l.url,p);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const f=c+"_"+a.guid,S=this.previouslyLoaded.get(f);if(S!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${f}`);let m=await S.catch(E=>(console.error(`Error loading LOD ${e} from ${c}
|
|
2
|
+
`,E),null)),x=!1;if(m==null||(m instanceof Y&&t instanceof Y?(o=m.image)!=null&&o.data||(r=m.source)!=null&&r.data?m=this.copySettings(t,m):(x=!0,this.previouslyLoaded.delete(f)):m instanceof oe&&t instanceof oe&&((n=m.attributes.position)!=null&&n.array||(x=!0,this.previouslyLoaded.delete(f)))),!x)return m}const M=a,I=new Promise(async(m,x)=>{const E=new Ue;ve(E),y&&(await new Promise(g=>setTimeout(g,1e3)),i&&console.warn("Start loading (delayed) "+c,M.guid));let k=c;if(M&&Array.isArray(M.lods)){const g=M.lods[e];g.hash&&(k+="?v="+g.hash)}const D=await E.loadAsync(k).catch(g=>(console.error(`Error loading LOD ${e} from ${c}
|
|
3
|
+
`,g),null));if(!D)return null;const G=D.parser;i&&console.log("Loading finished "+c,M.guid);let A=0;if(D.parser.json.textures){let g=!1;for(const h of D.parser.json.textures){if(h!=null&&h.extensions){const L=h?.extensions[j];if(L!=null&&L.guid&&L.guid===M.guid){g=!0;break}}A++}if(g){let h=await G.getDependency("texture",A);return h&&w.assignLODInformation(l.url,h,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',c,A,h,f),t instanceof Y&&(h=this.copySettings(t,h)),h&&(h.guid=M.guid),m(h)}else y&&console.warn("Could not find texture with guid",M.guid,D.parser.json)}if(A=0,D.parser.json.meshes){let g=!1;for(const h of D.parser.json.meshes){if(h!=null&&h.extensions){const L=h?.extensions[j];if(L!=null&&L.guid&&L.guid===M.guid){g=!0;break}}A++}if(g){const h=await G.getDependency("mesh",A),L=M;if(i&&console.log(`Loaded Mesh "${h.name}"`,c,A,h,f),h.isMesh===!0){const _=h.geometry;return w.assignLODInformation(l.url,_,u,e,void 0,L.density),m(_)}else{const _=new Array;for(let b=0;b<h.children.length;b++){const N=h.children[b];if(N.isMesh===!0){const U=N.geometry;w.assignLODInformation(l.url,U,u,e,b,L.density),_.push(U)}}return m(_)}}else y&&console.warn("Could not find mesh with guid",M.guid,D.parser.json)}return m(null)});return this.previouslyLoaded.set(f,I),await I}else if(t instanceof Y){i&&console.log("Load texture from uri: "+c);const f=await new We().loadAsync(c);return f?(f.guid=a.guid,f.flipY=!1,f.needsUpdate=!0,f.colorSpace=t.colorSpace,i&&console.log(a,f)):y&&console.warn("failed loading",c),f}}else y&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,s,o,r,n){if(!e)return;e.userData||(e.userData={});const i=new tt(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(),y&&console.warn(`Copying texture settings
|
|
4
4
|
`,t.uuid,`
|
|
5
|
-
`,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let b=w;d(b,"registerTexture",(t,e,s,o,r)=>{if(y&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,r),!e){y&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[Le]=r);const n=r.guid;w.assignLODInformation(t,e,n,s,o,void 0),w.lodInfos.set(n,r),w.lowresCache.set(n,e)}),d(b,"registerMesh",(t,e,s,o,r,n)=>{var i;y&&console.log("> Progressive: register mesh",r,s.name,n,s.uuid,s);const l=s.geometry;if(!l){y&&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&&!ae(s)&&Ee(s,l);for(const a of N)(i=a.onRegisteredNewMesh)==null||i.call(a,s,n)}),d(b,"lodInfos",new Map),d(b,"previouslyLoaded",new Map),d(b,"lowresCache",new Map);class tt{constructor(e,s,o,r,n){d(this,"url"),d(this,"key"),d(this,"level"),d(this,"index"),d(this,"density"),this.url=e,this.key=s,this.level=o,r!=null&&(this.index=r),n!=null&&(this.density=n)}}const C=Z("debugprogressive"),st=Z("noprogressive"),De=Symbol("Needle:LODSManager"),we=Symbol("Needle:LODState"),X=Symbol("Needle:CurrentLOD"),k={mesh_lod:-1,texture_lod:-1};var T,$,_e,H,se,ue,z;const P=class{constructor(t,e){d(this,"context"),d(this,"renderer"),d(this,"projectionScreenMatrix",new Se),d(this,"cameraFrustrum",new Ne),d(this,"targetTriangleDensity",2e5),d(this,"updateInterval","auto"),V(this,T,1),d(this,"pause",!1),d(this,"_lodchangedlisteners",[]),V(this,$,void 0),V(this,_e,new $e),V(this,H,0),V(this,se,0),V(this,ue,0),V(this,z,0),d(this,"_fpsBuffer",[60,60,60,60,60]),d(this,"_sphere",new Ue),d(this,"_tempBox",new Te),d(this,"_tempBox2",new Te),d(this,"tempMatrix",new Se),d(this,"_tempWorldPosition",new F),d(this,"_tempBoxSize",new F),d(this,"_tempBox2Size",new F),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[we]}static addPlugin(t){N.push(t)}static removePlugin(t){const e=N.indexOf(t);e>=0&&N.splice(e,1)}static get(t,e){if(t[De])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[De];const s=new P(t,{engine:"unknown",...e});return t[De]=s,s}get plugins(){return N}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}enable(){if(v(this,$))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;G(this,$,this.renderer.render);const e=this;xe(this.renderer),this.renderer.render=function(s,o){e.renderer.getRenderTarget()==null&&(t=0,G(e,H,v(e,H)+1),G(e,se,v(e,_e).getDelta()),G(e,ue,v(e,ue)+v(e,se)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/v(e,se)),G(e,z,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),C&&v(e,H)%30===0&&console.log("FPS",Math.round(v(e,z)),"Interval:",v(e,T)));const r=v(e,H),n=t++;e.onBeforeRender(s,o,n,r),v(e,$).call(this,s,o),e.onAfterRender(s,o,n,r)}}disable(){v(this,$)&&(this.renderer.render=v(this,$),G(this,$,void 0))}onBeforeRender(t,e,s,o){}onAfterRender(t,e,s,o){var r,n;if(this.pause)return;const i=this.renderer.renderLists.get(t,0),l=i.opaque;let u=!0;if(l.length===1){const a=l[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(u=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(u=!1),u){if(st||(this.updateInterval==="auto"?v(this,z)<40&&v(this,T)<10?(G(this,T,v(this,T)+1),C&&console.warn("\u2193 Reducing LOD updates",v(this,T),v(this,z).toFixed(0))):v(this,z)>=80&&v(this,T)>1&&(G(this,T,v(this,T)-1),C&&console.warn("\u2191 Increasing LOD updates",v(this,T),v(this,z).toFixed(0))):G(this,T,this.updateInterval),v(this,T)>0&&o%v(this,T)!=0))return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const a=this.targetTriangleDensity;for(const c of l){if(c.material&&(((r=c.geometry)==null?void 0:r.type)==="BoxGeometry"||((n=c.geometry)==null?void 0:n.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){C&&(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(C==="color"&&c.material&&!c.object.progressive_debug_color){c.object.progressive_debug_color=!0;const S=Math.random()*16777215,M=new ze({color:S});c.object.material=M}const f=c.object;(f instanceof K||f.isMesh)&&this.updateLODs(t,e,f,a,o)}const p=i.transparent;for(const c of p){const f=c.object;(f instanceof K||f.isMesh)&&this.updateLODs(t,e,f,a,o)}}}updateLODs(t,e,s,o,r){var n,i;s.userData||(s.userData={});let l=s[we];if(l||(l=new rt,s[we]=l),l.frames++<2)return;for(const a of N)(n=a.onBeforeUpdateLOD)==null||n.call(a,this.renderer,t,e,s);this.calculateLodLevel(e,s,l,o,k),k.mesh_lod=Math.round(k.mesh_lod),k.texture_lod=Math.round(k.texture_lod),k.mesh_lod>=0&&this.loadProgressiveMeshes(s,k.mesh_lod);let u=k.texture_lod;if(s.material&&u>=0){const a=s["DEBUG:LOD"];a!=null&&(u=a),this.loadProgressiveTextures(s.material,u)}for(const a of N)(i=a.onAfterUpdatedLOD)==null||i.call(a,this.renderer,t,e,s,k);l.lastLodLevel_Mesh=k.mesh_lod,l.lastLodLevel_Texture=k.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[X]===void 0||e<t[X])&&(s=!0),s&&(t[X]=e,b.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[X]!==e){t[X]=e;const s=t.geometry;return b.assignMeshLOD(t,e).then(o=>(o&&t[X]==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,i;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let l=10+1,u=!1;if(C&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=b.getMeshLODInformation(e.geometry),p=a?.lods,c=p&&p.length>0,f=b.getMaterialMinMaxLODsCount(e.material),S=f?.min_count!=1/0&&f.min_count>0&&f.max_count>0;if(!c&&!S){r.mesh_lod=0,r.texture_lod=0;return}if(c||(u=!0,l=0),!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e))){r.mesh_lod=99,r.texture_lod=99;return}const M=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let A=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const g=e;g.boundingBox||g.computeBoundingBox(),A=g.boundingBox}if(A&&t.isPerspectiveCamera){const g=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const m=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(m)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(A),this._tempBox.applyMatrix4(e.matrixWorld),P.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&g.fov>70){const m=this._tempBox.min,h=this._tempBox.max;let L=m.x,_=m.y,O=h.x,W=h.y;const U=2,he=1.5,re=(m.x+h.x)*.5,ne=(m.y+h.y)*.5;L=(L-re)*U+re,_=(_-ne)*U+ne,O=(O-re)*U+re,W=(W-ne)*U+ne;const ke=L<0&&O>0?0:Math.min(Math.abs(m.x),Math.abs(h.x)),je=_<0&&W>0?0:Math.min(Math.abs(m.y),Math.abs(h.y)),fe=Math.max(ke,je);s.lastCentrality=(he-fe)*(he-fe)*(he-fe)}else s.lastCentrality=1;const x=this._tempBox.getSize(this._tempBoxSize);x.multiplyScalar(.5),screen.availHeight>0&&M>0&&x.multiplyScalar(M/screen.availHeight),x.x*=g.aspect;const E=t.matrixWorldInverse,I=this._tempBox2;I.copy(A),I.applyMatrix4(e.matrixWorld),I.applyMatrix4(E);const D=I.getSize(this._tempBox2Size),q=Math.max(D.x,D.y);if(Math.max(x.x,x.y)!=0&&q!=0&&(x.z=D.z/Math.max(D.x,D.y)*Math.max(x.x,x.y)),s.lastScreenCoverage=Math.max(x.x,x.y,x.z),s.lastScreenspaceVolume.copy(x),s.lastScreenCoverage*=s.lastCentrality,C&&P.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const h=P.corner0,L=P.corner1,_=P.corner2,O=P.corner3;h.copy(this._tempBox.min),L.copy(this._tempBox.max),L.x=h.x,_.copy(this._tempBox.max),_.y=h.y,O.copy(this._tempBox.max);const W=(h.z+O.z)*.5;h.z=L.z=_.z=O.z=W,h.applyMatrix4(m),L.applyMatrix4(m),_.applyMatrix4(m),O.applyMatrix4(m),P.debugDrawLine(h,L,255),P.debugDrawLine(h,_,255),P.debugDrawLine(L,O,255),P.debugDrawLine(_,O,255)}let B=999;if(p&&s.lastScreenCoverage>0){for(let m=0;m<p.length;m++)if(p[m].density/s.lastScreenCoverage<o){B=m;break}}B<l&&(l=B,u=!0)}if(u?r.mesh_lod=l:r.mesh_lod=s.lastLodLevel_Mesh,C&&r.mesh_lod!=s.lastLodLevel_Mesh){const g=p?.[r.mesh_lod];g&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} \u2192 ${r.mesh_lod} (${g.density.toFixed(0)}) - ${e.name}`)}if(S)if(s.lastLodLevel_Texture<0){if(r.texture_lod=f.max_count-1,C){const g=f.lods[f.max_count-1];C&&console.log(`First Texture LOD ${r.texture_lod} (${g.max_height}px) - ${e.name}`)}}else{const g=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let x=s.lastScreenCoverage*2;((i=this.context)==null?void 0:i.engine)==="model-viewer"&&(x*=2);const E=M/window.devicePixelRatio*x;for(let I=f.lods.length-1;I>=0;I--){let D=f.lods[I];if(!(Qe()&&D.max_height>4096)&&D.max_height>E){if(r.texture_lod=I,r.texture_lod<s.lastLodLevel_Texture){const q=D.max_height;C&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} \u2192 ${r.texture_lod} = ${q}px
|
|
6
|
-
Screensize: ${
|
|
7
|
-
${e.name}`)}break}}}else r.texture_lod=0}};let R=P;T=new WeakMap
|
|
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 it),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 it{constructor(){d(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[ce]==!0)return;s[ce]=!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,p,c;if(u[ce]==!0)return;u[ce]=!0,u.userData&&(u.userData.LOD=-1);const f=Object.keys(u);for(let S=0;S<f.length;S++){const M=f[S],
|
|
5
|
+
`,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let O=w;d(O,"registerTexture",(t,e,s,o,r)=>{if(y&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,r),!e){y&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[Le]=r);const n=r.guid;w.assignLODInformation(t,e,n,s,o,void 0),w.lodInfos.set(n,r),w.lowresCache.set(n,e)}),d(O,"registerMesh",(t,e,s,o,r,n)=>{var i;y&&console.log("> Progressive: register mesh",r,s.name,n,s.uuid,s);const l=s.geometry;if(!l){y&&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&&!ae(s)&&Ee(s,l);for(const a of $)(i=a.onRegisteredNewMesh)==null||i.call(a,s,n)}),d(O,"lodInfos",new Map),d(O,"previouslyLoaded",new Map),d(O,"lowresCache",new Map);class tt{constructor(e,s,o,r,n){d(this,"url"),d(this,"key"),d(this,"level"),d(this,"index"),d(this,"density"),this.url=e,this.key=s,this.level=o,r!=null&&(this.index=r),n!=null&&(this.density=n)}}const B=Z("debugprogressive"),st=Z("noprogressive"),De=Symbol("Needle:LODSManager"),we=Symbol("Needle:LODState"),K=Symbol("Needle:CurrentLOD"),C={mesh_lod:-1,texture_lod:-1};var T,z,_e,H,se,ue,V;const P=class{constructor(t,e){d(this,"context"),d(this,"renderer"),d(this,"projectionScreenMatrix",new Se),d(this,"cameraFrustrum",new Ne),d(this,"targetTriangleDensity",2e5),d(this,"updateInterval","auto"),q(this,T,1),d(this,"pause",!1),d(this,"_lodchangedlisteners",[]),q(this,z,void 0),q(this,_e,new $e),q(this,H,0),q(this,se,0),q(this,ue,0),q(this,V,0),d(this,"_fpsBuffer",[60,60,60,60,60]),d(this,"_sphere",new Ve),d(this,"_tempBox",new Te),d(this,"_tempBox2",new Te),d(this,"tempMatrix",new Se),d(this,"_tempWorldPosition",new W),d(this,"_tempBoxSize",new W),d(this,"_tempBox2Size",new W),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[we]}static addPlugin(t){$.push(t)}static removePlugin(t){const e=$.indexOf(t);e>=0&&$.splice(e,1)}static get(t,e){if(t[De])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[De];const s=new P(t,{engine:"unknown",...e});return t[De]=s,s}get plugins(){return $}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}enable(){if(v(this,z))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;F(this,z,this.renderer.render);const e=this;xe(this.renderer),this.renderer.render=function(s,o){e.renderer.getRenderTarget()==null&&(t=0,F(e,H,v(e,H)+1),F(e,se,v(e,_e).getDelta()),F(e,ue,v(e,ue)+v(e,se)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/v(e,se)),F(e,V,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),B&&v(e,H)%30===0&&console.log("FPS",Math.round(v(e,V)),"Interval:",v(e,T)));const r=v(e,H),n=t++;e.onBeforeRender(s,o,n,r),v(e,z).call(this,s,o),e.onAfterRender(s,o,n,r)}}disable(){v(this,z)&&(this.renderer.render=v(this,z),F(this,z,void 0))}onBeforeRender(t,e,s,o){}onAfterRender(t,e,s,o){var r,n;if(this.pause)return;const i=this.renderer.renderLists.get(t,0),l=i.opaque;let u=!0;if(l.length===1){const a=l[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(u=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(u=!1),u){if(st||(this.updateInterval==="auto"?v(this,V)<40&&v(this,T)<10?(F(this,T,v(this,T)+1),B&&console.warn("\u2193 Reducing LOD updates",v(this,T),v(this,V).toFixed(0))):v(this,V)>=60&&v(this,T)>1&&(F(this,T,v(this,T)-1),B&&console.warn("\u2191 Increasing LOD updates",v(this,T),v(this,V).toFixed(0))):F(this,T,this.updateInterval),v(this,T)>0&&o%v(this,T)!=0))return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const a=this.targetTriangleDensity;for(const c of l){if(c.material&&(((r=c.geometry)==null?void 0:r.type)==="BoxGeometry"||((n=c.geometry)==null?void 0:n.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){B&&(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(B==="color"&&c.material&&!c.object.progressive_debug_color){c.object.progressive_debug_color=!0;const S=Math.random()*16777215,M=new ze({color:S});c.object.material=M}const f=c.object;(f instanceof X||f.isMesh)&&this.updateLODs(t,e,f,a,o)}const p=i.transparent;for(const c of p){const f=c.object;(f instanceof X||f.isMesh)&&this.updateLODs(t,e,f,a,o)}}}updateLODs(t,e,s,o,r){var n,i;s.userData||(s.userData={});let l=s[we];if(l||(l=new rt,s[we]=l),l.frames++<2)return;for(const a of $)(n=a.onBeforeUpdateLOD)==null||n.call(a,this.renderer,t,e,s);this.calculateLodLevel(e,s,l,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 u=C.texture_lod;if(s.material&&u>=0){const a=s["DEBUG:LOD"];a!=null&&(u=a),this.loadProgressiveTextures(s.material,u)}for(const a of $)(i=a.onAfterUpdatedLOD)==null||i.call(a,this.renderer,t,e,s,C);l.lastLodLevel_Mesh=C.mesh_lod,l.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[K]===void 0||e<t[K])&&(s=!0),s&&(t[K]=e,O.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[K]!==e){t[K]=e;const s=t.geometry;return O.assignMeshLOD(t,e).then(o=>(o&&t[K]==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,i;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let l=10+1,u=!1;if(B&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=O.getMeshLODInformation(e.geometry),p=a?.lods,c=p&&p.length>0,f=O.getMaterialMinMaxLODsCount(e.material),S=f?.min_count!=1/0&&f.min_count>0&&f.max_count>0;if(!c&&!S){r.mesh_lod=0,r.texture_lod=0;return}if(c||(u=!0,l=0),!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e))){r.mesh_lod=99,r.texture_lod=99;return}const M=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let I=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const m=e;m.boundingBox||m.computeBoundingBox(),I=m.boundingBox}if(I&&t.isPerspectiveCamera){const m=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const g=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(I),this._tempBox.applyMatrix4(e.matrixWorld),P.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&m.fov>70){const g=this._tempBox.min,h=this._tempBox.max;let L=g.x,_=g.y,b=h.x,N=h.y;const U=2,he=1.5,re=(g.x+h.x)*.5,ne=(g.y+h.y)*.5;L=(L-re)*U+re,_=(_-ne)*U+ne,b=(b-re)*U+re,N=(N-ne)*U+ne;const ke=L<0&&b>0?0:Math.min(Math.abs(g.x),Math.abs(h.x)),je=_<0&&N>0?0:Math.min(Math.abs(g.y),Math.abs(h.y)),fe=Math.max(ke,je);s.lastCentrality=(he-fe)*(he-fe)*(he-fe)}else s.lastCentrality=1;const x=this._tempBox.getSize(this._tempBoxSize);x.multiplyScalar(.5),screen.availHeight>0&&M>0&&x.multiplyScalar(M/screen.availHeight),x.x*=m.aspect;const E=t.matrixWorldInverse,k=this._tempBox2;k.copy(I),k.applyMatrix4(e.matrixWorld),k.applyMatrix4(E);const D=k.getSize(this._tempBox2Size),G=Math.max(D.x,D.y);if(Math.max(x.x,x.y)!=0&&G!=0&&(x.z=D.z/Math.max(D.x,D.y)*Math.max(x.x,x.y)),s.lastScreenCoverage=Math.max(x.x,x.y,x.z),s.lastScreenspaceVolume.copy(x),s.lastScreenCoverage*=s.lastCentrality,B&&P.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const h=P.corner0,L=P.corner1,_=P.corner2,b=P.corner3;h.copy(this._tempBox.min),L.copy(this._tempBox.max),L.x=h.x,_.copy(this._tempBox.max),_.y=h.y,b.copy(this._tempBox.max);const N=(h.z+b.z)*.5;h.z=L.z=_.z=b.z=N,h.applyMatrix4(g),L.applyMatrix4(g),_.applyMatrix4(g),b.applyMatrix4(g),P.debugDrawLine(h,L,255),P.debugDrawLine(h,_,255),P.debugDrawLine(L,b,255),P.debugDrawLine(_,b,255)}let A=999;if(p&&s.lastScreenCoverage>0){for(let g=0;g<p.length;g++)if(p[g].density/s.lastScreenCoverage<o){A=g;break}}A<l&&(l=A,u=!0)}if(u?r.mesh_lod=l:r.mesh_lod=s.lastLodLevel_Mesh,B&&r.mesh_lod!=s.lastLodLevel_Mesh){const m=p?.[r.mesh_lod];m&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} \u2192 ${r.mesh_lod} (${m.density.toFixed(0)}) - ${e.name}`)}if(S){const m="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=f.max_count-1,B){const x=f.lods[f.max_count-1];B&&console.log(`First Texture LOD ${r.texture_lod} (${x.max_height}px) - ${e.name}`)}}else{const x=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let E=s.lastScreenCoverage*2;((i=this.context)==null?void 0:i.engine)==="model-viewer"&&(E*=2);const k=M/window.devicePixelRatio*E;for(let D=f.lods.length-1;D>=0;D--){let G=f.lods[D];if(!(m&&G.max_height>=2048)&&!(Qe()&&G.max_height>4096)&&G.max_height>k){if(r.texture_lod=D,r.texture_lod<s.lastLodLevel_Texture){const A=G.max_height;B&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} \u2192 ${r.texture_lod} = ${A}px
|
|
6
|
+
Screensize: ${k.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${x.toFixed(1)}
|
|
7
|
+
${e.name}`)}break}}}}else r.texture_lod=0}};let R=P;T=new WeakMap,z=new WeakMap,_e=new WeakMap,H=new WeakMap,se=new WeakMap,ue=new WeakMap,V=new WeakMap,d(R,"debugDrawLine"),d(R,"corner0",new W),d(R,"corner1",new W),d(R,"corner2",new W),d(R,"corner3",new W),d(R,"_tempPtInside",new W);class rt{constructor(){d(this,"frames",0),d(this,"lastLodLevel_Mesh",-1),d(this,"lastLodLevel_Texture",-1),d(this,"lastScreenCoverage",0),d(this,"lastScreenspaceVolume",new W),d(this,"lastCentrality",0)}}const Ie=Symbol("NEEDLE_mesh_lod"),ce=Symbol("NEEDLE_texture_lod");let de=null;function Oe(){const t=nt();t&&(t.mapURLs(function(e){return Pe(),e}),Pe(),de?.disconnect(),de=new MutationObserver(e=>{e.forEach(s=>{s.addedNodes.forEach(o=>{o instanceof HTMLElement&&o.tagName.toLowerCase()==="model-viewer"&&Ce(o)})})}),de.observe(document,{childList:!0,subtree:!0}))}function nt(){return customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Oe()}),null)}function Pe(){document.querySelectorAll("model-viewer").forEach(t=>{Ce(t)})}const Be=new WeakSet;let ot=0;function Ce(t){if(!t||Be.has(t))return null;Be.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++ot+`
|
|
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 it),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 it{constructor(){d(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[ce]==!0)return;s[ce]=!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,p,c;if(u[ce]==!0)return;u[ce]=!0,u.userData&&(u.userData.LOD=-1);const f=Object.keys(u);for(let S=0;S<f.length;S++){const M=f[S],I=u[M];if(I?.isTexture===!0){const m=(p=(a=I.userData)==null?void 0:a.associations)==null?void 0:p.textures;if(m==null)continue;const x=o.parser.json.textures[m];if(!x){console.warn("Texture data not found for texture index "+m);continue}if((c=x?.extensions)!=null&&c[j]){const E=x.extensions[j];E&&n&&O.registerTexture(n,I,E.lods.length,m,E)}}}};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[Ie]==!0)return;s[Ie]=!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[j];if(l&&i){const u=s.uuid;O.registerMesh(i,u,s,0,l.lods.length,l)}}}function lt(t,e,s,o){xe(e),ve(s),s.register(n=>new O(n,t));const r=R.get(e);return o?.enableLODsManager!==!1&&r.enable(),r}Oe();export{j as EXTENSION_NAME,R as LODsManager,O as NEEDLE_progressive,ge as VERSION,ve as addDracoAndKTX2Loaders,xe as createLoaders,ae as getRaycastMesh,Oe as patchModelViewer,Ee as registerRaycastMesh,He as setDracoDecoderLocation,Ye as setKTX2TranscoderLocation,lt as useNeedleProgressive,Ze as useRaycastMeshes};
|
package/gltf-progressive.umd.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"use strict";var Re=Object.defineProperty;var Ge=(a,t,e)=>t in a?Re(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var d=(a,t,e)=>(Ge(a,typeof t!="symbol"?t+"":t,e),e),be=(a,t,e)=>{if(!t.has(a))throw TypeError("Cannot "+e)};var x=(a,t,e)=>(be(a,t,"read from private field"),e?e.call(a):t.get(a)),K=(a,t,e)=>{if(t.has(a))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(a):t.set(a,e)},$=(a,t,e,r)=>(be(a,t,"write to private field"),r?r.call(a,e):t.set(a,e),e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("three"),Fe=require("three/examples/jsm/loaders/GLTFLoader.js"),Ve=require("three/examples/jsm/libs/meshopt_decoder.module.js"),$e=require("three/examples/jsm/loaders/DRACOLoader.js"),Ne=require("three/examples/jsm/loaders/KTX2Loader.js"),we="";globalThis.GLTF_PROGRESSIVE_VERSION=we;console.debug(`[gltf-progressive] version ${we}`);let ue="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",_e="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(ue+"draco_decoder.js",{method:"head"}).catch(a=>{ue="./include/draco/",_e="./include/ktx2/"});function ze(a){ue=a}function Ue(a){_e=a}let re,Le,se;function ve(a){re||(re=new $e.DRACOLoader,re.setDecoderPath(ue),re.setDecoderConfig({type:"js"})),se||(se=new Ne.KTX2Loader,se.setTranscoderPath(_e)),Le||(Le=Ve.MeshoptDecoder),a?se.detectSupport(a):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function Oe(a){a.dracoLoader||a.setDRACOLoader(re),a.ktx2Loader||a.setKTX2Loader(se),a.meshoptDecoder||a.setMeshoptDecoder(Le)}ie("debugprogressive");function ie(a){const e=new URL(window.location.href).searchParams.get(a);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function We(a,t){if(t===void 0||t.startsWith("./")||t.startsWith("http")||a===void 0)return t;const e=a.lastIndexOf("/");if(e>=0){const r=a.substring(0,e+1);for(;r.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return r+t}return t}let Z;function qe(){return Z!==void 0||(Z=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ie("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",Z)),Z}const Me=Symbol("needle:raycast-mesh");function he(a){return(a==null?void 0:a[Me])instanceof h.BufferGeometry?a[Me]:null}function Ce(a,t){if((a.type==="Mesh"||a.type==="SkinnedMesh")&&!he(a)){const r=Xe(t);r.userData={isRaycastMesh:!0},a[Me]=r}}function Ke(a=!0){if(a){if(ee)return;const t=ee=h.Mesh.prototype.raycast;h.Mesh.prototype.raycast=function(e,r){const i=this,o=he(i);let s;o&&i.isMesh&&(s=i.geometry,i.geometry=o),t.call(this,e,r),s&&(i.geometry=s)}}else{if(!ee)return;h.Mesh.prototype.raycast=ee,ee=null}}let ee=null;function Xe(a){const t=new h.BufferGeometry;for(const e in a.attributes)t.setAttribute(e,a.getAttribute(e));return t.setIndex(a.getIndex()),t}const X=new Array,N="NEEDLE_progressive",M=ie("debugprogressive"),ye=Symbol("needle-progressive-texture"),oe=new Map,De=new Set;if(M){let a=function(){t+=1,console.log("Toggle LOD level",t,oe),oe.forEach((i,o)=>{for(const s of i.keys){const n=o[s];if(n!=null){if(n.isBufferGeometry===!0){const l=b.getMeshLODInformation(n),f=l?Math.min(t,l.lods.length):0;o["DEBUG:LOD"]=t,b.assignMeshLOD(o,f),l&&(e=Math.max(e,l.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=t,b.assignTextureLOD(o,t);break}}}}),t>=e&&(t=-1)},t=-1,e=2,r=!1;window.addEventListener("keyup",i=>{i.key==="p"&&a(),i.key==="w"&&(r=!r,De&&De.forEach(o=>{o.name!="BackgroundCubeMaterial"&&o.glyphMap==null&&"wireframe"in o&&(o.wireframe=r)}))})}function Te(a,t,e){var i;if(!M)return;oe.has(a)||oe.set(a,{keys:[],sourceId:e});const r=oe.get(a);((i=r==null?void 0:r.keys)==null?void 0:i.includes(t))==!1&&r.keys.push(t)}const S=class{constructor(t,e){d(this,"parser");d(this,"url");d(this,"_isLoadingMesh");d(this,"loadMesh",t=>{var r,i;if(this._isLoadingMesh)return null;const e=(i=(r=this.parser.json.meshes[t])==null?void 0:r.extensions)==null?void 0:i[N];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(o=>{var s;return this._isLoadingMesh=!1,o&&S.registerMesh(this.url,e.guid,o,(s=e.lods)==null?void 0:s.length,void 0,e),o})):null});M&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return N}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const r=this,i="LODS:minmax",o=t[i];if(o!=null)return o;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const n of t)this.getMaterialMinMaxLODsCount(n,e);return t[i]=e,e}if(M==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const n=t;for(const l of Object.keys(n.uniforms)){const f=n.uniforms[l].value;(f==null?void 0:f.isTexture)===!0&&s(f,e)}}else if(t.isMaterial)for(const n of Object.keys(t)){const l=t[n];(l==null?void 0:l.isTexture)===!0&&s(l,e)}return t[i]=e,e;function s(n,l){const f=r.getAssignedLODInformation(n);if(f){const c=r.lodInfos.get(f.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 D=0;D<c.lods.length;D++){const u=c.lods[D];u.width&&(l.lods[D]=l.lods[D]||{min_height:1/0,max_height:0},l.lods[D].min_height=Math.min(l.lods[D].min_height,u.height),l.lods[D].max_height=Math.max(l.lods[D].max_height,u.height))}}}}}static hasLODLevelAvailable(t,e){var o;if(Array.isArray(t)){for(const s of t)if(this.hasLODLevelAvailable(s,e))return!0;return!1}if(t.isMaterial===!0){for(const s of Object.keys(t)){const n=t[s];if(n&&n.isTexture&&this.hasLODLevelAvailable(n,e))return!0}return!1}else if(t.isGroup===!0){for(const s of t.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let r,i;if(t.isMesh?r=t.geometry:(t.isBufferGeometry||t.isTexture)&&(r=t),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const s=r.userData.LODS;if(i=this.lodInfos.get(s.key),e===void 0)return i!=null;if(i)return Array.isArray(i.lods)?e<i.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof h.Mesh||t.isMesh===!0){const i=t.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of X)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,S.getOrLoadLOD(i,e).then(s=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(s)){const n=o.index||0;s=s[n]}s&&i!=s&&((s==null?void 0:s.isBufferGeometry)?(t.geometry=s,M&&Te(t,"geometry",o.url)):M&&console.error("Invalid LOD geometry",s))}return s}).catch(s=>(console.error("Error loading mesh LOD",t,s),null))}else M&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof h.Material||t.isMaterial===!0){const r=t,i=[],o=new Array;if(M&&De.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const n of Object.keys(s.uniforms)){const l=s.uniforms[n].value;if((l==null?void 0:l.isTexture)===!0){const f=this.assignTextureLODForSlot(l,e,r,n);i.push(f),o.push(n)}}}else for(const s of Object.keys(r)){const n=r[s];if((n==null?void 0:n.isTexture)===!0){const l=this.assignTextureLODForSlot(n,e,r,s);i.push(l),o.push(s)}}return Promise.all(i).then(s=>{const n=new Array;for(let l=0;l<s.length;l++){const f=s[l],c=o[l];f&&f.isTexture===!0?n.push({material:r,slot:c,texture:f,level:e}):n.push({material:r,slot:c,texture:null,level:e})}return n})}if(t instanceof h.Texture||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,i){return(t==null?void 0:t.isTexture)!==!0?Promise.resolve(null):i==="glyphMap"?Promise.resolve(t):S.getOrLoadLOD(t,e).then(o=>{if(Array.isArray(o))return null;if((o==null?void 0:o.isTexture)===!0){if(o!=t){if(r&&i){const s=r[i];if(s){const n=this.getAssignedLODInformation(s);if(n&&(n==null?void 0:n.level)<e)return M==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,e,r,s,o),null}r[i]=o}if(M&&i&&r){const s=this.getAssignedLODInformation(t);s&&Te(r,i,s.url)}}return o}else M=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(o=>(console.error("Error loading LOD",t,o),null))}afterRoot(t){var e,r;return M&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((i,o)=>{var s;if(i!=null&&i.extensions){const n=i==null?void 0:i.extensions[N];if(n){if(!n.lods){M&&console.warn("Texture has no LODs",n);return}let l=!1;for(const f of this.parser.associations.keys())if(f.isTexture===!0){const c=this.parser.associations.get(f);(c==null?void 0:c.textures)===o&&(l=!0,S.registerTexture(this.url,f,(s=n.lods)==null?void 0:s.length,o,n))}l||this.parser.getDependency("texture",o).then(f=>{var c;f&&S.registerTexture(this.url,f,(c=n.lods)==null?void 0:c.length,o,n)})}}}),(r=this.parser.json.meshes)==null||r.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[N];if(s&&s.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const l=this.parser.associations.get(n);(l==null?void 0:l.meshes)===o&&S.registerMesh(this.url,s.guid,n,s.lods.length,l.primitives,s)}}}}),null}static async getOrLoadLOD(t,e){var n,l,f,c;const r=M=="verbose",i=t.userData.LODS;if(!i)return null;const o=i==null?void 0:i.key;let s;if(t.isTexture===!0){const D=t;D.source&&D.source[ye]&&(s=D.source[ye])}if(s||(s=S.lodInfos.get(o)),s){if(e>0){let m=!1;const v=Array.isArray(s.lods);if(v&&e>=s.lods.length?m=!0:v||(m=!0),m)return this.lowresCache.get(o)}const D=Array.isArray(s.lods)?(n=s.lods[e])==null?void 0:n.path:s.lods;if(!D)return M&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,s)),null;const u=We(i.url,D);if(u.endsWith(".glb")||u.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const m=u+"_"+s.guid,v=this.previouslyLoaded.get(m);if(v!==void 0){r&&console.log(`LOD ${e} was already loading/loaded: ${m}`);let y=await v.catch(Y=>(console.error(`Error loading LOD ${e} from ${u}
|
|
2
|
-
`,
|
|
3
|
-
`,
|
|
1
|
+
"use strict";var Re=Object.defineProperty;var Ge=(a,t,e)=>t in a?Re(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var d=(a,t,e)=>(Ge(a,typeof t!="symbol"?t+"":t,e),e),be=(a,t,e)=>{if(!t.has(a))throw TypeError("Cannot "+e)};var x=(a,t,e)=>(be(a,t,"read from private field"),e?e.call(a):t.get(a)),X=(a,t,e)=>{if(t.has(a))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(a):t.set(a,e)},V=(a,t,e,r)=>(be(a,t,"write to private field"),r?r.call(a,e):t.set(a,e),e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("three"),Fe=require("three/examples/jsm/loaders/GLTFLoader.js"),Ve=require("three/examples/jsm/libs/meshopt_decoder.module.js"),$e=require("three/examples/jsm/loaders/DRACOLoader.js"),Ne=require("three/examples/jsm/loaders/KTX2Loader.js"),we="";globalThis.GLTF_PROGRESSIVE_VERSION=we;console.debug(`[gltf-progressive] version ${we}`);let ue="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ve="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(ue+"draco_decoder.js",{method:"head"}).catch(a=>{ue="./include/draco/",ve="./include/ktx2/"});function ze(a){ue=a}function Ue(a){ve=a}let re,Le,se;function _e(a){re||(re=new $e.DRACOLoader,re.setDecoderPath(ue),re.setDecoderConfig({type:"js"})),se||(se=new Ne.KTX2Loader,se.setTranscoderPath(ve)),Le||(Le=Ve.MeshoptDecoder),a?se.detectSupport(a):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function Oe(a){a.dracoLoader||a.setDRACOLoader(re),a.ktx2Loader||a.setKTX2Loader(se),a.meshoptDecoder||a.setMeshoptDecoder(Le)}oe("debugprogressive");function oe(a){const e=new URL(window.location.href).searchParams.get(a);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function We(a,t){if(t===void 0||t.startsWith("./")||t.startsWith("http")||a===void 0)return t;const e=a.lastIndexOf("/");if(e>=0){const r=a.substring(0,e+1);for(;r.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return r+t}return t}let Z;function qe(){return Z!==void 0||(Z=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),oe("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",Z)),Z}const Me=Symbol("needle:raycast-mesh");function he(a){return(a==null?void 0:a[Me])instanceof h.BufferGeometry?a[Me]:null}function Ce(a,t){if((a.type==="Mesh"||a.type==="SkinnedMesh")&&!he(a)){const r=Xe(t);r.userData={isRaycastMesh:!0},a[Me]=r}}function Ke(a=!0){if(a){if(ee)return;const t=ee=h.Mesh.prototype.raycast;h.Mesh.prototype.raycast=function(e,r){const o=this,i=he(o);let s;i&&o.isMesh&&(s=o.geometry,o.geometry=i),t.call(this,e,r),s&&(o.geometry=s)}}else{if(!ee)return;h.Mesh.prototype.raycast=ee,ee=null}}let ee=null;function Xe(a){const t=new h.BufferGeometry;for(const e in a.attributes)t.setAttribute(e,a.getAttribute(e));return t.setIndex(a.getIndex()),t}const Y=new Array,$="NEEDLE_progressive",M=oe("debugprogressive"),ye=Symbol("needle-progressive-texture"),ie=new Map,De=new Set;if(M){let a=function(){t+=1,console.log("Toggle LOD level",t,ie),ie.forEach((o,i)=>{for(const s of o.keys){const n=i[s];if(n!=null){if(n.isBufferGeometry===!0){const l=b.getMeshLODInformation(n),f=l?Math.min(t,l.lods.length):0;i["DEBUG:LOD"]=t,b.assignMeshLOD(i,f),l&&(e=Math.max(e,l.lods.length-1))}else if(i.isMaterial===!0){i["DEBUG:LOD"]=t,b.assignTextureLOD(i,t);break}}}}),t>=e&&(t=-1)},t=-1,e=2,r=!1;window.addEventListener("keyup",o=>{o.key==="p"&&a(),o.key==="w"&&(r=!r,De&&De.forEach(i=>{i.name!="BackgroundCubeMaterial"&&i.glyphMap==null&&"wireframe"in i&&(i.wireframe=r)}))})}function Te(a,t,e){var o;if(!M)return;ie.has(a)||ie.set(a,{keys:[],sourceId:e});const r=ie.get(a);((o=r==null?void 0:r.keys)==null?void 0:o.includes(t))==!1&&r.keys.push(t)}const O=class{constructor(t,e){d(this,"parser");d(this,"url");d(this,"_isLoadingMesh");d(this,"loadMesh",t=>{var r,o;if(this._isLoadingMesh)return null;const e=(o=(r=this.parser.json.meshes[t])==null?void 0:r.extensions)==null?void 0:o[$];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(i=>{var s;return this._isLoadingMesh=!1,i&&O.registerMesh(this.url,e.guid,i,(s=e.lods)==null?void 0:s.length,void 0,e),i})):null});M&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return $}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const r=this,o="LODS:minmax",i=t[o];if(i!=null)return i;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const n of t)this.getMaterialMinMaxLODsCount(n,e);return t[o]=e,e}if(M==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const n=t;for(const l of Object.keys(n.uniforms)){const f=n.uniforms[l].value;(f==null?void 0:f.isTexture)===!0&&s(f,e)}}else if(t.isMaterial)for(const n of Object.keys(t)){const l=t[n];(l==null?void 0:l.isTexture)===!0&&s(l,e)}return t[o]=e,e;function s(n,l){const f=r.getAssignedLODInformation(n);if(f){const c=r.lodInfos.get(f.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 D=0;D<c.lods.length;D++){const u=c.lods[D];u.width&&(l.lods[D]=l.lods[D]||{min_height:1/0,max_height:0},l.lods[D].min_height=Math.min(l.lods[D].min_height,u.height),l.lods[D].max_height=Math.max(l.lods[D].max_height,u.height))}}}}}static hasLODLevelAvailable(t,e){var i;if(Array.isArray(t)){for(const s of t)if(this.hasLODLevelAvailable(s,e))return!0;return!1}if(t.isMaterial===!0){for(const s of Object.keys(t)){const n=t[s];if(n&&n.isTexture&&this.hasLODLevelAvailable(n,e))return!0}return!1}else if(t.isGroup===!0){for(const s of t.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let r,o;if(t.isMesh?r=t.geometry:(t.isBufferGeometry||t.isTexture)&&(r=t),r&&(i=r==null?void 0:r.userData)!=null&&i.LODS){const s=r.userData.LODS;if(o=this.lodInfos.get(s.key),e===void 0)return o!=null;if(o)return Array.isArray(o.lods)?e<o.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof h.Mesh||t.isMesh===!0){const o=t.geometry,i=this.getAssignedLODInformation(o);if(!i)return Promise.resolve(null);for(const s of Y)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,O.getOrLoadLOD(o,e).then(s=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(s)){const n=i.index||0;s=s[n]}s&&o!=s&&((s==null?void 0:s.isBufferGeometry)?(t.geometry=s,M&&Te(t,"geometry",i.url)):M&&console.error("Invalid LOD geometry",s))}return s}).catch(s=>(console.error("Error loading mesh LOD",t,s),null))}else M&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof h.Material||t.isMaterial===!0){const r=t,o=[],i=new Array;if(M&&De.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const n of Object.keys(s.uniforms)){const l=s.uniforms[n].value;if((l==null?void 0:l.isTexture)===!0){const f=this.assignTextureLODForSlot(l,e,r,n);o.push(f),i.push(n)}}}else for(const s of Object.keys(r)){const n=r[s];if((n==null?void 0:n.isTexture)===!0){const l=this.assignTextureLODForSlot(n,e,r,s);o.push(l),i.push(s)}}return Promise.all(o).then(s=>{const n=new Array;for(let l=0;l<s.length;l++){const f=s[l],c=i[l];f&&f.isTexture===!0?n.push({material:r,slot:c,texture:f,level:e}):n.push({material:r,slot:c,texture:null,level:e})}return n})}if(t instanceof h.Texture||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,o){return(t==null?void 0:t.isTexture)!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):O.getOrLoadLOD(t,e).then(i=>{if(Array.isArray(i))return null;if((i==null?void 0:i.isTexture)===!0){if(i!=t){if(r&&o){const s=r[o];if(s){const n=this.getAssignedLODInformation(s);if(n&&(n==null?void 0:n.level)<e)return M==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,e,r,s,i),null}r[o]=i}if(M&&o&&r){const s=this.getAssignedLODInformation(t);s&&Te(r,o,s.url)}}return i}else M=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(i=>(console.error("Error loading LOD",t,i),null))}afterRoot(t){var e,r;return M&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,i)=>{var s;if(o!=null&&o.extensions){const n=o==null?void 0:o.extensions[$];if(n){if(!n.lods){M&&console.warn("Texture has no LODs",n);return}let l=!1;for(const f of this.parser.associations.keys())if(f.isTexture===!0){const c=this.parser.associations.get(f);(c==null?void 0:c.textures)===i&&(l=!0,O.registerTexture(this.url,f,(s=n.lods)==null?void 0:s.length,i,n))}l||this.parser.getDependency("texture",i).then(f=>{var c;f&&O.registerTexture(this.url,f,(c=n.lods)==null?void 0:c.length,i,n)})}}}),(r=this.parser.json.meshes)==null||r.forEach((o,i)=>{if(o!=null&&o.extensions){const s=o==null?void 0:o.extensions[$];if(s&&s.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const l=this.parser.associations.get(n);(l==null?void 0:l.meshes)===i&&O.registerMesh(this.url,s.guid,n,s.lods.length,l.primitives,s)}}}}),null}static async getOrLoadLOD(t,e){var n,l,f,c;const r=M=="verbose",o=t.userData.LODS;if(!o)return null;const i=o==null?void 0:o.key;let s;if(t.isTexture===!0){const D=t;D.source&&D.source[ye]&&(s=D.source[ye])}if(s||(s=O.lodInfos.get(i)),s){if(e>0){let m=!1;const _=Array.isArray(s.lods);if(_&&e>=s.lods.length?m=!0:_||(m=!0),m)return this.lowresCache.get(i)}const D=Array.isArray(s.lods)?(n=s.lods[e])==null?void 0:n.path:s.lods;if(!D)return M&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,s)),null;const u=We(o.url,D);if(u.endsWith(".glb")||u.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const m=u+"_"+s.guid,_=this.previouslyLoaded.get(m);if(_!==void 0){r&&console.log(`LOD ${e} was already loading/loaded: ${m}`);let y=await _.catch(z=>(console.error(`Error loading LOD ${e} from ${u}
|
|
2
|
+
`,z),null)),w=!1;if(y==null||(y instanceof h.Texture&&t instanceof h.Texture?(l=y.image)!=null&&l.data||(f=y.source)!=null&&f.data?y=this.copySettings(t,y):(w=!0,this.previouslyLoaded.delete(m)):y instanceof h.BufferGeometry&&t instanceof h.BufferGeometry&&((c=y.attributes.position)!=null&&c.array||(w=!0,this.previouslyLoaded.delete(m)))),!w)return y}const L=s,F=new Promise(async(y,w)=>{const z=new Fe.GLTFLoader;Oe(z),M&&(await new Promise(S=>setTimeout(S,1e3)),r&&console.warn("Start loading (delayed) "+u,L.guid));let K=u;if(L&&Array.isArray(L.lods)){const S=L.lods[e];S.hash&&(K+="?v="+S.hash)}const T=await z.loadAsync(K).catch(S=>(console.error(`Error loading LOD ${e} from ${u}
|
|
3
|
+
`,S),null));if(!T)return null;const U=T.parser;r&&console.log("Loading finished "+u,L.guid);let E=0;if(T.parser.json.textures){let S=!1;for(const p of T.parser.json.textures){if(p!=null&&p.extensions){const g=p==null?void 0:p.extensions[$];if(g!=null&&g.guid&&g.guid===L.guid){S=!0;break}}E++}if(S){let p=await U.getDependency("texture",E);return p&&O.assignLODInformation(o.url,p,i,e,void 0,void 0),r&&console.log('change "'+t.name+'" → "'+p.name+'"',u,E,p,m),t instanceof h.Texture&&(p=this.copySettings(t,p)),p&&(p.guid=L.guid),y(p)}else M&&console.warn("Could not find texture with guid",L.guid,T.parser.json)}if(E=0,T.parser.json.meshes){let S=!1;for(const p of T.parser.json.meshes){if(p!=null&&p.extensions){const g=p==null?void 0:p.extensions[$];if(g!=null&&g.guid&&g.guid===L.guid){S=!0;break}}E++}if(S){const p=await U.getDependency("mesh",E),g=L;if(r&&console.log(`Loaded Mesh "${p.name}"`,u,E,p,m),p.isMesh===!0){const v=p.geometry;return O.assignLODInformation(o.url,v,i,e,void 0,g.density),y(v)}else{const v=new Array;for(let A=0;A<p.children.length;A++){const P=p.children[A];if(P.isMesh===!0){const C=P.geometry;O.assignLODInformation(o.url,C,i,e,A,g.density),v.push(C)}}return y(v)}}else M&&console.warn("Could not find mesh with guid",L.guid,T.parser.json)}return y(null)});return this.previouslyLoaded.set(m,F),await F}else if(t instanceof h.Texture){r&&console.log("Load texture from uri: "+u);const _=await new h.TextureLoader().loadAsync(u);return _?(_.guid=s.guid,_.flipY=!1,_.needsUpdate=!0,_.colorSpace=t.colorSpace,r&&console.log(s,_)):M&&console.warn("failed loading",u),_}}else M&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,o,i,s){if(!e)return;e.userData||(e.userData={});const n=new Ye(t,r,o,i,s);e.userData.LODS=n}static getAssignedLODInformation(t){var e;return((e=t==null?void 0:t.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),M&&console.warn(`Copying texture settings
|
|
4
4
|
`,t.uuid,`
|
|
5
|
-
`,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let b=S;d(b,"registerTexture",(t,e,r,i,o)=>{if(M&&console.log("> Progressive: register texture",i,e.name,e.uuid,e,o),!e){M&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[ye]=o);const s=o.guid;S.assignLODInformation(t,e,s,r,i,void 0),S.lodInfos.set(s,o),S.lowresCache.set(s,e)}),d(b,"registerMesh",(t,e,r,i,o,s)=>{var f;M&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const n=r.geometry;if(!n){M&&console.warn("gltf-progressive: Register mesh without geometry");return}n.userData||(n.userData={}),S.assignLODInformation(t,n,e,i,o,s.density),S.lodInfos.set(e,s);let l=S.lowresCache.get(e);l?l.push(r.geometry):l=[r.geometry],S.lowresCache.set(e,l),i>0&&!he(r)&&Ce(r,n);for(const c of X)(f=c.onRegisteredNewMesh)==null||f.call(c,r,s)}),d(b,"lodInfos",new Map),d(b,"previouslyLoaded",new Map),d(b,"lowresCache",new Map);class Ye{constructor(t,e,r,i,o){d(this,"url");d(this,"key");d(this,"level");d(this,"index");d(this,"density");this.url=t,this.key=e,this.level=r,i!=null&&(this.index=i),o!=null&&(this.density=o)}}const k=ie("debugprogressive"),He=ie("noprogressive"),me=Symbol("Needle:LODSManager"),xe=Symbol("Needle:LODState"),H=Symbol("Needle:CurrentLOD"),R={mesh_lod:-1,texture_lod:-1};var B,U,fe,j,J,de,W;const C=class{constructor(t,e){d(this,"context");d(this,"renderer");d(this,"projectionScreenMatrix",new h.Matrix4);d(this,"cameraFrustrum",new h.Frustum);d(this,"targetTriangleDensity",2e5);d(this,"updateInterval","auto");K(this,B,1);d(this,"pause",!1);d(this,"_lodchangedlisteners",[]);K(this,U,void 0);K(this,fe,new h.Clock);K(this,j,0);K(this,J,0);K(this,de,0);K(this,W,0);d(this,"_fpsBuffer",[60,60,60,60,60]);d(this,"_sphere",new h.Sphere);d(this,"_tempBox",new h.Box3);d(this,"_tempBox2",new h.Box3);d(this,"tempMatrix",new h.Matrix4);d(this,"_tempWorldPosition",new h.Vector3);d(this,"_tempBoxSize",new h.Vector3);d(this,"_tempBox2Size",new h.Vector3);this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[xe]}static addPlugin(t){X.push(t)}static removePlugin(t){const e=X.indexOf(t);e>=0&&X.splice(e,1)}static get(t,e){if(t[me])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[me];const r=new C(t,{engine:"unknown",...e});return t[me]=r,r}get plugins(){return X}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}enable(){if(x(this,U))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;$(this,U,this.renderer.render);const e=this;ve(this.renderer),this.renderer.render=function(r,i){e.renderer.getRenderTarget()==null&&(t=0,$(e,j,x(e,j)+1),$(e,J,x(e,fe).getDelta()),$(e,de,x(e,de)+x(e,J)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/x(e,J)),$(e,W,e._fpsBuffer.reduce((l,f)=>l+f)/e._fpsBuffer.length),k&&x(e,j)%30===0&&console.log("FPS",Math.round(x(e,W)),"Interval:",x(e,B)));const s=x(e,j),n=t++;e.onBeforeRender(r,i,n,s),x(e,U).call(this,r,i),e.onAfterRender(r,i,n,s)}}disable(){x(this,U)&&(this.renderer.render=x(this,U),$(this,U,void 0))}onBeforeRender(t,e,r,i){}onAfterRender(t,e,r,i){var l,f;if(this.pause)return;const o=this.renderer.renderLists.get(t,0),s=o.opaque;let n=!0;if(s.length===1){const c=s[0].material;(c.name==="EffectMaterial"||c.name==="CopyShader")&&(n=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(n=!1),n){if(He||(this.updateInterval==="auto"?x(this,W)<40&&x(this,B)<10?($(this,B,x(this,B)+1),k&&console.warn("↓ Reducing LOD updates",x(this,B),x(this,W).toFixed(0))):x(this,W)>=80&&x(this,B)>1&&($(this,B,x(this,B)-1),k&&console.warn("↑ Increasing LOD updates",x(this,B),x(this,W).toFixed(0))):$(this,B,this.updateInterval),x(this,B)>0&&i%x(this,B)!=0))return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const c=this.targetTriangleDensity;for(const u of s){if(u.material&&(((l=u.geometry)==null?void 0:l.type)==="BoxGeometry"||((f=u.geometry)==null?void 0:f.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){k&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}switch(u.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(k==="color"&&u.material&&!u.object.progressive_debug_color){u.object.progressive_debug_color=!0;const v=Math.random()*16777215,L=new h.MeshStandardMaterial({color:v});u.object.material=L}const m=u.object;(m instanceof h.Mesh||m.isMesh)&&this.updateLODs(t,e,m,c,i)}const D=o.transparent;for(const u of D){const m=u.object;(m instanceof h.Mesh||m.isMesh)&&this.updateLODs(t,e,m,c,i)}}}updateLODs(t,e,r,i,o){var l,f;r.userData||(r.userData={});let s=r[xe];if(s||(s=new je,r[xe]=s),s.frames++<2)return;for(const c of X)(l=c.onBeforeUpdateLOD)==null||l.call(c,this.renderer,t,e,r);this.calculateLodLevel(e,r,s,i,R),R.mesh_lod=Math.round(R.mesh_lod),R.texture_lod=Math.round(R.texture_lod),R.mesh_lod>=0&&this.loadProgressiveMeshes(r,R.mesh_lod);let n=R.texture_lod;if(r.material&&n>=0){const c=r["DEBUG:LOD"];c!=null&&(n=c),this.loadProgressiveTextures(r.material,n)}for(const c of X)(f=c.onAfterUpdatedLOD)==null||f.call(c,this.renderer,t,e,r,R);s.lastLodLevel_Mesh=R.mesh_lod,s.lastLodLevel_Texture=R.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const i of t)this.loadProgressiveTextures(i,e);return}let r=!1;(t[H]===void 0||e<t[H])&&(r=!0),r&&(t[H]=e,b.assignTextureLOD(t,e).then(i=>{this._lodchangedlisteners.forEach(o=>o({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[H]!==e){t[H]=e;const r=t.geometry;return b.assignMeshLOD(t,e).then(i=>(i&&t[H]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(o=>o({type:"mesh",level:e,object:t})),i))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,i=t.max,o=(r.x+i.x)*.5,s=(r.y+i.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,i,o){var G,z;if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let n=10+1,l=!1;if(k&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const f=b.getMeshLODInformation(e.geometry),c=f==null?void 0:f.lods,D=c&&c.length>0,u=b.getMaterialMinMaxLODsCount(e.material),m=(u==null?void 0:u.min_count)!=1/0&&u.min_count>0&&u.max_count>0;if(!D&&!m){o.mesh_lod=0,o.texture_lod=0;return}if(D||(l=!0,n=0),!((G=this.cameraFrustrum)!=null&&G.intersectsObject(e))){o.mesh_lod=99,o.texture_lod=99;return}const v=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let L=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const y=e;y.boundingBox||y.computeBoundingBox(),L=y.boundingBox}if(L&&t.isPerspectiveCamera){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 g=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(L),this._tempBox.applyMatrix4(e.matrixWorld),C.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&y.fov>70){const g=this._tempBox.min,_=this._tempBox.max;let A=g.x,E=g.y,P=_.x,Q=_.y;const ne=2,ge=1.5,ae=(g.x+_.x)*.5,le=(g.y+_.y)*.5;A=(A-ae)*ne+ae,E=(E-le)*ne+le,P=(P-ae)*ne+ae,Q=(Q-le)*ne+le;const Ie=A<0&&P>0?0:Math.min(Math.abs(g.x),Math.abs(_.x)),ke=E<0&&Q>0?0:Math.min(Math.abs(g.y),Math.abs(_.y)),pe=Math.max(Ie,ke);r.lastCentrality=(ge-pe)*(ge-pe)*(ge-pe)}else r.lastCentrality=1;const w=this._tempBox.getSize(this._tempBoxSize);w.multiplyScalar(.5),screen.availHeight>0&&v>0&&w.multiplyScalar(v/screen.availHeight),w.x*=y.aspect;const Y=t.matrixWorldInverse,F=this._tempBox2;F.copy(L),F.applyMatrix4(e.matrixWorld),F.applyMatrix4(Y);const O=F.getSize(this._tempBox2Size),q=Math.max(O.x,O.y);if(Math.max(w.x,w.y)!=0&&q!=0&&(w.z=O.z/Math.max(O.x,O.y)*Math.max(w.x,w.y)),r.lastScreenCoverage=Math.max(w.x,w.y,w.z),r.lastScreenspaceVolume.copy(w),r.lastScreenCoverage*=r.lastCentrality,k&&C.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const _=C.corner0,A=C.corner1,E=C.corner2,P=C.corner3;_.copy(this._tempBox.min),A.copy(this._tempBox.max),A.x=_.x,E.copy(this._tempBox.max),E.y=_.y,P.copy(this._tempBox.max);const Q=(_.z+P.z)*.5;_.z=A.z=E.z=P.z=Q,_.applyMatrix4(g),A.applyMatrix4(g),E.applyMatrix4(g),P.applyMatrix4(g),C.debugDrawLine(_,A,255),C.debugDrawLine(_,E,255),C.debugDrawLine(A,P,255),C.debugDrawLine(E,P,255)}let T=999;if(c&&r.lastScreenCoverage>0){for(let g=0;g<c.length;g++)if(c[g].density/r.lastScreenCoverage<i){T=g;break}}T<n&&(n=T,l=!0)}if(l?o.mesh_lod=n:o.mesh_lod=r.lastLodLevel_Mesh,k&&o.mesh_lod!=r.lastLodLevel_Mesh){const w=c==null?void 0:c[o.mesh_lod];w&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${o.mesh_lod} (${w.density.toFixed(0)}) - ${e.name}`)}if(m)if(r.lastLodLevel_Texture<0){if(o.texture_lod=u.max_count-1,k){const y=u.lods[u.max_count-1];k&&console.log(`First Texture LOD ${o.texture_lod} (${y.max_height}px) - ${e.name}`)}}else{const y=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let w=r.lastScreenCoverage*2;((z=this.context)==null?void 0:z.engine)==="model-viewer"&&(w*=2);const F=v/window.devicePixelRatio*w;for(let O=u.lods.length-1;O>=0;O--){let q=u.lods[O];if(!(qe()&&q.max_height>4096)&&q.max_height>F){if(o.texture_lod=O,o.texture_lod<r.lastLodLevel_Texture){const V=q.max_height;k&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${o.texture_lod} = ${V}px
|
|
6
|
-
Screensize: ${
|
|
7
|
-
${e.name}`)}break}}}else
|
|
8
|
-
`,a.getAttribute("src"));let t=null,e=null,r=null;for(let
|
|
5
|
+
`,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let b=O;d(b,"registerTexture",(t,e,r,o,i)=>{if(M&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,i),!e){M&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[ye]=i);const s=i.guid;O.assignLODInformation(t,e,s,r,o,void 0),O.lodInfos.set(s,i),O.lowresCache.set(s,e)}),d(b,"registerMesh",(t,e,r,o,i,s)=>{var f;M&&console.log("> Progressive: register mesh",i,r.name,s,r.uuid,r);const n=r.geometry;if(!n){M&&console.warn("gltf-progressive: Register mesh without geometry");return}n.userData||(n.userData={}),O.assignLODInformation(t,n,e,o,i,s.density),O.lodInfos.set(e,s);let l=O.lowresCache.get(e);l?l.push(r.geometry):l=[r.geometry],O.lowresCache.set(e,l),o>0&&!he(r)&&Ce(r,n);for(const c of Y)(f=c.onRegisteredNewMesh)==null||f.call(c,r,s)}),d(b,"lodInfos",new Map),d(b,"previouslyLoaded",new Map),d(b,"lowresCache",new Map);class Ye{constructor(t,e,r,o,i){d(this,"url");d(this,"key");d(this,"level");d(this,"index");d(this,"density");this.url=t,this.key=e,this.level=r,o!=null&&(this.index=o),i!=null&&(this.density=i)}}const R=oe("debugprogressive"),He=oe("noprogressive"),me=Symbol("Needle:LODSManager"),xe=Symbol("Needle:LODState"),H=Symbol("Needle:CurrentLOD"),G={mesh_lod:-1,texture_lod:-1};var I,W,fe,j,J,de,q;const B=class{constructor(t,e){d(this,"context");d(this,"renderer");d(this,"projectionScreenMatrix",new h.Matrix4);d(this,"cameraFrustrum",new h.Frustum);d(this,"targetTriangleDensity",2e5);d(this,"updateInterval","auto");X(this,I,1);d(this,"pause",!1);d(this,"_lodchangedlisteners",[]);X(this,W,void 0);X(this,fe,new h.Clock);X(this,j,0);X(this,J,0);X(this,de,0);X(this,q,0);d(this,"_fpsBuffer",[60,60,60,60,60]);d(this,"_sphere",new h.Sphere);d(this,"_tempBox",new h.Box3);d(this,"_tempBox2",new h.Box3);d(this,"tempMatrix",new h.Matrix4);d(this,"_tempWorldPosition",new h.Vector3);d(this,"_tempBoxSize",new h.Vector3);d(this,"_tempBox2Size",new h.Vector3);this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[xe]}static addPlugin(t){Y.push(t)}static removePlugin(t){const e=Y.indexOf(t);e>=0&&Y.splice(e,1)}static get(t,e){if(t[me])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[me];const r=new B(t,{engine:"unknown",...e});return t[me]=r,r}get plugins(){return Y}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}enable(){if(x(this,W))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;V(this,W,this.renderer.render);const e=this;_e(this.renderer),this.renderer.render=function(r,o){e.renderer.getRenderTarget()==null&&(t=0,V(e,j,x(e,j)+1),V(e,J,x(e,fe).getDelta()),V(e,de,x(e,de)+x(e,J)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/x(e,J)),V(e,q,e._fpsBuffer.reduce((l,f)=>l+f)/e._fpsBuffer.length),R&&x(e,j)%30===0&&console.log("FPS",Math.round(x(e,q)),"Interval:",x(e,I)));const s=x(e,j),n=t++;e.onBeforeRender(r,o,n,s),x(e,W).call(this,r,o),e.onAfterRender(r,o,n,s)}}disable(){x(this,W)&&(this.renderer.render=x(this,W),V(this,W,void 0))}onBeforeRender(t,e,r,o){}onAfterRender(t,e,r,o){var l,f;if(this.pause)return;const i=this.renderer.renderLists.get(t,0),s=i.opaque;let n=!0;if(s.length===1){const c=s[0].material;(c.name==="EffectMaterial"||c.name==="CopyShader")&&(n=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(n=!1),n){if(He||(this.updateInterval==="auto"?x(this,q)<40&&x(this,I)<10?(V(this,I,x(this,I)+1),R&&console.warn("↓ Reducing LOD updates",x(this,I),x(this,q).toFixed(0))):x(this,q)>=60&&x(this,I)>1&&(V(this,I,x(this,I)-1),R&&console.warn("↑ Increasing LOD updates",x(this,I),x(this,q).toFixed(0))):V(this,I,this.updateInterval),x(this,I)>0&&o%x(this,I)!=0))return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const c=this.targetTriangleDensity;for(const u of s){if(u.material&&(((l=u.geometry)==null?void 0:l.type)==="BoxGeometry"||((f=u.geometry)==null?void 0:f.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){R&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}switch(u.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(R==="color"&&u.material&&!u.object.progressive_debug_color){u.object.progressive_debug_color=!0;const _=Math.random()*16777215,L=new h.MeshStandardMaterial({color:_});u.object.material=L}const m=u.object;(m instanceof h.Mesh||m.isMesh)&&this.updateLODs(t,e,m,c,o)}const D=i.transparent;for(const u of D){const m=u.object;(m instanceof h.Mesh||m.isMesh)&&this.updateLODs(t,e,m,c,o)}}}updateLODs(t,e,r,o,i){var l,f;r.userData||(r.userData={});let s=r[xe];if(s||(s=new je,r[xe]=s),s.frames++<2)return;for(const c of Y)(l=c.onBeforeUpdateLOD)==null||l.call(c,this.renderer,t,e,r);this.calculateLodLevel(e,r,s,o,G),G.mesh_lod=Math.round(G.mesh_lod),G.texture_lod=Math.round(G.texture_lod),G.mesh_lod>=0&&this.loadProgressiveMeshes(r,G.mesh_lod);let n=G.texture_lod;if(r.material&&n>=0){const c=r["DEBUG:LOD"];c!=null&&(n=c),this.loadProgressiveTextures(r.material,n)}for(const c of Y)(f=c.onAfterUpdatedLOD)==null||f.call(c,this.renderer,t,e,r,G);s.lastLodLevel_Mesh=G.mesh_lod,s.lastLodLevel_Texture=G.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}let r=!1;(t[H]===void 0||e<t[H])&&(r=!0),r&&(t[H]=e,b.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(i=>i({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[H]!==e){t[H]=e;const r=t.geometry;return b.assignMeshLOD(t,e).then(o=>(o&&t[H]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(i=>i({type:"mesh",level:e,object:t})),o))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,o=t.max,i=(r.x+o.x)*.5,s=(r.y+o.y)*.5;return this._tempPtInside.set(i,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,o,i){var F,N;if(!e){i.mesh_lod=-1,i.texture_lod=-1;return}if(!t){i.mesh_lod=-1,i.texture_lod=-1;return}let n=10+1,l=!1;if(R&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const f=b.getMeshLODInformation(e.geometry),c=f==null?void 0:f.lods,D=c&&c.length>0,u=b.getMaterialMinMaxLODsCount(e.material),m=(u==null?void 0:u.min_count)!=1/0&&u.min_count>0&&u.max_count>0;if(!D&&!m){i.mesh_lod=0,i.texture_lod=0;return}if(D||(l=!0,n=0),!((F=this.cameraFrustrum)!=null&&F.intersectsObject(e))){i.mesh_lod=99,i.texture_lod=99;return}const _=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let L=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const y=e;y.boundingBox||y.computeBoundingBox(),L=y.boundingBox}if(L&&t.isPerspectiveCamera){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 g=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g)){i.mesh_lod=0,i.texture_lod=0;return}}if(this._tempBox.copy(L),this._tempBox.applyMatrix4(e.matrixWorld),B.isInside(this._tempBox,this.projectionScreenMatrix)){i.mesh_lod=0,i.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&y.fov>70){const g=this._tempBox.min,v=this._tempBox.max;let A=g.x,P=g.y,C=v.x,Q=v.y;const ne=2,ge=1.5,ae=(g.x+v.x)*.5,le=(g.y+v.y)*.5;A=(A-ae)*ne+ae,P=(P-le)*ne+le,C=(C-ae)*ne+ae,Q=(Q-le)*ne+le;const Ie=A<0&&C>0?0:Math.min(Math.abs(g.x),Math.abs(v.x)),ke=P<0&&Q>0?0:Math.min(Math.abs(g.y),Math.abs(v.y)),pe=Math.max(Ie,ke);r.lastCentrality=(ge-pe)*(ge-pe)*(ge-pe)}else r.lastCentrality=1;const w=this._tempBox.getSize(this._tempBoxSize);w.multiplyScalar(.5),screen.availHeight>0&&_>0&&w.multiplyScalar(_/screen.availHeight),w.x*=y.aspect;const z=t.matrixWorldInverse,K=this._tempBox2;K.copy(L),K.applyMatrix4(e.matrixWorld),K.applyMatrix4(z);const T=K.getSize(this._tempBox2Size),U=Math.max(T.x,T.y);if(Math.max(w.x,w.y)!=0&&U!=0&&(w.z=T.z/Math.max(T.x,T.y)*Math.max(w.x,w.y)),r.lastScreenCoverage=Math.max(w.x,w.y,w.z),r.lastScreenspaceVolume.copy(w),r.lastScreenCoverage*=r.lastCentrality,R&&B.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const v=B.corner0,A=B.corner1,P=B.corner2,C=B.corner3;v.copy(this._tempBox.min),A.copy(this._tempBox.max),A.x=v.x,P.copy(this._tempBox.max),P.y=v.y,C.copy(this._tempBox.max);const Q=(v.z+C.z)*.5;v.z=A.z=P.z=C.z=Q,v.applyMatrix4(g),A.applyMatrix4(g),P.applyMatrix4(g),C.applyMatrix4(g),B.debugDrawLine(v,A,255),B.debugDrawLine(v,P,255),B.debugDrawLine(A,C,255),B.debugDrawLine(P,C,255)}let S=999;if(c&&r.lastScreenCoverage>0){for(let g=0;g<c.length;g++)if(c[g].density/r.lastScreenCoverage<o){S=g;break}}S<n&&(n=S,l=!0)}if(l?i.mesh_lod=n:i.mesh_lod=r.lastLodLevel_Mesh,R&&i.mesh_lod!=r.lastLodLevel_Mesh){const w=c==null?void 0:c[i.mesh_lod];w&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${i.mesh_lod} (${w.density.toFixed(0)}) - ${e.name}`)}if(m){const y="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(i.texture_lod=u.max_count-1,R){const w=u.lods[u.max_count-1];R&&console.log(`First Texture LOD ${i.texture_lod} (${w.max_height}px) - ${e.name}`)}}else{const w=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let z=r.lastScreenCoverage*2;((N=this.context)==null?void 0:N.engine)==="model-viewer"&&(z*=2);const T=_/window.devicePixelRatio*z;for(let U=u.lods.length-1;U>=0;U--){let E=u.lods[U];if(!(y&&E.max_height>=2048)&&!(qe()&&E.max_height>4096)&&E.max_height>T){if(i.texture_lod=U,i.texture_lod<r.lastLodLevel_Texture){const S=E.max_height;R&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${i.texture_lod} = ${S}px
|
|
6
|
+
Screensize: ${T.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${w.toFixed(1)}
|
|
7
|
+
${e.name}`)}break}}}}else i.texture_lod=0}};let k=B;I=new WeakMap,W=new WeakMap,fe=new WeakMap,j=new WeakMap,J=new WeakMap,de=new WeakMap,q=new WeakMap,d(k,"debugDrawLine"),d(k,"corner0",new h.Vector3),d(k,"corner1",new h.Vector3),d(k,"corner2",new h.Vector3),d(k,"corner3",new h.Vector3),d(k,"_tempPtInside",new h.Vector3);class je{constructor(){d(this,"frames",0);d(this,"lastLodLevel_Mesh",-1);d(this,"lastLodLevel_Texture",-1);d(this,"lastScreenCoverage",0);d(this,"lastScreenspaceVolume",new h.Vector3);d(this,"lastCentrality",0)}}const Ae=Symbol("NEEDLE_mesh_lod"),ce=Symbol("NEEDLE_texture_lod");let te=null;function Se(){const a=Je();a&&(a.mapURLs(function(t){return Ee(),t}),Ee(),te==null||te.disconnect(),te=new MutationObserver(t=>{t.forEach(e=>{e.addedNodes.forEach(r=>{r instanceof HTMLElement&&r.tagName.toLowerCase()==="model-viewer"&&Be(r)})})}),te.observe(document,{childList:!0,subtree:!0}))}function Je(){const a=customElements.get("model-viewer");return a||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Se()}),null)}function Ee(){document.querySelectorAll("model-viewer").forEach(t=>{Be(t)})}const Pe=new WeakSet;let Qe=0;function Be(a){if(!a||Pe.has(a))return null;Pe.add(a),console.debug("[gltf-progressive] found new model-viewer..."+ ++Qe+`
|
|
8
|
+
`,a.getAttribute("src"));let t=null,e=null,r=null;for(let o=a;o!=null;o=Object.getPrototypeOf(o)){const i=Object.getOwnPropertySymbols(o),s=i.find(f=>f.toString()=="Symbol(renderer)"),n=i.find(f=>f.toString()=="Symbol(scene)"),l=i.find(f=>f.toString()=="Symbol(needsRender)");!t&&s!=null&&(t=a[s].threeRenderer),!e&&n!=null&&(e=a[n]),!r&&l!=null&&(r=a[l])}if(t&&e){let o=function(){if(r){let s=0,n=setInterval(()=>{if(s++>5){clearInterval(n);return}r==null||r.call(a)},300)}};console.debug("[gltf-progressive] setup model-viewer");const i=k.get(t,{engine:"model-viewer"});return k.addPlugin(new Ze),i.enable(),i.addEventListener("changed",()=>{r==null||r.call(a)}),a.addEventListener("model-visibility",s=>{s.detail.visible&&(r==null||r.call(a))}),a.addEventListener("load",()=>{o()}),()=>{i.disable()}}return null}class Ze{constructor(){d(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(t,e,r,o){this.tryParseMeshLOD(e,o),this.tryParseTextureLOD(e,o)}getUrl(t){if(!t)return null;let e=t.getAttribute("src");return e||(e=t.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",t),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(t){return t._currentGLTF}tryGetCurrentModelViewer(t){return t.element}tryParseTextureLOD(t,e){if(e[ce]==!0)return;e[ce]=!0;const r=this.tryGetCurrentGLTF(t),o=this.tryGetCurrentModelViewer(t),i=this.getUrl(o);if(i&&r&&e.material){let s=function(l){var c,D,u;if(l[ce]==!0)return;l[ce]=!0,l.userData&&(l.userData.LOD=-1);const f=Object.keys(l);for(let m=0;m<f.length;m++){const _=f[m],L=l[_];if((L==null?void 0:L.isTexture)===!0){const F=(D=(c=L.userData)==null?void 0:c.associations)==null?void 0:D.textures;if(F==null)continue;const N=r.parser.json.textures[F];if(!N){console.warn("Texture data not found for texture index "+F);continue}if((u=N==null?void 0:N.extensions)!=null&&u[$]){const y=N.extensions[$];y&&i&&b.registerTexture(i,L,y.lods.length,F,y)}}}};const n=e.material;if(Array.isArray(n))for(const l of n)s(l);else s(n)}}tryParseMeshLOD(t,e){var s,n;if(e[Ae]==!0)return;e[Ae]=!0;const r=this.tryGetCurrentModelViewer(t),o=this.getUrl(r);if(!o)return;const i=(n=(s=e.userData)==null?void 0:s.gltfExtensions)==null?void 0:n[$];if(i&&o){const l=e.uuid;b.registerMesh(o,l,e,0,i.lods.length,i)}}}function et(a,t,e,r){_e(t),Oe(e),e.register(i=>new b(i,a));const o=k.get(t);return(r==null?void 0:r.enableLODsManager)!==!1&&o.enable(),o}Se();exports.EXTENSION_NAME=$;exports.LODsManager=k;exports.NEEDLE_progressive=b;exports.VERSION=we;exports.addDracoAndKTX2Loaders=Oe;exports.createLoaders=_e;exports.getRaycastMesh=he;exports.patchModelViewer=Se;exports.registerRaycastMesh=Ce;exports.setDracoDecoderLocation=ze;exports.setKTX2TranscoderLocation=Ue;exports.useNeedleProgressive=et;exports.useRaycastMeshes=Ke;
|
package/lib/lods_manager.js
CHANGED
|
@@ -191,7 +191,7 @@ export class LODsManager {
|
|
|
191
191
|
if (debugProgressiveLoading)
|
|
192
192
|
console.warn("↓ Reducing LOD updates", this.#updateInterval, this.#fps.toFixed(0));
|
|
193
193
|
}
|
|
194
|
-
else if (this.#fps >=
|
|
194
|
+
else if (this.#fps >= 60 && this.#updateInterval > 1) {
|
|
195
195
|
this.#updateInterval -= 1;
|
|
196
196
|
if (debugProgressiveLoading)
|
|
197
197
|
console.warn("↑ Increasing LOD updates", this.#updateInterval, this.#fps.toFixed(0));
|
|
@@ -575,6 +575,7 @@ export class LODsManager {
|
|
|
575
575
|
}
|
|
576
576
|
}
|
|
577
577
|
if (has_texture_lods) {
|
|
578
|
+
const saveDataEnabled = "saveData" in globalThis.navigator && globalThis.navigator.saveData === true;
|
|
578
579
|
// If this is the first time a texture LOD is requested we want to get the highest LOD to not display the minimal resolution that the root glTF contains as long while we wait for loading of e.g. the 8k LOD 0 texture
|
|
579
580
|
if (state.lastLodLevel_Texture < 0) {
|
|
580
581
|
result.texture_lod = texture_lods_minmax.max_count - 1;
|
|
@@ -594,6 +595,9 @@ export class LODsManager {
|
|
|
594
595
|
const pixelSizeOnScreen = screenSize * factor;
|
|
595
596
|
for (let i = texture_lods_minmax.lods.length - 1; i >= 0; i--) {
|
|
596
597
|
let lod = texture_lods_minmax.lods[i];
|
|
598
|
+
if (saveDataEnabled && lod.max_height >= 2048) {
|
|
599
|
+
continue; // skip 2k textures when saveData is enabled
|
|
600
|
+
}
|
|
597
601
|
if (isMobileDevice() && lod.max_height > 4096)
|
|
598
602
|
continue; // skip 8k textures on mobile devices (for now)
|
|
599
603
|
if (lod.max_height > pixelSizeOnScreen) {
|
package/lib/version.js
CHANGED
package/package.json
CHANGED