@needle-tools/gltf-progressive 3.5.0-rc → 3.6.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -1
- package/LICENSE +21 -0
- package/gltf-progressive.js +896 -636
- package/gltf-progressive.min.js +9 -9
- package/gltf-progressive.umd.cjs +9 -9
- package/lib/extension.d.ts +65 -6
- package/lib/extension.js +278 -110
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/lods.debug.js +1 -1
- package/lib/lods.manager.d.ts +90 -15
- package/lib/lods.manager.js +282 -150
- package/lib/lods.promise.js +1 -1
- package/lib/plugins/modelviewer.js +1 -1
- package/lib/version.js +1 -1
- package/package.json +4 -2
package/gltf-progressive.js
CHANGED
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
import { BufferGeometry as
|
|
2
|
-
import { GLTFLoader as
|
|
3
|
-
import { MeshoptDecoder as
|
|
4
|
-
import { DRACOLoader as
|
|
5
|
-
import { KTX2Loader as
|
|
6
|
-
const
|
|
7
|
-
globalThis.GLTF_PROGRESSIVE_VERSION =
|
|
1
|
+
import { BufferGeometry as j, Mesh as K, Box3 as le, Vector3 as k, Sphere as Se, CompressedTexture as ze, Texture as G, Matrix3 as Ee, InterleavedBuffer as Ne, InterleavedBufferAttribute as Ve, BufferAttribute as Xe, TextureLoader as je, Color as Ce, Matrix4 as Pe, Clock as Ke } from "three";
|
|
2
|
+
import { GLTFLoader as we } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
3
|
+
import { MeshoptDecoder as Ye } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
4
|
+
import { DRACOLoader as He } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
5
|
+
import { KTX2Loader as Qe } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
6
|
+
const Je = "";
|
|
7
|
+
globalThis.GLTF_PROGRESSIVE_VERSION = Je;
|
|
8
8
|
console.debug("[gltf-progressive] version -");
|
|
9
|
-
let I = "https://www.gstatic.com/draco/versioned/decoders/1.5.7/",
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
fetch(
|
|
9
|
+
let I = "https://www.gstatic.com/draco/versioned/decoders/1.5.7/", Y = "https://cdn.needle.tools/static/three/0.179.1/basis2/";
|
|
10
|
+
const Ze = I, et = Y, ke = new URL(I + "draco_decoder.js");
|
|
11
|
+
ke.searchParams.append("range", "true");
|
|
12
|
+
fetch(ke, {
|
|
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 ${I} (offline: ${typeof navigator < "u" ? navigator.onLine : "unknown"})`), I ===
|
|
17
|
+
}).catch((i) => {
|
|
18
|
+
console.debug(`Failed to fetch remote Draco decoder from ${I} (offline: ${typeof navigator < "u" ? navigator.onLine : "unknown"})`), I === Ze && st("./include/draco/"), Y === et && rt("./include/ktx2/");
|
|
19
19
|
}).finally(() => {
|
|
20
|
-
|
|
20
|
+
Re();
|
|
21
21
|
});
|
|
22
|
-
const
|
|
22
|
+
const tt = () => ({
|
|
23
23
|
dracoDecoderPath: I,
|
|
24
|
-
ktx2TranscoderPath:
|
|
24
|
+
ktx2TranscoderPath: Y
|
|
25
25
|
});
|
|
26
|
-
function
|
|
27
|
-
I =
|
|
26
|
+
function st(i) {
|
|
27
|
+
I = i, P && P[me] != I ? (console.debug("Updating Draco decoder path to " + i), P[me] = I, P.setDecoderPath(I), P.preload()) : console.debug("Setting Draco decoder path to " + i);
|
|
28
28
|
}
|
|
29
|
-
function
|
|
30
|
-
|
|
29
|
+
function rt(i) {
|
|
30
|
+
Y = i, $ && $.transcoderPath != Y ? (console.debug("Updating KTX2 transcoder path to " + i), $.setTranscoderPath(Y), $.init()) : console.debug("Setting KTX2 transcoder path to " + i);
|
|
31
31
|
}
|
|
32
|
-
function
|
|
33
|
-
return
|
|
32
|
+
function Le(i) {
|
|
33
|
+
return Re(), i ? $.detectSupport(i) : i !== null && console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"), { dracoLoader: P, ktx2Loader: $, meshoptDecoder: ae };
|
|
34
34
|
}
|
|
35
|
-
function
|
|
36
|
-
|
|
35
|
+
function Ae(i) {
|
|
36
|
+
i.dracoLoader || i.setDRACOLoader(P), i.ktx2Loader || i.setKTX2Loader($), i.meshoptDecoder || i.setMeshoptDecoder(ae);
|
|
37
37
|
}
|
|
38
|
-
const
|
|
39
|
-
let
|
|
40
|
-
function
|
|
41
|
-
|
|
38
|
+
const me = /* @__PURE__ */ Symbol("dracoDecoderPath");
|
|
39
|
+
let P, ae, $;
|
|
40
|
+
function Re() {
|
|
41
|
+
P || (P = new He(), P[me] = I, P.setDecoderPath(I), P.setDecoderConfig({ type: "js" }), P.preload()), $ || ($ = new Qe(), $.setTranscoderPath(Y), $.init()), ae || (ae = Ye);
|
|
42
42
|
}
|
|
43
|
-
const
|
|
44
|
-
function
|
|
45
|
-
let e =
|
|
46
|
-
e ? e = Object.assign(e, t) : e = t,
|
|
43
|
+
const ye = /* @__PURE__ */ new WeakMap();
|
|
44
|
+
function Ie(i, t) {
|
|
45
|
+
let e = ye.get(i);
|
|
46
|
+
e ? e = Object.assign(e, t) : e = t, ye.set(i, e);
|
|
47
47
|
}
|
|
48
|
-
const
|
|
49
|
-
function
|
|
50
|
-
const t =
|
|
51
|
-
let e =
|
|
48
|
+
const nt = we.prototype.load;
|
|
49
|
+
function ot(...i) {
|
|
50
|
+
const t = ye.get(this);
|
|
51
|
+
let e = i[0];
|
|
52
52
|
const s = new URL(e, window.location.href);
|
|
53
53
|
if (s.hostname.endsWith("needle.tools")) {
|
|
54
|
-
const
|
|
55
|
-
|
|
54
|
+
const n = t?.progressive !== void 0 ? t.progressive : !0, o = t?.usecase ? t.usecase : "default";
|
|
55
|
+
n ? this.requestHeader.Accept = `*/*;progressive=allowed;usecase=${o}` : this.requestHeader.Accept = `*/*;usecase=${o}`, e = s.toString();
|
|
56
56
|
}
|
|
57
|
-
return
|
|
57
|
+
return i[0] = e, nt?.call(this, ...i);
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
function
|
|
59
|
+
we.prototype.load = ot;
|
|
60
|
+
N("debugprogressive");
|
|
61
|
+
function N(i) {
|
|
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(i);
|
|
64
64
|
return e == null || e === "0" || e === "false" ? !1 : e === "" ? !0 : e;
|
|
65
65
|
}
|
|
66
|
-
function
|
|
67
|
-
if (t === void 0 ||
|
|
66
|
+
function it(i, t) {
|
|
67
|
+
if (t === void 0 || i === void 0 || t.startsWith("./") || t.startsWith("http") || t.startsWith("data:") || t.startsWith("blob:"))
|
|
68
68
|
return t;
|
|
69
|
-
const e =
|
|
69
|
+
const e = i.lastIndexOf("/");
|
|
70
70
|
if (e >= 0) {
|
|
71
|
-
const s =
|
|
71
|
+
const s = i.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
|
-
function
|
|
78
|
-
return
|
|
77
|
+
function ve() {
|
|
78
|
+
return Z !== void 0 || (Z = /iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent), N("debugprogressive") && console.log("[glTF Progressive]: isMobileDevice", Z)), Z;
|
|
79
79
|
}
|
|
80
|
-
let
|
|
81
|
-
function
|
|
80
|
+
let Z;
|
|
81
|
+
function $e() {
|
|
82
82
|
if (typeof window > "u") return !1;
|
|
83
|
-
const
|
|
84
|
-
return
|
|
83
|
+
const i = new URL(window.location.href), t = i.hostname === "localhost" || /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(i.hostname);
|
|
84
|
+
return i.hostname === "127.0.0.1" || t;
|
|
85
85
|
}
|
|
86
|
-
class
|
|
86
|
+
class at {
|
|
87
87
|
constructor(t, e = {}) {
|
|
88
88
|
this.maxConcurrent = t, this.debug = e.debug ?? !1, typeof window < "u" && window.requestAnimationFrame(this.tick);
|
|
89
89
|
}
|
|
@@ -112,96 +112,97 @@ class rt {
|
|
|
112
112
|
this.debug && console.debug(`[PromiseQueue]: Running ${this._running.size} promises, waiting for ${this._queue.length} more.`);
|
|
113
113
|
const { key: s, resolve: r } = this._queue.shift();
|
|
114
114
|
r({
|
|
115
|
-
use: (
|
|
115
|
+
use: (n) => this.add(s, n)
|
|
116
116
|
});
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
|
-
function
|
|
121
|
-
const t =
|
|
122
|
-
return t * e * s *
|
|
120
|
+
function lt(i) {
|
|
121
|
+
const t = i.image?.width ?? 0, e = i.image?.height ?? 0, s = i.image?.depth ?? 1, r = Math.floor(Math.log2(Math.max(t, e, s))) + 1, n = ut(i);
|
|
122
|
+
return t * e * s * n * (1 - Math.pow(0.25, r)) / (1 - 0.25);
|
|
123
123
|
}
|
|
124
|
-
function
|
|
124
|
+
function ut(i) {
|
|
125
125
|
let t = 4;
|
|
126
|
-
const e =
|
|
126
|
+
const e = i.format;
|
|
127
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
128
|
let s = 1;
|
|
129
|
-
const r =
|
|
129
|
+
const r = i.type;
|
|
130
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
131
|
}
|
|
132
|
-
const
|
|
133
|
-
function
|
|
134
|
-
return
|
|
132
|
+
const ct = typeof window > "u" && typeof document > "u", xe = /* @__PURE__ */ Symbol("needle:raycast-mesh");
|
|
133
|
+
function ne(i) {
|
|
134
|
+
return i?.[xe] instanceof j ? i[xe] : null;
|
|
135
135
|
}
|
|
136
|
-
function
|
|
137
|
-
if ((
|
|
138
|
-
const s =
|
|
139
|
-
s.userData = { isRaycastMesh: !0 },
|
|
136
|
+
function dt(i, t) {
|
|
137
|
+
if ((i.type === "Mesh" || i.type === "SkinnedMesh") && !ne(i)) {
|
|
138
|
+
const s = ht(t);
|
|
139
|
+
s.userData = { isRaycastMesh: !0 }, i[xe] = s;
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
-
function
|
|
143
|
-
if (
|
|
144
|
-
if (
|
|
145
|
-
const t =
|
|
146
|
-
|
|
147
|
-
const r = this,
|
|
142
|
+
function ft(i = !0) {
|
|
143
|
+
if (i) {
|
|
144
|
+
if (ee) return;
|
|
145
|
+
const t = ee = K.prototype.raycast;
|
|
146
|
+
K.prototype.raycast = function(e, s) {
|
|
147
|
+
const r = this, n = ne(r);
|
|
148
148
|
let o;
|
|
149
|
-
|
|
149
|
+
n && r.isMesh && (o = r.geometry, r.geometry = n), t.call(this, e, s), o && (r.geometry = o);
|
|
150
150
|
};
|
|
151
151
|
} else {
|
|
152
|
-
if (!
|
|
153
|
-
|
|
152
|
+
if (!ee) return;
|
|
153
|
+
K.prototype.raycast = ee, ee = null;
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
|
-
let
|
|
157
|
-
function
|
|
158
|
-
const t = new
|
|
159
|
-
for (const e in
|
|
160
|
-
t.setAttribute(e,
|
|
161
|
-
return t.setIndex(
|
|
156
|
+
let ee = null;
|
|
157
|
+
function ht(i) {
|
|
158
|
+
const t = new j();
|
|
159
|
+
for (const e in i.attributes)
|
|
160
|
+
t.setAttribute(e, i.getAttribute(e));
|
|
161
|
+
return t.setIndex(i.getIndex()), t;
|
|
162
162
|
}
|
|
163
|
-
const
|
|
164
|
-
let
|
|
163
|
+
const E = new Array(), f = N("debugprogressive");
|
|
164
|
+
let re, X = -1;
|
|
165
165
|
if (f) {
|
|
166
|
-
let
|
|
167
|
-
|
|
168
|
-
}
|
|
166
|
+
let i = function() {
|
|
167
|
+
X += 1, X >= t && (X = -1), console.log(`Toggle LOD level [${X}]`);
|
|
168
|
+
};
|
|
169
|
+
const t = 6;
|
|
169
170
|
window.addEventListener("keyup", (e) => {
|
|
170
|
-
e.key === "p" &&
|
|
171
|
+
e.key === "p" && i(), e.key === "w" && (re = !re, console.log(`Toggle wireframe [${re}]`));
|
|
171
172
|
const s = parseInt(e.key);
|
|
172
|
-
!isNaN(s) && s >= 0 && (
|
|
173
|
+
!isNaN(s) && s >= 0 && (X = s, console.log(`Set LOD level to [${X}]`));
|
|
173
174
|
});
|
|
174
175
|
}
|
|
175
|
-
function
|
|
176
|
-
if (f &&
|
|
177
|
-
if (Array.isArray(
|
|
178
|
-
for (const t of
|
|
179
|
-
|
|
180
|
-
else
|
|
176
|
+
function Be(i) {
|
|
177
|
+
if (f && re !== void 0)
|
|
178
|
+
if (Array.isArray(i))
|
|
179
|
+
for (const t of i)
|
|
180
|
+
Be(t);
|
|
181
|
+
else i && "wireframe" in i && (i.wireframe = re === !0);
|
|
181
182
|
}
|
|
182
|
-
const
|
|
183
|
-
let
|
|
184
|
-
const
|
|
185
|
-
function
|
|
186
|
-
if (
|
|
187
|
-
const s =
|
|
183
|
+
const te = new Array();
|
|
184
|
+
let gt = 0;
|
|
185
|
+
const pt = ve() ? 2 : 10;
|
|
186
|
+
function mt(i) {
|
|
187
|
+
if (te.length < pt) {
|
|
188
|
+
const s = te.length;
|
|
188
189
|
f && console.warn(`[Worker] Creating new worker #${s}`);
|
|
189
|
-
const r =
|
|
190
|
-
return
|
|
190
|
+
const r = _e.createWorker(i || {});
|
|
191
|
+
return te.push(r), r;
|
|
191
192
|
}
|
|
192
|
-
const t =
|
|
193
|
-
return
|
|
193
|
+
const t = gt++ % te.length;
|
|
194
|
+
return te[t];
|
|
194
195
|
}
|
|
195
|
-
class
|
|
196
|
+
class _e {
|
|
196
197
|
constructor(t, e) {
|
|
197
198
|
this.worker = t, this._debug = e.debug ?? !1, t.onmessage = (s) => {
|
|
198
199
|
const r = s.data;
|
|
199
200
|
switch (this._debug && console.log("[Worker] EVENT", r), r.type) {
|
|
200
201
|
case "loaded-gltf":
|
|
201
|
-
for (const
|
|
202
|
-
if (
|
|
203
|
-
|
|
204
|
-
const o =
|
|
202
|
+
for (const n of this._running)
|
|
203
|
+
if (n.url === r.result.url) {
|
|
204
|
+
yt(r.result), n.resolve(r.result);
|
|
205
|
+
const o = n.url;
|
|
205
206
|
o.startsWith("blob:") && URL.revokeObjectURL(o);
|
|
206
207
|
}
|
|
207
208
|
}
|
|
@@ -219,61 +220,61 @@ class Le {
|
|
|
219
220
|
), {
|
|
220
221
|
type: "module"
|
|
221
222
|
});
|
|
222
|
-
return new
|
|
223
|
+
return new _e(e, t);
|
|
223
224
|
}
|
|
224
225
|
_running = [];
|
|
225
226
|
_webglRenderer = null;
|
|
226
227
|
async load(t, e) {
|
|
227
|
-
const s =
|
|
228
|
+
const s = tt();
|
|
228
229
|
let r = e?.renderer;
|
|
229
230
|
r || (this._webglRenderer ??= (async () => {
|
|
230
|
-
const { WebGLRenderer:
|
|
231
|
-
return new
|
|
231
|
+
const { WebGLRenderer: l } = await import("three");
|
|
232
|
+
return new l();
|
|
232
233
|
})(), r = await this._webglRenderer);
|
|
233
|
-
const
|
|
234
|
+
const u = Le(r).ktx2Loader.workerConfig;
|
|
234
235
|
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());
|
|
235
236
|
const a = {
|
|
236
237
|
type: "load",
|
|
237
238
|
url: t,
|
|
238
239
|
dracoDecoderPath: s.dracoDecoderPath,
|
|
239
240
|
ktx2TranscoderPath: s.ktx2TranscoderPath,
|
|
240
|
-
ktx2LoaderConfig:
|
|
241
|
+
ktx2LoaderConfig: u
|
|
241
242
|
};
|
|
242
|
-
return this._debug && console.debug("[Worker] Sending load request", a), this.worker.postMessage(a), new Promise((
|
|
243
|
+
return this._debug && console.debug("[Worker] Sending load request", a), this.worker.postMessage(a), new Promise((l) => {
|
|
243
244
|
this._running.push({
|
|
244
245
|
url: t.toString(),
|
|
245
|
-
resolve:
|
|
246
|
+
resolve: l
|
|
246
247
|
});
|
|
247
248
|
});
|
|
248
249
|
}
|
|
249
250
|
_debug = !1;
|
|
250
251
|
}
|
|
251
|
-
function
|
|
252
|
-
for (const t of
|
|
253
|
-
const e = t.geometry, s = new
|
|
252
|
+
function yt(i) {
|
|
253
|
+
for (const t of i.geometries) {
|
|
254
|
+
const e = t.geometry, s = new j();
|
|
254
255
|
if (s.name = e.name || "", e.index) {
|
|
255
256
|
const r = e.index;
|
|
256
|
-
s.setIndex(
|
|
257
|
+
s.setIndex(ce(r));
|
|
257
258
|
}
|
|
258
259
|
for (const r in e.attributes) {
|
|
259
|
-
const
|
|
260
|
+
const n = e.attributes[r], o = ce(n);
|
|
260
261
|
s.setAttribute(r, o);
|
|
261
262
|
}
|
|
262
263
|
if (e.morphAttributes)
|
|
263
264
|
for (const r in e.morphAttributes) {
|
|
264
|
-
const o = e.morphAttributes[r].map((
|
|
265
|
+
const o = e.morphAttributes[r].map((u) => ce(u));
|
|
265
266
|
s.morphAttributes[r] = o;
|
|
266
267
|
}
|
|
267
|
-
if (s.morphTargetsRelative = e.morphTargetsRelative ?? !1, s.boundingBox = new
|
|
268
|
+
if (s.morphTargetsRelative = e.morphTargetsRelative ?? !1, s.boundingBox = new le(), s.boundingBox.min = new k(
|
|
268
269
|
e.boundingBox?.min.x,
|
|
269
270
|
e.boundingBox?.min.y,
|
|
270
271
|
e.boundingBox?.min.z
|
|
271
|
-
), s.boundingBox.max = new
|
|
272
|
+
), s.boundingBox.max = new k(
|
|
272
273
|
e.boundingBox?.max.x,
|
|
273
274
|
e.boundingBox?.max.y,
|
|
274
275
|
e.boundingBox?.max.z
|
|
275
276
|
), s.boundingSphere = new Se(
|
|
276
|
-
new
|
|
277
|
+
new k(
|
|
277
278
|
e.boundingSphere?.center.x,
|
|
278
279
|
e.boundingSphere?.center.y,
|
|
279
280
|
e.boundingSphere?.center.z
|
|
@@ -284,14 +285,14 @@ function ht(n) {
|
|
|
284
285
|
s.addGroup(r.start, r.count, r.materialIndex);
|
|
285
286
|
e.userData && (s.userData = e.userData), t.geometry = s;
|
|
286
287
|
}
|
|
287
|
-
for (const t of
|
|
288
|
+
for (const t of i.textures) {
|
|
288
289
|
const e = t.texture;
|
|
289
290
|
let s = null;
|
|
290
291
|
if (e.isCompressedTexture) {
|
|
291
|
-
const r = e.mipmaps,
|
|
292
|
-
s = new
|
|
292
|
+
const r = e.mipmaps, n = e.image?.width || e.source?.data?.width || -1, o = e.image?.height || e.source?.data?.height || -1;
|
|
293
|
+
s = new ze(
|
|
293
294
|
r,
|
|
294
|
-
|
|
295
|
+
n,
|
|
295
296
|
o,
|
|
296
297
|
e.format,
|
|
297
298
|
e.type,
|
|
@@ -304,7 +305,7 @@ function ht(n) {
|
|
|
304
305
|
e.colorSpace
|
|
305
306
|
);
|
|
306
307
|
} else
|
|
307
|
-
s = new
|
|
308
|
+
s = new G(
|
|
308
309
|
e.image,
|
|
309
310
|
e.mapping,
|
|
310
311
|
e.wrapS,
|
|
@@ -315,75 +316,98 @@ function ht(n) {
|
|
|
315
316
|
e.type,
|
|
316
317
|
e.anisotropy,
|
|
317
318
|
e.colorSpace
|
|
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
|
|
319
|
+
), 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 Ee(...e.matrix.elements);
|
|
319
320
|
if (!s) {
|
|
320
321
|
console.error("[Worker] Failed to create new texture from received data. Texture is not a CompressedTexture or Texture.");
|
|
321
322
|
continue;
|
|
322
323
|
}
|
|
323
324
|
t.texture = s;
|
|
324
325
|
}
|
|
325
|
-
return
|
|
326
|
+
return i;
|
|
326
327
|
}
|
|
327
|
-
function
|
|
328
|
-
let t =
|
|
329
|
-
if ("isInterleavedBufferAttribute" in
|
|
330
|
-
const e =
|
|
331
|
-
t = new
|
|
332
|
-
} else "isBufferAttribute" in
|
|
328
|
+
function ce(i) {
|
|
329
|
+
let t = i;
|
|
330
|
+
if ("isInterleavedBufferAttribute" in i && i.isInterleavedBufferAttribute) {
|
|
331
|
+
const e = i.data, s = e.array, r = new Ne(s, e.stride);
|
|
332
|
+
t = new Ve(r, i.itemSize, s.byteOffset, i.normalized), t.offset = i.offset;
|
|
333
|
+
} else "isBufferAttribute" in i && i.isBufferAttribute && (t = new Xe(i.array, i.itemSize, i.normalized), t.usage = i.usage, t.gpuType = i.gpuType, t.updateRanges = i.updateRanges);
|
|
333
334
|
return t;
|
|
334
335
|
}
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
const
|
|
338
|
-
class
|
|
336
|
+
const xt = N("gltf-progressive-worker");
|
|
337
|
+
N("gltf-progressive-reduce-mipmaps");
|
|
338
|
+
const se = N("gltf-progressive-gc"), de = /* @__PURE__ */ Symbol("needle-progressive-texture"), F = "NEEDLE_progressive";
|
|
339
|
+
class h {
|
|
339
340
|
/** The name of the extension */
|
|
340
341
|
get name() {
|
|
341
|
-
return
|
|
342
|
+
return F;
|
|
342
343
|
}
|
|
343
344
|
// #region PUBLIC API
|
|
345
|
+
/**
|
|
346
|
+
* Get the progressive mesh LOD extension data associated with a geometry.
|
|
347
|
+
* Returns the extension metadata (available LOD levels, vertex/index counts, densities) if the geometry was registered with progressive LODs, or `null` otherwise.
|
|
348
|
+
*
|
|
349
|
+
* @param geo - The buffer geometry to look up.
|
|
350
|
+
* @returns The mesh LOD extension data, or `null` if no progressive LODs are registered for this geometry.
|
|
351
|
+
*/
|
|
344
352
|
static getMeshLODExtension(t) {
|
|
345
353
|
const e = this.getAssignedLODInformation(t);
|
|
346
354
|
return e?.key ? this.lodInfos.get(e.key) : null;
|
|
347
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* Get the glTF primitive index for a geometry within its parent mesh.
|
|
358
|
+
* A single glTF mesh node can contain multiple primitives (sub-geometries). This returns which primitive the geometry corresponds to.
|
|
359
|
+
*
|
|
360
|
+
* @param geo - The buffer geometry to look up.
|
|
361
|
+
* @returns The zero-based primitive index, or `-1` if no LOD information is assigned to this geometry.
|
|
362
|
+
*/
|
|
348
363
|
static getPrimitiveIndex(t) {
|
|
349
364
|
const e = this.getAssignedLODInformation(t)?.index;
|
|
350
365
|
return e ?? -1;
|
|
351
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* Compute the minimum and maximum number of texture LOD levels across all textures of a material (or array of materials).
|
|
369
|
+
* Iterates over all texture slots on the material and collects LOD count ranges and per-level resolution bounds.
|
|
370
|
+
* Results are cached on the material so subsequent calls are free.
|
|
371
|
+
*
|
|
372
|
+
* @param material - A single material or an array of materials to inspect.
|
|
373
|
+
* @param minmax - Optional accumulator to merge results into (used internally for recursive calls with material arrays).
|
|
374
|
+
* @returns An object with `min_count` / `max_count` (the range of LOD levels across all textures) and a per-level `lods` array with `min_height` / `max_height`.
|
|
375
|
+
*/
|
|
352
376
|
static getMaterialMinMaxLODsCount(t, e) {
|
|
353
|
-
const s = this, r = "LODS:minmax",
|
|
354
|
-
if (
|
|
377
|
+
const s = this, r = "LODS:minmax", n = t[r];
|
|
378
|
+
if (n != null) return n;
|
|
355
379
|
if (e || (e = {
|
|
356
380
|
min_count: 1 / 0,
|
|
357
381
|
max_count: 0,
|
|
358
382
|
lods: []
|
|
359
383
|
}), Array.isArray(t)) {
|
|
360
|
-
for (const
|
|
361
|
-
this.getMaterialMinMaxLODsCount(
|
|
384
|
+
for (const u of t)
|
|
385
|
+
this.getMaterialMinMaxLODsCount(u, e);
|
|
362
386
|
return t[r] = e, e;
|
|
363
387
|
}
|
|
364
388
|
if (f === "verbose" && console.log("getMaterialMinMaxLODsCount", t), t.type === "ShaderMaterial" || t.type === "RawShaderMaterial") {
|
|
365
|
-
const
|
|
366
|
-
for (const a of Object.keys(
|
|
367
|
-
const
|
|
368
|
-
|
|
389
|
+
const u = t;
|
|
390
|
+
for (const a of Object.keys(u.uniforms)) {
|
|
391
|
+
const l = u.uniforms[a].value;
|
|
392
|
+
l?.isTexture === !0 && o(l, e);
|
|
369
393
|
}
|
|
370
394
|
} else if (t.isMaterial)
|
|
371
|
-
for (const
|
|
372
|
-
const a = t[
|
|
395
|
+
for (const u of Object.keys(t)) {
|
|
396
|
+
const a = t[u];
|
|
373
397
|
a?.isTexture === !0 && o(a, e);
|
|
374
398
|
}
|
|
375
399
|
else
|
|
376
400
|
f && console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);
|
|
377
401
|
return t[r] = e, e;
|
|
378
|
-
function o(
|
|
379
|
-
const
|
|
380
|
-
if (
|
|
381
|
-
const c = s.lodInfos.get(
|
|
402
|
+
function o(u, a) {
|
|
403
|
+
const l = s.getAssignedLODInformation(u);
|
|
404
|
+
if (l) {
|
|
405
|
+
const c = s.lodInfos.get(l.key);
|
|
382
406
|
if (c && c.lods) {
|
|
383
407
|
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
|
|
385
|
-
const
|
|
386
|
-
|
|
408
|
+
for (let d = 0; d < c.lods.length; d++) {
|
|
409
|
+
const g = c.lods[d];
|
|
410
|
+
g.width && (a.lods[d] = a.lods[d] || { min_height: 1 / 0, max_height: 0 }, a.lods[d].min_height = Math.min(a.lods[d].min_height, g.height), a.lods[d].max_height = Math.max(a.lods[d].max_height, g.height));
|
|
387
411
|
}
|
|
388
412
|
}
|
|
389
413
|
}
|
|
@@ -396,26 +420,26 @@ class m {
|
|
|
396
420
|
*/
|
|
397
421
|
static hasLODLevelAvailable(t, e) {
|
|
398
422
|
if (Array.isArray(t)) {
|
|
399
|
-
for (const
|
|
400
|
-
if (this.hasLODLevelAvailable(
|
|
423
|
+
for (const n of t)
|
|
424
|
+
if (this.hasLODLevelAvailable(n, e)) return !0;
|
|
401
425
|
return !1;
|
|
402
426
|
}
|
|
403
427
|
if (t.isMaterial === !0) {
|
|
404
|
-
for (const
|
|
405
|
-
const o = t[
|
|
428
|
+
for (const n of Object.keys(t)) {
|
|
429
|
+
const o = t[n];
|
|
406
430
|
if (o && o.isTexture && this.hasLODLevelAvailable(o, e))
|
|
407
431
|
return !0;
|
|
408
432
|
}
|
|
409
433
|
return !1;
|
|
410
434
|
} else if (t.isGroup === !0) {
|
|
411
|
-
for (const
|
|
412
|
-
if (
|
|
435
|
+
for (const n of t.children)
|
|
436
|
+
if (n.isMesh === !0 && this.hasLODLevelAvailable(n, e))
|
|
413
437
|
return !0;
|
|
414
438
|
}
|
|
415
439
|
let s, r;
|
|
416
440
|
if (t.isMesh ? s = t.geometry : (t.isBufferGeometry || t.isTexture) && (s = t), s && s?.userData?.LODS) {
|
|
417
|
-
const
|
|
418
|
-
if (r = this.lodInfos.get(
|
|
441
|
+
const n = s.userData.LODS;
|
|
442
|
+
if (r = this.lodInfos.get(n.key), e === void 0) return r != null;
|
|
419
443
|
if (r)
|
|
420
444
|
return Array.isArray(r.lods) ? e < r.lods.length : e === 0;
|
|
421
445
|
}
|
|
@@ -435,74 +459,75 @@ class m {
|
|
|
435
459
|
* });
|
|
436
460
|
* ```
|
|
437
461
|
*/
|
|
438
|
-
static assignMeshLOD(t, e) {
|
|
462
|
+
static assignMeshLOD(t, e, s) {
|
|
439
463
|
if (!t) return Promise.resolve(null);
|
|
440
|
-
if (t instanceof
|
|
441
|
-
const
|
|
442
|
-
if (!
|
|
464
|
+
if (t instanceof K || t.isMesh === !0) {
|
|
465
|
+
const r = t.geometry, n = this.getAssignedLODInformation(r);
|
|
466
|
+
if (!n)
|
|
443
467
|
return Promise.resolve(null);
|
|
444
|
-
for (const
|
|
445
|
-
|
|
446
|
-
return t["LOD:requested level"] = e,
|
|
447
|
-
if (Array.isArray(
|
|
448
|
-
const
|
|
449
|
-
|
|
468
|
+
for (const o of E)
|
|
469
|
+
o.onBeforeGetLODMesh?.(t, e);
|
|
470
|
+
return t["LOD:requested level"] = e, h.getOrLoadLOD(r, e).then((o) => {
|
|
471
|
+
if (Array.isArray(o)) {
|
|
472
|
+
const u = n.index || 0;
|
|
473
|
+
o = o[u];
|
|
450
474
|
}
|
|
451
|
-
return t["LOD:requested level"] === e && (delete t["LOD:requested level"],
|
|
452
|
-
}).catch((
|
|
475
|
+
return t["LOD:requested level"] === e && (delete t["LOD:requested level"], o && r != o && (o?.isBufferGeometry ? typeof s?.apply == "function" ? s.apply(o, e, t) : s?.apply !== !1 && (t.geometry = o) : f && console.error("Invalid LOD geometry", o))), o;
|
|
476
|
+
}).catch((o) => (console.error("Error loading mesh LOD", t, o), null));
|
|
453
477
|
} else f && console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh", t);
|
|
454
478
|
return Promise.resolve(null);
|
|
455
479
|
}
|
|
456
|
-
static assignTextureLOD(t, e = 0) {
|
|
480
|
+
static assignTextureLOD(t, e = 0, s) {
|
|
457
481
|
if (!t) return Promise.resolve(null);
|
|
482
|
+
const r = s?.force === !0;
|
|
458
483
|
if (t.isMesh === !0) {
|
|
459
|
-
const
|
|
460
|
-
if (Array.isArray(
|
|
461
|
-
const
|
|
462
|
-
for (const
|
|
463
|
-
const
|
|
464
|
-
|
|
484
|
+
const n = t;
|
|
485
|
+
if (Array.isArray(n.material)) {
|
|
486
|
+
const o = new Array();
|
|
487
|
+
for (const u of n.material) {
|
|
488
|
+
const a = this.assignTextureLOD(u, e, s);
|
|
489
|
+
o.push(a);
|
|
465
490
|
}
|
|
466
|
-
return Promise.all(
|
|
467
|
-
const
|
|
468
|
-
for (const l of
|
|
469
|
-
Array.isArray(l) &&
|
|
470
|
-
return
|
|
491
|
+
return Promise.all(o).then((u) => {
|
|
492
|
+
const a = new Array();
|
|
493
|
+
for (const l of u)
|
|
494
|
+
Array.isArray(l) && a.push(...l);
|
|
495
|
+
return a;
|
|
471
496
|
});
|
|
472
497
|
} else
|
|
473
|
-
return this.assignTextureLOD(
|
|
498
|
+
return this.assignTextureLOD(n.material, e, s);
|
|
474
499
|
}
|
|
475
500
|
if (t.isMaterial === !0) {
|
|
476
|
-
const
|
|
477
|
-
if (
|
|
478
|
-
const
|
|
479
|
-
for (const l of Object.keys(
|
|
480
|
-
const
|
|
481
|
-
if (
|
|
482
|
-
const
|
|
483
|
-
|
|
501
|
+
const n = t, o = [], u = new Array();
|
|
502
|
+
if (this.trackCurrentMaterialTextureSlots(n), n.uniforms && (n.isRawShaderMaterial || n.isShaderMaterial === !0)) {
|
|
503
|
+
const a = n;
|
|
504
|
+
for (const l of Object.keys(a.uniforms)) {
|
|
505
|
+
const c = a.uniforms[l].value;
|
|
506
|
+
if (c?.isTexture === !0) {
|
|
507
|
+
const d = this.assignTextureLODForSlot(c, e, n, l, r).then((g) => (g && a.uniforms[l].value != g && (a.uniforms[l].value = g, a.uniformsNeedUpdate = !0), g));
|
|
508
|
+
o.push(d), u.push(l);
|
|
484
509
|
}
|
|
485
510
|
}
|
|
486
511
|
} else
|
|
487
|
-
for (const
|
|
488
|
-
const l =
|
|
512
|
+
for (const a of Object.keys(n)) {
|
|
513
|
+
const l = n[a];
|
|
489
514
|
if (l?.isTexture === !0) {
|
|
490
|
-
const
|
|
491
|
-
|
|
515
|
+
const c = this.assignTextureLODForSlot(l, e, n, a, r);
|
|
516
|
+
o.push(c), u.push(a);
|
|
492
517
|
}
|
|
493
518
|
}
|
|
494
|
-
return Promise.all(
|
|
519
|
+
return Promise.all(o).then((a) => {
|
|
495
520
|
const l = new Array();
|
|
496
|
-
for (let
|
|
497
|
-
const
|
|
498
|
-
|
|
521
|
+
for (let c = 0; c < a.length; c++) {
|
|
522
|
+
const d = a[c], g = u[c];
|
|
523
|
+
d && d.isTexture === !0 ? l.push({ material: n, slot: g, texture: d, level: e }) : l.push({ material: n, slot: g, texture: null, level: e });
|
|
499
524
|
}
|
|
500
525
|
return l;
|
|
501
526
|
});
|
|
502
527
|
}
|
|
503
|
-
if (t instanceof
|
|
504
|
-
const
|
|
505
|
-
return this.assignTextureLODForSlot(
|
|
528
|
+
if (t instanceof G || t.isTexture === !0) {
|
|
529
|
+
const n = t;
|
|
530
|
+
return this.assignTextureLODForSlot(n, e, null, null, r);
|
|
506
531
|
}
|
|
507
532
|
return Promise.resolve(null);
|
|
508
533
|
}
|
|
@@ -511,34 +536,107 @@ class m {
|
|
|
511
536
|
* @default 50 on desktop, 20 on mobile devices
|
|
512
537
|
*/
|
|
513
538
|
static set maxConcurrentLoadingTasks(t) {
|
|
514
|
-
|
|
539
|
+
h.queue.maxConcurrent = t;
|
|
515
540
|
}
|
|
516
541
|
static get maxConcurrentLoadingTasks() {
|
|
517
|
-
return
|
|
542
|
+
return h.queue.maxConcurrent;
|
|
518
543
|
}
|
|
519
544
|
// #region INTERNAL
|
|
520
|
-
static assignTextureLODForSlot(t, e, s, r) {
|
|
521
|
-
|
|
522
|
-
|
|
545
|
+
static assignTextureLODForSlot(t, e, s, r, n) {
|
|
546
|
+
if (t?.isTexture !== !0)
|
|
547
|
+
return Promise.resolve(null);
|
|
548
|
+
if (r === "glyphMap")
|
|
549
|
+
return Promise.resolve(t);
|
|
550
|
+
const o = this.getAssignedLODInformation(t);
|
|
551
|
+
if (o && (o.level === e || !n && o.level < e))
|
|
552
|
+
return Promise.resolve(t);
|
|
553
|
+
if (s && r) {
|
|
554
|
+
const a = this.getPendingTextureSlotRequest(s, r);
|
|
555
|
+
if (a && a.level === e && a.force === n)
|
|
556
|
+
return a.promise;
|
|
557
|
+
}
|
|
558
|
+
const u = h.getOrLoadLOD(t, e).then((a) => {
|
|
559
|
+
if (Array.isArray(a))
|
|
523
560
|
return console.warn("Progressive: Got an array of textures for a texture slot, this should not happen..."), null;
|
|
524
|
-
if (
|
|
525
|
-
if (
|
|
526
|
-
const
|
|
527
|
-
if (
|
|
528
|
-
const
|
|
529
|
-
if (
|
|
530
|
-
return f === "verbose" && console.warn("Assigned texture level is already higher: ",
|
|
561
|
+
if (a?.isTexture === !0) {
|
|
562
|
+
if (a != t && s && r) {
|
|
563
|
+
const l = this.getMaterialTextureSlot(s, r) ?? t;
|
|
564
|
+
if (l && !n) {
|
|
565
|
+
const c = this.getAssignedLODInformation(l);
|
|
566
|
+
if (c && c?.level < e)
|
|
567
|
+
return f === "verbose" && console.warn("Assigned texture level is already higher: ", c.level, e, s, l, a), null;
|
|
531
568
|
}
|
|
532
|
-
|
|
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);
|
|
535
|
-
}
|
|
536
|
-
s[r] = i;
|
|
569
|
+
this.assignTrackedTextureSlot(s, r, a);
|
|
537
570
|
}
|
|
538
|
-
return
|
|
571
|
+
return a;
|
|
539
572
|
} else f == "verbose" && console.warn("No LOD found for", t, e);
|
|
540
573
|
return null;
|
|
541
|
-
}).catch((
|
|
574
|
+
}).catch((a) => (console.error("Error loading LOD", t, a), null));
|
|
575
|
+
return s && r && this.setPendingTextureSlotRequest(s, r, e, n, u), u;
|
|
576
|
+
}
|
|
577
|
+
// Track material slots, not just texture objects. A shared fallback texture can be
|
|
578
|
+
// referenced by many slots and should only be disposed after every slot moved away.
|
|
579
|
+
static trackedTextureSlots = /* @__PURE__ */ new WeakMap();
|
|
580
|
+
static pendingTextureSlotRequests = /* @__PURE__ */ new WeakMap();
|
|
581
|
+
static trackCurrentMaterialTextureSlots(t) {
|
|
582
|
+
if (t.uniforms && (t.isRawShaderMaterial || t.isShaderMaterial === !0)) {
|
|
583
|
+
const e = t;
|
|
584
|
+
for (const s of Object.keys(e.uniforms)) {
|
|
585
|
+
const r = e.uniforms[s].value;
|
|
586
|
+
r?.isTexture === !0 && this.ensureTrackedTextureSlot(t, s, r);
|
|
587
|
+
}
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
for (const e of Object.keys(t)) {
|
|
591
|
+
const s = t[e];
|
|
592
|
+
s?.isTexture === !0 && this.ensureTrackedTextureSlot(t, e, s);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
static getPendingTextureSlotRequest(t, e) {
|
|
596
|
+
return this.pendingTextureSlotRequests.get(t)?.get(e);
|
|
597
|
+
}
|
|
598
|
+
static setPendingTextureSlotRequest(t, e, s, r, n) {
|
|
599
|
+
let o = this.pendingTextureSlotRequests.get(t);
|
|
600
|
+
o || (o = /* @__PURE__ */ new Map(), this.pendingTextureSlotRequests.set(t, o));
|
|
601
|
+
const u = { level: s, force: r, promise: n };
|
|
602
|
+
o.set(e, u), n.finally(() => {
|
|
603
|
+
o.get(e) === u && o.delete(e);
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
static getMaterialTextureSlot(t, e) {
|
|
607
|
+
const r = t.uniforms?.[e];
|
|
608
|
+
if (r?.value?.isTexture === !0)
|
|
609
|
+
return r.value;
|
|
610
|
+
const n = t[e];
|
|
611
|
+
return n?.isTexture === !0 ? n : null;
|
|
612
|
+
}
|
|
613
|
+
static setMaterialTextureSlot(t, e, s) {
|
|
614
|
+
const n = t.uniforms?.[e];
|
|
615
|
+
if (n?.value?.isTexture === !0) {
|
|
616
|
+
n.value = s, t.uniformsNeedUpdate = !0;
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
t[e] = s;
|
|
620
|
+
}
|
|
621
|
+
static assignTrackedTextureSlot(t, e, s) {
|
|
622
|
+
let r = this.trackedTextureSlots.get(t);
|
|
623
|
+
r || (r = /* @__PURE__ */ new Map(), this.trackedTextureSlots.set(t, r));
|
|
624
|
+
const n = this.getMaterialTextureSlot(t, e);
|
|
625
|
+
let o = r.get(e);
|
|
626
|
+
!o && n ? o = this.ensureTrackedTextureSlot(t, e, n) : o && n && o !== n && (this.releaseTrackedTextureSlot(t, e, o), o = this.ensureTrackedTextureSlot(t, e, n)), !(o === s && n === s) && (o && o !== s && this.releaseTrackedTextureSlot(t, e, o), o !== s && (this.trackTextureUsage(s), r.set(e, s)), n !== s && this.setMaterialTextureSlot(t, e, s));
|
|
627
|
+
}
|
|
628
|
+
static ensureTrackedTextureSlot(t, e, s) {
|
|
629
|
+
let r = this.trackedTextureSlots.get(t);
|
|
630
|
+
r || (r = /* @__PURE__ */ new Map(), this.trackedTextureSlots.set(t, r));
|
|
631
|
+
const n = r.get(e);
|
|
632
|
+
return n === s ? n : (n && this.releaseTrackedTextureSlot(t, e, n), this.trackTextureUsage(s), r.set(e, s), s);
|
|
633
|
+
}
|
|
634
|
+
static releaseTrackedTextureSlot(t, e, s) {
|
|
635
|
+
const r = this.trackedTextureSlots.get(t);
|
|
636
|
+
if (r?.get(e) === s && r.delete(e), this.untrackTextureUsage(s) && (f || se)) {
|
|
637
|
+
const o = this.getAssignedLODInformation(s);
|
|
638
|
+
console.log(`[gltf-progressive] Disposed old texture LOD ${o?.level ?? "?"} for ${t.name || t.type}.${e}`, s.uuid);
|
|
639
|
+
}
|
|
542
640
|
}
|
|
543
641
|
parser;
|
|
544
642
|
url;
|
|
@@ -549,8 +647,8 @@ class m {
|
|
|
549
647
|
_isLoadingMesh;
|
|
550
648
|
loadMesh = (t) => {
|
|
551
649
|
if (this._isLoadingMesh) return null;
|
|
552
|
-
const e = this.parser.json.meshes[t]?.extensions?.[
|
|
553
|
-
return e ? (this._isLoadingMesh = !0, this.parser.getDependency("mesh", t).then((s) => (this._isLoadingMesh = !1, s &&
|
|
650
|
+
const e = this.parser.json.meshes[t]?.extensions?.[F];
|
|
651
|
+
return e ? (this._isLoadingMesh = !0, this.parser.getDependency("mesh", t).then((s) => (this._isLoadingMesh = !1, s && h.registerMesh(this.url, e.guid, s, e.lods?.length, 0, e), s))) : null;
|
|
554
652
|
};
|
|
555
653
|
// private _isLoadingTexture;
|
|
556
654
|
// loadTexture = (textureIndex: number) => {
|
|
@@ -569,62 +667,80 @@ class m {
|
|
|
569
667
|
afterRoot(t) {
|
|
570
668
|
return f && console.log("AFTER", this.url, t), this.parser.json.textures?.forEach((e, s) => {
|
|
571
669
|
if (e?.extensions) {
|
|
572
|
-
const r = e?.extensions[
|
|
670
|
+
const r = e?.extensions[F];
|
|
573
671
|
if (r) {
|
|
574
672
|
if (!r.lods) {
|
|
575
673
|
f && console.warn("Texture has no LODs", r);
|
|
576
674
|
return;
|
|
577
675
|
}
|
|
578
|
-
let
|
|
676
|
+
let n = !1;
|
|
579
677
|
for (const o of this.parser.associations.keys())
|
|
580
|
-
o.isTexture === !0 && this.parser.associations.get(o)?.textures === s && (
|
|
581
|
-
|
|
582
|
-
o &&
|
|
678
|
+
o.isTexture === !0 && this.parser.associations.get(o)?.textures === s && (n = !0, h.registerTexture(this.url, o, r.lods?.length, s, r));
|
|
679
|
+
n || this.parser.getDependency("texture", s).then((o) => {
|
|
680
|
+
o && h.registerTexture(this.url, o, r.lods?.length, s, r);
|
|
583
681
|
});
|
|
584
682
|
}
|
|
585
683
|
}
|
|
586
684
|
}), this.parser.json.meshes?.forEach((e, s) => {
|
|
587
685
|
if (e?.extensions) {
|
|
588
|
-
const r = e?.extensions[
|
|
686
|
+
const r = e?.extensions[F];
|
|
589
687
|
if (r && r.lods) {
|
|
590
|
-
for (const
|
|
591
|
-
if (
|
|
592
|
-
const o = this.parser.associations.get(
|
|
593
|
-
o?.meshes === s &&
|
|
688
|
+
for (const n of this.parser.associations.keys())
|
|
689
|
+
if (n.isMesh) {
|
|
690
|
+
const o = this.parser.associations.get(n);
|
|
691
|
+
o?.meshes === s && h.registerMesh(this.url, r.guid, n, r.lods.length, o.primitives, r);
|
|
594
692
|
}
|
|
595
693
|
}
|
|
596
694
|
}
|
|
597
695
|
}), null;
|
|
598
696
|
}
|
|
599
697
|
/**
|
|
600
|
-
* Register a texture with LOD information
|
|
698
|
+
* Register a texture with progressive LOD information. This associates the texture with its LOD extension data
|
|
699
|
+
* so the LODs manager can later swap it for higher or lower resolution versions based on screen coverage.
|
|
700
|
+
* Typically called during glTF loading when the progressive extension is parsed.
|
|
701
|
+
*
|
|
702
|
+
* @param url - The source URL of the glTF file this texture was loaded from.
|
|
703
|
+
* @param tex - The three.js Texture instance to register.
|
|
704
|
+
* @param level - The LOD level this texture represents (0 = highest resolution).
|
|
705
|
+
* @param index - The texture index within the glTF file.
|
|
706
|
+
* @param ext - The parsed progressive texture extension data containing all available LOD levels and their dimensions.
|
|
601
707
|
*/
|
|
602
|
-
static registerTexture = (t, e, s, r,
|
|
708
|
+
static registerTexture = (t, e, s, r, n) => {
|
|
603
709
|
if (!e) {
|
|
604
710
|
f && console.error("!! gltf-progressive: Called register texture without texture");
|
|
605
711
|
return;
|
|
606
712
|
}
|
|
607
713
|
if (f) {
|
|
608
|
-
const
|
|
609
|
-
console.log(`> gltf-progressive: register texture[${r}] "${e.name || e.uuid}", Current: ${
|
|
714
|
+
const u = e.image?.width || e.source?.data?.width || 0, a = e.image?.height || e.source?.data?.height || 0;
|
|
715
|
+
console.log(`> gltf-progressive: register texture[${r}] "${e.name || e.uuid}", Current: ${u}x${a}, Max: ${n.lods[0]?.width}x${n.lods[0]?.height}, uuid: ${e.uuid}`, n, e);
|
|
610
716
|
}
|
|
611
|
-
e.source && (e.source[
|
|
612
|
-
const o =
|
|
613
|
-
|
|
717
|
+
e.source && (e.source[de] = n);
|
|
718
|
+
const o = n.guid;
|
|
719
|
+
h.assignLODInformation(t, e, o, s, r), h.lodInfos.set(o, n), h.lowresCache.set(o, new WeakRef(e));
|
|
614
720
|
};
|
|
615
721
|
/**
|
|
616
|
-
* Register a mesh with LOD information
|
|
722
|
+
* Register a mesh with progressive LOD information. This associates the mesh geometry with its LOD extension data
|
|
723
|
+
* so the LODs manager can later swap it for higher or lower density versions based on screen coverage.
|
|
724
|
+
* Typically called during glTF loading when the progressive extension is parsed.
|
|
725
|
+
* If the mesh is registered at a level > 0 (i.e. not full resolution), a raycast mesh is automatically preserved for accurate picking.
|
|
726
|
+
*
|
|
727
|
+
* @param url - The source URL of the glTF file this mesh was loaded from.
|
|
728
|
+
* @param key - A unique key identifying this mesh's LOD group (typically derived from the extension GUID).
|
|
729
|
+
* @param mesh - The three.js Mesh instance to register.
|
|
730
|
+
* @param level - The LOD level this mesh represents (0 = highest resolution / full density).
|
|
731
|
+
* @param index - The primitive index within the glTF mesh node.
|
|
732
|
+
* @param ext - The parsed progressive mesh extension data containing all available LOD levels with vertex/index counts and densities.
|
|
617
733
|
*/
|
|
618
|
-
static registerMesh = (t, e, s, r,
|
|
619
|
-
const
|
|
620
|
-
if (!
|
|
734
|
+
static registerMesh = (t, e, s, r, n, o) => {
|
|
735
|
+
const u = s.geometry;
|
|
736
|
+
if (!u) {
|
|
621
737
|
f && console.warn("gltf-progressive: Register mesh without geometry");
|
|
622
738
|
return;
|
|
623
739
|
}
|
|
624
|
-
|
|
625
|
-
let
|
|
626
|
-
|
|
627
|
-
for (const c of
|
|
740
|
+
u.userData || (u.userData = {}), f && console.log("> Progressive: register mesh " + s.name, { index: n, uuid: s.uuid }, o, s), h.assignLODInformation(t, u, e, r, n), h.lodInfos.set(e, o);
|
|
741
|
+
let l = h.lowresCache.get(e)?.deref();
|
|
742
|
+
l ? l.push(s.geometry) : l = [s.geometry], h.lowresCache.set(e, new WeakRef(l)), r > 0 && !ne(s) && dt(s, u);
|
|
743
|
+
for (const c of E)
|
|
628
744
|
c.onRegisteredNewMesh?.(s, o);
|
|
629
745
|
};
|
|
630
746
|
/**
|
|
@@ -666,7 +782,7 @@ class m {
|
|
|
666
782
|
this.lowresCache.clear();
|
|
667
783
|
for (const [, e] of this.cache)
|
|
668
784
|
this._disposeCacheEntry(e);
|
|
669
|
-
this.cache.clear(), this.textureRefCounts.clear();
|
|
785
|
+
this.cache.clear(), this.textureRefCounts.clear(), this.trackedTextureSlots = /* @__PURE__ */ new WeakMap(), this.pendingTextureSlotRequests = /* @__PURE__ */ new WeakMap();
|
|
670
786
|
}
|
|
671
787
|
}
|
|
672
788
|
/** Dispose a single cache entry's three.js resource(s) to free GPU memory. */
|
|
@@ -698,9 +814,9 @@ class m {
|
|
|
698
814
|
* The held value is the cache key string used in `previouslyLoaded`.
|
|
699
815
|
*/
|
|
700
816
|
static _resourceRegistry = new FinalizationRegistry((t) => {
|
|
701
|
-
const e =
|
|
702
|
-
(f ||
|
|
703
|
-
${t}`), e instanceof WeakRef && (e.deref() || (
|
|
817
|
+
const e = h.cache.get(t);
|
|
818
|
+
(f || se) && console.debug(`[gltf-progressive] Memory: Resource GC'd
|
|
819
|
+
${t}`), e instanceof WeakRef && (e.deref() || (h.cache.delete(t), (f || se) && console.log("[gltf-progressive] ↪ Cache entry deleted (GC)")));
|
|
704
820
|
});
|
|
705
821
|
/**
|
|
706
822
|
* Track texture usage by incrementing reference count
|
|
@@ -717,16 +833,15 @@ ${t}`), e instanceof WeakRef && (e.deref() || (m.cache.delete(t), (f || K) && co
|
|
|
717
833
|
static untrackTextureUsage(t) {
|
|
718
834
|
const e = t.uuid, s = this.textureRefCounts.get(e);
|
|
719
835
|
if (!s)
|
|
720
|
-
return (f === "verbose" ||
|
|
836
|
+
return (f === "verbose" || se) && n("[gltf-progressive] Memory: Untrack untracked texture (dispose immediately)", 0), t.dispose(), !0;
|
|
721
837
|
const r = s - 1;
|
|
722
838
|
if (r <= 0)
|
|
723
|
-
return this.textureRefCounts.delete(e), (f ||
|
|
724
|
-
return this.textureRefCounts.set(e, r), f === "verbose" &&
|
|
725
|
-
function
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
a && u && (y = `~${(it(t) / (1024 * 1024)).toFixed(2)} MB`), console.log(`${o} — ${t.name} ${c} (${y}), refCount: ${s} → ${l}
|
|
839
|
+
return this.textureRefCounts.delete(e), (f || se) && n("[gltf-progressive] Memory: Dispose texture", r), t.dispose(), !0;
|
|
840
|
+
return this.textureRefCounts.set(e, r), f === "verbose" && n("[gltf-progressive] Memory: Untrack texture", r), !1;
|
|
841
|
+
function n(o, u) {
|
|
842
|
+
const a = t.image?.width || t.source?.data?.width || 0, l = t.image?.height || t.source?.data?.height || 0, c = a && l ? `${a}x${l}` : "N/A";
|
|
843
|
+
let d = "N/A";
|
|
844
|
+
a && l && (d = `~${(lt(t) / (1024 * 1024)).toFixed(2)} MB`), console.log(`${o} — ${t.name} ${c} (${d}), refCount: ${s} → ${u}
|
|
730
845
|
${e}`);
|
|
731
846
|
}
|
|
732
847
|
}
|
|
@@ -736,24 +851,24 @@ ${e}`);
|
|
|
736
851
|
const s = f == "verbose", r = this.getAssignedLODInformation(t);
|
|
737
852
|
if (!r)
|
|
738
853
|
return f && console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`, t), null;
|
|
739
|
-
const
|
|
854
|
+
const n = r?.key;
|
|
740
855
|
let o;
|
|
741
856
|
if (t.isTexture === !0) {
|
|
742
857
|
const a = t;
|
|
743
|
-
a.source && a.source[
|
|
858
|
+
a.source && a.source[de] && (o = a.source[de]);
|
|
744
859
|
}
|
|
745
|
-
if (o || (o =
|
|
746
|
-
f && console.warn(`Can not load LOD ${e}: no LOD info found for "${
|
|
860
|
+
if (o || (o = h.lodInfos.get(n)), !o)
|
|
861
|
+
f && console.warn(`Can not load LOD ${e}: no LOD info found for "${n}" ${t.name}`, t.type, h.lodInfos);
|
|
747
862
|
else {
|
|
748
863
|
if (e > 0) {
|
|
749
864
|
let c = !1;
|
|
750
|
-
const
|
|
751
|
-
if (
|
|
752
|
-
const
|
|
753
|
-
if (
|
|
754
|
-
const
|
|
755
|
-
if (
|
|
756
|
-
this.lowresCache.delete(
|
|
865
|
+
const d = Array.isArray(o.lods);
|
|
866
|
+
if (d && e >= o.lods.length ? c = !0 : d || (c = !0), c) {
|
|
867
|
+
const g = this.lowresCache.get(n);
|
|
868
|
+
if (g) {
|
|
869
|
+
const m = g.deref();
|
|
870
|
+
if (m) return m;
|
|
871
|
+
this.lowresCache.delete(n), f && console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${n}`);
|
|
757
872
|
}
|
|
758
873
|
return null;
|
|
759
874
|
}
|
|
@@ -761,128 +876,132 @@ ${e}`);
|
|
|
761
876
|
const a = Array.isArray(o.lods) ? o.lods[e]?.path : o.lods;
|
|
762
877
|
if (!a)
|
|
763
878
|
return f && !o["missing:uri"] && (o["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + e, o)), null;
|
|
764
|
-
const
|
|
765
|
-
if (
|
|
879
|
+
const l = it(r.url, a);
|
|
880
|
+
if (l.endsWith(".glb") || l.endsWith(".gltf")) {
|
|
766
881
|
if (!o.guid)
|
|
767
882
|
return console.warn("missing pointer for glb/gltf texture", o), null;
|
|
768
|
-
const c =
|
|
769
|
-
if (
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
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;
|
|
783
|
-
}
|
|
784
|
-
if (!y.use)
|
|
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);
|
|
789
|
-
if (x.textures.length > 0)
|
|
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);
|
|
883
|
+
const c = l + "_" + o.guid, d = await this.tryResolveLODCacheEntry(this.cache.get(c), c, l, t, e, s);
|
|
884
|
+
if (d.found) return d.value;
|
|
885
|
+
const g = await this.queue.slot(l), m = await this.tryResolveLODCacheEntry(this.cache.get(c), c, l, t, e, s);
|
|
886
|
+
if (m.found) return m.value;
|
|
887
|
+
if (!g.use)
|
|
888
|
+
return f && console.log(`LOD ${e} was aborted: ${l}`), null;
|
|
889
|
+
const x = o, v = new Promise(async (_, C) => {
|
|
890
|
+
if (xt) {
|
|
891
|
+
const y = await (await mt({})).load(l);
|
|
892
|
+
if (y.textures.length > 0)
|
|
893
|
+
for (const M of y.textures) {
|
|
894
|
+
let b = M.texture;
|
|
895
|
+
return h.assignLODInformation(r.url, b, n, e, void 0), t instanceof G && (b = this.copySettings(t, b)), b && (b.guid = x.guid), _(b);
|
|
793
896
|
}
|
|
794
|
-
if (
|
|
795
|
-
const
|
|
796
|
-
for (const
|
|
797
|
-
const
|
|
798
|
-
|
|
897
|
+
if (y.geometries.length > 0) {
|
|
898
|
+
const M = new Array();
|
|
899
|
+
for (const b of y.geometries) {
|
|
900
|
+
const B = b.geometry;
|
|
901
|
+
h.assignLODInformation(r.url, B, n, e, b.primitiveIndex), M.push(B);
|
|
799
902
|
}
|
|
800
|
-
return
|
|
903
|
+
return _(M);
|
|
801
904
|
}
|
|
802
|
-
return
|
|
905
|
+
return _(null);
|
|
803
906
|
}
|
|
804
|
-
const
|
|
805
|
-
|
|
806
|
-
let
|
|
807
|
-
if (
|
|
808
|
-
const
|
|
809
|
-
|
|
907
|
+
const W = new we();
|
|
908
|
+
Ae(W), f && (await new Promise((D) => setTimeout(D, 1e3)), s && console.warn("Start loading (delayed) " + l, x.guid));
|
|
909
|
+
let L = l;
|
|
910
|
+
if (x && Array.isArray(x.lods)) {
|
|
911
|
+
const D = x.lods[e];
|
|
912
|
+
D.hash && (L += "?v=" + D.hash);
|
|
810
913
|
}
|
|
811
|
-
const
|
|
812
|
-
`,
|
|
813
|
-
if (!
|
|
814
|
-
return
|
|
815
|
-
const
|
|
816
|
-
s && console.log("Loading finished " +
|
|
817
|
-
let
|
|
818
|
-
if (
|
|
819
|
-
let
|
|
820
|
-
for (const
|
|
821
|
-
if (
|
|
822
|
-
const
|
|
823
|
-
if (
|
|
824
|
-
|
|
914
|
+
const w = await W.loadAsync(L).catch((D) => (console.error(`Error loading LOD ${e} from ${l}
|
|
915
|
+
`, D), _(null)));
|
|
916
|
+
if (!w)
|
|
917
|
+
return _(null);
|
|
918
|
+
const S = w.parser;
|
|
919
|
+
s && console.log("Loading finished " + l, x.guid);
|
|
920
|
+
let O = 0;
|
|
921
|
+
if (w.parser.json.textures) {
|
|
922
|
+
let D = !1;
|
|
923
|
+
for (const y of w.parser.json.textures) {
|
|
924
|
+
if (y?.extensions) {
|
|
925
|
+
const M = y?.extensions[F];
|
|
926
|
+
if (M?.guid && M.guid === x.guid) {
|
|
927
|
+
D = !0;
|
|
825
928
|
break;
|
|
826
929
|
}
|
|
827
930
|
}
|
|
828
|
-
|
|
931
|
+
O++;
|
|
829
932
|
}
|
|
830
|
-
if (
|
|
831
|
-
let
|
|
832
|
-
return
|
|
833
|
-
} else f && console.warn("Could not find texture with guid",
|
|
933
|
+
if (D) {
|
|
934
|
+
let y = await S.getDependency("texture", O);
|
|
935
|
+
return y && h.assignLODInformation(r.url, y, n, e, void 0), s && console.log('change "' + t.name + '" → "' + y.name + '"', l, O, y, c), t instanceof G && (y = this.copySettings(t, y)), y && (y.guid = x.guid), _(y);
|
|
936
|
+
} else f && console.warn("Could not find texture with guid", x.guid, w.parser.json);
|
|
834
937
|
}
|
|
835
|
-
if (
|
|
836
|
-
let
|
|
837
|
-
for (const
|
|
838
|
-
if (
|
|
839
|
-
const
|
|
840
|
-
if (
|
|
841
|
-
|
|
938
|
+
if (O = 0, w.parser.json.meshes) {
|
|
939
|
+
let D = !1;
|
|
940
|
+
for (const y of w.parser.json.meshes) {
|
|
941
|
+
if (y?.extensions) {
|
|
942
|
+
const M = y?.extensions[F];
|
|
943
|
+
if (M?.guid && M.guid === x.guid) {
|
|
944
|
+
D = !0;
|
|
842
945
|
break;
|
|
843
946
|
}
|
|
844
947
|
}
|
|
845
|
-
|
|
948
|
+
O++;
|
|
846
949
|
}
|
|
847
|
-
if (
|
|
848
|
-
const
|
|
849
|
-
if (s && console.log(`Loaded Mesh "${
|
|
850
|
-
const
|
|
851
|
-
return
|
|
950
|
+
if (D) {
|
|
951
|
+
const y = await S.getDependency("mesh", O);
|
|
952
|
+
if (s && console.log(`Loaded Mesh "${y.name}"`, l, O, y, c), y.isMesh === !0) {
|
|
953
|
+
const M = y.geometry;
|
|
954
|
+
return h.assignLODInformation(r.url, M, n, e, 0), _(M);
|
|
852
955
|
} else {
|
|
853
|
-
const
|
|
854
|
-
for (let
|
|
855
|
-
const
|
|
856
|
-
if (
|
|
857
|
-
const
|
|
858
|
-
|
|
956
|
+
const M = new Array();
|
|
957
|
+
for (let b = 0; b < y.children.length; b++) {
|
|
958
|
+
const B = y.children[b];
|
|
959
|
+
if (B.isMesh === !0) {
|
|
960
|
+
const V = B.geometry;
|
|
961
|
+
h.assignLODInformation(r.url, V, n, e, b), M.push(V);
|
|
859
962
|
}
|
|
860
963
|
}
|
|
861
|
-
return
|
|
964
|
+
return _(M);
|
|
862
965
|
}
|
|
863
|
-
} else f && console.warn("Could not find mesh with guid",
|
|
966
|
+
} else f && console.warn("Could not find mesh with guid", x.guid, w.parser.json);
|
|
864
967
|
}
|
|
865
|
-
return
|
|
968
|
+
return _(null);
|
|
866
969
|
});
|
|
867
|
-
this.cache.set(c,
|
|
868
|
-
const
|
|
869
|
-
return
|
|
870
|
-
} else if (t instanceof
|
|
871
|
-
s && console.log("Load texture from uri: " +
|
|
872
|
-
const
|
|
873
|
-
return
|
|
970
|
+
this.cache.set(c, v), g.use(v);
|
|
971
|
+
const p = await v;
|
|
972
|
+
return p != null ? p instanceof G ? (this.cache.set(c, new WeakRef(p)), h._resourceRegistry.register(p, c)) : Array.isArray(p) ? this.cache.set(c, Promise.resolve(p)) : this.cache.set(c, Promise.resolve(p)) : this.cache.set(c, Promise.resolve(null)), p;
|
|
973
|
+
} else if (t instanceof G) {
|
|
974
|
+
s && console.log("Load texture from uri: " + l);
|
|
975
|
+
const d = await new je().loadAsync(l);
|
|
976
|
+
return d ? (d.guid = o.guid, d.flipY = !1, d.needsUpdate = !0, d.colorSpace = t.colorSpace, s && console.log(o, d)) : f && console.warn("failed loading", l), d;
|
|
874
977
|
}
|
|
875
978
|
}
|
|
876
979
|
return null;
|
|
877
980
|
}
|
|
981
|
+
static async tryResolveLODCacheEntry(t, e, s, r, n, o) {
|
|
982
|
+
if (t === void 0)
|
|
983
|
+
return { found: !1 };
|
|
984
|
+
if (o && console.log(`LOD ${n} was already loading/loaded: ${e}`), t instanceof WeakRef) {
|
|
985
|
+
const l = t.deref();
|
|
986
|
+
if (l) {
|
|
987
|
+
let c = l, d = !1;
|
|
988
|
+
if (c instanceof G && r instanceof G ? c.image?.data || c.source?.data ? c = this.copySettings(r, c) : d = !0 : c instanceof j && r instanceof j && (c.attributes.position?.array || (d = !0)), !d)
|
|
989
|
+
return { found: !0, value: c };
|
|
990
|
+
}
|
|
991
|
+
return this.cache.delete(e), f && console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${e}`), { found: !1 };
|
|
992
|
+
}
|
|
993
|
+
let u = await t.catch((l) => (console.error(`Error loading LOD ${n} from ${s}
|
|
994
|
+
`, l), null)), a = !1;
|
|
995
|
+
return u == null || (u instanceof G && r instanceof G ? u.image?.data || u.source?.data ? u = this.copySettings(r, u) : (a = !0, this.cache.delete(e)) : u instanceof j && r instanceof j && (u.attributes.position?.array || (a = !0, this.cache.delete(e)))), a ? { found: !1 } : { found: !0, value: u };
|
|
996
|
+
}
|
|
878
997
|
static _queue;
|
|
879
998
|
static get queue() {
|
|
880
|
-
return this._queue ??= new
|
|
999
|
+
return this._queue ??= new at(ve() ? 20 : 50, { debug: f != !1 });
|
|
881
1000
|
}
|
|
882
|
-
static assignLODInformation(t, e, s, r,
|
|
1001
|
+
static assignLODInformation(t, e, s, r, n) {
|
|
883
1002
|
if (!e) return;
|
|
884
1003
|
e.userData || (e.userData = {});
|
|
885
|
-
const o = new
|
|
1004
|
+
const o = new wt(t, s, r, n);
|
|
886
1005
|
e.userData.LODS = o, "source" in e && typeof e.source == "object" && (e.source.LODS = o);
|
|
887
1006
|
}
|
|
888
1007
|
static getAssignedLODInformation(t) {
|
|
@@ -895,7 +1014,7 @@ ${e}`);
|
|
|
895
1014
|
`, 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;
|
|
896
1015
|
}
|
|
897
1016
|
}
|
|
898
|
-
class
|
|
1017
|
+
class wt {
|
|
899
1018
|
url;
|
|
900
1019
|
/** the key to lookup the LOD information */
|
|
901
1020
|
key;
|
|
@@ -906,10 +1025,10 @@ class pt {
|
|
|
906
1025
|
this.url = t, this.key = e, this.level = s, r != null && (this.index = r);
|
|
907
1026
|
}
|
|
908
1027
|
}
|
|
909
|
-
class
|
|
1028
|
+
class oe {
|
|
910
1029
|
static addPromise = (t, e, s, r) => {
|
|
911
|
-
r.forEach((
|
|
912
|
-
|
|
1030
|
+
r.forEach((n) => {
|
|
1031
|
+
n.add(t, e, s);
|
|
913
1032
|
});
|
|
914
1033
|
};
|
|
915
1034
|
ready;
|
|
@@ -940,8 +1059,8 @@ class ce {
|
|
|
940
1059
|
_maxPromisesPerObject = 1;
|
|
941
1060
|
constructor(t, e) {
|
|
942
1061
|
const r = Math.max(e.frames ?? 2, 2);
|
|
943
|
-
this._frame_start = e.waitForFirstCapture ? void 0 : t, this._frames_to_capture = r, this.ready = new Promise((
|
|
944
|
-
this._resolve =
|
|
1062
|
+
this._frame_start = e.waitForFirstCapture ? void 0 : t, this._frames_to_capture = r, this.ready = new Promise((n) => {
|
|
1063
|
+
this._resolve = n;
|
|
945
1064
|
}), this.ready.finally(() => {
|
|
946
1065
|
this._resolved = !0, this._awaiting.length = 0;
|
|
947
1066
|
}), this._signal = e.signal, this._signal?.addEventListener("abort", () => {
|
|
@@ -961,7 +1080,7 @@ class ce {
|
|
|
961
1080
|
if (!(this._frame_start !== void 0 && this._currentFrame > this._frame_start + this._frames_to_capture)) {
|
|
962
1081
|
if (this._maxPromisesPerObject >= 1)
|
|
963
1082
|
if (this._seen.has(e)) {
|
|
964
|
-
|
|
1083
|
+
const r = this._seen.get(e);
|
|
965
1084
|
if (r >= this._maxPromisesPerObject) {
|
|
966
1085
|
f && console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");
|
|
967
1086
|
return;
|
|
@@ -982,22 +1101,112 @@ class ce {
|
|
|
982
1101
|
});
|
|
983
1102
|
}
|
|
984
1103
|
}
|
|
985
|
-
const
|
|
986
|
-
|
|
1104
|
+
const A = N("debugprogressive"), Lt = A === "colors", vt = N("noprogressive"), fe = /* @__PURE__ */ Symbol("Needle:LODSManager"), he = /* @__PURE__ */ Symbol("Needle:LODState"), q = /* @__PURE__ */ Symbol("Needle:CurrentLOD"), T = { mesh_lod: -1, texture_lod: -1 }, _t = new Ce(), Me = [
|
|
1105
|
+
3526751,
|
|
1106
|
+
11065402,
|
|
1107
|
+
15978811,
|
|
1108
|
+
15897394,
|
|
1109
|
+
15749691,
|
|
1110
|
+
11032304,
|
|
1111
|
+
4827122,
|
|
1112
|
+
3332036,
|
|
1113
|
+
16739229,
|
|
1114
|
+
7306743,
|
|
1115
|
+
14053330,
|
|
1116
|
+
3516499,
|
|
1117
|
+
12035359,
|
|
1118
|
+
14703919,
|
|
1119
|
+
3963096,
|
|
1120
|
+
42662,
|
|
1121
|
+
14100029,
|
|
1122
|
+
8344319,
|
|
1123
|
+
4633680,
|
|
1124
|
+
16229681,
|
|
1125
|
+
3120096,
|
|
1126
|
+
12076434,
|
|
1127
|
+
9083434,
|
|
1128
|
+
2060171,
|
|
1129
|
+
15751837,
|
|
1130
|
+
10182117,
|
|
1131
|
+
48121,
|
|
1132
|
+
62932,
|
|
1133
|
+
16704576,
|
|
1134
|
+
15817653,
|
|
1135
|
+
5083278,
|
|
1136
|
+
5592405
|
|
1137
|
+
], ge = new le(), z = new le(), De = new le(), Mt = new k(), Dt = new k(), bt = new Pe(), U = new k(), H = new k(), Q = new k(), J = new k();
|
|
1138
|
+
function Ot(i, t) {
|
|
1139
|
+
const e = i.min, s = i.max, r = (e.x + s.x) * 0.5, n = (e.y + s.y) * 0.5;
|
|
1140
|
+
return U.set(r, n, e.z).applyMatrix4(t).z < 0;
|
|
1141
|
+
}
|
|
1142
|
+
function Tt(i) {
|
|
1143
|
+
const {
|
|
1144
|
+
geometry: t,
|
|
1145
|
+
matrixWorld: e,
|
|
1146
|
+
camera: s,
|
|
1147
|
+
projectionScreenMatrix: r,
|
|
1148
|
+
desiredDensity: n,
|
|
1149
|
+
canvasHeight: o = 0,
|
|
1150
|
+
currentLevel: u = -1,
|
|
1151
|
+
xrEnabled: a = !1,
|
|
1152
|
+
debugDrawLine: l,
|
|
1153
|
+
warnMissingPrimitiveDensities: c = !1
|
|
1154
|
+
} = i, d = h.getMeshLODExtension(t)?.lods, g = h.getPrimitiveIndex(t), m = i.target ?? {
|
|
1155
|
+
level: u,
|
|
1156
|
+
primitiveIndex: g,
|
|
1157
|
+
screenCoverage: 0,
|
|
1158
|
+
screenspaceVolume: new k(),
|
|
1159
|
+
centrality: 1
|
|
1160
|
+
};
|
|
1161
|
+
if (m.level = u, m.primitiveIndex = g, m.screenCoverage = 0, m.screenspaceVolume.set(0, 0, 0), m.centrality = 1, !d?.length) return m;
|
|
1162
|
+
let x = i.boundingBox ?? t.boundingBox;
|
|
1163
|
+
if (x || (t.computeBoundingBox(), x = t.boundingBox), !x) return m;
|
|
1164
|
+
if (ge.copy(x).applyMatrix4(e), s.isPerspectiveCamera && Ot(ge, r))
|
|
1165
|
+
return m.level = 0, m.screenCoverage = 1 / 0, m.screenspaceVolume.set(1 / 0, 1 / 0, 1 / 0), m;
|
|
1166
|
+
if (z.copy(ge).applyMatrix4(r), a && s.isPerspectiveCamera && s.fov > 70) {
|
|
1167
|
+
const L = z.min, w = z.max;
|
|
1168
|
+
let S = L.x, O = L.y, D = w.x, y = w.y;
|
|
1169
|
+
const M = 2, b = 1.5, B = (L.x + w.x) * 0.5, V = (L.y + w.y) * 0.5;
|
|
1170
|
+
S = (S - B) * M + B, O = (O - V) * M + V, D = (D - B) * M + B, y = (y - V) * M + V;
|
|
1171
|
+
const Fe = S < 0 && D > 0 ? 0 : Math.min(Math.abs(L.x), Math.abs(w.x)), qe = O < 0 && y > 0 ? 0 : Math.min(Math.abs(L.y), Math.abs(w.y)), ue = Math.max(Fe, qe);
|
|
1172
|
+
m.centrality = (b - ue) * (b - ue) * (b - ue);
|
|
1173
|
+
}
|
|
1174
|
+
const v = z.getSize(Mt);
|
|
1175
|
+
v.multiplyScalar(0.5), globalThis.screen?.availHeight > 0 && o > 0 && v.multiplyScalar(o / globalThis.screen.availHeight), s.isPerspectiveCamera && (v.x *= s.aspect), De.copy(x).applyMatrix4(e).applyMatrix4(s.matrixWorldInverse);
|
|
1176
|
+
const p = De.getSize(Dt), _ = Math.max(v.x, v.y), C = Math.max(p.x, p.y);
|
|
1177
|
+
_ !== 0 && C !== 0 && (v.z = p.z / C * _);
|
|
1178
|
+
const W = Math.max(v.x, v.y, v.z) * m.centrality;
|
|
1179
|
+
if (m.screenCoverage = W, m.screenspaceVolume.copy(v), W <= 0) return m;
|
|
1180
|
+
if (l) {
|
|
1181
|
+
const L = bt.copy(r);
|
|
1182
|
+
L.invert(), U.copy(z.min), H.copy(z.max), H.x = U.x, Q.copy(z.max), Q.y = U.y, J.copy(z.max);
|
|
1183
|
+
const w = (U.z + J.z) * 0.5;
|
|
1184
|
+
U.z = H.z = Q.z = J.z = w, U.applyMatrix4(L), H.applyMatrix4(L), Q.applyMatrix4(L), J.applyMatrix4(L), l(U, H, 255), l(U, Q, 255), l(H, J, 255), l(Q, J, 255);
|
|
1185
|
+
}
|
|
1186
|
+
for (let L = 0; L < d.length; L++) {
|
|
1187
|
+
const w = d[L], S = w.densities?.[g] || w.density || 1e-5;
|
|
1188
|
+
if (g > 0 && c && $e() && !w.densities && !globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"] && (globalThis["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 / W < n) {
|
|
1189
|
+
m.level = L;
|
|
1190
|
+
break;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
return m;
|
|
1194
|
+
}
|
|
1195
|
+
class R {
|
|
987
1196
|
/**
|
|
988
1197
|
* 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.
|
|
989
1198
|
*/
|
|
990
1199
|
static debugDrawLine;
|
|
991
1200
|
/** @internal */
|
|
992
1201
|
static getObjectLODState(t) {
|
|
993
|
-
return t[
|
|
1202
|
+
return t[he];
|
|
994
1203
|
}
|
|
995
1204
|
static addPlugin(t) {
|
|
996
|
-
|
|
1205
|
+
E.push(t);
|
|
997
1206
|
}
|
|
998
1207
|
static removePlugin(t) {
|
|
999
|
-
const e =
|
|
1000
|
-
e >= 0 &&
|
|
1208
|
+
const e = E.indexOf(t);
|
|
1209
|
+
e >= 0 && E.splice(e, 1);
|
|
1001
1210
|
}
|
|
1002
1211
|
/**
|
|
1003
1212
|
* Gets the LODsManager for the given renderer. If the LODsManager does not exist yet, it will be created.
|
|
@@ -1005,20 +1214,20 @@ class v {
|
|
|
1005
1214
|
* @returns The LODsManager instance.
|
|
1006
1215
|
*/
|
|
1007
1216
|
static get(t, e) {
|
|
1008
|
-
if (t[
|
|
1009
|
-
return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), t[
|
|
1010
|
-
const s = new
|
|
1217
|
+
if (t[fe])
|
|
1218
|
+
return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), t[fe];
|
|
1219
|
+
const s = new R(t, {
|
|
1011
1220
|
engine: "unknown",
|
|
1012
1221
|
...e
|
|
1013
1222
|
});
|
|
1014
|
-
return t[
|
|
1223
|
+
return t[fe] = s, s;
|
|
1015
1224
|
}
|
|
1016
1225
|
renderer;
|
|
1017
1226
|
context;
|
|
1018
|
-
projectionScreenMatrix = new
|
|
1227
|
+
projectionScreenMatrix = new Pe();
|
|
1019
1228
|
/** @deprecated use static `LODsManager.addPlugin()` method. This getter will be removed in later versions */
|
|
1020
1229
|
get plugins() {
|
|
1021
|
-
return
|
|
1230
|
+
return E;
|
|
1022
1231
|
}
|
|
1023
1232
|
/**
|
|
1024
1233
|
* Force override the LOD level for all objects (meshes + textures) rendered in the scene
|
|
@@ -1056,44 +1265,98 @@ class v {
|
|
|
1056
1265
|
_newPromiseGroups = [];
|
|
1057
1266
|
_promiseGroupIds = 0;
|
|
1058
1267
|
/**
|
|
1059
|
-
*
|
|
1268
|
+
* Returns a promise that resolves once all LOD requests initiated during the next render cycles have finished loading.
|
|
1269
|
+
* This is useful for hiding low-resolution placeholders (e.g. with a loading overlay or CSS blur) until high-quality assets are ready.
|
|
1270
|
+
*
|
|
1271
|
+
* By default, the returned promise captures LOD loading requests for 2 frames and resolves when all of them complete.
|
|
1272
|
+
* Use `waitForFirstCapture` if no LOD requests may happen immediately (e.g. after a scene switch).
|
|
1273
|
+
*
|
|
1274
|
+
* @param opts - Optional configuration for how long to capture and what to wait for. See {@link PromiseGroupOptions}.
|
|
1275
|
+
* @returns A promise that resolves with `{ cancelled, awaited_count, resolved_count }` once all captured LOD loads complete (or the signal aborts).
|
|
1276
|
+
*
|
|
1277
|
+
* @example
|
|
1278
|
+
* ```ts
|
|
1279
|
+
* // Wait for initial LODs to finish loading, then remove a blur overlay
|
|
1280
|
+
* const result = await lodsManager.awaitLoading({
|
|
1281
|
+
* frames: 5,
|
|
1282
|
+
* signal: AbortSignal.timeout(10_000),
|
|
1283
|
+
* });
|
|
1284
|
+
* console.log(`Loaded ${result.resolved_count} of ${result.awaited_count} LODs`);
|
|
1285
|
+
* document.querySelector('.blur-overlay')?.remove();
|
|
1286
|
+
* ```
|
|
1287
|
+
*
|
|
1288
|
+
* @example
|
|
1289
|
+
* ```ts
|
|
1290
|
+
* // Wait until at least one LOD starts loading before resolving
|
|
1291
|
+
* await lodsManager.awaitLoading({ waitForFirstCapture: true });
|
|
1292
|
+
* ```
|
|
1060
1293
|
*/
|
|
1061
1294
|
awaitLoading(t) {
|
|
1062
|
-
const e = this._promiseGroupIds++, s = new
|
|
1295
|
+
const e = this._promiseGroupIds++, s = new oe(this.#r, { ...t });
|
|
1063
1296
|
this._newPromiseGroups.push(s);
|
|
1064
1297
|
const r = performance.now();
|
|
1065
1298
|
return s.ready.finally(() => {
|
|
1066
|
-
const
|
|
1067
|
-
|
|
1299
|
+
const n = this._newPromiseGroups.indexOf(s);
|
|
1300
|
+
n >= 0 && (this._newPromiseGroups.splice(n, 1), $e() && performance.measure("LODsManager:awaitLoading", {
|
|
1068
1301
|
start: r,
|
|
1069
1302
|
detail: { id: e, name: t?.name, awaited: s.awaitedCount, resolved: s.resolvedCount }
|
|
1070
1303
|
}));
|
|
1071
1304
|
}), s.ready;
|
|
1072
1305
|
}
|
|
1306
|
+
/** Track LOD work started outside this manager so {@link awaitLoading} waits for it too. */
|
|
1307
|
+
trackLoadingPromise(t, e, s) {
|
|
1308
|
+
return oe.addPromise(t, e, s, this._newPromiseGroups), s;
|
|
1309
|
+
}
|
|
1073
1310
|
_postprocessPromiseGroups() {
|
|
1074
1311
|
if (this._newPromiseGroups.length !== 0)
|
|
1075
1312
|
for (let t = this._newPromiseGroups.length - 1; t >= 0; t--)
|
|
1076
1313
|
this._newPromiseGroups[t].update(this.#r);
|
|
1077
1314
|
}
|
|
1078
1315
|
_lodchangedlisteners = [];
|
|
1316
|
+
/**
|
|
1317
|
+
* Register a listener that is called whenever a mesh or texture LOD level has finished loading and has been applied.
|
|
1318
|
+
* The listener receives the type of asset (`"mesh"` or `"texture"`), the new LOD level, and the affected object.
|
|
1319
|
+
*
|
|
1320
|
+
* @param evt - The event type. Currently only `"changed"` is supported.
|
|
1321
|
+
* @param listener - Callback invoked after a LOD swap completes.
|
|
1322
|
+
* @return A function to unregister the listener.
|
|
1323
|
+
*
|
|
1324
|
+
* @example
|
|
1325
|
+
* ```ts
|
|
1326
|
+
* lodsManager.addEventListener("changed", ({ type, level, object }) => {
|
|
1327
|
+
* console.log(`${type} LOD changed to level ${level}`, object);
|
|
1328
|
+
* });
|
|
1329
|
+
* ```
|
|
1330
|
+
*/
|
|
1079
1331
|
addEventListener(t, e) {
|
|
1080
|
-
t === "changed"
|
|
1332
|
+
return t === "changed" ? (this._lodchangedlisteners.push(e), () => {
|
|
1333
|
+
this.removeEventListener(t, e);
|
|
1334
|
+
}) : () => {
|
|
1335
|
+
};
|
|
1081
1336
|
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Remove a previously registered `"changed"` event listener.
|
|
1339
|
+
* @param evt - The event type (`"changed"`).
|
|
1340
|
+
* @param listener - The listener to remove.
|
|
1341
|
+
* @return `true` if the listener was found and removed, `false` otherwise.
|
|
1342
|
+
*/
|
|
1082
1343
|
removeEventListener(t, e) {
|
|
1344
|
+
let s = !1;
|
|
1083
1345
|
if (t === "changed") {
|
|
1084
|
-
const
|
|
1085
|
-
|
|
1346
|
+
const r = this._lodchangedlisteners.indexOf(e);
|
|
1347
|
+
r >= 0 && (this._lodchangedlisteners.splice(r, 1), s = !0);
|
|
1086
1348
|
}
|
|
1349
|
+
return s;
|
|
1087
1350
|
}
|
|
1088
1351
|
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
1089
1352
|
constructor(t, e) {
|
|
1090
1353
|
this.renderer = t, this.context = { ...e };
|
|
1091
1354
|
}
|
|
1092
1355
|
#t;
|
|
1093
|
-
#o = new
|
|
1356
|
+
#o = new Ke();
|
|
1094
1357
|
#r = 0;
|
|
1095
|
-
#i = 0;
|
|
1096
1358
|
#n = 0;
|
|
1359
|
+
#i = 0;
|
|
1097
1360
|
#s = 0;
|
|
1098
1361
|
_fpsBuffer = [60, 60, 60, 60, 60];
|
|
1099
1362
|
/**
|
|
@@ -1105,9 +1368,9 @@ class v {
|
|
|
1105
1368
|
let t = 0;
|
|
1106
1369
|
this.#t = this.renderer.render;
|
|
1107
1370
|
const e = this;
|
|
1108
|
-
|
|
1109
|
-
const
|
|
1110
|
-
(
|
|
1371
|
+
Le(this.renderer), this.renderer.render = function(s, r) {
|
|
1372
|
+
const n = e.renderer.getRenderTarget();
|
|
1373
|
+
(n == null || "isXRRenderTarget" in n && n.isXRRenderTarget) && (t = 0, e.#r += 1, e.#n = e.#o.getDelta(), e.#i += e.#n, e._fpsBuffer.shift(), e._fpsBuffer.push(1 / e.#n), e.#s = e._fpsBuffer.reduce((u, a) => u + a) / e._fpsBuffer.length, A && e.#r % 200 === 0 && console.log("FPS", Math.round(e.#s), "Interval:", e.#e));
|
|
1111
1374
|
const o = t++;
|
|
1112
1375
|
e.#t.call(this, s, r), e.onAfterRender(s, r, o);
|
|
1113
1376
|
};
|
|
@@ -1115,19 +1378,34 @@ class v {
|
|
|
1115
1378
|
disable() {
|
|
1116
1379
|
this.#t && (console.debug("[gltf-progressive] Disabling LODsManager for renderer"), this.renderer.render = this.#t, this.#t = void 0);
|
|
1117
1380
|
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Manually trigger a LOD update for a scene and camera.
|
|
1383
|
+
* Only needed when {@link manual} is set to `true` — otherwise LOD updates happen automatically on each render call.
|
|
1384
|
+
*
|
|
1385
|
+
* @param scene - The scene containing objects with progressive LODs.
|
|
1386
|
+
* @param camera - The camera used to determine screen coverage and LOD levels.
|
|
1387
|
+
*
|
|
1388
|
+
* @example
|
|
1389
|
+
* ```ts
|
|
1390
|
+
* const lodsManager = LODsManager.get(renderer);
|
|
1391
|
+
* lodsManager.manual = true;
|
|
1392
|
+
* // ... later, trigger an update at a specific point:
|
|
1393
|
+
* lodsManager.update(scene, camera);
|
|
1394
|
+
* ```
|
|
1395
|
+
*/
|
|
1118
1396
|
update(t, e) {
|
|
1119
1397
|
this.internalUpdate(t, e);
|
|
1120
1398
|
}
|
|
1121
1399
|
onAfterRender(t, e, s) {
|
|
1122
1400
|
if (this.pause) return;
|
|
1123
|
-
const
|
|
1401
|
+
const n = this.renderer.renderLists.get(t, 0).opaque;
|
|
1124
1402
|
let o = !0;
|
|
1125
|
-
if (
|
|
1126
|
-
const
|
|
1127
|
-
(
|
|
1403
|
+
if (n.length === 1) {
|
|
1404
|
+
const u = n[0].material;
|
|
1405
|
+
(u.name === "EffectMaterial" || u.name === "CopyShader") && (o = !1);
|
|
1128
1406
|
}
|
|
1129
1407
|
if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (o = !1), o) {
|
|
1130
|
-
if (
|
|
1408
|
+
if (vt || (this.updateInterval === "auto" ? this.#s < 40 && this.#e < 10 ? (this.#e += 1, A && console.warn("↓ Reducing LOD updates", this.#e, this.#s.toFixed(0))) : this.#s >= 60 && this.#e > 1 && (this.#e -= 1, A && console.warn("↑ Increasing LOD updates", this.#e, this.#s.toFixed(0))) : this.#e = this.updateInterval, this.#e > 0 && this.#r % this.#e != 0))
|
|
1131
1409
|
return;
|
|
1132
1410
|
this.internalUpdate(t, e), this._postprocessPromiseGroups();
|
|
1133
1411
|
}
|
|
@@ -1138,10 +1416,10 @@ class v {
|
|
|
1138
1416
|
internalUpdate(t, e) {
|
|
1139
1417
|
const s = this.renderer.renderLists.get(t, 0), r = s.opaque;
|
|
1140
1418
|
this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix, e.matrixWorldInverse);
|
|
1141
|
-
const
|
|
1419
|
+
const n = this.targetTriangleDensity;
|
|
1142
1420
|
for (const a of r) {
|
|
1143
1421
|
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")) {
|
|
1144
|
-
|
|
1422
|
+
A && (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)));
|
|
1145
1423
|
continue;
|
|
1146
1424
|
}
|
|
1147
1425
|
switch (a.material.type) {
|
|
@@ -1153,38 +1431,33 @@ class v {
|
|
|
1153
1431
|
case "MeshDepthMaterial":
|
|
1154
1432
|
continue;
|
|
1155
1433
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
const c = Math.random() * 16777215, y = new Ve({ color: c });
|
|
1159
|
-
a.object.material = y;
|
|
1160
|
-
}
|
|
1161
|
-
const u = a.object;
|
|
1162
|
-
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1434
|
+
const l = a.object;
|
|
1435
|
+
(l instanceof K || l.isMesh) && this.updateLODs(t, e, l, n);
|
|
1163
1436
|
}
|
|
1164
1437
|
const o = s.transparent;
|
|
1165
1438
|
for (const a of o) {
|
|
1166
|
-
const
|
|
1167
|
-
(
|
|
1439
|
+
const l = a.object;
|
|
1440
|
+
(l instanceof K || l.isMesh) && this.updateLODs(t, e, l, n);
|
|
1168
1441
|
}
|
|
1169
|
-
const
|
|
1170
|
-
for (const a of
|
|
1171
|
-
const
|
|
1172
|
-
(
|
|
1442
|
+
const u = s.transmissive;
|
|
1443
|
+
for (const a of u) {
|
|
1444
|
+
const l = a.object;
|
|
1445
|
+
(l instanceof K || l.isMesh) && this.updateLODs(t, e, l, n);
|
|
1173
1446
|
}
|
|
1174
1447
|
}
|
|
1175
1448
|
/** Update the LOD levels for the renderer. */
|
|
1176
1449
|
updateLODs(t, e, s, r) {
|
|
1177
1450
|
s.userData || (s.userData = {});
|
|
1178
|
-
let
|
|
1179
|
-
if (
|
|
1451
|
+
let n = s[he];
|
|
1452
|
+
if (n || (n = new St(), s[he] = n), n.frames++ < 2)
|
|
1180
1453
|
return;
|
|
1181
|
-
for (const
|
|
1182
|
-
|
|
1183
|
-
const o = this.overrideLodLevel !== void 0 ? this.overrideLodLevel :
|
|
1184
|
-
o >= 0 ? (T.mesh_lod = o, T.texture_lod = o) : (this.calculateLodLevel(e, s,
|
|
1185
|
-
for (const
|
|
1186
|
-
|
|
1187
|
-
|
|
1454
|
+
for (const u of E)
|
|
1455
|
+
u.onBeforeUpdateLOD?.(this.renderer, t, e, s);
|
|
1456
|
+
const o = this.overrideLodLevel !== void 0 ? this.overrideLodLevel : X;
|
|
1457
|
+
o >= 0 ? (T.mesh_lod = o, T.texture_lod = o) : (this.calculateLodLevel(e, s, n, 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 && Be(s.material), Lt && s.material && !s.isGizmo && !s.isBatchedMesh && Ge(s.material, T.mesh_lod);
|
|
1458
|
+
for (const u of E)
|
|
1459
|
+
u.onAfterUpdatedLOD?.(this.renderer, t, e, s, T);
|
|
1460
|
+
n.lastLodLevel_Mesh = T.mesh_lod, n.lastLodLevel_Texture = T.texture_lod;
|
|
1188
1461
|
}
|
|
1189
1462
|
/** Load progressive textures for the given material
|
|
1190
1463
|
* @param material the material to load the textures for
|
|
@@ -1194,17 +1467,19 @@ class v {
|
|
|
1194
1467
|
loadProgressiveTextures(t, e, s) {
|
|
1195
1468
|
if (!t) return;
|
|
1196
1469
|
if (Array.isArray(t)) {
|
|
1197
|
-
for (const
|
|
1198
|
-
this.loadProgressiveTextures(
|
|
1470
|
+
for (const o of t)
|
|
1471
|
+
this.loadProgressiveTextures(o, e, s);
|
|
1199
1472
|
return;
|
|
1200
1473
|
}
|
|
1201
1474
|
let r = !1;
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1475
|
+
(t[q] === void 0 || e < t[q]) && (r = !0);
|
|
1476
|
+
const n = s !== void 0 && s >= 0;
|
|
1477
|
+
if (n && (r = t[q] != s, e = s), r) {
|
|
1478
|
+
t[q] = e;
|
|
1479
|
+
const o = n ? { force: !0 } : void 0, u = h.assignTextureLOD(t, e, o).then((a) => {
|
|
1205
1480
|
this._lodchangedlisteners.forEach((l) => l({ type: "texture", level: e, object: t }));
|
|
1206
1481
|
});
|
|
1207
|
-
|
|
1482
|
+
oe.addPromise("texture", t, u, this._newPromiseGroups);
|
|
1208
1483
|
}
|
|
1209
1484
|
}
|
|
1210
1485
|
/** Load progressive meshes for the given mesh
|
|
@@ -1215,143 +1490,110 @@ class v {
|
|
|
1215
1490
|
*/
|
|
1216
1491
|
loadProgressiveMeshes(t, e) {
|
|
1217
1492
|
if (!t) return Promise.resolve(null);
|
|
1218
|
-
let s = t[
|
|
1493
|
+
let s = t[q] !== e;
|
|
1219
1494
|
const r = t["DEBUG:LOD"];
|
|
1220
|
-
if (r != null && (s = t[
|
|
1221
|
-
t[
|
|
1222
|
-
const
|
|
1223
|
-
return
|
|
1495
|
+
if (r != null && (s = t[q] != r, e = r), s) {
|
|
1496
|
+
t[q] = e;
|
|
1497
|
+
const n = t.geometry, o = h.assignMeshLOD(t, e).then((u) => (u && t[q] == e && n != t.geometry && this._lodchangedlisteners.forEach((a) => a({ type: "mesh", level: e, object: t })), u));
|
|
1498
|
+
return oe.addPromise("mesh", t, o, this._newPromiseGroups), o;
|
|
1224
1499
|
}
|
|
1225
1500
|
return Promise.resolve(null);
|
|
1226
1501
|
}
|
|
1227
1502
|
// private testIfLODLevelsAreAvailable() {
|
|
1228
1503
|
_sphere = new Se();
|
|
1229
|
-
|
|
1230
|
-
_tempBox2 = new ge();
|
|
1231
|
-
tempMatrix = new ve();
|
|
1232
|
-
_tempWorldPosition = new A();
|
|
1233
|
-
_tempBoxSize = new A();
|
|
1234
|
-
_tempBox2Size = new A();
|
|
1235
|
-
static corner0 = new A();
|
|
1236
|
-
static corner1 = new A();
|
|
1237
|
-
static corner2 = new A();
|
|
1238
|
-
static corner3 = new A();
|
|
1239
|
-
static _tempPtInside = new A();
|
|
1240
|
-
static isInside(t, e) {
|
|
1241
|
-
const s = t.min, r = t.max, i = (s.x + r.x) * 0.5, o = (s.y + r.y) * 0.5;
|
|
1242
|
-
return this._tempPtInside.set(i, o, s.z).applyMatrix4(e).z < 0;
|
|
1243
|
-
}
|
|
1504
|
+
_tempWorldPosition = new k();
|
|
1244
1505
|
static skinnedMeshBoundsFrameOffsetCounter = 0;
|
|
1245
1506
|
static $skinnedMeshBoundsOffset = /* @__PURE__ */ Symbol("gltf-progressive-skinnedMeshBoundsOffset");
|
|
1246
1507
|
// #region calculateLodLevel
|
|
1247
|
-
calculateLodLevel(t, e, s, r,
|
|
1508
|
+
calculateLodLevel(t, e, s, r, n) {
|
|
1248
1509
|
if (!e) {
|
|
1249
|
-
|
|
1510
|
+
n.mesh_lod = -1, n.texture_lod = -1;
|
|
1250
1511
|
return;
|
|
1251
1512
|
}
|
|
1252
1513
|
if (!t) {
|
|
1253
|
-
|
|
1514
|
+
n.mesh_lod = -1, n.texture_lod = -1;
|
|
1254
1515
|
return;
|
|
1255
1516
|
}
|
|
1256
|
-
let
|
|
1257
|
-
if (
|
|
1517
|
+
let u = 10 + 1, a = !1;
|
|
1518
|
+
if (A && e["DEBUG:LOD"] != null)
|
|
1258
1519
|
return e["DEBUG:LOD"];
|
|
1259
|
-
const
|
|
1260
|
-
if (!
|
|
1261
|
-
|
|
1520
|
+
const l = h.getMeshLODExtension(e.geometry)?.lods, c = h.getPrimitiveIndex(e.geometry), d = l && l.length > 0, g = h.getMaterialMinMaxLODsCount(e.material), m = g.min_count !== 1 / 0 && g.min_count >= 0 && g.max_count >= 0;
|
|
1521
|
+
if (!d && !m) {
|
|
1522
|
+
n.mesh_lod = 0, n.texture_lod = 0;
|
|
1262
1523
|
return;
|
|
1263
1524
|
}
|
|
1264
|
-
|
|
1265
|
-
const
|
|
1266
|
-
let
|
|
1525
|
+
d || (a = !0, u = 0);
|
|
1526
|
+
const x = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
|
|
1527
|
+
let v = e.geometry.boundingBox;
|
|
1267
1528
|
if (e.type === "SkinnedMesh") {
|
|
1268
|
-
const
|
|
1269
|
-
if (!
|
|
1270
|
-
|
|
1529
|
+
const p = e;
|
|
1530
|
+
if (!p.boundingBox)
|
|
1531
|
+
p.computeBoundingBox();
|
|
1271
1532
|
else if (this.skinnedMeshAutoUpdateBoundsInterval > 0) {
|
|
1272
|
-
if (!
|
|
1273
|
-
const
|
|
1274
|
-
|
|
1533
|
+
if (!p[R.$skinnedMeshBoundsOffset]) {
|
|
1534
|
+
const C = R.skinnedMeshBoundsFrameOffsetCounter++;
|
|
1535
|
+
p[R.$skinnedMeshBoundsOffset] = C;
|
|
1275
1536
|
}
|
|
1276
|
-
const
|
|
1277
|
-
if ((s.frames +
|
|
1278
|
-
const
|
|
1279
|
-
|
|
1537
|
+
const _ = p[R.$skinnedMeshBoundsOffset];
|
|
1538
|
+
if ((s.frames + _) % this.skinnedMeshAutoUpdateBoundsInterval === 0) {
|
|
1539
|
+
const C = ne(p), W = p.geometry;
|
|
1540
|
+
C && (p.geometry = C), p.computeBoundingBox(), p.geometry = W;
|
|
1280
1541
|
}
|
|
1281
1542
|
}
|
|
1282
|
-
|
|
1543
|
+
v = p.boundingBox;
|
|
1283
1544
|
}
|
|
1284
|
-
if (
|
|
1285
|
-
const d = t;
|
|
1545
|
+
if (v) {
|
|
1286
1546
|
if (e.geometry.attributes.color && e.geometry.attributes.color.count < 100 && e.geometry.boundingSphere) {
|
|
1287
1547
|
this._sphere.copy(e.geometry.boundingSphere), this._sphere.applyMatrix4(e.matrixWorld);
|
|
1288
|
-
const
|
|
1289
|
-
if (this._sphere.containsPoint(
|
|
1290
|
-
|
|
1548
|
+
const C = t.getWorldPosition(this._tempWorldPosition);
|
|
1549
|
+
if (this._sphere.containsPoint(C)) {
|
|
1550
|
+
n.mesh_lod = 0, n.texture_lod = 0;
|
|
1291
1551
|
return;
|
|
1292
1552
|
}
|
|
1293
1553
|
}
|
|
1294
|
-
|
|
1295
|
-
|
|
1554
|
+
const p = Tt({
|
|
1555
|
+
geometry: e.geometry,
|
|
1556
|
+
matrixWorld: e.matrixWorld,
|
|
1557
|
+
camera: t,
|
|
1558
|
+
projectionScreenMatrix: this.projectionScreenMatrix,
|
|
1559
|
+
desiredDensity: r,
|
|
1560
|
+
canvasHeight: x,
|
|
1561
|
+
currentLevel: s.lastLodLevel_Mesh,
|
|
1562
|
+
boundingBox: v,
|
|
1563
|
+
xrEnabled: this.renderer.xr.enabled,
|
|
1564
|
+
debugDrawLine: A ? R.debugDrawLine : void 0,
|
|
1565
|
+
warnMissingPrimitiveDensities: !0
|
|
1566
|
+
});
|
|
1567
|
+
if (s.lastCentrality = p.centrality, s.lastScreenCoverage = p.screenCoverage, s.lastScreenspaceVolume.copy(p.screenspaceVolume), p.screenCoverage === 1 / 0) {
|
|
1568
|
+
n.mesh_lod = 0, n.texture_lod = 0;
|
|
1296
1569
|
return;
|
|
1297
1570
|
}
|
|
1298
|
-
|
|
1299
|
-
const h = this._tempBox.min, p = this._tempBox.max;
|
|
1300
|
-
let O = h.x, S = h.y, G = p.x, Y = p.y;
|
|
1301
|
-
const te = 2, ne = 1.5, se = (h.x + p.x) * 0.5, re = (h.y + p.y) * 0.5;
|
|
1302
|
-
O = (O - se) * te + se, S = (S - re) * te + re, G = (G - se) * te + se, Y = (Y - re) * te + re;
|
|
1303
|
-
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);
|
|
1304
|
-
s.lastCentrality = (ne - ae) * (ne - ae) * (ne - ae);
|
|
1305
|
-
} else
|
|
1306
|
-
s.lastCentrality = 1;
|
|
1307
|
-
const g = this._tempBox.getSize(this._tempBoxSize);
|
|
1308
|
-
g.multiplyScalar(0.5), screen.availHeight > 0 && k > 0 && g.multiplyScalar(k / screen.availHeight), t.isPerspectiveCamera ? g.x *= t.aspect : t.isOrthographicCamera;
|
|
1309
|
-
const b = t.matrixWorldInverse, B = this._tempBox2;
|
|
1310
|
-
B.copy(M), B.applyMatrix4(e.matrixWorld), B.applyMatrix4(b);
|
|
1311
|
-
const D = B.getSize(this._tempBox2Size), N = Math.max(D.x, D.y);
|
|
1312
|
-
if (Math.max(g.x, g.y) != 0 && N != 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) {
|
|
1313
|
-
const h = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
1314
|
-
h.invert();
|
|
1315
|
-
const p = v.corner0, O = v.corner1, S = v.corner2, G = v.corner3;
|
|
1316
|
-
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);
|
|
1317
|
-
const Y = (p.z + G.z) * 0.5;
|
|
1318
|
-
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);
|
|
1319
|
-
}
|
|
1320
|
-
let L = 999;
|
|
1321
|
-
if (u && s.lastScreenCoverage > 0)
|
|
1322
|
-
for (let h = 0; h < u.length; h++) {
|
|
1323
|
-
const p = u[h], S = (p.densities?.[c] || p.density || 1e-5) / s.lastScreenCoverage;
|
|
1324
|
-
if (c > 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.")), S < r) {
|
|
1325
|
-
L = h;
|
|
1326
|
-
break;
|
|
1327
|
-
}
|
|
1328
|
-
}
|
|
1329
|
-
L < l && (l = L, a = !0);
|
|
1571
|
+
p.level >= 0 && p.level < u && (u = p.level, a = !0);
|
|
1330
1572
|
}
|
|
1331
|
-
if (a ?
|
|
1332
|
-
const
|
|
1333
|
-
|
|
1573
|
+
if (a ? n.mesh_lod = u : n.mesh_lod = s.lastLodLevel_Mesh, A && n.mesh_lod != s.lastLodLevel_Mesh) {
|
|
1574
|
+
const _ = l?.[n.mesh_lod];
|
|
1575
|
+
_ && console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${n.mesh_lod} (density: ${_.densities?.[c].toFixed(0)}) | ${e.name}`);
|
|
1334
1576
|
}
|
|
1335
|
-
if (
|
|
1336
|
-
const
|
|
1577
|
+
if (m) {
|
|
1578
|
+
const p = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
|
|
1337
1579
|
if (s.lastLodLevel_Texture < 0) {
|
|
1338
|
-
if (
|
|
1339
|
-
const
|
|
1340
|
-
|
|
1580
|
+
if (n.texture_lod = g.max_count - 1, A) {
|
|
1581
|
+
const _ = g.lods[g.max_count - 1];
|
|
1582
|
+
A && console.log(`First Texture LOD ${n.texture_lod} (${_.max_height}px) - ${e.name}`);
|
|
1341
1583
|
}
|
|
1342
1584
|
} else {
|
|
1343
|
-
const
|
|
1344
|
-
let
|
|
1345
|
-
this.context?.engine === "model-viewer" && (
|
|
1346
|
-
const
|
|
1347
|
-
let
|
|
1348
|
-
for (let
|
|
1349
|
-
const
|
|
1350
|
-
if (!(
|
|
1351
|
-
if (
|
|
1352
|
-
const
|
|
1353
|
-
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${
|
|
1354
|
-
Screensize: ${
|
|
1585
|
+
const _ = s.lastScreenspaceVolume.x + s.lastScreenspaceVolume.y + s.lastScreenspaceVolume.z;
|
|
1586
|
+
let C = s.lastScreenCoverage * 4;
|
|
1587
|
+
this.context?.engine === "model-viewer" && (C *= 1.5);
|
|
1588
|
+
const L = x / window.devicePixelRatio * C;
|
|
1589
|
+
let w = !1;
|
|
1590
|
+
for (let S = g.lods.length - 1; S >= 0; S--) {
|
|
1591
|
+
const O = g.lods[S];
|
|
1592
|
+
if (!(p && O.max_height >= 2048) && !(ve() && O.max_height > 4096) && (O.max_height > L || !w && S === 0)) {
|
|
1593
|
+
if (w = !0, n.texture_lod = S, A && n.texture_lod < s.lastLodLevel_Texture) {
|
|
1594
|
+
const D = O.max_height;
|
|
1595
|
+
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${n.texture_lod} = ${D}px
|
|
1596
|
+
Screensize: ${L.toFixed(0)}px, Coverage: ${(100 * s.lastScreenCoverage).toFixed(2)}%, Volume ${_.toFixed(1)}
|
|
1355
1597
|
${e.name}`);
|
|
1356
1598
|
}
|
|
1357
1599
|
break;
|
|
@@ -1359,83 +1601,98 @@ ${e.name}`);
|
|
|
1359
1601
|
}
|
|
1360
1602
|
}
|
|
1361
1603
|
} else
|
|
1362
|
-
|
|
1604
|
+
n.texture_lod = 0;
|
|
1363
1605
|
}
|
|
1364
1606
|
}
|
|
1365
|
-
class
|
|
1607
|
+
class St {
|
|
1366
1608
|
frames = 0;
|
|
1367
1609
|
lastLodLevel_Mesh = -1;
|
|
1368
1610
|
lastLodLevel_Texture = -1;
|
|
1369
1611
|
lastScreenCoverage = 0;
|
|
1370
|
-
lastScreenspaceVolume = new
|
|
1612
|
+
lastScreenspaceVolume = new k();
|
|
1371
1613
|
lastCentrality = 0;
|
|
1372
1614
|
}
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1615
|
+
function Ge(i, t) {
|
|
1616
|
+
if (!(t < 0)) {
|
|
1617
|
+
if (Array.isArray(i)) {
|
|
1618
|
+
for (const e of i)
|
|
1619
|
+
Ge(e, t);
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
"color" in i && i.color instanceof Ce && (i.color.copy(Ct(t, _t)), i.needsUpdate = !0);
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
function Ct(i, t) {
|
|
1626
|
+
const e = Math.max(0, Math.min(Me.length - 1, Math.floor(i)));
|
|
1627
|
+
return t.setHex(Me[e]);
|
|
1628
|
+
}
|
|
1629
|
+
const be = /* @__PURE__ */ Symbol("NEEDLE_mesh_lod"), ie = /* @__PURE__ */ Symbol("NEEDLE_texture_lod");
|
|
1630
|
+
let pe = null;
|
|
1631
|
+
function We() {
|
|
1632
|
+
const i = Pt();
|
|
1633
|
+
i && (i.mapURLs(function(t) {
|
|
1634
|
+
return Oe(), t;
|
|
1635
|
+
}), Oe(), pe?.disconnect(), pe = new MutationObserver((t) => {
|
|
1380
1636
|
t.forEach((e) => {
|
|
1381
1637
|
e.addedNodes.forEach((s) => {
|
|
1382
|
-
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" &&
|
|
1638
|
+
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" && Ue(s);
|
|
1383
1639
|
});
|
|
1384
1640
|
});
|
|
1385
|
-
}),
|
|
1641
|
+
}), pe.observe(document, { childList: !0, subtree: !0 }));
|
|
1386
1642
|
}
|
|
1387
|
-
function
|
|
1643
|
+
function Pt() {
|
|
1388
1644
|
if (typeof customElements > "u") return null;
|
|
1389
|
-
const
|
|
1390
|
-
return
|
|
1391
|
-
console.debug("[gltf-progressive] model-viewer defined"),
|
|
1645
|
+
const i = customElements.get("model-viewer");
|
|
1646
|
+
return i || (customElements.whenDefined("model-viewer").then(() => {
|
|
1647
|
+
console.debug("[gltf-progressive] model-viewer defined"), We();
|
|
1392
1648
|
}), null);
|
|
1393
1649
|
}
|
|
1394
|
-
function
|
|
1650
|
+
function Oe() {
|
|
1395
1651
|
if (typeof document > "u") return;
|
|
1396
1652
|
document.querySelectorAll("model-viewer").forEach((t) => {
|
|
1397
|
-
|
|
1653
|
+
Ue(t);
|
|
1398
1654
|
});
|
|
1399
1655
|
}
|
|
1400
|
-
const
|
|
1401
|
-
let
|
|
1402
|
-
function
|
|
1403
|
-
if (!
|
|
1656
|
+
const Te = /* @__PURE__ */ new WeakSet();
|
|
1657
|
+
let kt = 0;
|
|
1658
|
+
function Ue(i) {
|
|
1659
|
+
if (!i || Te.has(i))
|
|
1404
1660
|
return null;
|
|
1405
|
-
|
|
1406
|
-
`,
|
|
1661
|
+
Te.add(i), console.debug("[gltf-progressive] found new model-viewer..." + ++kt + `
|
|
1662
|
+
`, i.getAttribute("src"));
|
|
1407
1663
|
let t = null, e = null, s = null;
|
|
1408
|
-
for (let r =
|
|
1409
|
-
const
|
|
1410
|
-
!t && o != null && (t =
|
|
1664
|
+
for (let r = i; r != null; r = Object.getPrototypeOf(r)) {
|
|
1665
|
+
const n = Object.getOwnPropertySymbols(r), o = n.find((l) => l.toString() == "Symbol(renderer)"), u = n.find((l) => l.toString() == "Symbol(scene)"), a = n.find((l) => l.toString() == "Symbol(needsRender)");
|
|
1666
|
+
!t && o != null && (t = i[o].threeRenderer), !e && u != null && (e = i[u]), !s && a != null && (s = i[a]);
|
|
1411
1667
|
}
|
|
1412
1668
|
if (t && e) {
|
|
1413
1669
|
let r = function() {
|
|
1414
1670
|
if (s) {
|
|
1415
|
-
let o = 0
|
|
1671
|
+
let o = 0;
|
|
1672
|
+
const u = setInterval(() => {
|
|
1416
1673
|
if (o++ > 5) {
|
|
1417
|
-
clearInterval(
|
|
1674
|
+
clearInterval(u);
|
|
1418
1675
|
return;
|
|
1419
1676
|
}
|
|
1420
|
-
s?.call(
|
|
1677
|
+
s?.call(i);
|
|
1421
1678
|
}, 300);
|
|
1422
1679
|
}
|
|
1423
1680
|
};
|
|
1424
1681
|
console.debug("[gltf-progressive] setup model-viewer");
|
|
1425
|
-
const
|
|
1426
|
-
return
|
|
1427
|
-
s?.call(
|
|
1428
|
-
}),
|
|
1429
|
-
o.detail.visible && s?.call(
|
|
1430
|
-
}),
|
|
1682
|
+
const n = R.get(t, { engine: "model-viewer" });
|
|
1683
|
+
return R.addPlugin(new At()), n.enable(), n.addEventListener("changed", () => {
|
|
1684
|
+
s?.call(i);
|
|
1685
|
+
}), i.addEventListener("model-visibility", (o) => {
|
|
1686
|
+
o.detail.visible && s?.call(i);
|
|
1687
|
+
}), i.addEventListener("load", () => {
|
|
1431
1688
|
r();
|
|
1432
1689
|
}), () => {
|
|
1433
|
-
|
|
1690
|
+
n.disable();
|
|
1434
1691
|
};
|
|
1435
1692
|
}
|
|
1436
1693
|
return null;
|
|
1437
1694
|
}
|
|
1438
|
-
class
|
|
1695
|
+
class At {
|
|
1439
1696
|
_didWarnAboutMissingUrl = !1;
|
|
1440
1697
|
onBeforeUpdateLOD(t, e, s, r) {
|
|
1441
1698
|
this.tryParseMeshLOD(e, r), this.tryParseTextureLOD(e, r);
|
|
@@ -1455,99 +1712,102 @@ class _t {
|
|
|
1455
1712
|
tryParseTextureLOD(t, e) {
|
|
1456
1713
|
if (e[ie] == !0) return;
|
|
1457
1714
|
e[ie] = !0;
|
|
1458
|
-
const s = this.tryGetCurrentGLTF(t), r = this.tryGetCurrentModelViewer(t),
|
|
1459
|
-
if (
|
|
1715
|
+
const s = this.tryGetCurrentGLTF(t), r = this.tryGetCurrentModelViewer(t), n = this.getUrl(r);
|
|
1716
|
+
if (n && s && e.material) {
|
|
1460
1717
|
let o = function(a) {
|
|
1461
1718
|
if (a[ie] == !0) return;
|
|
1462
1719
|
a[ie] = !0, a.userData && (a.userData.LOD = -1);
|
|
1463
|
-
const
|
|
1464
|
-
for (let c = 0; c <
|
|
1465
|
-
const
|
|
1466
|
-
if (
|
|
1467
|
-
const
|
|
1468
|
-
if (
|
|
1469
|
-
const
|
|
1470
|
-
if (!
|
|
1471
|
-
console.warn("Texture data not found for texture index " +
|
|
1720
|
+
const l = Object.keys(a);
|
|
1721
|
+
for (let c = 0; c < l.length; c++) {
|
|
1722
|
+
const d = l[c], g = a[d];
|
|
1723
|
+
if (g?.isTexture === !0) {
|
|
1724
|
+
const m = g.userData?.associations?.textures;
|
|
1725
|
+
if (m == null) continue;
|
|
1726
|
+
const x = s.parser.json.textures[m];
|
|
1727
|
+
if (!x) {
|
|
1728
|
+
console.warn("Texture data not found for texture index " + m);
|
|
1472
1729
|
continue;
|
|
1473
1730
|
}
|
|
1474
|
-
if (
|
|
1475
|
-
const
|
|
1476
|
-
|
|
1731
|
+
if (x?.extensions?.[F]) {
|
|
1732
|
+
const v = x.extensions[F];
|
|
1733
|
+
v && n && h.registerTexture(n, g, v.lods.length, m, v);
|
|
1477
1734
|
}
|
|
1478
1735
|
}
|
|
1479
1736
|
}
|
|
1480
1737
|
};
|
|
1481
|
-
const
|
|
1482
|
-
if (Array.isArray(
|
|
1483
|
-
else o(
|
|
1738
|
+
const u = e.material;
|
|
1739
|
+
if (Array.isArray(u)) for (const a of u) o(a);
|
|
1740
|
+
else o(u);
|
|
1484
1741
|
}
|
|
1485
1742
|
}
|
|
1486
1743
|
tryParseMeshLOD(t, e) {
|
|
1487
|
-
if (e[
|
|
1488
|
-
e[
|
|
1744
|
+
if (e[be] == !0) return;
|
|
1745
|
+
e[be] = !0;
|
|
1489
1746
|
const s = this.tryGetCurrentModelViewer(t), r = this.getUrl(s);
|
|
1490
1747
|
if (!r)
|
|
1491
1748
|
return;
|
|
1492
|
-
const
|
|
1493
|
-
if (
|
|
1749
|
+
const n = e.userData?.gltfExtensions?.[F];
|
|
1750
|
+
if (n && r) {
|
|
1494
1751
|
const o = e.uuid;
|
|
1495
|
-
|
|
1752
|
+
h.registerMesh(r, o, e, 0, n.lods.length, n);
|
|
1496
1753
|
}
|
|
1497
1754
|
}
|
|
1498
1755
|
}
|
|
1499
|
-
function
|
|
1756
|
+
function Rt(...i) {
|
|
1500
1757
|
let t, e, s, r;
|
|
1501
|
-
switch (
|
|
1758
|
+
switch (i.length) {
|
|
1502
1759
|
case 2:
|
|
1503
|
-
[s, e] =
|
|
1760
|
+
[s, e] = i, r = {};
|
|
1504
1761
|
break;
|
|
1505
1762
|
case 3:
|
|
1506
|
-
[s, e, r] =
|
|
1763
|
+
[s, e, r] = i;
|
|
1507
1764
|
break;
|
|
1508
1765
|
case 4:
|
|
1509
|
-
[t, e, s, r] =
|
|
1766
|
+
[t, e, s, r] = i;
|
|
1510
1767
|
break;
|
|
1511
1768
|
default:
|
|
1512
1769
|
throw new Error("Invalid arguments");
|
|
1513
1770
|
}
|
|
1514
|
-
|
|
1771
|
+
Le(e), Ae(s), Ie(s, {
|
|
1515
1772
|
progressive: !0,
|
|
1516
1773
|
...r?.hints
|
|
1517
|
-
}), s.register((o) => new
|
|
1518
|
-
const
|
|
1519
|
-
return r?.enableLODsManager !== !1 &&
|
|
1774
|
+
}), s.register((o) => new h(o));
|
|
1775
|
+
const n = R.get(e);
|
|
1776
|
+
return r?.enableLODsManager !== !1 && n.enable(), n;
|
|
1520
1777
|
}
|
|
1521
|
-
|
|
1522
|
-
if (!
|
|
1523
|
-
const
|
|
1778
|
+
We();
|
|
1779
|
+
if (!ct) {
|
|
1780
|
+
const i = {
|
|
1524
1781
|
gltfProgressive: {
|
|
1525
|
-
useNeedleProgressive:
|
|
1526
|
-
LODsManager:
|
|
1527
|
-
configureLoader:
|
|
1528
|
-
getRaycastMesh:
|
|
1529
|
-
useRaycastMeshes:
|
|
1782
|
+
useNeedleProgressive: Rt,
|
|
1783
|
+
LODsManager: R,
|
|
1784
|
+
configureLoader: Ie,
|
|
1785
|
+
getRaycastMesh: ne,
|
|
1786
|
+
useRaycastMeshes: ft
|
|
1530
1787
|
}
|
|
1531
1788
|
};
|
|
1532
1789
|
if (!globalThis.Needle)
|
|
1533
|
-
globalThis.Needle =
|
|
1790
|
+
globalThis.Needle = i;
|
|
1534
1791
|
else
|
|
1535
|
-
for (const t in
|
|
1536
|
-
globalThis.Needle[t] =
|
|
1792
|
+
for (const t in i)
|
|
1793
|
+
globalThis.Needle[t] = i[t];
|
|
1537
1794
|
}
|
|
1538
1795
|
export {
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1796
|
+
F as EXTENSION_NAME,
|
|
1797
|
+
R as LODsManager,
|
|
1798
|
+
h as NEEDLE_progressive,
|
|
1799
|
+
Je as VERSION,
|
|
1800
|
+
Ae as addDracoAndKTX2Loaders,
|
|
1801
|
+
Tt as calculateMeshLODLevel,
|
|
1802
|
+
Ie as configureLoader,
|
|
1803
|
+
Le as createLoaders,
|
|
1804
|
+
Ct as getLODColor,
|
|
1805
|
+
ne as getRaycastMesh,
|
|
1806
|
+
Me as lodDebugColors,
|
|
1807
|
+
We as patchModelViewer,
|
|
1808
|
+
dt as registerRaycastMesh,
|
|
1809
|
+
st as setDracoDecoderLocation,
|
|
1810
|
+
rt as setKTX2TranscoderLocation,
|
|
1811
|
+
Rt as useNeedleProgressive,
|
|
1812
|
+
ft as useRaycastMeshes
|
|
1553
1813
|
};
|