@needle-tools/gltf-progressive 1.0.0-alpha → 1.0.0-alpha.2
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/dist/@needle-tools-gltf-progressive.js +651 -0
- package/dist/@needle-tools-gltf-progressive.min.js +3 -0
- package/dist/@needle-tools-gltf-progressive.umd.cjs +3 -0
- package/package.json +14 -11
- package/types/extension.d.ts +109 -0
- package/types/index.d.ts +10 -0
- package/types/loaders.d.ts +4 -0
- package/types/lods_manager.d.ts +51 -0
- package/types/plugins/index.d.ts +2 -0
- package/types/plugins/modelviewer.d.ts +15 -0
- package/types/plugins/plugin.d.ts +14 -0
- package/types/utils.d.ts +2 -0
- package/examples/@needle-tools-gltf-progressive.min.js +0 -3
- package/examples/modelviewer.html +0 -27
- package/src/extension.ts +0 -768
- package/src/index.ts +0 -14
- package/src/loaders.ts +0 -49
- package/src/lods_manager.ts +0 -387
- package/src/plugins/index.ts +0 -2
- package/src/plugins/modelviewer.ts +0 -113
- package/src/plugins/plugin.ts +0 -21
- package/src/utils.ts +0 -41
- package/tsconfig.json +0 -33
- package/vite.config.ts +0 -69
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
var ne = Object.defineProperty;
|
|
2
|
+
var ae = (l, e, t) => e in l ? ne(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
|
|
3
|
+
var u = (l, e, t) => (ae(l, typeof e != "symbol" ? e + "" : e, t), t);
|
|
4
|
+
import { Mesh as Y, BufferGeometry as X, Material as le, RawShaderMaterial as ue, Texture as z, TextureLoader as ce, Matrix4 as Z, Frustum as fe, Sphere as de, Box3 as j, Vector3 as C } from "three";
|
|
5
|
+
import { GLTFLoader as ge } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
6
|
+
import { MeshoptDecoder as he } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
7
|
+
import { DRACOLoader as pe } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
8
|
+
import { KTX2Loader as ye } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
9
|
+
let Le = "https://www.gstatic.com/draco/versioned/decoders/1.4.1/", De = "https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/", U, V, I;
|
|
10
|
+
function se(l) {
|
|
11
|
+
U || (U = new pe(), U.setDecoderPath(Le), U.setDecoderConfig({ type: "js" })), I || (I = new ye(), I.setTranscoderPath(De)), V || (V = he), l ? I.detectSupport(l) : console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail");
|
|
12
|
+
}
|
|
13
|
+
function ie(l) {
|
|
14
|
+
l.dracoLoader || l.setDRACOLoader(U), l.ktx2Loader || l.setKTX2Loader(I), l.meshoptDecoder || l.setMeshoptDecoder(V);
|
|
15
|
+
}
|
|
16
|
+
function Q(l) {
|
|
17
|
+
let t = new URL(window.location.href).searchParams.get(l);
|
|
18
|
+
return t == null || t === "0" || t === "false" ? !1 : t === "" ? !0 : t;
|
|
19
|
+
}
|
|
20
|
+
function me(l, e) {
|
|
21
|
+
if (e === void 0 || e.startsWith("./") || e.startsWith("http") || l === void 0)
|
|
22
|
+
return e;
|
|
23
|
+
const t = l.lastIndexOf("/");
|
|
24
|
+
if (t >= 0) {
|
|
25
|
+
const r = l.substring(0, t + 1);
|
|
26
|
+
for (; r.endsWith("/") && e.startsWith("/"); )
|
|
27
|
+
e = e.substring(1);
|
|
28
|
+
return r + e;
|
|
29
|
+
}
|
|
30
|
+
return e;
|
|
31
|
+
}
|
|
32
|
+
const H = new Array();
|
|
33
|
+
function ke(l) {
|
|
34
|
+
H.push(l);
|
|
35
|
+
}
|
|
36
|
+
const R = "NEEDLE_progressive", S = Q("debugprogressive"), q = Symbol("needle-progressive-texture"), W = /* @__PURE__ */ new Map(), J = /* @__PURE__ */ new Set();
|
|
37
|
+
if (S) {
|
|
38
|
+
let l = function() {
|
|
39
|
+
e += 1, console.log("Toggle LOD level", e, W), W.forEach((i, o) => {
|
|
40
|
+
for (const s of i.keys) {
|
|
41
|
+
const n = o[s];
|
|
42
|
+
if (n.isBufferGeometry === !0) {
|
|
43
|
+
const a = M.getMeshLODInformation(n), d = a ? Math.min(e, a.lods.length) : 0;
|
|
44
|
+
o["DEBUG:LOD"] = d, M.assignMeshLOD(o, d), a && (t = Math.max(t, a.lods.length - 1));
|
|
45
|
+
} else if (o.isMaterial === !0) {
|
|
46
|
+
o["DEBUG:LOD"] = e, M.assignTextureLOD(o, e);
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}), e >= t && (e = -1);
|
|
51
|
+
}, e = -1, t = 2, r = !1;
|
|
52
|
+
window.addEventListener("keyup", (i) => {
|
|
53
|
+
i.key === "p" && l(), i.key === "w" && (r = !r, J && J.forEach((o) => {
|
|
54
|
+
o.name != "BackgroundCubeMaterial" && "wireframe" in o && (o.wireframe = r);
|
|
55
|
+
}));
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function ee(l, e, t) {
|
|
59
|
+
var i;
|
|
60
|
+
if (!S)
|
|
61
|
+
return;
|
|
62
|
+
W.has(l) || W.set(l, { keys: [], sourceId: t });
|
|
63
|
+
const r = W.get(l);
|
|
64
|
+
((i = r == null ? void 0 : r.keys) == null ? void 0 : i.includes(e)) == !1 && r.keys.push(e);
|
|
65
|
+
}
|
|
66
|
+
const v = class {
|
|
67
|
+
constructor(e, t) {
|
|
68
|
+
u(this, "parser");
|
|
69
|
+
u(this, "url");
|
|
70
|
+
S && console.log("Progressive extension registered for", t), this.parser = e, this.url = t;
|
|
71
|
+
}
|
|
72
|
+
/** The name of the extension */
|
|
73
|
+
get name() {
|
|
74
|
+
return R;
|
|
75
|
+
}
|
|
76
|
+
static getMeshLODInformation(e) {
|
|
77
|
+
const t = this.getAssignedLODInformation(e);
|
|
78
|
+
return t != null && t.key ? this.lodInfos.get(t.key) : null;
|
|
79
|
+
}
|
|
80
|
+
/** Check if a LOD level is available for a mesh or a texture
|
|
81
|
+
* @param obj the mesh or texture to check
|
|
82
|
+
* @param level the level of detail to check for (0 is the highest resolution). If undefined, the function checks if any LOD level is available
|
|
83
|
+
* @returns true if the LOD level is available (or if any LOD level is available if level is undefined)
|
|
84
|
+
*/
|
|
85
|
+
static hasLODLevelAvailable(e, t) {
|
|
86
|
+
var o;
|
|
87
|
+
if (e.isMaterial === !0) {
|
|
88
|
+
for (const s of Object.keys(e)) {
|
|
89
|
+
const n = e[s];
|
|
90
|
+
if (n.isTexture && this.hasLODLevelAvailable(n, t))
|
|
91
|
+
return !0;
|
|
92
|
+
}
|
|
93
|
+
return !1;
|
|
94
|
+
} else if (e.isGroup === !0) {
|
|
95
|
+
for (const s of e.children)
|
|
96
|
+
if (s.isMesh === !0 && this.hasLODLevelAvailable(s, t))
|
|
97
|
+
return !0;
|
|
98
|
+
}
|
|
99
|
+
let r, i;
|
|
100
|
+
if (e.isMesh ? r = e.geometry : (e.isBufferGeometry || e.isTexture) && (r = e), r && (o = r == null ? void 0 : r.userData) != null && o.LODS) {
|
|
101
|
+
const s = r.userData.LODS;
|
|
102
|
+
if (i = this.lodInfos.get(s.key), t === void 0)
|
|
103
|
+
return i != null;
|
|
104
|
+
if (i)
|
|
105
|
+
return Array.isArray(i.lods) ? t < i.lods.length : t === 0;
|
|
106
|
+
}
|
|
107
|
+
return !1;
|
|
108
|
+
}
|
|
109
|
+
/** Load a different resolution of a mesh (if available)
|
|
110
|
+
* @param context the context
|
|
111
|
+
* @param source the sourceid of the file from which the mesh is loaded (this is usually the component's sourceId)
|
|
112
|
+
* @param mesh the mesh to load the LOD for
|
|
113
|
+
* @param level the level of detail to load (0 is the highest resolution)
|
|
114
|
+
* @returns a promise that resolves to the mesh with the requested LOD level
|
|
115
|
+
* @example
|
|
116
|
+
* ```javascript
|
|
117
|
+
* const mesh = this.gameObject as Mesh;
|
|
118
|
+
* NEEDLE_progressive.assignMeshLOD(context, sourceId, mesh, 1).then(mesh => {
|
|
119
|
+
* console.log("Mesh with LOD level 1 loaded", mesh);
|
|
120
|
+
* });
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
static assignMeshLOD(e, t) {
|
|
124
|
+
var r;
|
|
125
|
+
if (!e)
|
|
126
|
+
return Promise.resolve(null);
|
|
127
|
+
if (e instanceof Y || e.isMesh === !0) {
|
|
128
|
+
const i = e.geometry, o = this.getAssignedLODInformation(i);
|
|
129
|
+
if (!o)
|
|
130
|
+
return Promise.resolve(null);
|
|
131
|
+
for (const s of H)
|
|
132
|
+
(r = s.onBeforeGetLODMesh) == null || r.call(s, e, t);
|
|
133
|
+
return e["LOD:requested level"] = t, v.getOrLoadLOD(i, t).then((s) => {
|
|
134
|
+
if (e["LOD:requested level"] === t) {
|
|
135
|
+
if (delete e["LOD:requested level"], Array.isArray(s)) {
|
|
136
|
+
const n = o.index || 0;
|
|
137
|
+
s = s[n];
|
|
138
|
+
}
|
|
139
|
+
s && i != s && s instanceof X && (e.geometry = s, S && ee(e, "geometry", o.url));
|
|
140
|
+
}
|
|
141
|
+
return s;
|
|
142
|
+
}).catch((s) => (console.error("Error loading mesh LOD", e, s), null));
|
|
143
|
+
} else
|
|
144
|
+
S && console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh", e);
|
|
145
|
+
return Promise.resolve(null);
|
|
146
|
+
}
|
|
147
|
+
/** Load a different resolution of a texture (if available)
|
|
148
|
+
* @param context the context
|
|
149
|
+
* @param source the sourceid of the file from which the texture is loaded (this is usually the component's sourceId)
|
|
150
|
+
* @param materialOrTexture the material or texture to load the LOD for (if passing in a material all textures in the material will be loaded)
|
|
151
|
+
* @param level the level of detail to load (0 is the highest resolution) - currently only 0 is supported
|
|
152
|
+
* @returns a promise that resolves to the material or texture with the requested LOD level
|
|
153
|
+
*/
|
|
154
|
+
static assignTextureLOD(e, t = 0) {
|
|
155
|
+
if (!e)
|
|
156
|
+
return Promise.resolve(null);
|
|
157
|
+
if (e instanceof le || e.isMaterial === !0) {
|
|
158
|
+
const r = e, i = [], o = new Array();
|
|
159
|
+
if (S && J.add(r), r instanceof ue)
|
|
160
|
+
for (const s of Object.keys(r.uniforms)) {
|
|
161
|
+
const n = r.uniforms[s].value;
|
|
162
|
+
if ((n == null ? void 0 : n.isTexture) === !0) {
|
|
163
|
+
const a = this.assignTextureLODForSlot(n, t, r, s);
|
|
164
|
+
i.push(a), o.push(s);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else
|
|
168
|
+
for (const s of Object.keys(r)) {
|
|
169
|
+
const n = r[s];
|
|
170
|
+
if ((n == null ? void 0 : n.isTexture) === !0) {
|
|
171
|
+
const a = this.assignTextureLODForSlot(n, t, r, s);
|
|
172
|
+
i.push(a), o.push(s);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return Promise.all(i).then((s) => {
|
|
176
|
+
const n = new Array();
|
|
177
|
+
for (let a = 0; a < s.length; a++) {
|
|
178
|
+
const d = s[a], f = o[a];
|
|
179
|
+
d && d.isTexture === !0 ? n.push({ material: r, slot: f, texture: d, level: t }) : n.push({ material: r, slot: f, texture: null, level: t });
|
|
180
|
+
}
|
|
181
|
+
return n;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
if (e instanceof z || e.isTexture === !0) {
|
|
185
|
+
const r = e;
|
|
186
|
+
return this.assignTextureLODForSlot(r, t, null, null);
|
|
187
|
+
}
|
|
188
|
+
return Promise.resolve(null);
|
|
189
|
+
}
|
|
190
|
+
static assignTextureLODForSlot(e, t, r, i) {
|
|
191
|
+
return (e == null ? void 0 : e.isTexture) !== !0 ? Promise.resolve(null) : v.getOrLoadLOD(e, t).then((o) => {
|
|
192
|
+
if (Array.isArray(o))
|
|
193
|
+
return null;
|
|
194
|
+
if ((o == null ? void 0 : o.isTexture) === !0) {
|
|
195
|
+
if (o != e && (r && i && (r[i] = o), S && i && r)) {
|
|
196
|
+
const s = this.getAssignedLODInformation(e);
|
|
197
|
+
s && ee(r, i, s.url);
|
|
198
|
+
}
|
|
199
|
+
return o;
|
|
200
|
+
} else
|
|
201
|
+
S == "verbose" && console.warn("No LOD found for", e, t);
|
|
202
|
+
return null;
|
|
203
|
+
}).catch((o) => (console.error("Error loading LOD", e, o), null));
|
|
204
|
+
}
|
|
205
|
+
afterRoot(e) {
|
|
206
|
+
var t, r;
|
|
207
|
+
return S && console.log("AFTER", this.url, e), (t = this.parser.json.textures) == null || t.forEach((i, o) => {
|
|
208
|
+
if (i != null && i.extensions) {
|
|
209
|
+
const s = i == null ? void 0 : i.extensions[R];
|
|
210
|
+
if (s) {
|
|
211
|
+
let n = !1;
|
|
212
|
+
for (const a of this.parser.associations.keys())
|
|
213
|
+
a.isTexture === !0 && this.parser.associations.get(a).textures === o && (n = !0, v.registerTexture(this.url, a, o, s));
|
|
214
|
+
n || this.parser.getDependency("texture", o).then((a) => {
|
|
215
|
+
a && v.registerTexture(this.url, a, o, s);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}), (r = this.parser.json.meshes) == null || r.forEach((i, o) => {
|
|
220
|
+
if (i != null && i.extensions) {
|
|
221
|
+
const s = i == null ? void 0 : i.extensions[R];
|
|
222
|
+
if (s && s.lods) {
|
|
223
|
+
for (const n of this.parser.associations.keys())
|
|
224
|
+
if (n.isMesh) {
|
|
225
|
+
const a = this.parser.associations.get(n);
|
|
226
|
+
a.meshes === o && v.registerMesh(this.url, n.uuid, n, s.lods.length, a.primitives, s);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}), null;
|
|
231
|
+
}
|
|
232
|
+
static async getOrLoadLOD(e, t) {
|
|
233
|
+
var n, a, d;
|
|
234
|
+
const r = S == "verbose", i = e.userData.LODS;
|
|
235
|
+
if (!i)
|
|
236
|
+
return null;
|
|
237
|
+
const o = i == null ? void 0 : i.key;
|
|
238
|
+
let s;
|
|
239
|
+
if (e.isTexture === !0) {
|
|
240
|
+
const f = e;
|
|
241
|
+
f.source && f.source[q] && (s = f.source[q]);
|
|
242
|
+
}
|
|
243
|
+
if (s || (s = v.lodInfos.get(o)), s) {
|
|
244
|
+
if (t > 0) {
|
|
245
|
+
let g = !1;
|
|
246
|
+
const w = Array.isArray(s.lods);
|
|
247
|
+
if (w && t >= s.lods.length ? g = !0 : w || (g = !0), g)
|
|
248
|
+
return this.lowresCache.get(o);
|
|
249
|
+
}
|
|
250
|
+
const f = Array.isArray(s.lods) ? s.lods[t].path : s.lods;
|
|
251
|
+
if (!f)
|
|
252
|
+
return S && !s["missing:uri"] && (s["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + t, s)), null;
|
|
253
|
+
const L = me(i.url, f);
|
|
254
|
+
if (L.endsWith(".glb") || L.endsWith(".gltf")) {
|
|
255
|
+
if (!s.guid)
|
|
256
|
+
return console.warn("missing pointer for glb/gltf texture", s), null;
|
|
257
|
+
const g = L + "_" + s.guid, w = this.previouslyLoaded.get(g);
|
|
258
|
+
if (w !== void 0) {
|
|
259
|
+
r && console.log(`LOD ${t} was already loading/loaded: ${g}`);
|
|
260
|
+
let m = await w.catch((E) => (console.error(`Error loading LOD ${t} from ${L}
|
|
261
|
+
`, E), null)), B = !1;
|
|
262
|
+
if (m == null || (m instanceof z && e instanceof z ? (n = m.image) != null && n.data || (a = m.source) != null && a.data ? m = this.copySettings(e, m) : (B = !0, this.previouslyLoaded.delete(g)) : m instanceof X && e instanceof X && ((d = m.attributes.position) != null && d.array || (B = !0, this.previouslyLoaded.delete(g)))), !B)
|
|
263
|
+
return m;
|
|
264
|
+
}
|
|
265
|
+
const D = s, P = new Promise(async (m, B) => {
|
|
266
|
+
const E = new ge();
|
|
267
|
+
ie(E), S && (await new Promise((p) => setTimeout(p, 1e3)), r && console.warn("Start loading (delayed) " + L, D.guid));
|
|
268
|
+
let y = L;
|
|
269
|
+
if (D && Array.isArray(D.lods)) {
|
|
270
|
+
const p = D.lods[t];
|
|
271
|
+
p.hash && (y += "?v=" + p.hash);
|
|
272
|
+
}
|
|
273
|
+
const h = await E.loadAsync(y).catch((p) => (console.error(`Error loading LOD ${t} from ${L}
|
|
274
|
+
`, p), null));
|
|
275
|
+
if (!h)
|
|
276
|
+
return null;
|
|
277
|
+
const T = h.parser;
|
|
278
|
+
r && console.log("Loading finished " + L, D.guid);
|
|
279
|
+
let x = 0;
|
|
280
|
+
if (h.parser.json.textures) {
|
|
281
|
+
let p = !1;
|
|
282
|
+
for (const c of h.parser.json.textures) {
|
|
283
|
+
if (c != null && c.extensions) {
|
|
284
|
+
const O = c == null ? void 0 : c.extensions[R];
|
|
285
|
+
if (O != null && O.guid && O.guid === D.guid) {
|
|
286
|
+
p = !0;
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
x++;
|
|
291
|
+
}
|
|
292
|
+
if (p) {
|
|
293
|
+
let c = await T.getDependency("texture", x);
|
|
294
|
+
return r && console.log('change "' + e.name + '" → "' + c.name + '"', L, x, c, g), e instanceof z && (c = this.copySettings(e, c)), c && (c.guid = D.guid), m(c);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (x = 0, h.parser.json.meshes) {
|
|
298
|
+
let p = !1;
|
|
299
|
+
for (const c of h.parser.json.meshes) {
|
|
300
|
+
if (c != null && c.extensions) {
|
|
301
|
+
const O = c == null ? void 0 : c.extensions[R];
|
|
302
|
+
if (O != null && O.guid && O.guid === D.guid) {
|
|
303
|
+
p = !0;
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
x++;
|
|
308
|
+
}
|
|
309
|
+
if (p) {
|
|
310
|
+
const c = await T.getDependency("mesh", x), O = D;
|
|
311
|
+
if (r && console.log(`Loaded Mesh "${c.name}"`, L, x, c, g), c.isMesh === !0) {
|
|
312
|
+
const b = c.geometry;
|
|
313
|
+
return v.assignLODInformation(i.url, b, o, t, void 0, O.density), m(b);
|
|
314
|
+
} else {
|
|
315
|
+
const b = new Array();
|
|
316
|
+
for (let _ = 0; _ < c.children.length; _++) {
|
|
317
|
+
const F = c.children[_];
|
|
318
|
+
if (F instanceof Y) {
|
|
319
|
+
const $ = F.geometry;
|
|
320
|
+
v.assignLODInformation(i.url, $, o, t, _, O.density), b.push($);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return m(b);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return m(null);
|
|
328
|
+
});
|
|
329
|
+
return this.previouslyLoaded.set(g, P), await P;
|
|
330
|
+
} else if (e instanceof z) {
|
|
331
|
+
r && console.log("Load texture from uri: " + L);
|
|
332
|
+
const w = await new ce().loadAsync(L);
|
|
333
|
+
return w ? (w.guid = s.guid, w.flipY = !1, w.needsUpdate = !0, w.colorSpace = e.colorSpace, r && console.log(s, w)) : S && console.warn("failed loading", L), w;
|
|
334
|
+
}
|
|
335
|
+
} else
|
|
336
|
+
S && console.warn(`Can not load LOD ${t}: no LOD info found for "${o}" ${e.name}`, e.type);
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
static assignLODInformation(e, t, r, i, o, s) {
|
|
340
|
+
if (!t)
|
|
341
|
+
return;
|
|
342
|
+
t.userData || (t.userData = {});
|
|
343
|
+
const n = new xe(e, r, i, o, s);
|
|
344
|
+
t.userData.LODS = n, t.userData.LOD = i;
|
|
345
|
+
}
|
|
346
|
+
static getAssignedLODInformation(e) {
|
|
347
|
+
var t;
|
|
348
|
+
return ((t = e == null ? void 0 : e.userData) == null ? void 0 : t.LODS) || null;
|
|
349
|
+
}
|
|
350
|
+
static copySettings(e, t) {
|
|
351
|
+
const r = this._copiedTextures.get(e);
|
|
352
|
+
return r || (t = t.clone(), this._copiedTextures.set(e, t), t.offset = e.offset, t.repeat = e.repeat, t.colorSpace = e.colorSpace, t);
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
let M = v;
|
|
356
|
+
/**
|
|
357
|
+
* Register a texture with LOD information
|
|
358
|
+
*/
|
|
359
|
+
u(M, "registerTexture", (e, t, r, i) => {
|
|
360
|
+
S && console.log("> Progressive: register texture", r, t.name, t.uuid, t, i), t.source && (t.source[q] = i);
|
|
361
|
+
const o = t.uuid;
|
|
362
|
+
v.assignLODInformation(e, t, o, 0, 0, void 0), v.lodInfos.set(o, i), v.lowresCache.set(o, t);
|
|
363
|
+
}), /**
|
|
364
|
+
* Register a mesh with LOD information
|
|
365
|
+
*/
|
|
366
|
+
u(M, "registerMesh", (e, t, r, i, o, s) => {
|
|
367
|
+
var d;
|
|
368
|
+
S && console.log("> Progressive: register mesh", o, r.name, s, r.uuid, r);
|
|
369
|
+
const n = r.geometry;
|
|
370
|
+
n.userData || (n.userData = {}), v.assignLODInformation(e, n, t, i, o, s.density), v.lodInfos.set(t, s);
|
|
371
|
+
let a = v.lowresCache.get(t);
|
|
372
|
+
a ? a.push(r.geometry) : a = [r.geometry], v.lowresCache.set(t, a);
|
|
373
|
+
for (const f of H)
|
|
374
|
+
(d = f.onRegisteredNewMesh) == null || d.call(f, r, s);
|
|
375
|
+
}), /** A map of key = asset uuid and value = LOD information */
|
|
376
|
+
u(M, "lodInfos", /* @__PURE__ */ new Map()), /** cache of already loaded mesh lods */
|
|
377
|
+
u(M, "previouslyLoaded", /* @__PURE__ */ new Map()), /** this contains the geometry/textures that were originally loaded */
|
|
378
|
+
u(M, "lowresCache", /* @__PURE__ */ new Map()), u(M, "_copiedTextures", /* @__PURE__ */ new Map());
|
|
379
|
+
class xe {
|
|
380
|
+
constructor(e, t, r, i, o) {
|
|
381
|
+
u(this, "url");
|
|
382
|
+
/** the key to lookup the LOD information */
|
|
383
|
+
u(this, "key");
|
|
384
|
+
u(this, "level");
|
|
385
|
+
/** For multi objects (e.g. a group of meshes) this is the index of the object */
|
|
386
|
+
u(this, "index");
|
|
387
|
+
/** the mesh density */
|
|
388
|
+
u(this, "density");
|
|
389
|
+
this.url = e, this.key = t, this.level = r, i != null && (this.index = i), o != null && (this.density = o);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
let te = Q("debugprogressive");
|
|
393
|
+
const we = Q("noprogressive"), A = class {
|
|
394
|
+
constructor(e) {
|
|
395
|
+
u(this, "renderer");
|
|
396
|
+
u(this, "projectionScreenMatrix", new Z());
|
|
397
|
+
u(this, "cameraFrustrum", new fe());
|
|
398
|
+
u(this, "updateInterval", 0);
|
|
399
|
+
u(this, "pause", !1);
|
|
400
|
+
u(this, "plugins", []);
|
|
401
|
+
u(this, "_originalRender");
|
|
402
|
+
// private testIfLODLevelsAreAvailable() {
|
|
403
|
+
u(this, "_sphere", new de());
|
|
404
|
+
u(this, "_tempBox", new j());
|
|
405
|
+
u(this, "tempMatrix", new Z());
|
|
406
|
+
u(this, "_tempWorldPosition", new C());
|
|
407
|
+
u(this, "_tempBoxSize", new C());
|
|
408
|
+
u(this, "_tempBox2Size", new C());
|
|
409
|
+
this.renderer = e;
|
|
410
|
+
}
|
|
411
|
+
enable() {
|
|
412
|
+
if (this._originalRender)
|
|
413
|
+
return;
|
|
414
|
+
let e = 0;
|
|
415
|
+
this._originalRender = this.renderer.render;
|
|
416
|
+
const t = this;
|
|
417
|
+
let r = 0;
|
|
418
|
+
se(this.renderer), this.renderer.render = function(i, o) {
|
|
419
|
+
const s = r++, n = e++;
|
|
420
|
+
t.onBeforeRender(i, o, n, s), t._originalRender.call(this, i, o), t.onAfterRender(i, o, n, s), e--;
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
disable() {
|
|
424
|
+
this._originalRender && (this.renderer.render = this._originalRender, this._originalRender = void 0);
|
|
425
|
+
}
|
|
426
|
+
onBeforeRender(e, t, r, i) {
|
|
427
|
+
}
|
|
428
|
+
onAfterRender(e, t, r, i) {
|
|
429
|
+
if (we || this.pause || this.updateInterval > 0 && i % this.updateInterval != 0)
|
|
430
|
+
return;
|
|
431
|
+
this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix, t.matrixWorldInverse), this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix, this.renderer.coordinateSystem);
|
|
432
|
+
const o = 1e5, n = this.renderer.renderLists.get(e, r).opaque;
|
|
433
|
+
for (const a of n) {
|
|
434
|
+
const d = a.object;
|
|
435
|
+
(d instanceof Y || d.isMesh) && this.updateLODs(e, t, d, o);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
static getObjectLODState(e) {
|
|
439
|
+
var t;
|
|
440
|
+
return (t = e.userData) == null ? void 0 : t.LOD_state;
|
|
441
|
+
}
|
|
442
|
+
/** Update the LOD levels for the renderer. */
|
|
443
|
+
updateLODs(e, t, r, i) {
|
|
444
|
+
var a, d;
|
|
445
|
+
for (const f of this.plugins)
|
|
446
|
+
(a = f.onBeforeUpdateLOD) == null || a.call(f, this.renderer, e, t, r);
|
|
447
|
+
let o = r.userData.LOD_state;
|
|
448
|
+
o || (o = new Oe(), r.userData.LOD_state = o);
|
|
449
|
+
let s = this.calculateLodLevel(t, r, o, i);
|
|
450
|
+
s = Math.round(s), s >= 0 && this.loadProgressiveMeshes(r, s);
|
|
451
|
+
let n = 0;
|
|
452
|
+
if (r.material) {
|
|
453
|
+
const f = r["DEBUG:LOD"];
|
|
454
|
+
if (f != null && (n = f), Array.isArray(r.material))
|
|
455
|
+
for (const L of r.material)
|
|
456
|
+
this.loadProgressiveTextures(L, n);
|
|
457
|
+
else
|
|
458
|
+
this.loadProgressiveTextures(r.material, n);
|
|
459
|
+
}
|
|
460
|
+
for (const f of this.plugins)
|
|
461
|
+
(d = f.onAfterUpdatedLOD) == null || d.call(f, this.renderer, e, t, r, s);
|
|
462
|
+
o.lastLodLevel = s;
|
|
463
|
+
}
|
|
464
|
+
/** Load progressive textures for the given material
|
|
465
|
+
* @param material the material to load the textures for
|
|
466
|
+
* @param level the LOD level to load. Level 0 is the best quality, higher levels are lower quality
|
|
467
|
+
* @returns Promise with true if the LOD was loaded, false if not
|
|
468
|
+
*/
|
|
469
|
+
loadProgressiveTextures(e, t) {
|
|
470
|
+
return e && e.userData && e.userData.LOD !== t ? (e.userData.LOD = t, M.assignTextureLOD(e, t)) : Promise.resolve(null);
|
|
471
|
+
}
|
|
472
|
+
/** Load progressive meshes for the given mesh
|
|
473
|
+
* @param mesh the mesh to load the LOD for
|
|
474
|
+
* @param index the index of the mesh if it's part of a group
|
|
475
|
+
* @param level the LOD level to load. Level 0 is the best quality, higher levels are lower quality
|
|
476
|
+
* @returns Promise with true if the LOD was loaded, false if not
|
|
477
|
+
*/
|
|
478
|
+
loadProgressiveMeshes(e, t) {
|
|
479
|
+
if (!e)
|
|
480
|
+
return Promise.resolve(null);
|
|
481
|
+
if (e.userData || (e.userData = {}), e.userData.LOD !== t) {
|
|
482
|
+
e.userData.LOD = t;
|
|
483
|
+
const r = e.geometry;
|
|
484
|
+
return M.assignMeshLOD(e, t).then((i) => (i && e.userData.LOD == t && r != e.geometry, i));
|
|
485
|
+
}
|
|
486
|
+
return Promise.resolve(null);
|
|
487
|
+
}
|
|
488
|
+
calculateLodLevel(e, t, r, i) {
|
|
489
|
+
var n;
|
|
490
|
+
if (!t)
|
|
491
|
+
return -1;
|
|
492
|
+
let s = 10 + 1;
|
|
493
|
+
if (e) {
|
|
494
|
+
if (te && t["DEBUG:LOD"] != null)
|
|
495
|
+
return t["DEBUG:LOD"];
|
|
496
|
+
const a = M.getMeshLODInformation(t.geometry), d = a == null ? void 0 : a.lods;
|
|
497
|
+
if (!d || d.length <= 0 || !((n = this.cameraFrustrum) != null && n.intersectsObject(t)))
|
|
498
|
+
return 99;
|
|
499
|
+
const f = t.geometry.boundingBox;
|
|
500
|
+
if (f && e.isPerspectiveCamera) {
|
|
501
|
+
const L = e;
|
|
502
|
+
if (t.geometry.attributes.color && t.geometry.attributes.color.count < 100 && t.geometry.boundingSphere) {
|
|
503
|
+
this._sphere.copy(t.geometry.boundingSphere), this._sphere.applyMatrix4(t.matrixWorld);
|
|
504
|
+
const y = e.getWorldPosition(this._tempWorldPosition);
|
|
505
|
+
if (this._sphere.containsPoint(y))
|
|
506
|
+
return 0;
|
|
507
|
+
}
|
|
508
|
+
if (this._tempBox.copy(f), this._tempBox.applyMatrix4(t.matrixWorld), this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && L.fov > 70) {
|
|
509
|
+
const y = this._tempBox.min, h = this._tempBox.max;
|
|
510
|
+
let T = y.x, x = y.y, p = h.x, c = h.y;
|
|
511
|
+
const O = 2, b = 1.5, _ = (y.x + h.x) * 0.5, F = (y.y + h.y) * 0.5;
|
|
512
|
+
T = (T - _) * O + _, x = (x - F) * O + F, p = (p - _) * O + _, c = (c - F) * O + F;
|
|
513
|
+
const $ = T < 0 && p > 0 ? 0 : Math.min(Math.abs(y.x), Math.abs(h.x)), oe = x < 0 && c > 0 ? 0 : Math.min(Math.abs(y.y), Math.abs(h.y)), N = Math.max($, oe);
|
|
514
|
+
r.lastCentrality = (b - N) * (b - N) * (b - N);
|
|
515
|
+
} else
|
|
516
|
+
r.lastCentrality = 1;
|
|
517
|
+
const g = this._tempBox.getSize(this._tempBoxSize);
|
|
518
|
+
g.multiplyScalar(0.5), screen.availHeight > 0 && g.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), g.x *= L.aspect;
|
|
519
|
+
const w = e.matrixWorldInverse, D = new j();
|
|
520
|
+
D.copy(f), D.applyMatrix4(t.matrixWorld), D.applyMatrix4(w);
|
|
521
|
+
const P = D.getSize(this._tempBox2Size), G = Math.max(P.x, P.y);
|
|
522
|
+
if (Math.max(g.x, g.y) != 0 && G != 0 && (g.z = P.z / Math.max(P.x, P.y) * Math.max(g.x, g.y)), r.lastScreenCoverage = Math.max(g.x, g.y, g.z), r.lastScreenspaceVolume.copy(g), r.lastScreenCoverage *= r.lastCentrality, te && A.debugDrawLine) {
|
|
523
|
+
const y = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
524
|
+
y.invert();
|
|
525
|
+
const h = A.corner0, T = A.corner1, x = A.corner2, p = A.corner3;
|
|
526
|
+
h.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = h.x, x.copy(this._tempBox.max), x.y = h.y, p.copy(this._tempBox.max);
|
|
527
|
+
const c = (h.z + p.z) * 0.5;
|
|
528
|
+
h.z = T.z = x.z = p.z = c, h.applyMatrix4(y), T.applyMatrix4(y), x.applyMatrix4(y), p.applyMatrix4(y), A.debugDrawLine(h, T, 255), A.debugDrawLine(h, x, 255), A.debugDrawLine(T, p, 255), A.debugDrawLine(x, p, 255);
|
|
529
|
+
}
|
|
530
|
+
let B = 999;
|
|
531
|
+
if (d && r.lastScreenCoverage > 0) {
|
|
532
|
+
for (let y = 0; y < d.length; y++)
|
|
533
|
+
if (d[y].density / r.lastScreenCoverage < i) {
|
|
534
|
+
B = y;
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
B < s && (s = B);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
return s;
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
let k = A;
|
|
545
|
+
u(k, "corner0", new C()), u(k, "corner1", new C()), u(k, "corner2", new C()), u(k, "corner3", new C()), u(k, "debugDrawLine");
|
|
546
|
+
class Oe {
|
|
547
|
+
constructor() {
|
|
548
|
+
u(this, "lastLodLevel", 0);
|
|
549
|
+
u(this, "lastScreenCoverage", 0);
|
|
550
|
+
u(this, "lastScreenspaceVolume", new C());
|
|
551
|
+
u(this, "lastCentrality", 0);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
const re = Symbol("NEEDLE_mesh_lod"), K = Symbol("NEEDLE_texture_lod");
|
|
555
|
+
function ve() {
|
|
556
|
+
const l = document.querySelector("model-viewer");
|
|
557
|
+
if (!l)
|
|
558
|
+
return;
|
|
559
|
+
let e = null;
|
|
560
|
+
for (let t = l; t != null; t = Object.getPrototypeOf(t)) {
|
|
561
|
+
const i = Object.getOwnPropertySymbols(t).find((o) => o.toString() == "Symbol(renderer)");
|
|
562
|
+
!e && i != null && (e = l[i].threeRenderer);
|
|
563
|
+
}
|
|
564
|
+
if (e) {
|
|
565
|
+
console.log("Adding Needle LODs to modelviewer");
|
|
566
|
+
const t = new k(e);
|
|
567
|
+
t.plugins.push(new Me(l)), t.enable();
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
class Me {
|
|
571
|
+
constructor(e) {
|
|
572
|
+
u(this, "modelviewer");
|
|
573
|
+
this.modelviewer = e;
|
|
574
|
+
}
|
|
575
|
+
onBeforeUpdateLOD(e, t, r, i) {
|
|
576
|
+
this.tryParseMeshLOD(t, i), this.tryParseTextureLOD(t, i);
|
|
577
|
+
}
|
|
578
|
+
getUrl() {
|
|
579
|
+
return this.modelviewer.getAttribute("src");
|
|
580
|
+
}
|
|
581
|
+
tryGetCurrentGLTF(e) {
|
|
582
|
+
return e._currentGLTF;
|
|
583
|
+
}
|
|
584
|
+
tryParseTextureLOD(e, t) {
|
|
585
|
+
if (t[K] == !0)
|
|
586
|
+
return;
|
|
587
|
+
t[K] = !0;
|
|
588
|
+
const r = this.tryGetCurrentGLTF(e), i = this.getUrl();
|
|
589
|
+
if (!i) {
|
|
590
|
+
console.error("No url found in modelviewer");
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
if (r && t.material) {
|
|
594
|
+
let o = function(n) {
|
|
595
|
+
var d, f, L;
|
|
596
|
+
if (n[K] == !0)
|
|
597
|
+
return;
|
|
598
|
+
n[K] = !0, n.userData && (n.userData.LOD = -1);
|
|
599
|
+
const a = Object.keys(n);
|
|
600
|
+
for (let g = 0; g < a.length; g++) {
|
|
601
|
+
const w = a[g], D = n[w];
|
|
602
|
+
if ((D == null ? void 0 : D.isTexture) === !0) {
|
|
603
|
+
const P = (f = (d = D.userData) == null ? void 0 : d.associations) == null ? void 0 : f.textures, G = r.parser.json.textures[P];
|
|
604
|
+
if ((L = G.extensions) != null && L[R]) {
|
|
605
|
+
const m = G.extensions[R];
|
|
606
|
+
m && i && M.registerTexture(i, D, m.lods.length, m);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
const s = t.material;
|
|
612
|
+
if (Array.isArray(s))
|
|
613
|
+
for (const n of s)
|
|
614
|
+
o(n);
|
|
615
|
+
else
|
|
616
|
+
o(s);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
tryParseMeshLOD(e, t) {
|
|
620
|
+
var o, s;
|
|
621
|
+
if (t[re] == !0)
|
|
622
|
+
return;
|
|
623
|
+
t[re] = !0;
|
|
624
|
+
const r = this.getUrl();
|
|
625
|
+
if (!r) {
|
|
626
|
+
console.error("No url found in modelviewer");
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
const i = (s = (o = t.userData) == null ? void 0 : o.gltfExtensions) == null ? void 0 : s[R];
|
|
630
|
+
if (i && r) {
|
|
631
|
+
const n = t.uuid;
|
|
632
|
+
M.registerMesh(r, n, t, 0, i.lods.length, i);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
function Be(l, e, t) {
|
|
637
|
+
se(e), ie(t), t.register((i) => new M(i, l));
|
|
638
|
+
const r = new k(e);
|
|
639
|
+
return r.enable(), r;
|
|
640
|
+
}
|
|
641
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
642
|
+
ve();
|
|
643
|
+
});
|
|
644
|
+
export {
|
|
645
|
+
R as EXTENSION_NAME,
|
|
646
|
+
k as LODsManager,
|
|
647
|
+
M as NEEDLE_progressive,
|
|
648
|
+
ve as patchModelViewer,
|
|
649
|
+
ke as registerPlugin,
|
|
650
|
+
Be as useNeedleGLTFProgressive
|
|
651
|
+
};
|