@needle-tools/gltf-progressive 1.0.0-alpha.15 → 1.0.0-alpha.16
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 +5 -1
- package/gltf-progressive.js +181 -162
- package/gltf-progressive.min.js +3 -3
- package/gltf-progressive.umd.cjs +3 -3
- package/lib/extension.js +6 -0
- package/lib/lods_manager.d.ts +3 -0
- package/lib/lods_manager.js +30 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,11 @@ 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.
|
|
7
|
+
## [1.0.0-alpha.16] - 2023-05-29
|
|
8
|
+
- fix: LODs manager now clamps to LOD 0 if the near plane is inside the bounds
|
|
9
|
+
- change: Ignore certain material in lods update loop
|
|
10
|
+
|
|
11
|
+
## [1.0.0-alpha.15] - 2023-05-25
|
|
8
12
|
- add: `getRaycastMesh` method
|
|
9
13
|
- add: LODsManager does now expose `targetTriangleDensity`. The target triangle density is the desired max amount of triangles on screen when the mesh is filling the screen.
|
|
10
14
|
- change: create LODsManager via `LODsManager.get(renderer)`
|
package/gltf-progressive.js
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
1
|
+
var ce = Object.defineProperty;
|
|
2
|
+
var ue = (a, e, t) => e in a ? ce(a, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[e] = t;
|
|
3
|
+
var u = (a, e, t) => (ue(a, typeof e != "symbol" ? e + "" : e, t), t);
|
|
4
4
|
import { MeshoptDecoder as fe } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
5
5
|
import { DRACOLoader as de } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
6
6
|
import { KTX2Loader as ge } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
7
|
-
import { BufferGeometry as K, Mesh as X, Material as he, Texture as U, TextureLoader as pe, Matrix4 as te, Frustum as ye, Sphere as me, Box3 as re, Vector3 as
|
|
7
|
+
import { BufferGeometry as K, Mesh as X, Material as he, Texture as U, TextureLoader as pe, Matrix4 as te, Frustum as ye, Sphere as me, Box3 as re, Vector3 as k } from "three";
|
|
8
8
|
import { GLTFLoader as Le } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
9
9
|
let Y = "https://www.gstatic.com/draco/versioned/decoders/1.4.1/", j = "https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";
|
|
10
10
|
fetch(Y + "draco_decoder.js", { method: "head" }).catch((a) => {
|
|
11
11
|
Y = "./include/draco/", j = "./include/ktx2/";
|
|
12
12
|
});
|
|
13
|
-
function
|
|
13
|
+
function Ce(a) {
|
|
14
14
|
Y = a;
|
|
15
15
|
}
|
|
16
|
-
function
|
|
16
|
+
function Re(a) {
|
|
17
17
|
j = a;
|
|
18
18
|
}
|
|
19
|
-
let
|
|
19
|
+
let z, Q, W;
|
|
20
20
|
function oe(a) {
|
|
21
|
-
|
|
21
|
+
z || (z = new de(), z.setDecoderPath(Y), z.setDecoderConfig({ type: "js" })), W || (W = new ge(), W.setTranscoderPath(j)), Q || (Q = fe), a ? W.detectSupport(a) : console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail");
|
|
22
22
|
}
|
|
23
23
|
function ae(a) {
|
|
24
|
-
a.dracoLoader || a.setDRACOLoader(
|
|
24
|
+
a.dracoLoader || a.setDRACOLoader(z), a.ktx2Loader || a.setKTX2Loader(W), a.meshoptDecoder || a.setMeshoptDecoder(Q);
|
|
25
25
|
}
|
|
26
26
|
function ee(a) {
|
|
27
27
|
const t = new URL(window.location.href).searchParams.get(a);
|
|
@@ -46,17 +46,17 @@ function xe(a) {
|
|
|
46
46
|
function we(a, e) {
|
|
47
47
|
(a.type === "Mesh" || a.type === "SkinnedMesh") && (a.userData || (a.userData = {}), a.userData["needle:raycast-mesh"] = e);
|
|
48
48
|
}
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
49
|
+
const G = new Array(), E = "NEEDLE_progressive", v = ee("debugprogressive"), H = Symbol("needle-progressive-texture"), N = /* @__PURE__ */ new Map(), Z = /* @__PURE__ */ new Set();
|
|
50
|
+
if (v) {
|
|
51
51
|
let a = function() {
|
|
52
52
|
e += 1, console.log("Toggle LOD level", e, N), N.forEach((i, n) => {
|
|
53
53
|
for (const s of i.keys) {
|
|
54
54
|
const o = n[s];
|
|
55
55
|
if (o.isBufferGeometry === !0) {
|
|
56
|
-
const l =
|
|
57
|
-
n["DEBUG:LOD"] = e,
|
|
56
|
+
const l = S.getMeshLODInformation(o), g = l ? Math.min(e, l.lods.length) : 0;
|
|
57
|
+
n["DEBUG:LOD"] = e, S.assignMeshLOD(n, g), l && (t = Math.max(t, l.lods.length - 1));
|
|
58
58
|
} else if (n.isMaterial === !0) {
|
|
59
|
-
n["DEBUG:LOD"] = e,
|
|
59
|
+
n["DEBUG:LOD"] = e, S.assignTextureLOD(n, e);
|
|
60
60
|
break;
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -70,17 +70,17 @@ if (S) {
|
|
|
70
70
|
}
|
|
71
71
|
function se(a, e, t) {
|
|
72
72
|
var i;
|
|
73
|
-
if (!
|
|
73
|
+
if (!v)
|
|
74
74
|
return;
|
|
75
75
|
N.has(a) || N.set(a, { keys: [], sourceId: t });
|
|
76
76
|
const r = N.get(a);
|
|
77
77
|
((i = r == null ? void 0 : r.keys) == null ? void 0 : i.includes(e)) == !1 && r.keys.push(e);
|
|
78
78
|
}
|
|
79
|
-
const
|
|
79
|
+
const O = class {
|
|
80
80
|
constructor(e, t) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
u(this, "parser");
|
|
82
|
+
u(this, "url");
|
|
83
|
+
v && console.log("Progressive extension registered for", t), this.parser = e, this.url = t;
|
|
84
84
|
}
|
|
85
85
|
/** The name of the extension */
|
|
86
86
|
get name() {
|
|
@@ -141,20 +141,20 @@ const M = class {
|
|
|
141
141
|
const i = e.geometry, n = this.getAssignedLODInformation(i);
|
|
142
142
|
if (!n)
|
|
143
143
|
return Promise.resolve(null);
|
|
144
|
-
for (const s of
|
|
144
|
+
for (const s of G)
|
|
145
145
|
(r = s.onBeforeGetLODMesh) == null || r.call(s, e, t);
|
|
146
|
-
return e["LOD:requested level"] = t,
|
|
146
|
+
return e["LOD:requested level"] = t, O.getOrLoadLOD(i, t).then((s) => {
|
|
147
147
|
if (e["LOD:requested level"] === t) {
|
|
148
148
|
if (delete e["LOD:requested level"], Array.isArray(s)) {
|
|
149
149
|
const o = n.index || 0;
|
|
150
150
|
s = s[o];
|
|
151
151
|
}
|
|
152
|
-
s && i != s && s instanceof K && (e.geometry = s,
|
|
152
|
+
s && i != s && s instanceof K && (e.geometry = s, v && se(e, "geometry", n.url));
|
|
153
153
|
}
|
|
154
154
|
return s;
|
|
155
155
|
}).catch((s) => (console.error("Error loading mesh LOD", e, s), null));
|
|
156
156
|
} else
|
|
157
|
-
|
|
157
|
+
v && console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh", e);
|
|
158
158
|
return Promise.resolve(null);
|
|
159
159
|
}
|
|
160
160
|
/** Load a different resolution of a texture (if available)
|
|
@@ -169,7 +169,7 @@ const M = class {
|
|
|
169
169
|
return Promise.resolve(null);
|
|
170
170
|
if (e instanceof he || e.isMaterial === !0) {
|
|
171
171
|
const r = e, i = [], n = new Array();
|
|
172
|
-
if (
|
|
172
|
+
if (v && Z.add(r), r.uniforms && r.isRawShaderMaterial || r.isShaderMaterial === !0) {
|
|
173
173
|
const s = r;
|
|
174
174
|
for (const o of Object.keys(s.uniforms)) {
|
|
175
175
|
const l = s.uniforms[o].value;
|
|
@@ -202,31 +202,31 @@ const M = class {
|
|
|
202
202
|
return Promise.resolve(null);
|
|
203
203
|
}
|
|
204
204
|
static assignTextureLODForSlot(e, t, r, i) {
|
|
205
|
-
return (e == null ? void 0 : e.isTexture) !== !0 ? Promise.resolve(null) :
|
|
205
|
+
return (e == null ? void 0 : e.isTexture) !== !0 ? Promise.resolve(null) : O.getOrLoadLOD(e, t).then((n) => {
|
|
206
206
|
if (Array.isArray(n))
|
|
207
207
|
return null;
|
|
208
208
|
if ((n == null ? void 0 : n.isTexture) === !0) {
|
|
209
|
-
if (n != e && (r && i && (r[i] = n),
|
|
209
|
+
if (n != e && (r && i && (r[i] = n), v && i && r)) {
|
|
210
210
|
const s = this.getAssignedLODInformation(e);
|
|
211
211
|
s && se(r, i, s.url);
|
|
212
212
|
}
|
|
213
213
|
return n;
|
|
214
214
|
} else
|
|
215
|
-
|
|
215
|
+
v == "verbose" && console.warn("No LOD found for", e, t);
|
|
216
216
|
return null;
|
|
217
217
|
}).catch((n) => (console.error("Error loading LOD", e, n), null));
|
|
218
218
|
}
|
|
219
219
|
afterRoot(e) {
|
|
220
220
|
var t, r;
|
|
221
|
-
return
|
|
221
|
+
return v && console.log("AFTER", this.url, e), (t = this.parser.json.textures) == null || t.forEach((i, n) => {
|
|
222
222
|
if (i != null && i.extensions) {
|
|
223
223
|
const s = i == null ? void 0 : i.extensions[E];
|
|
224
224
|
if (s) {
|
|
225
225
|
let o = !1;
|
|
226
226
|
for (const l of this.parser.associations.keys())
|
|
227
|
-
l.isTexture === !0 && this.parser.associations.get(l).textures === n && (o = !0,
|
|
227
|
+
l.isTexture === !0 && this.parser.associations.get(l).textures === n && (o = !0, O.registerTexture(this.url, l, n, s));
|
|
228
228
|
o || this.parser.getDependency("texture", n).then((l) => {
|
|
229
|
-
l &&
|
|
229
|
+
l && O.registerTexture(this.url, l, n, s);
|
|
230
230
|
});
|
|
231
231
|
}
|
|
232
232
|
}
|
|
@@ -237,7 +237,7 @@ const M = class {
|
|
|
237
237
|
for (const o of this.parser.associations.keys())
|
|
238
238
|
if (o.isMesh) {
|
|
239
239
|
const l = this.parser.associations.get(o);
|
|
240
|
-
l.meshes === n &&
|
|
240
|
+
l.meshes === n && O.registerMesh(this.url, s.guid, o, s.lods.length, l.primitives, s);
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
243
|
}
|
|
@@ -245,7 +245,7 @@ const M = class {
|
|
|
245
245
|
}
|
|
246
246
|
static async getOrLoadLOD(e, t) {
|
|
247
247
|
var o, l, g;
|
|
248
|
-
const r =
|
|
248
|
+
const r = v == "verbose", i = e.userData.LODS;
|
|
249
249
|
if (!i)
|
|
250
250
|
return null;
|
|
251
251
|
const n = i == null ? void 0 : i.key;
|
|
@@ -254,49 +254,49 @@ const M = class {
|
|
|
254
254
|
const f = e;
|
|
255
255
|
f.source && f.source[H] && (s = f.source[H]);
|
|
256
256
|
}
|
|
257
|
-
if (s || (s =
|
|
257
|
+
if (s || (s = O.lodInfos.get(n)), s) {
|
|
258
258
|
if (t > 0) {
|
|
259
|
-
let
|
|
259
|
+
let c = !1;
|
|
260
260
|
const h = Array.isArray(s.lods);
|
|
261
|
-
if (h && t >= s.lods.length ?
|
|
261
|
+
if (h && t >= s.lods.length ? c = !0 : h || (c = !0), c)
|
|
262
262
|
return this.lowresCache.get(n);
|
|
263
263
|
}
|
|
264
264
|
const f = Array.isArray(s.lods) ? s.lods[t].path : s.lods;
|
|
265
265
|
if (!f)
|
|
266
|
-
return
|
|
266
|
+
return v && !s["missing:uri"] && (s["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + t, s)), null;
|
|
267
267
|
const p = De(i.url, f);
|
|
268
268
|
if (p.endsWith(".glb") || p.endsWith(".gltf")) {
|
|
269
269
|
if (!s.guid)
|
|
270
270
|
return console.warn("missing pointer for glb/gltf texture", s), null;
|
|
271
|
-
const
|
|
271
|
+
const c = p + "_" + s.guid, h = this.previouslyLoaded.get(c);
|
|
272
272
|
if (h !== void 0) {
|
|
273
|
-
r && console.log(`LOD ${t} was already loading/loaded: ${
|
|
274
|
-
let x = await h.catch((
|
|
275
|
-
`,
|
|
276
|
-
if (x == null || (x instanceof U && e instanceof U ? (o = x.image) != null && o.data || (l = x.source) != null && l.data ? x = this.copySettings(e, x) : (R = !0, this.previouslyLoaded.delete(
|
|
273
|
+
r && console.log(`LOD ${t} was already loading/loaded: ${c}`);
|
|
274
|
+
let x = await h.catch((F) => (console.error(`Error loading LOD ${t} from ${p}
|
|
275
|
+
`, F), null)), R = !1;
|
|
276
|
+
if (x == null || (x instanceof U && e instanceof U ? (o = x.image) != null && o.data || (l = x.source) != null && l.data ? x = this.copySettings(e, x) : (R = !0, this.previouslyLoaded.delete(c)) : x instanceof K && e instanceof K && ((g = x.attributes.position) != null && g.array || (R = !0, this.previouslyLoaded.delete(c)))), !R)
|
|
277
277
|
return x;
|
|
278
278
|
}
|
|
279
|
-
const
|
|
280
|
-
const
|
|
281
|
-
ae(
|
|
282
|
-
let
|
|
283
|
-
if (
|
|
284
|
-
const m =
|
|
285
|
-
m.hash && (
|
|
279
|
+
const L = s, A = new Promise(async (x, R) => {
|
|
280
|
+
const F = new Le();
|
|
281
|
+
ae(F), v && (await new Promise((m) => setTimeout(m, 1e3)), r && console.warn("Start loading (delayed) " + p, L.guid));
|
|
282
|
+
let D = p;
|
|
283
|
+
if (L && Array.isArray(L.lods)) {
|
|
284
|
+
const m = L.lods[t];
|
|
285
|
+
m.hash && (D += "?v=" + m.hash);
|
|
286
286
|
}
|
|
287
|
-
const y = await
|
|
287
|
+
const y = await F.loadAsync(D).catch((m) => (console.error(`Error loading LOD ${t} from ${p}
|
|
288
288
|
`, m), null));
|
|
289
289
|
if (!y)
|
|
290
290
|
return null;
|
|
291
291
|
const T = y.parser;
|
|
292
|
-
r && console.log("Loading finished " + p,
|
|
292
|
+
r && console.log("Loading finished " + p, L.guid);
|
|
293
293
|
let w = 0;
|
|
294
294
|
if (y.parser.json.textures) {
|
|
295
295
|
let m = !1;
|
|
296
296
|
for (const d of y.parser.json.textures) {
|
|
297
297
|
if (d != null && d.extensions) {
|
|
298
|
-
const
|
|
299
|
-
if (
|
|
298
|
+
const M = d == null ? void 0 : d.extensions[E];
|
|
299
|
+
if (M != null && M.guid && M.guid === L.guid) {
|
|
300
300
|
m = !0;
|
|
301
301
|
break;
|
|
302
302
|
}
|
|
@@ -305,15 +305,16 @@ const M = class {
|
|
|
305
305
|
}
|
|
306
306
|
if (m) {
|
|
307
307
|
let d = await T.getDependency("texture", w);
|
|
308
|
-
return r && console.log('change "' + e.name + '" → "' + d.name + '"', p, w, d,
|
|
309
|
-
}
|
|
308
|
+
return d && O.assignLODInformation(i.url, d, n, t, void 0, void 0), r && console.log('change "' + e.name + '" → "' + d.name + '"', p, w, d, c), e instanceof U && (d = this.copySettings(e, d)), d && (d.guid = L.guid), x(d);
|
|
309
|
+
} else
|
|
310
|
+
v && console.warn("Could not find texture with guid", L.guid);
|
|
310
311
|
}
|
|
311
312
|
if (w = 0, y.parser.json.meshes) {
|
|
312
313
|
let m = !1;
|
|
313
314
|
for (const d of y.parser.json.meshes) {
|
|
314
315
|
if (d != null && d.extensions) {
|
|
315
|
-
const
|
|
316
|
-
if (
|
|
316
|
+
const M = d == null ? void 0 : d.extensions[E];
|
|
317
|
+
if (M != null && M.guid && M.guid === L.guid) {
|
|
317
318
|
m = !0;
|
|
318
319
|
break;
|
|
319
320
|
}
|
|
@@ -321,17 +322,17 @@ const M = class {
|
|
|
321
322
|
w++;
|
|
322
323
|
}
|
|
323
324
|
if (m) {
|
|
324
|
-
const d = await T.getDependency("mesh", w),
|
|
325
|
-
if (r && console.log(`Loaded Mesh "${d.name}"`, p, w, d,
|
|
325
|
+
const d = await T.getDependency("mesh", w), M = L;
|
|
326
|
+
if (r && console.log(`Loaded Mesh "${d.name}"`, p, w, d, c), d.isMesh === !0) {
|
|
326
327
|
const _ = d.geometry;
|
|
327
|
-
return
|
|
328
|
+
return O.assignLODInformation(i.url, _, n, t, void 0, M.density), x(_);
|
|
328
329
|
} else {
|
|
329
330
|
const _ = new Array();
|
|
330
|
-
for (let
|
|
331
|
-
const
|
|
332
|
-
if (
|
|
333
|
-
const $ =
|
|
334
|
-
|
|
331
|
+
for (let B = 0; B < d.children.length; B++) {
|
|
332
|
+
const I = d.children[B];
|
|
333
|
+
if (I instanceof X) {
|
|
334
|
+
const $ = I.geometry;
|
|
335
|
+
O.assignLODInformation(i.url, $, n, t, B, M.density), _.push($);
|
|
335
336
|
}
|
|
336
337
|
}
|
|
337
338
|
return x(_);
|
|
@@ -340,14 +341,14 @@ const M = class {
|
|
|
340
341
|
}
|
|
341
342
|
return x(null);
|
|
342
343
|
});
|
|
343
|
-
return this.previouslyLoaded.set(
|
|
344
|
+
return this.previouslyLoaded.set(c, A), await A;
|
|
344
345
|
} else if (e instanceof U) {
|
|
345
346
|
r && console.log("Load texture from uri: " + p);
|
|
346
347
|
const h = await new pe().loadAsync(p);
|
|
347
|
-
return h ? (h.guid = s.guid, h.flipY = !1, h.needsUpdate = !0, h.colorSpace = e.colorSpace, r && console.log(s, h)) :
|
|
348
|
+
return h ? (h.guid = s.guid, h.flipY = !1, h.needsUpdate = !0, h.colorSpace = e.colorSpace, r && console.log(s, h)) : v && console.warn("failed loading", p), h;
|
|
348
349
|
}
|
|
349
350
|
} else
|
|
350
|
-
|
|
351
|
+
v && console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`, e.type);
|
|
351
352
|
return null;
|
|
352
353
|
}
|
|
353
354
|
static assignLODInformation(e, t, r, i, n, s) {
|
|
@@ -366,71 +367,72 @@ const M = class {
|
|
|
366
367
|
return r || (t = t.clone(), this._copiedTextures.set(e, t), t.offset = e.offset, t.repeat = e.repeat, t.colorSpace = e.colorSpace, t.magFilter = e.magFilter, t.minFilter = e.minFilter, t.wrapS = e.wrapS, t.wrapT = e.wrapT, t.flipY = e.flipY, t.anisotropy = e.anisotropy, t.generateMipmaps = e.generateMipmaps, t);
|
|
367
368
|
}
|
|
368
369
|
};
|
|
369
|
-
let
|
|
370
|
+
let S = O;
|
|
370
371
|
/**
|
|
371
372
|
* Register a texture with LOD information
|
|
372
373
|
*/
|
|
373
|
-
|
|
374
|
-
|
|
374
|
+
u(S, "registerTexture", (e, t, r, i) => {
|
|
375
|
+
v && console.log("> Progressive: register texture", r, t.name, t.uuid, t, i), t.source && (t.source[H] = i);
|
|
375
376
|
const n = i.guid;
|
|
376
|
-
|
|
377
|
+
O.assignLODInformation(e, t, n, 0, 0, void 0), O.lodInfos.set(n, i), O.lowresCache.set(n, t);
|
|
377
378
|
}), /**
|
|
378
379
|
* Register a mesh with LOD information
|
|
379
380
|
*/
|
|
380
|
-
|
|
381
|
+
u(S, "registerMesh", (e, t, r, i, n, s) => {
|
|
381
382
|
var g;
|
|
382
|
-
|
|
383
|
+
v && console.log("> Progressive: register mesh", n, r.name, s, r.uuid, r);
|
|
383
384
|
const o = r.geometry;
|
|
384
|
-
o.userData || (o.userData = {}),
|
|
385
|
-
let l =
|
|
386
|
-
l ? l.push(r.geometry) : l = [r.geometry],
|
|
387
|
-
for (const f of
|
|
385
|
+
o.userData || (o.userData = {}), O.assignLODInformation(e, o, t, i, n, s.density), O.lodInfos.set(t, s);
|
|
386
|
+
let l = O.lowresCache.get(t);
|
|
387
|
+
l ? l.push(r.geometry) : l = [r.geometry], O.lowresCache.set(t, l), i > 0 && !xe(r) && we(r, o);
|
|
388
|
+
for (const f of G)
|
|
388
389
|
(g = f.onRegisteredNewMesh) == null || g.call(f, r, s);
|
|
389
390
|
}), /** A map of key = asset uuid and value = LOD information */
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
391
|
+
u(S, "lodInfos", /* @__PURE__ */ new Map()), /** cache of already loaded mesh lods */
|
|
392
|
+
u(S, "previouslyLoaded", /* @__PURE__ */ new Map()), /** this contains the geometry/textures that were originally loaded */
|
|
393
|
+
u(S, "lowresCache", /* @__PURE__ */ new Map()), u(S, "_copiedTextures", /* @__PURE__ */ new Map());
|
|
393
394
|
class Oe {
|
|
394
395
|
constructor(e, t, r, i, n) {
|
|
395
|
-
|
|
396
|
+
u(this, "url");
|
|
396
397
|
/** the key to lookup the LOD information */
|
|
397
|
-
|
|
398
|
-
|
|
398
|
+
u(this, "key");
|
|
399
|
+
u(this, "level");
|
|
399
400
|
/** For multi objects (e.g. a group of meshes) this is the index of the object */
|
|
400
|
-
|
|
401
|
+
u(this, "index");
|
|
401
402
|
/** the mesh density */
|
|
402
|
-
|
|
403
|
+
u(this, "density");
|
|
403
404
|
this.url = e, this.key = t, this.level = r, i != null && (this.index = i), n != null && (this.density = n);
|
|
404
405
|
}
|
|
405
406
|
}
|
|
406
|
-
const J = ee("debugprogressive"), Me = ee("noprogressive"), ie = Symbol("Needle:LODSManager"),
|
|
407
|
+
const J = ee("debugprogressive"), Me = ee("noprogressive"), ie = Symbol("Needle:LODSManager"), P = class {
|
|
407
408
|
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
408
409
|
constructor(e) {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
410
|
+
u(this, "renderer");
|
|
411
|
+
u(this, "projectionScreenMatrix", new te());
|
|
412
|
+
u(this, "cameraFrustrum", new ye());
|
|
412
413
|
/**
|
|
413
414
|
* The target triangle density is the desired max amount of triangles on screen when the mesh is filling the screen.
|
|
414
415
|
* @default 200_000
|
|
415
416
|
*/
|
|
416
|
-
|
|
417
|
+
u(this, "targetTriangleDensity", 2e5);
|
|
417
418
|
/**
|
|
418
419
|
* 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.
|
|
419
420
|
*/
|
|
420
|
-
|
|
421
|
+
u(this, "updateInterval", 0);
|
|
421
422
|
/**
|
|
422
423
|
* If set to true, the LODsManager will not update the LODs.
|
|
423
424
|
*/
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
425
|
+
u(this, "pause", !1);
|
|
426
|
+
u(this, "_frame", 0);
|
|
427
|
+
u(this, "_originalRender");
|
|
427
428
|
// private testIfLODLevelsAreAvailable() {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
429
|
+
u(this, "_sphere", new me());
|
|
430
|
+
u(this, "_tempBox", new re());
|
|
431
|
+
u(this, "_tempBox2", new re());
|
|
432
|
+
u(this, "tempMatrix", new te());
|
|
433
|
+
u(this, "_tempWorldPosition", new k());
|
|
434
|
+
u(this, "_tempBoxSize", new k());
|
|
435
|
+
u(this, "_tempBox2Size", new k());
|
|
434
436
|
this.renderer = e;
|
|
435
437
|
}
|
|
436
438
|
/** @internal */
|
|
@@ -439,11 +441,11 @@ const J = ee("debugprogressive"), Me = ee("noprogressive"), ie = Symbol("Needle:
|
|
|
439
441
|
return (t = e.userData) == null ? void 0 : t.LOD_state;
|
|
440
442
|
}
|
|
441
443
|
static addPlugin(e) {
|
|
442
|
-
|
|
444
|
+
G.push(e);
|
|
443
445
|
}
|
|
444
446
|
static removePlugin(e) {
|
|
445
|
-
const t =
|
|
446
|
-
t >= 0 &&
|
|
447
|
+
const t = G.indexOf(e);
|
|
448
|
+
t >= 0 && G.splice(t, 1);
|
|
447
449
|
}
|
|
448
450
|
/**
|
|
449
451
|
* Gets the LODsManager for the given renderer. If the LODsManager does not exist yet, it will be created.
|
|
@@ -451,7 +453,7 @@ const J = ee("debugprogressive"), Me = ee("noprogressive"), ie = Symbol("Needle:
|
|
|
451
453
|
* @returns The LODsManager instance.
|
|
452
454
|
*/
|
|
453
455
|
static get(e) {
|
|
454
|
-
return e[ie] ? e[ie] : new
|
|
456
|
+
return e[ie] ? e[ie] : new P(e);
|
|
455
457
|
}
|
|
456
458
|
/**
|
|
457
459
|
* Enable the LODsManager. This will replace the render method of the renderer with a method that updates the LODs.
|
|
@@ -488,17 +490,26 @@ const J = ee("debugprogressive"), Me = ee("noprogressive"), ie = Symbol("Needle:
|
|
|
488
490
|
return;
|
|
489
491
|
this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix, t.matrixWorldInverse), this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix, this.renderer.coordinateSystem);
|
|
490
492
|
const f = this.targetTriangleDensity;
|
|
491
|
-
for (const
|
|
492
|
-
if (
|
|
493
|
-
J && (
|
|
493
|
+
for (const c of s) {
|
|
494
|
+
if (c.material && (((l = c.geometry) == null ? void 0 : l.type) === "BoxGeometry" || ((g = c.geometry) == null ? void 0 : g.type) === "BufferGeometry") && (c.material.name === "SphericalGaussianBlur" || c.material.name == "BackgroundCubeMaterial" || c.material.name === "CubemapFromEquirect" || c.material.name === "EquirectangularToCubeUV")) {
|
|
495
|
+
J && (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)));
|
|
494
496
|
continue;
|
|
495
497
|
}
|
|
496
|
-
|
|
498
|
+
switch (c.material.type) {
|
|
499
|
+
case "LineBasicMaterial":
|
|
500
|
+
case "LineDashedMaterial":
|
|
501
|
+
case "PointsMaterial":
|
|
502
|
+
case "ShadowMaterial":
|
|
503
|
+
case "MeshDistanceMaterial":
|
|
504
|
+
case "MeshDepthMaterial":
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
const h = c.object;
|
|
497
508
|
(h instanceof X || h.isMesh) && this.updateLODs(e, t, h, f);
|
|
498
509
|
}
|
|
499
510
|
const p = n.transparent;
|
|
500
|
-
for (const
|
|
501
|
-
const h =
|
|
511
|
+
for (const c of p) {
|
|
512
|
+
const h = c.object;
|
|
502
513
|
(h instanceof X || h.isMesh) && this.updateLODs(e, t, h, f);
|
|
503
514
|
}
|
|
504
515
|
}
|
|
@@ -506,7 +517,7 @@ const J = ee("debugprogressive"), Me = ee("noprogressive"), ie = Symbol("Needle:
|
|
|
506
517
|
/** Update the LOD levels for the renderer. */
|
|
507
518
|
updateLODs(e, t, r, i) {
|
|
508
519
|
var l, g;
|
|
509
|
-
for (const f of
|
|
520
|
+
for (const f of G)
|
|
510
521
|
(l = f.onBeforeUpdateLOD) == null || l.call(f, this.renderer, e, t, r);
|
|
511
522
|
let n = r.userData.LOD_state;
|
|
512
523
|
n || (n = new ve(), r.userData.LOD_state = n);
|
|
@@ -521,7 +532,7 @@ const J = ee("debugprogressive"), Me = ee("noprogressive"), ie = Symbol("Needle:
|
|
|
521
532
|
else
|
|
522
533
|
this.loadProgressiveTextures(r.material, o);
|
|
523
534
|
}
|
|
524
|
-
for (const f of
|
|
535
|
+
for (const f of G)
|
|
525
536
|
(g = f.onAfterUpdatedLOD) == null || g.call(f, this.renderer, e, t, r, s);
|
|
526
537
|
n.lastLodLevel = s;
|
|
527
538
|
}
|
|
@@ -531,7 +542,7 @@ const J = ee("debugprogressive"), Me = ee("noprogressive"), ie = Symbol("Needle:
|
|
|
531
542
|
* @returns Promise with true if the LOD was loaded, false if not
|
|
532
543
|
*/
|
|
533
544
|
loadProgressiveTextures(e, t) {
|
|
534
|
-
return e && e.userData && e.userData.LOD !== t ? (e.userData.LOD = t,
|
|
545
|
+
return e && e.userData && e.userData.LOD !== t ? (e.userData.LOD = t, S.assignTextureLOD(e, t)) : Promise.resolve(null);
|
|
535
546
|
}
|
|
536
547
|
/** Load progressive meshes for the given mesh
|
|
537
548
|
* @param mesh the mesh to load the LOD for
|
|
@@ -545,10 +556,14 @@ const J = ee("debugprogressive"), Me = ee("noprogressive"), ie = Symbol("Needle:
|
|
|
545
556
|
if (e.userData || (e.userData = {}), e.userData.LOD !== t) {
|
|
546
557
|
e.userData.LOD = t;
|
|
547
558
|
const r = e.geometry;
|
|
548
|
-
return
|
|
559
|
+
return S.assignMeshLOD(e, t).then((i) => (i && e.userData.LOD == t && r != e.geometry, i));
|
|
549
560
|
}
|
|
550
561
|
return Promise.resolve(null);
|
|
551
562
|
}
|
|
563
|
+
static isInside(e, t) {
|
|
564
|
+
const r = e.min, i = e.max, n = (r.x + i.x) * 0.5, s = (r.y + i.y) * 0.5;
|
|
565
|
+
return this._tempPtInside.set(n, s, r.z).applyMatrix4(t).z < 0;
|
|
566
|
+
}
|
|
552
567
|
calculateLodLevel(e, t, r, i) {
|
|
553
568
|
var o;
|
|
554
569
|
if (!t)
|
|
@@ -557,45 +572,49 @@ const J = ee("debugprogressive"), Me = ee("noprogressive"), ie = Symbol("Needle:
|
|
|
557
572
|
if (e) {
|
|
558
573
|
if (J && t["DEBUG:LOD"] != null)
|
|
559
574
|
return t["DEBUG:LOD"];
|
|
560
|
-
const l =
|
|
561
|
-
if (!g || g.length <= 0
|
|
575
|
+
const l = S.getMeshLODInformation(t.geometry), g = l == null ? void 0 : l.lods;
|
|
576
|
+
if (!g || g.length <= 0)
|
|
577
|
+
return 0;
|
|
578
|
+
if (!((o = this.cameraFrustrum) != null && o.intersectsObject(t)))
|
|
562
579
|
return 99;
|
|
563
580
|
const f = t.geometry.boundingBox;
|
|
564
581
|
if (f && e.isPerspectiveCamera) {
|
|
565
582
|
const p = e;
|
|
566
583
|
if (t.geometry.attributes.color && t.geometry.attributes.color.count < 100 && t.geometry.boundingSphere) {
|
|
567
584
|
this._sphere.copy(t.geometry.boundingSphere), this._sphere.applyMatrix4(t.matrixWorld);
|
|
568
|
-
const
|
|
569
|
-
if (this._sphere.containsPoint(
|
|
585
|
+
const D = e.getWorldPosition(this._tempWorldPosition);
|
|
586
|
+
if (this._sphere.containsPoint(D))
|
|
570
587
|
return 0;
|
|
571
588
|
}
|
|
572
|
-
if (this._tempBox.copy(f), this._tempBox.applyMatrix4(t.matrixWorld),
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
const
|
|
576
|
-
T =
|
|
577
|
-
const
|
|
589
|
+
if (this._tempBox.copy(f), this._tempBox.applyMatrix4(t.matrixWorld), P.isInside(this._tempBox, this.projectionScreenMatrix))
|
|
590
|
+
return 0;
|
|
591
|
+
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && p.fov > 70) {
|
|
592
|
+
const D = this._tempBox.min, y = this._tempBox.max;
|
|
593
|
+
let T = D.x, w = D.y, m = y.x, d = y.y;
|
|
594
|
+
const M = 2, _ = 1.5, B = (D.x + y.x) * 0.5, I = (D.y + y.y) * 0.5;
|
|
595
|
+
T = (T - B) * M + B, w = (w - I) * M + I, m = (m - B) * M + B, d = (d - I) * M + I;
|
|
596
|
+
const $ = T < 0 && m > 0 ? 0 : Math.min(Math.abs(D.x), Math.abs(y.x)), le = w < 0 && d > 0 ? 0 : Math.min(Math.abs(D.y), Math.abs(y.y)), V = Math.max($, le);
|
|
578
597
|
r.lastCentrality = (_ - V) * (_ - V) * (_ - V);
|
|
579
598
|
} else
|
|
580
599
|
r.lastCentrality = 1;
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
const h = e.matrixWorldInverse,
|
|
584
|
-
|
|
585
|
-
const A =
|
|
586
|
-
if (Math.max(
|
|
587
|
-
const
|
|
588
|
-
|
|
589
|
-
const y =
|
|
600
|
+
const c = this._tempBox.getSize(this._tempBoxSize);
|
|
601
|
+
c.multiplyScalar(0.5), screen.availHeight > 0 && c.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), c.x *= p.aspect;
|
|
602
|
+
const h = e.matrixWorldInverse, L = this._tempBox2;
|
|
603
|
+
L.copy(f), L.applyMatrix4(t.matrixWorld), L.applyMatrix4(h);
|
|
604
|
+
const A = L.getSize(this._tempBox2Size), C = Math.max(A.x, A.y);
|
|
605
|
+
if (Math.max(c.x, c.y) != 0 && C != 0 && (c.z = A.z / Math.max(A.x, A.y) * Math.max(c.x, c.y)), r.lastScreenCoverage = Math.max(c.x, c.y, c.z), r.lastScreenspaceVolume.copy(c), r.lastScreenCoverage *= r.lastCentrality, J && P.debugDrawLine) {
|
|
606
|
+
const D = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
607
|
+
D.invert();
|
|
608
|
+
const y = P.corner0, T = P.corner1, w = P.corner2, m = P.corner3;
|
|
590
609
|
y.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = y.x, w.copy(this._tempBox.max), w.y = y.y, m.copy(this._tempBox.max);
|
|
591
610
|
const d = (y.z + m.z) * 0.5;
|
|
592
|
-
y.z = T.z = w.z = m.z = d, y.applyMatrix4(
|
|
611
|
+
y.z = T.z = w.z = m.z = d, y.applyMatrix4(D), T.applyMatrix4(D), w.applyMatrix4(D), m.applyMatrix4(D), P.debugDrawLine(y, T, 255), P.debugDrawLine(y, w, 255), P.debugDrawLine(T, m, 255), P.debugDrawLine(w, m, 255);
|
|
593
612
|
}
|
|
594
613
|
let R = 999;
|
|
595
614
|
if (g && r.lastScreenCoverage > 0) {
|
|
596
|
-
for (let
|
|
597
|
-
if (g[
|
|
598
|
-
R =
|
|
615
|
+
for (let D = 0; D < g.length; D++)
|
|
616
|
+
if (g[D].density / r.lastScreenCoverage < i) {
|
|
617
|
+
R = D;
|
|
599
618
|
break;
|
|
600
619
|
}
|
|
601
620
|
}
|
|
@@ -605,16 +624,16 @@ const J = ee("debugprogressive"), Me = ee("noprogressive"), ie = Symbol("Needle:
|
|
|
605
624
|
return s;
|
|
606
625
|
}
|
|
607
626
|
};
|
|
608
|
-
let
|
|
627
|
+
let b = P;
|
|
609
628
|
/** 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.
|
|
610
629
|
*/
|
|
611
|
-
|
|
630
|
+
u(b, "debugDrawLine"), u(b, "corner0", new k()), u(b, "corner1", new k()), u(b, "corner2", new k()), u(b, "corner3", new k()), u(b, "_tempPtInside", new k());
|
|
612
631
|
class ve {
|
|
613
632
|
constructor() {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
633
|
+
u(this, "lastLodLevel", 0);
|
|
634
|
+
u(this, "lastScreenCoverage", 0);
|
|
635
|
+
u(this, "lastScreenspaceVolume", new k());
|
|
636
|
+
u(this, "lastCentrality", 0);
|
|
618
637
|
}
|
|
619
638
|
}
|
|
620
639
|
const ne = Symbol("NEEDLE_mesh_lod"), q = Symbol("NEEDLE_texture_lod");
|
|
@@ -628,8 +647,8 @@ function Se(a) {
|
|
|
628
647
|
}
|
|
629
648
|
if (e) {
|
|
630
649
|
console.log("Adding Needle LODs to modelviewer");
|
|
631
|
-
const r =
|
|
632
|
-
if (
|
|
650
|
+
const r = b.get(e);
|
|
651
|
+
if (b.addPlugin(new Te(a)), r.enable(), t) {
|
|
633
652
|
const i = t.camera || t.traverse((n) => n.type == "PerspectiveCamera")[0];
|
|
634
653
|
i && e.render(t, i);
|
|
635
654
|
}
|
|
@@ -641,8 +660,8 @@ function Se(a) {
|
|
|
641
660
|
}
|
|
642
661
|
class Te {
|
|
643
662
|
constructor(e) {
|
|
644
|
-
|
|
645
|
-
|
|
663
|
+
u(this, "modelviewer");
|
|
664
|
+
u(this, "_didWarnAboutMissingUrl", !1);
|
|
646
665
|
this.modelviewer = e;
|
|
647
666
|
}
|
|
648
667
|
onBeforeUpdateLOD(e, t, r, i) {
|
|
@@ -667,17 +686,17 @@ class Te {
|
|
|
667
686
|
return;
|
|
668
687
|
o[q] = !0, o.userData && (o.userData.LOD = -1);
|
|
669
688
|
const l = Object.keys(o);
|
|
670
|
-
for (let
|
|
671
|
-
const h = l[
|
|
672
|
-
if ((
|
|
673
|
-
const A = (f = (g =
|
|
674
|
-
if (!
|
|
689
|
+
for (let c = 0; c < l.length; c++) {
|
|
690
|
+
const h = l[c], L = o[h];
|
|
691
|
+
if ((L == null ? void 0 : L.isTexture) === !0) {
|
|
692
|
+
const A = (f = (g = L.userData) == null ? void 0 : g.associations) == null ? void 0 : f.textures, C = r.parser.json.textures[A];
|
|
693
|
+
if (!C) {
|
|
675
694
|
console.warn("Texture data not found for texture index " + A);
|
|
676
695
|
continue;
|
|
677
696
|
}
|
|
678
|
-
if ((p =
|
|
679
|
-
const x =
|
|
680
|
-
x && i &&
|
|
697
|
+
if ((p = C == null ? void 0 : C.extensions) != null && p[E]) {
|
|
698
|
+
const x = C.extensions[E];
|
|
699
|
+
x && i && S.registerTexture(i, L, x.lods.length, x);
|
|
681
700
|
}
|
|
682
701
|
}
|
|
683
702
|
}
|
|
@@ -701,13 +720,13 @@ class Te {
|
|
|
701
720
|
const i = (s = (n = t.userData) == null ? void 0 : n.gltfExtensions) == null ? void 0 : s[E];
|
|
702
721
|
if (i && r) {
|
|
703
722
|
const o = t.uuid;
|
|
704
|
-
|
|
723
|
+
S.registerMesh(r, o, t, 0, i.lods.length, i);
|
|
705
724
|
}
|
|
706
725
|
}
|
|
707
726
|
}
|
|
708
727
|
function Ee(a, e, t, r) {
|
|
709
|
-
oe(e), ae(t), t.register((n) => new
|
|
710
|
-
const i =
|
|
728
|
+
oe(e), ae(t), t.register((n) => new S(n, a));
|
|
729
|
+
const i = b.get(e);
|
|
711
730
|
return (r == null ? void 0 : r.enableLODsManager) !== !1 && i.enable(), i;
|
|
712
731
|
}
|
|
713
732
|
document.addEventListener("DOMContentLoaded", () => {
|
|
@@ -715,14 +734,14 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
715
734
|
});
|
|
716
735
|
export {
|
|
717
736
|
E as EXTENSION_NAME,
|
|
718
|
-
|
|
719
|
-
|
|
737
|
+
b as LODsManager,
|
|
738
|
+
S as NEEDLE_progressive,
|
|
720
739
|
ae as addDracoAndKTX2Loaders,
|
|
721
740
|
oe as createLoaders,
|
|
722
741
|
xe as getRaycastMesh,
|
|
723
742
|
Se as patchModelViewer,
|
|
724
|
-
|
|
725
|
-
|
|
743
|
+
Ce as setDracoDecoderLocation,
|
|
744
|
+
Re as setKTX2TranscoderLocation,
|
|
726
745
|
we as setRaycastMesh,
|
|
727
746
|
Ee as useNeedleProgressive
|
|
728
747
|
};
|
package/gltf-progressive.min.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var le=Object.defineProperty,ue=(
|
|
2
|
-
`,m),null)),
|
|
3
|
-
`,L),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+h,D.guid);let T=0;if(x.parser.json.textures){let L=!1;for(const g of x.parser.json.textures){if(g!=null&&g.extensions){const M=g?.extensions[P];if(M!=null&&M.guid&&M.guid===D.guid){L=!0;break}}T++}if(L){let g=await S.getDependency("texture",T);return s&&console.log('change "'+r.name+'" \u2192 "'+g.name+'"',h,T,g,u),r instanceof C&&(g=this.copySettings(r,g)),g&&(g.guid=D.guid),y(g)}}if(T=0,x.parser.json.meshes){let L=!1;for(const g of x.parser.json.meshes){if(g!=null&&g.extensions){const M=g?.extensions[P];if(M!=null&&M.guid&&M.guid===D.guid){L=!0;break}}T++}if(L){const g=await S.getDependency("mesh",T),M=D;if(s&&console.log(`Loaded Mesh "${g.name}"`,h,T,g,u),g.isMesh===!0){const E=g.geometry;return O.assignLODInformation(a.url,E,i,e,void 0,M.density),y(E)}else{const E=new Array;for(let k=0;k<g.children.length;k++){const W=g.children[k];if(W instanceof z){const j=W.geometry;O.assignLODInformation(a.url,j,i,e,k,M.density),E.push(j)}}return y(E)}}}return y(null)});return this.previouslyLoaded.set(u,A),await A}else if(r instanceof C){s&&console.log("Load texture from uri: "+h);const u=await new ge().loadAsync(h);return u?(u.guid=l.guid,u.flipY=!1,u.needsUpdate=!0,u.colorSpace=r.colorSpace,s&&console.log(l,u)):v&&console.warn("failed loading",h),u}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,o,n,s){if(!e)return;e.userData||(e.userData={});const a=new ve(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.magFilter=r.magFilter,e.minFilter=r.minFilter,e.wrapS=r.wrapS,e.wrapT=r.wrapT,e.flipY=r.flipY,e.anisotropy=r.anisotropy,e.generateMipmaps=r.generateMipmaps,e)}};let w=O;c(w,"registerTexture",(r,e,t,o)=>{v&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,o),e.source&&(e.source[J]=o);const n=o.guid;O.assignLODInformation(r,e,n,0,0,void 0),O.lodInfos.set(n,o),O.lowresCache.set(n,e)}),c(w,"registerMesh",(r,e,t,o,n,s)=>{var a;v&&console.log("> Progressive: register mesh",n,t.name,s,t.uuid,t);const i=t.geometry;i.userData||(i.userData={}),O.assignLODInformation(r,i,e,o,n,s.density),O.lodInfos.set(e,s);let l=O.lowresCache.get(e);l?l.push(t.geometry):l=[t.geometry],O.lowresCache.set(e,l),o>0&&!te(t)&&se(t,i);for(const d of R)(a=d.onRegisteredNewMesh)==null||a.call(d,t,s)}),c(w,"lodInfos",new Map),c(w,"previouslyLoaded",new Map),c(w,"lowresCache",new Map),c(w,"_copiedTextures",new Map);class ve{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 Z=Y("debugprogressive"),Oe=Y("noprogressive"),ne=Symbol("Needle:LODSManager"),_=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new ee),c(this,"cameraFrustrum",new me),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new pe),c(this,"_tempBox",new re),c(this,"tempMatrix",new ee),c(this,"_tempWorldPosition",new I),c(this,"_tempBoxSize",new I),c(this,"_tempBox2Size",new I),this.renderer=r}static getObjectLODState(r){var e;return(e=r.userData)==null?void 0:e.LOD_state}static addPlugin(r){R.push(r)}static removePlugin(r){const e=R.indexOf(r);e>=0&&R.splice(e,1)}static get(r){return r[ne]?r[ne]:new _(r)}enable(){if(this._originalRender)return;let r=0;this._originalRender=this.renderer.render;const e=this;K(this.renderer),this.renderer.render=function(t,o){e.renderer.getRenderTarget()==null&&(r=0,e._frame+=1);const n=e._frame,s=r++;e.onBeforeRender(t,o,s,n),e._originalRender.call(this,t,o),e.onAfterRender(t,o,s,n)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(r,e,t,o){}onAfterRender(r,e,t,o){var n,s;if(this.pause)return;const a=this.renderer.renderLists.get(r,0),i=a.opaque;let l=!0;if(i.length===1){const d=i[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(l=!1)}if(l){if(Oe||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=this.targetTriangleDensity;for(const u of i){if(u.material&&(((n=u.geometry)==null?void 0:n.type)==="BoxGeometry"||((s=u.geometry)==null?void 0:s.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){Z&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}const p=u.object;(p instanceof z||p.isMesh)&&this.updateLODs(r,e,p,d)}const h=a.transparent;for(const u of h){const p=u.object;(p instanceof z||p.isMesh)&&this.updateLODs(r,e,p,d)}}}updateLODs(r,e,t,o){var n,s;for(const d of R)(n=d.onBeforeUpdateLOD)==null||n.call(d,this.renderer,r,e,t);let a=t.userData.LOD_state;a||(a=new we,t.userData.LOD_state=a);let i=this.calculateLodLevel(e,t,a,o);i=Math.round(i),i>=0&&this.loadProgressiveMeshes(t,i);let l=0;if(t.material){const d=t["DEBUG:LOD"];if(d!=null&&(l=d),Array.isArray(t.material))for(const h of t.material)this.loadProgressiveTextures(h,l);else this.loadProgressiveTextures(t.material,l)}for(const d of R)(s=d.onAfterUpdatedLOD)==null||s.call(d,this.renderer,r,e,t,i);a.lastLodLevel=i}loadProgressiveTextures(r,e){return r&&r.userData&&r.userData.LOD!==e?(r.userData.LOD=e,w.assignTextureLOD(r,e)):Promise.resolve(null)}loadProgressiveMeshes(r,e){if(!r)return Promise.resolve(null);if(r.userData||(r.userData={}),r.userData.LOD!==e){r.userData.LOD=e;const t=r.geometry;return w.assignMeshLOD(r,e).then(o=>(o&&r.userData.LOD==e&&t!=r.geometry,o))}return Promise.resolve(null)}calculateLodLevel(r,e,t,o){var n;if(!e)return-1;let s=10+1;if(r){if(Z&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=w.getMeshLODInformation(e.geometry),i=a?.lods;if(!i||i.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e)))return 99;const l=e.geometry.boundingBox;if(l&&r.isPerspectiveCamera){const d=r;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const 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,m=this._tempBox.max;let b=f.x,x=f.y,S=m.x,T=m.y;const L=2,g=1.5,M=(f.x+m.x)*.5,E=(f.y+m.y)*.5;b=(b-M)*L+M,x=(x-E)*L+E,S=(S-M)*L+M,T=(T-E)*L+E;const k=b<0&&S>0?0:Math.min(Math.abs(f.x),Math.abs(m.x)),W=x<0&&T>0?0:Math.min(Math.abs(f.y),Math.abs(m.y)),j=Math.max(k,W);t.lastCentrality=(g-j)*(g-j)*(g-j)}else t.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&h.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),h.x*=d.aspect;const u=r.matrixWorldInverse,p=new re;p.copy(l),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(u);const D=p.getSize(this._tempBox2Size),A=Math.max(D.x,D.y);if(Math.max(h.x,h.y)!=0&&A!=0&&(h.z=D.z/Math.max(D.x,D.y)*Math.max(h.x,h.y)),t.lastScreenCoverage=Math.max(h.x,h.y,h.z),t.lastScreenspaceVolume.copy(h),t.lastScreenCoverage*=t.lastCentrality,Z&&_.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const m=_.corner0,b=_.corner1,x=_.corner2,S=_.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 T=(m.z+S.z)*.5;m.z=b.z=x.z=S.z=T,m.applyMatrix4(f),b.applyMatrix4(f),x.applyMatrix4(f),S.applyMatrix4(f),_.debugDrawLine(m,b,255),_.debugDrawLine(m,x,255),_.debugDrawLine(b,S,255),_.debugDrawLine(x,S,255)}let y=999;if(i&&t.lastScreenCoverage>0){for(let f=0;f<i.length;f++)if(i[f].density/t.lastScreenCoverage<o){y=f;break}}y<s&&(s=y)}}return s}};let B=_;c(B,"debugDrawLine"),c(B,"corner0",new I),c(B,"corner1",new I),c(B,"corner2",new I),c(B,"corner3",new I);class we{constructor(){c(this,"lastLodLevel",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new I),c(this,"lastCentrality",0)}}const ie=Symbol("NEEDLE_mesh_lod"),q=Symbol("NEEDLE_texture_lod");function ae(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=B.get(e);if(B.addPlugin(new Me(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 Me{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[q]==!0)return;t[q]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&t.material){let s=function(i){var l,d,h;if(i[q]==!0)return;i[q]=!0,i.userData&&(i.userData.LOD=-1);const u=Object.keys(i);for(let p=0;p<u.length;p++){const D=u[p],A=i[D];if(A?.isTexture===!0){const y=(d=(l=A.userData)==null?void 0:l.associations)==null?void 0:d.textures,f=o.parser.json.textures[y];if(!f){console.warn("Texture data not found for texture index "+y);continue}if((h=f?.extensions)!=null&&h[P]){const m=f.extensions[P];m&&n&&w.registerTexture(n,A,m.lods.length,m)}}}};const a=t.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,t){var o,n;if(t[ie]==!0)return;t[ie]=!0;const s=this.getUrl();if(!s)return;const a=(n=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:n[P];if(a&&s){const i=t.uuid;w.registerMesh(s,i,t,0,a.lods.length,a)}}}function be(r,e,t,o){K(e),H(t),t.register(s=>new w(s,r));const n=B.get(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{ae(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,B as LODsManager,w as NEEDLE_progressive,H as addDracoAndKTX2Loaders,K as createLoaders,te as getRaycastMesh,ae as patchModelViewer,De as setDracoDecoderLocation,xe as setKTX2TranscoderLocation,se as setRaycastMesh,be as useNeedleProgressive};
|
|
1
|
+
var le=Object.defineProperty,ue=(t,e,r)=>e in t?le(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,c=(t,e,r)=>(ue(t,typeof e!="symbol"?e+"":e,r),r);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";import{BufferGeometry as z,Mesh as U,Material as fe,Texture as k,TextureLoader as ge,Matrix4 as ee,Frustum as me,Sphere as pe,Box3 as te,Vector3 as B}from"three";import{GLTFLoader as ye}from"three/examples/jsm/loaders/GLTFLoader.js";let $="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",V="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch($+"draco_decoder.js",{method:"head"}).catch(t=>{$="./include/draco/",V="./include/ktx2/"});function De(t){$=t}function xe(t){V=t}let G,X,N;function K(t){G||(G=new de,G.setDecoderPath($),G.setDecoderConfig({type:"js"})),N||(N=new he,N.setTranscoderPath(V)),X||(X=ce),t?N.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function H(t){t.dracoLoader||t.setDRACOLoader(G),t.ktx2Loader||t.setKTX2Loader(N),t.meshoptDecoder||t.setMeshoptDecoder(X)}function Y(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Le(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const r=t.lastIndexOf("/");if(r>=0){const n=t.substring(0,r+1);for(;n.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return n+e}return e}function re(t){var e;return((e=t.userData)==null?void 0:e["needle:raycast-mesh"])instanceof z?t.userData["needle:raycast-mesh"]:null}function se(t,e){(t.type==="Mesh"||t.type==="SkinnedMesh")&&(t.userData||(t.userData={}),t.userData["needle:raycast-mesh"]=e)}const R=new Array,I="NEEDLE_progressive",v=Y("debugprogressive"),J=Symbol("needle-progressive-texture"),F=new Map,Q=new Set;if(v){let t=function(){e+=1,console.log("Toggle LOD level",e,F),F.forEach((o,s)=>{for(const a of o.keys){const i=s[a];if(i.isBufferGeometry===!0){const l=O.getMeshLODInformation(i),d=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=e,O.assignMeshLOD(s,d),l&&(r=Math.max(r,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,O.assignTextureLOD(s,e);break}}}),e>=r&&(e=-1)},e=-1,r=2,n=!1;window.addEventListener("keyup",o=>{o.key==="p"&&t(),o.key==="w"&&(n=!n,Q&&Q.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=n)}))})}function ne(t,e,r){var n;if(!v)return;F.has(t)||F.set(t,{keys:[],sourceId:r});const o=F.get(t);((n=o?.keys)==null?void 0:n.includes(e))==!1&&o.keys.push(e)}const M=class{constructor(t,e){c(this,"parser"),c(this,"url"),v&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return I}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static hasLODLevelAvailable(t,e){var r;if(t.isMaterial===!0){for(const s of Object.keys(t)){const a=t[s];if(a.isTexture&&this.hasLODLevelAvailable(a,e))return!0}return!1}else if(t.isGroup===!0){for(const s of t.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let n,o;if(t.isMesh?n=t.geometry:(t.isBufferGeometry||t.isTexture)&&(n=t),n&&(r=n?.userData)!=null&&r.LODS){const s=n.userData.LODS;if(o=this.lodInfos.get(s.key),e===void 0)return o!=null;if(o)return Array.isArray(o.lods)?e<o.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof U||t.isMesh===!0){const n=t.geometry,o=this.getAssignedLODInformation(n);if(!o)return Promise.resolve(null);for(const s of R)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,M.getOrLoadLOD(n,e).then(s=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(s)){const a=o.index||0;s=s[a]}s&&n!=s&&s instanceof z&&(t.geometry=s,v&&ne(t,"geometry",o.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",t,s),null))}else v&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof fe||t.isMaterial===!0){const r=t,n=[],o=new Array;if(v&&Q.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const a of Object.keys(s.uniforms)){const i=s.uniforms[a].value;if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,r,a);n.push(l),o.push(a)}}}else for(const s of Object.keys(r)){const a=r[s];if(a?.isTexture===!0){const i=this.assignTextureLODForSlot(a,e,r,s);n.push(i),o.push(s)}}return Promise.all(n).then(s=>{const a=new Array;for(let i=0;i<s.length;i++){const l=s[i],d=o[i];l&&l.isTexture===!0?a.push({material:r,slot:d,texture:l,level:e}):a.push({material:r,slot:d,texture:null,level:e})}return a})}if(t instanceof k||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,n){return t?.isTexture!==!0?Promise.resolve(null):M.getOrLoadLOD(t,e).then(o=>{if(Array.isArray(o))return null;if(o?.isTexture===!0){if(o!=t&&(r&&n&&(r[n]=o),v&&n&&r)){const s=this.getAssignedLODInformation(t);s&&ne(r,n,s.url)}return o}else v=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(o=>(console.error("Error loading LOD",t,o),null))}afterRoot(t){var e,r;return v&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[I];if(s){let a=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i).textures===o&&(a=!0,M.registerTexture(this.url,i,o,s));a||this.parser.getDependency("texture",o).then(i=>{i&&M.registerTexture(this.url,i,o,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[I];if(s&&s.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const i=this.parser.associations.get(a);i.meshes===o&&M.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(t,e){var r,n,o;const s=v=="verbose",a=t.userData.LODS;if(!a)return null;const i=a?.key;let l;if(t.isTexture===!0){const d=t;d.source&&d.source[J]&&(l=d.source[J])}if(l||(l=M.lodInfos.get(i)),l){if(e>0){let u=!1;const p=Array.isArray(l.lods);if(p&&e>=l.lods.length?u=!0:p||(u=!0),u)return this.lowresCache.get(i)}const d=Array.isArray(l.lods)?l.lods[e].path:l.lods;if(!d)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const h=Le(a.url,d);if(h.endsWith(".glb")||h.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const u=h+"_"+l.guid,p=this.previouslyLoaded.get(u);if(p!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${u}`);let y=await p.catch(m=>(console.error(`Error loading LOD ${e} from ${h}
|
|
2
|
+
`,m),null)),g=!1;if(y==null||(y instanceof k&&t instanceof k?(r=y.image)!=null&&r.data||(n=y.source)!=null&&n.data?y=this.copySettings(t,y):(g=!0,this.previouslyLoaded.delete(u)):y instanceof z&&t instanceof z&&((o=y.attributes.position)!=null&&o.array||(g=!0,this.previouslyLoaded.delete(u)))),!g)return y}const D=l,P=new Promise(async(y,g)=>{const m=new ye;H(m),v&&(await new Promise(L=>setTimeout(L,1e3)),s&&console.warn("Start loading (delayed) "+h,D.guid));let b=h;if(D&&Array.isArray(D.lods)){const L=D.lods[e];L.hash&&(b+="?v="+L.hash)}const x=await m.loadAsync(b).catch(L=>(console.error(`Error loading LOD ${e} from ${h}
|
|
3
|
+
`,L),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+h,D.guid);let _=0;if(x.parser.json.textures){let L=!1;for(const f of x.parser.json.textures){if(f!=null&&f.extensions){const w=f?.extensions[I];if(w!=null&&w.guid&&w.guid===D.guid){L=!0;break}}_++}if(L){let f=await S.getDependency("texture",_);return f&&M.assignLODInformation(a.url,f,i,e,void 0,void 0),s&&console.log('change "'+t.name+'" \u2192 "'+f.name+'"',h,_,f,u),t instanceof k&&(f=this.copySettings(t,f)),f&&(f.guid=D.guid),y(f)}else v&&console.warn("Could not find texture with guid",D.guid)}if(_=0,x.parser.json.meshes){let L=!1;for(const f of x.parser.json.meshes){if(f!=null&&f.extensions){const w=f?.extensions[I];if(w!=null&&w.guid&&w.guid===D.guid){L=!0;break}}_++}if(L){const f=await S.getDependency("mesh",_),w=D;if(s&&console.log(`Loaded Mesh "${f.name}"`,h,_,f,u),f.isMesh===!0){const E=f.geometry;return M.assignLODInformation(a.url,E,i,e,void 0,w.density),y(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;M.assignLODInformation(a.url,j,i,e,C,w.density),E.push(j)}}return y(E)}}}return y(null)});return this.previouslyLoaded.set(u,P),await P}else if(t instanceof k){s&&console.log("Load texture from uri: "+h);const u=await new ge().loadAsync(h);return u?(u.guid=l.guid,u.flipY=!1,u.needsUpdate=!0,u.colorSpace=t.colorSpace,s&&console.log(l,u)):v&&console.warn("failed loading",h),u}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,n,o,s){if(!e)return;e.userData||(e.userData={});const a=new ve(t,r,n,o,s);e.userData.LODS=a,e.userData.LOD=n}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return this._copiedTextures.get(t)||(e=e.clone(),this._copiedTextures.set(t,e),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.generateMipmaps=t.generateMipmaps,e)}};let O=M;c(O,"registerTexture",(t,e,r,n)=>{v&&console.log("> Progressive: register texture",r,e.name,e.uuid,e,n),e.source&&(e.source[J]=n);const o=n.guid;M.assignLODInformation(t,e,o,0,0,void 0),M.lodInfos.set(o,n),M.lowresCache.set(o,e)}),c(O,"registerMesh",(t,e,r,n,o,s)=>{var a;v&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const i=r.geometry;i.userData||(i.userData={}),M.assignLODInformation(t,i,e,n,o,s.density),M.lodInfos.set(e,s);let l=M.lowresCache.get(e);l?l.push(r.geometry):l=[r.geometry],M.lowresCache.set(e,l),n>0&&!re(r)&&se(r,i);for(const d of R)(a=d.onRegisteredNewMesh)==null||a.call(d,r,s)}),c(O,"lodInfos",new Map),c(O,"previouslyLoaded",new Map),c(O,"lowresCache",new Map),c(O,"_copiedTextures",new Map);class ve{constructor(e,r,n,o,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=r,this.level=n,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const Z=Y("debugprogressive"),Me=Y("noprogressive"),oe=Symbol("Needle:LODSManager"),T=class{constructor(t){c(this,"renderer"),c(this,"projectionScreenMatrix",new ee),c(this,"cameraFrustrum",new me),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new pe),c(this,"_tempBox",new te),c(this,"_tempBox2",new te),c(this,"tempMatrix",new ee),c(this,"_tempWorldPosition",new B),c(this,"_tempBoxSize",new B),c(this,"_tempBox2Size",new B),this.renderer=t}static getObjectLODState(t){var e;return(e=t.userData)==null?void 0:e.LOD_state}static addPlugin(t){R.push(t)}static removePlugin(t){const e=R.indexOf(t);e>=0&&R.splice(e,1)}static get(t){return t[oe]?t[oe]:new T(t)}enable(){if(this._originalRender)return;let t=0;this._originalRender=this.renderer.render;const e=this;K(this.renderer),this.renderer.render=function(r,n){e.renderer.getRenderTarget()==null&&(t=0,e._frame+=1);const o=e._frame,s=t++;e.onBeforeRender(r,n,s,o),e._originalRender.call(this,r,n),e.onAfterRender(r,n,s,o)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,n){}onAfterRender(t,e,r,n){var o,s;if(this.pause)return;const a=this.renderer.renderLists.get(t,0),i=a.opaque;let l=!0;if(i.length===1){const d=i[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(l=!1)}if(l){if(Me||this.updateInterval>0&&n%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=this.targetTriangleDensity;for(const u of i){if(u.material&&(((o=u.geometry)==null?void 0:o.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")){Z&&(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}switch(u.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const p=u.object;(p instanceof U||p.isMesh)&&this.updateLODs(t,e,p,d)}const h=a.transparent;for(const u of h){const p=u.object;(p instanceof U||p.isMesh)&&this.updateLODs(t,e,p,d)}}}updateLODs(t,e,r,n){var o,s;for(const d of R)(o=d.onBeforeUpdateLOD)==null||o.call(d,this.renderer,t,e,r);let a=r.userData.LOD_state;a||(a=new Oe,r.userData.LOD_state=a);let i=this.calculateLodLevel(e,r,a,n);i=Math.round(i),i>=0&&this.loadProgressiveMeshes(r,i);let l=0;if(r.material){const d=r["DEBUG:LOD"];if(d!=null&&(l=d),Array.isArray(r.material))for(const h of r.material)this.loadProgressiveTextures(h,l);else this.loadProgressiveTextures(r.material,l)}for(const d of R)(s=d.onAfterUpdatedLOD)==null||s.call(d,this.renderer,t,e,r,i);a.lastLodLevel=i}loadProgressiveTextures(t,e){return t&&t.userData&&t.userData.LOD!==e?(t.userData.LOD=e,O.assignTextureLOD(t,e)):Promise.resolve(null)}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t.userData||(t.userData={}),t.userData.LOD!==e){t.userData.LOD=e;const r=t.geometry;return O.assignMeshLOD(t,e).then(n=>(n&&t.userData.LOD==e&&r!=t.geometry,n))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,n=t.max,o=(r.x+n.x)*.5,s=(r.y+n.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,n){var o;if(!e)return-1;let s=10+1;if(t){if(Z&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=O.getMeshLODInformation(e.geometry),i=a?.lods;if(!i||i.length<=0)return 0;if(!((o=this.cameraFrustrum)!=null&&o.intersectsObject(e)))return 99;const l=e.geometry.boundingBox;if(l&&t.isPerspectiveCamera){const d=t;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=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g))return 0}if(this._tempBox.copy(l),this._tempBox.applyMatrix4(e.matrixWorld),T.isInside(this._tempBox,this.projectionScreenMatrix))return 0;if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&d.fov>70){const g=this._tempBox.min,m=this._tempBox.max;let b=g.x,x=g.y,S=m.x,_=m.y;const L=2,f=1.5,w=(g.x+m.x)*.5,E=(g.y+m.y)*.5;b=(b-w)*L+w,x=(x-E)*L+E,S=(S-w)*L+w,_=(_-E)*L+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);r.lastCentrality=(f-j)*(f-j)*(f-j)}else r.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&h.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),h.x*=d.aspect;const u=t.matrixWorldInverse,p=this._tempBox2;p.copy(l),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(u);const D=p.getSize(this._tempBox2Size),P=Math.max(D.x,D.y);if(Math.max(h.x,h.y)!=0&&P!=0&&(h.z=D.z/Math.max(D.x,D.y)*Math.max(h.x,h.y)),r.lastScreenCoverage=Math.max(h.x,h.y,h.z),r.lastScreenspaceVolume.copy(h),r.lastScreenCoverage*=r.lastCentrality,Z&&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 y=999;if(i&&r.lastScreenCoverage>0){for(let g=0;g<i.length;g++)if(i[g].density/r.lastScreenCoverage<n){y=g;break}}y<s&&(s=y)}}return s}};let A=T;c(A,"debugDrawLine"),c(A,"corner0",new B),c(A,"corner1",new B),c(A,"corner2",new B),c(A,"corner3",new B),c(A,"_tempPtInside",new B);class Oe{constructor(){c(this,"lastLodLevel",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const ie=Symbol("NEEDLE_mesh_lod"),q=Symbol("NEEDLE_texture_lod");function ae(t){if(!t)return null;let e=null,r=null;for(let n=t;n!=null;n=Object.getPrototypeOf(n)){const o=Object.getOwnPropertySymbols(n),s=o.find(i=>i.toString()=="Symbol(renderer)"),a=o.find(i=>i.toString()=="Symbol(scene)");!e&&s!=null&&(e=t[s].threeRenderer),!r&&a!=null&&(r=t[a])}if(e){console.log("Adding Needle LODs to modelviewer");const n=A.get(e);if(A.addPlugin(new we(t)),n.enable(),r){const o=r.camera||r.traverse(s=>s.type=="PerspectiveCamera")[0];o&&e.render(r,o)}return()=>{n.disable()}}return null}class we{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,r,n,o){this.tryParseMeshLOD(r,o),this.tryParseTextureLOD(r,o)}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,r){if(r[q]==!0)return;r[q]=!0;const n=this.tryGetCurrentGLTF(e),o=this.getUrl();if(o&&n&&r.material){let s=function(i){var l,d,h;if(i[q]==!0)return;i[q]=!0,i.userData&&(i.userData.LOD=-1);const u=Object.keys(i);for(let p=0;p<u.length;p++){const D=u[p],P=i[D];if(P?.isTexture===!0){const y=(d=(l=P.userData)==null?void 0:l.associations)==null?void 0:d.textures,g=n.parser.json.textures[y];if(!g){console.warn("Texture data not found for texture index "+y);continue}if((h=g?.extensions)!=null&&h[I]){const m=g.extensions[I];m&&o&&O.registerTexture(o,P,m.lods.length,m)}}}};const a=r.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,r){var n,o;if(r[ie]==!0)return;r[ie]=!0;const s=this.getUrl();if(!s)return;const a=(o=(n=r.userData)==null?void 0:n.gltfExtensions)==null?void 0:o[I];if(a&&s){const i=r.uuid;O.registerMesh(s,i,r,0,a.lods.length,a)}}}function be(t,e,r,n){K(e),H(r),r.register(s=>new O(s,t));const o=A.get(e);return n?.enableLODsManager!==!1&&o.enable(),o}document.addEventListener("DOMContentLoaded",()=>{ae(document.querySelector("model-viewer"))});export{I as EXTENSION_NAME,A as LODsManager,O as NEEDLE_progressive,H as addDracoAndKTX2Loaders,K as createLoaders,re as getRaycastMesh,ae as patchModelViewer,De as setDracoDecoderLocation,xe as setKTX2TranscoderLocation,se as setRaycastMesh,be as useNeedleProgressive};
|
package/gltf-progressive.umd.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var ae=Object.defineProperty;var le=(a,e,t)=>e in a?ae(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var u=(a,e,t)=>(le(a,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ce=require("three/examples/jsm/libs/meshopt_decoder.module.js"),ue=require("three/examples/jsm/loaders/DRACOLoader.js"),fe=require("three/examples/jsm/loaders/KTX2Loader.js"),
|
|
2
|
-
`,
|
|
3
|
-
`,L),null));if(!m)return null;const A=m.parser;r&&console.log("Loading finished "+y,x.guid);let w=0;if(m.parser.json.textures){let L=!1;for(const d of m.parser.json.textures){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[R];if(v!=null&&v.guid&&v.guid===x.guid){L=!0;break}}w++}if(L){let d=await A.getDependency("texture",w);return r&&console.log('change "'+e.name+'" → "'+d.name+'"',y,w,d,c),e instanceof h.Texture&&(d=this.copySettings(e,d)),d&&(d.guid=x.guid),O(d)}}if(w=0,m.parser.json.meshes){let L=!1;for(const d of m.parser.json.meshes){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[R];if(v!=null&&v.guid&&v.guid===x.guid){L=!0;break}}w++}if(L){const d=await A.getDependency("mesh",w),v=x;if(r&&console.log(`Loaded Mesh "${d.name}"`,y,w,d,c),d.isMesh===!0){const B=d.geometry;return S.assignLODInformation(i.url,B,n,t,void 0,v.density),O(B)}else{const B=new Array;for(let E=0;E<d.children.length;E++){const G=d.children[E];if(G instanceof h.Mesh){const z=G.geometry;S.assignLODInformation(i.url,z,n,t,E,v.density),B.push(z)}}return O(B)}}}return O(null)});return this.previouslyLoaded.set(c,P),await P}else if(e instanceof h.Texture){r&&console.log("Load texture from uri: "+y);const p=await new h.TextureLoader().loadAsync(y);return p?(p.guid=s.guid,p.flipY=!1,p.needsUpdate=!0,p.colorSpace=e.colorSpace,r&&console.log(s,p)):T&&console.warn("failed loading",y),p}}else T&&console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,i,n,s){if(!t)return;t.userData||(t.userData={});const o=new ye(e,r,i,n,s);t.userData.LODS=o,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.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.generateMipmaps=e.generateMipmaps,t)}};let M=S;u(M,"registerTexture",(e,t,r,i)=>{T&&console.log("> Progressive: register texture",r,t.name,t.uuid,t,i),t.source&&(t.source[$]=i);const n=i.guid;S.assignLODInformation(e,t,n,0,0,void 0),S.lodInfos.set(n,i),S.lowresCache.set(n,t)}),u(M,"registerMesh",(e,t,r,i,n,s)=>{var g;T&&console.log("> Progressive: register mesh",n,r.name,s,r.uuid,r);const o=r.geometry;o.userData||(o.userData={}),S.assignLODInformation(e,o,t,i,n,s.density),S.lodInfos.set(t,s);let l=S.lowresCache.get(t);l?l.push(r.geometry):l=[r.geometry],S.lowresCache.set(t,l),i>0&&!se(r)&&ie(r,o);for(const f of F)(g=f.onRegisteredNewMesh)==null||g.call(f,r,s)}),u(M,"lodInfos",new Map),u(M,"previouslyLoaded",new Map),u(M,"lowresCache",new Map),u(M,"_copiedTextures",new Map);class ye{constructor(e,t,r,i,n){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),n!=null&&(this.density=n)}}const K=j("debugprogressive"),me=j("noprogressive"),te=Symbol("Needle:LODSManager"),b=class{constructor(e){u(this,"renderer");u(this,"projectionScreenMatrix",new h.Matrix4);u(this,"cameraFrustrum",new h.Frustum);u(this,"targetTriangleDensity",2e5);u(this,"updateInterval",0);u(this,"pause",!1);u(this,"_frame",0);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}static addPlugin(e){F.push(e)}static removePlugin(e){const t=F.indexOf(e);t>=0&&F.splice(t,1)}static get(e){return e[te]?e[te]:new b(e)}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;Q(this.renderer),this.renderer.render=function(r,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,o=e++;t.onBeforeRender(r,i,o,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,o,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var l,g;if(this.pause)return;const n=this.renderer.renderLists.get(e,0),s=n.opaque;let o=!0;if(s.length===1){const f=s[0].material;(f.name==="EffectMaterial"||f.name==="CopyShader")&&(o=!1)}if(o){if(me||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const f=this.targetTriangleDensity;for(const c of s){if(c.material&&(((l=c.geometry)==null?void 0:l.type)==="BoxGeometry"||((g=c.geometry)==null?void 0:g.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){K&&(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 p=c.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}const y=n.transparent;for(const c of y){const p=c.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}}}updateLODs(e,t,r,i){var l,g;for(const f of F)(l=f.onBeforeUpdateLOD)==null||l.call(f,this.renderer,e,t,r);let n=r.userData.LOD_state;n||(n=new Le,r.userData.LOD_state=n);let s=this.calculateLodLevel(t,r,n,i);s=Math.round(s),s>=0&&this.loadProgressiveMeshes(r,s);let o=0;if(r.material){const f=r["DEBUG:LOD"];if(f!=null&&(o=f),Array.isArray(r.material))for(const y of r.material)this.loadProgressiveTextures(y,o);else this.loadProgressiveTextures(r.material,o)}for(const f of F)(g=f.onAfterUpdatedLOD)==null||g.call(f,this.renderer,e,t,r,s);n.lastLodLevel=s}loadProgressiveTextures(e,t){return e&&e.userData&&e.userData.LOD!==t?(e.userData.LOD=t,M.assignTextureLOD(e,t)):Promise.resolve(null)}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e.userData||(e.userData={}),e.userData.LOD!==t){e.userData.LOD=t;const r=e.geometry;return M.assignMeshLOD(e,t).then(i=>(i&&e.userData.LOD==t&&r!=e.geometry,i))}return Promise.resolve(null)}calculateLodLevel(e,t,r,i){var o;if(!t)return-1;let s=10+1;if(e){if(K&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const l=M.getMeshLODInformation(t.geometry),g=l==null?void 0:l.lods;if(!g||g.length<=0||!((o=this.cameraFrustrum)!=null&&o.intersectsObject(t)))return 99;const f=t.geometry.boundingBox;if(f&&e.isPerspectiveCamera){const y=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const D=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(D))return 0}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(t.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&y.fov>70){const D=this._tempBox.min,m=this._tempBox.max;let A=D.x,w=D.y,L=m.x,d=m.y;const v=2,B=1.5,E=(D.x+m.x)*.5,G=(D.y+m.y)*.5;A=(A-E)*v+E,w=(w-G)*v+G,L=(L-E)*v+E,d=(d-G)*v+G;const z=A<0&&L>0?0:Math.min(Math.abs(D.x),Math.abs(m.x)),oe=w<0&&d>0?0:Math.min(Math.abs(D.y),Math.abs(m.y)),X=Math.max(z,oe);r.lastCentrality=(B-X)*(B-X)*(B-X)}else r.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*=y.aspect;const p=e.matrixWorldInverse,x=new h.Box3;x.copy(f),x.applyMatrix4(t.matrixWorld),x.applyMatrix4(p);const P=x.getSize(this._tempBox2Size),k=Math.max(P.x,P.y);if(Math.max(c.x,c.y)!=0&&k!=0&&(c.z=P.z/Math.max(P.x,P.y)*Math.max(c.x,c.y)),r.lastScreenCoverage=Math.max(c.x,c.y,c.z),r.lastScreenspaceVolume.copy(c),r.lastScreenCoverage*=r.lastCentrality,K&&b.debugDrawLine){const D=this.tempMatrix.copy(this.projectionScreenMatrix);D.invert();const m=b.corner0,A=b.corner1,w=b.corner2,L=b.corner3;m.copy(this._tempBox.min),A.copy(this._tempBox.max),A.x=m.x,w.copy(this._tempBox.max),w.y=m.y,L.copy(this._tempBox.max);const d=(m.z+L.z)*.5;m.z=A.z=w.z=L.z=d,m.applyMatrix4(D),A.applyMatrix4(D),w.applyMatrix4(D),L.applyMatrix4(D),b.debugDrawLine(m,A,255),b.debugDrawLine(m,w,255),b.debugDrawLine(A,L,255),b.debugDrawLine(w,L,255)}let C=999;if(g&&r.lastScreenCoverage>0){for(let D=0;D<g.length;D++)if(g[D].density/r.lastScreenCoverage<i){C=D;break}}C<s&&(s=C)}}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 Le{constructor(){u(this,"lastLodLevel",0);u(this,"lastScreenCoverage",0);u(this,"lastScreenspaceVolume",new h.Vector3);u(this,"lastCentrality",0)}}const re=Symbol("NEEDLE_mesh_lod"),V=Symbol("NEEDLE_texture_lod");function ne(a){if(!a)return null;let e=null,t=null;for(let r=a;r!=null;r=Object.getPrototypeOf(r)){const i=Object.getOwnPropertySymbols(r),n=i.find(o=>o.toString()=="Symbol(renderer)"),s=i.find(o=>o.toString()=="Symbol(scene)");!e&&n!=null&&(e=a[n].threeRenderer),!t&&s!=null&&(t=a[s])}if(e){console.log("Adding Needle LODs to modelviewer");const r=_.get(e);if(_.addPlugin(new De(a)),r.enable(),t){const i=t.camera||t.traverse(n=>n.type=="PerspectiveCamera")[0];i&&e.render(t,i)}return()=>{r.disable()}}return null}class De{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[V]==!0)return;t[V]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let n=function(o){var g,f,y;if(o[V]==!0)return;o[V]=!0,o.userData&&(o.userData.LOD=-1);const l=Object.keys(o);for(let c=0;c<l.length;c++){const p=l[c],x=o[p];if((x==null?void 0:x.isTexture)===!0){const P=(f=(g=x.userData)==null?void 0:g.associations)==null?void 0:f.textures,k=r.parser.json.textures[P];if(!k){console.warn("Texture data not found for texture index "+P);continue}if((y=k==null?void 0:k.extensions)!=null&&y[R]){const O=k.extensions[R];O&&i&&M.registerTexture(i,x,O.lods.length,O)}}}};const s=t.material;if(Array.isArray(s))for(const o of s)n(o);else n(s)}}tryParseMeshLOD(e,t){var n,s;if(t[re]==!0)return;t[re]=!0;const r=this.getUrl();if(!r)return;const i=(s=(n=t.userData)==null?void 0:n.gltfExtensions)==null?void 0:s[R];if(i&&r){const o=t.uuid;M.registerMesh(r,o,t,0,i.lods.length,i)}}}function xe(a,e,t,r){Q(e),Z(t),t.register(n=>new M(n,a));const i=_.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{ne(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=R;exports.LODsManager=_;exports.NEEDLE_progressive=M;exports.addDracoAndKTX2Loaders=Z;exports.createLoaders=Q;exports.getRaycastMesh=se;exports.patchModelViewer=ne;exports.setDracoDecoderLocation=ge;exports.setKTX2TranscoderLocation=he;exports.setRaycastMesh=ie;exports.useNeedleProgressive=xe;
|
|
1
|
+
"use strict";var ae=Object.defineProperty;var le=(a,e,t)=>e in a?ae(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var u=(a,e,t)=>(le(a,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ce=require("three/examples/jsm/libs/meshopt_decoder.module.js"),ue=require("three/examples/jsm/loaders/DRACOLoader.js"),fe=require("three/examples/jsm/loaders/KTX2Loader.js"),g=require("three"),de=require("three/examples/jsm/loaders/GLTFLoader.js");let q="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",J="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(q+"draco_decoder.js",{method:"head"}).catch(a=>{q="./include/draco/",J="./include/ktx2/"});function ge(a){q=a}function he(a){J=a}let N,Y,U;function Q(a){N||(N=new ue.DRACOLoader,N.setDecoderPath(q),N.setDecoderConfig({type:"js"})),U||(U=new fe.KTX2Loader,U.setTranscoderPath(J)),Y||(Y=ce.MeshoptDecoder),a?U.detectSupport(a):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function Z(a){a.dracoLoader||a.setDRACOLoader(N),a.ktx2Loader||a.setKTX2Loader(U),a.meshoptDecoder||a.setMeshoptDecoder(Y)}function j(a){const t=new URL(window.location.href).searchParams.get(a);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function pe(a,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||a===void 0)return e;const t=a.lastIndexOf("/");if(t>=0){const r=a.substring(0,t+1);for(;r.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return r+e}return e}function se(a){var e;return((e=a.userData)==null?void 0:e["needle:raycast-mesh"])instanceof g.BufferGeometry?a.userData["needle:raycast-mesh"]:null}function ie(a,e){(a.type==="Mesh"||a.type==="SkinnedMesh")&&(a.userData||(a.userData={}),a.userData["needle:raycast-mesh"]=e)}const I=new Array,R="NEEDLE_progressive",T=j("debugprogressive"),$=Symbol("needle-progressive-texture"),z=new Map,H=new Set;if(T){let a=function(){e+=1,console.log("Toggle LOD level",e,z),z.forEach((i,n)=>{for(const s of i.keys){const o=n[s];if(o.isBufferGeometry===!0){const l=v.getMeshLODInformation(o),h=l?Math.min(e,l.lods.length):0;n["DEBUG:LOD"]=e,v.assignMeshLOD(n,h),l&&(t=Math.max(t,l.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,v.assignTextureLOD(n,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",i=>{i.key==="p"&&a(),i.key==="w"&&(r=!r,H&&H.forEach(n=>{n.name!="BackgroundCubeMaterial"&&"wireframe"in n&&(n.wireframe=r)}))})}function ee(a,e,t){var i;if(!T)return;z.has(a)||z.set(a,{keys:[],sourceId:t});const r=z.get(a);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const O=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 R}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static hasLODLevelAvailable(e,t){var n;if(e.isMaterial===!0){for(const s of Object.keys(e)){const o=e[s];if(o.isTexture&&this.hasLODLevelAvailable(o,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&&(n=r==null?void 0:r.userData)!=null&&n.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 g.Mesh||e.isMesh===!0){const i=e.geometry,n=this.getAssignedLODInformation(i);if(!n)return Promise.resolve(null);for(const s of I)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,O.getOrLoadLOD(i,t).then(s=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(s)){const o=n.index||0;s=s[o]}s&&i!=s&&s instanceof g.BufferGeometry&&(e.geometry=s,T&&ee(e,"geometry",n.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 g.Material||e.isMaterial===!0){const r=e,i=[],n=new Array;if(T&&H.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const o of Object.keys(s.uniforms)){const l=s.uniforms[o].value;if((l==null?void 0:l.isTexture)===!0){const h=this.assignTextureLODForSlot(l,t,r,o);i.push(h),n.push(o)}}}else for(const s of Object.keys(r)){const o=r[s];if((o==null?void 0:o.isTexture)===!0){const l=this.assignTextureLODForSlot(o,t,r,s);i.push(l),n.push(s)}}return Promise.all(i).then(s=>{const o=new Array;for(let l=0;l<s.length;l++){const h=s[l],f=n[l];h&&h.isTexture===!0?o.push({material:r,slot:f,texture:h,level:t}):o.push({material:r,slot:f,texture:null,level:t})}return o})}if(e instanceof g.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):O.getOrLoadLOD(e,t).then(n=>{if(Array.isArray(n))return null;if((n==null?void 0:n.isTexture)===!0){if(n!=e&&(r&&i&&(r[i]=n),T&&i&&r)){const s=this.getAssignedLODInformation(e);s&&ee(r,i,s.url)}return n}else T=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(n=>(console.error("Error loading LOD",e,n),null))}afterRoot(e){var t,r;return T&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((i,n)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[R];if(s){let o=!1;for(const l of this.parser.associations.keys())l.isTexture===!0&&this.parser.associations.get(l).textures===n&&(o=!0,O.registerTexture(this.url,l,n,s));o||this.parser.getDependency("texture",n).then(l=>{l&&O.registerTexture(this.url,l,n,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((i,n)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[R];if(s&&s.lods){for(const o of this.parser.associations.keys())if(o.isMesh){const l=this.parser.associations.get(o);l.meshes===n&&O.registerMesh(this.url,s.guid,o,s.lods.length,l.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var o,l,h;const r=T=="verbose",i=e.userData.LODS;if(!i)return null;const n=i==null?void 0:i.key;let s;if(e.isTexture===!0){const f=e;f.source&&f.source[$]&&(s=f.source[$])}if(s||(s=O.lodInfos.get(n)),s){if(t>0){let c=!1;const p=Array.isArray(s.lods);if(p&&t>=s.lods.length?c=!0:p||(c=!0),c)return this.lowresCache.get(n)}const f=Array.isArray(s.lods)?s.lods[t].path:s.lods;if(!f)return T&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const y=pe(i.url,f);if(y.endsWith(".glb")||y.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const c=y+"_"+s.guid,p=this.previouslyLoaded.get(c);if(p!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${c}`);let M=await p.catch(F=>(console.error(`Error loading LOD ${t} from ${y}
|
|
2
|
+
`,F),null)),k=!1;if(M==null||(M instanceof g.Texture&&e instanceof g.Texture?(o=M.image)!=null&&o.data||(l=M.source)!=null&&l.data?M=this.copySettings(e,M):(k=!0,this.previouslyLoaded.delete(c)):M instanceof g.BufferGeometry&&e instanceof g.BufferGeometry&&((h=M.attributes.position)!=null&&h.array||(k=!0,this.previouslyLoaded.delete(c)))),!k)return M}const D=s,b=new Promise(async(M,k)=>{const F=new de.GLTFLoader;Z(F),T&&(await new Promise(L=>setTimeout(L,1e3)),r&&console.warn("Start loading (delayed) "+y,D.guid));let x=y;if(D&&Array.isArray(D.lods)){const L=D.lods[t];L.hash&&(x+="?v="+L.hash)}const m=await F.loadAsync(x).catch(L=>(console.error(`Error loading LOD ${t} from ${y}
|
|
3
|
+
`,L),null));if(!m)return null;const P=m.parser;r&&console.log("Loading finished "+y,D.guid);let w=0;if(m.parser.json.textures){let L=!1;for(const d of m.parser.json.textures){if(d!=null&&d.extensions){const S=d==null?void 0:d.extensions[R];if(S!=null&&S.guid&&S.guid===D.guid){L=!0;break}}w++}if(L){let d=await P.getDependency("texture",w);return d&&O.assignLODInformation(i.url,d,n,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+d.name+'"',y,w,d,c),e instanceof g.Texture&&(d=this.copySettings(e,d)),d&&(d.guid=D.guid),M(d)}else T&&console.warn("Could not find texture with guid",D.guid)}if(w=0,m.parser.json.meshes){let L=!1;for(const d of m.parser.json.meshes){if(d!=null&&d.extensions){const S=d==null?void 0:d.extensions[R];if(S!=null&&S.guid&&S.guid===D.guid){L=!0;break}}w++}if(L){const d=await P.getDependency("mesh",w),S=D;if(r&&console.log(`Loaded Mesh "${d.name}"`,y,w,d,c),d.isMesh===!0){const B=d.geometry;return O.assignLODInformation(i.url,B,n,t,void 0,S.density),M(B)}else{const B=new Array;for(let E=0;E<d.children.length;E++){const G=d.children[E];if(G instanceof g.Mesh){const W=G.geometry;O.assignLODInformation(i.url,W,n,t,E,S.density),B.push(W)}}return M(B)}}}return M(null)});return this.previouslyLoaded.set(c,b),await b}else if(e instanceof g.Texture){r&&console.log("Load texture from uri: "+y);const p=await new g.TextureLoader().loadAsync(y);return p?(p.guid=s.guid,p.flipY=!1,p.needsUpdate=!0,p.colorSpace=e.colorSpace,r&&console.log(s,p)):T&&console.warn("failed loading",y),p}}else T&&console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,i,n,s){if(!t)return;t.userData||(t.userData={});const o=new ye(e,r,i,n,s);t.userData.LODS=o,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.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.generateMipmaps=e.generateMipmaps,t)}};let v=O;u(v,"registerTexture",(e,t,r,i)=>{T&&console.log("> Progressive: register texture",r,t.name,t.uuid,t,i),t.source&&(t.source[$]=i);const n=i.guid;O.assignLODInformation(e,t,n,0,0,void 0),O.lodInfos.set(n,i),O.lowresCache.set(n,t)}),u(v,"registerMesh",(e,t,r,i,n,s)=>{var h;T&&console.log("> Progressive: register mesh",n,r.name,s,r.uuid,r);const o=r.geometry;o.userData||(o.userData={}),O.assignLODInformation(e,o,t,i,n,s.density),O.lodInfos.set(t,s);let l=O.lowresCache.get(t);l?l.push(r.geometry):l=[r.geometry],O.lowresCache.set(t,l),i>0&&!se(r)&&ie(r,o);for(const f of I)(h=f.onRegisteredNewMesh)==null||h.call(f,r,s)}),u(v,"lodInfos",new Map),u(v,"previouslyLoaded",new Map),u(v,"lowresCache",new Map),u(v,"_copiedTextures",new Map);class ye{constructor(e,t,r,i,n){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),n!=null&&(this.density=n)}}const K=j("debugprogressive"),me=j("noprogressive"),te=Symbol("Needle:LODSManager"),A=class{constructor(e){u(this,"renderer");u(this,"projectionScreenMatrix",new g.Matrix4);u(this,"cameraFrustrum",new g.Frustum);u(this,"targetTriangleDensity",2e5);u(this,"updateInterval",0);u(this,"pause",!1);u(this,"_frame",0);u(this,"_originalRender");u(this,"_sphere",new g.Sphere);u(this,"_tempBox",new g.Box3);u(this,"_tempBox2",new g.Box3);u(this,"tempMatrix",new g.Matrix4);u(this,"_tempWorldPosition",new g.Vector3);u(this,"_tempBoxSize",new g.Vector3);u(this,"_tempBox2Size",new g.Vector3);this.renderer=e}static getObjectLODState(e){var t;return(t=e.userData)==null?void 0:t.LOD_state}static addPlugin(e){I.push(e)}static removePlugin(e){const t=I.indexOf(e);t>=0&&I.splice(t,1)}static get(e){return e[te]?e[te]:new A(e)}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;Q(this.renderer),this.renderer.render=function(r,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,o=e++;t.onBeforeRender(r,i,o,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,o,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var l,h;if(this.pause)return;const n=this.renderer.renderLists.get(e,0),s=n.opaque;let o=!0;if(s.length===1){const f=s[0].material;(f.name==="EffectMaterial"||f.name==="CopyShader")&&(o=!1)}if(o){if(me||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const f=this.targetTriangleDensity;for(const c of s){if(c.material&&(((l=c.geometry)==null?void 0:l.type)==="BoxGeometry"||((h=c.geometry)==null?void 0:h.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){K&&(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}switch(c.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const p=c.object;(p instanceof g.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}const y=n.transparent;for(const c of y){const p=c.object;(p instanceof g.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}}}updateLODs(e,t,r,i){var l,h;for(const f of I)(l=f.onBeforeUpdateLOD)==null||l.call(f,this.renderer,e,t,r);let n=r.userData.LOD_state;n||(n=new Le,r.userData.LOD_state=n);let s=this.calculateLodLevel(t,r,n,i);s=Math.round(s),s>=0&&this.loadProgressiveMeshes(r,s);let o=0;if(r.material){const f=r["DEBUG:LOD"];if(f!=null&&(o=f),Array.isArray(r.material))for(const y of r.material)this.loadProgressiveTextures(y,o);else this.loadProgressiveTextures(r.material,o)}for(const f of I)(h=f.onAfterUpdatedLOD)==null||h.call(f,this.renderer,e,t,r,s);n.lastLodLevel=s}loadProgressiveTextures(e,t){return e&&e.userData&&e.userData.LOD!==t?(e.userData.LOD=t,v.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 v.assignMeshLOD(e,t).then(i=>(i&&e.userData.LOD==t&&r!=e.geometry,i))}return Promise.resolve(null)}static isInside(e,t){const r=e.min,i=e.max,n=(r.x+i.x)*.5,s=(r.y+i.y)*.5;return this._tempPtInside.set(n,s,r.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,r,i){var o;if(!t)return-1;let s=10+1;if(e){if(K&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const l=v.getMeshLODInformation(t.geometry),h=l==null?void 0:l.lods;if(!h||h.length<=0)return 0;if(!((o=this.cameraFrustrum)!=null&&o.intersectsObject(t)))return 99;const f=t.geometry.boundingBox;if(f&&e.isPerspectiveCamera){const y=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const x=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(x))return 0}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(t.matrixWorld),A.isInside(this._tempBox,this.projectionScreenMatrix))return 0;if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&y.fov>70){const x=this._tempBox.min,m=this._tempBox.max;let P=x.x,w=x.y,L=m.x,d=m.y;const S=2,B=1.5,E=(x.x+m.x)*.5,G=(x.y+m.y)*.5;P=(P-E)*S+E,w=(w-G)*S+G,L=(L-E)*S+E,d=(d-G)*S+G;const W=P<0&&L>0?0:Math.min(Math.abs(x.x),Math.abs(m.x)),oe=w<0&&d>0?0:Math.min(Math.abs(x.y),Math.abs(m.y)),X=Math.max(W,oe);r.lastCentrality=(B-X)*(B-X)*(B-X)}else r.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*=y.aspect;const p=e.matrixWorldInverse,D=this._tempBox2;D.copy(f),D.applyMatrix4(t.matrixWorld),D.applyMatrix4(p);const b=D.getSize(this._tempBox2Size),C=Math.max(b.x,b.y);if(Math.max(c.x,c.y)!=0&&C!=0&&(c.z=b.z/Math.max(b.x,b.y)*Math.max(c.x,c.y)),r.lastScreenCoverage=Math.max(c.x,c.y,c.z),r.lastScreenspaceVolume.copy(c),r.lastScreenCoverage*=r.lastCentrality,K&&A.debugDrawLine){const x=this.tempMatrix.copy(this.projectionScreenMatrix);x.invert();const m=A.corner0,P=A.corner1,w=A.corner2,L=A.corner3;m.copy(this._tempBox.min),P.copy(this._tempBox.max),P.x=m.x,w.copy(this._tempBox.max),w.y=m.y,L.copy(this._tempBox.max);const d=(m.z+L.z)*.5;m.z=P.z=w.z=L.z=d,m.applyMatrix4(x),P.applyMatrix4(x),w.applyMatrix4(x),L.applyMatrix4(x),A.debugDrawLine(m,P,255),A.debugDrawLine(m,w,255),A.debugDrawLine(P,L,255),A.debugDrawLine(w,L,255)}let k=999;if(h&&r.lastScreenCoverage>0){for(let x=0;x<h.length;x++)if(h[x].density/r.lastScreenCoverage<i){k=x;break}}k<s&&(s=k)}}return s}};let _=A;u(_,"debugDrawLine"),u(_,"corner0",new g.Vector3),u(_,"corner1",new g.Vector3),u(_,"corner2",new g.Vector3),u(_,"corner3",new g.Vector3),u(_,"_tempPtInside",new g.Vector3);class Le{constructor(){u(this,"lastLodLevel",0);u(this,"lastScreenCoverage",0);u(this,"lastScreenspaceVolume",new g.Vector3);u(this,"lastCentrality",0)}}const re=Symbol("NEEDLE_mesh_lod"),V=Symbol("NEEDLE_texture_lod");function ne(a){if(!a)return null;let e=null,t=null;for(let r=a;r!=null;r=Object.getPrototypeOf(r)){const i=Object.getOwnPropertySymbols(r),n=i.find(o=>o.toString()=="Symbol(renderer)"),s=i.find(o=>o.toString()=="Symbol(scene)");!e&&n!=null&&(e=a[n].threeRenderer),!t&&s!=null&&(t=a[s])}if(e){console.log("Adding Needle LODs to modelviewer");const r=_.get(e);if(_.addPlugin(new De(a)),r.enable(),t){const i=t.camera||t.traverse(n=>n.type=="PerspectiveCamera")[0];i&&e.render(t,i)}return()=>{r.disable()}}return null}class De{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[V]==!0)return;t[V]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let n=function(o){var h,f,y;if(o[V]==!0)return;o[V]=!0,o.userData&&(o.userData.LOD=-1);const l=Object.keys(o);for(let c=0;c<l.length;c++){const p=l[c],D=o[p];if((D==null?void 0:D.isTexture)===!0){const b=(f=(h=D.userData)==null?void 0:h.associations)==null?void 0:f.textures,C=r.parser.json.textures[b];if(!C){console.warn("Texture data not found for texture index "+b);continue}if((y=C==null?void 0:C.extensions)!=null&&y[R]){const M=C.extensions[R];M&&i&&v.registerTexture(i,D,M.lods.length,M)}}}};const s=t.material;if(Array.isArray(s))for(const o of s)n(o);else n(s)}}tryParseMeshLOD(e,t){var n,s;if(t[re]==!0)return;t[re]=!0;const r=this.getUrl();if(!r)return;const i=(s=(n=t.userData)==null?void 0:n.gltfExtensions)==null?void 0:s[R];if(i&&r){const o=t.uuid;v.registerMesh(r,o,t,0,i.lods.length,i)}}}function xe(a,e,t,r){Q(e),Z(t),t.register(n=>new v(n,a));const i=_.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{ne(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=R;exports.LODsManager=_;exports.NEEDLE_progressive=v;exports.addDracoAndKTX2Loaders=Z;exports.createLoaders=Q;exports.getRaycastMesh=se;exports.patchModelViewer=ne;exports.setDracoDecoderLocation=ge;exports.setKTX2TranscoderLocation=he;exports.setRaycastMesh=ie;exports.useNeedleProgressive=xe;
|
package/lib/extension.js
CHANGED
|
@@ -540,6 +540,9 @@ export class NEEDLE_progressive {
|
|
|
540
540
|
}
|
|
541
541
|
if (found) {
|
|
542
542
|
let tex = await parser.getDependency("texture", index);
|
|
543
|
+
if (tex) {
|
|
544
|
+
NEEDLE_progressive.assignLODInformation(LOD.url, tex, LODKEY, level, undefined, undefined);
|
|
545
|
+
}
|
|
543
546
|
if (debugverbose)
|
|
544
547
|
console.log("change \"" + current.name + "\" → \"" + tex.name + "\"", lod_url, index, tex, KEY);
|
|
545
548
|
if (current instanceof Texture)
|
|
@@ -549,6 +552,9 @@ export class NEEDLE_progressive {
|
|
|
549
552
|
}
|
|
550
553
|
return resolve(tex);
|
|
551
554
|
}
|
|
555
|
+
else if (debug) {
|
|
556
|
+
console.warn("Could not find texture with guid", ext.guid);
|
|
557
|
+
}
|
|
552
558
|
}
|
|
553
559
|
index = 0;
|
|
554
560
|
if (gltf.parser.json.meshes) {
|
package/lib/lods_manager.d.ts
CHANGED
|
@@ -86,6 +86,7 @@ export declare class LODsManager {
|
|
|
86
86
|
private loadProgressiveMeshes;
|
|
87
87
|
private readonly _sphere;
|
|
88
88
|
private readonly _tempBox;
|
|
89
|
+
private readonly _tempBox2;
|
|
89
90
|
private readonly tempMatrix;
|
|
90
91
|
private readonly _tempWorldPosition;
|
|
91
92
|
private readonly _tempBoxSize;
|
|
@@ -94,6 +95,8 @@ export declare class LODsManager {
|
|
|
94
95
|
private static corner1;
|
|
95
96
|
private static corner2;
|
|
96
97
|
private static corner3;
|
|
98
|
+
private static readonly _tempPtInside;
|
|
99
|
+
private static isInside;
|
|
97
100
|
private calculateLodLevel;
|
|
98
101
|
}
|
|
99
102
|
declare class LOD_state {
|
package/lib/lods_manager.js
CHANGED
|
@@ -169,6 +169,15 @@ export class LODsManager {
|
|
|
169
169
|
continue;
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
|
+
switch (entry.material.type) {
|
|
173
|
+
case "LineBasicMaterial":
|
|
174
|
+
case "LineDashedMaterial":
|
|
175
|
+
case "PointsMaterial":
|
|
176
|
+
case "ShadowMaterial":
|
|
177
|
+
case "MeshDistanceMaterial":
|
|
178
|
+
case "MeshDepthMaterial":
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
172
181
|
const object = entry.object;
|
|
173
182
|
if (object instanceof Mesh || (object.isMesh)) {
|
|
174
183
|
this.updateLODs(scene, camera, object, desiredDensity);
|
|
@@ -267,6 +276,7 @@ export class LODsManager {
|
|
|
267
276
|
// private testIfLODLevelsAreAvailable() {
|
|
268
277
|
_sphere = new Sphere();
|
|
269
278
|
_tempBox = new Box3();
|
|
279
|
+
_tempBox2 = new Box3();
|
|
270
280
|
tempMatrix = new Matrix4();
|
|
271
281
|
_tempWorldPosition = new Vector3();
|
|
272
282
|
_tempBoxSize = new Vector3();
|
|
@@ -275,6 +285,15 @@ export class LODsManager {
|
|
|
275
285
|
static corner1 = new Vector3();
|
|
276
286
|
static corner2 = new Vector3();
|
|
277
287
|
static corner3 = new Vector3();
|
|
288
|
+
static _tempPtInside = new Vector3();
|
|
289
|
+
static isInside(box, matrix) {
|
|
290
|
+
const min = box.min;
|
|
291
|
+
const max = box.max;
|
|
292
|
+
const centerx = (min.x + max.x) * 0.5;
|
|
293
|
+
const centery = (min.y + max.y) * 0.5;
|
|
294
|
+
const pt1 = this._tempPtInside.set(centerx, centery, min.z).applyMatrix4(matrix);
|
|
295
|
+
return pt1.z < 0;
|
|
296
|
+
}
|
|
278
297
|
calculateLodLevel(camera, mesh, state, desiredDensity) {
|
|
279
298
|
if (!mesh)
|
|
280
299
|
return -1;
|
|
@@ -292,8 +311,10 @@ export class LODsManager {
|
|
|
292
311
|
const lodsInfo = NEEDLE_progressive.getMeshLODInformation(mesh.geometry);
|
|
293
312
|
const lods = lodsInfo?.lods;
|
|
294
313
|
// We can skip all this if we dont have any LOD information - we can ask the progressive extension for that
|
|
314
|
+
// But if the MESH has no LODs we might still have materials that do - we would need to check that
|
|
315
|
+
// Until we properly check if an object has *any* LODs we do return the best quality for now
|
|
295
316
|
if (!lods || lods.length <= 0) {
|
|
296
|
-
return
|
|
317
|
+
return 0;
|
|
297
318
|
}
|
|
298
319
|
if (!this.cameraFrustrum?.intersectsObject(mesh)) {
|
|
299
320
|
// console.log("Mesh not visible");
|
|
@@ -306,8 +327,8 @@ export class LODsManager {
|
|
|
306
327
|
// the object is not visible by the camera
|
|
307
328
|
return 99;
|
|
308
329
|
}
|
|
309
|
-
const
|
|
310
|
-
if (
|
|
330
|
+
const boundingBox = mesh.geometry.boundingBox;
|
|
331
|
+
if (boundingBox && camera.isPerspectiveCamera) {
|
|
311
332
|
const cam = camera;
|
|
312
333
|
// hack: if the mesh has vertex colors, has less than 100 vertices we always select the highest LOD
|
|
313
334
|
if (mesh.geometry.attributes.color && mesh.geometry.attributes.color.count < 100) {
|
|
@@ -321,7 +342,7 @@ export class LODsManager {
|
|
|
321
342
|
}
|
|
322
343
|
}
|
|
323
344
|
// calculate size on screen
|
|
324
|
-
this._tempBox.copy(
|
|
345
|
+
this._tempBox.copy(boundingBox);
|
|
325
346
|
this._tempBox.applyMatrix4(mesh.matrixWorld);
|
|
326
347
|
// Converting into projection space has the disadvantage that objects further to the side
|
|
327
348
|
// will have a much larger coverage, especially with high-field-of-view situations like in VR.
|
|
@@ -330,6 +351,9 @@ export class LODsManager {
|
|
|
330
351
|
// High distortions would lead to lower LOD levels.
|
|
331
352
|
// "Centrality" of the calculated screen-space bounding box could be a factor here –
|
|
332
353
|
// what's the distance of the bounding box to the center of the screen?
|
|
354
|
+
if (LODsManager.isInside(this._tempBox, this.projectionScreenMatrix)) {
|
|
355
|
+
return 0;
|
|
356
|
+
}
|
|
333
357
|
this._tempBox.applyMatrix4(this.projectionScreenMatrix);
|
|
334
358
|
// TODO might need to be adjusted for cameras that are rendered during an XR session but are
|
|
335
359
|
// actually not XR cameras (e.g. a render texture)
|
|
@@ -365,8 +389,8 @@ export class LODsManager {
|
|
|
365
389
|
boxSize.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight); // correct for size of context on screen
|
|
366
390
|
boxSize.x *= cam.aspect;
|
|
367
391
|
const matView = camera.matrixWorldInverse;
|
|
368
|
-
const box2 =
|
|
369
|
-
box2.copy(
|
|
392
|
+
const box2 = this._tempBox2;
|
|
393
|
+
box2.copy(boundingBox);
|
|
370
394
|
box2.applyMatrix4(mesh.matrixWorld);
|
|
371
395
|
box2.applyMatrix4(matView);
|
|
372
396
|
const boxSize2 = box2.getSize(this._tempBox2Size);
|
package/package.json
CHANGED