@needle-tools/gltf-progressive 1.0.0-alpha.11 → 1.0.0-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/gltf-progressive.js +184 -176
- package/gltf-progressive.min.js +3 -3
- package/gltf-progressive.umd.cjs +3 -3
- package/lib/lods_manager.js +17 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,9 @@ All notable changes to this package will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [1.0.0-alpha.12] - 2023-05-19
|
|
8
|
+
- fix: update LODs when using postprocessing
|
|
9
|
+
|
|
7
10
|
## [1.0.0-alpha.11] - 2023-05-17
|
|
8
11
|
- add: expose `setDracoDecoderLocation` and `setKTX2TranscoderLocation`
|
|
9
12
|
- fix: allow using draco decoder and ktx2 transcoder from local filepath
|
package/gltf-progressive.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var le = Object.defineProperty;
|
|
2
2
|
var ue = (l, e, t) => e in l ? le(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
|
|
3
|
-
var
|
|
4
|
-
import { Mesh as q, BufferGeometry as V, Material as ce, Texture as U, TextureLoader as fe, Matrix4 as te, Frustum as de, Sphere as ge, Box3 as re, Vector3 as
|
|
3
|
+
var c = (l, e, t) => (ue(l, typeof e != "symbol" ? e + "" : e, t), t);
|
|
4
|
+
import { Mesh as q, BufferGeometry as V, Material as ce, Texture as U, TextureLoader as fe, Matrix4 as te, Frustum as de, Sphere as ge, Box3 as re, Vector3 as C } from "three";
|
|
5
5
|
import { GLTFLoader as he } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
6
6
|
import { MeshoptDecoder as pe } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
7
7
|
import { DRACOLoader as ye } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
@@ -40,18 +40,18 @@ function Le(l, e) {
|
|
|
40
40
|
return e;
|
|
41
41
|
}
|
|
42
42
|
const Q = new Array();
|
|
43
|
-
function
|
|
43
|
+
function ke(l) {
|
|
44
44
|
Q.push(l);
|
|
45
45
|
}
|
|
46
|
-
const
|
|
46
|
+
const R = "NEEDLE_progressive", S = ee("debugprogressive"), Y = Symbol("needle-progressive-texture"), z = /* @__PURE__ */ new Map(), Z = /* @__PURE__ */ new Set();
|
|
47
47
|
if (S) {
|
|
48
48
|
let l = function() {
|
|
49
49
|
e += 1, console.log("Toggle LOD level", e, z), z.forEach((i, n) => {
|
|
50
50
|
for (const s of i.keys) {
|
|
51
51
|
const o = n[s];
|
|
52
52
|
if (o.isBufferGeometry === !0) {
|
|
53
|
-
const a = v.getMeshLODInformation(o),
|
|
54
|
-
n["DEBUG:LOD"] = e, v.assignMeshLOD(n,
|
|
53
|
+
const a = v.getMeshLODInformation(o), g = a ? Math.min(e, a.lods.length) : 0;
|
|
54
|
+
n["DEBUG:LOD"] = e, v.assignMeshLOD(n, g), a && (t = Math.max(t, a.lods.length - 1));
|
|
55
55
|
} else if (n.isMaterial === !0) {
|
|
56
56
|
n["DEBUG:LOD"] = e, v.assignTextureLOD(n, e);
|
|
57
57
|
break;
|
|
@@ -75,13 +75,13 @@ function se(l, e, t) {
|
|
|
75
75
|
}
|
|
76
76
|
const M = class {
|
|
77
77
|
constructor(e, t) {
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
c(this, "parser");
|
|
79
|
+
c(this, "url");
|
|
80
80
|
S && console.log("Progressive extension registered for", t), this.parser = e, this.url = t;
|
|
81
81
|
}
|
|
82
82
|
/** The name of the extension */
|
|
83
83
|
get name() {
|
|
84
|
-
return
|
|
84
|
+
return R;
|
|
85
85
|
}
|
|
86
86
|
static getMeshLODInformation(e) {
|
|
87
87
|
const t = this.getAssignedLODInformation(e);
|
|
@@ -171,8 +171,8 @@ const M = class {
|
|
|
171
171
|
for (const o of Object.keys(s.uniforms)) {
|
|
172
172
|
const a = s.uniforms[o].value;
|
|
173
173
|
if ((a == null ? void 0 : a.isTexture) === !0) {
|
|
174
|
-
const
|
|
175
|
-
i.push(
|
|
174
|
+
const g = this.assignTextureLODForSlot(a, t, r, o);
|
|
175
|
+
i.push(g), n.push(o);
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
} else
|
|
@@ -186,8 +186,8 @@ const M = class {
|
|
|
186
186
|
return Promise.all(i).then((s) => {
|
|
187
187
|
const o = new Array();
|
|
188
188
|
for (let a = 0; a < s.length; a++) {
|
|
189
|
-
const
|
|
190
|
-
|
|
189
|
+
const g = s[a], f = n[a];
|
|
190
|
+
g && g.isTexture === !0 ? o.push({ material: r, slot: f, texture: g, level: t }) : o.push({ material: r, slot: f, texture: null, level: t });
|
|
191
191
|
}
|
|
192
192
|
return o;
|
|
193
193
|
});
|
|
@@ -217,7 +217,7 @@ const M = class {
|
|
|
217
217
|
var t, r;
|
|
218
218
|
return S && console.log("AFTER", this.url, e), (t = this.parser.json.textures) == null || t.forEach((i, n) => {
|
|
219
219
|
if (i != null && i.extensions) {
|
|
220
|
-
const s = i == null ? void 0 : i.extensions[
|
|
220
|
+
const s = i == null ? void 0 : i.extensions[R];
|
|
221
221
|
if (s) {
|
|
222
222
|
let o = !1;
|
|
223
223
|
for (const a of this.parser.associations.keys())
|
|
@@ -229,7 +229,7 @@ const M = class {
|
|
|
229
229
|
}
|
|
230
230
|
}), (r = this.parser.json.meshes) == null || r.forEach((i, n) => {
|
|
231
231
|
if (i != null && i.extensions) {
|
|
232
|
-
const s = i == null ? void 0 : i.extensions[
|
|
232
|
+
const s = i == null ? void 0 : i.extensions[R];
|
|
233
233
|
if (s && s.lods) {
|
|
234
234
|
for (const o of this.parser.associations.keys())
|
|
235
235
|
if (o.isMesh) {
|
|
@@ -241,107 +241,107 @@ const M = class {
|
|
|
241
241
|
}), null;
|
|
242
242
|
}
|
|
243
243
|
static async getOrLoadLOD(e, t) {
|
|
244
|
-
var o, a,
|
|
244
|
+
var o, a, g;
|
|
245
245
|
const r = S == "verbose", i = e.userData.LODS;
|
|
246
246
|
if (!i)
|
|
247
247
|
return null;
|
|
248
248
|
const n = i == null ? void 0 : i.key;
|
|
249
249
|
let s;
|
|
250
250
|
if (e.isTexture === !0) {
|
|
251
|
-
const
|
|
252
|
-
|
|
251
|
+
const f = e;
|
|
252
|
+
f.source && f.source[Y] && (s = f.source[Y]);
|
|
253
253
|
}
|
|
254
254
|
if (s || (s = M.lodInfos.get(n)), s) {
|
|
255
255
|
if (t > 0) {
|
|
256
|
-
let
|
|
257
|
-
const
|
|
258
|
-
if (
|
|
256
|
+
let u = !1;
|
|
257
|
+
const h = Array.isArray(s.lods);
|
|
258
|
+
if (h && t >= s.lods.length ? u = !0 : h || (u = !0), u)
|
|
259
259
|
return this.lowresCache.get(n);
|
|
260
260
|
}
|
|
261
|
-
const
|
|
262
|
-
if (!
|
|
261
|
+
const f = Array.isArray(s.lods) ? s.lods[t].path : s.lods;
|
|
262
|
+
if (!f)
|
|
263
263
|
return S && !s["missing:uri"] && (s["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + t, s)), null;
|
|
264
|
-
const
|
|
265
|
-
if (
|
|
264
|
+
const p = Le(i.url, f);
|
|
265
|
+
if (p.endsWith(".glb") || p.endsWith(".gltf")) {
|
|
266
266
|
if (!s.guid)
|
|
267
267
|
return console.warn("missing pointer for glb/gltf texture", s), null;
|
|
268
|
-
const
|
|
269
|
-
if (
|
|
270
|
-
r && console.log(`LOD ${t} was already loading/loaded: ${
|
|
271
|
-
let
|
|
272
|
-
`, I), null)),
|
|
273
|
-
if (
|
|
274
|
-
return
|
|
268
|
+
const u = p + "_" + s.guid, h = this.previouslyLoaded.get(u);
|
|
269
|
+
if (h !== void 0) {
|
|
270
|
+
r && console.log(`LOD ${t} was already loading/loaded: ${u}`);
|
|
271
|
+
let x = await h.catch((I) => (console.error(`Error loading LOD ${t} from ${p}
|
|
272
|
+
`, I), null)), k = !1;
|
|
273
|
+
if (x == null || (x instanceof U && e instanceof U ? (o = x.image) != null && o.data || (a = x.source) != null && a.data ? x = this.copySettings(e, x) : (k = !0, this.previouslyLoaded.delete(u)) : x instanceof V && e instanceof V && ((g = x.attributes.position) != null && g.array || (k = !0, this.previouslyLoaded.delete(u)))), !k)
|
|
274
|
+
return x;
|
|
275
275
|
}
|
|
276
|
-
const
|
|
276
|
+
const D = s, A = new Promise(async (x, k) => {
|
|
277
277
|
const I = new he();
|
|
278
|
-
oe(I), S && (await new Promise((
|
|
279
|
-
let
|
|
280
|
-
if (
|
|
281
|
-
const
|
|
282
|
-
|
|
278
|
+
oe(I), S && (await new Promise((m) => setTimeout(m, 1e3)), r && console.warn("Start loading (delayed) " + p, D.guid));
|
|
279
|
+
let L = p;
|
|
280
|
+
if (D && Array.isArray(D.lods)) {
|
|
281
|
+
const m = D.lods[t];
|
|
282
|
+
m.hash && (L += "?v=" + m.hash);
|
|
283
283
|
}
|
|
284
|
-
const
|
|
285
|
-
`,
|
|
286
|
-
if (!
|
|
284
|
+
const y = await I.loadAsync(L).catch((m) => (console.error(`Error loading LOD ${t} from ${p}
|
|
285
|
+
`, m), null));
|
|
286
|
+
if (!y)
|
|
287
287
|
return null;
|
|
288
|
-
const T =
|
|
289
|
-
r && console.log("Loading finished " +
|
|
290
|
-
let
|
|
291
|
-
if (
|
|
292
|
-
let
|
|
293
|
-
for (const d of
|
|
288
|
+
const T = y.parser;
|
|
289
|
+
r && console.log("Loading finished " + p, D.guid);
|
|
290
|
+
let O = 0;
|
|
291
|
+
if (y.parser.json.textures) {
|
|
292
|
+
let m = !1;
|
|
293
|
+
for (const d of y.parser.json.textures) {
|
|
294
294
|
if (d != null && d.extensions) {
|
|
295
|
-
const
|
|
296
|
-
if (
|
|
297
|
-
|
|
295
|
+
const w = d == null ? void 0 : d.extensions[R];
|
|
296
|
+
if (w != null && w.guid && w.guid === D.guid) {
|
|
297
|
+
m = !0;
|
|
298
298
|
break;
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
|
-
|
|
301
|
+
O++;
|
|
302
302
|
}
|
|
303
|
-
if (
|
|
304
|
-
let d = await T.getDependency("texture",
|
|
305
|
-
return r && console.log('change "' + e.name + '" → "' + d.name + '"',
|
|
303
|
+
if (m) {
|
|
304
|
+
let d = await T.getDependency("texture", O);
|
|
305
|
+
return r && console.log('change "' + e.name + '" → "' + d.name + '"', p, O, d, u), e instanceof U && (d = this.copySettings(e, d)), d && (d.guid = D.guid), x(d);
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
|
-
if (
|
|
309
|
-
let
|
|
310
|
-
for (const d of
|
|
308
|
+
if (O = 0, y.parser.json.meshes) {
|
|
309
|
+
let m = !1;
|
|
310
|
+
for (const d of y.parser.json.meshes) {
|
|
311
311
|
if (d != null && d.extensions) {
|
|
312
|
-
const
|
|
313
|
-
if (
|
|
314
|
-
|
|
312
|
+
const w = d == null ? void 0 : d.extensions[R];
|
|
313
|
+
if (w != null && w.guid && w.guid === D.guid) {
|
|
314
|
+
m = !0;
|
|
315
315
|
break;
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
|
-
|
|
318
|
+
O++;
|
|
319
319
|
}
|
|
320
|
-
if (
|
|
321
|
-
const d = await T.getDependency("mesh",
|
|
322
|
-
if (r && console.log(`Loaded Mesh "${d.name}"`,
|
|
320
|
+
if (m) {
|
|
321
|
+
const d = await T.getDependency("mesh", O), w = D;
|
|
322
|
+
if (r && console.log(`Loaded Mesh "${d.name}"`, p, O, d, u), d.isMesh === !0) {
|
|
323
323
|
const P = d.geometry;
|
|
324
|
-
return M.assignLODInformation(i.url, P, n, t, void 0,
|
|
324
|
+
return M.assignLODInformation(i.url, P, n, t, void 0, w.density), x(P);
|
|
325
325
|
} else {
|
|
326
326
|
const P = new Array();
|
|
327
327
|
for (let _ = 0; _ < d.children.length; _++) {
|
|
328
328
|
const E = d.children[_];
|
|
329
329
|
if (E instanceof q) {
|
|
330
330
|
const N = E.geometry;
|
|
331
|
-
M.assignLODInformation(i.url, N, n, t, _,
|
|
331
|
+
M.assignLODInformation(i.url, N, n, t, _, w.density), P.push(N);
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
|
-
return
|
|
334
|
+
return x(P);
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
337
|
}
|
|
338
|
-
return
|
|
338
|
+
return x(null);
|
|
339
339
|
});
|
|
340
|
-
return this.previouslyLoaded.set(
|
|
340
|
+
return this.previouslyLoaded.set(u, A), await A;
|
|
341
341
|
} else if (e instanceof U) {
|
|
342
|
-
r && console.log("Load texture from uri: " +
|
|
343
|
-
const
|
|
344
|
-
return
|
|
342
|
+
r && console.log("Load texture from uri: " + p);
|
|
343
|
+
const h = await new fe().loadAsync(p);
|
|
344
|
+
return h ? (h.guid = s.guid, h.flipY = !1, h.needsUpdate = !0, h.colorSpace = e.colorSpace, r && console.log(s, h)) : S && console.warn("failed loading", p), h;
|
|
345
345
|
}
|
|
346
346
|
} else
|
|
347
347
|
S && console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`, e.type);
|
|
@@ -367,62 +367,62 @@ let v = M;
|
|
|
367
367
|
/**
|
|
368
368
|
* Register a texture with LOD information
|
|
369
369
|
*/
|
|
370
|
-
|
|
370
|
+
c(v, "registerTexture", (e, t, r, i) => {
|
|
371
371
|
S && console.log("> Progressive: register texture", r, t.name, t.uuid, t, i), t.source && (t.source[Y] = i);
|
|
372
372
|
const n = i.guid;
|
|
373
373
|
M.assignLODInformation(e, t, n, 0, 0, void 0), M.lodInfos.set(n, i), M.lowresCache.set(n, t);
|
|
374
374
|
}), /**
|
|
375
375
|
* Register a mesh with LOD information
|
|
376
376
|
*/
|
|
377
|
-
|
|
378
|
-
var
|
|
377
|
+
c(v, "registerMesh", (e, t, r, i, n, s) => {
|
|
378
|
+
var g;
|
|
379
379
|
S && console.log("> Progressive: register mesh", n, r.name, s, r.uuid, r);
|
|
380
380
|
const o = r.geometry;
|
|
381
381
|
o.userData || (o.userData = {}), M.assignLODInformation(e, o, t, i, n, s.density), M.lodInfos.set(t, s);
|
|
382
382
|
let a = M.lowresCache.get(t);
|
|
383
383
|
a ? a.push(r.geometry) : a = [r.geometry], M.lowresCache.set(t, a);
|
|
384
|
-
for (const
|
|
385
|
-
(
|
|
384
|
+
for (const f of Q)
|
|
385
|
+
(g = f.onRegisteredNewMesh) == null || g.call(f, r, s);
|
|
386
386
|
}), /** A map of key = asset uuid and value = LOD information */
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
387
|
+
c(v, "lodInfos", /* @__PURE__ */ new Map()), /** cache of already loaded mesh lods */
|
|
388
|
+
c(v, "previouslyLoaded", /* @__PURE__ */ new Map()), /** this contains the geometry/textures that were originally loaded */
|
|
389
|
+
c(v, "lowresCache", /* @__PURE__ */ new Map()), c(v, "_copiedTextures", /* @__PURE__ */ new Map());
|
|
390
390
|
class De {
|
|
391
391
|
constructor(e, t, r, i, n) {
|
|
392
|
-
|
|
392
|
+
c(this, "url");
|
|
393
393
|
/** the key to lookup the LOD information */
|
|
394
|
-
|
|
395
|
-
|
|
394
|
+
c(this, "key");
|
|
395
|
+
c(this, "level");
|
|
396
396
|
/** For multi objects (e.g. a group of meshes) this is the index of the object */
|
|
397
|
-
|
|
397
|
+
c(this, "index");
|
|
398
398
|
/** the mesh density */
|
|
399
|
-
|
|
399
|
+
c(this, "density");
|
|
400
400
|
this.url = e, this.key = t, this.level = r, i != null && (this.index = i), n != null && (this.density = n);
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
403
|
const H = ee("debugprogressive"), xe = ee("noprogressive"), b = class {
|
|
404
404
|
constructor(e) {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
405
|
+
c(this, "renderer");
|
|
406
|
+
c(this, "projectionScreenMatrix", new te());
|
|
407
|
+
c(this, "cameraFrustrum", new de());
|
|
408
408
|
/**
|
|
409
409
|
* 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.
|
|
410
410
|
*/
|
|
411
|
-
|
|
411
|
+
c(this, "updateInterval", 0);
|
|
412
412
|
/**
|
|
413
413
|
* If set to true, the LODsManager will not update the LODs.
|
|
414
414
|
*/
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
415
|
+
c(this, "pause", !1);
|
|
416
|
+
c(this, "plugins", []);
|
|
417
|
+
c(this, "_frame", 0);
|
|
418
|
+
c(this, "_originalRender");
|
|
419
419
|
// private testIfLODLevelsAreAvailable() {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
420
|
+
c(this, "_sphere", new ge());
|
|
421
|
+
c(this, "_tempBox", new re());
|
|
422
|
+
c(this, "tempMatrix", new te());
|
|
423
|
+
c(this, "_tempWorldPosition", new C());
|
|
424
|
+
c(this, "_tempBoxSize", new C());
|
|
425
|
+
c(this, "_tempBox2Size", new C());
|
|
426
426
|
this.renderer = e;
|
|
427
427
|
}
|
|
428
428
|
/** @internal */
|
|
@@ -451,47 +451,55 @@ const H = ee("debugprogressive"), xe = ee("noprogressive"), b = class {
|
|
|
451
451
|
onBeforeRender(e, t, r, i) {
|
|
452
452
|
}
|
|
453
453
|
onAfterRender(e, t, r, i) {
|
|
454
|
-
var
|
|
455
|
-
if (
|
|
454
|
+
var a, g;
|
|
455
|
+
if (this.pause)
|
|
456
|
+
return;
|
|
457
|
+
const n = this.renderer.renderLists.get(e, 0), s = n.opaque;
|
|
458
|
+
let o = !0;
|
|
459
|
+
if (s.length === 1) {
|
|
460
|
+
const f = s[0].material;
|
|
461
|
+
(f.name === "EffectMaterial" || f.name === "CopyShader") && (o = !1);
|
|
462
|
+
}
|
|
463
|
+
if (o) {
|
|
456
464
|
if (xe || this.updateInterval > 0 && i % this.updateInterval != 0)
|
|
457
465
|
return;
|
|
458
466
|
this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix, t.matrixWorldInverse), this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix, this.renderer.coordinateSystem);
|
|
459
|
-
const
|
|
460
|
-
for (const
|
|
461
|
-
if (
|
|
462
|
-
H && (
|
|
467
|
+
const f = 1e5;
|
|
468
|
+
for (const u of s) {
|
|
469
|
+
if (u.material && (((a = u.geometry) == null ? void 0 : a.type) === "BoxGeometry" || ((g = u.geometry) == null ? void 0 : g.type) === "BufferGeometry") && (u.material.name === "SphericalGaussianBlur" || u.material.name == "BackgroundCubeMaterial" || u.material.name === "CubemapFromEquirect" || u.material.name === "EquirectangularToCubeUV")) {
|
|
470
|
+
H && (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)));
|
|
463
471
|
continue;
|
|
464
472
|
}
|
|
465
|
-
const
|
|
466
|
-
(
|
|
473
|
+
const h = u.object;
|
|
474
|
+
(h instanceof q || h.isMesh) && this.updateLODs(e, t, h, f);
|
|
467
475
|
}
|
|
468
|
-
const
|
|
469
|
-
for (const
|
|
470
|
-
const
|
|
471
|
-
(
|
|
476
|
+
const p = n.transparent;
|
|
477
|
+
for (const u of p) {
|
|
478
|
+
const h = u.object;
|
|
479
|
+
(h instanceof q || h.isMesh) && this.updateLODs(e, t, h, f);
|
|
472
480
|
}
|
|
473
481
|
}
|
|
474
482
|
}
|
|
475
483
|
/** Update the LOD levels for the renderer. */
|
|
476
484
|
updateLODs(e, t, r, i) {
|
|
477
|
-
var a,
|
|
478
|
-
for (const
|
|
479
|
-
(a =
|
|
485
|
+
var a, g;
|
|
486
|
+
for (const f of this.plugins)
|
|
487
|
+
(a = f.onBeforeUpdateLOD) == null || a.call(f, this.renderer, e, t, r);
|
|
480
488
|
let n = r.userData.LOD_state;
|
|
481
|
-
n || (n = new
|
|
489
|
+
n || (n = new Oe(), r.userData.LOD_state = n);
|
|
482
490
|
let s = this.calculateLodLevel(t, r, n, i);
|
|
483
491
|
s = Math.round(s), s >= 0 && this.loadProgressiveMeshes(r, s);
|
|
484
492
|
let o = 0;
|
|
485
493
|
if (r.material) {
|
|
486
|
-
const
|
|
487
|
-
if (
|
|
488
|
-
for (const
|
|
489
|
-
this.loadProgressiveTextures(
|
|
494
|
+
const f = r["DEBUG:LOD"];
|
|
495
|
+
if (f != null && (o = f), Array.isArray(r.material))
|
|
496
|
+
for (const p of r.material)
|
|
497
|
+
this.loadProgressiveTextures(p, o);
|
|
490
498
|
else
|
|
491
499
|
this.loadProgressiveTextures(r.material, o);
|
|
492
500
|
}
|
|
493
|
-
for (const
|
|
494
|
-
(
|
|
501
|
+
for (const f of this.plugins)
|
|
502
|
+
(g = f.onAfterUpdatedLOD) == null || g.call(f, this.renderer, e, t, r, s);
|
|
495
503
|
n.lastLodLevel = s;
|
|
496
504
|
}
|
|
497
505
|
/** Load progressive textures for the given material
|
|
@@ -526,49 +534,49 @@ const H = ee("debugprogressive"), xe = ee("noprogressive"), b = class {
|
|
|
526
534
|
if (e) {
|
|
527
535
|
if (H && t["DEBUG:LOD"] != null)
|
|
528
536
|
return t["DEBUG:LOD"];
|
|
529
|
-
const a = v.getMeshLODInformation(t.geometry),
|
|
530
|
-
if (!
|
|
537
|
+
const a = v.getMeshLODInformation(t.geometry), g = a == null ? void 0 : a.lods;
|
|
538
|
+
if (!g || g.length <= 0 || !((o = this.cameraFrustrum) != null && o.intersectsObject(t)))
|
|
531
539
|
return 99;
|
|
532
|
-
const
|
|
533
|
-
if (
|
|
534
|
-
const
|
|
540
|
+
const f = t.geometry.boundingBox;
|
|
541
|
+
if (f && e.isPerspectiveCamera) {
|
|
542
|
+
const p = e;
|
|
535
543
|
if (t.geometry.attributes.color && t.geometry.attributes.color.count < 100 && t.geometry.boundingSphere) {
|
|
536
544
|
this._sphere.copy(t.geometry.boundingSphere), this._sphere.applyMatrix4(t.matrixWorld);
|
|
537
|
-
const
|
|
538
|
-
if (this._sphere.containsPoint(
|
|
545
|
+
const L = e.getWorldPosition(this._tempWorldPosition);
|
|
546
|
+
if (this._sphere.containsPoint(L))
|
|
539
547
|
return 0;
|
|
540
548
|
}
|
|
541
|
-
if (this._tempBox.copy(
|
|
542
|
-
const
|
|
543
|
-
let T =
|
|
544
|
-
const
|
|
545
|
-
T = (T - _) *
|
|
546
|
-
const N = T < 0 &&
|
|
549
|
+
if (this._tempBox.copy(f), this._tempBox.applyMatrix4(t.matrixWorld), this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && p.fov > 70) {
|
|
550
|
+
const L = this._tempBox.min, y = this._tempBox.max;
|
|
551
|
+
let T = L.x, O = L.y, m = y.x, d = y.y;
|
|
552
|
+
const w = 2, P = 1.5, _ = (L.x + y.x) * 0.5, E = (L.y + y.y) * 0.5;
|
|
553
|
+
T = (T - _) * w + _, O = (O - E) * w + E, m = (m - _) * w + _, d = (d - E) * w + E;
|
|
554
|
+
const N = T < 0 && m > 0 ? 0 : Math.min(Math.abs(L.x), Math.abs(y.x)), ae = O < 0 && d > 0 ? 0 : Math.min(Math.abs(L.y), Math.abs(y.y)), X = Math.max(N, ae);
|
|
547
555
|
r.lastCentrality = (P - X) * (P - X) * (P - X);
|
|
548
556
|
} else
|
|
549
557
|
r.lastCentrality = 1;
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
const A =
|
|
555
|
-
if (Math.max(
|
|
556
|
-
const
|
|
557
|
-
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
const d = (
|
|
561
|
-
|
|
558
|
+
const u = this._tempBox.getSize(this._tempBoxSize);
|
|
559
|
+
u.multiplyScalar(0.5), screen.availHeight > 0 && u.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), u.x *= p.aspect;
|
|
560
|
+
const h = e.matrixWorldInverse, D = new re();
|
|
561
|
+
D.copy(f), D.applyMatrix4(t.matrixWorld), D.applyMatrix4(h);
|
|
562
|
+
const A = D.getSize(this._tempBox2Size), G = Math.max(A.x, A.y);
|
|
563
|
+
if (Math.max(u.x, u.y) != 0 && G != 0 && (u.z = A.z / Math.max(A.x, A.y) * Math.max(u.x, u.y)), r.lastScreenCoverage = Math.max(u.x, u.y, u.z), r.lastScreenspaceVolume.copy(u), r.lastScreenCoverage *= r.lastCentrality, H && b.debugDrawLine) {
|
|
564
|
+
const L = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
565
|
+
L.invert();
|
|
566
|
+
const y = b.corner0, T = b.corner1, O = b.corner2, m = b.corner3;
|
|
567
|
+
y.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = y.x, O.copy(this._tempBox.max), O.y = y.y, m.copy(this._tempBox.max);
|
|
568
|
+
const d = (y.z + m.z) * 0.5;
|
|
569
|
+
y.z = T.z = O.z = m.z = d, y.applyMatrix4(L), T.applyMatrix4(L), O.applyMatrix4(L), m.applyMatrix4(L), b.debugDrawLine(y, T, 255), b.debugDrawLine(y, O, 255), b.debugDrawLine(T, m, 255), b.debugDrawLine(O, m, 255);
|
|
562
570
|
}
|
|
563
|
-
let
|
|
564
|
-
if (
|
|
565
|
-
for (let
|
|
566
|
-
if (
|
|
567
|
-
|
|
571
|
+
let k = 999;
|
|
572
|
+
if (g && r.lastScreenCoverage > 0) {
|
|
573
|
+
for (let L = 0; L < g.length; L++)
|
|
574
|
+
if (g[L].density / r.lastScreenCoverage < i) {
|
|
575
|
+
k = L;
|
|
568
576
|
break;
|
|
569
577
|
}
|
|
570
578
|
}
|
|
571
|
-
|
|
579
|
+
k < s && (s = k);
|
|
572
580
|
}
|
|
573
581
|
}
|
|
574
582
|
return s;
|
|
@@ -577,17 +585,17 @@ const H = ee("debugprogressive"), xe = ee("noprogressive"), b = class {
|
|
|
577
585
|
let B = b;
|
|
578
586
|
/** 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.
|
|
579
587
|
*/
|
|
580
|
-
|
|
581
|
-
class
|
|
588
|
+
c(B, "debugDrawLine"), c(B, "corner0", new C()), c(B, "corner1", new C()), c(B, "corner2", new C()), c(B, "corner3", new C());
|
|
589
|
+
class Oe {
|
|
582
590
|
constructor() {
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
591
|
+
c(this, "lastLodLevel", 0);
|
|
592
|
+
c(this, "lastScreenCoverage", 0);
|
|
593
|
+
c(this, "lastScreenspaceVolume", new C());
|
|
594
|
+
c(this, "lastCentrality", 0);
|
|
587
595
|
}
|
|
588
596
|
}
|
|
589
597
|
const ie = Symbol("NEEDLE_mesh_lod"), $ = Symbol("NEEDLE_texture_lod");
|
|
590
|
-
function
|
|
598
|
+
function we(l) {
|
|
591
599
|
if (!l)
|
|
592
600
|
return null;
|
|
593
601
|
let e = null, t = null;
|
|
@@ -610,8 +618,8 @@ function Oe(l) {
|
|
|
610
618
|
}
|
|
611
619
|
class Me {
|
|
612
620
|
constructor(e) {
|
|
613
|
-
|
|
614
|
-
|
|
621
|
+
c(this, "modelviewer");
|
|
622
|
+
c(this, "_didWarnAboutMissingUrl", !1);
|
|
615
623
|
this.modelviewer = e;
|
|
616
624
|
}
|
|
617
625
|
onBeforeUpdateLOD(e, t, r, i) {
|
|
@@ -631,18 +639,18 @@ class Me {
|
|
|
631
639
|
const r = this.tryGetCurrentGLTF(e), i = this.getUrl();
|
|
632
640
|
if (i && r && t.material) {
|
|
633
641
|
let n = function(o) {
|
|
634
|
-
var
|
|
642
|
+
var g, f, p;
|
|
635
643
|
if (o[$] == !0)
|
|
636
644
|
return;
|
|
637
645
|
o[$] = !0, o.userData && (o.userData.LOD = -1);
|
|
638
646
|
const a = Object.keys(o);
|
|
639
|
-
for (let
|
|
640
|
-
const
|
|
641
|
-
if ((
|
|
642
|
-
const A = (
|
|
643
|
-
if ((
|
|
644
|
-
const
|
|
645
|
-
|
|
647
|
+
for (let u = 0; u < a.length; u++) {
|
|
648
|
+
const h = a[u], D = o[h];
|
|
649
|
+
if ((D == null ? void 0 : D.isTexture) === !0) {
|
|
650
|
+
const A = (f = (g = D.userData) == null ? void 0 : g.associations) == null ? void 0 : f.textures, G = r.parser.json.textures[A];
|
|
651
|
+
if ((p = G.extensions) != null && p[R]) {
|
|
652
|
+
const x = G.extensions[R];
|
|
653
|
+
x && i && v.registerTexture(i, D, x.lods.length, x);
|
|
646
654
|
}
|
|
647
655
|
}
|
|
648
656
|
}
|
|
@@ -663,28 +671,28 @@ class Me {
|
|
|
663
671
|
const r = this.getUrl();
|
|
664
672
|
if (!r)
|
|
665
673
|
return;
|
|
666
|
-
const i = (s = (n = t.userData) == null ? void 0 : n.gltfExtensions) == null ? void 0 : s[
|
|
674
|
+
const i = (s = (n = t.userData) == null ? void 0 : n.gltfExtensions) == null ? void 0 : s[R];
|
|
667
675
|
if (i && r) {
|
|
668
676
|
const o = t.uuid;
|
|
669
677
|
v.registerMesh(r, o, t, 0, i.lods.length, i);
|
|
670
678
|
}
|
|
671
679
|
}
|
|
672
680
|
}
|
|
673
|
-
function
|
|
681
|
+
function Ce(l, e, t, r) {
|
|
674
682
|
ne(e), oe(t), t.register((n) => new v(n, l));
|
|
675
683
|
const i = new B(e);
|
|
676
684
|
return (r == null ? void 0 : r.enableLODsManager) !== !1 && i.enable(), i;
|
|
677
685
|
}
|
|
678
686
|
document.addEventListener("DOMContentLoaded", () => {
|
|
679
|
-
|
|
687
|
+
we(document.querySelector("model-viewer"));
|
|
680
688
|
});
|
|
681
689
|
export {
|
|
682
|
-
|
|
690
|
+
R as EXTENSION_NAME,
|
|
683
691
|
B as LODsManager,
|
|
684
692
|
v as NEEDLE_progressive,
|
|
685
|
-
|
|
686
|
-
|
|
693
|
+
we as patchModelViewer,
|
|
694
|
+
ke as registerPlugin,
|
|
687
695
|
_e as setDracoDecoderLocation,
|
|
688
696
|
Be as setKTX2TranscoderLocation,
|
|
689
|
-
|
|
697
|
+
Ce as useNeedleProgressive
|
|
690
698
|
};
|
package/gltf-progressive.min.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var ne=Object.defineProperty,ie=(r,e,t)=>e in r?ne(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,c=(r,e,t)=>(ie(r,typeof e!="symbol"?e+"":e,t),t);import{Mesh as U,BufferGeometry as $,Material as ae,Texture as
|
|
2
|
-
`,m),null)),g=!1;if(
|
|
3
|
-
`,L),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 L=!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){L=!0;break}}_++}if(L){let f=await S.getDependency("texture",_);return s&&console.log('change "'+r.name+'" \u2192 "'+f.name+'"',u,_,f,d),r instanceof j&&(f=this.copySettings(r,f)),f&&(f.guid=y.guid),p(f)}}if(_=0,x.parser.json.meshes){let L=!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){L=!0;break}}_++}if(L){const f=await S.getDependency("mesh",_),w=y;if(s&&console.log(`Loaded Mesh "${f.name}"`,u,_,f,d),f.isMesh===!0){const T=f.geometry;return D.assignLODInformation(a.url,T,i,e,void 0,w.density),p(T)}else{const T=new Array;for(let C=0;C<f.children.length;C++){const W=f.children[C];if(W instanceof U){const R=W.geometry;D.assignLODInformation(a.url,R,i,e,C,w.density),T.push(R)}}return p(T)}}}return p(null)});return this.previouslyLoaded.set(d,A),await A}else if(r instanceof j){s&&console.log("Load texture from uri: "+u);const d=await new le().loadAsync(u);return d?(d.guid=l.guid,d.flipY=!1,d.needsUpdate=!0,d.colorSpace=r.colorSpace,s&&console.log(l,d)):v&&console.warn("failed loading",u),d}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,o,n,s){if(!e)return;e.userData||(e.userData={});const a=new Le(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)=>{v&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,o),e.source&&(e.source[H]=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;v&&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 K)(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 Le{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 J=X("debugprogressive"),ve=X("noprogressive"),E=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new Q),c(this,"cameraFrustrum",new ue),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"plugins",[]),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new ce),c(this,"_tempBox",new Z),c(this,"tempMatrix",new Q),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;ee(this.renderer),this.renderer.render=function(t,o){e.renderer.getRenderTarget()==null&&(r=0,e._frame+=1);const n=e._frame,s=r++;e.onBeforeRender(t,o,s,n),e._originalRender.call(this,t,o),e.onAfterRender(t,o,s,n)}}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(!this.pause&&t==0){if(ve||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")){J&&(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 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 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(J&&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 L=2,f=1.5,w=(g.x+m.x)*.5,T=(g.y+m.y)*.5;b=(b-w)*L+w,x=(x-T)*L+T,S=(S-w)*L+w,_=(_-T)*L+T;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)),R=Math.max(C,W);t.lastCentrality=(f-R)*(f-R)*(f-R)}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 Z;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,J&&E.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const m=E.corner0,b=E.corner1,x=E.corner2,S=E.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),E.debugDrawLine(m,b,255),E.debugDrawLine(m,x,255),E.debugDrawLine(b,S,255),E.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=E;c(I,"debugDrawLine"),c(I,"corner0",new B),c(I,"corner1",new B),c(I,"corner2",new B),c(I,"corner3",new B);class De{constructor(){c(this,"lastLodLevel",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const se=Symbol("NEEDLE_mesh_lod"),F=Symbol("NEEDLE_texture_lod");function oe(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 Oe(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 Oe{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[F]==!0)return;t[F]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&t.material){let s=function(i){var l,h,u;if(i[F]==!0)return;i[F]=!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[se]==!0)return;t[se]=!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 we(r,e,t,o){ee(e),re(t),t.register(s=>new O(s,r));const n=new I(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{oe(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,O as NEEDLE_progressive,oe as patchModelViewer,xe as registerPlugin,me as setDracoDecoderLocation,pe as setKTX2TranscoderLocation,we as useNeedleProgressive};
|
|
1
|
+
var ne=Object.defineProperty,ie=(r,e,t)=>e in r?ne(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,c=(r,e,t)=>(ie(r,typeof e!="symbol"?e+"":e,t),t);import{Mesh as U,BufferGeometry as $,Material as ae,Texture as C,TextureLoader as le,Matrix4 as Q,Frustum as ue,Sphere as ce,Box3 as Z,Vector3 as B}from"three";import{GLTFLoader as de}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as he}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as fe}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as ge}from"three/examples/jsm/loaders/KTX2Loader.js";let z="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",q="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(z+"draco_decoder.js",{method:"head"}).catch(r=>{z="./include/draco/",q="./include/ktx2/"});function me(r){z=r}function pe(r){q=r}let R,V,G;function ee(r){R||(R=new fe,R.setDecoderPath(z),R.setDecoderConfig({type:"js"})),G||(G=new ge,G.setTranscoderPath(q)),V||(V=he),r?G.detectSupport(r):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function re(r){r.dracoLoader||r.setDRACOLoader(R),r.ktx2Loader||r.setKTX2Loader(G),r.meshoptDecoder||r.setMeshoptDecoder(V)}function X(r){const e=new URL(window.location.href).searchParams.get(r);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function ye(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 K=new Array;function Le(r){K.push(r)}const P="NEEDLE_progressive",v=X("debugprogressive"),H=Symbol("needle-progressive-texture"),N=new Map,Y=new Set;if(v){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=w.getMeshLODInformation(i),d=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=e,w.assignMeshLOD(s,d),l&&(t=Math.max(t,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,w.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,Y&&Y.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=o)}))})}function te(r,e,t){var o;if(!v)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 O=class{constructor(r,e){c(this,"parser"),c(this,"url"),v&&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 K)(t=s.onBeforeGetLODMesh)==null||t.call(s,r,e);return r["LOD:requested level"]=e,O.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 $&&(r.geometry=s,v&&te(r,"geometry",n.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",r,s),null))}else v&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",r);return Promise.resolve(null)}static assignTextureLOD(r,e=0){if(!r)return Promise.resolve(null);if(r instanceof ae||r.isMaterial===!0){const t=r,o=[],n=new Array;if(v&&Y.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],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):O.getOrLoadLOD(r,e).then(n=>{if(Array.isArray(n))return null;if(n?.isTexture===!0){if(n!=r&&(t&&o&&(t[o]=n),v&&o&&t)){const s=this.getAssignedLODInformation(r);s&&te(t,o,s.url)}return n}else v=="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 v&&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,O.registerTexture(this.url,i,n,s));a||this.parser.getDependency("texture",n).then(i=>{i&&O.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&&O.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(r,e){var t,o,n;const s=v=="verbose",a=r.userData.LODS;if(!a)return null;const i=a?.key;let l;if(r.isTexture===!0){const d=r;d.source&&d.source[H]&&(l=d.source[H])}if(l||(l=O.lodInfos.get(i)),l){if(e>0){let u=!1;const p=Array.isArray(l.lods);if(p&&e>=l.lods.length?u=!0:p||(u=!0),u)return this.lowresCache.get(i)}const d=Array.isArray(l.lods)?l.lods[e].path:l.lods;if(!d)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const h=ye(a.url,d);if(h.endsWith(".glb")||h.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const u=h+"_"+l.guid,p=this.previouslyLoaded.get(u);if(p!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${u}`);let y=await p.catch(m=>(console.error(`Error loading LOD ${e} from ${h}
|
|
2
|
+
`,m),null)),g=!1;if(y==null||(y instanceof C&&r instanceof C?(t=y.image)!=null&&t.data||(o=y.source)!=null&&o.data?y=this.copySettings(r,y):(g=!0,this.previouslyLoaded.delete(u)):y instanceof $&&r instanceof $&&((n=y.attributes.position)!=null&&n.array||(g=!0,this.previouslyLoaded.delete(u)))),!g)return y}const L=l,A=new Promise(async(y,g)=>{const m=new de;re(m),v&&(await new Promise(D=>setTimeout(D,1e3)),s&&console.warn("Start loading (delayed) "+h,L.guid));let b=h;if(L&&Array.isArray(L.lods)){const D=L.lods[e];D.hash&&(b+="?v="+D.hash)}const x=await m.loadAsync(b).catch(D=>(console.error(`Error loading LOD ${e} from ${h}
|
|
3
|
+
`,D),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+h,L.guid);let _=0;if(x.parser.json.textures){let D=!1;for(const f of x.parser.json.textures){if(f!=null&&f.extensions){const M=f?.extensions[P];if(M!=null&&M.guid&&M.guid===L.guid){D=!0;break}}_++}if(D){let f=await S.getDependency("texture",_);return s&&console.log('change "'+r.name+'" \u2192 "'+f.name+'"',h,_,f,u),r instanceof C&&(f=this.copySettings(r,f)),f&&(f.guid=L.guid),y(f)}}if(_=0,x.parser.json.meshes){let D=!1;for(const f of x.parser.json.meshes){if(f!=null&&f.extensions){const M=f?.extensions[P];if(M!=null&&M.guid&&M.guid===L.guid){D=!0;break}}_++}if(D){const f=await S.getDependency("mesh",_),M=L;if(s&&console.log(`Loaded Mesh "${f.name}"`,h,_,f,u),f.isMesh===!0){const T=f.geometry;return O.assignLODInformation(a.url,T,i,e,void 0,M.density),y(T)}else{const T=new Array;for(let k=0;k<f.children.length;k++){const W=f.children[k];if(W instanceof U){const j=W.geometry;O.assignLODInformation(a.url,j,i,e,k,M.density),T.push(j)}}return y(T)}}}return y(null)});return this.previouslyLoaded.set(u,A),await A}else if(r instanceof C){s&&console.log("Load texture from uri: "+h);const u=await new le().loadAsync(h);return u?(u.guid=l.guid,u.flipY=!1,u.needsUpdate=!0,u.colorSpace=r.colorSpace,s&&console.log(l,u)):v&&console.warn("failed loading",h),u}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,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 w=O;c(w,"registerTexture",(r,e,t,o)=>{v&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,o),e.source&&(e.source[H]=o);const n=o.guid;O.assignLODInformation(r,e,n,0,0,void 0),O.lodInfos.set(n,o),O.lowresCache.set(n,e)}),c(w,"registerMesh",(r,e,t,o,n,s)=>{var a;v&&console.log("> Progressive: register mesh",n,t.name,s,t.uuid,t);const i=t.geometry;i.userData||(i.userData={}),O.assignLODInformation(r,i,e,o,n,s.density),O.lodInfos.set(e,s);let l=O.lowresCache.get(e);l?l.push(t.geometry):l=[t.geometry],O.lowresCache.set(e,l);for(const d of K)(a=d.onRegisteredNewMesh)==null||a.call(d,t,s)}),c(w,"lodInfos",new Map),c(w,"previouslyLoaded",new Map),c(w,"lowresCache",new Map),c(w,"_copiedTextures",new Map);class xe{constructor(e,t,o,n,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=t,this.level=o,n!=null&&(this.index=n),s!=null&&(this.density=s)}}const J=X("debugprogressive"),De=X("noprogressive"),E=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new Q),c(this,"cameraFrustrum",new ue),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"plugins",[]),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new ce),c(this,"_tempBox",new Z),c(this,"tempMatrix",new Q),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;ee(this.renderer),this.renderer.render=function(t,o){e.renderer.getRenderTarget()==null&&(r=0,e._frame+=1);const n=e._frame,s=r++;e.onBeforeRender(t,o,s,n),e._originalRender.call(this,t,o),e.onAfterRender(t,o,s,n)}}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(this.pause)return;const a=this.renderer.renderLists.get(r,0),i=a.opaque;let l=!0;if(i.length===1){const d=i[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(l=!1)}if(l){if(De||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=1e5;for(const u of i){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")){J&&(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 p=u.object;(p instanceof U||p.isMesh)&&this.updateLODs(r,e,p,d)}const h=a.transparent;for(const u of h){const p=u.object;(p instanceof U||p.isMesh)&&this.updateLODs(r,e,p,d)}}}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 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 d=t["DEBUG:LOD"];if(d!=null&&(l=d),Array.isArray(t.material))for(const h of t.material)this.loadProgressiveTextures(h,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,w.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 w.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(J&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=w.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 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&&d.fov>70){const g=this._tempBox.min,m=this._tempBox.max;let b=g.x,x=g.y,S=m.x,_=m.y;const D=2,f=1.5,M=(g.x+m.x)*.5,T=(g.y+m.y)*.5;b=(b-M)*D+M,x=(x-T)*D+T,S=(S-M)*D+M,_=(_-T)*D+T;const k=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(k,W);t.lastCentrality=(f-j)*(f-j)*(f-j)}else t.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&h.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),h.x*=d.aspect;const u=r.matrixWorldInverse,p=new Z;p.copy(l),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(u);const L=p.getSize(this._tempBox2Size),A=Math.max(L.x,L.y);if(Math.max(h.x,h.y)!=0&&A!=0&&(h.z=L.z/Math.max(L.x,L.y)*Math.max(h.x,h.y)),t.lastScreenCoverage=Math.max(h.x,h.y,h.z),t.lastScreenspaceVolume.copy(h),t.lastScreenCoverage*=t.lastCentrality,J&&E.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const m=E.corner0,b=E.corner1,x=E.corner2,S=E.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),E.debugDrawLine(m,b,255),E.debugDrawLine(m,x,255),E.debugDrawLine(b,S,255),E.debugDrawLine(x,S,255)}let y=999;if(i&&t.lastScreenCoverage>0){for(let g=0;g<i.length;g++)if(i[g].density/t.lastScreenCoverage<o){y=g;break}}y<s&&(s=y)}}return s}};let I=E;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 se=Symbol("NEEDLE_mesh_lod"),F=Symbol("NEEDLE_texture_lod");function oe(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 Oe(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 Oe{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[F]==!0)return;t[F]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&t.material){let s=function(i){var l,d,h;if(i[F]==!0)return;i[F]=!0,i.userData&&(i.userData.LOD=-1);const u=Object.keys(i);for(let p=0;p<u.length;p++){const L=u[p],A=i[L];if(A?.isTexture===!0){const y=(d=(l=A.userData)==null?void 0:l.associations)==null?void 0:d.textures,g=o.parser.json.textures[y];if((h=g.extensions)!=null&&h[P]){const m=g.extensions[P];m&&n&&w.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[se]==!0)return;t[se]=!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;w.registerMesh(s,i,t,0,a.lods.length,a)}}}function we(r,e,t,o){ee(e),re(t),t.register(s=>new w(s,r));const n=new I(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{oe(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,w as NEEDLE_progressive,oe as patchModelViewer,Le as registerPlugin,me as setDracoDecoderLocation,pe as setKTX2TranscoderLocation,we as useNeedleProgressive};
|
package/gltf-progressive.umd.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var ie=Object.defineProperty;var oe=(l,e,t)=>e in l?ie(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var
|
|
2
|
-
`,I),null)),
|
|
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 d of y.parser.json.textures){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===D.guid){L=!0;break}}O++}if(L){let d=await b.getDependency("texture",O);return r&&console.log('change "'+e.name+'" → "'+d.name+'"',c,O,d,f),e instanceof p.Texture&&(d=this.copySettings(e,d)),d&&(d.guid=D.guid),x(d)}}if(O=0,y.parser.json.meshes){let L=!1;for(const d of y.parser.json.meshes){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===D.guid){L=!0;break}}O++}if(L){const d=await b.getDependency("mesh",O),v=D;if(r&&console.log(`Loaded Mesh "${d.name}"`,c,O,d,f),d.isMesh===!0){const B=d.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<d.children.length;E++){const k=d.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 he(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[X]=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 g of Y)(h=g.onRegisteredNewMesh)==null||h.call(g,r,s)}),u(w,"lodInfos",new Map),u(w,"previouslyLoaded",new Map),u(w,"lowresCache",new Map),u(w,"_copiedTextures",new Map);class he{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 $=Q("debugprogressive"),pe=Q("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,"_frame",0);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;ee(this.renderer),this.renderer.render=function(r,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,n=e++;t.onBeforeRender(r,i,n,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,n,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var o,s;if(!this.pause&&r==0){if(pe||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const n=1e5,a=this.renderer.renderLists.get(e,r),h=a.opaque;for(const c of h){if(c.material&&(((o=c.geometry)==null?void 0:o.type)==="BoxGeometry"||((s=c.geometry)==null?void 0:s.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,n)}const g=a.transparent;for(const c of g){const f=c.object;(f instanceof p.Mesh||f.isMesh)&&this.updateLODs(e,t,f,n)}}}updateLODs(e,t,r,i){var a,h;for(const g of this.plugins)(a=g.onBeforeUpdateLOD)==null||a.call(g,this.renderer,e,t,r);let o=r.userData.LOD_state;o||(o=new ye,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 g=r["DEBUG:LOD"];if(g!=null&&(n=g),Array.isArray(r.material))for(const c of r.material)this.loadProgressiveTextures(c,n);else this.loadProgressiveTextures(r.material,n)}for(const g of this.plugins)(h=g.onAfterUpdatedLOD)==null||h.call(g,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 g=t.geometry.boundingBox;if(g&&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(g),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,d=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,d=(d-k)*v+k;const W=b<0&&L>0?0:Math.min(Math.abs(m.x),Math.abs(y.x)),se=O<0&&d>0?0:Math.min(Math.abs(m.y),Math.abs(y.y)),q=Math.max(W,se);r.lastCentrality=(B-q)*(B-q)*(B-q)}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(g),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 d=(y.z+L.z)*.5;y.z=b.z=O.z=L.z=d,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 ye{constructor(){u(this,"lastLodLevel",0);u(this,"lastScreenCoverage",0);u(this,"lastScreenspaceVolume",new p.Vector3);u(this,"lastCentrality",0)}}const j=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function re(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 Le(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 Le{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,g,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=(g=(h=D.userData)==null?void 0:h.associations)==null?void 0:g.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[j]==!0)return;t[j]=!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 me(l,e,t,r){ee(e),te(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",()=>{re(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=C;exports.LODsManager=_;exports.NEEDLE_progressive=w;exports.patchModelViewer=re;exports.registerPlugin=ge;exports.setDracoDecoderLocation=ce;exports.setKTX2TranscoderLocation=fe;exports.useNeedleProgressive=me;
|
|
1
|
+
"use strict";var ie=Object.defineProperty;var oe=(l,e,t)=>e in l?ie(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var c=(l,e,t)=>(oe(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("three"),ne=require("three/examples/jsm/loaders/GLTFLoader.js"),ae=require("three/examples/jsm/libs/meshopt_decoder.module.js"),le=require("three/examples/jsm/loaders/DRACOLoader.js"),ue=require("three/examples/jsm/loaders/KTX2Loader.js");let V="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",J="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(V+"draco_decoder.js",{method:"head"}).catch(l=>{V="./include/draco/",J="./include/ktx2/"});function ce(l){V=l}function fe(l){J=l}let F,K,U;function ee(l){F||(F=new le.DRACOLoader,F.setDecoderPath(V),F.setDecoderConfig({type:"js"})),U||(U=new ue.KTX2Loader,U.setTranscoderPath(J)),K||(K=ae.MeshoptDecoder),l?U.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function te(l){l.dracoLoader||l.setDRACOLoader(F),l.ktx2Loader||l.setKTX2Loader(U),l.meshoptDecoder||l.setMeshoptDecoder(K)}function Q(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function de(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 Y=new Array;function ge(l){Y.push(l)}const C="NEEDLE_progressive",T=Q("debugprogressive"),X=Symbol("needle-progressive-texture"),N=new Map,H=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=M.getMeshLODInformation(n),g=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,M.assignMeshLOD(o,g),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,M.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,H&&H.forEach(o=>{o.name!="BackgroundCubeMaterial"&&"wireframe"in o&&(o.wireframe=r)}))})}function Z(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){c(this,"parser");c(this,"url");T&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return C}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static hasLODLevelAvailable(e,t){var o;if(e.isMaterial===!0){for(const s of Object.keys(e)){const n=e[s];if(n.isTexture&&this.hasLODLevelAvailable(n,t))return!0}return!1}else if(e.isGroup===!0){for(const s of e.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,t))return!0}let r,i;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const s=r.userData.LODS;if(i=this.lodInfos.get(s.key),t===void 0)return i!=null;if(i)return Array.isArray(i.lods)?t<i.lods.length:t===0}return!1}static assignMeshLOD(e,t){var r;if(!e)return Promise.resolve(null);if(e instanceof h.Mesh||e.isMesh===!0){const i=e.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of Y)(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&&Z(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&&H.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 g=this.assignTextureLODForSlot(a,t,r,n);i.push(g),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 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&&Z(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,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[X]&&(s=f.source[X])}if(s||(s=S.lodInfos.get(o)),s){if(t>0){let u=!1;const p=Array.isArray(s.lods);if(p&&t>=s.lods.length?u=!0:p||(u=!0),u)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 y=de(i.url,f);if(y.endsWith(".glb")||y.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const u=y+"_"+s.guid,p=this.previouslyLoaded.get(u);if(p!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${u}`);let O=await p.catch(I=>(console.error(`Error loading LOD ${t} from ${y}
|
|
2
|
+
`,I),null)),k=!1;if(O==null||(O instanceof h.Texture&&e instanceof h.Texture?(n=O.image)!=null&&n.data||(a=O.source)!=null&&a.data?O=this.copySettings(e,O):(k=!0,this.previouslyLoaded.delete(u)):O instanceof h.BufferGeometry&&e instanceof h.BufferGeometry&&((g=O.attributes.position)!=null&&g.array||(k=!0,this.previouslyLoaded.delete(u)))),!k)return O}const x=s,P=new Promise(async(O,k)=>{const I=new ne.GLTFLoader;te(I),T&&(await new Promise(m=>setTimeout(m,1e3)),r&&console.warn("Start loading (delayed) "+y,x.guid));let D=y;if(x&&Array.isArray(x.lods)){const m=x.lods[t];m.hash&&(D+="?v="+m.hash)}const L=await I.loadAsync(D).catch(m=>(console.error(`Error loading LOD ${t} from ${y}
|
|
3
|
+
`,m),null));if(!L)return null;const b=L.parser;r&&console.log("Loading finished "+y,x.guid);let w=0;if(L.parser.json.textures){let m=!1;for(const d of L.parser.json.textures){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===x.guid){m=!0;break}}w++}if(m){let d=await b.getDependency("texture",w);return r&&console.log('change "'+e.name+'" → "'+d.name+'"',y,w,d,u),e instanceof h.Texture&&(d=this.copySettings(e,d)),d&&(d.guid=x.guid),O(d)}}if(w=0,L.parser.json.meshes){let m=!1;for(const d of L.parser.json.meshes){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===x.guid){m=!0;break}}w++}if(m){const d=await b.getDependency("mesh",w),v=x;if(r&&console.log(`Loaded Mesh "${d.name}"`,y,w,d,u),d.isMesh===!0){const B=d.geometry;return S.assignLODInformation(i.url,B,o,t,void 0,v.density),O(B)}else{const B=new Array;for(let E=0;E<d.children.length;E++){const R=d.children[E];if(R instanceof h.Mesh){const W=R.geometry;S.assignLODInformation(i.url,W,o,t,E,v.density),B.push(W)}}return O(B)}}}return O(null)});return this.previouslyLoaded.set(u,P),await P}else if(e instanceof h.Texture){r&&console.log("Load texture from uri: "+y);const p=await new h.TextureLoader().loadAsync(y);return p?(p.guid=s.guid,p.flipY=!1,p.needsUpdate=!0,p.colorSpace=e.colorSpace,r&&console.log(s,p)):T&&console.warn("failed loading",y),p}}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 he(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 M=S;c(M,"registerTexture",(e,t,r,i)=>{T&&console.log("> Progressive: register texture",r,t.name,t.uuid,t,i),t.source&&(t.source[X]=i);const o=i.guid;S.assignLODInformation(e,t,o,0,0,void 0),S.lodInfos.set(o,i),S.lowresCache.set(o,t)}),c(M,"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 Y)(g=f.onRegisteredNewMesh)==null||g.call(f,r,s)}),c(M,"lodInfos",new Map),c(M,"previouslyLoaded",new Map),c(M,"lowresCache",new Map),c(M,"_copiedTextures",new Map);class he{constructor(e,t,r,i,o){c(this,"url");c(this,"key");c(this,"level");c(this,"index");c(this,"density");this.url=e,this.key=t,this.level=r,i!=null&&(this.index=i),o!=null&&(this.density=o)}}const $=Q("debugprogressive"),pe=Q("noprogressive"),A=class{constructor(e){c(this,"renderer");c(this,"projectionScreenMatrix",new h.Matrix4);c(this,"cameraFrustrum",new h.Frustum);c(this,"updateInterval",0);c(this,"pause",!1);c(this,"plugins",[]);c(this,"_frame",0);c(this,"_originalRender");c(this,"_sphere",new h.Sphere);c(this,"_tempBox",new h.Box3);c(this,"tempMatrix",new h.Matrix4);c(this,"_tempWorldPosition",new h.Vector3);c(this,"_tempBoxSize",new h.Vector3);c(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;ee(this.renderer),this.renderer.render=function(r,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,n=e++;t.onBeforeRender(r,i,n,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,n,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var a,g;if(this.pause)return;const o=this.renderer.renderLists.get(e,0),s=o.opaque;let n=!0;if(s.length===1){const f=s[0].material;(f.name==="EffectMaterial"||f.name==="CopyShader")&&(n=!1)}if(n){if(pe||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const f=1e5;for(const u of s){if(u.material&&(((a=u.geometry)==null?void 0:a.type)==="BoxGeometry"||((g=u.geometry)==null?void 0:g.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){$&&(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 p=u.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}const y=o.transparent;for(const u of y){const p=u.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}}}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 ye,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 y of r.material)this.loadProgressiveTextures(y,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,M.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 M.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=M.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 y=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 D=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(D))return 0}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(t.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&y.fov>70){const D=this._tempBox.min,L=this._tempBox.max;let b=D.x,w=D.y,m=L.x,d=L.y;const v=2,B=1.5,E=(D.x+L.x)*.5,R=(D.y+L.y)*.5;b=(b-E)*v+E,w=(w-R)*v+R,m=(m-E)*v+E,d=(d-R)*v+R;const W=b<0&&m>0?0:Math.min(Math.abs(D.x),Math.abs(L.x)),se=w<0&&d>0?0:Math.min(Math.abs(D.y),Math.abs(L.y)),q=Math.max(W,se);r.lastCentrality=(B-q)*(B-q)*(B-q)}else r.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*=y.aspect;const p=e.matrixWorldInverse,x=new h.Box3;x.copy(f),x.applyMatrix4(t.matrixWorld),x.applyMatrix4(p);const P=x.getSize(this._tempBox2Size),G=Math.max(P.x,P.y);if(Math.max(u.x,u.y)!=0&&G!=0&&(u.z=P.z/Math.max(P.x,P.y)*Math.max(u.x,u.y)),r.lastScreenCoverage=Math.max(u.x,u.y,u.z),r.lastScreenspaceVolume.copy(u),r.lastScreenCoverage*=r.lastCentrality,$&&A.debugDrawLine){const D=this.tempMatrix.copy(this.projectionScreenMatrix);D.invert();const L=A.corner0,b=A.corner1,w=A.corner2,m=A.corner3;L.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=L.x,w.copy(this._tempBox.max),w.y=L.y,m.copy(this._tempBox.max);const d=(L.z+m.z)*.5;L.z=b.z=w.z=m.z=d,L.applyMatrix4(D),b.applyMatrix4(D),w.applyMatrix4(D),m.applyMatrix4(D),A.debugDrawLine(L,b,255),A.debugDrawLine(L,w,255),A.debugDrawLine(b,m,255),A.debugDrawLine(w,m,255)}let k=999;if(g&&r.lastScreenCoverage>0){for(let D=0;D<g.length;D++)if(g[D].density/r.lastScreenCoverage<i){k=D;break}}k<s&&(s=k)}}return s}};let _=A;c(_,"debugDrawLine"),c(_,"corner0",new h.Vector3),c(_,"corner1",new h.Vector3),c(_,"corner2",new h.Vector3),c(_,"corner3",new h.Vector3);class ye{constructor(){c(this,"lastLodLevel",0);c(this,"lastScreenCoverage",0);c(this,"lastScreenspaceVolume",new h.Vector3);c(this,"lastCentrality",0)}}const j=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function re(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 Le(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 Le{constructor(e){c(this,"modelviewer");c(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 g,f,y;if(n[z]==!0)return;n[z]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let u=0;u<a.length;u++){const p=a[u],x=n[p];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((y=G.extensions)!=null&&y[C]){const O=G.extensions[C];O&&i&&M.registerTexture(i,x,O.lods.length,O)}}}};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[j]==!0)return;t[j]=!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;M.registerMesh(r,n,t,0,i.lods.length,i)}}}function me(l,e,t,r){ee(e),te(t),t.register(o=>new M(o,l));const i=new _(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{re(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=C;exports.LODsManager=_;exports.NEEDLE_progressive=M;exports.patchModelViewer=re;exports.registerPlugin=ge;exports.setDracoDecoderLocation=ce;exports.setKTX2TranscoderLocation=fe;exports.useNeedleProgressive=me;
|
package/lib/lods_manager.js
CHANGED
|
@@ -70,11 +70,25 @@ export class LODsManager {
|
|
|
70
70
|
}
|
|
71
71
|
onBeforeRender(_scene, _camera, _stack, _frame) {
|
|
72
72
|
}
|
|
73
|
-
onAfterRender(scene, camera,
|
|
73
|
+
onAfterRender(scene, camera, _stack, frame) {
|
|
74
74
|
if (this.pause)
|
|
75
75
|
return;
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
const renderList = this.renderer.renderLists.get(scene, 0);
|
|
77
|
+
const opaque = renderList.opaque;
|
|
78
|
+
let updateLODs = true;
|
|
79
|
+
// check if we're rendering a postprocessing pass
|
|
80
|
+
if (opaque.length === 1) {
|
|
81
|
+
const material = opaque[0].material;
|
|
82
|
+
// pmndrs postprocessing
|
|
83
|
+
if (material.name === "EffectMaterial") {
|
|
84
|
+
updateLODs = false;
|
|
85
|
+
}
|
|
86
|
+
// builtin three postprocessing
|
|
87
|
+
else if (material.name === "CopyShader") {
|
|
88
|
+
updateLODs = false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (updateLODs) {
|
|
78
92
|
if (suppressProgressiveLoading)
|
|
79
93
|
return;
|
|
80
94
|
if (this.updateInterval > 0 && frame % this.updateInterval != 0)
|
|
@@ -92,8 +106,6 @@ export class LODsManager {
|
|
|
92
106
|
currentAllowedDensity *= 1.25;
|
|
93
107
|
}
|
|
94
108
|
*/
|
|
95
|
-
const renderList = this.renderer.renderLists.get(scene, stack);
|
|
96
|
-
const opaque = renderList.opaque;
|
|
97
109
|
for (const entry of opaque) {
|
|
98
110
|
if (entry.material && (entry.geometry?.type === "BoxGeometry" || entry.geometry?.type === "BufferGeometry")) {
|
|
99
111
|
// Ignore the skybox
|
package/package.json
CHANGED