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