@needle-tools/gltf-progressive 3.4.0-beta → 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/gltf-progressive.js +635 -584
- package/gltf-progressive.min.js +9 -8
- package/gltf-progressive.umd.cjs +8 -7
- package/lib/extension.d.ts +13 -0
- package/lib/extension.js +105 -23
- 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 Ye =
|
|
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,87 +110,99 @@ 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 ot(
|
|
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
|
|
136
|
-
let
|
|
137
|
-
|
|
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);
|
|
148
|
+
let o;
|
|
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 z = new Array(),
|
|
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
|
|
193
|
-
|
|
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;
|
|
205
|
+
o.startsWith("blob:") && URL.revokeObjectURL(o);
|
|
194
206
|
}
|
|
195
207
|
}
|
|
196
208
|
}, t.onerror = (s) => {
|
|
@@ -207,18 +219,18 @@ class we {
|
|
|
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,51 +248,51 @@ 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
|
|
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
|
|
259
|
-
), s.boundingBox.max = new
|
|
271
|
+
), s.boundingBox.max = new A(
|
|
260
272
|
e.boundingBox?.max.x,
|
|
261
273
|
e.boundingBox?.max.y,
|
|
262
274
|
e.boundingBox?.max.z
|
|
263
|
-
), s.boundingSphere = new
|
|
264
|
-
new
|
|
275
|
+
), s.boundingSphere = new Oe(
|
|
276
|
+
new A(
|
|
265
277
|
e.boundingSphere?.center.x,
|
|
266
278
|
e.boundingSphere?.center.y,
|
|
267
279
|
e.boundingSphere?.center.z
|
|
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
|
-
o,
|
|
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,
|
|
283
|
-
|
|
294
|
+
i,
|
|
295
|
+
o,
|
|
284
296
|
e.format,
|
|
285
297
|
e.type,
|
|
286
298
|
e.mapping,
|
|
@@ -303,25 +315,27 @@ 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
|
|
324
|
-
|
|
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";
|
|
338
|
+
class y {
|
|
325
339
|
/** The name of the extension */
|
|
326
340
|
get name() {
|
|
327
341
|
return W;
|
|
@@ -336,8 +350,8 @@ class m {
|
|
|
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,31 +359,31 @@ class m {
|
|
|
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;
|
|
354
|
-
u?.isTexture === !0 &&
|
|
368
|
+
u?.isTexture === !0 && o(u, e);
|
|
355
369
|
}
|
|
356
370
|
} else if (t.isMaterial)
|
|
357
371
|
for (const l of Object.keys(t)) {
|
|
358
372
|
const a = t[l];
|
|
359
|
-
a?.isTexture === !0 &&
|
|
373
|
+
a?.isTexture === !0 && o(a, e);
|
|
360
374
|
}
|
|
361
375
|
else
|
|
362
|
-
|
|
363
|
-
return t[
|
|
364
|
-
function
|
|
376
|
+
f && console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);
|
|
377
|
+
return t[r] = e, e;
|
|
378
|
+
function o(l, a) {
|
|
365
379
|
const u = s.getAssignedLODInformation(l);
|
|
366
380
|
if (u) {
|
|
367
|
-
const
|
|
368
|
-
if (
|
|
369
|
-
a.min_count = Math.min(a.min_count,
|
|
370
|
-
for (let
|
|
371
|
-
const w =
|
|
372
|
-
w.width && (a.lods[
|
|
381
|
+
const c = s.lodInfos.get(u.key);
|
|
382
|
+
if (c && c.lods) {
|
|
383
|
+
a.min_count = Math.min(a.min_count, c.lods.length), a.max_count = Math.max(a.max_count, c.lods.length);
|
|
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 m {
|
|
|
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
|
|
392
|
-
if (
|
|
404
|
+
for (const i of Object.keys(t)) {
|
|
405
|
+
const o = t[i];
|
|
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 m {
|
|
|
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,
|
|
433
|
-
if (Array.isArray(
|
|
434
|
-
const
|
|
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,44 +458,44 @@ class m {
|
|
|
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
|
|
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(
|
|
453
|
-
const
|
|
454
|
-
for (const l of
|
|
455
|
-
Array.isArray(l) &&
|
|
456
|
-
return
|
|
466
|
+
return Promise.all(r).then((i) => {
|
|
467
|
+
const o = new Array();
|
|
468
|
+
for (const l of i)
|
|
469
|
+
Array.isArray(l) && o.push(...l);
|
|
470
|
+
return o;
|
|
457
471
|
});
|
|
458
472
|
} else
|
|
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
|
-
const
|
|
465
|
-
for (const l of Object.keys(
|
|
466
|
-
const a =
|
|
478
|
+
const o = s;
|
|
479
|
+
for (const l of Object.keys(o.uniforms)) {
|
|
480
|
+
const a = o.uniforms[l].value;
|
|
467
481
|
if (a?.isTexture === !0) {
|
|
468
|
-
const u = this.assignTextureLODForSlot(a, e, s, l).then((
|
|
469
|
-
|
|
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));
|
|
483
|
+
r.push(u), i.push(l);
|
|
470
484
|
}
|
|
471
485
|
}
|
|
472
486
|
} else
|
|
473
|
-
for (const
|
|
474
|
-
const l = s[
|
|
487
|
+
for (const o of Object.keys(s)) {
|
|
488
|
+
const l = s[o];
|
|
475
489
|
if (l?.isTexture === !0) {
|
|
476
|
-
const a = this.assignTextureLODForSlot(l, e, s,
|
|
477
|
-
|
|
490
|
+
const a = this.assignTextureLODForSlot(l, e, s, o);
|
|
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
|
-
for (let a = 0; a <
|
|
483
|
-
const u =
|
|
484
|
-
u && u.isTexture === !0 ? l.push({ material: s, slot:
|
|
496
|
+
for (let a = 0; a < o.length; a++) {
|
|
497
|
+
const u = o[a], c = i[a];
|
|
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
|
});
|
|
@@ -493,40 +507,40 @@ class m {
|
|
|
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
|
|
503
|
-
if (
|
|
504
|
-
const l = this.getAssignedLODInformation(
|
|
514
|
+
if (i?.isTexture === !0) {
|
|
515
|
+
if (i != t && s && r) {
|
|
516
|
+
const o = s[r];
|
|
517
|
+
if (o && !f) {
|
|
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
542
|
const e = this.parser.json.meshes[t]?.extensions?.[W];
|
|
529
|
-
return e ? (this._isLoadingMesh = !0, this.parser.getDependency("mesh", t).then((s) => (this._isLoadingMesh = !1, s &&
|
|
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;
|
|
532
546
|
// loadTexture = (textureIndex: number) => {
|
|
@@ -543,30 +557,30 @@ class m {
|
|
|
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
|
|
555
|
-
for (const
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
568
|
+
let i = !1;
|
|
569
|
+
for (const o of this.parser.associations.keys())
|
|
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
|
|
569
|
-
|
|
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,38 +589,39 @@ class m {
|
|
|
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
|
|
589
|
-
|
|
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 u =
|
|
602
|
-
u ? u.push(s.geometry) : u = [s.geometry],
|
|
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
|
};
|
|
606
620
|
/**
|
|
607
621
|
* Dispose cached resources to free memory.
|
|
608
622
|
* Call this when a model is removed from the scene to allow garbage collection of its LOD resources.
|
|
609
623
|
* Calls three.js `.dispose()` on cached Textures and BufferGeometries to free GPU memory.
|
|
624
|
+
* Also clears reference counts for disposed textures.
|
|
610
625
|
* @param guid Optional GUID to dispose resources for a specific model. If omitted, all cached resources are cleared.
|
|
611
626
|
*/
|
|
612
627
|
static dispose(t) {
|
|
@@ -616,42 +631,48 @@ class m {
|
|
|
616
631
|
if (e) {
|
|
617
632
|
const s = e.deref();
|
|
618
633
|
if (s) {
|
|
619
|
-
if (s.isTexture)
|
|
620
|
-
s
|
|
621
|
-
|
|
622
|
-
|
|
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();
|
|
623
639
|
}
|
|
624
640
|
this.lowresCache.delete(t);
|
|
625
641
|
}
|
|
626
|
-
for (const [s,
|
|
627
|
-
s.includes(t) && (this._disposeCacheEntry(
|
|
642
|
+
for (const [s, r] of this.cache)
|
|
643
|
+
s.includes(t) && (this._disposeCacheEntry(r), this.cache.delete(s));
|
|
628
644
|
} else {
|
|
629
645
|
this.lodInfos.clear();
|
|
630
646
|
for (const [, e] of this.lowresCache) {
|
|
631
647
|
const s = e.deref();
|
|
632
648
|
if (s) {
|
|
633
|
-
if (s.isTexture)
|
|
634
|
-
s
|
|
635
|
-
|
|
636
|
-
|
|
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();
|
|
637
654
|
}
|
|
638
655
|
}
|
|
639
656
|
this.lowresCache.clear();
|
|
640
657
|
for (const [, e] of this.cache)
|
|
641
658
|
this._disposeCacheEntry(e);
|
|
642
|
-
this.cache.clear();
|
|
659
|
+
this.cache.clear(), this.textureRefCounts.clear();
|
|
643
660
|
}
|
|
644
661
|
}
|
|
645
662
|
/** Dispose a single cache entry's three.js resource(s) to free GPU memory. */
|
|
646
663
|
static _disposeCacheEntry(t) {
|
|
647
|
-
t instanceof WeakRef
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
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
|
+
});
|
|
655
676
|
}
|
|
656
677
|
/** A map of key = asset uuid and value = LOD information */
|
|
657
678
|
static lodInfos = /* @__PURE__ */ new Map();
|
|
@@ -659,107 +680,137 @@ class m {
|
|
|
659
680
|
static cache = /* @__PURE__ */ new Map();
|
|
660
681
|
/** this contains the geometry/textures that were originally loaded. Uses WeakRef to allow garbage collection when unused. */
|
|
661
682
|
static lowresCache = /* @__PURE__ */ new Map();
|
|
683
|
+
/** Reference counting for textures to track usage across multiple materials/objects */
|
|
684
|
+
static textureRefCounts = /* @__PURE__ */ new Map();
|
|
662
685
|
/**
|
|
663
686
|
* FinalizationRegistry to automatically clean up `previouslyLoaded` cache entries
|
|
664
687
|
* when their associated three.js resources are garbage collected by the browser.
|
|
665
688
|
* The held value is the cache key string used in `previouslyLoaded`.
|
|
666
689
|
*/
|
|
667
690
|
static _resourceRegistry = new FinalizationRegistry((t) => {
|
|
668
|
-
const e =
|
|
669
|
-
|
|
670
|
-
${t}`), e instanceof WeakRef && (e.deref() || (
|
|
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)")));
|
|
671
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
|
+
}
|
|
672
723
|
static workers = [];
|
|
673
724
|
static _workersIndex = 0;
|
|
674
725
|
static async getOrLoadLOD(t, e) {
|
|
675
|
-
const s =
|
|
676
|
-
if (!
|
|
677
|
-
return
|
|
678
|
-
const
|
|
679
|
-
let
|
|
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;
|
|
730
|
+
let o;
|
|
680
731
|
if (t.isTexture === !0) {
|
|
681
732
|
const a = t;
|
|
682
|
-
a.source && a.source[
|
|
733
|
+
a.source && a.source[ue] && (o = a.source[ue]);
|
|
683
734
|
}
|
|
684
|
-
if (
|
|
685
|
-
|
|
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);
|
|
686
737
|
else {
|
|
687
738
|
if (e > 0) {
|
|
688
|
-
let
|
|
689
|
-
const
|
|
690
|
-
if (
|
|
691
|
-
const w = this.lowresCache.get(
|
|
739
|
+
let c = !1;
|
|
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);
|
|
692
743
|
if (w) {
|
|
693
744
|
const _ = w.deref();
|
|
694
745
|
if (_) return _;
|
|
695
|
-
this.lowresCache.delete(
|
|
746
|
+
this.lowresCache.delete(i), f && console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${i}`);
|
|
696
747
|
}
|
|
697
748
|
return null;
|
|
698
749
|
}
|
|
699
750
|
}
|
|
700
|
-
const a = Array.isArray(
|
|
751
|
+
const a = Array.isArray(o.lods) ? o.lods[e]?.path : o.lods;
|
|
701
752
|
if (!a)
|
|
702
|
-
return
|
|
703
|
-
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);
|
|
704
755
|
if (u.endsWith(".glb") || u.endsWith(".gltf")) {
|
|
705
|
-
if (!
|
|
706
|
-
return console.warn("missing pointer for glb/gltf texture",
|
|
707
|
-
const
|
|
756
|
+
if (!o.guid)
|
|
757
|
+
return console.warn("missing pointer for glb/gltf texture", o), null;
|
|
758
|
+
const c = u + "_" + o.guid, m = await this.queue.slot(u), w = this.cache.get(c);
|
|
708
759
|
if (w !== void 0)
|
|
709
|
-
if (s && console.log(`LOD ${e} was already loading/loaded: ${
|
|
710
|
-
const
|
|
711
|
-
if (
|
|
712
|
-
let g =
|
|
713
|
-
if (g instanceof F && t instanceof F ? g.image?.data || g.source?.data ? g = this.copySettings(t, g) : b = !0 : g instanceof
|
|
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)
|
|
714
765
|
return g;
|
|
715
766
|
}
|
|
716
|
-
this.cache.delete(
|
|
767
|
+
this.cache.delete(c), f && console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${c}`);
|
|
717
768
|
} else {
|
|
718
|
-
let
|
|
769
|
+
let d = await w.catch((b) => (console.error(`Error loading LOD ${e} from ${u}
|
|
719
770
|
`, b), null)), g = !1;
|
|
720
|
-
if (
|
|
721
|
-
return
|
|
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;
|
|
722
773
|
}
|
|
723
|
-
if (!
|
|
724
|
-
return
|
|
725
|
-
const _ =
|
|
726
|
-
if (
|
|
727
|
-
const x = await (await
|
|
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);
|
|
728
779
|
if (x.textures.length > 0)
|
|
729
|
-
for (const
|
|
730
|
-
let p =
|
|
731
|
-
return
|
|
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);
|
|
732
783
|
}
|
|
733
784
|
if (x.geometries.length > 0) {
|
|
734
|
-
const
|
|
785
|
+
const h = new Array();
|
|
735
786
|
for (const p of x.geometries) {
|
|
736
787
|
const O = p.geometry;
|
|
737
|
-
|
|
788
|
+
y.assignLODInformation(r.url, O, i, e, p.primitiveIndex), h.push(O);
|
|
738
789
|
}
|
|
739
|
-
return
|
|
790
|
+
return d(h);
|
|
740
791
|
}
|
|
741
|
-
return
|
|
792
|
+
return d(null);
|
|
742
793
|
}
|
|
743
|
-
const b = new
|
|
744
|
-
|
|
794
|
+
const b = new xe();
|
|
795
|
+
Pe(b), f && (await new Promise((L) => setTimeout(L, 1e3)), s && console.warn("Start loading (delayed) " + u, _.guid));
|
|
745
796
|
let B = u;
|
|
746
797
|
if (_ && Array.isArray(_.lods)) {
|
|
747
798
|
const L = _.lods[e];
|
|
748
799
|
L.hash && (B += "?v=" + L.hash);
|
|
749
800
|
}
|
|
750
801
|
const D = await b.loadAsync(B).catch((L) => (console.error(`Error loading LOD ${e} from ${u}
|
|
751
|
-
`, L),
|
|
802
|
+
`, L), d(null)));
|
|
752
803
|
if (!D)
|
|
753
|
-
return
|
|
754
|
-
const
|
|
804
|
+
return d(null);
|
|
805
|
+
const q = D.parser;
|
|
755
806
|
s && console.log("Loading finished " + u, _.guid);
|
|
756
807
|
let P = 0;
|
|
757
808
|
if (D.parser.json.textures) {
|
|
758
809
|
let L = !1;
|
|
759
810
|
for (const x of D.parser.json.textures) {
|
|
760
811
|
if (x?.extensions) {
|
|
761
|
-
const
|
|
762
|
-
if (
|
|
812
|
+
const h = x?.extensions[W];
|
|
813
|
+
if (h?.guid && h.guid === _.guid) {
|
|
763
814
|
L = !0;
|
|
764
815
|
break;
|
|
765
816
|
}
|
|
@@ -767,16 +818,16 @@ ${t}`), e instanceof WeakRef && (e.deref() || (m.cache.delete(t), h && console.l
|
|
|
767
818
|
P++;
|
|
768
819
|
}
|
|
769
820
|
if (L) {
|
|
770
|
-
let x = await
|
|
771
|
-
return x &&
|
|
772
|
-
} else
|
|
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);
|
|
773
824
|
}
|
|
774
825
|
if (P = 0, D.parser.json.meshes) {
|
|
775
826
|
let L = !1;
|
|
776
827
|
for (const x of D.parser.json.meshes) {
|
|
777
828
|
if (x?.extensions) {
|
|
778
|
-
const
|
|
779
|
-
if (
|
|
829
|
+
const h = x?.extensions[W];
|
|
830
|
+
if (h?.guid && h.guid === _.guid) {
|
|
780
831
|
L = !0;
|
|
781
832
|
break;
|
|
782
833
|
}
|
|
@@ -784,69 +835,69 @@ ${t}`), e instanceof WeakRef && (e.deref() || (m.cache.delete(t), h && console.l
|
|
|
784
835
|
P++;
|
|
785
836
|
}
|
|
786
837
|
if (L) {
|
|
787
|
-
const x = await
|
|
788
|
-
if (s && console.log(`Loaded Mesh "${x.name}"`, u, P, x,
|
|
789
|
-
const
|
|
790
|
-
return
|
|
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);
|
|
791
842
|
} else {
|
|
792
|
-
const
|
|
843
|
+
const h = new Array();
|
|
793
844
|
for (let p = 0; p < x.children.length; p++) {
|
|
794
845
|
const O = x.children[p];
|
|
795
846
|
if (O.isMesh === !0) {
|
|
796
847
|
const S = O.geometry;
|
|
797
|
-
|
|
848
|
+
y.assignLODInformation(r.url, S, i, e, p), h.push(S);
|
|
798
849
|
}
|
|
799
850
|
}
|
|
800
|
-
return
|
|
851
|
+
return d(h);
|
|
801
852
|
}
|
|
802
|
-
} else
|
|
853
|
+
} else f && console.warn("Could not find mesh with guid", _.guid, D.parser.json);
|
|
803
854
|
}
|
|
804
|
-
return
|
|
855
|
+
return d(null);
|
|
805
856
|
});
|
|
806
|
-
this.cache.set(
|
|
807
|
-
const M = await
|
|
808
|
-
return M != null ? M instanceof F ? (this.cache.set(
|
|
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;
|
|
809
860
|
} else if (t instanceof F) {
|
|
810
861
|
s && console.log("Load texture from uri: " + u);
|
|
811
|
-
const
|
|
812
|
-
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;
|
|
813
864
|
}
|
|
814
865
|
}
|
|
815
866
|
return null;
|
|
816
867
|
}
|
|
817
868
|
static maxConcurrent = 50;
|
|
818
|
-
static queue = new
|
|
819
|
-
static assignLODInformation(t, e, s,
|
|
869
|
+
static queue = new rt(y.maxConcurrent, { debug: f != !1 });
|
|
870
|
+
static assignLODInformation(t, e, s, r, i) {
|
|
820
871
|
if (!e) return;
|
|
821
872
|
e.userData || (e.userData = {});
|
|
822
|
-
const
|
|
823
|
-
e.userData.LODS =
|
|
873
|
+
const o = new pt(t, s, r, i);
|
|
874
|
+
e.userData.LODS = o, "source" in e && typeof e.source == "object" && (e.source.LODS = o);
|
|
824
875
|
}
|
|
825
876
|
static getAssignedLODInformation(t) {
|
|
826
877
|
return t ? t.userData?.LODS ? t.userData.LODS : "source" in t && t.source?.LODS ? t.source.LODS : null : null;
|
|
827
878
|
}
|
|
828
879
|
// private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
|
|
829
880
|
static copySettings(t, e) {
|
|
830
|
-
return e ? (
|
|
881
|
+
return e ? (f === "verbose" && console.debug(`Copy texture settings
|
|
831
882
|
`, t.uuid, `
|
|
832
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;
|
|
833
884
|
}
|
|
834
885
|
}
|
|
835
|
-
class
|
|
886
|
+
class pt {
|
|
836
887
|
url;
|
|
837
888
|
/** the key to lookup the LOD information */
|
|
838
889
|
key;
|
|
839
890
|
level;
|
|
840
891
|
/** For multi objects (e.g. a group of meshes) this is the index of the object */
|
|
841
892
|
index;
|
|
842
|
-
constructor(t, e, s,
|
|
843
|
-
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);
|
|
844
895
|
}
|
|
845
896
|
}
|
|
846
|
-
class
|
|
847
|
-
static addPromise = (t, e, s,
|
|
848
|
-
|
|
849
|
-
|
|
897
|
+
class ce {
|
|
898
|
+
static addPromise = (t, e, s, r) => {
|
|
899
|
+
r.forEach((i) => {
|
|
900
|
+
i.add(t, e, s);
|
|
850
901
|
});
|
|
851
902
|
};
|
|
852
903
|
ready;
|
|
@@ -876,9 +927,9 @@ class ue {
|
|
|
876
927
|
_awaiting = [];
|
|
877
928
|
_maxPromisesPerObject = 1;
|
|
878
929
|
constructor(t, e) {
|
|
879
|
-
const
|
|
880
|
-
this._frame_start = e.waitForFirstCapture ? void 0 : t, this._frames_to_capture =
|
|
881
|
-
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;
|
|
882
933
|
}), this.ready.finally(() => {
|
|
883
934
|
this._resolved = !0, this._awaiting.length = 0;
|
|
884
935
|
}), this._signal = e.signal, this._signal?.addEventListener("abort", () => {
|
|
@@ -892,18 +943,18 @@ class ue {
|
|
|
892
943
|
_seen = /* @__PURE__ */ new WeakMap();
|
|
893
944
|
add(t, e, s) {
|
|
894
945
|
if (this._resolved) {
|
|
895
|
-
|
|
946
|
+
f && console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");
|
|
896
947
|
return;
|
|
897
948
|
}
|
|
898
949
|
if (!(this._frame_start !== void 0 && this._currentFrame > this._frame_start + this._frames_to_capture)) {
|
|
899
950
|
if (this._maxPromisesPerObject >= 1)
|
|
900
951
|
if (this._seen.has(e)) {
|
|
901
|
-
let
|
|
902
|
-
if (
|
|
903
|
-
|
|
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.");
|
|
904
955
|
return;
|
|
905
956
|
}
|
|
906
|
-
this._seen.set(e,
|
|
957
|
+
this._seen.set(e, r + 1);
|
|
907
958
|
} else
|
|
908
959
|
this._seen.set(e, 1);
|
|
909
960
|
this._awaiting.push(s), this._addedCount++, s.finally(() => {
|
|
@@ -919,7 +970,7 @@ class ue {
|
|
|
919
970
|
});
|
|
920
971
|
}
|
|
921
972
|
}
|
|
922
|
-
const
|
|
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 };
|
|
923
974
|
class v {
|
|
924
975
|
/**
|
|
925
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.
|
|
@@ -927,7 +978,7 @@ class v {
|
|
|
927
978
|
static debugDrawLine;
|
|
928
979
|
/** @internal */
|
|
929
980
|
static getObjectLODState(t) {
|
|
930
|
-
return t[
|
|
981
|
+
return t[fe];
|
|
931
982
|
}
|
|
932
983
|
static addPlugin(t) {
|
|
933
984
|
z.push(t);
|
|
@@ -952,7 +1003,7 @@ class v {
|
|
|
952
1003
|
}
|
|
953
1004
|
renderer;
|
|
954
1005
|
context;
|
|
955
|
-
projectionScreenMatrix = new
|
|
1006
|
+
projectionScreenMatrix = new Le();
|
|
956
1007
|
/** @deprecated use static `LODsManager.addPlugin()` method. This getter will be removed in later versions */
|
|
957
1008
|
get plugins() {
|
|
958
1009
|
return z;
|
|
@@ -996,13 +1047,13 @@ class v {
|
|
|
996
1047
|
* Call to await LODs loading during the next render cycle.
|
|
997
1048
|
*/
|
|
998
1049
|
awaitLoading(t) {
|
|
999
|
-
const e = this._promiseGroupIds++, s = new
|
|
1050
|
+
const e = this._promiseGroupIds++, s = new ce(this.#r, { ...t });
|
|
1000
1051
|
this._newPromiseGroups.push(s);
|
|
1001
|
-
const
|
|
1052
|
+
const r = performance.now();
|
|
1002
1053
|
return s.ready.finally(() => {
|
|
1003
|
-
const
|
|
1004
|
-
|
|
1005
|
-
start:
|
|
1054
|
+
const i = this._newPromiseGroups.indexOf(s);
|
|
1055
|
+
i >= 0 && (this._newPromiseGroups.splice(i, 1), ve() && performance.measure("LODsManager:awaitLoading", {
|
|
1056
|
+
start: r,
|
|
1006
1057
|
detail: { id: e, name: t?.name, awaited: s.awaitedCount, resolved: s.resolvedCount }
|
|
1007
1058
|
}));
|
|
1008
1059
|
}), s.ready;
|
|
@@ -1027,10 +1078,10 @@ class v {
|
|
|
1027
1078
|
this.renderer = t, this.context = { ...e };
|
|
1028
1079
|
}
|
|
1029
1080
|
#t;
|
|
1030
|
-
#
|
|
1081
|
+
#o = new qe();
|
|
1031
1082
|
#r = 0;
|
|
1032
|
-
#o = 0;
|
|
1033
1083
|
#i = 0;
|
|
1084
|
+
#n = 0;
|
|
1034
1085
|
#s = 0;
|
|
1035
1086
|
_fpsBuffer = [60, 60, 60, 60, 60];
|
|
1036
1087
|
/**
|
|
@@ -1042,11 +1093,11 @@ class v {
|
|
|
1042
1093
|
let t = 0;
|
|
1043
1094
|
this.#t = this.renderer.render;
|
|
1044
1095
|
const e = this;
|
|
1045
|
-
|
|
1046
|
-
const
|
|
1047
|
-
(
|
|
1048
|
-
const
|
|
1049
|
-
e.#t.call(this, s,
|
|
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));
|
|
1099
|
+
const o = t++;
|
|
1100
|
+
e.#t.call(this, s, r), e.onAfterRender(s, r, o);
|
|
1050
1101
|
};
|
|
1051
1102
|
}
|
|
1052
1103
|
disable() {
|
|
@@ -1057,14 +1108,14 @@ class v {
|
|
|
1057
1108
|
}
|
|
1058
1109
|
onAfterRender(t, e, s) {
|
|
1059
1110
|
if (this.pause) return;
|
|
1060
|
-
const
|
|
1061
|
-
let
|
|
1062
|
-
if (
|
|
1063
|
-
const l =
|
|
1064
|
-
(l.name === "EffectMaterial" || l.name === "CopyShader") && (
|
|
1111
|
+
const i = this.renderer.renderLists.get(t, 0).opaque;
|
|
1112
|
+
let o = !0;
|
|
1113
|
+
if (i.length === 1) {
|
|
1114
|
+
const l = i[0].material;
|
|
1115
|
+
(l.name === "EffectMaterial" || l.name === "CopyShader") && (o = !1);
|
|
1065
1116
|
}
|
|
1066
|
-
if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (
|
|
1067
|
-
if (
|
|
1117
|
+
if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (o = !1), o) {
|
|
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))
|
|
1068
1119
|
return;
|
|
1069
1120
|
this.internalUpdate(t, e), this._postprocessPromiseGroups();
|
|
1070
1121
|
}
|
|
@@ -1073,12 +1124,12 @@ class v {
|
|
|
1073
1124
|
* Update LODs in a scene
|
|
1074
1125
|
*/
|
|
1075
1126
|
internalUpdate(t, e) {
|
|
1076
|
-
const s = this.renderer.renderLists.get(t, 0),
|
|
1127
|
+
const s = this.renderer.renderLists.get(t, 0), r = s.opaque;
|
|
1077
1128
|
this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix, e.matrixWorldInverse);
|
|
1078
|
-
const
|
|
1079
|
-
for (const a of
|
|
1129
|
+
const i = this.targetTriangleDensity;
|
|
1130
|
+
for (const a of r) {
|
|
1080
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")) {
|
|
1081
|
-
|
|
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)));
|
|
1082
1133
|
continue;
|
|
1083
1134
|
}
|
|
1084
1135
|
switch (a.material.type) {
|
|
@@ -1090,38 +1141,38 @@ class v {
|
|
|
1090
1141
|
case "MeshDepthMaterial":
|
|
1091
1142
|
continue;
|
|
1092
1143
|
}
|
|
1093
|
-
if (
|
|
1144
|
+
if (R === "color" && a.material && !a.object.progressive_debug_color) {
|
|
1094
1145
|
a.object.progressive_debug_color = !0;
|
|
1095
|
-
const
|
|
1096
|
-
a.object.material =
|
|
1146
|
+
const c = Math.random() * 16777215, m = new Ee({ color: c });
|
|
1147
|
+
a.object.material = m;
|
|
1097
1148
|
}
|
|
1098
1149
|
const u = a.object;
|
|
1099
|
-
(u instanceof
|
|
1150
|
+
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1100
1151
|
}
|
|
1101
|
-
const
|
|
1102
|
-
for (const a of
|
|
1152
|
+
const o = s.transparent;
|
|
1153
|
+
for (const a of o) {
|
|
1103
1154
|
const u = a.object;
|
|
1104
|
-
(u instanceof
|
|
1155
|
+
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1105
1156
|
}
|
|
1106
1157
|
const l = s.transmissive;
|
|
1107
1158
|
for (const a of l) {
|
|
1108
1159
|
const u = a.object;
|
|
1109
|
-
(u instanceof
|
|
1160
|
+
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1110
1161
|
}
|
|
1111
1162
|
}
|
|
1112
1163
|
/** Update the LOD levels for the renderer. */
|
|
1113
|
-
updateLODs(t, e, s,
|
|
1164
|
+
updateLODs(t, e, s, r) {
|
|
1114
1165
|
s.userData || (s.userData = {});
|
|
1115
|
-
let
|
|
1116
|
-
if (
|
|
1166
|
+
let i = s[fe];
|
|
1167
|
+
if (i || (i = new yt(), s[fe] = i), i.frames++ < 2)
|
|
1117
1168
|
return;
|
|
1118
1169
|
for (const l of z)
|
|
1119
1170
|
l.onBeforeUpdateLOD?.(this.renderer, t, e, s);
|
|
1120
|
-
const
|
|
1121
|
-
|
|
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);
|
|
1122
1173
|
for (const l of z)
|
|
1123
1174
|
l.onAfterUpdatedLOD?.(this.renderer, t, e, s, T);
|
|
1124
|
-
|
|
1175
|
+
i.lastLodLevel_Mesh = T.mesh_lod, i.lastLodLevel_Texture = T.texture_lod;
|
|
1125
1176
|
}
|
|
1126
1177
|
/** Load progressive textures for the given material
|
|
1127
1178
|
* @param material the material to load the textures for
|
|
@@ -1131,17 +1182,17 @@ class v {
|
|
|
1131
1182
|
loadProgressiveTextures(t, e, s) {
|
|
1132
1183
|
if (!t) return;
|
|
1133
1184
|
if (Array.isArray(t)) {
|
|
1134
|
-
for (const
|
|
1135
|
-
this.loadProgressiveTextures(
|
|
1185
|
+
for (const i of t)
|
|
1186
|
+
this.loadProgressiveTextures(i, e);
|
|
1136
1187
|
return;
|
|
1137
1188
|
}
|
|
1138
|
-
let
|
|
1139
|
-
if ((t[U] === void 0 || e < t[U]) && (
|
|
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) {
|
|
1140
1191
|
t[U] = e;
|
|
1141
|
-
const
|
|
1192
|
+
const i = y.assignTextureLOD(t, e).then((o) => {
|
|
1142
1193
|
this._lodchangedlisteners.forEach((l) => l({ type: "texture", level: e, object: t }));
|
|
1143
1194
|
});
|
|
1144
|
-
|
|
1195
|
+
ce.addPromise("texture", t, i, this._newPromiseGroups);
|
|
1145
1196
|
}
|
|
1146
1197
|
}
|
|
1147
1198
|
/** Load progressive meshes for the given mesh
|
|
@@ -1153,141 +1204,141 @@ class v {
|
|
|
1153
1204
|
loadProgressiveMeshes(t, e) {
|
|
1154
1205
|
if (!t) return Promise.resolve(null);
|
|
1155
1206
|
let s = t[U] !== e;
|
|
1156
|
-
const
|
|
1157
|
-
if (
|
|
1207
|
+
const r = t["DEBUG:LOD"];
|
|
1208
|
+
if (r != null && (s = t[U] != r, e = r), s) {
|
|
1158
1209
|
t[U] = e;
|
|
1159
|
-
const
|
|
1160
|
-
return
|
|
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;
|
|
1161
1212
|
}
|
|
1162
1213
|
return Promise.resolve(null);
|
|
1163
1214
|
}
|
|
1164
1215
|
// private testIfLODLevelsAreAvailable() {
|
|
1165
|
-
_sphere = new
|
|
1166
|
-
_tempBox = new
|
|
1167
|
-
_tempBox2 = new
|
|
1168
|
-
tempMatrix = new
|
|
1169
|
-
_tempWorldPosition = new
|
|
1170
|
-
_tempBoxSize = new
|
|
1171
|
-
_tempBox2Size = new
|
|
1172
|
-
static corner0 = new
|
|
1173
|
-
static corner1 = new
|
|
1174
|
-
static corner2 = new
|
|
1175
|
-
static corner3 = new
|
|
1176
|
-
static _tempPtInside = new
|
|
1216
|
+
_sphere = new Oe();
|
|
1217
|
+
_tempBox = new ge();
|
|
1218
|
+
_tempBox2 = new ge();
|
|
1219
|
+
tempMatrix = new Le();
|
|
1220
|
+
_tempWorldPosition = new A();
|
|
1221
|
+
_tempBoxSize = new A();
|
|
1222
|
+
_tempBox2Size = new A();
|
|
1223
|
+
static corner0 = new A();
|
|
1224
|
+
static corner1 = new A();
|
|
1225
|
+
static corner2 = new A();
|
|
1226
|
+
static corner3 = new A();
|
|
1227
|
+
static _tempPtInside = new A();
|
|
1177
1228
|
static isInside(t, e) {
|
|
1178
|
-
const s = t.min,
|
|
1179
|
-
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;
|
|
1180
1231
|
}
|
|
1181
1232
|
static skinnedMeshBoundsFrameOffsetCounter = 0;
|
|
1182
1233
|
static $skinnedMeshBoundsOffset = /* @__PURE__ */ Symbol("gltf-progressive-skinnedMeshBoundsOffset");
|
|
1183
1234
|
// #region calculateLodLevel
|
|
1184
|
-
calculateLodLevel(t, e, s,
|
|
1235
|
+
calculateLodLevel(t, e, s, r, i) {
|
|
1185
1236
|
if (!e) {
|
|
1186
|
-
|
|
1237
|
+
i.mesh_lod = -1, i.texture_lod = -1;
|
|
1187
1238
|
return;
|
|
1188
1239
|
}
|
|
1189
1240
|
if (!t) {
|
|
1190
|
-
|
|
1241
|
+
i.mesh_lod = -1, i.texture_lod = -1;
|
|
1191
1242
|
return;
|
|
1192
1243
|
}
|
|
1193
1244
|
let l = 10 + 1, a = !1;
|
|
1194
|
-
if (
|
|
1245
|
+
if (R && e["DEBUG:LOD"] != null)
|
|
1195
1246
|
return e["DEBUG:LOD"];
|
|
1196
|
-
const u =
|
|
1197
|
-
if (!
|
|
1198
|
-
|
|
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;
|
|
1199
1250
|
return;
|
|
1200
1251
|
}
|
|
1201
|
-
|
|
1202
|
-
const
|
|
1252
|
+
m || (a = !0, l = 0);
|
|
1253
|
+
const k = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
|
|
1203
1254
|
let M = e.geometry.boundingBox;
|
|
1204
1255
|
if (e.type === "SkinnedMesh") {
|
|
1205
|
-
const
|
|
1206
|
-
if (!
|
|
1207
|
-
|
|
1256
|
+
const d = e;
|
|
1257
|
+
if (!d.boundingBox)
|
|
1258
|
+
d.computeBoundingBox();
|
|
1208
1259
|
else if (this.skinnedMeshAutoUpdateBoundsInterval > 0) {
|
|
1209
|
-
if (!
|
|
1260
|
+
if (!d[v.$skinnedMeshBoundsOffset]) {
|
|
1210
1261
|
const b = v.skinnedMeshBoundsFrameOffsetCounter++;
|
|
1211
|
-
|
|
1262
|
+
d[v.$skinnedMeshBoundsOffset] = b;
|
|
1212
1263
|
}
|
|
1213
|
-
const g =
|
|
1264
|
+
const g = d[v.$skinnedMeshBoundsOffset];
|
|
1214
1265
|
if ((s.frames + g) % this.skinnedMeshAutoUpdateBoundsInterval === 0) {
|
|
1215
|
-
const b =
|
|
1216
|
-
b && (
|
|
1266
|
+
const b = ee(d), B = d.geometry;
|
|
1267
|
+
b && (d.geometry = b), d.computeBoundingBox(), d.geometry = B;
|
|
1217
1268
|
}
|
|
1218
1269
|
}
|
|
1219
|
-
M =
|
|
1270
|
+
M = d.boundingBox;
|
|
1220
1271
|
}
|
|
1221
1272
|
if (M) {
|
|
1222
|
-
const
|
|
1273
|
+
const d = t;
|
|
1223
1274
|
if (e.geometry.attributes.color && e.geometry.attributes.color.count < 100 && e.geometry.boundingSphere) {
|
|
1224
1275
|
this._sphere.copy(e.geometry.boundingSphere), this._sphere.applyMatrix4(e.matrixWorld);
|
|
1225
|
-
const
|
|
1226
|
-
if (this._sphere.containsPoint(
|
|
1227
|
-
|
|
1276
|
+
const h = t.getWorldPosition(this._tempWorldPosition);
|
|
1277
|
+
if (this._sphere.containsPoint(h)) {
|
|
1278
|
+
i.mesh_lod = 0, i.texture_lod = 0;
|
|
1228
1279
|
return;
|
|
1229
1280
|
}
|
|
1230
1281
|
}
|
|
1231
|
-
if (this._tempBox.copy(M), this._tempBox.applyMatrix4(e.matrixWorld),
|
|
1232
|
-
|
|
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;
|
|
1233
1284
|
return;
|
|
1234
1285
|
}
|
|
1235
|
-
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled &&
|
|
1236
|
-
const
|
|
1237
|
-
let O =
|
|
1238
|
-
const
|
|
1239
|
-
O = (O -
|
|
1240
|
-
const
|
|
1241
|
-
s.lastCentrality = (ne -
|
|
1286
|
+
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && d.isPerspectiveCamera && d.fov > 70) {
|
|
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);
|
|
1242
1293
|
} else
|
|
1243
1294
|
s.lastCentrality = 1;
|
|
1244
1295
|
const g = this._tempBox.getSize(this._tempBoxSize);
|
|
1245
|
-
g.multiplyScalar(0.5), screen.availHeight > 0 &&
|
|
1296
|
+
g.multiplyScalar(0.5), screen.availHeight > 0 && k > 0 && g.multiplyScalar(k / screen.availHeight), t.isPerspectiveCamera ? g.x *= t.aspect : t.isOrthographicCamera;
|
|
1246
1297
|
const b = t.matrixWorldInverse, B = this._tempBox2;
|
|
1247
1298
|
B.copy(M), B.applyMatrix4(e.matrixWorld), B.applyMatrix4(b);
|
|
1248
|
-
const D = B.getSize(this._tempBox2Size),
|
|
1249
|
-
if (Math.max(g.x, g.y) != 0 &&
|
|
1250
|
-
const
|
|
1251
|
-
|
|
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();
|
|
1252
1303
|
const p = v.corner0, O = v.corner1, S = v.corner2, G = v.corner3;
|
|
1253
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);
|
|
1254
1305
|
const Y = (p.z + G.z) * 0.5;
|
|
1255
|
-
p.z = O.z = S.z = G.z = Y, p.applyMatrix4(
|
|
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);
|
|
1256
1307
|
}
|
|
1257
1308
|
let L = 999;
|
|
1258
1309
|
if (u && s.lastScreenCoverage > 0)
|
|
1259
|
-
for (let
|
|
1260
|
-
const p = u[
|
|
1261
|
-
if (
|
|
1262
|
-
L =
|
|
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;
|
|
1263
1314
|
break;
|
|
1264
1315
|
}
|
|
1265
1316
|
}
|
|
1266
1317
|
L < l && (l = L, a = !0);
|
|
1267
1318
|
}
|
|
1268
|
-
if (a ?
|
|
1269
|
-
const g = u?.[
|
|
1270
|
-
g && console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${
|
|
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}`);
|
|
1271
1322
|
}
|
|
1272
1323
|
if (_) {
|
|
1273
|
-
const
|
|
1324
|
+
const d = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
|
|
1274
1325
|
if (s.lastLodLevel_Texture < 0) {
|
|
1275
|
-
if (
|
|
1326
|
+
if (i.texture_lod = w.max_count - 1, R) {
|
|
1276
1327
|
const g = w.lods[w.max_count - 1];
|
|
1277
|
-
|
|
1328
|
+
R && console.log(`First Texture LOD ${i.texture_lod} (${g.max_height}px) - ${e.name}`);
|
|
1278
1329
|
}
|
|
1279
1330
|
} else {
|
|
1280
1331
|
const g = s.lastScreenspaceVolume.x + s.lastScreenspaceVolume.y + s.lastScreenspaceVolume.z;
|
|
1281
1332
|
let b = s.lastScreenCoverage * 4;
|
|
1282
1333
|
this.context?.engine === "model-viewer" && (b *= 1.5);
|
|
1283
|
-
const D =
|
|
1284
|
-
let
|
|
1334
|
+
const D = k / window.devicePixelRatio * b;
|
|
1335
|
+
let q = !1;
|
|
1285
1336
|
for (let P = w.lods.length - 1; P >= 0; P--) {
|
|
1286
1337
|
const L = w.lods[P];
|
|
1287
|
-
if (!(
|
|
1288
|
-
if (
|
|
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) {
|
|
1289
1340
|
const x = L.max_height;
|
|
1290
|
-
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${
|
|
1341
|
+
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${i.texture_lod} = ${x}px
|
|
1291
1342
|
Screensize: ${D.toFixed(0)}px, Coverage: ${(100 * s.lastScreenCoverage).toFixed(2)}%, Volume ${g.toFixed(1)}
|
|
1292
1343
|
${e.name}`);
|
|
1293
1344
|
}
|
|
@@ -1296,86 +1347,86 @@ ${e.name}`);
|
|
|
1296
1347
|
}
|
|
1297
1348
|
}
|
|
1298
1349
|
} else
|
|
1299
|
-
|
|
1350
|
+
i.texture_lod = 0;
|
|
1300
1351
|
}
|
|
1301
1352
|
}
|
|
1302
|
-
class
|
|
1353
|
+
class yt {
|
|
1303
1354
|
frames = 0;
|
|
1304
1355
|
lastLodLevel_Mesh = -1;
|
|
1305
1356
|
lastLodLevel_Texture = -1;
|
|
1306
1357
|
lastScreenCoverage = 0;
|
|
1307
|
-
lastScreenspaceVolume = new
|
|
1358
|
+
lastScreenspaceVolume = new A();
|
|
1308
1359
|
lastCentrality = 0;
|
|
1309
1360
|
}
|
|
1310
|
-
const
|
|
1311
|
-
let
|
|
1312
|
-
function
|
|
1313
|
-
const
|
|
1314
|
-
|
|
1315
|
-
return
|
|
1316
|
-
}),
|
|
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) => {
|
|
1317
1368
|
t.forEach((e) => {
|
|
1318
1369
|
e.addedNodes.forEach((s) => {
|
|
1319
|
-
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" &&
|
|
1370
|
+
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" && Ie(s);
|
|
1320
1371
|
});
|
|
1321
1372
|
});
|
|
1322
|
-
}),
|
|
1373
|
+
}), he.observe(document, { childList: !0, subtree: !0 }));
|
|
1323
1374
|
}
|
|
1324
|
-
function
|
|
1375
|
+
function xt() {
|
|
1325
1376
|
if (typeof customElements > "u") return null;
|
|
1326
|
-
const
|
|
1327
|
-
return
|
|
1328
|
-
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();
|
|
1329
1380
|
}), null);
|
|
1330
1381
|
}
|
|
1331
|
-
function
|
|
1382
|
+
function Me() {
|
|
1332
1383
|
if (typeof document > "u") return;
|
|
1333
1384
|
document.querySelectorAll("model-viewer").forEach((t) => {
|
|
1334
|
-
|
|
1385
|
+
Ie(t);
|
|
1335
1386
|
});
|
|
1336
1387
|
}
|
|
1337
|
-
const
|
|
1338
|
-
let
|
|
1339
|
-
function
|
|
1340
|
-
if (!
|
|
1388
|
+
const De = /* @__PURE__ */ new WeakSet();
|
|
1389
|
+
let wt = 0;
|
|
1390
|
+
function Ie(n) {
|
|
1391
|
+
if (!n || De.has(n))
|
|
1341
1392
|
return null;
|
|
1342
|
-
|
|
1343
|
-
`,
|
|
1393
|
+
De.add(n), console.debug("[gltf-progressive] found new model-viewer..." + ++wt + `
|
|
1394
|
+
`, n.getAttribute("src"));
|
|
1344
1395
|
let t = null, e = null, s = null;
|
|
1345
|
-
for (let
|
|
1346
|
-
const
|
|
1347
|
-
!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]);
|
|
1348
1399
|
}
|
|
1349
1400
|
if (t && e) {
|
|
1350
|
-
let
|
|
1401
|
+
let r = function() {
|
|
1351
1402
|
if (s) {
|
|
1352
|
-
let
|
|
1353
|
-
if (
|
|
1403
|
+
let o = 0, l = setInterval(() => {
|
|
1404
|
+
if (o++ > 5) {
|
|
1354
1405
|
clearInterval(l);
|
|
1355
1406
|
return;
|
|
1356
1407
|
}
|
|
1357
|
-
s?.call(
|
|
1408
|
+
s?.call(n);
|
|
1358
1409
|
}, 300);
|
|
1359
1410
|
}
|
|
1360
1411
|
};
|
|
1361
1412
|
console.debug("[gltf-progressive] setup model-viewer");
|
|
1362
|
-
const
|
|
1363
|
-
return v.addPlugin(new
|
|
1364
|
-
s?.call(
|
|
1365
|
-
}),
|
|
1366
|
-
|
|
1367
|
-
}),
|
|
1368
|
-
|
|
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();
|
|
1369
1420
|
}), () => {
|
|
1370
|
-
|
|
1421
|
+
i.disable();
|
|
1371
1422
|
};
|
|
1372
1423
|
}
|
|
1373
1424
|
return null;
|
|
1374
1425
|
}
|
|
1375
|
-
class
|
|
1426
|
+
class _t {
|
|
1376
1427
|
_didWarnAboutMissingUrl = !1;
|
|
1377
|
-
onBeforeUpdateLOD(t, e, s,
|
|
1378
|
-
this.tryParseMeshLOD(e,
|
|
1428
|
+
onBeforeUpdateLOD(t, e, s, r) {
|
|
1429
|
+
this.tryParseMeshLOD(e, r), this.tryParseTextureLOD(e, r);
|
|
1379
1430
|
}
|
|
1380
1431
|
getUrl(t) {
|
|
1381
1432
|
if (!t)
|
|
@@ -1390,101 +1441,101 @@ class xt {
|
|
|
1390
1441
|
return t.element;
|
|
1391
1442
|
}
|
|
1392
1443
|
tryParseTextureLOD(t, e) {
|
|
1393
|
-
if (e[
|
|
1394
|
-
e[
|
|
1395
|
-
const s = this.tryGetCurrentGLTF(t),
|
|
1396
|
-
if (
|
|
1397
|
-
let
|
|
1398
|
-
if (a[
|
|
1399
|
-
a[
|
|
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) {
|
|
1448
|
+
let o = function(a) {
|
|
1449
|
+
if (a[ie] == !0) return;
|
|
1450
|
+
a[ie] = !0, a.userData && (a.userData.LOD = -1);
|
|
1400
1451
|
const u = Object.keys(a);
|
|
1401
|
-
for (let
|
|
1402
|
-
const
|
|
1452
|
+
for (let c = 0; c < u.length; c++) {
|
|
1453
|
+
const m = u[c], w = a[m];
|
|
1403
1454
|
if (w?.isTexture === !0) {
|
|
1404
1455
|
const _ = w.userData?.associations?.textures;
|
|
1405
1456
|
if (_ == null) continue;
|
|
1406
|
-
const
|
|
1407
|
-
if (!
|
|
1457
|
+
const k = s.parser.json.textures[_];
|
|
1458
|
+
if (!k) {
|
|
1408
1459
|
console.warn("Texture data not found for texture index " + _);
|
|
1409
1460
|
continue;
|
|
1410
1461
|
}
|
|
1411
|
-
if (
|
|
1412
|
-
const M =
|
|
1413
|
-
M &&
|
|
1462
|
+
if (k?.extensions?.[W]) {
|
|
1463
|
+
const M = k.extensions[W];
|
|
1464
|
+
M && i && y.registerTexture(i, w, M.lods.length, _, M);
|
|
1414
1465
|
}
|
|
1415
1466
|
}
|
|
1416
1467
|
}
|
|
1417
1468
|
};
|
|
1418
1469
|
const l = e.material;
|
|
1419
|
-
if (Array.isArray(l)) for (const a of l)
|
|
1420
|
-
else
|
|
1470
|
+
if (Array.isArray(l)) for (const a of l) o(a);
|
|
1471
|
+
else o(l);
|
|
1421
1472
|
}
|
|
1422
1473
|
}
|
|
1423
1474
|
tryParseMeshLOD(t, e) {
|
|
1424
|
-
if (e[
|
|
1425
|
-
e[
|
|
1426
|
-
const s = this.tryGetCurrentModelViewer(t),
|
|
1427
|
-
if (!
|
|
1475
|
+
if (e[be] == !0) return;
|
|
1476
|
+
e[be] = !0;
|
|
1477
|
+
const s = this.tryGetCurrentModelViewer(t), r = this.getUrl(s);
|
|
1478
|
+
if (!r)
|
|
1428
1479
|
return;
|
|
1429
|
-
const
|
|
1430
|
-
if (
|
|
1431
|
-
const
|
|
1432
|
-
|
|
1480
|
+
const i = e.userData?.gltfExtensions?.[W];
|
|
1481
|
+
if (i && r) {
|
|
1482
|
+
const o = e.uuid;
|
|
1483
|
+
y.registerMesh(r, o, e, 0, i.lods.length, i);
|
|
1433
1484
|
}
|
|
1434
1485
|
}
|
|
1435
1486
|
}
|
|
1436
|
-
function
|
|
1437
|
-
let t, e, s,
|
|
1438
|
-
switch (
|
|
1487
|
+
function Lt(...n) {
|
|
1488
|
+
let t, e, s, r;
|
|
1489
|
+
switch (n.length) {
|
|
1439
1490
|
case 2:
|
|
1440
|
-
[s, e] =
|
|
1491
|
+
[s, e] = n, r = {};
|
|
1441
1492
|
break;
|
|
1442
1493
|
case 3:
|
|
1443
|
-
[s, e,
|
|
1494
|
+
[s, e, r] = n;
|
|
1444
1495
|
break;
|
|
1445
1496
|
case 4:
|
|
1446
|
-
[t, e, s,
|
|
1497
|
+
[t, e, s, r] = n;
|
|
1447
1498
|
break;
|
|
1448
1499
|
default:
|
|
1449
1500
|
throw new Error("Invalid arguments");
|
|
1450
1501
|
}
|
|
1451
|
-
|
|
1502
|
+
we(e), Pe(s), Ce(s, {
|
|
1452
1503
|
progressive: !0,
|
|
1453
|
-
...
|
|
1454
|
-
}), s.register((
|
|
1455
|
-
const
|
|
1456
|
-
return
|
|
1504
|
+
...r?.hints
|
|
1505
|
+
}), s.register((o) => new y(o));
|
|
1506
|
+
const i = v.get(e);
|
|
1507
|
+
return r?.enableLODsManager !== !1 && i.enable(), i;
|
|
1457
1508
|
}
|
|
1458
|
-
|
|
1459
|
-
if (!
|
|
1460
|
-
const
|
|
1509
|
+
Re();
|
|
1510
|
+
if (!nt) {
|
|
1511
|
+
const n = {
|
|
1461
1512
|
gltfProgressive: {
|
|
1462
|
-
useNeedleProgressive:
|
|
1513
|
+
useNeedleProgressive: Lt,
|
|
1463
1514
|
LODsManager: v,
|
|
1464
|
-
configureLoader:
|
|
1465
|
-
getRaycastMesh:
|
|
1466
|
-
useRaycastMeshes:
|
|
1515
|
+
configureLoader: Ce,
|
|
1516
|
+
getRaycastMesh: ee,
|
|
1517
|
+
useRaycastMeshes: lt
|
|
1467
1518
|
}
|
|
1468
1519
|
};
|
|
1469
1520
|
if (!globalThis.Needle)
|
|
1470
|
-
globalThis.Needle =
|
|
1521
|
+
globalThis.Needle = n;
|
|
1471
1522
|
else
|
|
1472
|
-
for (const t in
|
|
1473
|
-
globalThis.Needle[t] =
|
|
1523
|
+
for (const t in n)
|
|
1524
|
+
globalThis.Needle[t] = n[t];
|
|
1474
1525
|
}
|
|
1475
1526
|
export {
|
|
1476
1527
|
W as EXTENSION_NAME,
|
|
1477
1528
|
v as LODsManager,
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1529
|
+
y as NEEDLE_progressive,
|
|
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
|
|
1490
1541
|
};
|