@needle-tools/gltf-progressive 3.3.5 → 3.4.0-beta.1
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/NEEDLE_progressive/README.md +45 -47
- package/gltf-progressive.js +697 -569
- package/gltf-progressive.min.js +9 -7
- package/gltf-progressive.umd.cjs +9 -7
- package/lib/extension.d.ts +31 -3
- package/lib/extension.js +301 -56
- package/lib/utils.internal.d.ts +6 -0
- package/lib/utils.internal.js +92 -0
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/gltf-progressive.js
CHANGED
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
import { BufferGeometry as
|
|
2
|
-
import { GLTFLoader as
|
|
3
|
-
import { MeshoptDecoder as
|
|
4
|
-
import { DRACOLoader as
|
|
5
|
-
import { KTX2Loader as
|
|
6
|
-
const
|
|
7
|
-
globalThis.GLTF_PROGRESSIVE_VERSION =
|
|
1
|
+
import { BufferGeometry as V, Mesh as X, Box3 as ge, Vector3 as A, Sphere as Oe, CompressedTexture as Ge, Texture as F, Matrix3 as Fe, InterleavedBuffer as We, InterleavedBufferAttribute as Ue, BufferAttribute as ze, TextureLoader as Ne, Matrix4 as Le, Clock as qe, MeshStandardMaterial as Ee } from "three";
|
|
2
|
+
import { GLTFLoader as xe } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
3
|
+
import { MeshoptDecoder as Ve } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
4
|
+
import { DRACOLoader as Xe } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
5
|
+
import { KTX2Loader as je } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
6
|
+
const Ke = "";
|
|
7
|
+
globalThis.GLTF_PROGRESSIVE_VERSION = Ke;
|
|
8
8
|
console.debug("[gltf-progressive] version -");
|
|
9
|
-
let
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
fetch(
|
|
9
|
+
let I = "https://www.gstatic.com/draco/versioned/decoders/1.5.7/", j = "https://cdn.needle.tools/static/three/0.179.1/basis2/";
|
|
10
|
+
const Ye = I, He = j, Se = new URL(I + "draco_decoder.js");
|
|
11
|
+
Se.searchParams.append("range", "true");
|
|
12
|
+
fetch(Se, {
|
|
13
13
|
method: "GET",
|
|
14
14
|
headers: {
|
|
15
15
|
Range: "bytes=0-1"
|
|
16
16
|
}
|
|
17
|
-
}).catch((
|
|
18
|
-
console.debug(`Failed to fetch remote Draco decoder from ${
|
|
17
|
+
}).catch((n) => {
|
|
18
|
+
console.debug(`Failed to fetch remote Draco decoder from ${I} (offline: ${typeof navigator < "u" ? navigator.onLine : "unknown"})`), I === Ye && Je("./include/draco/"), j === He && Ze("./include/ktx2/");
|
|
19
19
|
}).finally(() => {
|
|
20
|
-
|
|
20
|
+
Te();
|
|
21
21
|
});
|
|
22
|
-
const
|
|
23
|
-
dracoDecoderPath:
|
|
24
|
-
ktx2TranscoderPath:
|
|
22
|
+
const Qe = () => ({
|
|
23
|
+
dracoDecoderPath: I,
|
|
24
|
+
ktx2TranscoderPath: j
|
|
25
25
|
});
|
|
26
|
-
function
|
|
27
|
-
|
|
26
|
+
function Je(n) {
|
|
27
|
+
I = n, C && C[pe] != I ? (console.debug("Updating Draco decoder path to " + n), C[pe] = I, C.setDecoderPath(I), C.preload()) : console.debug("Setting Draco decoder path to " + n);
|
|
28
28
|
}
|
|
29
|
-
function
|
|
30
|
-
|
|
29
|
+
function Ze(n) {
|
|
30
|
+
j = n, $ && $.transcoderPath != j ? (console.debug("Updating KTX2 transcoder path to " + n), $.setTranscoderPath(j), $.init()) : console.debug("Setting KTX2 transcoder path to " + n);
|
|
31
31
|
}
|
|
32
|
-
function
|
|
33
|
-
return
|
|
32
|
+
function we(n) {
|
|
33
|
+
return Te(), n ? $.detectSupport(n) : n !== null && console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"), { dracoLoader: C, ktx2Loader: $, meshoptDecoder: oe };
|
|
34
34
|
}
|
|
35
|
-
function
|
|
36
|
-
|
|
35
|
+
function Pe(n) {
|
|
36
|
+
n.dracoLoader || n.setDRACOLoader(C), n.ktx2Loader || n.setKTX2Loader($), n.meshoptDecoder || n.setMeshoptDecoder(oe);
|
|
37
37
|
}
|
|
38
|
-
const
|
|
39
|
-
let
|
|
40
|
-
function
|
|
41
|
-
|
|
38
|
+
const pe = /* @__PURE__ */ Symbol("dracoDecoderPath");
|
|
39
|
+
let C, oe, $;
|
|
40
|
+
function Te() {
|
|
41
|
+
C || (C = new Xe(), C[pe] = I, C.setDecoderPath(I), C.setDecoderConfig({ type: "js" }), C.preload()), $ || ($ = new je(), $.setTranscoderPath(j), $.init()), oe || (oe = Ve);
|
|
42
42
|
}
|
|
43
|
-
const
|
|
44
|
-
function
|
|
45
|
-
let e =
|
|
46
|
-
e ? e = Object.assign(e, t) : e = t,
|
|
43
|
+
const me = /* @__PURE__ */ new WeakMap();
|
|
44
|
+
function Ce(n, t) {
|
|
45
|
+
let e = me.get(n);
|
|
46
|
+
e ? e = Object.assign(e, t) : e = t, me.set(n, e);
|
|
47
47
|
}
|
|
48
|
-
const
|
|
49
|
-
function
|
|
50
|
-
const t =
|
|
51
|
-
let e =
|
|
48
|
+
const et = xe.prototype.load;
|
|
49
|
+
function tt(...n) {
|
|
50
|
+
const t = me.get(this);
|
|
51
|
+
let e = n[0];
|
|
52
52
|
const s = new URL(e, window.location.href);
|
|
53
53
|
if (s.hostname.endsWith("needle.tools")) {
|
|
54
|
-
const
|
|
55
|
-
|
|
54
|
+
const i = t?.progressive !== void 0 ? t.progressive : !0, o = t?.usecase ? t.usecase : "default";
|
|
55
|
+
i ? this.requestHeader.Accept = `*/*;progressive=allowed;usecase=${o}` : this.requestHeader.Accept = `*/*;usecase=${o}`, e = s.toString();
|
|
56
56
|
}
|
|
57
|
-
return
|
|
57
|
+
return n[0] = e, et?.call(this, ...n);
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
function
|
|
59
|
+
xe.prototype.load = tt;
|
|
60
|
+
N("debugprogressive");
|
|
61
|
+
function N(n) {
|
|
62
62
|
if (typeof window > "u") return !1;
|
|
63
|
-
const e = new URL(window.location.href).searchParams.get(
|
|
63
|
+
const e = new URL(window.location.href).searchParams.get(n);
|
|
64
64
|
return e == null || e === "0" || e === "false" ? !1 : e === "" ? !0 : e;
|
|
65
65
|
}
|
|
66
|
-
function
|
|
67
|
-
if (t === void 0 ||
|
|
66
|
+
function st(n, t) {
|
|
67
|
+
if (t === void 0 || n === void 0 || t.startsWith("./") || t.startsWith("http") || t.startsWith("data:") || t.startsWith("blob:"))
|
|
68
68
|
return t;
|
|
69
|
-
const e =
|
|
69
|
+
const e = n.lastIndexOf("/");
|
|
70
70
|
if (e >= 0) {
|
|
71
|
-
const s =
|
|
71
|
+
const s = n.substring(0, e + 1);
|
|
72
72
|
for (; s.endsWith("/") && t.startsWith("/"); ) t = t.substring(1);
|
|
73
73
|
return s + t;
|
|
74
74
|
}
|
|
75
75
|
return t;
|
|
76
76
|
}
|
|
77
77
|
function Ae() {
|
|
78
|
-
return
|
|
78
|
+
return H !== void 0 || (H = /iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent), N("debugprogressive") && console.log("[glTF Progressive]: isMobileDevice", H)), H;
|
|
79
79
|
}
|
|
80
|
-
let
|
|
81
|
-
function
|
|
80
|
+
let H;
|
|
81
|
+
function ve() {
|
|
82
82
|
if (typeof window > "u") return !1;
|
|
83
|
-
const
|
|
84
|
-
return
|
|
83
|
+
const n = new URL(window.location.href), t = n.hostname === "localhost" || /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(n.hostname);
|
|
84
|
+
return n.hostname === "127.0.0.1" || t;
|
|
85
85
|
}
|
|
86
|
-
class
|
|
86
|
+
class rt {
|
|
87
87
|
constructor(t = 100, e = {}) {
|
|
88
88
|
this.maxConcurrent = t, this.debug = e.debug ?? !1, window.requestAnimationFrame(this.tick);
|
|
89
89
|
}
|
|
@@ -110,86 +110,98 @@ class st {
|
|
|
110
110
|
const t = this.maxConcurrent - this._running.size;
|
|
111
111
|
for (let e = 0; e < t && this._queue.length > 0; e++) {
|
|
112
112
|
this.debug && console.debug(`[PromiseQueue]: Running ${this._running.size} promises, waiting for ${this._queue.length} more.`);
|
|
113
|
-
const { key: s, resolve:
|
|
114
|
-
|
|
115
|
-
use: (
|
|
113
|
+
const { key: s, resolve: r } = this._queue.shift();
|
|
114
|
+
r({
|
|
115
|
+
use: (i) => this.add(s, i)
|
|
116
116
|
});
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return
|
|
120
|
+
function it(n) {
|
|
121
|
+
const t = n.image?.width ?? 0, e = n.image?.height ?? 0, s = n.image?.depth ?? 1, r = Math.floor(Math.log2(Math.max(t, e, s))) + 1, i = ot(n);
|
|
122
|
+
return t * e * s * i * (1 - Math.pow(0.25, r)) / (1 - 0.25);
|
|
123
123
|
}
|
|
124
|
-
function
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
function ot(n) {
|
|
125
|
+
let t = 4;
|
|
126
|
+
const e = n.format;
|
|
127
|
+
e === 1024 || e === 1025 ? t = 1 : e === 1026 || e === 1027 ? t = 2 : e === 1022 || e === 1029 ? t = 3 : (e === 1023 || e === 1033) && (t = 4);
|
|
128
|
+
let s = 1;
|
|
129
|
+
const r = n.type;
|
|
130
|
+
return r === 1009 || r === 1010 ? s = 1 : r === 1011 || r === 1012 ? s = 2 : r === 1013 || r === 1014 || r === 1015 ? s = 4 : r === 1016 && (s = 2), t * s;
|
|
131
|
+
}
|
|
132
|
+
const nt = typeof window > "u" && typeof document > "u", ye = /* @__PURE__ */ Symbol("needle:raycast-mesh");
|
|
133
|
+
function ee(n) {
|
|
134
|
+
return n?.[ye] instanceof V ? n[ye] : null;
|
|
135
|
+
}
|
|
136
|
+
function at(n, t) {
|
|
137
|
+
if ((n.type === "Mesh" || n.type === "SkinnedMesh") && !ee(n)) {
|
|
138
|
+
const s = ut(t);
|
|
139
|
+
s.userData = { isRaycastMesh: !0 }, n[ye] = s;
|
|
128
140
|
}
|
|
129
141
|
}
|
|
130
|
-
function
|
|
131
|
-
if (
|
|
132
|
-
if (
|
|
133
|
-
const t =
|
|
134
|
-
|
|
135
|
-
const
|
|
142
|
+
function lt(n = !0) {
|
|
143
|
+
if (n) {
|
|
144
|
+
if (Q) return;
|
|
145
|
+
const t = Q = X.prototype.raycast;
|
|
146
|
+
X.prototype.raycast = function(e, s) {
|
|
147
|
+
const r = this, i = ee(r);
|
|
136
148
|
let o;
|
|
137
|
-
|
|
149
|
+
i && r.isMesh && (o = r.geometry, r.geometry = i), t.call(this, e, s), o && (r.geometry = o);
|
|
138
150
|
};
|
|
139
151
|
} else {
|
|
140
|
-
if (!
|
|
141
|
-
|
|
152
|
+
if (!Q) return;
|
|
153
|
+
X.prototype.raycast = Q, Q = null;
|
|
142
154
|
}
|
|
143
155
|
}
|
|
144
|
-
let
|
|
145
|
-
function
|
|
146
|
-
const t = new
|
|
147
|
-
for (const e in
|
|
148
|
-
t.setAttribute(e,
|
|
149
|
-
return t.setIndex(
|
|
156
|
+
let Q = null;
|
|
157
|
+
function ut(n) {
|
|
158
|
+
const t = new V();
|
|
159
|
+
for (const e in n.attributes)
|
|
160
|
+
t.setAttribute(e, n.getAttribute(e));
|
|
161
|
+
return t.setIndex(n.getIndex()), t;
|
|
150
162
|
}
|
|
151
|
-
const
|
|
152
|
-
let
|
|
153
|
-
if (
|
|
154
|
-
let
|
|
155
|
-
|
|
163
|
+
const z = new Array(), f = N("debugprogressive");
|
|
164
|
+
let Z, E = -1;
|
|
165
|
+
if (f) {
|
|
166
|
+
let n = function() {
|
|
167
|
+
E += 1, E >= t && (E = -1), console.log(`Toggle LOD level [${E}]`);
|
|
156
168
|
}, t = 6;
|
|
157
169
|
window.addEventListener("keyup", (e) => {
|
|
158
|
-
e.key === "p" &&
|
|
170
|
+
e.key === "p" && n(), e.key === "w" && (Z = !Z, console.log(`Toggle wireframe [${Z}]`));
|
|
159
171
|
const s = parseInt(e.key);
|
|
160
|
-
!isNaN(s) && s >= 0 && (
|
|
172
|
+
!isNaN(s) && s >= 0 && (E = s, console.log(`Set LOD level to [${E}]`));
|
|
161
173
|
});
|
|
162
174
|
}
|
|
163
|
-
function
|
|
164
|
-
if (
|
|
165
|
-
if (Array.isArray(
|
|
166
|
-
for (const t of
|
|
167
|
-
|
|
168
|
-
else
|
|
175
|
+
function ke(n) {
|
|
176
|
+
if (f && Z !== void 0)
|
|
177
|
+
if (Array.isArray(n))
|
|
178
|
+
for (const t of n)
|
|
179
|
+
ke(t);
|
|
180
|
+
else n && "wireframe" in n && (n.wireframe = Z === !0);
|
|
169
181
|
}
|
|
170
|
-
const
|
|
171
|
-
let
|
|
172
|
-
const
|
|
173
|
-
function
|
|
174
|
-
if (
|
|
175
|
-
const s =
|
|
176
|
-
|
|
177
|
-
const
|
|
178
|
-
return
|
|
179
|
-
}
|
|
180
|
-
const t =
|
|
181
|
-
return
|
|
182
|
+
const J = new Array();
|
|
183
|
+
let ct = 0;
|
|
184
|
+
const dt = Ae() ? 2 : 10;
|
|
185
|
+
function ft(n) {
|
|
186
|
+
if (J.length < dt) {
|
|
187
|
+
const s = J.length;
|
|
188
|
+
f && console.warn(`[Worker] Creating new worker #${s}`);
|
|
189
|
+
const r = _e.createWorker(n || {});
|
|
190
|
+
return J.push(r), r;
|
|
191
|
+
}
|
|
192
|
+
const t = ct++ % J.length;
|
|
193
|
+
return J[t];
|
|
182
194
|
}
|
|
183
|
-
class
|
|
195
|
+
class _e {
|
|
184
196
|
constructor(t, e) {
|
|
185
197
|
this.worker = t, this._debug = e.debug ?? !1, t.onmessage = (s) => {
|
|
186
|
-
const
|
|
187
|
-
switch (this._debug && console.log("[Worker] EVENT",
|
|
198
|
+
const r = s.data;
|
|
199
|
+
switch (this._debug && console.log("[Worker] EVENT", r), r.type) {
|
|
188
200
|
case "loaded-gltf":
|
|
189
|
-
for (const
|
|
190
|
-
if (
|
|
191
|
-
|
|
192
|
-
const o =
|
|
201
|
+
for (const i of this._running)
|
|
202
|
+
if (i.url === r.result.url) {
|
|
203
|
+
ht(r.result), i.resolve(r.result);
|
|
204
|
+
const o = i.url;
|
|
193
205
|
o.startsWith("blob:") && URL.revokeObjectURL(o);
|
|
194
206
|
}
|
|
195
207
|
}
|
|
@@ -202,23 +214,23 @@ class we {
|
|
|
202
214
|
static async createWorker(t) {
|
|
203
215
|
const e = new Worker(new URL(
|
|
204
216
|
/* @vite-ignore */
|
|
205
|
-
"/assets/loader.worker-
|
|
217
|
+
"/assets/loader.worker-CCrD-Ycm.js",
|
|
206
218
|
import.meta.url
|
|
207
219
|
), {
|
|
208
220
|
type: "module"
|
|
209
221
|
});
|
|
210
|
-
return new
|
|
222
|
+
return new _e(e, t);
|
|
211
223
|
}
|
|
212
224
|
_running = [];
|
|
213
225
|
_webglRenderer = null;
|
|
214
226
|
async load(t, e) {
|
|
215
|
-
const s =
|
|
216
|
-
let
|
|
217
|
-
|
|
227
|
+
const s = Qe();
|
|
228
|
+
let r = e?.renderer;
|
|
229
|
+
r || (this._webglRenderer ??= (async () => {
|
|
218
230
|
const { WebGLRenderer: u } = await import("three");
|
|
219
231
|
return new u();
|
|
220
|
-
})(),
|
|
221
|
-
const l =
|
|
232
|
+
})(), r = await this._webglRenderer);
|
|
233
|
+
const l = we(r).ktx2Loader.workerConfig;
|
|
222
234
|
t instanceof URL ? t = t.toString() : t.startsWith("file:") ? t = URL.createObjectURL(new Blob([t])) : !t.startsWith("blob:") && !t.startsWith("http:") && !t.startsWith("https:") && (t = new URL(t, window.location.href).toString());
|
|
223
235
|
const a = {
|
|
224
236
|
type: "load",
|
|
@@ -236,23 +248,23 @@ class we {
|
|
|
236
248
|
}
|
|
237
249
|
_debug = !1;
|
|
238
250
|
}
|
|
239
|
-
function
|
|
240
|
-
for (const t of
|
|
241
|
-
const e = t.geometry, s = new
|
|
251
|
+
function ht(n) {
|
|
252
|
+
for (const t of n.geometries) {
|
|
253
|
+
const e = t.geometry, s = new V();
|
|
242
254
|
if (s.name = e.name || "", e.index) {
|
|
243
|
-
const
|
|
244
|
-
s.setIndex(
|
|
255
|
+
const r = e.index;
|
|
256
|
+
s.setIndex(le(r));
|
|
245
257
|
}
|
|
246
|
-
for (const
|
|
247
|
-
const
|
|
248
|
-
s.setAttribute(
|
|
258
|
+
for (const r in e.attributes) {
|
|
259
|
+
const i = e.attributes[r], o = le(i);
|
|
260
|
+
s.setAttribute(r, o);
|
|
249
261
|
}
|
|
250
262
|
if (e.morphAttributes)
|
|
251
|
-
for (const
|
|
252
|
-
const o = e.morphAttributes[
|
|
253
|
-
s.morphAttributes[
|
|
263
|
+
for (const r in e.morphAttributes) {
|
|
264
|
+
const o = e.morphAttributes[r].map((l) => le(l));
|
|
265
|
+
s.morphAttributes[r] = o;
|
|
254
266
|
}
|
|
255
|
-
if (s.morphTargetsRelative = e.morphTargetsRelative ?? !1, s.boundingBox = new
|
|
267
|
+
if (s.morphTargetsRelative = e.morphTargetsRelative ?? !1, s.boundingBox = new ge(), s.boundingBox.min = new A(
|
|
256
268
|
e.boundingBox?.min.x,
|
|
257
269
|
e.boundingBox?.min.y,
|
|
258
270
|
e.boundingBox?.min.z
|
|
@@ -260,7 +272,7 @@ function dt(i) {
|
|
|
260
272
|
e.boundingBox?.max.x,
|
|
261
273
|
e.boundingBox?.max.y,
|
|
262
274
|
e.boundingBox?.max.z
|
|
263
|
-
), s.boundingSphere = new
|
|
275
|
+
), s.boundingSphere = new Oe(
|
|
264
276
|
new A(
|
|
265
277
|
e.boundingSphere?.center.x,
|
|
266
278
|
e.boundingSphere?.center.y,
|
|
@@ -268,18 +280,18 @@ function dt(i) {
|
|
|
268
280
|
),
|
|
269
281
|
e.boundingSphere?.radius
|
|
270
282
|
), e.groups)
|
|
271
|
-
for (const
|
|
272
|
-
s.addGroup(
|
|
283
|
+
for (const r of e.groups)
|
|
284
|
+
s.addGroup(r.start, r.count, r.materialIndex);
|
|
273
285
|
e.userData && (s.userData = e.userData), t.geometry = s;
|
|
274
286
|
}
|
|
275
|
-
for (const t of
|
|
287
|
+
for (const t of n.textures) {
|
|
276
288
|
const e = t.texture;
|
|
277
289
|
let s = null;
|
|
278
290
|
if (e.isCompressedTexture) {
|
|
279
|
-
const
|
|
280
|
-
s = new
|
|
281
|
-
n,
|
|
291
|
+
const r = e.mipmaps, i = e.image?.width || e.source?.data?.width || -1, o = e.image?.height || e.source?.data?.height || -1;
|
|
292
|
+
s = new Ge(
|
|
282
293
|
r,
|
|
294
|
+
i,
|
|
283
295
|
o,
|
|
284
296
|
e.format,
|
|
285
297
|
e.type,
|
|
@@ -292,7 +304,7 @@ function dt(i) {
|
|
|
292
304
|
e.colorSpace
|
|
293
305
|
);
|
|
294
306
|
} else
|
|
295
|
-
s = new
|
|
307
|
+
s = new F(
|
|
296
308
|
e.image,
|
|
297
309
|
e.mapping,
|
|
298
310
|
e.wrapS,
|
|
@@ -303,28 +315,30 @@ function dt(i) {
|
|
|
303
315
|
e.type,
|
|
304
316
|
e.anisotropy,
|
|
305
317
|
e.colorSpace
|
|
306
|
-
), s.mipmaps = e.mipmaps, s.channel = e.channel, s.source.data = e.source.data, s.flipY = e.flipY, s.premultiplyAlpha = e.premultiplyAlpha, s.unpackAlignment = e.unpackAlignment, s.matrix = new
|
|
318
|
+
), s.mipmaps = e.mipmaps, s.channel = e.channel, s.source.data = e.source.data, s.flipY = e.flipY, s.premultiplyAlpha = e.premultiplyAlpha, s.unpackAlignment = e.unpackAlignment, s.matrix = new Fe(...e.matrix.elements);
|
|
307
319
|
if (!s) {
|
|
308
320
|
console.error("[Worker] Failed to create new texture from received data. Texture is not a CompressedTexture or Texture.");
|
|
309
321
|
continue;
|
|
310
322
|
}
|
|
311
323
|
t.texture = s;
|
|
312
324
|
}
|
|
313
|
-
return
|
|
325
|
+
return n;
|
|
314
326
|
}
|
|
315
|
-
function
|
|
316
|
-
let t =
|
|
317
|
-
if ("isInterleavedBufferAttribute" in
|
|
318
|
-
const e =
|
|
319
|
-
t = new
|
|
320
|
-
} else "isBufferAttribute" in
|
|
327
|
+
function le(n) {
|
|
328
|
+
let t = n;
|
|
329
|
+
if ("isInterleavedBufferAttribute" in n && n.isInterleavedBufferAttribute) {
|
|
330
|
+
const e = n.data, s = e.array, r = new We(s, e.stride);
|
|
331
|
+
t = new Ue(r, n.itemSize, s.byteOffset, n.normalized), t.offset = n.offset;
|
|
332
|
+
} else "isBufferAttribute" in n && n.isBufferAttribute && (t = new ze(n.array, n.itemSize, n.normalized), t.usage = n.usage, t.gpuType = n.gpuType, t.updateRanges = n.updateRanges);
|
|
321
333
|
return t;
|
|
322
334
|
}
|
|
323
|
-
const
|
|
335
|
+
const gt = N("gltf-progressive-worker");
|
|
336
|
+
N("gltf-progressive-reduce-mipmaps");
|
|
337
|
+
const K = N("gltf-progressive-gc"), ue = /* @__PURE__ */ Symbol("needle-progressive-texture"), W = "NEEDLE_progressive";
|
|
324
338
|
class y {
|
|
325
339
|
/** The name of the extension */
|
|
326
340
|
get name() {
|
|
327
|
-
return
|
|
341
|
+
return W;
|
|
328
342
|
}
|
|
329
343
|
// #region PUBLIC API
|
|
330
344
|
static getMeshLODExtension(t) {
|
|
@@ -336,8 +350,8 @@ class y {
|
|
|
336
350
|
return e ?? -1;
|
|
337
351
|
}
|
|
338
352
|
static getMaterialMinMaxLODsCount(t, e) {
|
|
339
|
-
const s = this,
|
|
340
|
-
if (
|
|
353
|
+
const s = this, r = "LODS:minmax", i = t[r];
|
|
354
|
+
if (i != null) return i;
|
|
341
355
|
if (e || (e = {
|
|
342
356
|
min_count: 1 / 0,
|
|
343
357
|
max_count: 0,
|
|
@@ -345,9 +359,9 @@ class y {
|
|
|
345
359
|
}), Array.isArray(t)) {
|
|
346
360
|
for (const l of t)
|
|
347
361
|
this.getMaterialMinMaxLODsCount(l, e);
|
|
348
|
-
return t[
|
|
362
|
+
return t[r] = e, e;
|
|
349
363
|
}
|
|
350
|
-
if (
|
|
364
|
+
if (f === "verbose" && console.log("getMaterialMinMaxLODsCount", t), t.type === "ShaderMaterial" || t.type === "RawShaderMaterial") {
|
|
351
365
|
const l = t;
|
|
352
366
|
for (const a of Object.keys(l.uniforms)) {
|
|
353
367
|
const u = l.uniforms[a].value;
|
|
@@ -359,17 +373,17 @@ class y {
|
|
|
359
373
|
a?.isTexture === !0 && o(a, e);
|
|
360
374
|
}
|
|
361
375
|
else
|
|
362
|
-
|
|
363
|
-
return t[
|
|
376
|
+
f && console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);
|
|
377
|
+
return t[r] = e, e;
|
|
364
378
|
function o(l, a) {
|
|
365
379
|
const u = s.getAssignedLODInformation(l);
|
|
366
380
|
if (u) {
|
|
367
381
|
const c = s.lodInfos.get(u.key);
|
|
368
382
|
if (c && c.lods) {
|
|
369
383
|
a.min_count = Math.min(a.min_count, c.lods.length), a.max_count = Math.max(a.max_count, c.lods.length);
|
|
370
|
-
for (let
|
|
371
|
-
const
|
|
372
|
-
|
|
384
|
+
for (let m = 0; m < c.lods.length; m++) {
|
|
385
|
+
const w = c.lods[m];
|
|
386
|
+
w.width && (a.lods[m] = a.lods[m] || { min_height: 1 / 0, max_height: 0 }, a.lods[m].min_height = Math.min(a.lods[m].min_height, w.height), a.lods[m].max_height = Math.max(a.lods[m].max_height, w.height));
|
|
373
387
|
}
|
|
374
388
|
}
|
|
375
389
|
}
|
|
@@ -382,28 +396,28 @@ class y {
|
|
|
382
396
|
*/
|
|
383
397
|
static hasLODLevelAvailable(t, e) {
|
|
384
398
|
if (Array.isArray(t)) {
|
|
385
|
-
for (const
|
|
386
|
-
if (this.hasLODLevelAvailable(
|
|
399
|
+
for (const i of t)
|
|
400
|
+
if (this.hasLODLevelAvailable(i, e)) return !0;
|
|
387
401
|
return !1;
|
|
388
402
|
}
|
|
389
403
|
if (t.isMaterial === !0) {
|
|
390
|
-
for (const
|
|
391
|
-
const o = t[
|
|
404
|
+
for (const i of Object.keys(t)) {
|
|
405
|
+
const o = t[i];
|
|
392
406
|
if (o && o.isTexture && this.hasLODLevelAvailable(o, e))
|
|
393
407
|
return !0;
|
|
394
408
|
}
|
|
395
409
|
return !1;
|
|
396
410
|
} else if (t.isGroup === !0) {
|
|
397
|
-
for (const
|
|
398
|
-
if (
|
|
411
|
+
for (const i of t.children)
|
|
412
|
+
if (i.isMesh === !0 && this.hasLODLevelAvailable(i, e))
|
|
399
413
|
return !0;
|
|
400
414
|
}
|
|
401
|
-
let s,
|
|
415
|
+
let s, r;
|
|
402
416
|
if (t.isMesh ? s = t.geometry : (t.isBufferGeometry || t.isTexture) && (s = t), s && s?.userData?.LODS) {
|
|
403
|
-
const
|
|
404
|
-
if (
|
|
405
|
-
if (
|
|
406
|
-
return Array.isArray(
|
|
417
|
+
const i = s.userData.LODS;
|
|
418
|
+
if (r = this.lodInfos.get(i.key), e === void 0) return r != null;
|
|
419
|
+
if (r)
|
|
420
|
+
return Array.isArray(r.lods) ? e < r.lods.length : e === 0;
|
|
407
421
|
}
|
|
408
422
|
return !1;
|
|
409
423
|
}
|
|
@@ -423,20 +437,20 @@ class y {
|
|
|
423
437
|
*/
|
|
424
438
|
static assignMeshLOD(t, e) {
|
|
425
439
|
if (!t) return Promise.resolve(null);
|
|
426
|
-
if (t instanceof
|
|
427
|
-
const s = t.geometry,
|
|
428
|
-
if (!
|
|
440
|
+
if (t instanceof X || t.isMesh === !0) {
|
|
441
|
+
const s = t.geometry, r = this.getAssignedLODInformation(s);
|
|
442
|
+
if (!r)
|
|
429
443
|
return Promise.resolve(null);
|
|
430
|
-
for (const
|
|
431
|
-
|
|
432
|
-
return t["LOD:requested level"] = e, y.getOrLoadLOD(s, e).then((
|
|
433
|
-
if (Array.isArray(
|
|
434
|
-
const o =
|
|
435
|
-
|
|
444
|
+
for (const i of z)
|
|
445
|
+
i.onBeforeGetLODMesh?.(t, e);
|
|
446
|
+
return t["LOD:requested level"] = e, y.getOrLoadLOD(s, e).then((i) => {
|
|
447
|
+
if (Array.isArray(i)) {
|
|
448
|
+
const o = r.index || 0;
|
|
449
|
+
i = i[o];
|
|
436
450
|
}
|
|
437
|
-
return t["LOD:requested level"] === e && (delete t["LOD:requested level"],
|
|
438
|
-
}).catch((
|
|
439
|
-
} else
|
|
451
|
+
return t["LOD:requested level"] === e && (delete t["LOD:requested level"], i && s != i && (i?.isBufferGeometry ? t.geometry = i : f && console.error("Invalid LOD geometry", i))), i;
|
|
452
|
+
}).catch((i) => (console.error("Error loading mesh LOD", t, i), null));
|
|
453
|
+
} else f && console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh", t);
|
|
440
454
|
return Promise.resolve(null);
|
|
441
455
|
}
|
|
442
456
|
static assignTextureLOD(t, e = 0) {
|
|
@@ -444,14 +458,14 @@ class y {
|
|
|
444
458
|
if (t.isMesh === !0) {
|
|
445
459
|
const s = t;
|
|
446
460
|
if (Array.isArray(s.material)) {
|
|
447
|
-
const
|
|
448
|
-
for (const
|
|
449
|
-
const o = this.assignTextureLOD(
|
|
450
|
-
|
|
461
|
+
const r = new Array();
|
|
462
|
+
for (const i of s.material) {
|
|
463
|
+
const o = this.assignTextureLOD(i, e);
|
|
464
|
+
r.push(o);
|
|
451
465
|
}
|
|
452
|
-
return Promise.all(
|
|
466
|
+
return Promise.all(r).then((i) => {
|
|
453
467
|
const o = new Array();
|
|
454
|
-
for (const l of
|
|
468
|
+
for (const l of i)
|
|
455
469
|
Array.isArray(l) && o.push(...l);
|
|
456
470
|
return o;
|
|
457
471
|
});
|
|
@@ -459,14 +473,14 @@ class y {
|
|
|
459
473
|
return this.assignTextureLOD(s.material, e);
|
|
460
474
|
}
|
|
461
475
|
if (t.isMaterial === !0) {
|
|
462
|
-
const s = t,
|
|
476
|
+
const s = t, r = [], i = new Array();
|
|
463
477
|
if (s.uniforms && (s.isRawShaderMaterial || s.isShaderMaterial === !0)) {
|
|
464
478
|
const o = s;
|
|
465
479
|
for (const l of Object.keys(o.uniforms)) {
|
|
466
480
|
const a = o.uniforms[l].value;
|
|
467
481
|
if (a?.isTexture === !0) {
|
|
468
482
|
const u = this.assignTextureLODForSlot(a, e, s, l).then((c) => (c && o.uniforms[l].value != c && (o.uniforms[l].value = c, o.uniformsNeedUpdate = !0), c));
|
|
469
|
-
|
|
483
|
+
r.push(u), i.push(l);
|
|
470
484
|
}
|
|
471
485
|
}
|
|
472
486
|
} else
|
|
@@ -474,58 +488,58 @@ class y {
|
|
|
474
488
|
const l = s[o];
|
|
475
489
|
if (l?.isTexture === !0) {
|
|
476
490
|
const a = this.assignTextureLODForSlot(l, e, s, o);
|
|
477
|
-
|
|
491
|
+
r.push(a), i.push(o);
|
|
478
492
|
}
|
|
479
493
|
}
|
|
480
|
-
return Promise.all(
|
|
494
|
+
return Promise.all(r).then((o) => {
|
|
481
495
|
const l = new Array();
|
|
482
496
|
for (let a = 0; a < o.length; a++) {
|
|
483
|
-
const u = o[a], c =
|
|
497
|
+
const u = o[a], c = i[a];
|
|
484
498
|
u && u.isTexture === !0 ? l.push({ material: s, slot: c, texture: u, level: e }) : l.push({ material: s, slot: c, texture: null, level: e });
|
|
485
499
|
}
|
|
486
500
|
return l;
|
|
487
501
|
});
|
|
488
502
|
}
|
|
489
|
-
if (t instanceof
|
|
503
|
+
if (t instanceof F || t.isTexture === !0) {
|
|
490
504
|
const s = t;
|
|
491
505
|
return this.assignTextureLODForSlot(s, e, null, null);
|
|
492
506
|
}
|
|
493
507
|
return Promise.resolve(null);
|
|
494
508
|
}
|
|
495
509
|
// #region INTERNAL
|
|
496
|
-
static assignTextureLODForSlot(t, e, s,
|
|
497
|
-
return t?.isTexture !== !0 ? Promise.resolve(null) :
|
|
498
|
-
if (Array.isArray(
|
|
510
|
+
static assignTextureLODForSlot(t, e, s, r) {
|
|
511
|
+
return t?.isTexture !== !0 ? Promise.resolve(null) : r === "glyphMap" ? Promise.resolve(t) : y.getOrLoadLOD(t, e).then((i) => {
|
|
512
|
+
if (Array.isArray(i))
|
|
499
513
|
return console.warn("Progressive: Got an array of textures for a texture slot, this should not happen..."), null;
|
|
500
|
-
if (
|
|
501
|
-
if (
|
|
502
|
-
const o = s[
|
|
503
|
-
if (o && !
|
|
514
|
+
if (i?.isTexture === !0) {
|
|
515
|
+
if (i != t && s && r) {
|
|
516
|
+
const o = s[r];
|
|
517
|
+
if (o && !f) {
|
|
504
518
|
const l = this.getAssignedLODInformation(o);
|
|
505
519
|
if (l && l?.level < e)
|
|
506
|
-
return
|
|
520
|
+
return f === "verbose" && console.warn("Assigned texture level is already higher: ", l.level, e, s, o, i), i && i !== o && ((f || K) && console.log(`[gltf-progressive] Disposing rejected lower-quality texture LOD ${e} (assigned is ${l.level})`, i.uuid), i.dispose()), null;
|
|
507
521
|
}
|
|
508
|
-
if (
|
|
509
|
-
const
|
|
510
|
-
|
|
522
|
+
if (this.trackTextureUsage(i), o && o !== i && this.untrackTextureUsage(o) && (f || K)) {
|
|
523
|
+
const a = this.getAssignedLODInformation(o);
|
|
524
|
+
console.log(`[gltf-progressive] Disposed old texture LOD ${a?.level ?? "?"} → ${e} for ${s.name || s.type}.${r}`, o.uuid);
|
|
511
525
|
}
|
|
512
|
-
s[
|
|
526
|
+
s[r] = i;
|
|
513
527
|
}
|
|
514
|
-
return
|
|
515
|
-
} else
|
|
528
|
+
return i;
|
|
529
|
+
} else f == "verbose" && console.warn("No LOD found for", t, e);
|
|
516
530
|
return null;
|
|
517
|
-
}).catch((
|
|
531
|
+
}).catch((i) => (console.error("Error loading LOD", t, i), null));
|
|
518
532
|
}
|
|
519
533
|
parser;
|
|
520
534
|
url;
|
|
521
535
|
constructor(t) {
|
|
522
536
|
const e = t.options.path;
|
|
523
|
-
|
|
537
|
+
f && console.log("Progressive extension registered for", e), this.parser = t, this.url = e;
|
|
524
538
|
}
|
|
525
539
|
_isLoadingMesh;
|
|
526
540
|
loadMesh = (t) => {
|
|
527
541
|
if (this._isLoadingMesh) return null;
|
|
528
|
-
const e = this.parser.json.meshes[t]?.extensions?.[
|
|
542
|
+
const e = this.parser.json.meshes[t]?.extensions?.[W];
|
|
529
543
|
return e ? (this._isLoadingMesh = !0, this.parser.getDependency("mesh", t).then((s) => (this._isLoadingMesh = !1, s && y.registerMesh(this.url, e.guid, s, e.lods?.length, 0, e), s))) : null;
|
|
530
544
|
};
|
|
531
545
|
// private _isLoadingTexture;
|
|
@@ -543,30 +557,30 @@ class y {
|
|
|
543
557
|
// });
|
|
544
558
|
// }
|
|
545
559
|
afterRoot(t) {
|
|
546
|
-
return
|
|
560
|
+
return f && console.log("AFTER", this.url, t), this.parser.json.textures?.forEach((e, s) => {
|
|
547
561
|
if (e?.extensions) {
|
|
548
|
-
const
|
|
549
|
-
if (
|
|
550
|
-
if (!
|
|
551
|
-
|
|
562
|
+
const r = e?.extensions[W];
|
|
563
|
+
if (r) {
|
|
564
|
+
if (!r.lods) {
|
|
565
|
+
f && console.warn("Texture has no LODs", r);
|
|
552
566
|
return;
|
|
553
567
|
}
|
|
554
|
-
let
|
|
568
|
+
let i = !1;
|
|
555
569
|
for (const o of this.parser.associations.keys())
|
|
556
|
-
o.isTexture === !0 && this.parser.associations.get(o)?.textures === s && (
|
|
557
|
-
|
|
558
|
-
o && y.registerTexture(this.url, o,
|
|
570
|
+
o.isTexture === !0 && this.parser.associations.get(o)?.textures === s && (i = !0, y.registerTexture(this.url, o, r.lods?.length, s, r));
|
|
571
|
+
i || this.parser.getDependency("texture", s).then((o) => {
|
|
572
|
+
o && y.registerTexture(this.url, o, r.lods?.length, s, r);
|
|
559
573
|
});
|
|
560
574
|
}
|
|
561
575
|
}
|
|
562
576
|
}), this.parser.json.meshes?.forEach((e, s) => {
|
|
563
577
|
if (e?.extensions) {
|
|
564
|
-
const
|
|
565
|
-
if (
|
|
566
|
-
for (const
|
|
567
|
-
if (
|
|
568
|
-
const o = this.parser.associations.get(
|
|
569
|
-
o?.meshes === s && y.registerMesh(this.url,
|
|
578
|
+
const r = e?.extensions[W];
|
|
579
|
+
if (r && r.lods) {
|
|
580
|
+
for (const i of this.parser.associations.keys())
|
|
581
|
+
if (i.isMesh) {
|
|
582
|
+
const o = this.parser.associations.get(i);
|
|
583
|
+
o?.meshes === s && y.registerMesh(this.url, r.guid, i, r.lods.length, o.primitives, r);
|
|
570
584
|
}
|
|
571
585
|
}
|
|
572
586
|
}
|
|
@@ -575,174 +589,288 @@ class y {
|
|
|
575
589
|
/**
|
|
576
590
|
* Register a texture with LOD information
|
|
577
591
|
*/
|
|
578
|
-
static registerTexture = (t, e, s,
|
|
592
|
+
static registerTexture = (t, e, s, r, i) => {
|
|
579
593
|
if (!e) {
|
|
580
|
-
|
|
594
|
+
f && console.error("!! gltf-progressive: Called register texture without texture");
|
|
581
595
|
return;
|
|
582
596
|
}
|
|
583
|
-
if (
|
|
597
|
+
if (f) {
|
|
584
598
|
const l = e.image?.width || e.source?.data?.width || 0, a = e.image?.height || e.source?.data?.height || 0;
|
|
585
|
-
console.log(`> gltf-progressive: register texture[${
|
|
599
|
+
console.log(`> gltf-progressive: register texture[${r}] "${e.name || e.uuid}", Current: ${l}x${a}, Max: ${i.lods[0]?.width}x${i.lods[0]?.height}, uuid: ${e.uuid}`, i, e);
|
|
586
600
|
}
|
|
587
|
-
e.source && (e.source[
|
|
588
|
-
const o =
|
|
589
|
-
y.assignLODInformation(t, e, o, s,
|
|
601
|
+
e.source && (e.source[ue] = i);
|
|
602
|
+
const o = i.guid;
|
|
603
|
+
y.assignLODInformation(t, e, o, s, r), y.lodInfos.set(o, i), y.lowresCache.set(o, new WeakRef(e));
|
|
590
604
|
};
|
|
591
605
|
/**
|
|
592
606
|
* Register a mesh with LOD information
|
|
593
607
|
*/
|
|
594
|
-
static registerMesh = (t, e, s,
|
|
608
|
+
static registerMesh = (t, e, s, r, i, o) => {
|
|
595
609
|
const l = s.geometry;
|
|
596
610
|
if (!l) {
|
|
597
|
-
|
|
611
|
+
f && console.warn("gltf-progressive: Register mesh without geometry");
|
|
598
612
|
return;
|
|
599
613
|
}
|
|
600
|
-
l.userData || (l.userData = {}),
|
|
601
|
-
let
|
|
602
|
-
|
|
603
|
-
for (const
|
|
604
|
-
|
|
614
|
+
l.userData || (l.userData = {}), f && console.log("> Progressive: register mesh " + s.name, { index: i, uuid: s.uuid }, o, s), y.assignLODInformation(t, l, e, r, i), y.lodInfos.set(e, o);
|
|
615
|
+
let u = y.lowresCache.get(e)?.deref();
|
|
616
|
+
u ? u.push(s.geometry) : u = [s.geometry], y.lowresCache.set(e, new WeakRef(u)), r > 0 && !ee(s) && at(s, l);
|
|
617
|
+
for (const c of z)
|
|
618
|
+
c.onRegisteredNewMesh?.(s, o);
|
|
605
619
|
};
|
|
620
|
+
/**
|
|
621
|
+
* Dispose cached resources to free memory.
|
|
622
|
+
* Call this when a model is removed from the scene to allow garbage collection of its LOD resources.
|
|
623
|
+
* Calls three.js `.dispose()` on cached Textures and BufferGeometries to free GPU memory.
|
|
624
|
+
* Also clears reference counts for disposed textures.
|
|
625
|
+
* @param guid Optional GUID to dispose resources for a specific model. If omitted, all cached resources are cleared.
|
|
626
|
+
*/
|
|
627
|
+
static dispose(t) {
|
|
628
|
+
if (t) {
|
|
629
|
+
this.lodInfos.delete(t);
|
|
630
|
+
const e = this.lowresCache.get(t);
|
|
631
|
+
if (e) {
|
|
632
|
+
const s = e.deref();
|
|
633
|
+
if (s) {
|
|
634
|
+
if (s.isTexture) {
|
|
635
|
+
const r = s;
|
|
636
|
+
this.textureRefCounts.delete(r.uuid), r.dispose();
|
|
637
|
+
} else if (Array.isArray(s))
|
|
638
|
+
for (const r of s) r.dispose();
|
|
639
|
+
}
|
|
640
|
+
this.lowresCache.delete(t);
|
|
641
|
+
}
|
|
642
|
+
for (const [s, r] of this.cache)
|
|
643
|
+
s.includes(t) && (this._disposeCacheEntry(r), this.cache.delete(s));
|
|
644
|
+
} else {
|
|
645
|
+
this.lodInfos.clear();
|
|
646
|
+
for (const [, e] of this.lowresCache) {
|
|
647
|
+
const s = e.deref();
|
|
648
|
+
if (s) {
|
|
649
|
+
if (s.isTexture) {
|
|
650
|
+
const r = s;
|
|
651
|
+
this.textureRefCounts.delete(r.uuid), r.dispose();
|
|
652
|
+
} else if (Array.isArray(s))
|
|
653
|
+
for (const r of s) r.dispose();
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
this.lowresCache.clear();
|
|
657
|
+
for (const [, e] of this.cache)
|
|
658
|
+
this._disposeCacheEntry(e);
|
|
659
|
+
this.cache.clear(), this.textureRefCounts.clear();
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
/** Dispose a single cache entry's three.js resource(s) to free GPU memory. */
|
|
663
|
+
static _disposeCacheEntry(t) {
|
|
664
|
+
if (t instanceof WeakRef) {
|
|
665
|
+
const e = t.deref();
|
|
666
|
+
e && (e.isTexture && this.textureRefCounts.delete(e.uuid), e.dispose());
|
|
667
|
+
} else
|
|
668
|
+
t.then((e) => {
|
|
669
|
+
if (e)
|
|
670
|
+
if (Array.isArray(e))
|
|
671
|
+
for (const s of e) s.dispose();
|
|
672
|
+
else
|
|
673
|
+
e.isTexture && this.textureRefCounts.delete(e.uuid), e.dispose();
|
|
674
|
+
}).catch(() => {
|
|
675
|
+
});
|
|
676
|
+
}
|
|
606
677
|
/** A map of key = asset uuid and value = LOD information */
|
|
607
678
|
static lodInfos = /* @__PURE__ */ new Map();
|
|
608
|
-
/** cache of already loaded mesh lods */
|
|
609
|
-
static
|
|
610
|
-
/** this contains the geometry/textures that were originally loaded */
|
|
679
|
+
/** cache of already loaded mesh lods. Uses WeakRef for single resources to allow garbage collection when unused. */
|
|
680
|
+
static cache = /* @__PURE__ */ new Map();
|
|
681
|
+
/** this contains the geometry/textures that were originally loaded. Uses WeakRef to allow garbage collection when unused. */
|
|
611
682
|
static lowresCache = /* @__PURE__ */ new Map();
|
|
683
|
+
/** Reference counting for textures to track usage across multiple materials/objects */
|
|
684
|
+
static textureRefCounts = /* @__PURE__ */ new Map();
|
|
685
|
+
/**
|
|
686
|
+
* FinalizationRegistry to automatically clean up `previouslyLoaded` cache entries
|
|
687
|
+
* when their associated three.js resources are garbage collected by the browser.
|
|
688
|
+
* The held value is the cache key string used in `previouslyLoaded`.
|
|
689
|
+
*/
|
|
690
|
+
static _resourceRegistry = new FinalizationRegistry((t) => {
|
|
691
|
+
const e = y.cache.get(t);
|
|
692
|
+
(f || K) && console.debug(`[gltf-progressive] Memory: Resource GC'd
|
|
693
|
+
${t}`), e instanceof WeakRef && (e.deref() || (y.cache.delete(t), (f || K) && console.log("[gltf-progressive] ↪ Cache entry deleted (GC)")));
|
|
694
|
+
});
|
|
695
|
+
/**
|
|
696
|
+
* Track texture usage by incrementing reference count
|
|
697
|
+
*/
|
|
698
|
+
static trackTextureUsage(t) {
|
|
699
|
+
const e = t.uuid, s = this.textureRefCounts.get(e) || 0;
|
|
700
|
+
this.textureRefCounts.set(e, s + 1), f === "verbose" && console.log(`[gltf-progressive] Track texture ${e}, refCount: ${s} → ${s + 1}`);
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Untrack texture usage by decrementing reference count.
|
|
704
|
+
* Automatically disposes the texture when reference count reaches zero.
|
|
705
|
+
* @returns true if the texture was disposed, false otherwise
|
|
706
|
+
*/
|
|
707
|
+
static untrackTextureUsage(t) {
|
|
708
|
+
const e = t.uuid, s = this.textureRefCounts.get(e);
|
|
709
|
+
if (!s)
|
|
710
|
+
return (f === "verbose" || K) && i("[gltf-progressive] Memory: Untrack untracked texture (dispose immediately)", 0), t.dispose(), !0;
|
|
711
|
+
const r = s - 1;
|
|
712
|
+
if (r <= 0)
|
|
713
|
+
return this.textureRefCounts.delete(e), (f || K) && i("[gltf-progressive] Memory: Dispose texture", r), t.dispose(), !0;
|
|
714
|
+
return this.textureRefCounts.set(e, r), f === "verbose" && i("[gltf-progressive] Memory: Untrack texture", r), !1;
|
|
715
|
+
function i(o, l) {
|
|
716
|
+
let a = t.image?.width || t.source?.data?.width || 0, u = t.image?.height || t.source?.data?.height || 0;
|
|
717
|
+
const c = a && u ? `${a}x${u}` : "N/A";
|
|
718
|
+
let m = "N/A";
|
|
719
|
+
a && u && (m = `~${(it(t) / (1024 * 1024)).toFixed(2)} MB`), console.log(`${o} — ${t.name} ${c} (${m}), refCount: ${s} → ${l}
|
|
720
|
+
${e}`);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
612
723
|
static workers = [];
|
|
613
724
|
static _workersIndex = 0;
|
|
614
725
|
static async getOrLoadLOD(t, e) {
|
|
615
|
-
const s =
|
|
616
|
-
if (!
|
|
617
|
-
return
|
|
618
|
-
const
|
|
726
|
+
const s = f == "verbose", r = this.getAssignedLODInformation(t);
|
|
727
|
+
if (!r)
|
|
728
|
+
return f && console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`, t), null;
|
|
729
|
+
const i = r?.key;
|
|
619
730
|
let o;
|
|
620
731
|
if (t.isTexture === !0) {
|
|
621
732
|
const a = t;
|
|
622
|
-
a.source && a.source[
|
|
733
|
+
a.source && a.source[ue] && (o = a.source[ue]);
|
|
623
734
|
}
|
|
624
|
-
if (o || (o = y.lodInfos.get(
|
|
625
|
-
|
|
735
|
+
if (o || (o = y.lodInfos.get(i)), !o)
|
|
736
|
+
f && console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${t.name}`, t.type, y.lodInfos);
|
|
626
737
|
else {
|
|
627
738
|
if (e > 0) {
|
|
628
739
|
let c = !1;
|
|
629
|
-
const
|
|
630
|
-
if (
|
|
631
|
-
|
|
740
|
+
const m = Array.isArray(o.lods);
|
|
741
|
+
if (m && e >= o.lods.length ? c = !0 : m || (c = !0), c) {
|
|
742
|
+
const w = this.lowresCache.get(i);
|
|
743
|
+
if (w) {
|
|
744
|
+
const _ = w.deref();
|
|
745
|
+
if (_) return _;
|
|
746
|
+
this.lowresCache.delete(i), f && console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${i}`);
|
|
747
|
+
}
|
|
748
|
+
return null;
|
|
749
|
+
}
|
|
632
750
|
}
|
|
633
751
|
const a = Array.isArray(o.lods) ? o.lods[e]?.path : o.lods;
|
|
634
752
|
if (!a)
|
|
635
|
-
return
|
|
636
|
-
const u =
|
|
753
|
+
return f && !o["missing:uri"] && (o["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + e, o)), null;
|
|
754
|
+
const u = st(r.url, a);
|
|
637
755
|
if (u.endsWith(".glb") || u.endsWith(".gltf")) {
|
|
638
756
|
if (!o.guid)
|
|
639
757
|
return console.warn("missing pointer for glb/gltf texture", o), null;
|
|
640
|
-
const c = u + "_" + o.guid,
|
|
641
|
-
if (
|
|
642
|
-
s && console.log(`LOD ${e} was already loading/loaded: ${c}`)
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
if (
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
758
|
+
const c = u + "_" + o.guid, m = await this.queue.slot(u), w = this.cache.get(c);
|
|
759
|
+
if (w !== void 0)
|
|
760
|
+
if (s && console.log(`LOD ${e} was already loading/loaded: ${c}`), w instanceof WeakRef) {
|
|
761
|
+
const d = w.deref();
|
|
762
|
+
if (d) {
|
|
763
|
+
let g = d, b = !1;
|
|
764
|
+
if (g instanceof F && t instanceof F ? g.image?.data || g.source?.data ? g = this.copySettings(t, g) : b = !0 : g instanceof V && t instanceof V && (g.attributes.position?.array || (b = !0)), !b)
|
|
765
|
+
return g;
|
|
766
|
+
}
|
|
767
|
+
this.cache.delete(c), f && console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${c}`);
|
|
768
|
+
} else {
|
|
769
|
+
let d = await w.catch((b) => (console.error(`Error loading LOD ${e} from ${u}
|
|
770
|
+
`, b), null)), g = !1;
|
|
771
|
+
if (d == null || (d instanceof F && t instanceof F ? d.image?.data || d.source?.data ? d = this.copySettings(t, d) : (g = !0, this.cache.delete(c)) : d instanceof V && t instanceof V && (d.attributes.position?.array || (g = !0, this.cache.delete(c)))), !g)
|
|
772
|
+
return d;
|
|
773
|
+
}
|
|
774
|
+
if (!m.use)
|
|
775
|
+
return f && console.log(`LOD ${e} was aborted: ${u}`), null;
|
|
776
|
+
const _ = o, k = new Promise(async (d, g) => {
|
|
777
|
+
if (gt) {
|
|
778
|
+
const x = await (await ft({})).load(u);
|
|
779
|
+
if (x.textures.length > 0)
|
|
780
|
+
for (const h of x.textures) {
|
|
781
|
+
let p = h.texture;
|
|
782
|
+
return y.assignLODInformation(r.url, p, i, e, void 0), t instanceof F && (p = this.copySettings(t, p)), p && (p.guid = _.guid), d(p);
|
|
657
783
|
}
|
|
658
|
-
if (
|
|
659
|
-
const
|
|
660
|
-
for (const
|
|
661
|
-
const
|
|
662
|
-
y.assignLODInformation(
|
|
784
|
+
if (x.geometries.length > 0) {
|
|
785
|
+
const h = new Array();
|
|
786
|
+
for (const p of x.geometries) {
|
|
787
|
+
const O = p.geometry;
|
|
788
|
+
y.assignLODInformation(r.url, O, i, e, p.primitiveIndex), h.push(O);
|
|
663
789
|
}
|
|
664
|
-
return d(
|
|
790
|
+
return d(h);
|
|
665
791
|
}
|
|
666
792
|
return d(null);
|
|
667
793
|
}
|
|
668
|
-
const
|
|
669
|
-
|
|
794
|
+
const b = new xe();
|
|
795
|
+
Pe(b), f && (await new Promise((L) => setTimeout(L, 1e3)), s && console.warn("Start loading (delayed) " + u, _.guid));
|
|
670
796
|
let B = u;
|
|
671
|
-
if (
|
|
672
|
-
const
|
|
673
|
-
|
|
797
|
+
if (_ && Array.isArray(_.lods)) {
|
|
798
|
+
const L = _.lods[e];
|
|
799
|
+
L.hash && (B += "?v=" + L.hash);
|
|
674
800
|
}
|
|
675
|
-
const
|
|
676
|
-
`,
|
|
677
|
-
if (!
|
|
801
|
+
const D = await b.loadAsync(B).catch((L) => (console.error(`Error loading LOD ${e} from ${u}
|
|
802
|
+
`, L), d(null)));
|
|
803
|
+
if (!D)
|
|
678
804
|
return d(null);
|
|
679
|
-
const
|
|
680
|
-
s && console.log("Loading finished " + u,
|
|
681
|
-
let
|
|
682
|
-
if (
|
|
683
|
-
let
|
|
684
|
-
for (const
|
|
685
|
-
if (
|
|
686
|
-
const
|
|
687
|
-
if (
|
|
688
|
-
|
|
805
|
+
const q = D.parser;
|
|
806
|
+
s && console.log("Loading finished " + u, _.guid);
|
|
807
|
+
let P = 0;
|
|
808
|
+
if (D.parser.json.textures) {
|
|
809
|
+
let L = !1;
|
|
810
|
+
for (const x of D.parser.json.textures) {
|
|
811
|
+
if (x?.extensions) {
|
|
812
|
+
const h = x?.extensions[W];
|
|
813
|
+
if (h?.guid && h.guid === _.guid) {
|
|
814
|
+
L = !0;
|
|
689
815
|
break;
|
|
690
816
|
}
|
|
691
817
|
}
|
|
692
|
-
|
|
818
|
+
P++;
|
|
693
819
|
}
|
|
694
|
-
if (
|
|
695
|
-
let
|
|
696
|
-
return
|
|
697
|
-
} else
|
|
820
|
+
if (L) {
|
|
821
|
+
let x = await q.getDependency("texture", P);
|
|
822
|
+
return x && y.assignLODInformation(r.url, x, i, e, void 0), s && console.log('change "' + t.name + '" → "' + x.name + '"', u, P, x, c), t instanceof F && (x = this.copySettings(t, x)), x && (x.guid = _.guid), d(x);
|
|
823
|
+
} else f && console.warn("Could not find texture with guid", _.guid, D.parser.json);
|
|
698
824
|
}
|
|
699
|
-
if (
|
|
700
|
-
let
|
|
701
|
-
for (const
|
|
702
|
-
if (
|
|
703
|
-
const
|
|
704
|
-
if (
|
|
705
|
-
|
|
825
|
+
if (P = 0, D.parser.json.meshes) {
|
|
826
|
+
let L = !1;
|
|
827
|
+
for (const x of D.parser.json.meshes) {
|
|
828
|
+
if (x?.extensions) {
|
|
829
|
+
const h = x?.extensions[W];
|
|
830
|
+
if (h?.guid && h.guid === _.guid) {
|
|
831
|
+
L = !0;
|
|
706
832
|
break;
|
|
707
833
|
}
|
|
708
834
|
}
|
|
709
|
-
|
|
835
|
+
P++;
|
|
710
836
|
}
|
|
711
|
-
if (
|
|
712
|
-
const
|
|
713
|
-
if (s && console.log(`Loaded Mesh "${
|
|
714
|
-
const
|
|
715
|
-
return y.assignLODInformation(
|
|
837
|
+
if (L) {
|
|
838
|
+
const x = await q.getDependency("mesh", P);
|
|
839
|
+
if (s && console.log(`Loaded Mesh "${x.name}"`, u, P, x, c), x.isMesh === !0) {
|
|
840
|
+
const h = x.geometry;
|
|
841
|
+
return y.assignLODInformation(r.url, h, i, e, 0), d(h);
|
|
716
842
|
} else {
|
|
717
|
-
const
|
|
718
|
-
for (let
|
|
719
|
-
const
|
|
720
|
-
if (
|
|
721
|
-
const
|
|
722
|
-
y.assignLODInformation(
|
|
843
|
+
const h = new Array();
|
|
844
|
+
for (let p = 0; p < x.children.length; p++) {
|
|
845
|
+
const O = x.children[p];
|
|
846
|
+
if (O.isMesh === !0) {
|
|
847
|
+
const S = O.geometry;
|
|
848
|
+
y.assignLODInformation(r.url, S, i, e, p), h.push(S);
|
|
723
849
|
}
|
|
724
850
|
}
|
|
725
|
-
return d(
|
|
851
|
+
return d(h);
|
|
726
852
|
}
|
|
727
|
-
} else
|
|
853
|
+
} else f && console.warn("Could not find mesh with guid", _.guid, D.parser.json);
|
|
728
854
|
}
|
|
729
855
|
return d(null);
|
|
730
856
|
});
|
|
731
|
-
|
|
732
|
-
|
|
857
|
+
this.cache.set(c, k), m.use(k);
|
|
858
|
+
const M = await k;
|
|
859
|
+
return M != null ? M instanceof F ? (this.cache.set(c, new WeakRef(M)), y._resourceRegistry.register(M, c)) : Array.isArray(M) ? this.cache.set(c, Promise.resolve(M)) : this.cache.set(c, Promise.resolve(M)) : this.cache.set(c, Promise.resolve(null)), M;
|
|
860
|
+
} else if (t instanceof F) {
|
|
733
861
|
s && console.log("Load texture from uri: " + u);
|
|
734
|
-
const
|
|
735
|
-
return
|
|
862
|
+
const m = await new Ne().loadAsync(u);
|
|
863
|
+
return m ? (m.guid = o.guid, m.flipY = !1, m.needsUpdate = !0, m.colorSpace = t.colorSpace, s && console.log(o, m)) : f && console.warn("failed loading", u), m;
|
|
736
864
|
}
|
|
737
865
|
}
|
|
738
866
|
return null;
|
|
739
867
|
}
|
|
740
868
|
static maxConcurrent = 50;
|
|
741
|
-
static queue = new
|
|
742
|
-
static assignLODInformation(t, e, s,
|
|
869
|
+
static queue = new rt(y.maxConcurrent, { debug: f != !1 });
|
|
870
|
+
static assignLODInformation(t, e, s, r, i) {
|
|
743
871
|
if (!e) return;
|
|
744
872
|
e.userData || (e.userData = {});
|
|
745
|
-
const o = new
|
|
873
|
+
const o = new pt(t, s, r, i);
|
|
746
874
|
e.userData.LODS = o, "source" in e && typeof e.source == "object" && (e.source.LODS = o);
|
|
747
875
|
}
|
|
748
876
|
static getAssignedLODInformation(t) {
|
|
@@ -750,26 +878,26 @@ class y {
|
|
|
750
878
|
}
|
|
751
879
|
// private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
|
|
752
880
|
static copySettings(t, e) {
|
|
753
|
-
return e ? (
|
|
881
|
+
return e ? (f === "verbose" && console.debug(`Copy texture settings
|
|
754
882
|
`, t.uuid, `
|
|
755
883
|
`, e.uuid), e = e.clone(), 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.mipmaps || (e.generateMipmaps = t.generateMipmaps), e) : t;
|
|
756
884
|
}
|
|
757
885
|
}
|
|
758
|
-
class
|
|
886
|
+
class pt {
|
|
759
887
|
url;
|
|
760
888
|
/** the key to lookup the LOD information */
|
|
761
889
|
key;
|
|
762
890
|
level;
|
|
763
891
|
/** For multi objects (e.g. a group of meshes) this is the index of the object */
|
|
764
892
|
index;
|
|
765
|
-
constructor(t, e, s,
|
|
766
|
-
this.url = t, this.key = e, this.level = s,
|
|
893
|
+
constructor(t, e, s, r) {
|
|
894
|
+
this.url = t, this.key = e, this.level = s, r != null && (this.index = r);
|
|
767
895
|
}
|
|
768
896
|
}
|
|
769
|
-
class
|
|
770
|
-
static addPromise = (t, e, s,
|
|
771
|
-
|
|
772
|
-
|
|
897
|
+
class ce {
|
|
898
|
+
static addPromise = (t, e, s, r) => {
|
|
899
|
+
r.forEach((i) => {
|
|
900
|
+
i.add(t, e, s);
|
|
773
901
|
});
|
|
774
902
|
};
|
|
775
903
|
ready;
|
|
@@ -799,9 +927,9 @@ class ue {
|
|
|
799
927
|
_awaiting = [];
|
|
800
928
|
_maxPromisesPerObject = 1;
|
|
801
929
|
constructor(t, e) {
|
|
802
|
-
const
|
|
803
|
-
this._frame_start = e.waitForFirstCapture ? void 0 : t, this._frames_to_capture =
|
|
804
|
-
this._resolve =
|
|
930
|
+
const r = Math.max(e.frames ?? 2, 2);
|
|
931
|
+
this._frame_start = e.waitForFirstCapture ? void 0 : t, this._frames_to_capture = r, this.ready = new Promise((i) => {
|
|
932
|
+
this._resolve = i;
|
|
805
933
|
}), this.ready.finally(() => {
|
|
806
934
|
this._resolved = !0, this._awaiting.length = 0;
|
|
807
935
|
}), this._signal = e.signal, this._signal?.addEventListener("abort", () => {
|
|
@@ -815,18 +943,18 @@ class ue {
|
|
|
815
943
|
_seen = /* @__PURE__ */ new WeakMap();
|
|
816
944
|
add(t, e, s) {
|
|
817
945
|
if (this._resolved) {
|
|
818
|
-
|
|
946
|
+
f && console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");
|
|
819
947
|
return;
|
|
820
948
|
}
|
|
821
949
|
if (!(this._frame_start !== void 0 && this._currentFrame > this._frame_start + this._frames_to_capture)) {
|
|
822
950
|
if (this._maxPromisesPerObject >= 1)
|
|
823
951
|
if (this._seen.has(e)) {
|
|
824
|
-
let
|
|
825
|
-
if (
|
|
826
|
-
|
|
952
|
+
let r = this._seen.get(e);
|
|
953
|
+
if (r >= this._maxPromisesPerObject) {
|
|
954
|
+
f && console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");
|
|
827
955
|
return;
|
|
828
956
|
}
|
|
829
|
-
this._seen.set(e,
|
|
957
|
+
this._seen.set(e, r + 1);
|
|
830
958
|
} else
|
|
831
959
|
this._seen.set(e, 1);
|
|
832
960
|
this._awaiting.push(s), this._addedCount++, s.finally(() => {
|
|
@@ -842,22 +970,22 @@ class ue {
|
|
|
842
970
|
});
|
|
843
971
|
}
|
|
844
972
|
}
|
|
845
|
-
const
|
|
846
|
-
class
|
|
973
|
+
const R = N("debugprogressive"), mt = N("noprogressive"), de = /* @__PURE__ */ Symbol("Needle:LODSManager"), fe = /* @__PURE__ */ Symbol("Needle:LODState"), U = /* @__PURE__ */ Symbol("Needle:CurrentLOD"), T = { mesh_lod: -1, texture_lod: -1 };
|
|
974
|
+
class v {
|
|
847
975
|
/**
|
|
848
976
|
* 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.
|
|
849
977
|
*/
|
|
850
978
|
static debugDrawLine;
|
|
851
979
|
/** @internal */
|
|
852
980
|
static getObjectLODState(t) {
|
|
853
|
-
return t[
|
|
981
|
+
return t[fe];
|
|
854
982
|
}
|
|
855
983
|
static addPlugin(t) {
|
|
856
|
-
|
|
984
|
+
z.push(t);
|
|
857
985
|
}
|
|
858
986
|
static removePlugin(t) {
|
|
859
|
-
const e =
|
|
860
|
-
e >= 0 &&
|
|
987
|
+
const e = z.indexOf(t);
|
|
988
|
+
e >= 0 && z.splice(e, 1);
|
|
861
989
|
}
|
|
862
990
|
/**
|
|
863
991
|
* Gets the LODsManager for the given renderer. If the LODsManager does not exist yet, it will be created.
|
|
@@ -867,7 +995,7 @@ class L {
|
|
|
867
995
|
static get(t, e) {
|
|
868
996
|
if (t[de])
|
|
869
997
|
return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), t[de];
|
|
870
|
-
const s = new
|
|
998
|
+
const s = new v(t, {
|
|
871
999
|
engine: "unknown",
|
|
872
1000
|
...e
|
|
873
1001
|
});
|
|
@@ -875,10 +1003,10 @@ class L {
|
|
|
875
1003
|
}
|
|
876
1004
|
renderer;
|
|
877
1005
|
context;
|
|
878
|
-
projectionScreenMatrix = new
|
|
1006
|
+
projectionScreenMatrix = new Le();
|
|
879
1007
|
/** @deprecated use static `LODsManager.addPlugin()` method. This getter will be removed in later versions */
|
|
880
1008
|
get plugins() {
|
|
881
|
-
return
|
|
1009
|
+
return z;
|
|
882
1010
|
}
|
|
883
1011
|
/**
|
|
884
1012
|
* Force override the LOD level for all objects (meshes + textures) rendered in the scene
|
|
@@ -919,13 +1047,13 @@ class L {
|
|
|
919
1047
|
* Call to await LODs loading during the next render cycle.
|
|
920
1048
|
*/
|
|
921
1049
|
awaitLoading(t) {
|
|
922
|
-
const e = this._promiseGroupIds++, s = new
|
|
1050
|
+
const e = this._promiseGroupIds++, s = new ce(this.#r, { ...t });
|
|
923
1051
|
this._newPromiseGroups.push(s);
|
|
924
|
-
const
|
|
1052
|
+
const r = performance.now();
|
|
925
1053
|
return s.ready.finally(() => {
|
|
926
|
-
const
|
|
927
|
-
|
|
928
|
-
start:
|
|
1054
|
+
const i = this._newPromiseGroups.indexOf(s);
|
|
1055
|
+
i >= 0 && (this._newPromiseGroups.splice(i, 1), ve() && performance.measure("LODsManager:awaitLoading", {
|
|
1056
|
+
start: r,
|
|
929
1057
|
detail: { id: e, name: t?.name, awaited: s.awaitedCount, resolved: s.resolvedCount }
|
|
930
1058
|
}));
|
|
931
1059
|
}), s.ready;
|
|
@@ -950,10 +1078,10 @@ class L {
|
|
|
950
1078
|
this.renderer = t, this.context = { ...e };
|
|
951
1079
|
}
|
|
952
1080
|
#t;
|
|
953
|
-
#o = new
|
|
1081
|
+
#o = new qe();
|
|
954
1082
|
#r = 0;
|
|
955
|
-
#n = 0;
|
|
956
1083
|
#i = 0;
|
|
1084
|
+
#n = 0;
|
|
957
1085
|
#s = 0;
|
|
958
1086
|
_fpsBuffer = [60, 60, 60, 60, 60];
|
|
959
1087
|
/**
|
|
@@ -965,11 +1093,11 @@ class L {
|
|
|
965
1093
|
let t = 0;
|
|
966
1094
|
this.#t = this.renderer.render;
|
|
967
1095
|
const e = this;
|
|
968
|
-
|
|
969
|
-
const
|
|
970
|
-
(
|
|
1096
|
+
we(this.renderer), this.renderer.render = function(s, r) {
|
|
1097
|
+
const i = e.renderer.getRenderTarget();
|
|
1098
|
+
(i == null || "isXRRenderTarget" in i && i.isXRRenderTarget) && (t = 0, e.#r += 1, e.#i = e.#o.getDelta(), e.#n += e.#i, e._fpsBuffer.shift(), e._fpsBuffer.push(1 / e.#i), e.#s = e._fpsBuffer.reduce((l, a) => l + a) / e._fpsBuffer.length, R && e.#r % 200 === 0 && console.log("FPS", Math.round(e.#s), "Interval:", e.#e));
|
|
971
1099
|
const o = t++;
|
|
972
|
-
e.#t.call(this, s,
|
|
1100
|
+
e.#t.call(this, s, r), e.onAfterRender(s, r, o);
|
|
973
1101
|
};
|
|
974
1102
|
}
|
|
975
1103
|
disable() {
|
|
@@ -980,14 +1108,14 @@ class L {
|
|
|
980
1108
|
}
|
|
981
1109
|
onAfterRender(t, e, s) {
|
|
982
1110
|
if (this.pause) return;
|
|
983
|
-
const
|
|
1111
|
+
const i = this.renderer.renderLists.get(t, 0).opaque;
|
|
984
1112
|
let o = !0;
|
|
985
|
-
if (
|
|
986
|
-
const l =
|
|
1113
|
+
if (i.length === 1) {
|
|
1114
|
+
const l = i[0].material;
|
|
987
1115
|
(l.name === "EffectMaterial" || l.name === "CopyShader") && (o = !1);
|
|
988
1116
|
}
|
|
989
1117
|
if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (o = !1), o) {
|
|
990
|
-
if (
|
|
1118
|
+
if (mt || (this.updateInterval === "auto" ? this.#s < 40 && this.#e < 10 ? (this.#e += 1, R && console.warn("↓ Reducing LOD updates", this.#e, this.#s.toFixed(0))) : this.#s >= 60 && this.#e > 1 && (this.#e -= 1, R && console.warn("↑ Increasing LOD updates", this.#e, this.#s.toFixed(0))) : this.#e = this.updateInterval, this.#e > 0 && this.#r % this.#e != 0))
|
|
991
1119
|
return;
|
|
992
1120
|
this.internalUpdate(t, e), this._postprocessPromiseGroups();
|
|
993
1121
|
}
|
|
@@ -996,12 +1124,12 @@ class L {
|
|
|
996
1124
|
* Update LODs in a scene
|
|
997
1125
|
*/
|
|
998
1126
|
internalUpdate(t, e) {
|
|
999
|
-
const s = this.renderer.renderLists.get(t, 0),
|
|
1127
|
+
const s = this.renderer.renderLists.get(t, 0), r = s.opaque;
|
|
1000
1128
|
this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix, e.matrixWorldInverse);
|
|
1001
|
-
const
|
|
1002
|
-
for (const a of
|
|
1129
|
+
const i = this.targetTriangleDensity;
|
|
1130
|
+
for (const a of r) {
|
|
1003
1131
|
if (a.material && (a.geometry?.type === "BoxGeometry" || a.geometry?.type === "BufferGeometry") && (a.material.name === "SphericalGaussianBlur" || a.material.name == "BackgroundCubeMaterial" || a.material.name === "CubemapFromEquirect" || a.material.name === "EquirectangularToCubeUV")) {
|
|
1004
|
-
|
|
1132
|
+
R && (a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] || (a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] = !0, console.warn("Ignoring skybox or BLIT object", a, a.material.name, a.material.type)));
|
|
1005
1133
|
continue;
|
|
1006
1134
|
}
|
|
1007
1135
|
switch (a.material.type) {
|
|
@@ -1013,38 +1141,38 @@ class L {
|
|
|
1013
1141
|
case "MeshDepthMaterial":
|
|
1014
1142
|
continue;
|
|
1015
1143
|
}
|
|
1016
|
-
if (
|
|
1144
|
+
if (R === "color" && a.material && !a.object.progressive_debug_color) {
|
|
1017
1145
|
a.object.progressive_debug_color = !0;
|
|
1018
|
-
const c = Math.random() * 16777215,
|
|
1019
|
-
a.object.material =
|
|
1146
|
+
const c = Math.random() * 16777215, m = new Ee({ color: c });
|
|
1147
|
+
a.object.material = m;
|
|
1020
1148
|
}
|
|
1021
1149
|
const u = a.object;
|
|
1022
|
-
(u instanceof
|
|
1150
|
+
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1023
1151
|
}
|
|
1024
1152
|
const o = s.transparent;
|
|
1025
1153
|
for (const a of o) {
|
|
1026
1154
|
const u = a.object;
|
|
1027
|
-
(u instanceof
|
|
1155
|
+
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1028
1156
|
}
|
|
1029
1157
|
const l = s.transmissive;
|
|
1030
1158
|
for (const a of l) {
|
|
1031
1159
|
const u = a.object;
|
|
1032
|
-
(u instanceof
|
|
1160
|
+
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1033
1161
|
}
|
|
1034
1162
|
}
|
|
1035
1163
|
/** Update the LOD levels for the renderer. */
|
|
1036
|
-
updateLODs(t, e, s,
|
|
1164
|
+
updateLODs(t, e, s, r) {
|
|
1037
1165
|
s.userData || (s.userData = {});
|
|
1038
|
-
let
|
|
1039
|
-
if (
|
|
1166
|
+
let i = s[fe];
|
|
1167
|
+
if (i || (i = new yt(), s[fe] = i), i.frames++ < 2)
|
|
1040
1168
|
return;
|
|
1041
|
-
for (const l of
|
|
1169
|
+
for (const l of z)
|
|
1042
1170
|
l.onBeforeUpdateLOD?.(this.renderer, t, e, s);
|
|
1043
|
-
const o = this.overrideLodLevel !== void 0 ? this.overrideLodLevel :
|
|
1044
|
-
o >= 0 ? (
|
|
1045
|
-
for (const l of
|
|
1046
|
-
l.onAfterUpdatedLOD?.(this.renderer, t, e, s,
|
|
1047
|
-
|
|
1171
|
+
const o = this.overrideLodLevel !== void 0 ? this.overrideLodLevel : E;
|
|
1172
|
+
o >= 0 ? (T.mesh_lod = o, T.texture_lod = o) : (this.calculateLodLevel(e, s, i, r, T), T.mesh_lod = Math.round(T.mesh_lod), T.texture_lod = Math.round(T.texture_lod)), T.mesh_lod >= 0 && this.loadProgressiveMeshes(s, T.mesh_lod), s.material && T.texture_lod >= 0 && this.loadProgressiveTextures(s.material, T.texture_lod, o), f && s.material && !s.isGizmo && ke(s.material);
|
|
1173
|
+
for (const l of z)
|
|
1174
|
+
l.onAfterUpdatedLOD?.(this.renderer, t, e, s, T);
|
|
1175
|
+
i.lastLodLevel_Mesh = T.mesh_lod, i.lastLodLevel_Texture = T.texture_lod;
|
|
1048
1176
|
}
|
|
1049
1177
|
/** Load progressive textures for the given material
|
|
1050
1178
|
* @param material the material to load the textures for
|
|
@@ -1054,17 +1182,17 @@ class L {
|
|
|
1054
1182
|
loadProgressiveTextures(t, e, s) {
|
|
1055
1183
|
if (!t) return;
|
|
1056
1184
|
if (Array.isArray(t)) {
|
|
1057
|
-
for (const
|
|
1058
|
-
this.loadProgressiveTextures(
|
|
1185
|
+
for (const i of t)
|
|
1186
|
+
this.loadProgressiveTextures(i, e);
|
|
1059
1187
|
return;
|
|
1060
1188
|
}
|
|
1061
|
-
let
|
|
1062
|
-
if ((t[
|
|
1063
|
-
t[
|
|
1064
|
-
const
|
|
1189
|
+
let r = !1;
|
|
1190
|
+
if ((t[U] === void 0 || e < t[U]) && (r = !0), s !== void 0 && s >= 0 && (r = t[U] != s, e = s), r) {
|
|
1191
|
+
t[U] = e;
|
|
1192
|
+
const i = y.assignTextureLOD(t, e).then((o) => {
|
|
1065
1193
|
this._lodchangedlisteners.forEach((l) => l({ type: "texture", level: e, object: t }));
|
|
1066
1194
|
});
|
|
1067
|
-
|
|
1195
|
+
ce.addPromise("texture", t, i, this._newPromiseGroups);
|
|
1068
1196
|
}
|
|
1069
1197
|
}
|
|
1070
1198
|
/** Load progressive meshes for the given mesh
|
|
@@ -1075,20 +1203,20 @@ class L {
|
|
|
1075
1203
|
*/
|
|
1076
1204
|
loadProgressiveMeshes(t, e) {
|
|
1077
1205
|
if (!t) return Promise.resolve(null);
|
|
1078
|
-
let s = t[
|
|
1079
|
-
const
|
|
1080
|
-
if (
|
|
1081
|
-
t[
|
|
1082
|
-
const
|
|
1083
|
-
return
|
|
1206
|
+
let s = t[U] !== e;
|
|
1207
|
+
const r = t["DEBUG:LOD"];
|
|
1208
|
+
if (r != null && (s = t[U] != r, e = r), s) {
|
|
1209
|
+
t[U] = e;
|
|
1210
|
+
const i = t.geometry, o = y.assignMeshLOD(t, e).then((l) => (l && t[U] == e && i != t.geometry && this._lodchangedlisteners.forEach((a) => a({ type: "mesh", level: e, object: t })), l));
|
|
1211
|
+
return ce.addPromise("mesh", t, o, this._newPromiseGroups), o;
|
|
1084
1212
|
}
|
|
1085
1213
|
return Promise.resolve(null);
|
|
1086
1214
|
}
|
|
1087
1215
|
// private testIfLODLevelsAreAvailable() {
|
|
1088
|
-
_sphere = new
|
|
1089
|
-
_tempBox = new
|
|
1090
|
-
_tempBox2 = new
|
|
1091
|
-
tempMatrix = new
|
|
1216
|
+
_sphere = new Oe();
|
|
1217
|
+
_tempBox = new ge();
|
|
1218
|
+
_tempBox2 = new ge();
|
|
1219
|
+
tempMatrix = new Le();
|
|
1092
1220
|
_tempWorldPosition = new A();
|
|
1093
1221
|
_tempBoxSize = new A();
|
|
1094
1222
|
_tempBox2Size = new A();
|
|
@@ -1098,120 +1226,120 @@ class L {
|
|
|
1098
1226
|
static corner3 = new A();
|
|
1099
1227
|
static _tempPtInside = new A();
|
|
1100
1228
|
static isInside(t, e) {
|
|
1101
|
-
const s = t.min,
|
|
1102
|
-
return this._tempPtInside.set(
|
|
1229
|
+
const s = t.min, r = t.max, i = (s.x + r.x) * 0.5, o = (s.y + r.y) * 0.5;
|
|
1230
|
+
return this._tempPtInside.set(i, o, s.z).applyMatrix4(e).z < 0;
|
|
1103
1231
|
}
|
|
1104
1232
|
static skinnedMeshBoundsFrameOffsetCounter = 0;
|
|
1105
|
-
static $skinnedMeshBoundsOffset = Symbol("gltf-progressive-skinnedMeshBoundsOffset");
|
|
1233
|
+
static $skinnedMeshBoundsOffset = /* @__PURE__ */ Symbol("gltf-progressive-skinnedMeshBoundsOffset");
|
|
1106
1234
|
// #region calculateLodLevel
|
|
1107
|
-
calculateLodLevel(t, e, s,
|
|
1235
|
+
calculateLodLevel(t, e, s, r, i) {
|
|
1108
1236
|
if (!e) {
|
|
1109
|
-
|
|
1237
|
+
i.mesh_lod = -1, i.texture_lod = -1;
|
|
1110
1238
|
return;
|
|
1111
1239
|
}
|
|
1112
1240
|
if (!t) {
|
|
1113
|
-
|
|
1241
|
+
i.mesh_lod = -1, i.texture_lod = -1;
|
|
1114
1242
|
return;
|
|
1115
1243
|
}
|
|
1116
1244
|
let l = 10 + 1, a = !1;
|
|
1117
|
-
if (
|
|
1245
|
+
if (R && e["DEBUG:LOD"] != null)
|
|
1118
1246
|
return e["DEBUG:LOD"];
|
|
1119
|
-
const u = y.getMeshLODExtension(e.geometry)?.lods, c = y.getPrimitiveIndex(e.geometry),
|
|
1120
|
-
if (!
|
|
1121
|
-
|
|
1247
|
+
const u = y.getMeshLODExtension(e.geometry)?.lods, c = y.getPrimitiveIndex(e.geometry), m = u && u.length > 0, w = y.getMaterialMinMaxLODsCount(e.material), _ = w.min_count !== 1 / 0 && w.min_count >= 0 && w.max_count >= 0;
|
|
1248
|
+
if (!m && !_) {
|
|
1249
|
+
i.mesh_lod = 0, i.texture_lod = 0;
|
|
1122
1250
|
return;
|
|
1123
1251
|
}
|
|
1124
|
-
|
|
1125
|
-
const
|
|
1126
|
-
let
|
|
1252
|
+
m || (a = !0, l = 0);
|
|
1253
|
+
const k = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
|
|
1254
|
+
let M = e.geometry.boundingBox;
|
|
1127
1255
|
if (e.type === "SkinnedMesh") {
|
|
1128
1256
|
const d = e;
|
|
1129
1257
|
if (!d.boundingBox)
|
|
1130
1258
|
d.computeBoundingBox();
|
|
1131
1259
|
else if (this.skinnedMeshAutoUpdateBoundsInterval > 0) {
|
|
1132
|
-
if (!d[
|
|
1133
|
-
const
|
|
1134
|
-
d[
|
|
1260
|
+
if (!d[v.$skinnedMeshBoundsOffset]) {
|
|
1261
|
+
const b = v.skinnedMeshBoundsFrameOffsetCounter++;
|
|
1262
|
+
d[v.$skinnedMeshBoundsOffset] = b;
|
|
1135
1263
|
}
|
|
1136
|
-
const
|
|
1137
|
-
if ((s.frames +
|
|
1138
|
-
const
|
|
1139
|
-
|
|
1264
|
+
const g = d[v.$skinnedMeshBoundsOffset];
|
|
1265
|
+
if ((s.frames + g) % this.skinnedMeshAutoUpdateBoundsInterval === 0) {
|
|
1266
|
+
const b = ee(d), B = d.geometry;
|
|
1267
|
+
b && (d.geometry = b), d.computeBoundingBox(), d.geometry = B;
|
|
1140
1268
|
}
|
|
1141
1269
|
}
|
|
1142
|
-
|
|
1270
|
+
M = d.boundingBox;
|
|
1143
1271
|
}
|
|
1144
|
-
if (
|
|
1272
|
+
if (M) {
|
|
1145
1273
|
const d = t;
|
|
1146
1274
|
if (e.geometry.attributes.color && e.geometry.attributes.color.count < 100 && e.geometry.boundingSphere) {
|
|
1147
1275
|
this._sphere.copy(e.geometry.boundingSphere), this._sphere.applyMatrix4(e.matrixWorld);
|
|
1148
|
-
const
|
|
1149
|
-
if (this._sphere.containsPoint(
|
|
1150
|
-
|
|
1276
|
+
const h = t.getWorldPosition(this._tempWorldPosition);
|
|
1277
|
+
if (this._sphere.containsPoint(h)) {
|
|
1278
|
+
i.mesh_lod = 0, i.texture_lod = 0;
|
|
1151
1279
|
return;
|
|
1152
1280
|
}
|
|
1153
1281
|
}
|
|
1154
|
-
if (this._tempBox.copy(
|
|
1155
|
-
|
|
1282
|
+
if (this._tempBox.copy(M), this._tempBox.applyMatrix4(e.matrixWorld), d.isPerspectiveCamera && v.isInside(this._tempBox, this.projectionScreenMatrix)) {
|
|
1283
|
+
i.mesh_lod = 0, i.texture_lod = 0;
|
|
1156
1284
|
return;
|
|
1157
1285
|
}
|
|
1158
1286
|
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && d.isPerspectiveCamera && d.fov > 70) {
|
|
1159
|
-
const
|
|
1160
|
-
let
|
|
1161
|
-
const
|
|
1162
|
-
|
|
1163
|
-
const
|
|
1164
|
-
s.lastCentrality = (
|
|
1287
|
+
const h = this._tempBox.min, p = this._tempBox.max;
|
|
1288
|
+
let O = h.x, S = h.y, G = p.x, Y = p.y;
|
|
1289
|
+
const te = 2, ne = 1.5, se = (h.x + p.x) * 0.5, re = (h.y + p.y) * 0.5;
|
|
1290
|
+
O = (O - se) * te + se, S = (S - re) * te + re, G = (G - se) * te + se, Y = (Y - re) * te + re;
|
|
1291
|
+
const $e = O < 0 && G > 0 ? 0 : Math.min(Math.abs(h.x), Math.abs(p.x)), Be = S < 0 && Y > 0 ? 0 : Math.min(Math.abs(h.y), Math.abs(p.y)), ae = Math.max($e, Be);
|
|
1292
|
+
s.lastCentrality = (ne - ae) * (ne - ae) * (ne - ae);
|
|
1165
1293
|
} else
|
|
1166
1294
|
s.lastCentrality = 1;
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
const
|
|
1170
|
-
B.copy(
|
|
1171
|
-
const
|
|
1172
|
-
if (Math.max(
|
|
1173
|
-
const
|
|
1174
|
-
|
|
1175
|
-
const
|
|
1176
|
-
|
|
1177
|
-
const
|
|
1178
|
-
|
|
1295
|
+
const g = this._tempBox.getSize(this._tempBoxSize);
|
|
1296
|
+
g.multiplyScalar(0.5), screen.availHeight > 0 && k > 0 && g.multiplyScalar(k / screen.availHeight), t.isPerspectiveCamera ? g.x *= t.aspect : t.isOrthographicCamera;
|
|
1297
|
+
const b = t.matrixWorldInverse, B = this._tempBox2;
|
|
1298
|
+
B.copy(M), B.applyMatrix4(e.matrixWorld), B.applyMatrix4(b);
|
|
1299
|
+
const D = B.getSize(this._tempBox2Size), q = Math.max(D.x, D.y);
|
|
1300
|
+
if (Math.max(g.x, g.y) != 0 && q != 0 && (g.z = D.z / Math.max(D.x, D.y) * Math.max(g.x, g.y)), s.lastScreenCoverage = Math.max(g.x, g.y, g.z), s.lastScreenspaceVolume.copy(g), s.lastScreenCoverage *= s.lastCentrality, R && v.debugDrawLine) {
|
|
1301
|
+
const h = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
1302
|
+
h.invert();
|
|
1303
|
+
const p = v.corner0, O = v.corner1, S = v.corner2, G = v.corner3;
|
|
1304
|
+
p.copy(this._tempBox.min), O.copy(this._tempBox.max), O.x = p.x, S.copy(this._tempBox.max), S.y = p.y, G.copy(this._tempBox.max);
|
|
1305
|
+
const Y = (p.z + G.z) * 0.5;
|
|
1306
|
+
p.z = O.z = S.z = G.z = Y, p.applyMatrix4(h), O.applyMatrix4(h), S.applyMatrix4(h), G.applyMatrix4(h), v.debugDrawLine(p, O, 255), v.debugDrawLine(p, S, 255), v.debugDrawLine(O, G, 255), v.debugDrawLine(S, G, 255);
|
|
1179
1307
|
}
|
|
1180
|
-
let
|
|
1308
|
+
let L = 999;
|
|
1181
1309
|
if (u && s.lastScreenCoverage > 0)
|
|
1182
|
-
for (let
|
|
1183
|
-
const
|
|
1184
|
-
if (c > 0 &&
|
|
1185
|
-
|
|
1310
|
+
for (let h = 0; h < u.length; h++) {
|
|
1311
|
+
const p = u[h], S = (p.densities?.[c] || p.density || 1e-5) / s.lastScreenCoverage;
|
|
1312
|
+
if (c > 0 && ve() && !p.densities && !globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"] && (window["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"] = !0, console.warn("[Needle Progressive] Detected usage of mesh without primitive densities. This might cause incorrect LOD level selection: Consider re-optimizing your model by updating your Needle Integration, Needle glTF Pipeline or running optimization again on Needle Cloud.")), S < r) {
|
|
1313
|
+
L = h;
|
|
1186
1314
|
break;
|
|
1187
1315
|
}
|
|
1188
1316
|
}
|
|
1189
|
-
|
|
1317
|
+
L < l && (l = L, a = !0);
|
|
1190
1318
|
}
|
|
1191
|
-
if (a ?
|
|
1192
|
-
const
|
|
1193
|
-
|
|
1319
|
+
if (a ? i.mesh_lod = l : i.mesh_lod = s.lastLodLevel_Mesh, R && i.mesh_lod != s.lastLodLevel_Mesh) {
|
|
1320
|
+
const g = u?.[i.mesh_lod];
|
|
1321
|
+
g && console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${i.mesh_lod} (density: ${g.densities?.[c].toFixed(0)}) | ${e.name}`);
|
|
1194
1322
|
}
|
|
1195
|
-
if (
|
|
1323
|
+
if (_) {
|
|
1196
1324
|
const d = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
|
|
1197
1325
|
if (s.lastLodLevel_Texture < 0) {
|
|
1198
|
-
if (
|
|
1199
|
-
const
|
|
1200
|
-
|
|
1326
|
+
if (i.texture_lod = w.max_count - 1, R) {
|
|
1327
|
+
const g = w.lods[w.max_count - 1];
|
|
1328
|
+
R && console.log(`First Texture LOD ${i.texture_lod} (${g.max_height}px) - ${e.name}`);
|
|
1201
1329
|
}
|
|
1202
1330
|
} else {
|
|
1203
|
-
const
|
|
1204
|
-
let
|
|
1205
|
-
this.context?.engine === "model-viewer" && (
|
|
1206
|
-
const
|
|
1207
|
-
let
|
|
1208
|
-
for (let
|
|
1209
|
-
const
|
|
1210
|
-
if (!(d &&
|
|
1211
|
-
if (
|
|
1212
|
-
const
|
|
1213
|
-
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${
|
|
1214
|
-
Screensize: ${
|
|
1331
|
+
const g = s.lastScreenspaceVolume.x + s.lastScreenspaceVolume.y + s.lastScreenspaceVolume.z;
|
|
1332
|
+
let b = s.lastScreenCoverage * 4;
|
|
1333
|
+
this.context?.engine === "model-viewer" && (b *= 1.5);
|
|
1334
|
+
const D = k / window.devicePixelRatio * b;
|
|
1335
|
+
let q = !1;
|
|
1336
|
+
for (let P = w.lods.length - 1; P >= 0; P--) {
|
|
1337
|
+
const L = w.lods[P];
|
|
1338
|
+
if (!(d && L.max_height >= 2048) && !(Ae() && L.max_height > 4096) && (L.max_height > D || !q && P === 0)) {
|
|
1339
|
+
if (q = !0, i.texture_lod = P, R && i.texture_lod < s.lastLodLevel_Texture) {
|
|
1340
|
+
const x = L.max_height;
|
|
1341
|
+
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${i.texture_lod} = ${x}px
|
|
1342
|
+
Screensize: ${D.toFixed(0)}px, Coverage: ${(100 * s.lastScreenCoverage).toFixed(2)}%, Volume ${g.toFixed(1)}
|
|
1215
1343
|
${e.name}`);
|
|
1216
1344
|
}
|
|
1217
1345
|
break;
|
|
@@ -1219,10 +1347,10 @@ ${e.name}`);
|
|
|
1219
1347
|
}
|
|
1220
1348
|
}
|
|
1221
1349
|
} else
|
|
1222
|
-
|
|
1350
|
+
i.texture_lod = 0;
|
|
1223
1351
|
}
|
|
1224
1352
|
}
|
|
1225
|
-
class
|
|
1353
|
+
class yt {
|
|
1226
1354
|
frames = 0;
|
|
1227
1355
|
lastLodLevel_Mesh = -1;
|
|
1228
1356
|
lastLodLevel_Texture = -1;
|
|
@@ -1230,75 +1358,75 @@ class pt {
|
|
|
1230
1358
|
lastScreenspaceVolume = new A();
|
|
1231
1359
|
lastCentrality = 0;
|
|
1232
1360
|
}
|
|
1233
|
-
const
|
|
1234
|
-
let
|
|
1235
|
-
function
|
|
1236
|
-
const
|
|
1237
|
-
|
|
1238
|
-
return
|
|
1239
|
-
}),
|
|
1361
|
+
const be = /* @__PURE__ */ Symbol("NEEDLE_mesh_lod"), ie = /* @__PURE__ */ Symbol("NEEDLE_texture_lod");
|
|
1362
|
+
let he = null;
|
|
1363
|
+
function Re() {
|
|
1364
|
+
const n = xt();
|
|
1365
|
+
n && (n.mapURLs(function(t) {
|
|
1366
|
+
return Me(), t;
|
|
1367
|
+
}), Me(), he?.disconnect(), he = new MutationObserver((t) => {
|
|
1240
1368
|
t.forEach((e) => {
|
|
1241
1369
|
e.addedNodes.forEach((s) => {
|
|
1242
|
-
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" &&
|
|
1370
|
+
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" && Ie(s);
|
|
1243
1371
|
});
|
|
1244
1372
|
});
|
|
1245
|
-
}),
|
|
1373
|
+
}), he.observe(document, { childList: !0, subtree: !0 }));
|
|
1246
1374
|
}
|
|
1247
|
-
function
|
|
1375
|
+
function xt() {
|
|
1248
1376
|
if (typeof customElements > "u") return null;
|
|
1249
|
-
const
|
|
1250
|
-
return
|
|
1251
|
-
console.debug("[gltf-progressive] model-viewer defined"),
|
|
1377
|
+
const n = customElements.get("model-viewer");
|
|
1378
|
+
return n || (customElements.whenDefined("model-viewer").then(() => {
|
|
1379
|
+
console.debug("[gltf-progressive] model-viewer defined"), Re();
|
|
1252
1380
|
}), null);
|
|
1253
1381
|
}
|
|
1254
|
-
function
|
|
1382
|
+
function Me() {
|
|
1255
1383
|
if (typeof document > "u") return;
|
|
1256
1384
|
document.querySelectorAll("model-viewer").forEach((t) => {
|
|
1257
|
-
|
|
1385
|
+
Ie(t);
|
|
1258
1386
|
});
|
|
1259
1387
|
}
|
|
1260
|
-
const
|
|
1261
|
-
let
|
|
1262
|
-
function
|
|
1263
|
-
if (!
|
|
1388
|
+
const De = /* @__PURE__ */ new WeakSet();
|
|
1389
|
+
let wt = 0;
|
|
1390
|
+
function Ie(n) {
|
|
1391
|
+
if (!n || De.has(n))
|
|
1264
1392
|
return null;
|
|
1265
|
-
|
|
1266
|
-
`,
|
|
1393
|
+
De.add(n), console.debug("[gltf-progressive] found new model-viewer..." + ++wt + `
|
|
1394
|
+
`, n.getAttribute("src"));
|
|
1267
1395
|
let t = null, e = null, s = null;
|
|
1268
|
-
for (let
|
|
1269
|
-
const
|
|
1270
|
-
!t && o != null && (t =
|
|
1396
|
+
for (let r = n; r != null; r = Object.getPrototypeOf(r)) {
|
|
1397
|
+
const i = Object.getOwnPropertySymbols(r), o = i.find((u) => u.toString() == "Symbol(renderer)"), l = i.find((u) => u.toString() == "Symbol(scene)"), a = i.find((u) => u.toString() == "Symbol(needsRender)");
|
|
1398
|
+
!t && o != null && (t = n[o].threeRenderer), !e && l != null && (e = n[l]), !s && a != null && (s = n[a]);
|
|
1271
1399
|
}
|
|
1272
1400
|
if (t && e) {
|
|
1273
|
-
let
|
|
1401
|
+
let r = function() {
|
|
1274
1402
|
if (s) {
|
|
1275
1403
|
let o = 0, l = setInterval(() => {
|
|
1276
1404
|
if (o++ > 5) {
|
|
1277
1405
|
clearInterval(l);
|
|
1278
1406
|
return;
|
|
1279
1407
|
}
|
|
1280
|
-
s?.call(
|
|
1408
|
+
s?.call(n);
|
|
1281
1409
|
}, 300);
|
|
1282
1410
|
}
|
|
1283
1411
|
};
|
|
1284
1412
|
console.debug("[gltf-progressive] setup model-viewer");
|
|
1285
|
-
const
|
|
1286
|
-
return
|
|
1287
|
-
s?.call(
|
|
1288
|
-
}),
|
|
1289
|
-
o.detail.visible && s?.call(
|
|
1290
|
-
}),
|
|
1291
|
-
|
|
1413
|
+
const i = v.get(t, { engine: "model-viewer" });
|
|
1414
|
+
return v.addPlugin(new _t()), i.enable(), i.addEventListener("changed", () => {
|
|
1415
|
+
s?.call(n);
|
|
1416
|
+
}), n.addEventListener("model-visibility", (o) => {
|
|
1417
|
+
o.detail.visible && s?.call(n);
|
|
1418
|
+
}), n.addEventListener("load", () => {
|
|
1419
|
+
r();
|
|
1292
1420
|
}), () => {
|
|
1293
|
-
|
|
1421
|
+
i.disable();
|
|
1294
1422
|
};
|
|
1295
1423
|
}
|
|
1296
1424
|
return null;
|
|
1297
1425
|
}
|
|
1298
|
-
class
|
|
1426
|
+
class _t {
|
|
1299
1427
|
_didWarnAboutMissingUrl = !1;
|
|
1300
|
-
onBeforeUpdateLOD(t, e, s,
|
|
1301
|
-
this.tryParseMeshLOD(e,
|
|
1428
|
+
onBeforeUpdateLOD(t, e, s, r) {
|
|
1429
|
+
this.tryParseMeshLOD(e, r), this.tryParseTextureLOD(e, r);
|
|
1302
1430
|
}
|
|
1303
1431
|
getUrl(t) {
|
|
1304
1432
|
if (!t)
|
|
@@ -1313,27 +1441,27 @@ class xt {
|
|
|
1313
1441
|
return t.element;
|
|
1314
1442
|
}
|
|
1315
1443
|
tryParseTextureLOD(t, e) {
|
|
1316
|
-
if (e[
|
|
1317
|
-
e[
|
|
1318
|
-
const s = this.tryGetCurrentGLTF(t),
|
|
1319
|
-
if (
|
|
1444
|
+
if (e[ie] == !0) return;
|
|
1445
|
+
e[ie] = !0;
|
|
1446
|
+
const s = this.tryGetCurrentGLTF(t), r = this.tryGetCurrentModelViewer(t), i = this.getUrl(r);
|
|
1447
|
+
if (i && s && e.material) {
|
|
1320
1448
|
let o = function(a) {
|
|
1321
|
-
if (a[
|
|
1322
|
-
a[
|
|
1449
|
+
if (a[ie] == !0) return;
|
|
1450
|
+
a[ie] = !0, a.userData && (a.userData.LOD = -1);
|
|
1323
1451
|
const u = Object.keys(a);
|
|
1324
1452
|
for (let c = 0; c < u.length; c++) {
|
|
1325
|
-
const
|
|
1326
|
-
if (
|
|
1327
|
-
const
|
|
1328
|
-
if (
|
|
1329
|
-
const
|
|
1330
|
-
if (!
|
|
1331
|
-
console.warn("Texture data not found for texture index " +
|
|
1453
|
+
const m = u[c], w = a[m];
|
|
1454
|
+
if (w?.isTexture === !0) {
|
|
1455
|
+
const _ = w.userData?.associations?.textures;
|
|
1456
|
+
if (_ == null) continue;
|
|
1457
|
+
const k = s.parser.json.textures[_];
|
|
1458
|
+
if (!k) {
|
|
1459
|
+
console.warn("Texture data not found for texture index " + _);
|
|
1332
1460
|
continue;
|
|
1333
1461
|
}
|
|
1334
|
-
if (
|
|
1335
|
-
const
|
|
1336
|
-
|
|
1462
|
+
if (k?.extensions?.[W]) {
|
|
1463
|
+
const M = k.extensions[W];
|
|
1464
|
+
M && i && y.registerTexture(i, w, M.lods.length, _, M);
|
|
1337
1465
|
}
|
|
1338
1466
|
}
|
|
1339
1467
|
}
|
|
@@ -1344,70 +1472,70 @@ class xt {
|
|
|
1344
1472
|
}
|
|
1345
1473
|
}
|
|
1346
1474
|
tryParseMeshLOD(t, e) {
|
|
1347
|
-
if (e[
|
|
1348
|
-
e[
|
|
1349
|
-
const s = this.tryGetCurrentModelViewer(t),
|
|
1350
|
-
if (!
|
|
1475
|
+
if (e[be] == !0) return;
|
|
1476
|
+
e[be] = !0;
|
|
1477
|
+
const s = this.tryGetCurrentModelViewer(t), r = this.getUrl(s);
|
|
1478
|
+
if (!r)
|
|
1351
1479
|
return;
|
|
1352
|
-
const
|
|
1353
|
-
if (
|
|
1480
|
+
const i = e.userData?.gltfExtensions?.[W];
|
|
1481
|
+
if (i && r) {
|
|
1354
1482
|
const o = e.uuid;
|
|
1355
|
-
y.registerMesh(
|
|
1483
|
+
y.registerMesh(r, o, e, 0, i.lods.length, i);
|
|
1356
1484
|
}
|
|
1357
1485
|
}
|
|
1358
1486
|
}
|
|
1359
|
-
function
|
|
1360
|
-
let t, e, s,
|
|
1361
|
-
switch (
|
|
1487
|
+
function Lt(...n) {
|
|
1488
|
+
let t, e, s, r;
|
|
1489
|
+
switch (n.length) {
|
|
1362
1490
|
case 2:
|
|
1363
|
-
[s, e] =
|
|
1491
|
+
[s, e] = n, r = {};
|
|
1364
1492
|
break;
|
|
1365
1493
|
case 3:
|
|
1366
|
-
[s, e,
|
|
1494
|
+
[s, e, r] = n;
|
|
1367
1495
|
break;
|
|
1368
1496
|
case 4:
|
|
1369
|
-
[t, e, s,
|
|
1497
|
+
[t, e, s, r] = n;
|
|
1370
1498
|
break;
|
|
1371
1499
|
default:
|
|
1372
1500
|
throw new Error("Invalid arguments");
|
|
1373
1501
|
}
|
|
1374
|
-
|
|
1502
|
+
we(e), Pe(s), Ce(s, {
|
|
1375
1503
|
progressive: !0,
|
|
1376
|
-
...
|
|
1504
|
+
...r?.hints
|
|
1377
1505
|
}), s.register((o) => new y(o));
|
|
1378
|
-
const
|
|
1379
|
-
return
|
|
1506
|
+
const i = v.get(e);
|
|
1507
|
+
return r?.enableLODsManager !== !1 && i.enable(), i;
|
|
1380
1508
|
}
|
|
1381
|
-
|
|
1382
|
-
if (!
|
|
1383
|
-
const
|
|
1509
|
+
Re();
|
|
1510
|
+
if (!nt) {
|
|
1511
|
+
const n = {
|
|
1384
1512
|
gltfProgressive: {
|
|
1385
|
-
useNeedleProgressive:
|
|
1386
|
-
LODsManager:
|
|
1387
|
-
configureLoader:
|
|
1388
|
-
getRaycastMesh:
|
|
1389
|
-
useRaycastMeshes:
|
|
1513
|
+
useNeedleProgressive: Lt,
|
|
1514
|
+
LODsManager: v,
|
|
1515
|
+
configureLoader: Ce,
|
|
1516
|
+
getRaycastMesh: ee,
|
|
1517
|
+
useRaycastMeshes: lt
|
|
1390
1518
|
}
|
|
1391
1519
|
};
|
|
1392
1520
|
if (!globalThis.Needle)
|
|
1393
|
-
globalThis.Needle =
|
|
1521
|
+
globalThis.Needle = n;
|
|
1394
1522
|
else
|
|
1395
|
-
for (const t in
|
|
1396
|
-
globalThis.Needle[t] =
|
|
1523
|
+
for (const t in n)
|
|
1524
|
+
globalThis.Needle[t] = n[t];
|
|
1397
1525
|
}
|
|
1398
1526
|
export {
|
|
1399
|
-
|
|
1400
|
-
|
|
1527
|
+
W as EXTENSION_NAME,
|
|
1528
|
+
v as LODsManager,
|
|
1401
1529
|
y as NEEDLE_progressive,
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1530
|
+
Ke as VERSION,
|
|
1531
|
+
Pe as addDracoAndKTX2Loaders,
|
|
1532
|
+
Ce as configureLoader,
|
|
1533
|
+
we as createLoaders,
|
|
1534
|
+
ee as getRaycastMesh,
|
|
1535
|
+
Re as patchModelViewer,
|
|
1536
|
+
at as registerRaycastMesh,
|
|
1537
|
+
Je as setDracoDecoderLocation,
|
|
1538
|
+
Ze as setKTX2TranscoderLocation,
|
|
1539
|
+
Lt as useNeedleProgressive,
|
|
1540
|
+
lt as useRaycastMeshes
|
|
1413
1541
|
};
|