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

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,12 @@ 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.9] - 2023-05-03
8
+ - fix: handle loading of ShaderMaterial for VRM progressive textures
9
+
10
+ ## [1.0.0-alpha.8] - 2023-05-03
11
+ - fix: handle transparent materials
12
+
7
13
  ## [1.0.0-alpha.7] - 2023-05-01
8
14
  - fix: Handle modelviewer `src` set as property but not as attribute
9
15
  - 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";
5
- import { GLTFLoader as ge } from "three/examples/jsm/loaders/GLTFLoader.js";
6
- import { MeshoptDecoder as he } from "three/examples/jsm/libs/meshopt_decoder.module.js";
7
- import { DRACOLoader as pe } from "three/examples/jsm/loaders/DRACOLoader.js";
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;
4
+ import { Mesh as q, BufferGeometry as X, Material as le, Texture as U, TextureLoader as ue, Matrix4 as j, Frustum as ce, Sphere as fe, Box3 as ee, Vector3 as k } from "three";
5
+ import { GLTFLoader as de } from "three/examples/jsm/loaders/GLTFLoader.js";
6
+ import { MeshoptDecoder as ge } from "three/examples/jsm/libs/meshopt_decoder.module.js";
7
+ import { DRACOLoader as he } from "three/examples/jsm/loaders/DRACOLoader.js";
8
+ import { KTX2Loader as pe } from "three/examples/jsm/loaders/KTX2Loader.js";
9
+ const ye = "https://www.gstatic.com/draco/versioned/decoders/1.4.1/", me = "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 he(), F.setDecoderPath(ye), F.setDecoderConfig({ type: "js" })), W || (W = new pe(), W.setTranscoderPath(me)), H || (H = ge), 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 Le(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 _e(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,15 +157,16 @@ 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)
161
- for (const s of Object.keys(r.uniforms)) {
162
- const o = r.uniforms[s].value;
163
- if ((o == null ? void 0 : o.isTexture) === !0) {
164
- const a = this.assignTextureLODForSlot(o, t, r, s);
165
- i.push(a), n.push(s);
160
+ if (S && Q.add(r), r.uniforms && r.isRawShaderMaterial || r.isShaderMaterial === !0) {
161
+ const s = r;
162
+ for (const o of Object.keys(s.uniforms)) {
163
+ const a = s.uniforms[o].value;
164
+ if ((a == null ? void 0 : a.isTexture) === !0) {
165
+ const h = this.assignTextureLODForSlot(a, t, r, o);
166
+ i.push(h), n.push(o);
166
167
  }
167
168
  }
168
- else
169
+ } else
169
170
  for (const s of Object.keys(r)) {
170
171
  const o = r[s];
171
172
  if ((o == null ? void 0 : o.isTexture) === !0) {
@@ -176,13 +177,13 @@ const M = class {
176
177
  return Promise.all(i).then((s) => {
177
178
  const o = new Array();
178
179
  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 });
180
+ const h = s[a], d = n[a];
181
+ 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
182
  }
182
183
  return o;
183
184
  });
184
185
  }
185
- if (e instanceof G || e.isTexture === !0) {
186
+ if (e instanceof U || e.isTexture === !0) {
186
187
  const r = e;
187
188
  return this.assignTextureLODForSlot(r, t, null, null);
188
189
  }
@@ -195,7 +196,7 @@ const M = class {
195
196
  if ((n == null ? void 0 : n.isTexture) === !0) {
196
197
  if (n != e && (r && i && (r[i] = n), S && i && r)) {
197
198
  const s = this.getAssignedLODInformation(e);
198
- s && ee(r, i, s.url);
199
+ s && te(r, i, s.url);
199
200
  }
200
201
  return n;
201
202
  } else
@@ -231,107 +232,107 @@ const M = class {
231
232
  }), null;
232
233
  }
233
234
  static async getOrLoadLOD(e, t) {
234
- var o, a, g;
235
+ var o, a, h;
235
236
  const r = S == "verbose", i = e.userData.LODS;
236
237
  if (!i)
237
238
  return null;
238
239
  const n = i == null ? void 0 : i.key;
239
240
  let s;
240
241
  if (e.isTexture === !0) {
241
- const f = e;
242
- f.source && f.source[N] && (s = f.source[N]);
242
+ const d = e;
243
+ d.source && d.source[V] && (s = d.source[V]);
243
244
  }
244
245
  if (s || (s = M.lodInfos.get(n)), s) {
245
246
  if (t > 0) {
246
- let d = !1;
247
+ let f = !1;
247
248
  const w = Array.isArray(s.lods);
248
- if (w && t >= s.lods.length ? d = !0 : w || (d = !0), d)
249
+ if (w && t >= s.lods.length ? f = !0 : w || (f = !0), f)
249
250
  return this.lowresCache.get(n);
250
251
  }
251
- const f = Array.isArray(s.lods) ? s.lods[t].path : s.lods;
252
- if (!f)
252
+ const d = Array.isArray(s.lods) ? s.lods[t].path : s.lods;
253
+ if (!d)
253
254
  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")) {
255
+ const c = Le(i.url, d);
256
+ if (c.endsWith(".glb") || c.endsWith(".gltf")) {
256
257
  if (!s.guid)
257
258
  return console.warn("missing pointer for glb/gltf texture", s), null;
258
- const d = L + "_" + s.guid, w = this.previouslyLoaded.get(d);
259
+ const f = c + "_" + s.guid, w = this.previouslyLoaded.get(f);
259
260
  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;
261
+ r && console.log(`LOD ${t} was already loading/loaded: ${f}`);
262
+ let D = await w.catch((I) => (console.error(`Error loading LOD ${t} from ${c}
263
+ `, I), null)), C = !1;
264
+ 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)
265
+ return D;
265
266
  }
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);
267
+ const L = s, A = new Promise(async (D, C) => {
268
+ const I = new de();
269
+ ie(I), S && (await new Promise((y) => setTimeout(y, 1e3)), r && console.warn("Start loading (delayed) " + c, L.guid));
270
+ let m = c;
271
+ if (L && Array.isArray(L.lods)) {
272
+ const y = L.lods[t];
273
+ y.hash && (m += "?v=" + y.hash);
273
274
  }
274
- const h = await E.loadAsync(y).catch((p) => (console.error(`Error loading LOD ${t} from ${L}
275
- `, p), null));
276
- if (!h)
275
+ const p = await I.loadAsync(m).catch((y) => (console.error(`Error loading LOD ${t} from ${c}
276
+ `, y), null));
277
+ if (!p)
277
278
  return null;
278
- const T = h.parser;
279
- r && console.log("Loading finished " + L, D.guid);
279
+ const b = p.parser;
280
+ r && console.log("Loading finished " + c, L.guid);
280
281
  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;
282
+ if (p.parser.json.textures) {
283
+ let y = !1;
284
+ for (const g of p.parser.json.textures) {
285
+ if (g != null && g.extensions) {
286
+ const O = g == null ? void 0 : g.extensions[R];
287
+ if (O != null && O.guid && O.guid === L.guid) {
288
+ y = !0;
288
289
  break;
289
290
  }
290
291
  }
291
292
  x++;
292
293
  }
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);
294
+ if (y) {
295
+ let g = await b.getDependency("texture", x);
296
+ 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
297
  }
297
298
  }
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;
299
+ if (x = 0, p.parser.json.meshes) {
300
+ let y = !1;
301
+ for (const g of p.parser.json.meshes) {
302
+ if (g != null && g.extensions) {
303
+ const O = g == null ? void 0 : g.extensions[R];
304
+ if (O != null && O.guid && O.guid === L.guid) {
305
+ y = !0;
305
306
  break;
306
307
  }
307
308
  }
308
309
  x++;
309
310
  }
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);
311
+ if (y) {
312
+ const g = await b.getDependency("mesh", x), O = L;
313
+ if (r && console.log(`Loaded Mesh "${g.name}"`, c, x, g, f), g.isMesh === !0) {
314
+ const P = g.geometry;
315
+ return M.assignLODInformation(i.url, P, n, t, void 0, O.density), D(P);
315
316
  } else {
316
317
  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($);
318
+ for (let _ = 0; _ < g.children.length; _++) {
319
+ const E = g.children[_];
320
+ if (E instanceof q) {
321
+ const N = E.geometry;
322
+ M.assignLODInformation(i.url, N, n, t, _, O.density), P.push(N);
322
323
  }
323
324
  }
324
- return m(P);
325
+ return D(P);
325
326
  }
326
327
  }
327
328
  }
328
- return m(null);
329
+ return D(null);
329
330
  });
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;
331
+ return this.previouslyLoaded.set(f, A), await A;
332
+ } else if (e instanceof U) {
333
+ r && console.log("Load texture from uri: " + c);
334
+ const w = await new ue().loadAsync(c);
335
+ 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
336
  }
