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