@needle-tools/gltf-progressive 1.0.0-alpha.7 → 1.0.0-alpha.8

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 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.0.0-alpha.8] - 2023-05-03
8
+ - fix: handle transparent materials
9
+
7
10
  ## [1.0.0-alpha.7] - 2023-05-01
8
11
  - fix: Handle modelviewer `src` set as property but not as attribute
9
12
  - change: Remove sourcemap
@@ -1,24 +1,24 @@
1
1
  var oe = Object.defineProperty;
2
2
  var ae = (l, e, t) => e in l ? oe(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
3
3
  var u = (l, e, t) => (ae(l, typeof e != "symbol" ? e + "" : e, t), t);
4
- import { Mesh as Y, BufferGeometry as q, Material as le, RawShaderMaterial as ue, Texture as G, TextureLoader as ce, Matrix4 as Z, Frustum as fe, Sphere as de, Box3 as j, Vector3 as C } from "three";
4
+ import { Mesh as q, BufferGeometry as X, Material as le, RawShaderMaterial as ue, Texture as U, TextureLoader as ce, Matrix4 as j, Frustum as fe, Sphere as de, Box3 as ee, Vector3 as k } from "three";
5
5
  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
- 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 z, V, W;
9
+ const me = "https://www.gstatic.com/draco/versioned/decoders/1.4.1/", Le = "https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";
10
+ let F, H, W;
11
11
  function se(l) {
12
- z || (z = new pe(), z.setDecoderPath(Le), z.setDecoderConfig({ type: "js" })), W || (W = new ye(), W.setTranscoderPath(De)), V || (V = he), l ? W.detectSupport(l) : console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail");
12
+ F || (F = new pe(), F.setDecoderPath(me), F.setDecoderConfig({ type: "js" })), W || (W = new ye(), W.setTranscoderPath(Le)), H || (H = he), l ? W.detectSupport(l) : console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail");
13
13
  }
14
14
  function ie(l) {
15
- l.dracoLoader || l.setDRACOLoader(z), l.ktx2Loader || l.setKTX2Loader(W), l.meshoptDecoder || l.setMeshoptDecoder(V);
15
+ l.dracoLoader || l.setDRACOLoader(F), l.ktx2Loader || l.setKTX2Loader(W), l.meshoptDecoder || l.setMeshoptDecoder(H);
16
16
  }
17
- function Q(l) {
17
+ function Z(l) {
18
18
  const t = new URL(window.location.href).searchParams.get(l);
19
19
  return t == null || t === "0" || t === "false" ? !1 : t === "" ? !0 : t;
20
20
  }
21
- function me(l, e) {
21
+ function De(l, e) {
22
22
  if (e === void 0 || e.startsWith("./") || e.startsWith("http") || l === void 0)
23
23
  return e;
24
24
  const t = l.lastIndexOf("/");
@@ -30,19 +30,19 @@ function me(l, e) {
30
30
  }
31
31
  return e;
32
32
  }
33
- const H = new Array();
34
- function ke(l) {
35
- H.push(l);
33
+ const J = new Array();
34
+ function Be(l) {
35
+ J.push(l);
36
36
  }
37
- const R = "NEEDLE_progressive", S = Q("debugprogressive"), N = Symbol("needle-progressive-texture"), I = /* @__PURE__ */ new Map(), J = /* @__PURE__ */ new Set();
37
+ const R = "NEEDLE_progressive", S = Z("debugprogressive"), V = Symbol("needle-progressive-texture"), z = /* @__PURE__ */ new Map(), Q = /* @__PURE__ */ new Set();
38
38
  if (S) {
39
39
  let l = function() {
40
- e += 1, console.log("Toggle LOD level", e, I), I.forEach((i, n) => {
40
+ e += 1, console.log("Toggle LOD level", e, z), z.forEach((i, n) => {
41
41
  for (const s of i.keys) {
42
42
  const o = n[s];
43
43
  if (o.isBufferGeometry === !0) {
44
- const a = v.getMeshLODInformation(o), g = a ? Math.min(e, a.lods.length) : 0;
45
- n["DEBUG:LOD"] = e, v.assignMeshLOD(n, g), a && (t = Math.max(t, a.lods.length - 1));
44
+ const a = v.getMeshLODInformation(o), h = a ? Math.min(e, a.lods.length) : 0;
45
+ n["DEBUG:LOD"] = e, v.assignMeshLOD(n, h), a && (t = Math.max(t, a.lods.length - 1));
46
46
  } else if (n.isMaterial === !0) {
47
47
  n["DEBUG:LOD"] = e, v.assignTextureLOD(n, e);
48
48
  break;
@@ -51,17 +51,17 @@ if (S) {
51
51
  }), e >= t && (e = -1);
52
52
  }, e = -1, t = 2, r = !1;
53
53
  window.addEventListener("keyup", (i) => {
54
- i.key === "p" && l(), i.key === "w" && (r = !r, J && J.forEach((n) => {
54
+ i.key === "p" && l(), i.key === "w" && (r = !r, Q && Q.forEach((n) => {
55
55
  n.name != "BackgroundCubeMaterial" && "wireframe" in n && (n.wireframe = r);
56
56
  }));
57
57
  });
58
58
  }
59
- function ee(l, e, t) {
59
+ function te(l, e, t) {
60
60
  var i;
61
61
  if (!S)
62
62
  return;
63
- I.has(l) || I.set(l, { keys: [], sourceId: t });
64
- const r = I.get(l);
63
+ z.has(l) || z.set(l, { keys: [], sourceId: t });
64
+ const r = z.get(l);
65
65
  ((i = r == null ? void 0 : r.keys) == null ? void 0 : i.includes(e)) == !1 && r.keys.push(e);
66
66
  }
67
67
  const M = class {
@@ -125,11 +125,11 @@ const M = class {
125
125
  var r;
126
126
  if (!e)
127
127
  return Promise.resolve(null);
128
- if (e instanceof Y || e.isMesh === !0) {
128
+ if (e instanceof q || e.isMesh === !0) {
129
129
  const i = e.geometry, n = this.getAssignedLODInformation(i);
130
130
  if (!n)
131
131
  return Promise.resolve(null);
132
- for (const s of H)
132
+ for (const s of J)
133
133
  (r = s.onBeforeGetLODMesh) == null || r.call(s, e, t);
134
134
  return e["LOD:requested level"] = t, M.getOrLoadLOD(i, t).then((s) => {
135
135
  if (e["LOD:requested level"] === t) {
@@ -137,7 +137,7 @@ const M = class {
137
137
  const o = n.index || 0;
138
138
  s = s[o];
139
139
  }
140
- s && i != s && s instanceof q && (e.geometry = s, S && ee(e, "geometry", n.url));
140
+ s && i != s && s instanceof X && (e.geometry = s, S && te(e, "geometry", n.url));
141
141
  }
142
142
  return s;
143
143
  }).catch((s) => (console.error("Error loading mesh LOD", e, s), null));
@@ -157,7 +157,7 @@ const M = class {
157
157
  return Promise.resolve(null);
158
158
  if (e instanceof le || e.isMaterial === !0) {
159
159
  const r = e, i = [], n = new Array();
160
- if (S && J.add(r), r instanceof ue)
160
+ if (S && Q.add(r), r instanceof ue)
161
161
  for (const s of Object.keys(r.uniforms)) {
162
162
  const o = r.uniforms[s].value;
163
163
  if ((o == null ? void 0 : o.isTexture) === !0) {
@@ -176,13 +176,13 @@ const M = class {
176
176
  return Promise.all(i).then((s) => {
177
177
  const o = new Array();
178
178
  for (let a = 0; a < s.length; a++) {
179
- const g = s[a], f = n[a];
180
- g && g.isTexture === !0 ? o.push({ material: r, slot: f, texture: g, level: t }) : o.push({ material: r, slot: f, texture: null, level: t });
179
+ const h = s[a], d = n[a];
180
+ h && h.isTexture === !0 ? o.push({ material: r, slot: d, texture: h, level: t }) : o.push({ material: r, slot: d, texture: null, level: t });
181
181
  }
182
182
  return o;
183
183
  });
184
184
  }
185
- if (e instanceof G || e.isTexture === !0) {
185
+ if (e instanceof U || e.isTexture === !0) {
186
186
  const r = e;
187
187
  return this.assignTextureLODForSlot(r, t, null, null);
188
188
  }
@@ -195,7 +195,7 @@ const M = class {
195
195
  if ((n == null ? void 0 : n.isTexture) === !0) {
196
196
  if (n != e && (r && i && (r[i] = n), S && i && r)) {
197
197
  const s = this.getAssignedLODInformation(e);
198
- s && ee(r, i, s.url);
198
+ s && te(r, i, s.url);
199
199
  }
200
200
  return n;
201
201
  } else
@@ -231,107 +231,107 @@ const M = class {
231
231
  }), null;
232
232
  }
233
233
  static async getOrLoadLOD(e, t) {
234
- var o, a, g;
234
+ var o, a, h;
235
235
  const r = S == "verbose", i = e.userData.LODS;
236
236
  if (!i)
237
237
  return null;
238
238
  const n = i == null ? void 0 : i.key;
239
239
  let s;
240
240
  if (e.isTexture === !0) {
241
- const f = e;
242
- f.source && f.source[N] && (s = f.source[N]);
241
+ const d = e;
242
+ d.source && d.source[V] && (s = d.source[V]);
243
243
  }
244
244
  if (s || (s = M.lodInfos.get(n)), s) {
245
245
  if (t > 0) {
246
- let d = !1;
246
+ let f = !1;
247
247
  const w = Array.isArray(s.lods);
248
- if (w && t >= s.lods.length ? d = !0 : w || (d = !0), d)
248
+ if (w && t >= s.lods.length ? f = !0 : w || (f = !0), f)
249
249
  return this.lowresCache.get(n);
250
250
  }
251
- const f = Array.isArray(s.lods) ? s.lods[t].path : s.lods;
252
- if (!f)
251
+ const d = Array.isArray(s.lods) ? s.lods[t].path : s.lods;
252
+ if (!d)
253
253
  return S && !s["missing:uri"] && (s["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + t, s)), null;
254
- const L = me(i.url, f);
255
- if (L.endsWith(".glb") || L.endsWith(".gltf")) {
254
+ const c = De(i.url, d);
255
+ if (c.endsWith(".glb") || c.endsWith(".gltf")) {
256
256
  if (!s.guid)
257
257
  return console.warn("missing pointer for glb/gltf texture", s), null;
258
- const d = L + "_" + s.guid, w = this.previouslyLoaded.get(d);
258
+ const f = c + "_" + s.guid, w = this.previouslyLoaded.get(f);
259
259
  if (w !== void 0) {
260
- r && console.log(`LOD ${t} was already loading/loaded: ${d}`);
261
- let m = await w.catch((E) => (console.error(`Error loading LOD ${t} from ${L}
262
- `, E), null)), B = !1;
263
- if (m == null || (m instanceof G && e instanceof G ? (o = m.image) != null && o.data || (a = m.source) != null && a.data ? m = this.copySettings(e, m) : (B = !0, this.previouslyLoaded.delete(d)) : m instanceof q && e instanceof q && ((g = m.attributes.position) != null && g.array || (B = !0, this.previouslyLoaded.delete(d)))), !B)
264
- return m;
260
+ r && console.log(`LOD ${t} was already loading/loaded: ${f}`);
261
+ let D = await w.catch((I) => (console.error(`Error loading LOD ${t} from ${c}
262
+ `, I), null)), C = !1;
263
+ if (D == null || (D instanceof U && e instanceof U ? (o = D.image) != null && o.data || (a = D.source) != null && a.data ? D = this.copySettings(e, D) : (C = !0, this.previouslyLoaded.delete(f)) : D instanceof X && e instanceof X && ((h = D.attributes.position) != null && h.array || (C = !0, this.previouslyLoaded.delete(f)))), !C)
264
+ return D;
265
265
  }
266
- const D = s, b = new Promise(async (m, B) => {
267
- const E = new ge();
268
- ie(E), S && (await new Promise((p) => setTimeout(p, 1e3)), r && console.warn("Start loading (delayed) " + L, D.guid));
269
- let y = L;
270
- if (D && Array.isArray(D.lods)) {
271
- const p = D.lods[t];
272
- p.hash && (y += "?v=" + p.hash);
266
+ const L = s, A = new Promise(async (D, C) => {
267
+ const I = new ge();
268
+ ie(I), S && (await new Promise((y) => setTimeout(y, 1e3)), r && console.warn("Start loading (delayed) " + c, L.guid));
269
+ let m = c;
270
+ if (L && Array.isArray(L.lods)) {
271
+ const y = L.lods[t];
272
+ y.hash && (m += "?v=" + y.hash);
273
273
  }
274
- const h = await E.loadAsync(y).catch((p) => (console.error(`Error loading LOD ${t} from ${L}
275
- `, p), null));
276
- if (!h)
274
+ const p = await I.loadAsync(m).catch((y) => (console.error(`Error loading LOD ${t} from ${c}
275
+ `, y), null));
276
+ if (!p)
277
277
  return null;
278
- const T = h.parser;
279
- r && console.log("Loading finished " + L, D.guid);
278
+ const b = p.parser;
279
+ r && console.log("Loading finished " + c, L.guid);
280
280
  let x = 0;
281
- if (h.parser.json.textures) {
282
- let p = !1;
283
- for (const c of h.parser.json.textures) {
284
- if (c != null && c.extensions) {
285
- const O = c == null ? void 0 : c.extensions[R];
286
- if (O != null && O.guid && O.guid === D.guid) {
287
- p = !0;
281
+ if (p.parser.json.textures) {
282
+ let y = !1;
283
+ for (const g of p.parser.json.textures) {
284
+ if (g != null && g.extensions) {
285
+ const O = g == null ? void 0 : g.extensions[R];
286
+ if (O != null && O.guid && O.guid === L.guid) {
287
+ y = !0;
288
288
  break;
289
289
  }
290
290
  }
291
291
  x++;
292
292
  }
293
- if (p) {
294
- let c = await T.getDependency("texture", x);
295
- return r && console.log('change "' + e.name + '" → "' + c.name + '"', L, x, c, d), e instanceof G && (c = this.copySettings(e, c)), c && (c.guid = D.guid), m(c);
293
+ if (y) {
294
+ let g = await b.getDependency("texture", x);
295
+ return r && console.log('change "' + e.name + '" → "' + g.name + '"', c, x, g, f), e instanceof U && (g = this.copySettings(e, g)), g && (g.guid = L.guid), D(g);
296
296
  }
297
297
  }
298
- if (x = 0, h.parser.json.meshes) {
299
- let p = !1;
300
- for (const c of h.parser.json.meshes) {
301
- if (c != null && c.extensions) {
302
- const O = c == null ? void 0 : c.extensions[R];
303
- if (O != null && O.guid && O.guid === D.guid) {
304
- p = !0;
298
+ if (x = 0, p.parser.json.meshes) {
299
+ let y = !1;
300
+ for (const g of p.parser.json.meshes) {
301
+ if (g != null && g.extensions) {
302
+ const O = g == null ? void 0 : g.extensions[R];
303
+ if (O != null && O.guid && O.guid === L.guid) {
304
+ y = !0;
305
305
  break;
306
306
  }
307
307
  }
308
308
  x++;
309
309
  }
310
- if (p) {
311
- const c = await T.getDependency("mesh", x), O = D;
312
- if (r && console.log(`Loaded Mesh "${c.name}"`, L, x, c, d), c.isMesh === !0) {
313
- const P = c.geometry;
314
- return M.assignLODInformation(i.url, P, n, t, void 0, O.density), m(P);
310
+ if (y) {
311
+ const g = await b.getDependency("mesh", x), O = L;
312
+ if (r && console.log(`Loaded Mesh "${g.name}"`, c, x, g, f), g.isMesh === !0) {
313
+ const P = g.geometry;
314
+ return M.assignLODInformation(i.url, P, n, t, void 0, O.density), D(P);
315
315
  } else {
316
316
  const P = new Array();
317
- for (let _ = 0; _ < c.children.length; _++) {
318
- const U = c.children[_];
319
- if (U instanceof Y) {
320
- const $ = U.geometry;
321
- M.assignLODInformation(i.url, $, n, t, _, O.density), P.push($);
317
+ for (let _ = 0; _ < g.children.length; _++) {
318
+ const E = g.children[_];
319
+ if (E instanceof q) {
320
+ const N = E.geometry;
321
+ M.assignLODInformation(i.url, N, n, t, _, O.density), P.push(N);
322
322
  }
323
323
  }
324
- return m(P);
324
+ return D(P);
325
325
  }
326
326
  }
327
327
  }
328
- return m(null);
328
+ return D(null);
329
329
  });
330
- return this.previouslyLoaded.set(d, b), await b;
331
- } else if (e instanceof G) {
332
- r && console.log("Load texture from uri: " + L);
333
- const w = await new ce().loadAsync(L);
334
- return w ? (w.guid = s.guid, w.flipY = !1, w.needsUpdate = !0, w.colorSpace = e.colorSpace, r && console.log(s, w)) : S && console.warn("failed loading", L), w;
330
+ return this.previouslyLoaded.set(f, A), await A;
331
+ } else if (e instanceof U) {
332
+ r && console.log("Load texture from uri: " + c);
333
+ const w = await new ce().loadAsync(c);
334
+ return w ? (w.guid = s.guid, w.flipY = !1, w.needsUpdate = !0, w.colorSpace = e.colorSpace, r && console.log(s, w)) : S && console.warn("failed loading", c), w;
335
335
  }
336
336
  } else
337
337
  S && console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`, e.type);
@@ -358,21 +358,21 @@ let v = M;
358
358
  * Register a texture with LOD information
359
359
  */
360
360
  u(v, "registerTexture", (e, t, r, i) => {
361
- S && console.log("> Progressive: register texture", r, t.name, t.uuid, t, i), t.source && (t.source[N] = i);
361
+ S && console.log("> Progressive: register texture", r, t.name, t.uuid, t, i), t.source && (t.source[V] = i);
362
362
  const n = i.guid;
363
363
  M.assignLODInformation(e, t, n, 0, 0, void 0), M.lodInfos.set(n, i), M.lowresCache.set(n, t);
364
364
  }), /**
365
365
  * Register a mesh with LOD information
366
366
  */
367
367
  u(v, "registerMesh", (e, t, r, i, n, s) => {
368
- var g;
368
+ var h;
369
369
  S && console.log("> Progressive: register mesh", n, r.name, s, r.uuid, r);
370
370
  const o = r.geometry;
371
371
  o.userData || (o.userData = {}), M.assignLODInformation(e, o, t, i, n, s.density), M.lodInfos.set(t, s);
372
372
  let a = M.lowresCache.get(t);
373
373
  a ? a.push(r.geometry) : a = [r.geometry], M.lowresCache.set(t, a);
374
- for (const f of H)
375
- (g = f.onRegisteredNewMesh) == null || g.call(f, r, s);
374
+ for (const d of J)
375
+ (h = d.onRegisteredNewMesh) == null || h.call(d, r, s);
376
376
  }), /** A map of key = asset uuid and value = LOD information */
377
377
  u(v, "lodInfos", /* @__PURE__ */ new Map()), /** cache of already loaded mesh lods */
378
378
  u(v, "previouslyLoaded", /* @__PURE__ */ new Map()), /** this contains the geometry/textures that were originally loaded */
@@ -390,10 +390,10 @@ class xe {
390
390
  this.url = e, this.key = t, this.level = r, i != null && (this.index = i), n != null && (this.density = n);
391
391
  }
392
392
  }
393
- const te = Q("debugprogressive"), we = Q("noprogressive"), A = class {
393
+ const Y = Z("debugprogressive"), we = Z("noprogressive"), T = class {
394
394
  constructor(e) {
395
395
  u(this, "renderer");
396
- u(this, "projectionScreenMatrix", new Z());
396
+ u(this, "projectionScreenMatrix", new j());
397
397
  u(this, "cameraFrustrum", new fe());
398
398
  /**
399
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.
@@ -407,11 +407,11 @@ const te = Q("debugprogressive"), we = Q("noprogressive"), A = class {
407
407
  u(this, "_originalRender");
408
408
  // private testIfLODLevelsAreAvailable() {
409
409
  u(this, "_sphere", new de());
410
- u(this, "_tempBox", new j());
411
- u(this, "tempMatrix", new Z());
412
- u(this, "_tempWorldPosition", new C());
413
- u(this, "_tempBoxSize", new C());
414
- u(this, "_tempBox2Size", new C());
410
+ u(this, "_tempBox", new ee());
411
+ u(this, "tempMatrix", new j());
412
+ u(this, "_tempWorldPosition", new k());
413
+ u(this, "_tempBoxSize", new k());
414
+ u(this, "_tempBox2Size", new k());
415
415
  this.renderer = e;
416
416
  }
417
417
  /** @internal */
@@ -440,35 +440,45 @@ const te = Q("debugprogressive"), we = Q("noprogressive"), A = class {
440
440
  onBeforeRender(e, t, r, i) {
441
441
  }
442
442
  onAfterRender(e, t, r, i) {
443
+ var h, d;
443
444
  if (we || this.pause || this.updateInterval > 0 && i % this.updateInterval != 0)
444
445
  return;
445
446
  this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix, t.matrixWorldInverse), this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix, this.renderer.coordinateSystem);
446
- const n = 1e5, o = this.renderer.renderLists.get(e, r).opaque;
447
- for (const a of o) {
448
- const g = a.object;
449
- (g instanceof Y || g.isMesh) && this.updateLODs(e, t, g, n);
447
+ const n = 1e5, s = this.renderer.renderLists.get(e, r), o = s.opaque;
448
+ for (const c of o) {
449
+ if (c.material && (((h = c.geometry) == null ? void 0 : h.type) === "BoxGeometry" || ((d = c.geometry) == null ? void 0 : d.type) === "BufferGeometry") && (c.material.name === "SphericalGaussianBlur" || c.material.name == "BackgroundCubeMaterial" || c.material.name === "CubemapFromEquirect" || c.material.name === "EquirectangularToCubeUV")) {
450
+ Y && (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)));
451
+ continue;
452
+ }
453
+ const f = c.object;
454
+ (f instanceof q || f.isMesh) && this.updateLODs(e, t, f, n);
455
+ }
456
+ const a = s.transparent;
457
+ for (const c of a) {
458
+ const f = c.object;
459
+ (f instanceof q || f.isMesh) && this.updateLODs(e, t, f, n);
450
460
  }
451
461
  }
452
462
  /** Update the LOD levels for the renderer. */
453
463
  updateLODs(e, t, r, i) {
454
- var a, g;
455
- for (const f of this.plugins)
456
- (a = f.onBeforeUpdateLOD) == null || a.call(f, this.renderer, e, t, r);
464
+ var a, h;
465
+ for (const d of this.plugins)
466
+ (a = d.onBeforeUpdateLOD) == null || a.call(d, this.renderer, e, t, r);
457
467
  let n = r.userData.LOD_state;
458
468
  n || (n = new Oe(), r.userData.LOD_state = n);
459
469
  let s = this.calculateLodLevel(t, r, n, i);
460
470
  s = Math.round(s), s >= 0 && this.loadProgressiveMeshes(r, s);
461
471
  let o = 0;
462
472
  if (r.material) {
463
- const f = r["DEBUG:LOD"];
464
- if (f != null && (o = f), Array.isArray(r.material))
465
- for (const L of r.material)
466
- this.loadProgressiveTextures(L, o);
473
+ const d = r["DEBUG:LOD"];
474
+ if (d != null && (o = d), Array.isArray(r.material))
475
+ for (const c of r.material)
476
+ this.loadProgressiveTextures(c, o);
467
477
  else
468
478
  this.loadProgressiveTextures(r.material, o);
469
479
  }
470
- for (const f of this.plugins)
471
- (g = f.onAfterUpdatedLOD) == null || g.call(f, this.renderer, e, t, r, s);
480
+ for (const d of this.plugins)
481
+ (h = d.onAfterUpdatedLOD) == null || h.call(d, this.renderer, e, t, r, s);
472
482
  n.lastLodLevel = s;
473
483
  }
474
484
  /** Load progressive textures for the given material
@@ -501,69 +511,69 @@ const te = Q("debugprogressive"), we = Q("noprogressive"), A = class {
501
511
  return -1;
502
512
  let s = 10 + 1;
503
513
  if (e) {
504
- if (te && t["DEBUG:LOD"] != null)
514
+ if (Y && t["DEBUG:LOD"] != null)
505
515
  return t["DEBUG:LOD"];
506
- const a = v.getMeshLODInformation(t.geometry), g = a == null ? void 0 : a.lods;
507
- if (!g || g.length <= 0 || !((o = this.cameraFrustrum) != null && o.intersectsObject(t)))
516
+ const a = v.getMeshLODInformation(t.geometry), h = a == null ? void 0 : a.lods;
517
+ if (!h || h.length <= 0 || !((o = this.cameraFrustrum) != null && o.intersectsObject(t)))
508
518
  return 99;
509
- const f = t.geometry.boundingBox;
510
- if (f && e.isPerspectiveCamera) {
511
- const L = e;
519
+ const d = t.geometry.boundingBox;
520
+ if (d && e.isPerspectiveCamera) {
521
+ const c = e;
512
522
  if (t.geometry.attributes.color && t.geometry.attributes.color.count < 100 && t.geometry.boundingSphere) {
513
523
  this._sphere.copy(t.geometry.boundingSphere), this._sphere.applyMatrix4(t.matrixWorld);
514
- const y = e.getWorldPosition(this._tempWorldPosition);
515
- if (this._sphere.containsPoint(y))
524
+ const m = e.getWorldPosition(this._tempWorldPosition);
525
+ if (this._sphere.containsPoint(m))
516
526
  return 0;
517
527
  }
518
- if (this._tempBox.copy(f), this._tempBox.applyMatrix4(t.matrixWorld), this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && L.fov > 70) {
519
- const y = this._tempBox.min, h = this._tempBox.max;
520
- let T = y.x, x = y.y, p = h.x, c = h.y;
521
- const O = 2, P = 1.5, _ = (y.x + h.x) * 0.5, U = (y.y + h.y) * 0.5;
522
- T = (T - _) * O + _, x = (x - U) * O + U, p = (p - _) * O + _, c = (c - U) * O + U;
523
- const $ = T < 0 && p > 0 ? 0 : Math.min(Math.abs(y.x), Math.abs(h.x)), ne = x < 0 && c > 0 ? 0 : Math.min(Math.abs(y.y), Math.abs(h.y)), X = Math.max($, ne);
524
- r.lastCentrality = (P - X) * (P - X) * (P - X);
528
+ if (this._tempBox.copy(d), this._tempBox.applyMatrix4(t.matrixWorld), this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && c.fov > 70) {
529
+ const m = this._tempBox.min, p = this._tempBox.max;
530
+ let b = m.x, x = m.y, y = p.x, g = p.y;
531
+ const O = 2, P = 1.5, _ = (m.x + p.x) * 0.5, E = (m.y + p.y) * 0.5;
532
+ b = (b - _) * O + _, x = (x - E) * O + E, y = (y - _) * O + _, g = (g - E) * O + E;
533
+ const N = b < 0 && y > 0 ? 0 : Math.min(Math.abs(m.x), Math.abs(p.x)), ne = x < 0 && g > 0 ? 0 : Math.min(Math.abs(m.y), Math.abs(p.y)), K = Math.max(N, ne);
534
+ r.lastCentrality = (P - K) * (P - K) * (P - K);
525
535
  } else
526
536
  r.lastCentrality = 1;
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;
529
- const w = e.matrixWorldInverse, D = new j();
530
- D.copy(f), D.applyMatrix4(t.matrixWorld), D.applyMatrix4(w);
531
- const b = D.getSize(this._tempBox2Size), F = Math.max(b.x, b.y);
532
- if (Math.max(d.x, d.y) != 0 && F != 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, te && A.debugDrawLine) {
533
- const y = this.tempMatrix.copy(this.projectionScreenMatrix);
534
- y.invert();
535
- const h = A.corner0, T = A.corner1, x = A.corner2, p = A.corner3;
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);
537
- const c = (h.z + p.z) * 0.5;
538
- h.z = T.z = x.z = p.z = c, h.applyMatrix4(y), T.applyMatrix4(y), x.applyMatrix4(y), p.applyMatrix4(y), A.debugDrawLine(h, T, 255), A.debugDrawLine(h, x, 255), A.debugDrawLine(T, p, 255), A.debugDrawLine(x, p, 255);
537
+ const f = this._tempBox.getSize(this._tempBoxSize);
538
+ f.multiplyScalar(0.5), screen.availHeight > 0 && f.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), f.x *= c.aspect;
539
+ const w = e.matrixWorldInverse, L = new ee();
540
+ L.copy(d), L.applyMatrix4(t.matrixWorld), L.applyMatrix4(w);
541
+ const A = L.getSize(this._tempBox2Size), G = Math.max(A.x, A.y);
542
+ if (Math.max(f.x, f.y) != 0 && G != 0 && (f.z = A.z / Math.max(A.x, A.y) * Math.max(f.x, f.y)), r.lastScreenCoverage = Math.max(f.x, f.y, f.z), r.lastScreenspaceVolume.copy(f), r.lastScreenCoverage *= r.lastCentrality, Y && T.debugDrawLine) {
543
+ const m = this.tempMatrix.copy(this.projectionScreenMatrix);
544
+ m.invert();
545
+ const p = T.corner0, b = T.corner1, x = T.corner2, y = T.corner3;
546
+ p.copy(this._tempBox.min), b.copy(this._tempBox.max), b.x = p.x, x.copy(this._tempBox.max), x.y = p.y, y.copy(this._tempBox.max);
547
+ const g = (p.z + y.z) * 0.5;
548
+ p.z = b.z = x.z = y.z = g, p.applyMatrix4(m), b.applyMatrix4(m), x.applyMatrix4(m), y.applyMatrix4(m), T.debugDrawLine(p, b, 255), T.debugDrawLine(p, x, 255), T.debugDrawLine(b, y, 255), T.debugDrawLine(x, y, 255);
539
549
  }
540
- let B = 999;
541
- if (g && r.lastScreenCoverage > 0) {
542
- for (let y = 0; y < g.length; y++)
543
- if (g[y].density / r.lastScreenCoverage < i) {
544
- B = y;
550
+ let C = 999;
551
+ if (h && r.lastScreenCoverage > 0) {
552
+ for (let m = 0; m < h.length; m++)
553
+ if (h[m].density / r.lastScreenCoverage < i) {
554
+ C = m;
545
555
  break;
546
556
  }
547
557
  }
548
- B < s && (s = B);
558
+ C < s && (s = C);
549
559
  }
550
560
  }
551
561
  return s;
552
562
  }
553
563
  };
554
- let k = A;
564
+ let B = T;
555
565
  /** 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
566
  */
557
- u(k, "debugDrawLine"), u(k, "corner0", new C()), u(k, "corner1", new C()), u(k, "corner2", new C()), u(k, "corner3", new C());
567
+ u(B, "debugDrawLine"), u(B, "corner0", new k()), u(B, "corner1", new k()), u(B, "corner2", new k()), u(B, "corner3", new k());
558
568
  class Oe {
559
569
  constructor() {
560
570
  u(this, "lastLodLevel", 0);
561
571
  u(this, "lastScreenCoverage", 0);
562
- u(this, "lastScreenspaceVolume", new C());
572
+ u(this, "lastScreenspaceVolume", new k());
563
573
  u(this, "lastCentrality", 0);
564
574
  }
565
575
  }
566
- const re = Symbol("NEEDLE_mesh_lod"), K = Symbol("NEEDLE_texture_lod");
576
+ const re = Symbol("NEEDLE_mesh_lod"), $ = Symbol("NEEDLE_texture_lod");
567
577
  function Me(l) {
568
578
  if (!l)
569
579
  return null;
@@ -574,7 +584,7 @@ function Me(l) {
574
584
  }
575
585
  if (e) {
576
586
  console.log("Adding Needle LODs to modelviewer");
577
- const r = new k(e);
587
+ const r = new B(e);
578
588
  if (r.plugins.push(new ve(l)), r.enable(), t) {
579
589
  const i = t.camera || t.traverse((n) => n.type == "PerspectiveCamera")[0];
580
590
  i && e.render(t, i);
@@ -602,24 +612,24 @@ class ve {
602
612
  return e._currentGLTF;
603
613
  }
604
614
  tryParseTextureLOD(e, t) {
605
- if (t[K] == !0)
615
+ if (t[$] == !0)
606
616
  return;
607
- t[K] = !0;
617
+ t[$] = !0;
608
618
  const r = this.tryGetCurrentGLTF(e), i = this.getUrl();
609
619
  if (i && r && t.material) {
610
620
  let n = function(o) {
611
- var g, f, L;
612
- if (o[K] == !0)
621
+ var h, d, c;
622
+ if (o[$] == !0)
613
623
  return;
614
- o[K] = !0, o.userData && (o.userData.LOD = -1);
624
+ o[$] = !0, o.userData && (o.userData.LOD = -1);
615
625
  const a = Object.keys(o);
616
- for (let d = 0; d < a.length; d++) {
617
- const w = a[d], D = o[w];
618
- if ((D == null ? void 0 : D.isTexture) === !0) {
619
- const b = (f = (g = D.userData) == null ? void 0 : g.associations) == null ? void 0 : f.textures, F = r.parser.json.textures[b];
620
- if ((L = F.extensions) != null && L[R]) {
621
- const m = F.extensions[R];
622
- m && i && v.registerTexture(i, D, m.lods.length, m);
626
+ for (let f = 0; f < a.length; f++) {
627
+ const w = a[f], L = o[w];
628
+ if ((L == null ? void 0 : L.isTexture) === !0) {
629
+ const A = (d = (h = L.userData) == null ? void 0 : h.associations) == null ? void 0 : d.textures, G = r.parser.json.textures[A];
630
+ if ((c = G.extensions) != null && c[R]) {
631
+ const D = G.extensions[R];
632
+ D && i && v.registerTexture(i, L, D.lods.length, D);
623
633
  }
624
634
  }
625
635
  }
@@ -647,9 +657,9 @@ class ve {
647
657
  }
648
658
  }
649
659
  }
650
- function Be(l, e, t, r) {
660
+ function Ce(l, e, t, r) {
651
661
  se(e), ie(t), t.register((n) => new v(n, l));
652
- const i = new k(e);
662
+ const i = new B(e);
653
663
  return (r == null ? void 0 : r.enableLODsManager) !== !1 && i.enable(), i;
654
664
  }
655
665
  document.addEventListener("DOMContentLoaded", () => {
@@ -657,9 +667,9 @@ document.addEventListener("DOMContentLoaded", () => {
657
667
  });
658
668
  export {
659
669
  R as EXTENSION_NAME,
660
- k as LODsManager,
670
+ B as LODsManager,
661
671
  v as NEEDLE_progressive,
662
672
  Me as patchModelViewer,
663
- ke as registerPlugin,
664
- Be as useNeedleProgressive
673
+ Be as registerPlugin,
674
+ Ce as useNeedleProgressive
665
675
  };
@@ -1,3 +1,3 @@
1
- var se=Object.defineProperty,oe=(r,e,t)=>e in r?se(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,u=(r,e,t)=>(oe(r,typeof e!="symbol"?e+"":e,t),t);import{Mesh as F,BufferGeometry as N,Material as ne,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,$,U;function J(r){R||(R=new he,R.setDecoderPath(ge),R.setDecoderConfig({type:"js"})),U||(U=new fe,U.setTranscoderPath(pe)),$||($=de),r?U.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(U),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 o=r.substring(0,t+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}const V=new Array;function ye(r){V.push(r)}const B="NEEDLE_progressive",D=q("debugprogressive"),X=Symbol("needle-progressive-texture"),W=new Map,H=new Set;if(D){let r=function(){e+=1,console.log("Toggle LOD level",e,W),W.forEach((n,s)=>{for(const a of n.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,o=!1;window.addEventListener("keyup",n=>{n.key==="p"&&r(),n.key==="w"&&(o=!o,H&&H.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=o)}))})}function Z(r,e,t){var o;if(!D)return;W.has(r)||W.set(r,{keys:[],sourceId:t});const n=W.get(r);((o=n?.keys)==null?void 0:o.includes(e))==!1&&n.keys.push(e)}const L=class{constructor(r,e){u(this,"parser"),u(this,"url"),D&&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 o,n;if(r.isMesh?o=r.geometry:(r.isBufferGeometry||r.isTexture)&&(o=r),o&&(t=o?.userData)!=null&&t.LODS){const s=o.userData.LODS;if(n=this.lodInfos.get(s.key),e===void 0)return n!=null;if(n)return Array.isArray(n.lods)?e<n.lods.length:e===0}return!1}static assignMeshLOD(r,e){var t;if(!r)return Promise.resolve(null);if(r instanceof F||r.isMesh===!0){const o=r.geometry,n=this.getAssignedLODInformation(o);if(!n)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(o,e).then(s=>{if(r["LOD:requested level"]===e){if(delete r["LOD:requested level"],Array.isArray(s)){const a=n.index||0;s=s[a]}s&&o!=s&&s instanceof N&&(r.geometry=s,D&&Z(r,"geometry",n.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",r,s),null))}else D&&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 ne||r.isMaterial===!0){const t=r,o=[],n=new Array;if(D&&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);o.push(i),n.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);o.push(i),n.push(s)}}return Promise.all(o).then(s=>{const a=new Array;for(let i=0;i<s.length;i++){const l=s[i],d=n[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,o){return r?.isTexture!==!0?Promise.resolve(null):L.getOrLoadLOD(r,e).then(n=>{if(Array.isArray(n))return null;if(n?.isTexture===!0){if(n!=r&&(t&&o&&(t[o]=n),D&&o&&t)){const s=this.getAssignedLODInformation(r);s&&Z(t,o,s.url)}return n}else D=="verbose"&&console.warn("No LOD found for",r,e);return null}).catch(n=>(console.error("Error loading LOD",r,n),null))}afterRoot(r){var e,t;return D&&console.log("AFTER",this.url,r),(e=this.parser.json.textures)==null||e.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[B];if(s){let a=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i).textures===n&&(a=!0,L.registerTexture(this.url,i,n,s));a||this.parser.getDependency("texture",n).then(i=>{i&&L.registerTexture(this.url,i,n,s)})}}}),(t=this.parser.json.meshes)==null||t.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.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===n&&L.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(r,e){var t,o,n;const s=D=="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 D&&!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||(o=m.source)!=null&&o.data?m=this.copySettings(r,m):(f=!0,this.previouslyLoaded.delete(g)):m instanceof N&&r instanceof N&&((n=m.attributes.position)!=null&&n.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),D&&(await new Promise(v=>setTimeout(v,1e3)),s&&console.warn("Start loading (delayed) "+c,y.guid));let b=c;if(y&&Array.isArray(y.lods)){const v=y.lods[e];v.hash&&(b+="?v="+v.hash)}const x=await p.loadAsync(b).catch(v=>(console.error(`Error loading LOD ${e} from ${c}
3
- `,v),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+c,y.guid);let _=0;if(x.parser.json.textures){let v=!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){v=!0;break}}_++}if(v){let h=await S.getDependency("texture",_);return s&&console.log('change "'+r.name+'" \u2192 "'+h.name+'"',c,_,h,g),r instanceof C&&(h=this.copySettings(r,h)),h&&(h.guid=y.guid),m(h)}}if(_=0,x.parser.json.meshes){let v=!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){v=!0;break}}_++}if(v){const h=await S.getDependency("mesh",_),w=y;if(s&&console.log(`Loaded Mesh "${h.name}"`,c,_,h,g),h.isMesh===!0){const T=h.geometry;return L.assignLODInformation(a.url,T,i,e,void 0,w.density),m(T)}else{const T=new Array;for(let I=0;I<h.children.length;I++){const G=h.children[I];if(G instanceof F){const j=G.geometry;L.assignLODInformation(a.url,j,i,e,I,w.density),T.push(j)}}return m(T)}}}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)):D&&console.warn("failed loading",c),g}}else D&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,o,n,s){if(!e)return;e.userData||(e.userData={});const a=new xe(r,t,o,n,s);e.userData.LODS=a,e.userData.LOD=o}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,o)=>{D&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,o),e.source&&(e.source[X]=o);const n=o.guid;L.assignLODInformation(r,e,n,0,0,void 0),L.lodInfos.set(n,o),L.lowresCache.set(n,e)}),u(O,"registerMesh",(r,e,t,o,n,s)=>{var a;D&&console.log("> Progressive: register mesh",n,t.name,s,t.uuid,t);const i=t.geometry;i.userData||(i.userData={}),L.assignLODInformation(r,i,e,o,n,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,o,n,s){u(this,"url"),u(this,"key"),u(this,"level"),u(this,"index"),u(this,"density"),this.url=e,this.key=t,this.level=o,n!=null&&(this.index=n),s!=null&&(this.density=s)}}const ee=q("debugprogressive"),ve=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(o,n){const s=t++,a=r++;e.onBeforeRender(o,n,a,s),e._originalRender.call(this,o,n),e.onAfterRender(o,n,a,s),r--}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(r,e,t,o){}onAfterRender(r,e,t,o){if(ve||this.pause||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const n=1e5,s=this.renderer.renderLists.get(r,t).opaque;for(const a of s){const i=a.object;(i instanceof F||i.isMesh)&&this.updateLODs(r,e,i,n)}}updateLODs(r,e,t,o){var n,s;for(const d of this.plugins)(n=d.onBeforeUpdateLOD)==null||n.call(d,this.renderer,r,e,t);let a=t.userData.LOD_state;a||(a=new De,t.userData.LOD_state=a);let i=this.calculateLodLevel(e,t,a,o);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(o=>(o&&r.userData.LOD==e&&t!=r.geometry,o))}return Promise.resolve(null)}calculateLodLevel(r,e,t,o){var n;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||!((n=this.cameraFrustrum)!=null&&n.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,_=p.y;const v=2,h=1.5,w=(f.x+p.x)*.5,T=(f.y+p.y)*.5;b=(b-w)*v+w,x=(x-T)*v+T,S=(S-w)*v+w,_=(_-T)*v+T;const I=b<0&&S>0?0:Math.min(Math.abs(f.x),Math.abs(p.x)),G=x<0&&_>0?0:Math.min(Math.abs(f.y),Math.abs(p.y)),j=Math.max(I,G);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 _=(p.z+S.z)*.5;p.z=b.z=x.z=S.z=_,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<o){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 De{constructor(){u(this,"lastLodLevel",0),u(this,"lastScreenCoverage",0),u(this,"lastScreenspaceVolume",new E),u(this,"lastCentrality",0)}}const re=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function te(r){if(!r)return null;let e=null,t=null;for(let o=r;o!=null;o=Object.getPrototypeOf(o)){const n=Object.getOwnPropertySymbols(o),s=n.find(i=>i.toString()=="Symbol(renderer)"),a=n.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 o=new k(e);if(o.plugins.push(new Le(r)),o.enable(),t){const n=t.camera||t.traverse(s=>s.type=="PerspectiveCamera")[0];n&&e.render(t,n)}return()=>{o.disable()}}return null}class Le{constructor(e){u(this,"modelviewer"),u(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,t,o,n){this.tryParseMeshLOD(t,n),this.tryParseTextureLOD(t,n)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[z]==!0)return;t[z]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&t.material){let s=function(i){var l,d,c;if(i[z]==!0)return;i[z]=!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=o.parser.json.textures[m];if((c=f.extensions)!=null&&c[B]){const p=f.extensions[B];p&&n&&O.registerTexture(n,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 o,n;if(t[re]==!0)return;t[re]=!0;const s=this.getUrl();if(!s)return;const a=(n=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:n[B];if(a&&s){const i=t.uuid;O.registerMesh(s,i,t,0,a.lods.length,a)}}}function Oe(r,e,t,o){J(e),Q(t),t.register(s=>new O(s,r));const n=new k(e);return o?.enableLODsManager!==!1&&n.enable(),n}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};
1
+ var se=Object.defineProperty,oe=(r,e,t)=>e in r?se(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,c=(r,e,t)=>(oe(r,typeof e!="symbol"?e+"":e,t),t);import{Mesh as U,BufferGeometry as F,Material as ne,RawShaderMaterial as ie,Texture as k,TextureLoader as ae,Matrix4 as Y,Frustum as le,Sphere as ue,Box3 as J,Vector3 as B}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/",me="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";let R,$,G;function Q(r){R||(R=new he,R.setDecoderPath(ge),R.setDecoderConfig({type:"js"})),G||(G=new fe,G.setTranscoderPath(me)),$||($=de),r?G.detectSupport(r):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function Z(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 pe(r,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||r===void 0)return e;const t=r.lastIndexOf("/");if(t>=0){const o=r.substring(0,t+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}const V=new Array;function ye(r){V.push(r)}const P="NEEDLE_progressive",L=q("debugprogressive"),X=Symbol("needle-progressive-texture"),N=new Map,H=new Set;if(L){let r=function(){e+=1,console.log("Toggle LOD level",e,N),N.forEach((n,s)=>{for(const i of n.keys){const a=s[i];if(a.isBufferGeometry===!0){const u=O.getMeshLODInformation(a),h=u?Math.min(e,u.lods.length):0;s["DEBUG:LOD"]=e,O.assignMeshLOD(s,h),u&&(t=Math.max(t,u.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,o=!1;window.addEventListener("keyup",n=>{n.key==="p"&&r(),n.key==="w"&&(o=!o,H&&H.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=o)}))})}function ee(r,e,t){var o;if(!L)return;N.has(r)||N.set(r,{keys:[],sourceId:t});const n=N.get(r);((o=n?.keys)==null?void 0:o.includes(e))==!1&&n.keys.push(e)}const D=class{constructor(r,e){c(this,"parser"),c(this,"url"),L&&console.log("Progressive extension registered for",e),this.parser=r,this.url=e}get name(){return P}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 i=r[s];if(i.isTexture&&this.hasLODLevelAvailable(i,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 o,n;if(r.isMesh?o=r.geometry:(r.isBufferGeometry||r.isTexture)&&(o=r),o&&(t=o?.userData)!=null&&t.LODS){const s=o.userData.LODS;if(n=this.lodInfos.get(s.key),e===void 0)return n!=null;if(n)return Array.isArray(n.lods)?e<n.lods.length:e===0}return!1}static assignMeshLOD(r,e){var t;if(!r)return Promise.resolve(null);if(r instanceof U||r.isMesh===!0){const o=r.geometry,n=this.getAssignedLODInformation(o);if(!n)return Promise.resolve(null);for(const s of V)(t=s.onBeforeGetLODMesh)==null||t.call(s,r,e);return r["LOD:requested level"]=e,D.getOrLoadLOD(o,e).then(s=>{if(r["LOD:requested level"]===e){if(delete r["LOD:requested level"],Array.isArray(s)){const i=n.index||0;s=s[i]}s&&o!=s&&s instanceof F&&(r.geometry=s,L&&ee(r,"geometry",n.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",r,s),null))}else L&&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 ne||r.isMaterial===!0){const t=r,o=[],n=new Array;if(L&&H.add(t),t instanceof ie)for(const s of Object.keys(t.uniforms)){const i=t.uniforms[s].value;if(i?.isTexture===!0){const a=this.assignTextureLODForSlot(i,e,t,s);o.push(a),n.push(s)}}else for(const s of Object.keys(t)){const i=t[s];if(i?.isTexture===!0){const a=this.assignTextureLODForSlot(i,e,t,s);o.push(a),n.push(s)}}return Promise.all(o).then(s=>{const i=new Array;for(let a=0;a<s.length;a++){const u=s[a],h=n[a];u&&u.isTexture===!0?i.push({material:t,slot:h,texture:u,level:e}):i.push({material:t,slot:h,texture:null,level:e})}return i})}if(r instanceof k||r.isTexture===!0){const t=r;return this.assignTextureLODForSlot(t,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(r,e,t,o){return r?.isTexture!==!0?Promise.resolve(null):D.getOrLoadLOD(r,e).then(n=>{if(Array.isArray(n))return null;if(n?.isTexture===!0){if(n!=r&&(t&&o&&(t[o]=n),L&&o&&t)){const s=this.getAssignedLODInformation(r);s&&ee(t,o,s.url)}return n}else L=="verbose"&&console.warn("No LOD found for",r,e);return null}).catch(n=>(console.error("Error loading LOD",r,n),null))}afterRoot(r){var e,t;return L&&console.log("AFTER",this.url,r),(e=this.parser.json.textures)==null||e.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[P];if(s){let i=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===n&&(i=!0,D.registerTexture(this.url,a,n,s));i||this.parser.getDependency("texture",n).then(a=>{a&&D.registerTexture(this.url,a,n,s)})}}}),(t=this.parser.json.meshes)==null||t.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[P];if(s&&s.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const a=this.parser.associations.get(i);a.meshes===n&&D.registerMesh(this.url,s.guid,i,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(r,e){var t,o,n;const s=L=="verbose",i=r.userData.LODS;if(!i)return null;const a=i?.key;let u;if(r.isTexture===!0){const h=r;h.source&&h.source[X]&&(u=h.source[X])}if(u||(u=D.lodInfos.get(a)),u){if(e>0){let d=!1;const M=Array.isArray(u.lods);if(M&&e>=u.lods.length?d=!0:M||(d=!0),d)return this.lowresCache.get(a)}const h=Array.isArray(u.lods)?u.lods[e].path:u.lods;if(!h)return L&&!u["missing:uri"]&&(u["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,u)),null;const l=pe(i.url,h);if(l.endsWith(".glb")||l.endsWith(".gltf")){if(!u.guid)return console.warn("missing pointer for glb/gltf texture",u),null;const d=l+"_"+u.guid,M=this.previouslyLoaded.get(d);if(M!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${d}`);let p=await M.catch(m=>(console.error(`Error loading LOD ${e} from ${l}
2
+ `,m),null)),g=!1;if(p==null||(p instanceof k&&r instanceof k?(t=p.image)!=null&&t.data||(o=p.source)!=null&&o.data?p=this.copySettings(r,p):(g=!0,this.previouslyLoaded.delete(d)):p instanceof F&&r instanceof F&&((n=p.attributes.position)!=null&&n.array||(g=!0,this.previouslyLoaded.delete(d)))),!g)return p}const y=u,A=new Promise(async(p,g)=>{const m=new ce;Z(m),L&&(await new Promise(v=>setTimeout(v,1e3)),s&&console.warn("Start loading (delayed) "+l,y.guid));let b=l;if(y&&Array.isArray(y.lods)){const v=y.lods[e];v.hash&&(b+="?v="+v.hash)}const x=await m.loadAsync(b).catch(v=>(console.error(`Error loading LOD ${e} from ${l}
3
+ `,v),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+l,y.guid);let _=0;if(x.parser.json.textures){let v=!1;for(const f of x.parser.json.textures){if(f!=null&&f.extensions){const w=f?.extensions[P];if(w!=null&&w.guid&&w.guid===y.guid){v=!0;break}}_++}if(v){let f=await S.getDependency("texture",_);return s&&console.log('change "'+r.name+'" \u2192 "'+f.name+'"',l,_,f,d),r instanceof k&&(f=this.copySettings(r,f)),f&&(f.guid=y.guid),p(f)}}if(_=0,x.parser.json.meshes){let v=!1;for(const f of x.parser.json.meshes){if(f!=null&&f.extensions){const w=f?.extensions[P];if(w!=null&&w.guid&&w.guid===y.guid){v=!0;break}}_++}if(v){const f=await S.getDependency("mesh",_),w=y;if(s&&console.log(`Loaded Mesh "${f.name}"`,l,_,f,d),f.isMesh===!0){const E=f.geometry;return D.assignLODInformation(i.url,E,a,e,void 0,w.density),p(E)}else{const E=new Array;for(let C=0;C<f.children.length;C++){const W=f.children[C];if(W instanceof U){const j=W.geometry;D.assignLODInformation(i.url,j,a,e,C,w.density),E.push(j)}}return p(E)}}}return p(null)});return this.previouslyLoaded.set(d,A),await A}else if(r instanceof k){s&&console.log("Load texture from uri: "+l);const d=await new ae().loadAsync(l);return d?(d.guid=u.guid,d.flipY=!1,d.needsUpdate=!0,d.colorSpace=r.colorSpace,s&&console.log(u,d)):L&&console.warn("failed loading",l),d}}else L&&console.warn(`Can not load LOD ${e}: no LOD info found for "${a}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,o,n,s){if(!e)return;e.userData||(e.userData={});const i=new xe(r,t,o,n,s);e.userData.LODS=i,e.userData.LOD=o}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=D;c(O,"registerTexture",(r,e,t,o)=>{L&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,o),e.source&&(e.source[X]=o);const n=o.guid;D.assignLODInformation(r,e,n,0,0,void 0),D.lodInfos.set(n,o),D.lowresCache.set(n,e)}),c(O,"registerMesh",(r,e,t,o,n,s)=>{var i;L&&console.log("> Progressive: register mesh",n,t.name,s,t.uuid,t);const a=t.geometry;a.userData||(a.userData={}),D.assignLODInformation(r,a,e,o,n,s.density),D.lodInfos.set(e,s);let u=D.lowresCache.get(e);u?u.push(t.geometry):u=[t.geometry],D.lowresCache.set(e,u);for(const h of V)(i=h.onRegisteredNewMesh)==null||i.call(h,t,s)}),c(O,"lodInfos",new Map),c(O,"previouslyLoaded",new Map),c(O,"lowresCache",new Map),c(O,"_copiedTextures",new Map);class xe{constructor(e,t,o,n,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=t,this.level=o,n!=null&&(this.index=n),s!=null&&(this.density=s)}}const K=q("debugprogressive"),ve=q("noprogressive"),T=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new Y),c(this,"cameraFrustrum",new le),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"plugins",[]),c(this,"_originalRender"),c(this,"_sphere",new ue),c(this,"_tempBox",new J),c(this,"tempMatrix",new Y),c(this,"_tempWorldPosition",new B),c(this,"_tempBoxSize",new B),c(this,"_tempBox2Size",new B),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;Q(this.renderer),this.renderer.render=function(o,n){const s=t++,i=r++;e.onBeforeRender(o,n,i,s),e._originalRender.call(this,o,n),e.onAfterRender(o,n,i,s),r--}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(r,e,t,o){}onAfterRender(r,e,t,o){var n,s;if(ve||this.pause||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const i=1e5,a=this.renderer.renderLists.get(r,t),u=a.opaque;for(const l of u){if(l.material&&(((n=l.geometry)==null?void 0:n.type)==="BoxGeometry"||((s=l.geometry)==null?void 0:s.type)==="BufferGeometry")&&(l.material.name==="SphericalGaussianBlur"||l.material.name=="BackgroundCubeMaterial"||l.material.name==="CubemapFromEquirect"||l.material.name==="EquirectangularToCubeUV")){K&&(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",l,l.material.name,l.material.type)));continue}const d=l.object;(d instanceof U||d.isMesh)&&this.updateLODs(r,e,d,i)}const h=a.transparent;for(const l of h){const d=l.object;(d instanceof U||d.isMesh)&&this.updateLODs(r,e,d,i)}}updateLODs(r,e,t,o){var n,s;for(const h of this.plugins)(n=h.onBeforeUpdateLOD)==null||n.call(h,this.renderer,r,e,t);let i=t.userData.LOD_state;i||(i=new Le,t.userData.LOD_state=i);let a=this.calculateLodLevel(e,t,i,o);a=Math.round(a),a>=0&&this.loadProgressiveMeshes(t,a);let u=0;if(t.material){const h=t["DEBUG:LOD"];if(h!=null&&(u=h),Array.isArray(t.material))for(const l of t.material)this.loadProgressiveTextures(l,u);else this.loadProgressiveTextures(t.material,u)}for(const h of this.plugins)(s=h.onAfterUpdatedLOD)==null||s.call(h,this.renderer,r,e,t,a);i.lastLodLevel=a}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(o=>(o&&r.userData.LOD==e&&t!=r.geometry,o))}return Promise.resolve(null)}calculateLodLevel(r,e,t,o){var n;if(!e)return-1;let s=10+1;if(r){if(K&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const i=O.getMeshLODInformation(e.geometry),a=i?.lods;if(!a||a.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e)))return 99;const u=e.geometry.boundingBox;if(u&&r.isPerspectiveCamera){const h=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 g=r.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g))return 0}if(this._tempBox.copy(u),this._tempBox.applyMatrix4(e.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&h.fov>70){const g=this._tempBox.min,m=this._tempBox.max;let b=g.x,x=g.y,S=m.x,_=m.y;const v=2,f=1.5,w=(g.x+m.x)*.5,E=(g.y+m.y)*.5;b=(b-w)*v+w,x=(x-E)*v+E,S=(S-w)*v+w,_=(_-E)*v+E;const C=b<0&&S>0?0:Math.min(Math.abs(g.x),Math.abs(m.x)),W=x<0&&_>0?0:Math.min(Math.abs(g.y),Math.abs(m.y)),j=Math.max(C,W);t.lastCentrality=(f-j)*(f-j)*(f-j)}else t.lastCentrality=1;const l=this._tempBox.getSize(this._tempBoxSize);l.multiplyScalar(.5),screen.availHeight>0&&l.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),l.x*=h.aspect;const d=r.matrixWorldInverse,M=new J;M.copy(u),M.applyMatrix4(e.matrixWorld),M.applyMatrix4(d);const y=M.getSize(this._tempBox2Size),A=Math.max(y.x,y.y);if(Math.max(l.x,l.y)!=0&&A!=0&&(l.z=y.z/Math.max(y.x,y.y)*Math.max(l.x,l.y)),t.lastScreenCoverage=Math.max(l.x,l.y,l.z),t.lastScreenspaceVolume.copy(l),t.lastScreenCoverage*=t.lastCentrality,K&&T.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const m=T.corner0,b=T.corner1,x=T.corner2,S=T.corner3;m.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=m.x,x.copy(this._tempBox.max),x.y=m.y,S.copy(this._tempBox.max);const _=(m.z+S.z)*.5;m.z=b.z=x.z=S.z=_,m.applyMatrix4(g),b.applyMatrix4(g),x.applyMatrix4(g),S.applyMatrix4(g),T.debugDrawLine(m,b,255),T.debugDrawLine(m,x,255),T.debugDrawLine(b,S,255),T.debugDrawLine(x,S,255)}let p=999;if(a&&t.lastScreenCoverage>0){for(let g=0;g<a.length;g++)if(a[g].density/t.lastScreenCoverage<o){p=g;break}}p<s&&(s=p)}}return s}};let I=T;c(I,"debugDrawLine"),c(I,"corner0",new B),c(I,"corner1",new B),c(I,"corner2",new B),c(I,"corner3",new B);class Le{constructor(){c(this,"lastLodLevel",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const re=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function te(r){if(!r)return null;let e=null,t=null;for(let o=r;o!=null;o=Object.getPrototypeOf(o)){const n=Object.getOwnPropertySymbols(o),s=n.find(a=>a.toString()=="Symbol(renderer)"),i=n.find(a=>a.toString()=="Symbol(scene)");!e&&s!=null&&(e=r[s].threeRenderer),!t&&i!=null&&(t=r[i])}if(e){console.log("Adding Needle LODs to modelviewer");const o=new I(e);if(o.plugins.push(new De(r)),o.enable(),t){const n=t.camera||t.traverse(s=>s.type=="PerspectiveCamera")[0];n&&e.render(t,n)}return()=>{o.disable()}}return null}class De{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,t,o,n){this.tryParseMeshLOD(t,n),this.tryParseTextureLOD(t,n)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[z]==!0)return;t[z]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&t.material){let s=function(a){var u,h,l;if(a[z]==!0)return;a[z]=!0,a.userData&&(a.userData.LOD=-1);const d=Object.keys(a);for(let M=0;M<d.length;M++){const y=d[M],A=a[y];if(A?.isTexture===!0){const p=(h=(u=A.userData)==null?void 0:u.associations)==null?void 0:h.textures,g=o.parser.json.textures[p];if((l=g.extensions)!=null&&l[P]){const m=g.extensions[P];m&&n&&O.registerTexture(n,A,m.lods.length,m)}}}};const i=t.material;if(Array.isArray(i))for(const a of i)s(a);else s(i)}}tryParseMeshLOD(e,t){var o,n;if(t[re]==!0)return;t[re]=!0;const s=this.getUrl();if(!s)return;const i=(n=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:n[P];if(i&&s){const a=t.uuid;O.registerMesh(s,a,t,0,i.lods.length,i)}}}function Oe(r,e,t,o){Q(e),Z(t),t.register(s=>new O(s,r));const n=new I(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{te(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,O as NEEDLE_progressive,te as patchModelViewer,ye as registerPlugin,Oe as useNeedleProgressive};
@@ -1,3 +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 U,$,z;function Z(l){U||(U=new ne.DRACOLoader,U.setDecoderPath(le),U.setDecoderConfig({type:"js"})),z||(z=new ae.KTX2Loader,z.setTranscoderPath(ue)),$||($=oe.MeshoptDecoder),l?z.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function j(l){l.dracoLoader||l.setDRACOLoader(U),l.ktx2Loader||l.setKTX2Loader(z),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=O.getMeshLODInformation(n),g=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,O.assignMeshLOD(o,g),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,O.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,P=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 A=p.parser;r&&console.log("Loading finished "+D,x.guid);let w=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}}w++}if(y){let c=await A.getDependency("texture",w);return r&&console.log('change "'+e.name+'" → "'+c.name+'"',D,w,c,d),e instanceof h.Texture&&(c=this.copySettings(e,c)),c&&(c.guid=x.guid),m(c)}}if(w=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}}w++}if(y){const c=await A.getDependency("mesh",w),v=x;if(r&&console.log(`Loaded Mesh "${c.name}"`,D,w,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 W=E.geometry;S.assignLODInformation(i.url,W,o,t,C,v.density),B.push(W)}}return m(B)}}}return m(null)});return this.previouslyLoaded.set(d,P),await P}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 O=S;u(O,"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(O,"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(O,"lodInfos",new Map),u(O,"previouslyLoaded",new Map),u(O,"lowresCache",new Map),u(O,"_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"),b=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,O.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 O.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=O.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 A=L.x,w=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;A=(A-C)*v+C,w=(w-E)*v+E,y=(y-C)*v+C,c=(c-E)*v+E;const W=A<0&&y>0?0:Math.min(Math.abs(L.x),Math.abs(p.x)),te=w<0&&c>0?0:Math.min(Math.abs(L.y),Math.abs(p.y)),N=Math.max(W,te);r.lastCentrality=(B-N)*(B-N)*(B-N)}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 P=x.getSize(this._tempBox2Size),G=Math.max(P.x,P.y);if(Math.max(d.x,d.y)!=0&&G!=0&&(d.z=P.z/Math.max(P.x,P.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&&b.debugDrawLine){const L=this.tempMatrix.copy(this.projectionScreenMatrix);L.invert();const p=b.corner0,A=b.corner1,w=b.corner2,y=b.corner3;p.copy(this._tempBox.min),A.copy(this._tempBox.max),A.x=p.x,w.copy(this._tempBox.max),w.y=p.y,y.copy(this._tempBox.max);const c=(p.z+y.z)*.5;p.z=A.z=w.z=y.z=c,p.applyMatrix4(L),A.applyMatrix4(L),w.applyMatrix4(L),y.applyMatrix4(L),b.debugDrawLine(p,A,255),b.debugDrawLine(p,w,255),b.debugDrawLine(A,y,255),b.debugDrawLine(w,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 _=b;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"),q=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");u(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[q]==!0)return;t[q]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let o=function(n){var g,f,D;if(n[q]==!0)return;n[q]=!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 P=(f=(g=x.userData)==null?void 0:g.associations)==null?void 0:f.textures,G=r.parser.json.textures[P];if((D=G.extensions)!=null&&D[k]){const m=G.extensions[k];m&&i&&O.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)return;const i=(s=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:s[k];if(i&&r){const n=t.uuid;O.registerMesh(r,n,t,0,i.lods.length,i)}}}function ye(l,e,t,r){Z(e),j(t),t.register(o=>new O(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=O;exports.patchModelViewer=ee;exports.registerPlugin=fe;exports.useNeedleProgressive=ye;
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 F,X,U;function Z(l){F||(F=new ne.DRACOLoader,F.setDecoderPath(le),F.setDecoderConfig({type:"js"})),U||(U=new ae.KTX2Loader,U.setTranscoderPath(ue)),X||(X=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(F),l.ktx2Loader||l.setKTX2Loader(U),l.meshoptDecoder||l.setMeshoptDecoder(X)}function H(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 K=new Array;function fe(l){K.push(l)}const C="NEEDLE_progressive",T=H("debugprogressive"),q=Symbol("needle-progressive-texture"),N=new Map,Y=new Set;if(T){let l=function(){e+=1,console.log("Toggle LOD level",e,N),N.forEach((i,o)=>{for(const s of i.keys){const n=o[s];if(n.isBufferGeometry===!0){const a=w.getMeshLODInformation(n),p=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,w.assignMeshLOD(o,p),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,Y&&Y.forEach(o=>{o.name!="BackgroundCubeMaterial"&&"wireframe"in o&&(o.wireframe=r)}))})}function J(l,e,t){var i;if(!T)return;N.has(l)||N.set(l,{keys:[],sourceId:t});const r=N.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 C}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 K)(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&&J(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&&Y.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 p=s[a],d=o[a];p&&p.isTexture===!0?n.push({material:r,slot:d,texture:p,level:t}):n.push({material:r,slot:d,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&&J(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[C];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[C];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,p;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 d=e;d.source&&d.source[q]&&(s=d.source[q])}if(s||(s=S.lodInfos.get(o)),s){if(t>0){let f=!1;const M=Array.isArray(s.lods);if(M&&t>=s.lods.length?f=!0:M||(f=!0),f)return this.lowresCache.get(o)}const d=Array.isArray(s.lods)?s.lods[t].path:s.lods;if(!d)return T&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const c=ce(i.url,d);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const f=c+"_"+s.guid,M=this.previouslyLoaded.get(f);if(M!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${f}`);let x=await M.catch(I=>(console.error(`Error loading LOD ${t} from ${c}
2
+ `,I),null)),R=!1;if(x==null||(x instanceof h.Texture&&e instanceof h.Texture?(n=x.image)!=null&&n.data||(a=x.source)!=null&&a.data?x=this.copySettings(e,x):(R=!0,this.previouslyLoaded.delete(f)):x instanceof h.BufferGeometry&&e instanceof h.BufferGeometry&&((p=x.attributes.position)!=null&&p.array||(R=!0,this.previouslyLoaded.delete(f)))),!R)return x}const D=s,P=new Promise(async(x,R)=>{const I=new ie.GLTFLoader;j(I),T&&(await new Promise(L=>setTimeout(L,1e3)),r&&console.warn("Start loading (delayed) "+c,D.guid));let m=c;if(D&&Array.isArray(D.lods)){const L=D.lods[t];L.hash&&(m+="?v="+L.hash)}const y=await I.loadAsync(m).catch(L=>(console.error(`Error loading LOD ${t} from ${c}
3
+ `,L),null));if(!y)return null;const b=y.parser;r&&console.log("Loading finished "+c,D.guid);let O=0;if(y.parser.json.textures){let L=!1;for(const g of y.parser.json.textures){if(g!=null&&g.extensions){const v=g==null?void 0:g.extensions[C];if(v!=null&&v.guid&&v.guid===D.guid){L=!0;break}}O++}if(L){let g=await b.getDependency("texture",O);return r&&console.log('change "'+e.name+'" → "'+g.name+'"',c,O,g,f),e instanceof h.Texture&&(g=this.copySettings(e,g)),g&&(g.guid=D.guid),x(g)}}if(O=0,y.parser.json.meshes){let L=!1;for(const g of y.parser.json.meshes){if(g!=null&&g.extensions){const v=g==null?void 0:g.extensions[C];if(v!=null&&v.guid&&v.guid===D.guid){L=!0;break}}O++}if(L){const g=await b.getDependency("mesh",O),v=D;if(r&&console.log(`Loaded Mesh "${g.name}"`,c,O,g,f),g.isMesh===!0){const B=g.geometry;return S.assignLODInformation(i.url,B,o,t,void 0,v.density),x(B)}else{const B=new Array;for(let E=0;E<g.children.length;E++){const k=g.children[E];if(k instanceof h.Mesh){const W=k.geometry;S.assignLODInformation(i.url,W,o,t,E,v.density),B.push(W)}}return x(B)}}}return x(null)});return this.previouslyLoaded.set(f,P),await P}else if(e instanceof h.Texture){r&&console.log("Load texture from uri: "+c);const M=await new h.TextureLoader().loadAsync(c);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",c),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[q]=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 p;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 d of K)(p=d.onRegisteredNewMesh)==null||p.call(d,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 $=H("debugprogressive"),ge=H("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){var p,d;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,s=this.renderer.renderLists.get(e,r),n=s.opaque;for(const c of n){if(c.material&&(((p=c.geometry)==null?void 0:p.type)==="BoxGeometry"||((d=c.geometry)==null?void 0:d.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){$&&(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}const f=c.object;(f instanceof h.Mesh||f.isMesh)&&this.updateLODs(e,t,f,o)}const a=s.transparent;for(const c of a){const f=c.object;(f instanceof h.Mesh||f.isMesh)&&this.updateLODs(e,t,f,o)}}updateLODs(e,t,r,i){var a,p;for(const d of this.plugins)(a=d.onBeforeUpdateLOD)==null||a.call(d,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 d=r["DEBUG:LOD"];if(d!=null&&(n=d),Array.isArray(r.material))for(const c of r.material)this.loadProgressiveTextures(c,n);else this.loadProgressiveTextures(r.material,n)}for(const d of this.plugins)(p=d.onAfterUpdatedLOD)==null||p.call(d,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($&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=w.getMeshLODInformation(t.geometry),p=a==null?void 0:a.lods;if(!p||p.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(t)))return 99;const d=t.geometry.boundingBox;if(d&&e.isPerspectiveCamera){const c=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 m=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(m))return 0}if(this._tempBox.copy(d),this._tempBox.applyMatrix4(t.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&c.fov>70){const m=this._tempBox.min,y=this._tempBox.max;let b=m.x,O=m.y,L=y.x,g=y.y;const v=2,B=1.5,E=(m.x+y.x)*.5,k=(m.y+y.y)*.5;b=(b-E)*v+E,O=(O-k)*v+k,L=(L-E)*v+E,g=(g-k)*v+k;const W=b<0&&L>0?0:Math.min(Math.abs(m.x),Math.abs(y.x)),te=O<0&&g>0?0:Math.min(Math.abs(m.y),Math.abs(y.y)),V=Math.max(W,te);r.lastCentrality=(B-V)*(B-V)*(B-V)}else r.lastCentrality=1;const f=this._tempBox.getSize(this._tempBoxSize);f.multiplyScalar(.5),screen.availHeight>0&&f.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),f.x*=c.aspect;const M=e.matrixWorldInverse,D=new h.Box3;D.copy(d),D.applyMatrix4(t.matrixWorld),D.applyMatrix4(M);const P=D.getSize(this._tempBox2Size),G=Math.max(P.x,P.y);if(Math.max(f.x,f.y)!=0&&G!=0&&(f.z=P.z/Math.max(P.x,P.y)*Math.max(f.x,f.y)),r.lastScreenCoverage=Math.max(f.x,f.y,f.z),r.lastScreenspaceVolume.copy(f),r.lastScreenCoverage*=r.lastCentrality,$&&A.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const y=A.corner0,b=A.corner1,O=A.corner2,L=A.corner3;y.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=y.x,O.copy(this._tempBox.max),O.y=y.y,L.copy(this._tempBox.max);const g=(y.z+L.z)*.5;y.z=b.z=O.z=L.z=g,y.applyMatrix4(m),b.applyMatrix4(m),O.applyMatrix4(m),L.applyMatrix4(m),A.debugDrawLine(y,b,255),A.debugDrawLine(y,O,255),A.debugDrawLine(b,L,255),A.debugDrawLine(O,L,255)}let R=999;if(p&&r.lastScreenCoverage>0){for(let m=0;m<p.length;m++)if(p[m].density/r.lastScreenCoverage<i){R=m;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"),z=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");u(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[z]==!0)return;t[z]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let o=function(n){var p,d,c;if(n[z]==!0)return;n[z]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let f=0;f<a.length;f++){const M=a[f],D=n[M];if((D==null?void 0:D.isTexture)===!0){const P=(d=(p=D.userData)==null?void 0:p.associations)==null?void 0:d.textures,G=r.parser.json.textures[P];if((c=G.extensions)!=null&&c[C]){const x=G.extensions[C];x&&i&&w.registerTexture(i,D,x.lods.length,x)}}}};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)return;const i=(s=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:s[C];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=C;exports.LODsManager=_;exports.NEEDLE_progressive=w;exports.patchModelViewer=ee;exports.registerPlugin=fe;exports.useNeedleProgressive=ye;
@@ -86,6 +86,25 @@ export class LODsManager {
86
86
  const renderList = this.renderer.renderLists.get(scene, stack);
87
87
  const opaque = renderList.opaque;
88
88
  for (const entry of opaque) {
89
+ if (entry.material && (entry.geometry?.type === "BoxGeometry" || entry.geometry?.type === "BufferGeometry")) {
90
+ // Ignore the skybox
91
+ if (entry.material.name === "SphericalGaussianBlur" || entry.material.name == "BackgroundCubeMaterial" || entry.material.name === "CubemapFromEquirect" || entry.material.name === "EquirectangularToCubeUV") {
92
+ if (debugProgressiveLoading) {
93
+ if (!entry.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]) {
94
+ entry.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] = true;
95
+ console.warn("Ignoring skybox or BLIT object", entry, entry.material.name, entry.material.type);
96
+ }
97
+ }
98
+ continue;
99
+ }
100
+ }
101
+ const object = entry.object;
102
+ if (object instanceof Mesh || (object.isMesh)) {
103
+ this.updateLODs(scene, camera, object, desiredDensity);
104
+ }
105
+ }
106
+ const transparent = renderList.transparent;
107
+ for (const entry of transparent) {
89
108
  const object = entry.object;
90
109
  if (object instanceof Mesh || (object.isMesh)) {
91
110
  this.updateLODs(scene, camera, object, desiredDensity);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-progressive",
3
- "version": "1.0.0-alpha.7",
3
+ "version": "1.0.0-alpha.8",
4
4
  "description": "three.js support for loading glTF or GLB files that contain progressive loading data",
5
5
  "homepage": "https://needle.tools",
6
6
  "author": {