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