@needle-tools/gltf-progressive 1.0.0-alpha.4 → 1.0.0-alpha.6
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 -1
- package/{dist/@needle-tools-gltf-progressive.js → gltf-progressive.js} +87 -69
- package/gltf-progressive.min.js +3 -0
- package/gltf-progressive.umd.cjs +3 -0
- package/lib/extension.d.ts +109 -109
- package/lib/extension.js +672 -672
- package/lib/extension.js.map +1 -1
- package/lib/index.d.ts +26 -10
- package/lib/index.js +37 -21
- package/lib/index.js.map +1 -1
- package/lib/loaders.d.ts +4 -4
- package/lib/loaders.js +35 -35
- package/lib/loaders.js.map +1 -1
- package/lib/lods_manager.d.ts +69 -51
- package/lib/lods_manager.js +354 -336
- package/lib/lods_manager.js.map +1 -1
- package/lib/plugins/index.d.ts +2 -2
- package/lib/plugins/index.js +2 -2
- package/lib/plugins/modelviewer.d.ts +4 -15
- package/lib/plugins/modelviewer.js +125 -102
- package/lib/plugins/modelviewer.js.map +1 -1
- package/lib/plugins/plugin.d.ts +24 -14
- package/lib/plugins/plugin.js +11 -4
- package/lib/plugins/plugin.js.map +1 -1
- package/lib/utils.d.ts +2 -2
- package/lib/utils.js +36 -36
- package/lib/utils.js.map +1 -1
- package/package.json +18 -3
- package/dist/@needle-tools-gltf-progressive.min.js +0 -3
- package/dist/@needle-tools-gltf-progressive.umd.cjs +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,8 @@ 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.0.0-alpha.6] - 2023-05-01
|
|
8
|
+
- fix: LOD mesh assignment for multi-material meshes (meshes with multiple primitives)
|
|
7
9
|
|
|
8
|
-
## [1.0.0-alpha.
|
|
10
|
+
## [1.0.0-alpha.5] - 2023-04-30
|
|
9
11
|
- initial version
|
|
@@ -6,7 +6,8 @@ import { GLTFLoader as ge } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
|
6
6
|
import { MeshoptDecoder as he } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
7
7
|
import { DRACOLoader as pe } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
8
8
|
import { KTX2Loader as ye } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
9
|
-
|
|
9
|
+
const Le = "https://www.gstatic.com/draco/versioned/decoders/1.4.1/", De = "https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";
|
|
10
|
+
let U, V, I;
|
|
10
11
|
function se(l) {
|
|
11
12
|
U || (U = new pe(), U.setDecoderPath(Le), U.setDecoderConfig({ type: "js" })), I || (I = new ye(), I.setTranscoderPath(De)), V || (V = he), l ? I.detectSupport(l) : console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail");
|
|
12
13
|
}
|
|
@@ -14,7 +15,7 @@ function ie(l) {
|
|
|
14
15
|
l.dracoLoader || l.setDRACOLoader(U), l.ktx2Loader || l.setKTX2Loader(I), l.meshoptDecoder || l.setMeshoptDecoder(V);
|
|
15
16
|
}
|
|
16
17
|
function Q(l) {
|
|
17
|
-
|
|
18
|
+
const t = new URL(window.location.href).searchParams.get(l);
|
|
18
19
|
return t == null || t === "0" || t === "false" ? !1 : t === "" ? !0 : t;
|
|
19
20
|
}
|
|
20
21
|
function me(l, e) {
|
|
@@ -40,8 +41,8 @@ if (S) {
|
|
|
40
41
|
for (const s of i.keys) {
|
|
41
42
|
const n = o[s];
|
|
42
43
|
if (n.isBufferGeometry === !0) {
|
|
43
|
-
const a = M.getMeshLODInformation(n),
|
|
44
|
-
o["DEBUG:LOD"] =
|
|
44
|
+
const a = M.getMeshLODInformation(n), g = a ? Math.min(e, a.lods.length) : 0;
|
|
45
|
+
o["DEBUG:LOD"] = e, M.assignMeshLOD(o, g), a && (t = Math.max(t, a.lods.length - 1));
|
|
45
46
|
} else if (o.isMaterial === !0) {
|
|
46
47
|
o["DEBUG:LOD"] = e, M.assignTextureLOD(o, e);
|
|
47
48
|
break;
|
|
@@ -175,8 +176,8 @@ const v = class {
|
|
|
175
176
|
return Promise.all(i).then((s) => {
|
|
176
177
|
const n = new Array();
|
|
177
178
|
for (let a = 0; a < s.length; a++) {
|
|
178
|
-
const
|
|
179
|
-
|
|
179
|
+
const g = s[a], f = o[a];
|
|
180
|
+
g && g.isTexture === !0 ? n.push({ material: r, slot: f, texture: g, level: t }) : n.push({ material: r, slot: f, texture: null, level: t });
|
|
180
181
|
}
|
|
181
182
|
return n;
|
|
182
183
|
});
|
|
@@ -223,14 +224,14 @@ const v = class {
|
|
|
223
224
|
for (const n of this.parser.associations.keys())
|
|
224
225
|
if (n.isMesh) {
|
|
225
226
|
const a = this.parser.associations.get(n);
|
|
226
|
-
a.meshes === o && v.registerMesh(this.url,
|
|
227
|
+
a.meshes === o && v.registerMesh(this.url, s.guid, n, s.lods.length, a.primitives, s);
|
|
227
228
|
}
|
|
228
229
|
}
|
|
229
230
|
}
|
|
230
231
|
}), null;
|
|
231
232
|
}
|
|
232
233
|
static async getOrLoadLOD(e, t) {
|
|
233
|
-
var n, a,
|
|
234
|
+
var n, a, g;
|
|
234
235
|
const r = S == "verbose", i = e.userData.LODS;
|
|
235
236
|
if (!i)
|
|
236
237
|
return null;
|
|
@@ -242,9 +243,9 @@ const v = class {
|
|
|
242
243
|
}
|
|
243
244
|
if (s || (s = v.lodInfos.get(o)), s) {
|
|
244
245
|
if (t > 0) {
|
|
245
|
-
let
|
|
246
|
+
let d = !1;
|
|
246
247
|
const w = Array.isArray(s.lods);
|
|
247
|
-
if (w && t >= s.lods.length ?
|
|
248
|
+
if (w && t >= s.lods.length ? d = !0 : w || (d = !0), d)
|
|
248
249
|
return this.lowresCache.get(o);
|
|
249
250
|
}
|
|
250
251
|
const f = Array.isArray(s.lods) ? s.lods[t].path : s.lods;
|
|
@@ -254,23 +255,23 @@ const v = class {
|
|
|
254
255
|
if (L.endsWith(".glb") || L.endsWith(".gltf")) {
|
|
255
256
|
if (!s.guid)
|
|
256
257
|
return console.warn("missing pointer for glb/gltf texture", s), null;
|
|
257
|
-
const
|
|
258
|
+
const d = L + "_" + s.guid, w = this.previouslyLoaded.get(d);
|
|
258
259
|
if (w !== void 0) {
|
|
259
|
-
r && console.log(`LOD ${t} was already loading/loaded: ${
|
|
260
|
-
let m = await w.catch((
|
|
261
|
-
`,
|
|
262
|
-
if (m == null || (m instanceof z && e instanceof z ? (n = m.image) != null && n.data || (a = m.source) != null && a.data ? m = this.copySettings(e, m) : (B = !0, this.previouslyLoaded.delete(
|
|
260
|
+
r && console.log(`LOD ${t} was already loading/loaded: ${d}`);
|
|
261
|
+
let m = await w.catch((G) => (console.error(`Error loading LOD ${t} from ${L}
|
|
262
|
+
`, G), null)), B = !1;
|
|
263
|
+
if (m == null || (m instanceof z && e instanceof z ? (n = m.image) != null && n.data || (a = m.source) != null && a.data ? m = this.copySettings(e, m) : (B = !0, this.previouslyLoaded.delete(d)) : m instanceof X && e instanceof X && ((g = m.attributes.position) != null && g.array || (B = !0, this.previouslyLoaded.delete(d)))), !B)
|
|
263
264
|
return m;
|
|
264
265
|
}
|
|
265
|
-
const D = s,
|
|
266
|
-
const
|
|
267
|
-
ie(
|
|
266
|
+
const D = s, A = new Promise(async (m, B) => {
|
|
267
|
+
const G = new ge();
|
|
268
|
+
ie(G), S && (await new Promise((p) => setTimeout(p, 1e3)), r && console.warn("Start loading (delayed) " + L, D.guid));
|
|
268
269
|
let y = L;
|
|
269
270
|
if (D && Array.isArray(D.lods)) {
|
|
270
271
|
const p = D.lods[t];
|
|
271
272
|
p.hash && (y += "?v=" + p.hash);
|
|
272
273
|
}
|
|
273
|
-
const h = await
|
|
274
|
+
const h = await G.loadAsync(y).catch((p) => (console.error(`Error loading LOD ${t} from ${L}
|
|
274
275
|
`, p), null));
|
|
275
276
|
if (!h)
|
|
276
277
|
return null;
|
|
@@ -291,7 +292,7 @@ const v = class {
|
|
|
291
292
|
}
|
|
292
293
|
if (p) {
|
|
293
294
|
let c = await T.getDependency("texture", x);
|
|
294
|
-
return r && console.log('change "' + e.name + '" → "' + c.name + '"', L, x, c,
|
|
295
|
+
return r && console.log('change "' + e.name + '" → "' + c.name + '"', L, x, c, d), e instanceof z && (c = this.copySettings(e, c)), c && (c.guid = D.guid), m(c);
|
|
295
296
|
}
|
|
296
297
|
}
|
|
297
298
|
if (x = 0, h.parser.json.meshes) {
|
|
@@ -308,7 +309,7 @@ const v = class {
|
|
|
308
309
|
}
|
|
309
310
|
if (p) {
|
|
310
311
|
const c = await T.getDependency("mesh", x), O = D;
|
|
311
|
-
if (r && console.log(`Loaded Mesh "${c.name}"`, L, x, c,
|
|
312
|
+
if (r && console.log(`Loaded Mesh "${c.name}"`, L, x, c, d), c.isMesh === !0) {
|
|
312
313
|
const b = c.geometry;
|
|
313
314
|
return v.assignLODInformation(i.url, b, o, t, void 0, O.density), m(b);
|
|
314
315
|
} else {
|
|
@@ -326,7 +327,7 @@ const v = class {
|
|
|
326
327
|
}
|
|
327
328
|
return m(null);
|
|
328
329
|
});
|
|
329
|
-
return this.previouslyLoaded.set(
|
|
330
|
+
return this.previouslyLoaded.set(d, A), await A;
|
|
330
331
|
} else if (e instanceof z) {
|
|
331
332
|
r && console.log("Load texture from uri: " + L);
|
|
332
333
|
const w = await new ce().loadAsync(L);
|
|
@@ -358,20 +359,20 @@ let M = v;
|
|
|
358
359
|
*/
|
|
359
360
|
u(M, "registerTexture", (e, t, r, i) => {
|
|
360
361
|
S && console.log("> Progressive: register texture", r, t.name, t.uuid, t, i), t.source && (t.source[q] = i);
|
|
361
|
-
const o =
|
|
362
|
+
const o = i.guid;
|
|
362
363
|
v.assignLODInformation(e, t, o, 0, 0, void 0), v.lodInfos.set(o, i), v.lowresCache.set(o, t);
|
|
363
364
|
}), /**
|
|
364
365
|
* Register a mesh with LOD information
|
|
365
366
|
*/
|
|
366
367
|
u(M, "registerMesh", (e, t, r, i, o, s) => {
|
|
367
|
-
var
|
|
368
|
+
var g;
|
|
368
369
|
S && console.log("> Progressive: register mesh", o, r.name, s, r.uuid, r);
|
|
369
370
|
const n = r.geometry;
|
|
370
371
|
n.userData || (n.userData = {}), v.assignLODInformation(e, n, t, i, o, s.density), v.lodInfos.set(t, s);
|
|
371
372
|
let a = v.lowresCache.get(t);
|
|
372
373
|
a ? a.push(r.geometry) : a = [r.geometry], v.lowresCache.set(t, a);
|
|
373
374
|
for (const f of H)
|
|
374
|
-
(
|
|
375
|
+
(g = f.onRegisteredNewMesh) == null || g.call(f, r, s);
|
|
375
376
|
}), /** A map of key = asset uuid and value = LOD information */
|
|
376
377
|
u(M, "lodInfos", /* @__PURE__ */ new Map()), /** cache of already loaded mesh lods */
|
|
377
378
|
u(M, "previouslyLoaded", /* @__PURE__ */ new Map()), /** this contains the geometry/textures that were originally loaded */
|
|
@@ -389,13 +390,18 @@ class xe {
|
|
|
389
390
|
this.url = e, this.key = t, this.level = r, i != null && (this.index = i), o != null && (this.density = o);
|
|
390
391
|
}
|
|
391
392
|
}
|
|
392
|
-
|
|
393
|
-
const we = Q("noprogressive"), A = class {
|
|
393
|
+
const te = Q("debugprogressive"), we = Q("noprogressive"), P = class {
|
|
394
394
|
constructor(e) {
|
|
395
395
|
u(this, "renderer");
|
|
396
396
|
u(this, "projectionScreenMatrix", new Z());
|
|
397
397
|
u(this, "cameraFrustrum", new fe());
|
|
398
|
+
/**
|
|
399
|
+
* The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 1, the LODs will be updated every second frame, etc.
|
|
400
|
+
*/
|
|
398
401
|
u(this, "updateInterval", 0);
|
|
402
|
+
/**
|
|
403
|
+
* If set to true, the LODsManager will not update the LODs.
|
|
404
|
+
*/
|
|
399
405
|
u(this, "pause", !1);
|
|
400
406
|
u(this, "plugins", []);
|
|
401
407
|
u(this, "_originalRender");
|
|
@@ -408,6 +414,14 @@ const we = Q("noprogressive"), A = class {
|
|
|
408
414
|
u(this, "_tempBox2Size", new C());
|
|
409
415
|
this.renderer = e;
|
|
410
416
|
}
|
|
417
|
+
/** @internal */
|
|
418
|
+
static getObjectLODState(e) {
|
|
419
|
+
var t;
|
|
420
|
+
return (t = e.userData) == null ? void 0 : t.LOD_state;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Enable the LODsManager. This will replace the render method of the renderer with a method that updates the LODs.
|
|
424
|
+
*/
|
|
411
425
|
enable() {
|
|
412
426
|
if (this._originalRender)
|
|
413
427
|
return;
|
|
@@ -431,17 +445,13 @@ const we = Q("noprogressive"), A = class {
|
|
|
431
445
|
this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix, t.matrixWorldInverse), this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix, this.renderer.coordinateSystem);
|
|
432
446
|
const o = 1e5, n = this.renderer.renderLists.get(e, r).opaque;
|
|
433
447
|
for (const a of n) {
|
|
434
|
-
const
|
|
435
|
-
(
|
|
448
|
+
const g = a.object;
|
|
449
|
+
(g instanceof Y || g.isMesh) && this.updateLODs(e, t, g, o);
|
|
436
450
|
}
|
|
437
451
|
}
|
|
438
|
-
static getObjectLODState(e) {
|
|
439
|
-
var t;
|
|
440
|
-
return (t = e.userData) == null ? void 0 : t.LOD_state;
|
|
441
|
-
}
|
|
442
452
|
/** Update the LOD levels for the renderer. */
|
|
443
453
|
updateLODs(e, t, r, i) {
|
|
444
|
-
var a,
|
|
454
|
+
var a, g;
|
|
445
455
|
for (const f of this.plugins)
|
|
446
456
|
(a = f.onBeforeUpdateLOD) == null || a.call(f, this.renderer, e, t, r);
|
|
447
457
|
let o = r.userData.LOD_state;
|
|
@@ -458,7 +468,7 @@ const we = Q("noprogressive"), A = class {
|
|
|
458
468
|
this.loadProgressiveTextures(r.material, n);
|
|
459
469
|
}
|
|
460
470
|
for (const f of this.plugins)
|
|
461
|
-
(
|
|
471
|
+
(g = f.onAfterUpdatedLOD) == null || g.call(f, this.renderer, e, t, r, s);
|
|
462
472
|
o.lastLodLevel = s;
|
|
463
473
|
}
|
|
464
474
|
/** Load progressive textures for the given material
|
|
@@ -493,8 +503,8 @@ const we = Q("noprogressive"), A = class {
|
|
|
493
503
|
if (e) {
|
|
494
504
|
if (te && t["DEBUG:LOD"] != null)
|
|
495
505
|
return t["DEBUG:LOD"];
|
|
496
|
-
const a = M.getMeshLODInformation(t.geometry),
|
|
497
|
-
if (!
|
|
506
|
+
const a = M.getMeshLODInformation(t.geometry), g = a == null ? void 0 : a.lods;
|
|
507
|
+
if (!g || g.length <= 0 || !((n = this.cameraFrustrum) != null && n.intersectsObject(t)))
|
|
498
508
|
return 99;
|
|
499
509
|
const f = t.geometry.boundingBox;
|
|
500
510
|
if (f && e.isPerspectiveCamera) {
|
|
@@ -514,23 +524,23 @@ const we = Q("noprogressive"), A = class {
|
|
|
514
524
|
r.lastCentrality = (b - N) * (b - N) * (b - N);
|
|
515
525
|
} else
|
|
516
526
|
r.lastCentrality = 1;
|
|
517
|
-
const
|
|
518
|
-
|
|
527
|
+
const d = this._tempBox.getSize(this._tempBoxSize);
|
|
528
|
+
d.multiplyScalar(0.5), screen.availHeight > 0 && d.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), d.x *= L.aspect;
|
|
519
529
|
const w = e.matrixWorldInverse, D = new j();
|
|
520
530
|
D.copy(f), D.applyMatrix4(t.matrixWorld), D.applyMatrix4(w);
|
|
521
|
-
const
|
|
522
|
-
if (Math.max(
|
|
531
|
+
const A = D.getSize(this._tempBox2Size), E = Math.max(A.x, A.y);
|
|
532
|
+
if (Math.max(d.x, d.y) != 0 && E != 0 && (d.z = A.z / Math.max(A.x, A.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, te && P.debugDrawLine) {
|
|
523
533
|
const y = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
524
534
|
y.invert();
|
|
525
|
-
const h =
|
|
535
|
+
const h = P.corner0, T = P.corner1, x = P.corner2, p = P.corner3;
|
|
526
536
|
h.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = h.x, x.copy(this._tempBox.max), x.y = h.y, p.copy(this._tempBox.max);
|
|
527
537
|
const c = (h.z + p.z) * 0.5;
|
|
528
|
-
h.z = T.z = x.z = p.z = c, h.applyMatrix4(y), T.applyMatrix4(y), x.applyMatrix4(y), p.applyMatrix4(y),
|
|
538
|
+
h.z = T.z = x.z = p.z = c, h.applyMatrix4(y), T.applyMatrix4(y), x.applyMatrix4(y), p.applyMatrix4(y), P.debugDrawLine(h, T, 255), P.debugDrawLine(h, x, 255), P.debugDrawLine(T, p, 255), P.debugDrawLine(x, p, 255);
|
|
529
539
|
}
|
|
530
540
|
let B = 999;
|
|
531
|
-
if (
|
|
532
|
-
for (let y = 0; y <
|
|
533
|
-
if (
|
|
541
|
+
if (g && r.lastScreenCoverage > 0) {
|
|
542
|
+
for (let y = 0; y < g.length; y++)
|
|
543
|
+
if (g[y].density / r.lastScreenCoverage < i) {
|
|
534
544
|
B = y;
|
|
535
545
|
break;
|
|
536
546
|
}
|
|
@@ -541,8 +551,10 @@ const we = Q("noprogressive"), A = class {
|
|
|
541
551
|
return s;
|
|
542
552
|
}
|
|
543
553
|
};
|
|
544
|
-
let k =
|
|
545
|
-
|
|
554
|
+
let k = P;
|
|
555
|
+
/** 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.
|
|
556
|
+
*/
|
|
557
|
+
u(k, "debugDrawLine"), u(k, "corner0", new C()), u(k, "corner1", new C()), u(k, "corner2", new C()), u(k, "corner3", new C());
|
|
546
558
|
class Oe {
|
|
547
559
|
constructor() {
|
|
548
560
|
u(this, "lastLodLevel", 0);
|
|
@@ -552,20 +564,26 @@ class Oe {
|
|
|
552
564
|
}
|
|
553
565
|
}
|
|
554
566
|
const re = Symbol("NEEDLE_mesh_lod"), K = Symbol("NEEDLE_texture_lod");
|
|
555
|
-
function ve() {
|
|
556
|
-
const l = document.querySelector("model-viewer");
|
|
567
|
+
function ve(l) {
|
|
557
568
|
if (!l)
|
|
558
|
-
return;
|
|
559
|
-
let e = null;
|
|
560
|
-
for (let
|
|
561
|
-
const i = Object.getOwnPropertySymbols(
|
|
562
|
-
!e &&
|
|
569
|
+
return null;
|
|
570
|
+
let e = null, t = null;
|
|
571
|
+
for (let r = l; r != null; r = Object.getPrototypeOf(r)) {
|
|
572
|
+
const i = Object.getOwnPropertySymbols(r), o = i.find((n) => n.toString() == "Symbol(renderer)"), s = i.find((n) => n.toString() == "Symbol(scene)");
|
|
573
|
+
!e && o != null && (e = l[o].threeRenderer), !t && s != null && (t = l[s]);
|
|
563
574
|
}
|
|
564
575
|
if (e) {
|
|
565
576
|
console.log("Adding Needle LODs to modelviewer");
|
|
566
|
-
const
|
|
567
|
-
|
|
577
|
+
const r = new k(e);
|
|
578
|
+
if (r.plugins.push(new Me(l)), r.enable(), t) {
|
|
579
|
+
const i = t.camera || t.traverse((o) => o.type == "PerspectiveCamera")[0];
|
|
580
|
+
i && e.render(t, i);
|
|
581
|
+
}
|
|
582
|
+
return () => {
|
|
583
|
+
r.disable();
|
|
584
|
+
};
|
|
568
585
|
}
|
|
586
|
+
return null;
|
|
569
587
|
}
|
|
570
588
|
class Me {
|
|
571
589
|
constructor(e) {
|
|
@@ -592,17 +610,17 @@ class Me {
|
|
|
592
610
|
}
|
|
593
611
|
if (r && t.material) {
|
|
594
612
|
let o = function(n) {
|
|
595
|
-
var
|
|
613
|
+
var g, f, L;
|
|
596
614
|
if (n[K] == !0)
|
|
597
615
|
return;
|
|
598
616
|
n[K] = !0, n.userData && (n.userData.LOD = -1);
|
|
599
617
|
const a = Object.keys(n);
|
|
600
|
-
for (let
|
|
601
|
-
const w = a[
|
|
618
|
+
for (let d = 0; d < a.length; d++) {
|
|
619
|
+
const w = a[d], D = n[w];
|
|
602
620
|
if ((D == null ? void 0 : D.isTexture) === !0) {
|
|
603
|
-
const
|
|
604
|
-
if ((L =
|
|
605
|
-
const m =
|
|
621
|
+
const A = (f = (g = D.userData) == null ? void 0 : g.associations) == null ? void 0 : f.textures, E = r.parser.json.textures[A];
|
|
622
|
+
if ((L = E.extensions) != null && L[R]) {
|
|
623
|
+
const m = E.extensions[R];
|
|
606
624
|
m && i && M.registerTexture(i, D, m.lods.length, m);
|
|
607
625
|
}
|
|
608
626
|
}
|
|
@@ -633,13 +651,13 @@ class Me {
|
|
|
633
651
|
}
|
|
634
652
|
}
|
|
635
653
|
}
|
|
636
|
-
function Be(l, e, t) {
|
|
637
|
-
se(e), ie(t), t.register((
|
|
638
|
-
const
|
|
639
|
-
return r.enable(),
|
|
654
|
+
function Be(l, e, t, r) {
|
|
655
|
+
se(e), ie(t), t.register((o) => new M(o, l));
|
|
656
|
+
const i = new k(e);
|
|
657
|
+
return (r == null ? void 0 : r.enableLODsManager) !== !1 && i.enable(), i;
|
|
640
658
|
}
|
|
641
659
|
document.addEventListener("DOMContentLoaded", () => {
|
|
642
|
-
ve();
|
|
660
|
+
ve(document.querySelector("model-viewer"));
|
|
643
661
|
});
|
|
644
662
|
export {
|
|
645
663
|
R as EXTENSION_NAME,
|
|
@@ -647,5 +665,5 @@ export {
|
|
|
647
665
|
M as NEEDLE_progressive,
|
|
648
666
|
ve as patchModelViewer,
|
|
649
667
|
ke as registerPlugin,
|
|
650
|
-
Be as
|
|
668
|
+
Be as useNeedleProgressive
|
|
651
669
|
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var se=Object.defineProperty,ne=(r,e,t)=>e in r?se(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,u=(r,e,t)=>(ne(r,typeof e!="symbol"?e+"":e,t),t);import{Mesh as W,BufferGeometry as U,Material as oe,RawShaderMaterial as ie,Texture as C,TextureLoader as ae,Matrix4 as K,Frustum as le,Sphere as ue,Box3 as Y,Vector3 as E}from"three";import{GLTFLoader as ce}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as de}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as he}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as fe}from"three/examples/jsm/loaders/KTX2Loader.js";const ge="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",pe="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";let R,$,G;function J(r){R||(R=new he,R.setDecoderPath(ge),R.setDecoderConfig({type:"js"})),G||(G=new fe,G.setTranscoderPath(pe)),$||($=de),r?G.detectSupport(r):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function Q(r){r.dracoLoader||r.setDRACOLoader(R),r.ktx2Loader||r.setKTX2Loader(G),r.meshoptDecoder||r.setMeshoptDecoder($)}function q(r){const e=new URL(window.location.href).searchParams.get(r);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function me(r,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||r===void 0)return e;const t=r.lastIndexOf("/");if(t>=0){const n=r.substring(0,t+1);for(;n.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return n+e}return e}const V=new Array;function ye(r){V.push(r)}const B="NEEDLE_progressive",v=q("debugprogressive"),X=Symbol("needle-progressive-texture"),z=new Map,H=new Set;if(v){let r=function(){e+=1,console.log("Toggle LOD level",e,z),z.forEach((o,s)=>{for(const a of o.keys){const i=s[a];if(i.isBufferGeometry===!0){const l=O.getMeshLODInformation(i),d=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=e,O.assignMeshLOD(s,d),l&&(t=Math.max(t,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,O.assignTextureLOD(s,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,n=!1;window.addEventListener("keyup",o=>{o.key==="p"&&r(),o.key==="w"&&(n=!n,H&&H.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=n)}))})}function Z(r,e,t){var n;if(!v)return;z.has(r)||z.set(r,{keys:[],sourceId:t});const o=z.get(r);((n=o?.keys)==null?void 0:n.includes(e))==!1&&o.keys.push(e)}const L=class{constructor(r,e){u(this,"parser"),u(this,"url"),v&&console.log("Progressive extension registered for",e),this.parser=r,this.url=e}get name(){return B}static getMeshLODInformation(r){const e=this.getAssignedLODInformation(r);return e!=null&&e.key?this.lodInfos.get(e.key):null}static hasLODLevelAvailable(r,e){var t;if(r.isMaterial===!0){for(const s of Object.keys(r)){const a=r[s];if(a.isTexture&&this.hasLODLevelAvailable(a,e))return!0}return!1}else if(r.isGroup===!0){for(const s of r.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let n,o;if(r.isMesh?n=r.geometry:(r.isBufferGeometry||r.isTexture)&&(n=r),n&&(t=n?.userData)!=null&&t.LODS){const s=n.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(r,e){var t;if(!r)return Promise.resolve(null);if(r instanceof W||r.isMesh===!0){const n=r.geometry,o=this.getAssignedLODInformation(n);if(!o)return Promise.resolve(null);for(const s of V)(t=s.onBeforeGetLODMesh)==null||t.call(s,r,e);return r["LOD:requested level"]=e,L.getOrLoadLOD(n,e).then(s=>{if(r["LOD:requested level"]===e){if(delete r["LOD:requested level"],Array.isArray(s)){const a=o.index||0;s=s[a]}s&&n!=s&&s instanceof U&&(r.geometry=s,v&&Z(r,"geometry",o.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",r,s),null))}else v&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",r);return Promise.resolve(null)}static assignTextureLOD(r,e=0){if(!r)return Promise.resolve(null);if(r instanceof oe||r.isMaterial===!0){const t=r,n=[],o=new Array;if(v&&H.add(t),t instanceof ie)for(const s of Object.keys(t.uniforms)){const a=t.uniforms[s].value;if(a?.isTexture===!0){const i=this.assignTextureLODForSlot(a,e,t,s);n.push(i),o.push(s)}}else for(const s of Object.keys(t)){const a=t[s];if(a?.isTexture===!0){const i=this.assignTextureLODForSlot(a,e,t,s);n.push(i),o.push(s)}}return Promise.all(n).then(s=>{const a=new Array;for(let i=0;i<s.length;i++){const l=s[i],d=o[i];l&&l.isTexture===!0?a.push({material:t,slot:d,texture:l,level:e}):a.push({material:t,slot:d,texture:null,level:e})}return a})}if(r instanceof C||r.isTexture===!0){const t=r;return this.assignTextureLODForSlot(t,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(r,e,t,n){return r?.isTexture!==!0?Promise.resolve(null):L.getOrLoadLOD(r,e).then(o=>{if(Array.isArray(o))return null;if(o?.isTexture===!0){if(o!=r&&(t&&n&&(t[n]=o),v&&n&&t)){const s=this.getAssignedLODInformation(r);s&&Z(t,n,s.url)}return o}else v=="verbose"&&console.warn("No LOD found for",r,e);return null}).catch(o=>(console.error("Error loading LOD",r,o),null))}afterRoot(r){var e,t;return v&&console.log("AFTER",this.url,r),(e=this.parser.json.textures)==null||e.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[B];if(s){let a=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i).textures===o&&(a=!0,L.registerTexture(this.url,i,o,s));a||this.parser.getDependency("texture",o).then(i=>{i&&L.registerTexture(this.url,i,o,s)})}}}),(t=this.parser.json.meshes)==null||t.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[B];if(s&&s.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const i=this.parser.associations.get(a);i.meshes===o&&L.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(r,e){var t,n,o;const s=v=="verbose",a=r.userData.LODS;if(!a)return null;const i=a?.key;let l;if(r.isTexture===!0){const d=r;d.source&&d.source[X]&&(l=d.source[X])}if(l||(l=L.lodInfos.get(i)),l){if(e>0){let g=!1;const M=Array.isArray(l.lods);if(M&&e>=l.lods.length?g=!0:M||(g=!0),g)return this.lowresCache.get(i)}const d=Array.isArray(l.lods)?l.lods[e].path:l.lods;if(!d)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const c=me(a.url,d);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const g=c+"_"+l.guid,M=this.previouslyLoaded.get(g);if(M!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${g}`);let m=await M.catch(p=>(console.error(`Error loading LOD ${e} from ${c}
|
|
2
|
+
`,p),null)),f=!1;if(m==null||(m instanceof C&&r instanceof C?(t=m.image)!=null&&t.data||(n=m.source)!=null&&n.data?m=this.copySettings(r,m):(f=!0,this.previouslyLoaded.delete(g)):m instanceof U&&r instanceof U&&((o=m.attributes.position)!=null&&o.array||(f=!0,this.previouslyLoaded.delete(g)))),!f)return m}const y=l,P=new Promise(async(m,f)=>{const p=new ce;Q(p),v&&(await new Promise(D=>setTimeout(D,1e3)),s&&console.warn("Start loading (delayed) "+c,y.guid));let b=c;if(y&&Array.isArray(y.lods)){const D=y.lods[e];D.hash&&(b+="?v="+D.hash)}const x=await p.loadAsync(b).catch(D=>(console.error(`Error loading LOD ${e} from ${c}
|
|
3
|
+
`,D),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+c,y.guid);let T=0;if(x.parser.json.textures){let D=!1;for(const h of x.parser.json.textures){if(h!=null&&h.extensions){const w=h?.extensions[B];if(w!=null&&w.guid&&w.guid===y.guid){D=!0;break}}T++}if(D){let h=await S.getDependency("texture",T);return s&&console.log('change "'+r.name+'" \u2192 "'+h.name+'"',c,T,h,g),r instanceof C&&(h=this.copySettings(r,h)),h&&(h.guid=y.guid),m(h)}}if(T=0,x.parser.json.meshes){let D=!1;for(const h of x.parser.json.meshes){if(h!=null&&h.extensions){const w=h?.extensions[B];if(w!=null&&w.guid&&w.guid===y.guid){D=!0;break}}T++}if(D){const h=await S.getDependency("mesh",T),w=y;if(s&&console.log(`Loaded Mesh "${h.name}"`,c,T,h,g),h.isMesh===!0){const _=h.geometry;return L.assignLODInformation(a.url,_,i,e,void 0,w.density),m(_)}else{const _=new Array;for(let I=0;I<h.children.length;I++){const F=h.children[I];if(F instanceof W){const j=F.geometry;L.assignLODInformation(a.url,j,i,e,I,w.density),_.push(j)}}return m(_)}}}return m(null)});return this.previouslyLoaded.set(g,P),await P}else if(r instanceof C){s&&console.log("Load texture from uri: "+c);const g=await new ae().loadAsync(c);return g?(g.guid=l.guid,g.flipY=!1,g.needsUpdate=!0,g.colorSpace=r.colorSpace,s&&console.log(l,g)):v&&console.warn("failed loading",c),g}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,n,o,s){if(!e)return;e.userData||(e.userData={});const a=new xe(r,t,n,o,s);e.userData.LODS=a,e.userData.LOD=n}static getAssignedLODInformation(r){var e;return((e=r?.userData)==null?void 0:e.LODS)||null}static copySettings(r,e){return this._copiedTextures.get(r)||(e=e.clone(),this._copiedTextures.set(r,e),e.offset=r.offset,e.repeat=r.repeat,e.colorSpace=r.colorSpace,e)}};let O=L;u(O,"registerTexture",(r,e,t,n)=>{v&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,n),e.source&&(e.source[X]=n);const o=n.guid;L.assignLODInformation(r,e,o,0,0,void 0),L.lodInfos.set(o,n),L.lowresCache.set(o,e)}),u(O,"registerMesh",(r,e,t,n,o,s)=>{var a;v&&console.log("> Progressive: register mesh",o,t.name,s,t.uuid,t);const i=t.geometry;i.userData||(i.userData={}),L.assignLODInformation(r,i,e,n,o,s.density),L.lodInfos.set(e,s);let l=L.lowresCache.get(e);l?l.push(t.geometry):l=[t.geometry],L.lowresCache.set(e,l);for(const d of V)(a=d.onRegisteredNewMesh)==null||a.call(d,t,s)}),u(O,"lodInfos",new Map),u(O,"previouslyLoaded",new Map),u(O,"lowresCache",new Map),u(O,"_copiedTextures",new Map);class xe{constructor(e,t,n,o,s){u(this,"url"),u(this,"key"),u(this,"level"),u(this,"index"),u(this,"density"),this.url=e,this.key=t,this.level=n,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const ee=q("debugprogressive"),De=q("noprogressive"),A=class{constructor(r){u(this,"renderer"),u(this,"projectionScreenMatrix",new K),u(this,"cameraFrustrum",new le),u(this,"updateInterval",0),u(this,"pause",!1),u(this,"plugins",[]),u(this,"_originalRender"),u(this,"_sphere",new ue),u(this,"_tempBox",new Y),u(this,"tempMatrix",new K),u(this,"_tempWorldPosition",new E),u(this,"_tempBoxSize",new E),u(this,"_tempBox2Size",new E),this.renderer=r}static getObjectLODState(r){var e;return(e=r.userData)==null?void 0:e.LOD_state}enable(){if(this._originalRender)return;let r=0;this._originalRender=this.renderer.render;const e=this;let t=0;J(this.renderer),this.renderer.render=function(n,o){const s=t++,a=r++;e.onBeforeRender(n,o,a,s),e._originalRender.call(this,n,o),e.onAfterRender(n,o,a,s),r--}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(r,e,t,n){}onAfterRender(r,e,t,n){if(De||this.pause||this.updateInterval>0&&n%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const o=1e5,s=this.renderer.renderLists.get(r,t).opaque;for(const a of s){const i=a.object;(i instanceof W||i.isMesh)&&this.updateLODs(r,e,i,o)}}updateLODs(r,e,t,n){var o,s;for(const d of this.plugins)(o=d.onBeforeUpdateLOD)==null||o.call(d,this.renderer,r,e,t);let a=t.userData.LOD_state;a||(a=new ve,t.userData.LOD_state=a);let i=this.calculateLodLevel(e,t,a,n);i=Math.round(i),i>=0&&this.loadProgressiveMeshes(t,i);let l=0;if(t.material){const d=t["DEBUG:LOD"];if(d!=null&&(l=d),Array.isArray(t.material))for(const c of t.material)this.loadProgressiveTextures(c,l);else this.loadProgressiveTextures(t.material,l)}for(const d of this.plugins)(s=d.onAfterUpdatedLOD)==null||s.call(d,this.renderer,r,e,t,i);a.lastLodLevel=i}loadProgressiveTextures(r,e){return r&&r.userData&&r.userData.LOD!==e?(r.userData.LOD=e,O.assignTextureLOD(r,e)):Promise.resolve(null)}loadProgressiveMeshes(r,e){if(!r)return Promise.resolve(null);if(r.userData||(r.userData={}),r.userData.LOD!==e){r.userData.LOD=e;const t=r.geometry;return O.assignMeshLOD(r,e).then(n=>(n&&r.userData.LOD==e&&t!=r.geometry,n))}return Promise.resolve(null)}calculateLodLevel(r,e,t,n){var o;if(!e)return-1;let s=10+1;if(r){if(ee&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=O.getMeshLODInformation(e.geometry),i=a?.lods;if(!i||i.length<=0||!((o=this.cameraFrustrum)!=null&&o.intersectsObject(e)))return 99;const l=e.geometry.boundingBox;if(l&&r.isPerspectiveCamera){const d=r;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const f=r.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(f))return 0}if(this._tempBox.copy(l),this._tempBox.applyMatrix4(e.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&d.fov>70){const f=this._tempBox.min,p=this._tempBox.max;let b=f.x,x=f.y,S=p.x,T=p.y;const D=2,h=1.5,w=(f.x+p.x)*.5,_=(f.y+p.y)*.5;b=(b-w)*D+w,x=(x-_)*D+_,S=(S-w)*D+w,T=(T-_)*D+_;const I=b<0&&S>0?0:Math.min(Math.abs(f.x),Math.abs(p.x)),F=x<0&&T>0?0:Math.min(Math.abs(f.y),Math.abs(p.y)),j=Math.max(I,F);t.lastCentrality=(h-j)*(h-j)*(h-j)}else t.lastCentrality=1;const c=this._tempBox.getSize(this._tempBoxSize);c.multiplyScalar(.5),screen.availHeight>0&&c.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),c.x*=d.aspect;const g=r.matrixWorldInverse,M=new Y;M.copy(l),M.applyMatrix4(e.matrixWorld),M.applyMatrix4(g);const y=M.getSize(this._tempBox2Size),P=Math.max(y.x,y.y);if(Math.max(c.x,c.y)!=0&&P!=0&&(c.z=y.z/Math.max(y.x,y.y)*Math.max(c.x,c.y)),t.lastScreenCoverage=Math.max(c.x,c.y,c.z),t.lastScreenspaceVolume.copy(c),t.lastScreenCoverage*=t.lastCentrality,ee&&A.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const p=A.corner0,b=A.corner1,x=A.corner2,S=A.corner3;p.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=p.x,x.copy(this._tempBox.max),x.y=p.y,S.copy(this._tempBox.max);const T=(p.z+S.z)*.5;p.z=b.z=x.z=S.z=T,p.applyMatrix4(f),b.applyMatrix4(f),x.applyMatrix4(f),S.applyMatrix4(f),A.debugDrawLine(p,b,255),A.debugDrawLine(p,x,255),A.debugDrawLine(b,S,255),A.debugDrawLine(x,S,255)}let m=999;if(i&&t.lastScreenCoverage>0){for(let f=0;f<i.length;f++)if(i[f].density/t.lastScreenCoverage<n){m=f;break}}m<s&&(s=m)}}return s}};let k=A;u(k,"debugDrawLine"),u(k,"corner0",new E),u(k,"corner1",new E),u(k,"corner2",new E),u(k,"corner3",new E);class ve{constructor(){u(this,"lastLodLevel",0),u(this,"lastScreenCoverage",0),u(this,"lastScreenspaceVolume",new E),u(this,"lastCentrality",0)}}const re=Symbol("NEEDLE_mesh_lod"),N=Symbol("NEEDLE_texture_lod");function te(r){if(!r)return null;let e=null,t=null;for(let n=r;n!=null;n=Object.getPrototypeOf(n)){const o=Object.getOwnPropertySymbols(n),s=o.find(i=>i.toString()=="Symbol(renderer)"),a=o.find(i=>i.toString()=="Symbol(scene)");!e&&s!=null&&(e=r[s].threeRenderer),!t&&a!=null&&(t=r[a])}if(e){console.log("Adding Needle LODs to modelviewer");const n=new k(e);if(n.plugins.push(new Le(r)),n.enable(),t){const o=t.camera||t.traverse(s=>s.type=="PerspectiveCamera")[0];o&&e.render(t,o)}return()=>{n.disable()}}return null}class Le{constructor(e){u(this,"modelviewer"),this.modelviewer=e}onBeforeUpdateLOD(e,t,n,o){this.tryParseMeshLOD(t,o),this.tryParseTextureLOD(t,o)}getUrl(){return this.modelviewer.getAttribute("src")}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[N]==!0)return;t[N]=!0;const n=this.tryGetCurrentGLTF(e),o=this.getUrl();if(!o){console.error("No url found in modelviewer");return}if(n&&t.material){let s=function(i){var l,d,c;if(i[N]==!0)return;i[N]=!0,i.userData&&(i.userData.LOD=-1);const g=Object.keys(i);for(let M=0;M<g.length;M++){const y=g[M],P=i[y];if(P?.isTexture===!0){const m=(d=(l=P.userData)==null?void 0:l.associations)==null?void 0:d.textures,f=n.parser.json.textures[m];if((c=f.extensions)!=null&&c[B]){const p=f.extensions[B];p&&o&&O.registerTexture(o,P,p.lods.length,p)}}}};const a=t.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,t){var n,o;if(t[re]==!0)return;t[re]=!0;const s=this.getUrl();if(!s){console.error("No url found in modelviewer");return}const a=(o=(n=t.userData)==null?void 0:n.gltfExtensions)==null?void 0:o[B];if(a&&s){const i=t.uuid;O.registerMesh(s,i,t,0,a.lods.length,a)}}}function Oe(r,e,t,n){J(e),Q(t),t.register(s=>new O(s,r));const o=new k(e);return n?.enableLODsManager!==!1&&o.enable(),o}document.addEventListener("DOMContentLoaded",()=>{te(document.querySelector("model-viewer"))});export{B as EXTENSION_NAME,k as LODsManager,O as NEEDLE_progressive,te as patchModelViewer,ye as registerPlugin,Oe as useNeedleProgressive};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";var re=Object.defineProperty;var se=(l,e,t)=>e in l?re(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var u=(l,e,t)=>(se(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("three"),ie=require("three/examples/jsm/loaders/GLTFLoader.js"),oe=require("three/examples/jsm/libs/meshopt_decoder.module.js"),ne=require("three/examples/jsm/loaders/DRACOLoader.js"),ae=require("three/examples/jsm/loaders/KTX2Loader.js"),le="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ue="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";let z,$,U;function Z(l){z||(z=new ne.DRACOLoader,z.setDecoderPath(le),z.setDecoderConfig({type:"js"})),U||(U=new ae.KTX2Loader,U.setTranscoderPath(ue)),$||($=oe.MeshoptDecoder),l?U.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function j(l){l.dracoLoader||l.setDRACOLoader(z),l.ktx2Loader||l.setKTX2Loader(U),l.meshoptDecoder||l.setMeshoptDecoder($)}function Y(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function ce(l,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||l===void 0)return e;const t=l.lastIndexOf("/");if(t>=0){const r=l.substring(0,t+1);for(;r.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return r+e}return e}const X=new Array;function fe(l){X.push(l)}const k="NEEDLE_progressive",T=Y("debugprogressive"),V=Symbol("needle-progressive-texture"),I=new Map,K=new Set;if(T){let l=function(){e+=1,console.log("Toggle LOD level",e,I),I.forEach((i,o)=>{for(const s of i.keys){const n=o[s];if(n.isBufferGeometry===!0){const a=w.getMeshLODInformation(n),g=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,w.assignMeshLOD(o,g),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,w.assignTextureLOD(o,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",i=>{i.key==="p"&&l(),i.key==="w"&&(r=!r,K&&K.forEach(o=>{o.name!="BackgroundCubeMaterial"&&"wireframe"in o&&(o.wireframe=r)}))})}function H(l,e,t){var i;if(!T)return;I.has(l)||I.set(l,{keys:[],sourceId:t});const r=I.get(l);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const S=class{constructor(e,t){u(this,"parser");u(this,"url");T&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return k}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static hasLODLevelAvailable(e,t){var o;if(e.isMaterial===!0){for(const s of Object.keys(e)){const n=e[s];if(n.isTexture&&this.hasLODLevelAvailable(n,t))return!0}return!1}else if(e.isGroup===!0){for(const s of e.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,t))return!0}let r,i;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const s=r.userData.LODS;if(i=this.lodInfos.get(s.key),t===void 0)return i!=null;if(i)return Array.isArray(i.lods)?t<i.lods.length:t===0}return!1}static assignMeshLOD(e,t){var r;if(!e)return Promise.resolve(null);if(e instanceof h.Mesh||e.isMesh===!0){const i=e.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of X)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,S.getOrLoadLOD(i,t).then(s=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(s)){const n=o.index||0;s=s[n]}s&&i!=s&&s instanceof h.BufferGeometry&&(e.geometry=s,T&&H(e,"geometry",o.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",e,s),null))}else T&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e instanceof h.Material||e.isMaterial===!0){const r=e,i=[],o=new Array;if(T&&K.add(r),r instanceof h.RawShaderMaterial)for(const s of Object.keys(r.uniforms)){const n=r.uniforms[s].value;if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,t,r,s);i.push(a),o.push(s)}}else for(const s of Object.keys(r)){const n=r[s];if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,t,r,s);i.push(a),o.push(s)}}return Promise.all(i).then(s=>{const n=new Array;for(let a=0;a<s.length;a++){const g=s[a],f=o[a];g&&g.isTexture===!0?n.push({material:r,slot:f,texture:g,level:t}):n.push({material:r,slot:f,texture:null,level:t})}return n})}if(e instanceof h.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,i){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):S.getOrLoadLOD(e,t).then(o=>{if(Array.isArray(o))return null;if((o==null?void 0:o.isTexture)===!0){if(o!=e&&(r&&i&&(r[i]=o),T&&i&&r)){const s=this.getAssignedLODInformation(e);s&&H(r,i,s.url)}return o}else T=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(o=>(console.error("Error loading LOD",e,o),null))}afterRoot(e){var t,r;return T&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[k];if(s){let n=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===o&&(n=!0,S.registerTexture(this.url,a,o,s));n||this.parser.getDependency("texture",o).then(a=>{a&&S.registerTexture(this.url,a,o,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[k];if(s&&s.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const a=this.parser.associations.get(n);a.meshes===o&&S.registerMesh(this.url,s.guid,n,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var n,a,g;const r=T=="verbose",i=e.userData.LODS;if(!i)return null;const o=i==null?void 0:i.key;let s;if(e.isTexture===!0){const f=e;f.source&&f.source[V]&&(s=f.source[V])}if(s||(s=S.lodInfos.get(o)),s){if(t>0){let d=!1;const M=Array.isArray(s.lods);if(M&&t>=s.lods.length?d=!0:M||(d=!0),d)return this.lowresCache.get(o)}const f=Array.isArray(s.lods)?s.lods[t].path:s.lods;if(!f)return T&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const D=ce(i.url,f);if(D.endsWith(".glb")||D.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const d=D+"_"+s.guid,M=this.previouslyLoaded.get(d);if(M!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${d}`);let m=await M.catch(F=>(console.error(`Error loading LOD ${t} from ${D}
|
|
2
|
+
`,F),null)),R=!1;if(m==null||(m instanceof h.Texture&&e instanceof h.Texture?(n=m.image)!=null&&n.data||(a=m.source)!=null&&a.data?m=this.copySettings(e,m):(R=!0,this.previouslyLoaded.delete(d)):m instanceof h.BufferGeometry&&e instanceof h.BufferGeometry&&((g=m.attributes.position)!=null&&g.array||(R=!0,this.previouslyLoaded.delete(d)))),!R)return m}const x=s,b=new Promise(async(m,R)=>{const F=new ie.GLTFLoader;j(F),T&&(await new Promise(y=>setTimeout(y,1e3)),r&&console.warn("Start loading (delayed) "+D,x.guid));let L=D;if(x&&Array.isArray(x.lods)){const y=x.lods[t];y.hash&&(L+="?v="+y.hash)}const p=await F.loadAsync(L).catch(y=>(console.error(`Error loading LOD ${t} from ${D}
|
|
3
|
+
`,y),null));if(!p)return null;const P=p.parser;r&&console.log("Loading finished "+D,x.guid);let O=0;if(p.parser.json.textures){let y=!1;for(const c of p.parser.json.textures){if(c!=null&&c.extensions){const v=c==null?void 0:c.extensions[k];if(v!=null&&v.guid&&v.guid===x.guid){y=!0;break}}O++}if(y){let c=await P.getDependency("texture",O);return r&&console.log('change "'+e.name+'" → "'+c.name+'"',D,O,c,d),e instanceof h.Texture&&(c=this.copySettings(e,c)),c&&(c.guid=x.guid),m(c)}}if(O=0,p.parser.json.meshes){let y=!1;for(const c of p.parser.json.meshes){if(c!=null&&c.extensions){const v=c==null?void 0:c.extensions[k];if(v!=null&&v.guid&&v.guid===x.guid){y=!0;break}}O++}if(y){const c=await P.getDependency("mesh",O),v=x;if(r&&console.log(`Loaded Mesh "${c.name}"`,D,O,c,d),c.isMesh===!0){const B=c.geometry;return S.assignLODInformation(i.url,B,o,t,void 0,v.density),m(B)}else{const B=new Array;for(let C=0;C<c.children.length;C++){const E=c.children[C];if(E instanceof h.Mesh){const N=E.geometry;S.assignLODInformation(i.url,N,o,t,C,v.density),B.push(N)}}return m(B)}}}return m(null)});return this.previouslyLoaded.set(d,b),await b}else if(e instanceof h.Texture){r&&console.log("Load texture from uri: "+D);const M=await new h.TextureLoader().loadAsync(D);return M?(M.guid=s.guid,M.flipY=!1,M.needsUpdate=!0,M.colorSpace=e.colorSpace,r&&console.log(s,M)):T&&console.warn("failed loading",D),M}}else T&&console.warn(`Can not load LOD ${t}: no LOD info found for "${o}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,i,o,s){if(!t)return;t.userData||(t.userData={});const n=new de(e,r,i,o,s);t.userData.LODS=n,t.userData.LOD=i}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){const r=this._copiedTextures.get(e);return r||(t=t.clone(),this._copiedTextures.set(e,t),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t)}};let w=S;u(w,"registerTexture",(e,t,r,i)=>{T&&console.log("> Progressive: register texture",r,t.name,t.uuid,t,i),t.source&&(t.source[V]=i);const o=i.guid;S.assignLODInformation(e,t,o,0,0,void 0),S.lodInfos.set(o,i),S.lowresCache.set(o,t)}),u(w,"registerMesh",(e,t,r,i,o,s)=>{var g;T&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const n=r.geometry;n.userData||(n.userData={}),S.assignLODInformation(e,n,t,i,o,s.density),S.lodInfos.set(t,s);let a=S.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],S.lowresCache.set(t,a);for(const f of X)(g=f.onRegisteredNewMesh)==null||g.call(f,r,s)}),u(w,"lodInfos",new Map),u(w,"previouslyLoaded",new Map),u(w,"lowresCache",new Map),u(w,"_copiedTextures",new Map);class de{constructor(e,t,r,i,o){u(this,"url");u(this,"key");u(this,"level");u(this,"index");u(this,"density");this.url=e,this.key=t,this.level=r,i!=null&&(this.index=i),o!=null&&(this.density=o)}}const J=Y("debugprogressive"),ge=Y("noprogressive"),A=class{constructor(e){u(this,"renderer");u(this,"projectionScreenMatrix",new h.Matrix4);u(this,"cameraFrustrum",new h.Frustum);u(this,"updateInterval",0);u(this,"pause",!1);u(this,"plugins",[]);u(this,"_originalRender");u(this,"_sphere",new h.Sphere);u(this,"_tempBox",new h.Box3);u(this,"tempMatrix",new h.Matrix4);u(this,"_tempWorldPosition",new h.Vector3);u(this,"_tempBoxSize",new h.Vector3);u(this,"_tempBox2Size",new h.Vector3);this.renderer=e}static getObjectLODState(e){var t;return(t=e.userData)==null?void 0:t.LOD_state}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;let r=0;Z(this.renderer),this.renderer.render=function(i,o){const s=r++,n=e++;t.onBeforeRender(i,o,n,s),t._originalRender.call(this,i,o),t.onAfterRender(i,o,n,s),e--}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){if(ge||this.pause||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const o=1e5,n=this.renderer.renderLists.get(e,r).opaque;for(const a of n){const g=a.object;(g instanceof h.Mesh||g.isMesh)&&this.updateLODs(e,t,g,o)}}updateLODs(e,t,r,i){var a,g;for(const f of this.plugins)(a=f.onBeforeUpdateLOD)==null||a.call(f,this.renderer,e,t,r);let o=r.userData.LOD_state;o||(o=new he,r.userData.LOD_state=o);let s=this.calculateLodLevel(t,r,o,i);s=Math.round(s),s>=0&&this.loadProgressiveMeshes(r,s);let n=0;if(r.material){const f=r["DEBUG:LOD"];if(f!=null&&(n=f),Array.isArray(r.material))for(const D of r.material)this.loadProgressiveTextures(D,n);else this.loadProgressiveTextures(r.material,n)}for(const f of this.plugins)(g=f.onAfterUpdatedLOD)==null||g.call(f,this.renderer,e,t,r,s);o.lastLodLevel=s}loadProgressiveTextures(e,t){return e&&e.userData&&e.userData.LOD!==t?(e.userData.LOD=t,w.assignTextureLOD(e,t)):Promise.resolve(null)}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e.userData||(e.userData={}),e.userData.LOD!==t){e.userData.LOD=t;const r=e.geometry;return w.assignMeshLOD(e,t).then(i=>(i&&e.userData.LOD==t&&r!=e.geometry,i))}return Promise.resolve(null)}calculateLodLevel(e,t,r,i){var n;if(!t)return-1;let s=10+1;if(e){if(J&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=w.getMeshLODInformation(t.geometry),g=a==null?void 0:a.lods;if(!g||g.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(t)))return 99;const f=t.geometry.boundingBox;if(f&&e.isPerspectiveCamera){const D=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const L=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(L))return 0}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(t.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&D.fov>70){const L=this._tempBox.min,p=this._tempBox.max;let P=L.x,O=L.y,y=p.x,c=p.y;const v=2,B=1.5,C=(L.x+p.x)*.5,E=(L.y+p.y)*.5;P=(P-C)*v+C,O=(O-E)*v+E,y=(y-C)*v+C,c=(c-E)*v+E;const N=P<0&&y>0?0:Math.min(Math.abs(L.x),Math.abs(p.x)),te=O<0&&c>0?0:Math.min(Math.abs(L.y),Math.abs(p.y)),q=Math.max(N,te);r.lastCentrality=(B-q)*(B-q)*(B-q)}else r.lastCentrality=1;const d=this._tempBox.getSize(this._tempBoxSize);d.multiplyScalar(.5),screen.availHeight>0&&d.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),d.x*=D.aspect;const M=e.matrixWorldInverse,x=new h.Box3;x.copy(f),x.applyMatrix4(t.matrixWorld),x.applyMatrix4(M);const b=x.getSize(this._tempBox2Size),G=Math.max(b.x,b.y);if(Math.max(d.x,d.y)!=0&&G!=0&&(d.z=b.z/Math.max(b.x,b.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,J&&A.debugDrawLine){const L=this.tempMatrix.copy(this.projectionScreenMatrix);L.invert();const p=A.corner0,P=A.corner1,O=A.corner2,y=A.corner3;p.copy(this._tempBox.min),P.copy(this._tempBox.max),P.x=p.x,O.copy(this._tempBox.max),O.y=p.y,y.copy(this._tempBox.max);const c=(p.z+y.z)*.5;p.z=P.z=O.z=y.z=c,p.applyMatrix4(L),P.applyMatrix4(L),O.applyMatrix4(L),y.applyMatrix4(L),A.debugDrawLine(p,P,255),A.debugDrawLine(p,O,255),A.debugDrawLine(P,y,255),A.debugDrawLine(O,y,255)}let R=999;if(g&&r.lastScreenCoverage>0){for(let L=0;L<g.length;L++)if(g[L].density/r.lastScreenCoverage<i){R=L;break}}R<s&&(s=R)}}return s}};let _=A;u(_,"debugDrawLine"),u(_,"corner0",new h.Vector3),u(_,"corner1",new h.Vector3),u(_,"corner2",new h.Vector3),u(_,"corner3",new h.Vector3);class he{constructor(){u(this,"lastLodLevel",0);u(this,"lastScreenCoverage",0);u(this,"lastScreenspaceVolume",new h.Vector3);u(this,"lastCentrality",0)}}const Q=Symbol("NEEDLE_mesh_lod"),W=Symbol("NEEDLE_texture_lod");function ee(l){if(!l)return null;let e=null,t=null;for(let r=l;r!=null;r=Object.getPrototypeOf(r)){const i=Object.getOwnPropertySymbols(r),o=i.find(n=>n.toString()=="Symbol(renderer)"),s=i.find(n=>n.toString()=="Symbol(scene)");!e&&o!=null&&(e=l[o].threeRenderer),!t&&s!=null&&(t=l[s])}if(e){console.log("Adding Needle LODs to modelviewer");const r=new _(e);if(r.plugins.push(new pe(l)),r.enable(),t){const i=t.camera||t.traverse(o=>o.type=="PerspectiveCamera")[0];i&&e.render(t,i)}return()=>{r.disable()}}return null}class pe{constructor(e){u(this,"modelviewer");this.modelviewer=e}onBeforeUpdateLOD(e,t,r,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}getUrl(){return this.modelviewer.getAttribute("src")}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[W]==!0)return;t[W]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(!i){console.error("No url found in modelviewer");return}if(r&&t.material){let o=function(n){var g,f,D;if(n[W]==!0)return;n[W]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let d=0;d<a.length;d++){const M=a[d],x=n[M];if((x==null?void 0:x.isTexture)===!0){const b=(f=(g=x.userData)==null?void 0:g.associations)==null?void 0:f.textures,G=r.parser.json.textures[b];if((D=G.extensions)!=null&&D[k]){const m=G.extensions[k];m&&i&&w.registerTexture(i,x,m.lods.length,m)}}}};const s=t.material;if(Array.isArray(s))for(const n of s)o(n);else o(s)}}tryParseMeshLOD(e,t){var o,s;if(t[Q]==!0)return;t[Q]=!0;const r=this.getUrl();if(!r){console.error("No url found in modelviewer");return}const i=(s=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:s[k];if(i&&r){const n=t.uuid;w.registerMesh(r,n,t,0,i.lods.length,i)}}}function ye(l,e,t,r){Z(e),j(t),t.register(o=>new w(o,l));const i=new _(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{ee(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=k;exports.LODsManager=_;exports.NEEDLE_progressive=w;exports.patchModelViewer=ee;exports.registerPlugin=fe;exports.useNeedleProgressive=ye;
|