336
337
  } else
337
338
  S && console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`, e.type);
@@ -341,7 +342,7 @@ const M = class {
341
342
  if (!t)
342
343
  return;
343
344
  t.userData || (t.userData = {});
344
- const o = new xe(e, r, i, n, s);
345
+ const o = new De(e, r, i, n, s);
345
346
  t.userData.LODS = o, t.userData.LOD = i;
346
347
  }
347
348
  static getAssignedLODInformation(e) {
@@ -358,26 +359,26 @@ let v = M;
358
359
  * Register a texture with LOD information
359
360
  */
360
361
  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);
362
+ S && console.log("> Progressive: register texture", r, t.name, t.uuid, t, i), t.source && (t.source[V] = i);
362
363
  const n = i.guid;
363
364
  M.assignLODInformation(e, t, n, 0, 0, void 0), M.lodInfos.set(n, i), M.lowresCache.set(n, t);
364
365
  }), /**
365
366
  * Register a mesh with LOD information
366
367
  */
367
368
  u(v, "registerMesh", (e, t, r, i, n, s) => {
368
- var g;
369
+ var h;
369
370
  S && console.log("> Progressive: register mesh", n, r.name, s, r.uuid, r);
370
371
  const o = r.geometry;
371
372
  o.userData || (o.userData = {}), M.assignLODInformation(e, o, t, i, n, s.density), M.lodInfos.set(t, s);
372
373
  let a = M.lowresCache.get(t);
373
374
  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);
375
+ for (const d of J)
376
+ (h = d.onRegisteredNewMesh) == null || h.call(d, r, s);
376
377
  }), /** A map of key = asset uuid and value = LOD information */
377
378
  u(v, "lodInfos", /* @__PURE__ */ new Map()), /** cache of already loaded mesh lods */
378
379
  u(v, "previouslyLoaded", /* @__PURE__ */ new Map()), /** this contains the geometry/textures that were originally loaded */
379
380
  u(v, "lowresCache", /* @__PURE__ */ new Map()), u(v, "_copiedTextures", /* @__PURE__ */ new Map());
380
- class xe {
381
+ class De {
381
382
  constructor(e, t, r, i, n) {
382
383
  u(this, "url");
383
384
  /** the key to lookup the LOD information */
@@ -390,11 +391,11 @@ class xe {
390
391
  this.url = e, this.key = t, this.level = r, i != null && (this.index = i), n != null && (this.density = n);
391
392
  }
392
393
  }
393
- const te = Q("debugprogressive"), we = Q("noprogressive"), A = class {
394
+ const Y = Z("debugprogressive"), xe = Z("noprogressive"), T = class {
394
395
  constructor(e) {
395
396
  u(this, "renderer");
396
- u(this, "projectionScreenMatrix", new Z());
397
- u(this, "cameraFrustrum", new fe());
397
+ u(this, "projectionScreenMatrix", new j());
398
+ u(this, "cameraFrustrum", new ce());
398
399
  /**
399
400
  * The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 1, the LODs will be updated every second frame, etc.
400
401
  */
@@ -406,12 +407,12 @@ const te = Q("debugprogressive"), we = Q("noprogressive"), A = class {
406
407
  u(this, "plugins", []);
407
408
  u(this, "_originalRender");
408
409
  // private testIfLODLevelsAreAvailable() {
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, "_sphere", new fe());
411
+ u(this, "_tempBox", new ee());
412
+ u(this, "tempMatrix", new j());
413
+ u(this, "_tempWorldPosition", new k());
414
+ u(this, "_tempBoxSize", new k());
415
+ u(this, "_tempBox2Size", new k());
415
416
  this.renderer = e;
416
417
  }
417
418
  /** @internal */
@@ -440,35 +441,45 @@ const te = Q("debugprogressive"), we = Q("noprogressive"), A = class {
440
441
  onBeforeRender(e, t, r, i) {
441
442
  }
442
443
  onAfterRender(e, t, r, i) {
443
- if (we || this.pause || this.updateInterval > 0 && i % this.updateInterval != 0)
444
+ var h, d;
445
+ if (xe || this.pause || this.updateInterval > 0 && i % this.updateInterval != 0)
444
446
  return;
445
447
  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);
448
+ const n = 1e5, s = this.renderer.renderLists.get(e, r), o = s.opaque;
449
+ for (const c of o) {
450
+ 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")) {
451
+ 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)));
452
+ continue;
453
+ }
454
+ const f = c.object;
455
+ (f instanceof q || f.isMesh) && this.updateLODs(e, t, f, n);
456
+ }
457
+ const a = s.transparent;
458
+ for (const c of a) {
459
+ const f = c.object;
460
+ (f instanceof q || f.isMesh) && this.updateLODs(e, t, f, n);
450
461
  }
451
462
  }
452
463
  /** Update the LOD levels for the renderer. */
453
464
  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);
465
+ var a, h;
466
+ for (const d of this.plugins)
467
+ (a = d.onBeforeUpdateLOD) == null || a.call(d, this.renderer, e, t, r);
457
468
  let n = r.userData.LOD_state;
458
- n || (n = new Oe(), r.userData.LOD_state = n);
469
+ n || (n = new we(), r.userData.LOD_state = n);
459
470
  let s = this.calculateLodLevel(t, r, n, i);
460
471
  s = Math.round(s), s >= 0 && this.loadProgressiveMeshes(r, s);
461
472
  let o = 0;
462
473
  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);
474
+ const d = r["DEBUG:LOD"];
475
+ if (d != null && (o = d), Array.isArray(r.material))
476
+ for (const c of r.material)
477
+ this.loadProgressiveTextures(c, o);
467
478
  else
468
479
  this.loadProgressiveTextures(r.material, o);
469
480
  }
470
- for (const f of this.plugins)
471
- (g = f.onAfterUpdatedLOD) == null || g.call(f, this.renderer, e, t, r, s);
481
+ for (const d of this.plugins)
482
+ (h = d.onAfterUpdatedLOD) == null || h.call(d, this.renderer, e, t, r, s);
472
483
  n.lastLodLevel = s;
473
484
  }
474
485
  /** Load progressive textures for the given material
@@ -501,70 +512,70 @@ const te = Q("debugprogressive"), we = Q("noprogressive"), A = class {
501
512
  return -1;
502
513
  let s = 10 + 1;
503
514
  if (e) {
504
- if (te && t["DEBUG:LOD"] != null)
515
+ if (Y && t["DEBUG:LOD"] != null)
505
516
  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)))
517
+ const a = v.getMeshLODInformation(t.geometry), h = a == null ? void 0 : a.lods;
518
+ if (!h || h.length <= 0 || !((o = this.cameraFrustrum) != null && o.intersectsObject(t)))
508
519
  return 99;
509
- const f = t.geometry.boundingBox;
510
- if (f && e.isPerspectiveCamera) {
511
- const L = e;
520
+ const d = t.geometry.boundingBox;
521
+ if (d && e.isPerspectiveCamera) {
522
+ const c = e;
512
523
  if (t.geometry.attributes.color && t.geometry.attributes.color.count < 100 && t.geometry.boundingSphere) {
513
524
  this._sphere.copy(t.geometry.boundingSphere), this._sphere.applyMatrix4(t.matrixWorld);
514
- const y = e.getWorldPosition(this._tempWorldPosition);
515
- if (this._sphere.containsPoint(y))
525
+ const m = e.getWorldPosition(this._tempWorldPosition);
526
+ if (this._sphere.containsPoint(m))
516
527
  return 0;
517
528
  }
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);
529
+ if (this._tempBox.copy(d), this._tempBox.applyMatrix4(t.matrixWorld), this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && c.fov > 70) {
530
+ const m = this._tempBox.min, p = this._tempBox.max;
531
+ let b = m.x, x = m.y, y = p.x, g = p.y;
532
+ const O = 2, P = 1.5, _ = (m.x + p.x) * 0.5, E = (m.y + p.y) * 0.5;
533
+ b = (b - _) * O + _, x = (x - E) * O + E, y = (y - _) * O + _, g = (g - E) * O + E;
534
+ 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);
535
+ r.lastCentrality = (P - K) * (P - K) * (P - K);
525
536
  } else
526
537
  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);
538
+ const f = this._tempBox.getSize(this._tempBoxSize);
539
+ f.multiplyScalar(0.5), screen.availHeight > 0 && f.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), f.x *= c.aspect;
540
+ const w = e.matrixWorldInverse, L = new ee();
541
+ L.copy(d), L.applyMatrix4(t.matrixWorld), L.applyMatrix4(w);
542
+ const A = L.getSize(this._tempBox2Size), G = Math.max(A.x, A.y);
543
+ 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) {
544
+ const m = this.tempMatrix.copy(this.projectionScreenMatrix);
545
+ m.invert();
546
+ const p = T.corner0, b = T.corner1, x = T.corner2, y = T.corner3;
547
+ 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);
548
+ const g = (p.z + y.z) * 0.5;
549
+ 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
550
  }
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;
551
+ let C = 999;
552
+ if (h && r.lastScreenCoverage > 0) {
553
+ for (let m = 0; m < h.length; m++)
554
+ if (h[m].density / r.lastScreenCoverage < i) {
555
+ C = m;
545
556
  break;
546
557
  }
547
558
  }
548
- B < s && (s = B);
559
+ C < s && (s = C);
549
560
  }
550
561
  }
551
562
  return s;
552
563
  }
553
564
  };
554
- let k = A;
565
+ let B = T;
555
566
  /** 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
567
  */
557
- u(k, "debugDrawLine"), u(k, "corner0", new C()), u(k, "corner1", new C()), u(k, "corner2", new C()), u(k, "corner3", new C());
558
- class Oe {
568
+ u(B, "debugDrawLine"), u(B, "corner0", new k()), u(B, "corner1", new k()), u(B, "corner2", new k()), u(B, "corner3", new k());
569
+ class we {
559
570
  constructor() {
560
571
  u(this, "lastLodLevel", 0);
561
572
  u(this, "lastScreenCoverage", 0);
562
- u(this, "lastScreenspaceVolume", new C());
573
+ u(this, "lastScreenspaceVolume", new k());
563
574
  u(this, "lastCentrality", 0);
564
575
  }
565
576
  }
566
- const re = Symbol("NEEDLE_mesh_lod"), K = Symbol("NEEDLE_texture_lod");
567
- function Me(l) {
577
+ const re = Symbol("NEEDLE_mesh_lod"), $ = Symbol("NEEDLE_texture_lod");
578
+ function Oe(l) {
568
579
  if (!l)
569
580
  return null;
570
581
  let e = null, t = null;
@@ -574,8 +585,8 @@ function Me(l) {
574
585
  }
575
586
  if (e) {
576
587
  console.log("Adding Needle LODs to modelviewer");
577
- const r = new k(e);
578
- if (r.plugins.push(new ve(l)), r.enable(), t) {
588
+ const r = new B(e);
589
+ if (r.plugins.push(new Me(l)), r.enable(), t) {
579
590
  const i = t.camera || t.traverse((n) => n.type == "PerspectiveCamera")[0];
580
591
  i && e.render(t, i);
581
592
  }
@@ -585,7 +596,7 @@ function Me(l) {
585
596
  }
586
597
  return null;
587
598
  }
588
- class ve {
599
+ class Me {
589
600
  constructor(e) {
590
601
  u(this, "modelviewer");
591
602
  u(this, "_didWarnAboutMissingUrl", !1);
@@ -602,24 +613,24 @@ class ve {
602
613
  return e._currentGLTF;
603
614
  }
604
615
  tryParseTextureLOD(e, t) {
605
- if (t[K] == !0)
616
+ if (t[$] == !0)
606
617
  return;
607
- t[K] = !0;
618
+ t[$] = !0;
608
619
  const r = this.tryGetCurrentGLTF(e), i = this.getUrl();
609
620
  if (i && r && t.material) {
610
621
  let n = function(o) {
611
- var g, f, L;
612
- if (o[K] == !0)
622
+ var h, d, c;
623
+ if (o[$] == !0)
613
624
  return;
614
- o[K] = !0, o.userData && (o.userData.LOD = -1);
625
+ o[$] = !0, o.userData && (o.userData.LOD = -1);
615
626
  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);
627
+ for (let f = 0; f < a.length; f++) {
628
+ const w = a[f], L = o[w];
629
+ if ((L == null ? void 0 : L.isTexture) === !0) {
630
+ const A = (d = (h = L.userData) == null ? void 0 : h.associations) == null ? void 0 : d.textures, G = r.parser.json.textures[A];
631
+ if ((c = G.extensions) != null && c[R]) {
632
+ const D = G.extensions[R];
633
+ D && i && v.registerTexture(i, L, D.lods.length, D);
623
634
  }
624
635
  }
625
636
  }
@@ -649,17 +660,17 @@ class ve {
649
660
  }
650
661
  function Be(l, e, t, r) {
651
662
  se(e), ie(t), t.register((n) => new v(n, l));
652
- const i = new k(e);
663
+ const i = new B(e);
653
664
  return (r == null ? void 0 : r.enableLODsManager) !== !1 && i.enable(), i;
654
665
  }
655
666
  document.addEventListener("DOMContentLoaded", () => {
656
- Me(document.querySelector("model-viewer"));
667
+ Oe(document.querySelector("model-viewer"));
657
668
  });
658
669
  export {
659
670
  R as EXTENSION_NAME,
660
- k as LODsManager,
671
+ B as LODsManager,
661
672
  v as NEEDLE_progressive,
662
- Me as patchModelViewer,
663
- ke as registerPlugin,
673
+ Oe as patchModelViewer,
674
+ _e as registerPlugin,
664
675
  Be as useNeedleProgressive
665
676
  };
@@ -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,Texture as k,TextureLoader as ie,Matrix4 as Y,Frustum as ae,Sphere as le,Box3 as J,Vector3 as B}from"three";import{GLTFLoader as ue}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as ce}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as de}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as he}from"three/examples/jsm/loaders/KTX2Loader.js";const fe="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ge="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";let R,$,G;function Q(r){R||(R=new de,R.setDecoderPath(fe),R.setDecoderConfig({type:"js"})),G||(G=new he,G.setTranscoderPath(ge)),$||($=ce),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 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 pe(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 a of n.keys){const i=s[a];if(i.isBufferGeometry===!0){const l=O.getMeshLODInformation(i),h=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=e,O.assignMeshLOD(s,h),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 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 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 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 a=n.index||0;s=s[a]}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.uniforms&&t.isRawShaderMaterial||t.isShaderMaterial===!0){const s=t;for(const a of Object.keys(s.uniforms)){const i=s.uniforms[a].value;if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,t,a);o.push(l),n.push(a)}}}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],h=n[i];l&&l.isTexture===!0?a.push({material:t,slot:h,texture:l,level:e}):a.push({material:t,slot:h,texture:null,level:e})}return a})}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 a=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i).textures===n&&(a=!0,D.registerTexture(this.url,i,n,s));a||this.parser.getDependency("texture",n).then(i=>{i&&D.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[P];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&&D.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(r,e){var t,o,n;const s=L=="verbose",a=r.userData.LODS;if(!a)return null;const i=a?.key;let l;if(r.isTexture===!0){const h=r;h.source&&h.source[X]&&(l=h.source[X])}if(l||(l=D.lodInfos.get(i)),l){if(e>0){let d=!1;const M=Array.isArray(l.lods);if(M&&e>=l.lods.length?d=!0:M||(d=!0),d)return this.lowresCache.get(i)}const h=Array.isArray(l.lods)?l.lods[e].path:l.lods;if(!h)return L&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const u=me(a.url,h);if(u.endsWith(".glb")||u.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const d=u+"_"+l.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 ${u}
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=l,A=new Promise(async(p,g)=>{const m=new ue;Z(m),L&&(await new Promise(v=>setTimeout(v,1e3)),s&&console.warn("Start loading (delayed) "+u,y.guid));let b=u;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 ${u}
3
+ `,v),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+u,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+'"',u,_,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}"`,u,_,f,d),f.isMesh===!0){const E=f.geometry;return D.assignLODInformation(a.url,E,i,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(a.url,j,i,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: "+u);const d=await new ie().loadAsync(u);return d?(d.guid=l.guid,d.flipY=!1,d.needsUpdate=!0,d.colorSpace=r.colorSpace,s&&console.log(l,d)):L&&console.warn("failed loading",u),d}}else L&&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 ye(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=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 a;L&&console.log("> Progressive: register mesh",n,t.name,s,t.uuid,t);const i=t.geometry;i.userData||(i.userData={}),D.assignLODInformation(r,i,e,o,n,s.density),D.lodInfos.set(e,s);let l=D.lowresCache.get(e);l?l.push(t.geometry):l=[t.geometry],D.lowresCache.set(e,l);for(const h of V)(a=h.onRegisteredNewMesh)==null||a.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 ye{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"),xe=q("noprogressive"),T=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new Y),c(this,"cameraFrustrum",new ae),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"plugins",[]),c(this,"_originalRender"),c(this,"_sphere",new le),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++,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){var n,s;if(xe||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 a=1e5,i=this.renderer.renderLists.get(r,t),l=i.opaque;for(const u of l){if(u.material&&(((n=u.geometry)==null?void 0:n.type)==="BoxGeometry"||((s=u.geometry)==null?void 0:s.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){K&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}const d=u.object;(d instanceof U||d.isMesh)&&this.updateLODs(r,e,d,a)}const h=i.transparent;for(const u of h){const d=u.object;(d instanceof U||d.isMesh)&&this.updateLODs(r,e,d,a)}}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 a=t.userData.LOD_state;a||(a=new ve,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 h=t["DEBUG:LOD"];if(h!=null&&(l=h),Array.isArray(t.material))for(const u of t.material)this.loadProgressiveTextures(u,l);else this.loadProgressiveTextures(t.material,l)}for(const h of this.plugins)(s=h.onAfterUpdatedLOD)==null||s.call(h,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(K&&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 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(l),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 u=this._tempBox.getSize(this._tempBoxSize);u.multiplyScalar(.5),screen.availHeight>0&&u.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),u.x*=h.aspect;const d=r.matrixWorldInverse,M=new J;M.copy(l),M.applyMatrix4(e.matrixWorld),M.applyMatrix4(d);const y=M.getSize(this._tempBox2Size),A=Math.max(y.x,y.y);if(Math.max(u.x,u.y)!=0&&A!=0&&(u.z=y.z/Math.max(y.x,y.y)*Math.max(u.x,u.y)),t.lastScreenCoverage=Math.max(u.x,u.y,u.z),t.lastScreenspaceVolume.copy(u),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(i&&t.lastScreenCoverage>0){for(let g=0;g<i.length;g++)if(i[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 ve{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(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 I(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){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(i){var l,h,u;if(i[z]==!0)return;i[z]=!0,i.userData&&(i.userData.LOD=-1);const d=Object.keys(i);for(let M=0;M<d.length;M++){const y=d[M],A=i[y];if(A?.isTexture===!0){const p=(h=(l=A.userData)==null?void 0:l.associations)==null?void 0:h.textures,g=o.parser.json.textures[p];if((u=g.extensions)!=null&&u[P]){const m=g.extensions[P];m&&n&&O.registerTexture(n,A,m.lods.length,m)}}}};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[P];if(a&&s){const i=t.uuid;O.registerMesh(s,i,t,0,a.lods.length,a)}}}function De(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,pe as registerPlugin,De 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 p=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),h=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,w.assignMeshLOD(o,h),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 p.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 p.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 p.Material||e.isMaterial===!0){const r=e,i=[],o=new Array;if(T&&Y.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const n of Object.keys(s.uniforms)){const a=s.uniforms[n].value;if((a==null?void 0:a.isTexture)===!0){const h=this.assignTextureLODForSlot(a,t,r,n);i.push(h),o.push(n)}}}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 h=s[a],d=o[a];h&&h.isTexture===!0?n.push({material:r,slot:d,texture:h,level:t}):n.push({material:r,slot:d,texture:null,level:t})}return n})}if(e instanceof p.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,h;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 p.Texture&&e instanceof p.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 p.BufferGeometry&&e instanceof p.BufferGeometry&&((h=x.attributes.position)!=null&&h.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 p.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 p.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 p.Texture){r&&console.log("Load texture from uri: "+c);const M=await new p.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 h;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)(h=d.onRegisteredNewMesh)==null||h.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 p.Matrix4);u(this,"cameraFrustrum",new p.Frustum);u(this,"updateInterval",0);u(this,"pause",!1);u(this,"plugins",[]);u(this,"_originalRender");u(this,"_sphere",new p.Sphere);u(this,"_tempBox",new p.Box3);u(this,"tempMatrix",new p.Matrix4);u(this,"_tempWorldPosition",new p.Vector3);u(this,"_tempBoxSize",new p.Vector3);u(this,"_tempBox2Size",new p.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 h,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&&(((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")){$&&(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 p.Mesh||f.isMesh)&&this.updateLODs(e,t,f,o)}const a=s.transparent;for(const c of a){const f=c.object;(f instanceof p.Mesh||f.isMesh)&&this.updateLODs(e,t,f,o)}}updateLODs(e,t,r,i){var a,h;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)(h=d.onAfterUpdatedLOD)==null||h.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),h=a==null?void 0:a.lods;if(!h||h.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 p.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(h&&r.lastScreenCoverage>0){for(let m=0;m<h.length;m++)if(h[m].density/r.lastScreenCoverage<i){R=m;break}}R<s&&(s=R)}}return s}};let _=A;u(_,"debugDrawLine"),u(_,"corner0",new p.Vector3),u(_,"corner1",new p.Vector3),u(_,"corner2",new p.Vector3),u(_,"corner3",new p.Vector3);class he{constructor(){u(this,"lastLodLevel",0);u(this,"lastScreenCoverage",0);u(this,"lastScreenspaceVolume",new p.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 h,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=(h=D.userData)==null?void 0:h.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;
package/lib/extension.js CHANGED
@@ -1,4 +1,4 @@
1
- import { BufferGeometry, Material, Mesh, RawShaderMaterial, Texture, TextureLoader } from "three";
1
+ import { BufferGeometry, Material, Mesh, Texture, TextureLoader } from "three";
2
2
  import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
3
3
  import { addDracoAndKTX2Loaders } from "./loaders.js";
4
4
  import { getParam, resolveUrl } from "./utils.js";
@@ -219,10 +219,12 @@ export class NEEDLE_progressive {
219
219
  const slots = new Array();
220
220
  if (debug)
221
221
  debug_materials.add(material);
222
- if (material instanceof RawShaderMaterial) {
222
+ // Handle custom shaders / uniforms progressive textures. This includes support for VRM shaders
223
+ if (material.uniforms && material.isRawShaderMaterial || material.isShaderMaterial === true) {
223
224
  // iterate uniforms of custom shaders
224
- for (const slot of Object.keys(material.uniforms)) {
225
- const val = material.uniforms[slot].value;
225
+ const shaderMaterial = material;
226
+ for (const slot of Object.keys(shaderMaterial.uniforms)) {
227
+ const val = shaderMaterial.uniforms[slot].value;
226
228
  if (val?.isTexture === true) {
227
229
  const task = this.assignTextureLODForSlot(val, level, material, slot);
228
230
  promises.push(task);
@@ -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.9",
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": {