@needle-tools/gltf-progressive 3.4.0-beta → 3.4.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/README.md +9 -0
- package/gltf-progressive.js +632 -572
- package/gltf-progressive.min.js +9 -8
- package/gltf-progressive.umd.cjs +8 -7
- package/lib/extension.d.ts +19 -1
- package/lib/extension.js +116 -25
- 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,90 +1,90 @@
|
|
|
1
|
-
import { BufferGeometry as E, Mesh as
|
|
2
|
-
import { GLTFLoader as
|
|
1
|
+
import { BufferGeometry as E, 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 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 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 = 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 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
|
|
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
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 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
|
|
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
|
|
156
|
+
let Q = null;
|
|
157
|
+
function ut(n) {
|
|
146
158
|
const t = new E();
|
|
147
|
-
for (const e in
|
|
148
|
-
t.setAttribute(e,
|
|
149
|
-
return t.setIndex(
|
|
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, V = -1;
|
|
165
|
+
if (f) {
|
|
166
|
+
let n = function() {
|
|
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" &&
|
|
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 (
|
|
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
|
|
251
|
+
function ht(n) {
|
|
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((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,24 +315,26 @@ function dt(i) {
|
|
|
303
315
|
e.type,
|
|
304
316
|
e.anisotropy,
|
|
305
317
|
e.colorSpace
|
|
306
|
-
), s.mipmaps = e.mipmaps, s.channel = e.channel, s.source.data = e.source.data, s.flipY = e.flipY, s.premultiplyAlpha = e.premultiplyAlpha, s.unpackAlignment = e.unpackAlignment, s.matrix = new
|
|
318
|
+
), s.mipmaps = e.mipmaps, s.channel = e.channel, s.source.data = e.source.data, s.flipY = e.flipY, s.premultiplyAlpha = e.premultiplyAlpha, s.unpackAlignment = e.unpackAlignment, s.matrix = new Fe(...e.matrix.elements);
|
|
307
319
|
if (!s) {
|
|
308
320
|
console.error("[Worker] Failed to create new texture from received data. Texture is not a CompressedTexture or Texture.");
|
|
309
321
|
continue;
|
|
310
322
|
}
|
|
311
323
|
t.texture = s;
|
|
312
324
|
}
|
|
313
|
-
return
|
|
325
|
+
return n;
|
|
314
326
|
}
|
|
315
|
-
function
|
|
316
|
-
let t =
|
|
317
|
-
if ("isInterleavedBufferAttribute" in
|
|
318
|
-
const e =
|
|
319
|
-
t = new
|
|
320
|
-
} else "isBufferAttribute" in
|
|
327
|
+
function le(n) {
|
|
328
|
+
let t = n;
|
|
329
|
+
if ("isInterleavedBufferAttribute" in n && n.isInterleavedBufferAttribute) {
|
|
330
|
+
const e = n.data, s = e.array, r = new We(s, e.stride);
|
|
331
|
+
t = new Ue(r, n.itemSize, s.byteOffset, n.normalized), t.offset = n.offset;
|
|
332
|
+
} else "isBufferAttribute" in n && n.isBufferAttribute && (t = new ze(n.array, n.itemSize, n.normalized), t.usage = n.usage, t.gpuType = n.gpuType, t.updateRanges = n.updateRanges);
|
|
321
333
|
return t;
|
|
322
334
|
}
|
|
323
|
-
const
|
|
335
|
+
const gt = N("gltf-progressive-worker");
|
|
336
|
+
N("gltf-progressive-reduce-mipmaps");
|
|
337
|
+
const K = N("gltf-progressive-gc"), ue = /* @__PURE__ */ Symbol("needle-progressive-texture"), W = "NEEDLE_progressive";
|
|
324
338
|
class m {
|
|
325
339
|
/** The name of the extension */
|
|
326
340
|
get name() {
|
|
@@ -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,30 +359,30 @@ 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 y = 0; y <
|
|
371
|
-
const w =
|
|
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 y = 0; y < c.lods.length; y++) {
|
|
385
|
+
const w = c.lods[y];
|
|
372
386
|
w.width && (a.lods[y] = a.lods[y] || { min_height: 1 / 0, max_height: 0 }, a.lods[y].min_height = Math.min(a.lods[y].min_height, w.height), a.lods[y].max_height = Math.max(a.lods[y].max_height, w.height));
|
|
373
387
|
}
|
|
374
388
|
}
|
|
@@ -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 z)
|
|
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 : 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
|
});
|
|
@@ -492,35 +506,45 @@ 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
|
|
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 l = this.getAssignedLODInformation(
|
|
524
|
+
if (i?.isTexture === !0) {
|
|
525
|
+
if (i != t && s && r) {
|
|
526
|
+
const o = s[r];
|
|
527
|
+
if (o && !f) {
|
|
528
|
+
const l = this.getAssignedLODInformation(o);
|
|
505
529
|
if (l && l?.level < e)
|
|
506
|
-
return
|
|
530
|
+
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
531
|
}
|
|
508
|
-
if (
|
|
509
|
-
const
|
|
510
|
-
|
|
532
|
+
if (this.trackTextureUsage(i), o && o !== i && this.untrackTextureUsage(o) && (f || K)) {
|
|
533
|
+
const a = this.getAssignedLODInformation(o);
|
|
534
|
+
console.log(`[gltf-progressive] Disposed old texture LOD ${a?.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 f == "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
|
+
f && console.log("Progressive extension registered for", e), this.parser = t, this.url = e;
|
|
524
548
|
}
|
|
525
549
|
_isLoadingMesh;
|
|
526
550
|
loadMesh = (t) => {
|
|
@@ -543,30 +567,30 @@ class m {
|
|
|
543
567
|
// });
|
|
544
568
|
// }
|
|
545
569
|
afterRoot(t) {
|
|
546
|
-
return
|
|
570
|
+
return f && 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[W];
|
|
573
|
+
if (r) {
|
|
574
|
+
if (!r.lods) {
|
|
575
|
+
f && 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[W];
|
|
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
|
+
f && console.error("!! gltf-progressive: Called register texture without texture");
|
|
581
605
|
return;
|
|
582
606
|
}
|
|
583
|
-
if (
|
|
607
|
+
if (f) {
|
|
584
608
|
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[${
|
|
609
|
+
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
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,
|
|
618
|
+
static registerMesh = (t, e, s, r, i, o) => {
|
|
595
619
|
const l = s.geometry;
|
|
596
620
|
if (!l) {
|
|
597
|
-
|
|
621
|
+
f && console.warn("gltf-progressive: Register mesh without geometry");
|
|
598
622
|
return;
|
|
599
623
|
}
|
|
600
|
-
l.userData || (l.userData = {}),
|
|
624
|
+
l.userData || (l.userData = {}), f && console.log("> Progressive: register mesh " + s.name, { index: i, uuid: s.uuid }, o, s), m.assignLODInformation(t, l, e, r, i), m.lodInfos.set(e, o);
|
|
601
625
|
let u = m.lowresCache.get(e)?.deref();
|
|
602
|
-
u ? u.push(s.geometry) : u = [s.geometry], m.lowresCache.set(e, new WeakRef(u)),
|
|
603
|
-
for (const
|
|
604
|
-
|
|
626
|
+
u ? u.push(s.geometry) : u = [s.geometry], m.lowresCache.set(e, new WeakRef(u)), r > 0 && !ee(s) && at(s, l);
|
|
627
|
+
for (const c of z)
|
|
628
|
+
c.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,42 +641,48 @@ 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
655
|
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
667
|
for (const [, e] of this.cache)
|
|
641
668
|
this._disposeCacheEntry(e);
|
|
642
|
-
this.cache.clear();
|
|
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
|
+
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();
|
|
@@ -659,6 +690,8 @@ class m {
|
|
|
659
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.
|
|
@@ -666,100 +699,128 @@ class m {
|
|
|
666
699
|
*/
|
|
667
700
|
static _resourceRegistry = new FinalizationRegistry((t) => {
|
|
668
701
|
const e = m.cache.get(t);
|
|
669
|
-
|
|
670
|
-
${t}`), e instanceof WeakRef && (e.deref() || (m.cache.delete(t),
|
|
702
|
+
(f || K) && console.debug(`[gltf-progressive] Memory: Resource GC'd
|
|
703
|
+
${t}`), e instanceof WeakRef && (e.deref() || (m.cache.delete(t), (f || K) && console.log("[gltf-progressive] ↪ Cache entry deleted (GC)")));
|
|
671
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), f === "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 (f === "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), (f || K) && i("[gltf-progressive] Memory: Dispose texture", r), t.dispose(), !0;
|
|
724
|
+
return this.textureRefCounts.set(e, r), f === "verbose" && i("[gltf-progressive] Memory: Untrack texture", r), !1;
|
|
725
|
+
function i(o, l) {
|
|
726
|
+
let a = t.image?.width || t.source?.data?.width || 0, u = t.image?.height || t.source?.data?.height || 0;
|
|
727
|
+
const c = a && u ? `${a}x${u}` : "N/A";
|
|
728
|
+
let y = "N/A";
|
|
729
|
+
a && u && (y = `~${(it(t) / (1024 * 1024)).toFixed(2)} MB`), console.log(`${o} — ${t.name} ${c} (${y}), refCount: ${s} → ${l}
|
|
730
|
+
${e}`);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
672
733
|
static workers = [];
|
|
673
734
|
static _workersIndex = 0;
|
|
674
735
|
static async getOrLoadLOD(t, e) {
|
|
675
|
-
const s =
|
|
676
|
-
if (!
|
|
677
|
-
return
|
|
678
|
-
const
|
|
679
|
-
let
|
|
736
|
+
const s = f == "verbose", r = this.getAssignedLODInformation(t);
|
|
737
|
+
if (!r)
|
|
738
|
+
return f && console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`, t), null;
|
|
739
|
+
const i = r?.key;
|
|
740
|
+
let o;
|
|
680
741
|
if (t.isTexture === !0) {
|
|
681
742
|
const a = t;
|
|
682
|
-
a.source && a.source[
|
|
743
|
+
a.source && a.source[ue] && (o = a.source[ue]);
|
|
683
744
|
}
|
|
684
|
-
if (
|
|
685
|
-
|
|
745
|
+
if (o || (o = m.lodInfos.get(i)), !o)
|
|
746
|
+
f && console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${t.name}`, t.type, m.lodInfos);
|
|
686
747
|
else {
|
|
687
748
|
if (e > 0) {
|
|
688
|
-
let
|
|
689
|
-
const y = Array.isArray(
|
|
690
|
-
if (y && e >=
|
|
691
|
-
const w = this.lowresCache.get(
|
|
749
|
+
let c = !1;
|
|
750
|
+
const y = Array.isArray(o.lods);
|
|
751
|
+
if (y && e >= o.lods.length ? c = !0 : y || (c = !0), c) {
|
|
752
|
+
const w = this.lowresCache.get(i);
|
|
692
753
|
if (w) {
|
|
693
754
|
const _ = w.deref();
|
|
694
755
|
if (_) return _;
|
|
695
|
-
this.lowresCache.delete(
|
|
756
|
+
this.lowresCache.delete(i), f && console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${i}`);
|
|
696
757
|
}
|
|
697
758
|
return null;
|
|
698
759
|
}
|
|
699
760
|
}
|
|
700
|
-
const a = Array.isArray(
|
|
761
|
+
const a = Array.isArray(o.lods) ? o.lods[e]?.path : o.lods;
|
|
701
762
|
if (!a)
|
|
702
|
-
return
|
|
703
|
-
const u =
|
|
763
|
+
return f && !o["missing:uri"] && (o["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + e, o)), null;
|
|
764
|
+
const u = st(r.url, a);
|
|
704
765
|
if (u.endsWith(".glb") || u.endsWith(".gltf")) {
|
|
705
|
-
if (!
|
|
706
|
-
return console.warn("missing pointer for glb/gltf texture",
|
|
707
|
-
const
|
|
766
|
+
if (!o.guid)
|
|
767
|
+
return console.warn("missing pointer for glb/gltf texture", o), null;
|
|
768
|
+
const c = u + "_" + o.guid, y = await this.queue.slot(u), w = this.cache.get(c);
|
|
708
769
|
if (w !== void 0)
|
|
709
|
-
if (s && console.log(`LOD ${e} was already loading/loaded: ${
|
|
710
|
-
const
|
|
711
|
-
if (
|
|
712
|
-
let g =
|
|
770
|
+
if (s && console.log(`LOD ${e} was already loading/loaded: ${c}`), w instanceof WeakRef) {
|
|
771
|
+
const d = w.deref();
|
|
772
|
+
if (d) {
|
|
773
|
+
let g = d, b = !1;
|
|
713
774
|
if (g instanceof F && t instanceof F ? g.image?.data || g.source?.data ? g = this.copySettings(t, g) : b = !0 : g instanceof E && t instanceof E && (g.attributes.position?.array || (b = !0)), !b)
|
|
714
775
|
return g;
|
|
715
776
|
}
|
|
716
|
-
this.cache.delete(
|
|
777
|
+
this.cache.delete(c), f && console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${c}`);
|
|
717
778
|
} else {
|
|
718
|
-
let
|
|
779
|
+
let d = await w.catch((b) => (console.error(`Error loading LOD ${e} from ${u}
|
|
719
780
|
`, b), null)), g = !1;
|
|
720
|
-
if (
|
|
721
|
-
return
|
|
781
|
+
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 E && t instanceof E && (d.attributes.position?.array || (g = !0, this.cache.delete(c)))), !g)
|
|
782
|
+
return d;
|
|
722
783
|
}
|
|
723
784
|
if (!y.use)
|
|
724
|
-
return
|
|
725
|
-
const _ =
|
|
726
|
-
if (
|
|
727
|
-
const x = await (await
|
|
785
|
+
return f && console.log(`LOD ${e} was aborted: ${u}`), null;
|
|
786
|
+
const _ = o, k = new Promise(async (d, g) => {
|
|
787
|
+
if (gt) {
|
|
788
|
+
const x = await (await ft({})).load(u);
|
|
728
789
|
if (x.textures.length > 0)
|
|
729
|
-
for (const
|
|
730
|
-
let p =
|
|
731
|
-
return m.assignLODInformation(
|
|
790
|
+
for (const h of x.textures) {
|
|
791
|
+
let p = h.texture;
|
|
792
|
+
return m.assignLODInformation(r.url, p, i, e, void 0), t instanceof F && (p = this.copySettings(t, p)), p && (p.guid = _.guid), d(p);
|
|
732
793
|
}
|
|
733
794
|
if (x.geometries.length > 0) {
|
|
734
|
-
const
|
|
795
|
+
const h = new Array();
|
|
735
796
|
for (const p of x.geometries) {
|
|
736
797
|
const O = p.geometry;
|
|
737
|
-
m.assignLODInformation(
|
|
798
|
+
m.assignLODInformation(r.url, O, i, e, p.primitiveIndex), h.push(O);
|
|
738
799
|
}
|
|
739
|
-
return
|
|
800
|
+
return d(h);
|
|
740
801
|
}
|
|
741
|
-
return
|
|
802
|
+
return d(null);
|
|
742
803
|
}
|
|
743
|
-
const b = new
|
|
744
|
-
|
|
804
|
+
const b = new xe();
|
|
805
|
+
Pe(b), f && (await new Promise((L) => setTimeout(L, 1e3)), s && console.warn("Start loading (delayed) " + u, _.guid));
|
|
745
806
|
let B = u;
|
|
746
807
|
if (_ && Array.isArray(_.lods)) {
|
|
747
808
|
const L = _.lods[e];
|
|
748
809
|
L.hash && (B += "?v=" + L.hash);
|
|
749
810
|
}
|
|
750
811
|
const D = await b.loadAsync(B).catch((L) => (console.error(`Error loading LOD ${e} from ${u}
|
|
751
|
-
`, L),
|
|
812
|
+
`, L), d(null)));
|
|
752
813
|
if (!D)
|
|
753
|
-
return
|
|
754
|
-
const
|
|
814
|
+
return d(null);
|
|
815
|
+
const q = D.parser;
|
|
755
816
|
s && console.log("Loading finished " + u, _.guid);
|
|
756
817
|
let P = 0;
|
|
757
818
|
if (D.parser.json.textures) {
|
|
758
819
|
let L = !1;
|
|
759
820
|
for (const x of D.parser.json.textures) {
|
|
760
821
|
if (x?.extensions) {
|
|
761
|
-
const
|
|
762
|
-
if (
|
|
822
|
+
const h = x?.extensions[W];
|
|
823
|
+
if (h?.guid && h.guid === _.guid) {
|
|
763
824
|
L = !0;
|
|
764
825
|
break;
|
|
765
826
|
}
|
|
@@ -767,16 +828,16 @@ ${t}`), e instanceof WeakRef && (e.deref() || (m.cache.delete(t), h && console.l
|
|
|
767
828
|
P++;
|
|
768
829
|
}
|
|
769
830
|
if (L) {
|
|
770
|
-
let x = await
|
|
771
|
-
return x && m.assignLODInformation(
|
|
772
|
-
} else
|
|
831
|
+
let x = await q.getDependency("texture", P);
|
|
832
|
+
return x && m.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);
|
|
833
|
+
} else f && console.warn("Could not find texture with guid", _.guid, D.parser.json);
|
|
773
834
|
}
|
|
774
835
|
if (P = 0, D.parser.json.meshes) {
|
|
775
836
|
let L = !1;
|
|
776
837
|
for (const x of D.parser.json.meshes) {
|
|
777
838
|
if (x?.extensions) {
|
|
778
|
-
const
|
|
779
|
-
if (
|
|
839
|
+
const h = x?.extensions[W];
|
|
840
|
+
if (h?.guid && h.guid === _.guid) {
|
|
780
841
|
L = !0;
|
|
781
842
|
break;
|
|
782
843
|
}
|
|
@@ -784,69 +845,68 @@ ${t}`), e instanceof WeakRef && (e.deref() || (m.cache.delete(t), h && console.l
|
|
|
784
845
|
P++;
|
|
785
846
|
}
|
|
786
847
|
if (L) {
|
|
787
|
-
const x = await
|
|
788
|
-
if (s && console.log(`Loaded Mesh "${x.name}"`, u, P, x,
|
|
789
|
-
const
|
|
790
|
-
return m.assignLODInformation(
|
|
848
|
+
const x = await q.getDependency("mesh", P);
|
|
849
|
+
if (s && console.log(`Loaded Mesh "${x.name}"`, u, P, x, c), x.isMesh === !0) {
|
|
850
|
+
const h = x.geometry;
|
|
851
|
+
return m.assignLODInformation(r.url, h, i, e, 0), d(h);
|
|
791
852
|
} else {
|
|
792
|
-
const
|
|
853
|
+
const h = new Array();
|
|
793
854
|
for (let p = 0; p < x.children.length; p++) {
|
|
794
855
|
const O = x.children[p];
|
|
795
856
|
if (O.isMesh === !0) {
|
|
796
857
|
const S = O.geometry;
|
|
797
|
-
m.assignLODInformation(
|
|
858
|
+
m.assignLODInformation(r.url, S, i, e, p), h.push(S);
|
|
798
859
|
}
|
|
799
860
|
}
|
|
800
|
-
return
|
|
861
|
+
return d(h);
|
|
801
862
|
}
|
|
802
|
-
} else
|
|
863
|
+
} else f && console.warn("Could not find mesh with guid", _.guid, D.parser.json);
|
|
803
864
|
}
|
|
804
|
-
return
|
|
865
|
+
return d(null);
|
|
805
866
|
});
|
|
806
|
-
this.cache.set(
|
|
807
|
-
const M = await
|
|
808
|
-
return M != null ? M instanceof F ? (this.cache.set(
|
|
867
|
+
this.cache.set(c, k), y.use(k);
|
|
868
|
+
const M = await k;
|
|
869
|
+
return M != null ? M instanceof F ? (this.cache.set(c, new WeakRef(M)), m._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
870
|
} else if (t instanceof F) {
|
|
810
871
|
s && console.log("Load texture from uri: " + u);
|
|
811
|
-
const y = await new
|
|
812
|
-
return y ? (y.guid =
|
|
872
|
+
const y = await new Ne().loadAsync(u);
|
|
873
|
+
return y ? (y.guid = o.guid, y.flipY = !1, y.needsUpdate = !0, y.colorSpace = t.colorSpace, s && console.log(o, y)) : f && console.warn("failed loading", u), y;
|
|
813
874
|
}
|
|
814
875
|
}
|
|
815
876
|
return null;
|
|
816
877
|
}
|
|
817
|
-
static
|
|
818
|
-
static
|
|
819
|
-
static assignLODInformation(t, e, s, o, r) {
|
|
878
|
+
static queue = new rt(50, { debug: f != !1 });
|
|
879
|
+
static assignLODInformation(t, e, s, r, i) {
|
|
820
880
|
if (!e) return;
|
|
821
881
|
e.userData || (e.userData = {});
|
|
822
|
-
const
|
|
823
|
-
e.userData.LODS =
|
|
882
|
+
const o = new pt(t, s, r, i);
|
|
883
|
+
e.userData.LODS = o, "source" in e && typeof e.source == "object" && (e.source.LODS = o);
|
|
824
884
|
}
|
|
825
885
|
static getAssignedLODInformation(t) {
|
|
826
886
|
return t ? t.userData?.LODS ? t.userData.LODS : "source" in t && t.source?.LODS ? t.source.LODS : null : null;
|
|
827
887
|
}
|
|
828
888
|
// private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
|
|
829
889
|
static copySettings(t, e) {
|
|
830
|
-
return e ? (
|
|
890
|
+
return e ? (f === "verbose" && console.debug(`Copy texture settings
|
|
831
891
|
`, t.uuid, `
|
|
832
892
|
`, 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
893
|
}
|
|
834
894
|
}
|
|
835
|
-
class
|
|
895
|
+
class pt {
|
|
836
896
|
url;
|
|
837
897
|
/** the key to lookup the LOD information */
|
|
838
898
|
key;
|
|
839
899
|
level;
|
|
840
900
|
/** For multi objects (e.g. a group of meshes) this is the index of the object */
|
|
841
901
|
index;
|
|
842
|
-
constructor(t, e, s,
|
|
843
|
-
this.url = t, this.key = e, this.level = s,
|
|
902
|
+
constructor(t, e, s, r) {
|
|
903
|
+
this.url = t, this.key = e, this.level = s, r != null && (this.index = r);
|
|
844
904
|
}
|
|
845
905
|
}
|
|
846
|
-
class
|
|
847
|
-
static addPromise = (t, e, s,
|
|
848
|
-
|
|
849
|
-
|
|
906
|
+
class ce {
|
|
907
|
+
static addPromise = (t, e, s, r) => {
|
|
908
|
+
r.forEach((i) => {
|
|
909
|
+
i.add(t, e, s);
|
|
850
910
|
});
|
|
851
911
|
};
|
|
852
912
|
ready;
|
|
@@ -876,9 +936,9 @@ class ue {
|
|
|
876
936
|
_awaiting = [];
|
|
877
937
|
_maxPromisesPerObject = 1;
|
|
878
938
|
constructor(t, e) {
|
|
879
|
-
const
|
|
880
|
-
this._frame_start = e.waitForFirstCapture ? void 0 : t, this._frames_to_capture =
|
|
881
|
-
this._resolve =
|
|
939
|
+
const r = Math.max(e.frames ?? 2, 2);
|
|
940
|
+
this._frame_start = e.waitForFirstCapture ? void 0 : t, this._frames_to_capture = r, this.ready = new Promise((i) => {
|
|
941
|
+
this._resolve = i;
|
|
882
942
|
}), this.ready.finally(() => {
|
|
883
943
|
this._resolved = !0, this._awaiting.length = 0;
|
|
884
944
|
}), this._signal = e.signal, this._signal?.addEventListener("abort", () => {
|
|
@@ -892,18 +952,18 @@ class ue {
|
|
|
892
952
|
_seen = /* @__PURE__ */ new WeakMap();
|
|
893
953
|
add(t, e, s) {
|
|
894
954
|
if (this._resolved) {
|
|
895
|
-
|
|
955
|
+
f && console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");
|
|
896
956
|
return;
|
|
897
957
|
}
|
|
898
958
|
if (!(this._frame_start !== void 0 && this._currentFrame > this._frame_start + this._frames_to_capture)) {
|
|
899
959
|
if (this._maxPromisesPerObject >= 1)
|
|
900
960
|
if (this._seen.has(e)) {
|
|
901
|
-
let
|
|
902
|
-
if (
|
|
903
|
-
|
|
961
|
+
let r = this._seen.get(e);
|
|
962
|
+
if (r >= this._maxPromisesPerObject) {
|
|
963
|
+
f && console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");
|
|
904
964
|
return;
|
|
905
965
|
}
|
|
906
|
-
this._seen.set(e,
|
|
966
|
+
this._seen.set(e, r + 1);
|
|
907
967
|
} else
|
|
908
968
|
this._seen.set(e, 1);
|
|
909
969
|
this._awaiting.push(s), this._addedCount++, s.finally(() => {
|
|
@@ -919,7 +979,7 @@ class ue {
|
|
|
919
979
|
});
|
|
920
980
|
}
|
|
921
981
|
}
|
|
922
|
-
const
|
|
982
|
+
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
983
|
class v {
|
|
924
984
|
/**
|
|
925
985
|
* 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 +987,7 @@ class v {
|
|
|
927
987
|
static debugDrawLine;
|
|
928
988
|
/** @internal */
|
|
929
989
|
static getObjectLODState(t) {
|
|
930
|
-
return t[
|
|
990
|
+
return t[fe];
|
|
931
991
|
}
|
|
932
992
|
static addPlugin(t) {
|
|
933
993
|
z.push(t);
|
|
@@ -952,7 +1012,7 @@ class v {
|
|
|
952
1012
|
}
|
|
953
1013
|
renderer;
|
|
954
1014
|
context;
|
|
955
|
-
projectionScreenMatrix = new
|
|
1015
|
+
projectionScreenMatrix = new Le();
|
|
956
1016
|
/** @deprecated use static `LODsManager.addPlugin()` method. This getter will be removed in later versions */
|
|
957
1017
|
get plugins() {
|
|
958
1018
|
return z;
|
|
@@ -996,13 +1056,13 @@ class v {
|
|
|
996
1056
|
* Call to await LODs loading during the next render cycle.
|
|
997
1057
|
*/
|
|
998
1058
|
awaitLoading(t) {
|
|
999
|
-
const e = this._promiseGroupIds++, s = new
|
|
1059
|
+
const e = this._promiseGroupIds++, s = new ce(this.#r, { ...t });
|
|
1000
1060
|
this._newPromiseGroups.push(s);
|
|
1001
|
-
const
|
|
1061
|
+
const r = performance.now();
|
|
1002
1062
|
return s.ready.finally(() => {
|
|
1003
|
-
const
|
|
1004
|
-
|
|
1005
|
-
start:
|
|
1063
|
+
const i = this._newPromiseGroups.indexOf(s);
|
|
1064
|
+
i >= 0 && (this._newPromiseGroups.splice(i, 1), ve() && performance.measure("LODsManager:awaitLoading", {
|
|
1065
|
+
start: r,
|
|
1006
1066
|
detail: { id: e, name: t?.name, awaited: s.awaitedCount, resolved: s.resolvedCount }
|
|
1007
1067
|
}));
|
|
1008
1068
|
}), s.ready;
|
|
@@ -1027,10 +1087,10 @@ class v {
|
|
|
1027
1087
|
this.renderer = t, this.context = { ...e };
|
|
1028
1088
|
}
|
|
1029
1089
|
#t;
|
|
1030
|
-
#
|
|
1090
|
+
#o = new qe();
|
|
1031
1091
|
#r = 0;
|
|
1032
|
-
#o = 0;
|
|
1033
1092
|
#i = 0;
|
|
1093
|
+
#n = 0;
|
|
1034
1094
|
#s = 0;
|
|
1035
1095
|
_fpsBuffer = [60, 60, 60, 60, 60];
|
|
1036
1096
|
/**
|
|
@@ -1042,11 +1102,11 @@ class v {
|
|
|
1042
1102
|
let t = 0;
|
|
1043
1103
|
this.#t = this.renderer.render;
|
|
1044
1104
|
const e = this;
|
|
1045
|
-
|
|
1046
|
-
const
|
|
1047
|
-
(
|
|
1048
|
-
const
|
|
1049
|
-
e.#t.call(this, s,
|
|
1105
|
+
we(this.renderer), this.renderer.render = function(s, r) {
|
|
1106
|
+
const i = e.renderer.getRenderTarget();
|
|
1107
|
+
(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));
|
|
1108
|
+
const o = t++;
|
|
1109
|
+
e.#t.call(this, s, r), e.onAfterRender(s, r, o);
|
|
1050
1110
|
};
|
|
1051
1111
|
}
|
|
1052
1112
|
disable() {
|
|
@@ -1057,14 +1117,14 @@ class v {
|
|
|
1057
1117
|
}
|
|
1058
1118
|
onAfterRender(t, e, s) {
|
|
1059
1119
|
if (this.pause) return;
|
|
1060
|
-
const
|
|
1061
|
-
let
|
|
1062
|
-
if (
|
|
1063
|
-
const l =
|
|
1064
|
-
(l.name === "EffectMaterial" || l.name === "CopyShader") && (
|
|
1120
|
+
const i = this.renderer.renderLists.get(t, 0).opaque;
|
|
1121
|
+
let o = !0;
|
|
1122
|
+
if (i.length === 1) {
|
|
1123
|
+
const l = i[0].material;
|
|
1124
|
+
(l.name === "EffectMaterial" || l.name === "CopyShader") && (o = !1);
|
|
1065
1125
|
}
|
|
1066
|
-
if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (
|
|
1067
|
-
if (
|
|
1126
|
+
if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (o = !1), o) {
|
|
1127
|
+
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
1128
|
return;
|
|
1069
1129
|
this.internalUpdate(t, e), this._postprocessPromiseGroups();
|
|
1070
1130
|
}
|
|
@@ -1073,12 +1133,12 @@ class v {
|
|
|
1073
1133
|
* Update LODs in a scene
|
|
1074
1134
|
*/
|
|
1075
1135
|
internalUpdate(t, e) {
|
|
1076
|
-
const s = this.renderer.renderLists.get(t, 0),
|
|
1136
|
+
const s = this.renderer.renderLists.get(t, 0), r = s.opaque;
|
|
1077
1137
|
this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix, e.matrixWorldInverse);
|
|
1078
|
-
const
|
|
1079
|
-
for (const a of
|
|
1138
|
+
const i = this.targetTriangleDensity;
|
|
1139
|
+
for (const a of r) {
|
|
1080
1140
|
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
|
-
|
|
1141
|
+
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
1142
|
continue;
|
|
1083
1143
|
}
|
|
1084
1144
|
switch (a.material.type) {
|
|
@@ -1090,38 +1150,38 @@ class v {
|
|
|
1090
1150
|
case "MeshDepthMaterial":
|
|
1091
1151
|
continue;
|
|
1092
1152
|
}
|
|
1093
|
-
if (
|
|
1153
|
+
if (R === "color" && a.material && !a.object.progressive_debug_color) {
|
|
1094
1154
|
a.object.progressive_debug_color = !0;
|
|
1095
|
-
const
|
|
1155
|
+
const c = Math.random() * 16777215, y = new Ve({ color: c });
|
|
1096
1156
|
a.object.material = y;
|
|
1097
1157
|
}
|
|
1098
1158
|
const u = a.object;
|
|
1099
|
-
(u instanceof
|
|
1159
|
+
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1100
1160
|
}
|
|
1101
|
-
const
|
|
1102
|
-
for (const a of
|
|
1161
|
+
const o = s.transparent;
|
|
1162
|
+
for (const a of o) {
|
|
1103
1163
|
const u = a.object;
|
|
1104
|
-
(u instanceof
|
|
1164
|
+
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1105
1165
|
}
|
|
1106
1166
|
const l = s.transmissive;
|
|
1107
1167
|
for (const a of l) {
|
|
1108
1168
|
const u = a.object;
|
|
1109
|
-
(u instanceof
|
|
1169
|
+
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1110
1170
|
}
|
|
1111
1171
|
}
|
|
1112
1172
|
/** Update the LOD levels for the renderer. */
|
|
1113
|
-
updateLODs(t, e, s,
|
|
1173
|
+
updateLODs(t, e, s, r) {
|
|
1114
1174
|
s.userData || (s.userData = {});
|
|
1115
|
-
let
|
|
1116
|
-
if (
|
|
1175
|
+
let i = s[fe];
|
|
1176
|
+
if (i || (i = new yt(), s[fe] = i), i.frames++ < 2)
|
|
1117
1177
|
return;
|
|
1118
1178
|
for (const l of z)
|
|
1119
1179
|
l.onBeforeUpdateLOD?.(this.renderer, t, e, s);
|
|
1120
|
-
const
|
|
1121
|
-
|
|
1180
|
+
const o = this.overrideLodLevel !== void 0 ? this.overrideLodLevel : V;
|
|
1181
|
+
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
1182
|
for (const l of z)
|
|
1123
1183
|
l.onAfterUpdatedLOD?.(this.renderer, t, e, s, T);
|
|
1124
|
-
|
|
1184
|
+
i.lastLodLevel_Mesh = T.mesh_lod, i.lastLodLevel_Texture = T.texture_lod;
|
|
1125
1185
|
}
|
|
1126
1186
|
/** Load progressive textures for the given material
|
|
1127
1187
|
* @param material the material to load the textures for
|
|
@@ -1131,17 +1191,17 @@ class v {
|
|
|
1131
1191
|
loadProgressiveTextures(t, e, s) {
|
|
1132
1192
|
if (!t) return;
|
|
1133
1193
|
if (Array.isArray(t)) {
|
|
1134
|
-
for (const
|
|
1135
|
-
this.loadProgressiveTextures(
|
|
1194
|
+
for (const i of t)
|
|
1195
|
+
this.loadProgressiveTextures(i, e);
|
|
1136
1196
|
return;
|
|
1137
1197
|
}
|
|
1138
|
-
let
|
|
1139
|
-
if ((t[U] === void 0 || e < t[U]) && (
|
|
1198
|
+
let r = !1;
|
|
1199
|
+
if ((t[U] === void 0 || e < t[U]) && (r = !0), s !== void 0 && s >= 0 && (r = t[U] != s, e = s), r) {
|
|
1140
1200
|
t[U] = e;
|
|
1141
|
-
const
|
|
1201
|
+
const i = m.assignTextureLOD(t, e).then((o) => {
|
|
1142
1202
|
this._lodchangedlisteners.forEach((l) => l({ type: "texture", level: e, object: t }));
|
|
1143
1203
|
});
|
|
1144
|
-
|
|
1204
|
+
ce.addPromise("texture", t, i, this._newPromiseGroups);
|
|
1145
1205
|
}
|
|
1146
1206
|
}
|
|
1147
1207
|
/** Load progressive meshes for the given mesh
|
|
@@ -1153,141 +1213,141 @@ class v {
|
|
|
1153
1213
|
loadProgressiveMeshes(t, e) {
|
|
1154
1214
|
if (!t) return Promise.resolve(null);
|
|
1155
1215
|
let s = t[U] !== e;
|
|
1156
|
-
const
|
|
1157
|
-
if (
|
|
1216
|
+
const r = t["DEBUG:LOD"];
|
|
1217
|
+
if (r != null && (s = t[U] != r, e = r), s) {
|
|
1158
1218
|
t[U] = e;
|
|
1159
|
-
const
|
|
1160
|
-
return
|
|
1219
|
+
const i = t.geometry, o = m.assignMeshLOD(t, e).then((l) => (l && t[U] == e && i != t.geometry && this._lodchangedlisteners.forEach((a) => a({ type: "mesh", level: e, object: t })), l));
|
|
1220
|
+
return ce.addPromise("mesh", t, o, this._newPromiseGroups), o;
|
|
1161
1221
|
}
|
|
1162
1222
|
return Promise.resolve(null);
|
|
1163
1223
|
}
|
|
1164
1224
|
// 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
|
|
1225
|
+
_sphere = new Oe();
|
|
1226
|
+
_tempBox = new ge();
|
|
1227
|
+
_tempBox2 = new ge();
|
|
1228
|
+
tempMatrix = new Le();
|
|
1229
|
+
_tempWorldPosition = new A();
|
|
1230
|
+
_tempBoxSize = new A();
|
|
1231
|
+
_tempBox2Size = new A();
|
|
1232
|
+
static corner0 = new A();
|
|
1233
|
+
static corner1 = new A();
|
|
1234
|
+
static corner2 = new A();
|
|
1235
|
+
static corner3 = new A();
|
|
1236
|
+
static _tempPtInside = new A();
|
|
1177
1237
|
static isInside(t, e) {
|
|
1178
|
-
const s = t.min,
|
|
1179
|
-
return this._tempPtInside.set(
|
|
1238
|
+
const s = t.min, r = t.max, i = (s.x + r.x) * 0.5, o = (s.y + r.y) * 0.5;
|
|
1239
|
+
return this._tempPtInside.set(i, o, s.z).applyMatrix4(e).z < 0;
|
|
1180
1240
|
}
|
|
1181
1241
|
static skinnedMeshBoundsFrameOffsetCounter = 0;
|
|
1182
1242
|
static $skinnedMeshBoundsOffset = /* @__PURE__ */ Symbol("gltf-progressive-skinnedMeshBoundsOffset");
|
|
1183
1243
|
// #region calculateLodLevel
|
|
1184
|
-
calculateLodLevel(t, e, s,
|
|
1244
|
+
calculateLodLevel(t, e, s, r, i) {
|
|
1185
1245
|
if (!e) {
|
|
1186
|
-
|
|
1246
|
+
i.mesh_lod = -1, i.texture_lod = -1;
|
|
1187
1247
|
return;
|
|
1188
1248
|
}
|
|
1189
1249
|
if (!t) {
|
|
1190
|
-
|
|
1250
|
+
i.mesh_lod = -1, i.texture_lod = -1;
|
|
1191
1251
|
return;
|
|
1192
1252
|
}
|
|
1193
1253
|
let l = 10 + 1, a = !1;
|
|
1194
|
-
if (
|
|
1254
|
+
if (R && e["DEBUG:LOD"] != null)
|
|
1195
1255
|
return e["DEBUG:LOD"];
|
|
1196
|
-
const u = m.getMeshLODExtension(e.geometry)?.lods,
|
|
1256
|
+
const u = m.getMeshLODExtension(e.geometry)?.lods, c = m.getPrimitiveIndex(e.geometry), y = u && u.length > 0, w = m.getMaterialMinMaxLODsCount(e.material), _ = w.min_count !== 1 / 0 && w.min_count >= 0 && w.max_count >= 0;
|
|
1197
1257
|
if (!y && !_) {
|
|
1198
|
-
|
|
1258
|
+
i.mesh_lod = 0, i.texture_lod = 0;
|
|
1199
1259
|
return;
|
|
1200
1260
|
}
|
|
1201
1261
|
y || (a = !0, l = 0);
|
|
1202
|
-
const
|
|
1262
|
+
const k = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
|
|
1203
1263
|
let M = e.geometry.boundingBox;
|
|
1204
1264
|
if (e.type === "SkinnedMesh") {
|
|
1205
|
-
const
|
|
1206
|
-
if (!
|
|
1207
|
-
|
|
1265
|
+
const d = e;
|
|
1266
|
+
if (!d.boundingBox)
|
|
1267
|
+
d.computeBoundingBox();
|
|
1208
1268
|
else if (this.skinnedMeshAutoUpdateBoundsInterval > 0) {
|
|
1209
|
-
if (!
|
|
1269
|
+
if (!d[v.$skinnedMeshBoundsOffset]) {
|
|
1210
1270
|
const b = v.skinnedMeshBoundsFrameOffsetCounter++;
|
|
1211
|
-
|
|
1271
|
+
d[v.$skinnedMeshBoundsOffset] = b;
|
|
1212
1272
|
}
|
|
1213
|
-
const g =
|
|
1273
|
+
const g = d[v.$skinnedMeshBoundsOffset];
|
|
1214
1274
|
if ((s.frames + g) % this.skinnedMeshAutoUpdateBoundsInterval === 0) {
|
|
1215
|
-
const b =
|
|
1216
|
-
b && (
|
|
1275
|
+
const b = ee(d), B = d.geometry;
|
|
1276
|
+
b && (d.geometry = b), d.computeBoundingBox(), d.geometry = B;
|
|
1217
1277
|
}
|
|
1218
1278
|
}
|
|
1219
|
-
M =
|
|
1279
|
+
M = d.boundingBox;
|
|
1220
1280
|
}
|
|
1221
1281
|
if (M) {
|
|
1222
|
-
const
|
|
1282
|
+
const d = t;
|
|
1223
1283
|
if (e.geometry.attributes.color && e.geometry.attributes.color.count < 100 && e.geometry.boundingSphere) {
|
|
1224
1284
|
this._sphere.copy(e.geometry.boundingSphere), this._sphere.applyMatrix4(e.matrixWorld);
|
|
1225
|
-
const
|
|
1226
|
-
if (this._sphere.containsPoint(
|
|
1227
|
-
|
|
1285
|
+
const h = t.getWorldPosition(this._tempWorldPosition);
|
|
1286
|
+
if (this._sphere.containsPoint(h)) {
|
|
1287
|
+
i.mesh_lod = 0, i.texture_lod = 0;
|
|
1228
1288
|
return;
|
|
1229
1289
|
}
|
|
1230
1290
|
}
|
|
1231
|
-
if (this._tempBox.copy(M), this._tempBox.applyMatrix4(e.matrixWorld),
|
|
1232
|
-
|
|
1291
|
+
if (this._tempBox.copy(M), this._tempBox.applyMatrix4(e.matrixWorld), d.isPerspectiveCamera && v.isInside(this._tempBox, this.projectionScreenMatrix)) {
|
|
1292
|
+
i.mesh_lod = 0, i.texture_lod = 0;
|
|
1233
1293
|
return;
|
|
1234
1294
|
}
|
|
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 -
|
|
1295
|
+
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && d.isPerspectiveCamera && d.fov > 70) {
|
|
1296
|
+
const h = this._tempBox.min, p = this._tempBox.max;
|
|
1297
|
+
let O = h.x, S = h.y, G = p.x, Y = p.y;
|
|
1298
|
+
const te = 2, ne = 1.5, se = (h.x + p.x) * 0.5, re = (h.y + p.y) * 0.5;
|
|
1299
|
+
O = (O - se) * te + se, S = (S - re) * te + re, G = (G - se) * te + se, Y = (Y - re) * te + re;
|
|
1300
|
+
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);
|
|
1301
|
+
s.lastCentrality = (ne - ae) * (ne - ae) * (ne - ae);
|
|
1242
1302
|
} else
|
|
1243
1303
|
s.lastCentrality = 1;
|
|
1244
1304
|
const g = this._tempBox.getSize(this._tempBoxSize);
|
|
1245
|
-
g.multiplyScalar(0.5), screen.availHeight > 0 &&
|
|
1305
|
+
g.multiplyScalar(0.5), screen.availHeight > 0 && k > 0 && g.multiplyScalar(k / screen.availHeight), t.isPerspectiveCamera ? g.x *= t.aspect : t.isOrthographicCamera;
|
|
1246
1306
|
const b = t.matrixWorldInverse, B = this._tempBox2;
|
|
1247
1307
|
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
|
-
|
|
1308
|
+
const D = B.getSize(this._tempBox2Size), q = Math.max(D.x, D.y);
|
|
1309
|
+
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) {
|
|
1310
|
+
const h = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
1311
|
+
h.invert();
|
|
1252
1312
|
const p = v.corner0, O = v.corner1, S = v.corner2, G = v.corner3;
|
|
1253
1313
|
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
1314
|
const Y = (p.z + G.z) * 0.5;
|
|
1255
|
-
p.z = O.z = S.z = G.z = Y, p.applyMatrix4(
|
|
1315
|
+
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
1316
|
}
|
|
1257
1317
|
let L = 999;
|
|
1258
1318
|
if (u && s.lastScreenCoverage > 0)
|
|
1259
|
-
for (let
|
|
1260
|
-
const p = u[
|
|
1261
|
-
if (
|
|
1262
|
-
L =
|
|
1319
|
+
for (let h = 0; h < u.length; h++) {
|
|
1320
|
+
const p = u[h], S = (p.densities?.[c] || p.density || 1e-5) / s.lastScreenCoverage;
|
|
1321
|
+
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) {
|
|
1322
|
+
L = h;
|
|
1263
1323
|
break;
|
|
1264
1324
|
}
|
|
1265
1325
|
}
|
|
1266
1326
|
L < l && (l = L, a = !0);
|
|
1267
1327
|
}
|
|
1268
|
-
if (a ?
|
|
1269
|
-
const g = u?.[
|
|
1270
|
-
g && console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${
|
|
1328
|
+
if (a ? i.mesh_lod = l : i.mesh_lod = s.lastLodLevel_Mesh, R && i.mesh_lod != s.lastLodLevel_Mesh) {
|
|
1329
|
+
const g = u?.[i.mesh_lod];
|
|
1330
|
+
g && console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${i.mesh_lod} (density: ${g.densities?.[c].toFixed(0)}) | ${e.name}`);
|
|
1271
1331
|
}
|
|
1272
1332
|
if (_) {
|
|
1273
|
-
const
|
|
1333
|
+
const d = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
|
|
1274
1334
|
if (s.lastLodLevel_Texture < 0) {
|
|
1275
|
-
if (
|
|
1335
|
+
if (i.texture_lod = w.max_count - 1, R) {
|
|
1276
1336
|
const g = w.lods[w.max_count - 1];
|
|
1277
|
-
|
|
1337
|
+
R && console.log(`First Texture LOD ${i.texture_lod} (${g.max_height}px) - ${e.name}`);
|
|
1278
1338
|
}
|
|
1279
1339
|
} else {
|
|
1280
1340
|
const g = s.lastScreenspaceVolume.x + s.lastScreenspaceVolume.y + s.lastScreenspaceVolume.z;
|
|
1281
1341
|
let b = s.lastScreenCoverage * 4;
|
|
1282
1342
|
this.context?.engine === "model-viewer" && (b *= 1.5);
|
|
1283
|
-
const D =
|
|
1284
|
-
let
|
|
1343
|
+
const D = k / window.devicePixelRatio * b;
|
|
1344
|
+
let q = !1;
|
|
1285
1345
|
for (let P = w.lods.length - 1; P >= 0; P--) {
|
|
1286
1346
|
const L = w.lods[P];
|
|
1287
|
-
if (!(
|
|
1288
|
-
if (
|
|
1347
|
+
if (!(d && L.max_height >= 2048) && !(Ae() && L.max_height > 4096) && (L.max_height > D || !q && P === 0)) {
|
|
1348
|
+
if (q = !0, i.texture_lod = P, R && i.texture_lod < s.lastLodLevel_Texture) {
|
|
1289
1349
|
const x = L.max_height;
|
|
1290
|
-
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${
|
|
1350
|
+
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${i.texture_lod} = ${x}px
|
|
1291
1351
|
Screensize: ${D.toFixed(0)}px, Coverage: ${(100 * s.lastScreenCoverage).toFixed(2)}%, Volume ${g.toFixed(1)}
|
|
1292
1352
|
${e.name}`);
|
|
1293
1353
|
}
|
|
@@ -1296,86 +1356,86 @@ ${e.name}`);
|
|
|
1296
1356
|
}
|
|
1297
1357
|
}
|
|
1298
1358
|
} else
|
|
1299
|
-
|
|
1359
|
+
i.texture_lod = 0;
|
|
1300
1360
|
}
|
|
1301
1361
|
}
|
|
1302
|
-
class
|
|
1362
|
+
class yt {
|
|
1303
1363
|
frames = 0;
|
|
1304
1364
|
lastLodLevel_Mesh = -1;
|
|
1305
1365
|
lastLodLevel_Texture = -1;
|
|
1306
1366
|
lastScreenCoverage = 0;
|
|
1307
|
-
lastScreenspaceVolume = new
|
|
1367
|
+
lastScreenspaceVolume = new A();
|
|
1308
1368
|
lastCentrality = 0;
|
|
1309
1369
|
}
|
|
1310
|
-
const
|
|
1311
|
-
let
|
|
1312
|
-
function
|
|
1313
|
-
const
|
|
1314
|
-
|
|
1315
|
-
return
|
|
1316
|
-
}),
|
|
1370
|
+
const be = /* @__PURE__ */ Symbol("NEEDLE_mesh_lod"), ie = /* @__PURE__ */ Symbol("NEEDLE_texture_lod");
|
|
1371
|
+
let he = null;
|
|
1372
|
+
function Re() {
|
|
1373
|
+
const n = xt();
|
|
1374
|
+
n && (n.mapURLs(function(t) {
|
|
1375
|
+
return Me(), t;
|
|
1376
|
+
}), Me(), he?.disconnect(), he = new MutationObserver((t) => {
|
|
1317
1377
|
t.forEach((e) => {
|
|
1318
1378
|
e.addedNodes.forEach((s) => {
|
|
1319
|
-
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" &&
|
|
1379
|
+
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" && Ie(s);
|
|
1320
1380
|
});
|
|
1321
1381
|
});
|
|
1322
|
-
}),
|
|
1382
|
+
}), he.observe(document, { childList: !0, subtree: !0 }));
|
|
1323
1383
|
}
|
|
1324
|
-
function
|
|
1384
|
+
function xt() {
|
|
1325
1385
|
if (typeof customElements > "u") return null;
|
|
1326
|
-
const
|
|
1327
|
-
return
|
|
1328
|
-
console.debug("[gltf-progressive] model-viewer defined"),
|
|
1386
|
+
const n = customElements.get("model-viewer");
|
|
1387
|
+
return n || (customElements.whenDefined("model-viewer").then(() => {
|
|
1388
|
+
console.debug("[gltf-progressive] model-viewer defined"), Re();
|
|
1329
1389
|
}), null);
|
|
1330
1390
|
}
|
|
1331
|
-
function
|
|
1391
|
+
function Me() {
|
|
1332
1392
|
if (typeof document > "u") return;
|
|
1333
1393
|
document.querySelectorAll("model-viewer").forEach((t) => {
|
|
1334
|
-
|
|
1394
|
+
Ie(t);
|
|
1335
1395
|
});
|
|
1336
1396
|
}
|
|
1337
|
-
const
|
|
1338
|
-
let
|
|
1339
|
-
function
|
|
1340
|
-
if (!
|
|
1397
|
+
const De = /* @__PURE__ */ new WeakSet();
|
|
1398
|
+
let wt = 0;
|
|
1399
|
+
function Ie(n) {
|
|
1400
|
+
if (!n || De.has(n))
|
|
1341
1401
|
return null;
|
|
1342
|
-
|
|
1343
|
-
`,
|
|
1402
|
+
De.add(n), console.debug("[gltf-progressive] found new model-viewer..." + ++wt + `
|
|
1403
|
+
`, n.getAttribute("src"));
|
|
1344
1404
|
let t = null, e = null, s = null;
|
|
1345
|
-
for (let
|
|
1346
|
-
const
|
|
1347
|
-
!t &&
|
|
1405
|
+
for (let r = n; r != null; r = Object.getPrototypeOf(r)) {
|
|
1406
|
+
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)");
|
|
1407
|
+
!t && o != null && (t = n[o].threeRenderer), !e && l != null && (e = n[l]), !s && a != null && (s = n[a]);
|
|
1348
1408
|
}
|
|
1349
1409
|
if (t && e) {
|
|
1350
|
-
let
|
|
1410
|
+
let r = function() {
|
|
1351
1411
|
if (s) {
|
|
1352
|
-
let
|
|
1353
|
-
if (
|
|
1412
|
+
let o = 0, l = setInterval(() => {
|
|
1413
|
+
if (o++ > 5) {
|
|
1354
1414
|
clearInterval(l);
|
|
1355
1415
|
return;
|
|
1356
1416
|
}
|
|
1357
|
-
s?.call(
|
|
1417
|
+
s?.call(n);
|
|
1358
1418
|
}, 300);
|
|
1359
1419
|
}
|
|
1360
1420
|
};
|
|
1361
1421
|
console.debug("[gltf-progressive] setup model-viewer");
|
|
1362
|
-
const
|
|
1363
|
-
return v.addPlugin(new
|
|
1364
|
-
s?.call(
|
|
1365
|
-
}),
|
|
1366
|
-
|
|
1367
|
-
}),
|
|
1368
|
-
|
|
1422
|
+
const i = v.get(t, { engine: "model-viewer" });
|
|
1423
|
+
return v.addPlugin(new _t()), i.enable(), i.addEventListener("changed", () => {
|
|
1424
|
+
s?.call(n);
|
|
1425
|
+
}), n.addEventListener("model-visibility", (o) => {
|
|
1426
|
+
o.detail.visible && s?.call(n);
|
|
1427
|
+
}), n.addEventListener("load", () => {
|
|
1428
|
+
r();
|
|
1369
1429
|
}), () => {
|
|
1370
|
-
|
|
1430
|
+
i.disable();
|
|
1371
1431
|
};
|
|
1372
1432
|
}
|
|
1373
1433
|
return null;
|
|
1374
1434
|
}
|
|
1375
|
-
class
|
|
1435
|
+
class _t {
|
|
1376
1436
|
_didWarnAboutMissingUrl = !1;
|
|
1377
|
-
onBeforeUpdateLOD(t, e, s,
|
|
1378
|
-
this.tryParseMeshLOD(e,
|
|
1437
|
+
onBeforeUpdateLOD(t, e, s, r) {
|
|
1438
|
+
this.tryParseMeshLOD(e, r), this.tryParseTextureLOD(e, r);
|
|
1379
1439
|
}
|
|
1380
1440
|
getUrl(t) {
|
|
1381
1441
|
if (!t)
|
|
@@ -1390,101 +1450,101 @@ class xt {
|
|
|
1390
1450
|
return t.element;
|
|
1391
1451
|
}
|
|
1392
1452
|
tryParseTextureLOD(t, e) {
|
|
1393
|
-
if (e[
|
|
1394
|
-
e[
|
|
1395
|
-
const s = this.tryGetCurrentGLTF(t),
|
|
1396
|
-
if (
|
|
1397
|
-
let
|
|
1398
|
-
if (a[
|
|
1399
|
-
a[
|
|
1453
|
+
if (e[ie] == !0) return;
|
|
1454
|
+
e[ie] = !0;
|
|
1455
|
+
const s = this.tryGetCurrentGLTF(t), r = this.tryGetCurrentModelViewer(t), i = this.getUrl(r);
|
|
1456
|
+
if (i && s && e.material) {
|
|
1457
|
+
let o = function(a) {
|
|
1458
|
+
if (a[ie] == !0) return;
|
|
1459
|
+
a[ie] = !0, a.userData && (a.userData.LOD = -1);
|
|
1400
1460
|
const u = Object.keys(a);
|
|
1401
|
-
for (let
|
|
1402
|
-
const y = u[
|
|
1461
|
+
for (let c = 0; c < u.length; c++) {
|
|
1462
|
+
const y = u[c], w = a[y];
|
|
1403
1463
|
if (w?.isTexture === !0) {
|
|
1404
1464
|
const _ = w.userData?.associations?.textures;
|
|
1405
1465
|
if (_ == null) continue;
|
|
1406
|
-
const
|
|
1407
|
-
if (!
|
|
1466
|
+
const k = s.parser.json.textures[_];
|
|
1467
|
+
if (!k) {
|
|
1408
1468
|
console.warn("Texture data not found for texture index " + _);
|
|
1409
1469
|
continue;
|
|
1410
1470
|
}
|
|
1411
|
-
if (
|
|
1412
|
-
const M =
|
|
1413
|
-
M &&
|
|
1471
|
+
if (k?.extensions?.[W]) {
|
|
1472
|
+
const M = k.extensions[W];
|
|
1473
|
+
M && i && m.registerTexture(i, w, M.lods.length, _, M);
|
|
1414
1474
|
}
|
|
1415
1475
|
}
|
|
1416
1476
|
}
|
|
1417
1477
|
};
|
|
1418
1478
|
const l = e.material;
|
|
1419
|
-
if (Array.isArray(l)) for (const a of l)
|
|
1420
|
-
else
|
|
1479
|
+
if (Array.isArray(l)) for (const a of l) o(a);
|
|
1480
|
+
else o(l);
|
|
1421
1481
|
}
|
|
1422
1482
|
}
|
|
1423
1483
|
tryParseMeshLOD(t, e) {
|
|
1424
|
-
if (e[
|
|
1425
|
-
e[
|
|
1426
|
-
const s = this.tryGetCurrentModelViewer(t),
|
|
1427
|
-
if (!
|
|
1484
|
+
if (e[be] == !0) return;
|
|
1485
|
+
e[be] = !0;
|
|
1486
|
+
const s = this.tryGetCurrentModelViewer(t), r = this.getUrl(s);
|
|
1487
|
+
if (!r)
|
|
1428
1488
|
return;
|
|
1429
|
-
const
|
|
1430
|
-
if (
|
|
1431
|
-
const
|
|
1432
|
-
m.registerMesh(
|
|
1489
|
+
const i = e.userData?.gltfExtensions?.[W];
|
|
1490
|
+
if (i && r) {
|
|
1491
|
+
const o = e.uuid;
|
|
1492
|
+
m.registerMesh(r, o, e, 0, i.lods.length, i);
|
|
1433
1493
|
}
|
|
1434
1494
|
}
|
|
1435
1495
|
}
|
|
1436
|
-
function
|
|
1437
|
-
let t, e, s,
|
|
1438
|
-
switch (
|
|
1496
|
+
function Lt(...n) {
|
|
1497
|
+
let t, e, s, r;
|
|
1498
|
+
switch (n.length) {
|
|
1439
1499
|
case 2:
|
|
1440
|
-
[s, e] =
|
|
1500
|
+
[s, e] = n, r = {};
|
|
1441
1501
|
break;
|
|
1442
1502
|
case 3:
|
|
1443
|
-
[s, e,
|
|
1503
|
+
[s, e, r] = n;
|
|
1444
1504
|
break;
|
|
1445
1505
|
case 4:
|
|
1446
|
-
[t, e, s,
|
|
1506
|
+
[t, e, s, r] = n;
|
|
1447
1507
|
break;
|
|
1448
1508
|
default:
|
|
1449
1509
|
throw new Error("Invalid arguments");
|
|
1450
1510
|
}
|
|
1451
|
-
|
|
1511
|
+
we(e), Pe(s), Ce(s, {
|
|
1452
1512
|
progressive: !0,
|
|
1453
|
-
...
|
|
1454
|
-
}), s.register((
|
|
1455
|
-
const
|
|
1456
|
-
return
|
|
1513
|
+
...r?.hints
|
|
1514
|
+
}), s.register((o) => new m(o));
|
|
1515
|
+
const i = v.get(e);
|
|
1516
|
+
return r?.enableLODsManager !== !1 && i.enable(), i;
|
|
1457
1517
|
}
|
|
1458
|
-
|
|
1459
|
-
if (!
|
|
1460
|
-
const
|
|
1518
|
+
Re();
|
|
1519
|
+
if (!nt) {
|
|
1520
|
+
const n = {
|
|
1461
1521
|
gltfProgressive: {
|
|
1462
|
-
useNeedleProgressive:
|
|
1522
|
+
useNeedleProgressive: Lt,
|
|
1463
1523
|
LODsManager: v,
|
|
1464
|
-
configureLoader:
|
|
1465
|
-
getRaycastMesh:
|
|
1466
|
-
useRaycastMeshes:
|
|
1524
|
+
configureLoader: Ce,
|
|
1525
|
+
getRaycastMesh: ee,
|
|
1526
|
+
useRaycastMeshes: lt
|
|
1467
1527
|
}
|
|
1468
1528
|
};
|
|
1469
1529
|
if (!globalThis.Needle)
|
|
1470
|
-
globalThis.Needle =
|
|
1530
|
+
globalThis.Needle = n;
|
|
1471
1531
|
else
|
|
1472
|
-
for (const t in
|
|
1473
|
-
globalThis.Needle[t] =
|
|
1532
|
+
for (const t in n)
|
|
1533
|
+
globalThis.Needle[t] = n[t];
|
|
1474
1534
|
}
|
|
1475
1535
|
export {
|
|
1476
1536
|
W as EXTENSION_NAME,
|
|
1477
1537
|
v as LODsManager,
|
|
1478
1538
|
m as NEEDLE_progressive,
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1539
|
+
Ke as VERSION,
|
|
1540
|
+
Pe as addDracoAndKTX2Loaders,
|
|
1541
|
+
Ce as configureLoader,
|
|
1542
|
+
we as createLoaders,
|
|
1543
|
+
ee as getRaycastMesh,
|
|
1544
|
+
Re as patchModelViewer,
|
|
1545
|
+
at as registerRaycastMesh,
|
|
1546
|
+
Je as setDracoDecoderLocation,
|
|
1547
|
+
Ze as setKTX2TranscoderLocation,
|
|
1548
|
+
Lt as useNeedleProgressive,
|
|
1549
|
+
lt as useRaycastMeshes
|
|
1490
1550
|
};
|