@needle-tools/gltf-progressive 3.5.0-rc → 3.6.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -1
- package/LICENSE +21 -0
- package/gltf-progressive.js +851 -620
- package/gltf-progressive.min.js +9 -9
- package/gltf-progressive.umd.cjs +9 -9
- package/lib/extension.d.ts +61 -5
- package/lib/extension.js +268 -105
- 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 +66 -4
- package/lib/lods.manager.js +133 -16
- 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
|
|
1
|
+
import { BufferGeometry as V, Mesh as X, Box3 as ge, Vector3 as P, Sphere as Oe, CompressedTexture as Ue, Texture as W, Matrix3 as ze, InterleavedBuffer as qe, InterleavedBufferAttribute as Ne, BufferAttribute as Ee, TextureLoader as Ve, Color as ke, Matrix4 as ve, Clock as Xe } from "three";
|
|
2
2
|
import { GLTFLoader as xe } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
3
|
-
import { MeshoptDecoder as
|
|
4
|
-
import { DRACOLoader as
|
|
3
|
+
import { MeshoptDecoder as Ke } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
4
|
+
import { DRACOLoader as Ye } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
5
5
|
import { KTX2Loader as je } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
6
|
-
const
|
|
7
|
-
globalThis.GLTF_PROGRESSIVE_VERSION =
|
|
6
|
+
const He = "";
|
|
7
|
+
globalThis.GLTF_PROGRESSIVE_VERSION = He;
|
|
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/", K = "https://cdn.needle.tools/static/three/0.179.1/basis2/";
|
|
10
|
+
const Qe = I, Je = K, Ce = new URL(I + "draco_decoder.js");
|
|
11
|
+
Ce.searchParams.append("range", "true");
|
|
12
|
+
fetch(Ce, {
|
|
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 === Qe && et("./include/draco/"), K === Je && tt("./include/ktx2/");
|
|
19
19
|
}).finally(() => {
|
|
20
|
-
|
|
20
|
+
Ae();
|
|
21
21
|
});
|
|
22
|
-
const
|
|
22
|
+
const Ze = () => ({
|
|
23
23
|
dracoDecoderPath: I,
|
|
24
|
-
ktx2TranscoderPath:
|
|
24
|
+
ktx2TranscoderPath: K
|
|
25
25
|
});
|
|
26
|
-
function
|
|
27
|
-
I =
|
|
26
|
+
function et(i) {
|
|
27
|
+
I = i, k && k[pe] != I ? (console.debug("Updating Draco decoder path to " + i), k[pe] = I, k.setDecoderPath(I), k.preload()) : console.debug("Setting Draco decoder path to " + i);
|
|
28
28
|
}
|
|
29
|
-
function
|
|
30
|
-
|
|
29
|
+
function tt(i) {
|
|
30
|
+
K = i, $ && $.transcoderPath != K ? (console.debug("Updating KTX2 transcoder path to " + i), $.setTranscoderPath(K), $.init()) : console.debug("Setting KTX2 transcoder path to " + i);
|
|
31
31
|
}
|
|
32
|
-
function we(
|
|
33
|
-
return
|
|
32
|
+
function we(i) {
|
|
33
|
+
return Ae(), i ? $.detectSupport(i) : i !== null && console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"), { dracoLoader: k, ktx2Loader: $, meshoptDecoder: oe };
|
|
34
34
|
}
|
|
35
|
-
function
|
|
36
|
-
|
|
35
|
+
function Pe(i) {
|
|
36
|
+
i.dracoLoader || i.setDRACOLoader(k), i.ktx2Loader || i.setKTX2Loader($), i.meshoptDecoder || i.setMeshoptDecoder(oe);
|
|
37
37
|
}
|
|
38
38
|
const pe = /* @__PURE__ */ Symbol("dracoDecoderPath");
|
|
39
|
-
let
|
|
40
|
-
function
|
|
41
|
-
|
|
39
|
+
let k, oe, $;
|
|
40
|
+
function Ae() {
|
|
41
|
+
k || (k = new Ye(), k[pe] = I, k.setDecoderPath(I), k.setDecoderConfig({ type: "js" }), k.preload()), $ || ($ = new je(), $.setTranscoderPath(K), $.init()), oe || (oe = Ke);
|
|
42
42
|
}
|
|
43
43
|
const me = /* @__PURE__ */ new WeakMap();
|
|
44
|
-
function
|
|
45
|
-
let e = me.get(
|
|
46
|
-
e ? e = Object.assign(e, t) : e = t, me.set(
|
|
44
|
+
function Re(i, t) {
|
|
45
|
+
let e = me.get(i);
|
|
46
|
+
e ? e = Object.assign(e, t) : e = t, me.set(i, e);
|
|
47
47
|
}
|
|
48
|
-
const
|
|
49
|
-
function
|
|
48
|
+
const st = xe.prototype.load;
|
|
49
|
+
function rt(...i) {
|
|
50
50
|
const t = me.get(this);
|
|
51
|
-
let e =
|
|
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, st?.call(this, ...i);
|
|
58
58
|
}
|
|
59
|
-
xe.prototype.load =
|
|
60
|
-
|
|
61
|
-
function
|
|
59
|
+
xe.prototype.load = rt;
|
|
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 nt(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 Le() {
|
|
78
|
+
return j !== void 0 || (j = /iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent), N("debugprogressive") && console.log("[glTF Progressive]: isMobileDevice", j)), j;
|
|
79
79
|
}
|
|
80
|
-
let
|
|
81
|
-
function
|
|
80
|
+
let j;
|
|
81
|
+
function Me() {
|
|
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 ot {
|
|
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 it(
|
|
121
|
-
const t =
|
|
122
|
-
return t * e * s *
|
|
120
|
+
function it(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 = at(i);
|
|
122
|
+
return t * e * s * n * (1 - Math.pow(0.25, r)) / (1 - 0.25);
|
|
123
123
|
}
|
|
124
|
-
function
|
|
124
|
+
function at(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 ee(
|
|
134
|
-
return
|
|
132
|
+
const lt = typeof window > "u" && typeof document > "u", ye = /* @__PURE__ */ Symbol("needle:raycast-mesh");
|
|
133
|
+
function ee(i) {
|
|
134
|
+
return i?.[ye] instanceof V ? i[ye] : null;
|
|
135
135
|
}
|
|
136
|
-
function
|
|
137
|
-
if ((
|
|
138
|
-
const s =
|
|
139
|
-
s.userData = { isRaycastMesh: !0 },
|
|
136
|
+
function ut(i, t) {
|
|
137
|
+
if ((i.type === "Mesh" || i.type === "SkinnedMesh") && !ee(i)) {
|
|
138
|
+
const s = dt(t);
|
|
139
|
+
s.userData = { isRaycastMesh: !0 }, i[ye] = s;
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
-
function
|
|
143
|
-
if (
|
|
144
|
-
if (
|
|
145
|
-
const t =
|
|
142
|
+
function ct(i = !0) {
|
|
143
|
+
if (i) {
|
|
144
|
+
if (H) return;
|
|
145
|
+
const t = H = X.prototype.raycast;
|
|
146
146
|
X.prototype.raycast = function(e, s) {
|
|
147
|
-
const r = this,
|
|
147
|
+
const r = this, n = ee(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
|
-
X.prototype.raycast =
|
|
152
|
+
if (!H) return;
|
|
153
|
+
X.prototype.raycast = H, H = 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 H = null;
|
|
157
|
+
function dt(i) {
|
|
158
|
+
const t = new V();
|
|
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 Z,
|
|
165
|
-
if (
|
|
166
|
-
let
|
|
167
|
-
|
|
168
|
-
}
|
|
163
|
+
const q = new Array(), h = N("debugprogressive");
|
|
164
|
+
let Z, E = -1;
|
|
165
|
+
if (h) {
|
|
166
|
+
let i = function() {
|
|
167
|
+
E += 1, E >= t && (E = -1), console.log(`Toggle LOD level [${E}]`);
|
|
168
|
+
};
|
|
169
|
+
const t = 6;
|
|
169
170
|
window.addEventListener("keyup", (e) => {
|
|
170
|
-
e.key === "p" &&
|
|
171
|
+
e.key === "p" && i(), e.key === "w" && (Z = !Z, console.log(`Toggle wireframe [${Z}]`));
|
|
171
172
|
const s = parseInt(e.key);
|
|
172
|
-
!isNaN(s) && s >= 0 && (
|
|
173
|
+
!isNaN(s) && s >= 0 && (E = s, console.log(`Set LOD level to [${E}]`));
|
|
173
174
|
});
|
|
174
175
|
}
|
|
175
|
-
function
|
|
176
|
-
if (
|
|
177
|
-
if (Array.isArray(
|
|
178
|
-
for (const t of
|
|
179
|
-
|
|
180
|
-
else
|
|
176
|
+
function Ie(i) {
|
|
177
|
+
if (h && Z !== void 0)
|
|
178
|
+
if (Array.isArray(i))
|
|
179
|
+
for (const t of i)
|
|
180
|
+
Ie(t);
|
|
181
|
+
else i && "wireframe" in i && (i.wireframe = Z === !0);
|
|
181
182
|
}
|
|
182
|
-
const
|
|
183
|
-
let
|
|
184
|
-
const
|
|
185
|
-
function
|
|
186
|
-
if (
|
|
187
|
-
const s =
|
|
188
|
-
|
|
189
|
-
const r =
|
|
190
|
-
return
|
|
191
|
-
}
|
|
192
|
-
const t =
|
|
193
|
-
return
|
|
183
|
+
const Q = new Array();
|
|
184
|
+
let ft = 0;
|
|
185
|
+
const ht = Le() ? 2 : 10;
|
|
186
|
+
function gt(i) {
|
|
187
|
+
if (Q.length < ht) {
|
|
188
|
+
const s = Q.length;
|
|
189
|
+
h && console.warn(`[Worker] Creating new worker #${s}`);
|
|
190
|
+
const r = _e.createWorker(i || {});
|
|
191
|
+
return Q.push(r), r;
|
|
192
|
+
}
|
|
193
|
+
const t = ft++ % Q.length;
|
|
194
|
+
return Q[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
|
+
pt(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 = Ze();
|
|
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 = we(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 pt(i) {
|
|
253
|
+
for (const t of i.geometries) {
|
|
254
|
+
const e = t.geometry, s = new V();
|
|
254
255
|
if (s.name = e.name || "", e.index) {
|
|
255
256
|
const r = e.index;
|
|
256
257
|
s.setIndex(le(r));
|
|
257
258
|
}
|
|
258
259
|
for (const r in e.attributes) {
|
|
259
|
-
const
|
|
260
|
+
const n = e.attributes[r], o = le(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) => le(u));
|
|
265
266
|
s.morphAttributes[r] = o;
|
|
266
267
|
}
|
|
267
|
-
if (s.morphTargetsRelative = e.morphTargetsRelative ?? !1, s.boundingBox = new ge(), s.boundingBox.min = new
|
|
268
|
+
if (s.morphTargetsRelative = e.morphTargetsRelative ?? !1, s.boundingBox = new ge(), s.boundingBox.min = new P(
|
|
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 P(
|
|
272
273
|
e.boundingBox?.max.x,
|
|
273
274
|
e.boundingBox?.max.y,
|
|
274
275
|
e.boundingBox?.max.z
|
|
275
|
-
), s.boundingSphere = new
|
|
276
|
-
new
|
|
276
|
+
), s.boundingSphere = new Oe(
|
|
277
|
+
new P(
|
|
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 Ue(
|
|
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 W(
|
|
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 ze(...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 le(
|
|
328
|
-
let t =
|
|
329
|
-
if ("isInterleavedBufferAttribute" in
|
|
330
|
-
const e =
|
|
331
|
-
t = new
|
|
332
|
-
} else "isBufferAttribute" in
|
|
328
|
+
function le(i) {
|
|
329
|
+
let t = i;
|
|
330
|
+
if ("isInterleavedBufferAttribute" in i && i.isInterleavedBufferAttribute) {
|
|
331
|
+
const e = i.data, s = e.array, r = new qe(s, e.stride);
|
|
332
|
+
t = new Ne(r, i.itemSize, s.byteOffset, i.normalized), t.offset = i.offset;
|
|
333
|
+
} else "isBufferAttribute" in i && i.isBufferAttribute && (t = new Ee(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 mt = N("gltf-progressive-worker");
|
|
337
|
+
N("gltf-progressive-reduce-mipmaps");
|
|
338
|
+
const J = N("gltf-progressive-gc"), ue = /* @__PURE__ */ Symbol("needle-progressive-texture"), U = "NEEDLE_progressive";
|
|
339
|
+
class p {
|
|
339
340
|
/** The name of the extension */
|
|
340
341
|
get name() {
|
|
341
|
-
return
|
|
342
|
+
return U;
|
|
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
|
-
if (
|
|
365
|
-
const
|
|
366
|
-
for (const a of Object.keys(
|
|
367
|
-
const
|
|
368
|
-
|
|
388
|
+
if (h === "verbose" && console.log("getMaterialMinMaxLODsCount", t), t.type === "ShaderMaterial" || t.type === "RawShaderMaterial") {
|
|
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
|
+
h && 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 f = 0; f < c.lods.length; f++) {
|
|
409
|
+
const y = c.lods[f];
|
|
410
|
+
y.width && (a.lods[f] = a.lods[f] || { min_height: 1 / 0, max_height: 0 }, a.lods[f].min_height = Math.min(a.lods[f].min_height, y.height), a.lods[f].max_height = Math.max(a.lods[f].max_height, y.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
|
}
|
|
@@ -441,68 +465,69 @@ class m {
|
|
|
441
465
|
const s = t.geometry, r = this.getAssignedLODInformation(s);
|
|
442
466
|
if (!r)
|
|
443
467
|
return Promise.resolve(null);
|
|
444
|
-
for (const
|
|
445
|
-
|
|
446
|
-
return t["LOD:requested level"] = e,
|
|
447
|
-
if (Array.isArray(
|
|
468
|
+
for (const n of q)
|
|
469
|
+
n.onBeforeGetLODMesh?.(t, e);
|
|
470
|
+
return t["LOD:requested level"] = e, p.getOrLoadLOD(s, e).then((n) => {
|
|
471
|
+
if (Array.isArray(n)) {
|
|
448
472
|
const o = r.index || 0;
|
|
449
|
-
|
|
473
|
+
n = n[o];
|
|
450
474
|
}
|
|
451
|
-
return t["LOD:requested level"] === e && (delete t["LOD:requested level"],
|
|
452
|
-
}).catch((
|
|
453
|
-
} else
|
|
475
|
+
return t["LOD:requested level"] === e && (delete t["LOD:requested level"], n && s != n && (n?.isBufferGeometry ? t.geometry = n : h && console.error("Invalid LOD geometry", n))), n;
|
|
476
|
+
}).catch((n) => (console.error("Error loading mesh LOD", t, n), null));
|
|
477
|
+
} else h && 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 f = this.assignTextureLODForSlot(c, e, n, l, r).then((y) => (y && a.uniforms[l].value != y && (a.uniforms[l].value = y, a.uniformsNeedUpdate = !0), y));
|
|
508
|
+
o.push(f), 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 f = a[c], y = u[c];
|
|
523
|
+
f && f.isTexture === !0 ? l.push({ material: n, slot: y, texture: f, level: e }) : l.push({ material: n, slot: y, 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 W || 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,46 +536,119 @@ class m {
|
|
|
511
536
|
* @default 50 on desktop, 20 on mobile devices
|
|
512
537
|
*/
|
|
513
538
|
static set maxConcurrentLoadingTasks(t) {
|
|
514
|
-
|
|
539
|
+
p.queue.maxConcurrent = t;
|
|
515
540
|
}
|
|
516
541
|
static get maxConcurrentLoadingTasks() {
|
|
517
|
-
return
|
|
542
|
+
return p.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 = p.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
|
|
531
|
-
}
|
|
532
|
-
if (this.trackTextureUsage(i), o && o !== i && this.untrackTextureUsage(o) && (f || K)) {
|
|
533
|
-
const a = this.getAssignedLODInformation(o);
|
|
534
|
-
console.log(`[gltf-progressive] Disposed old texture LOD ${a?.level ?? "?"} → ${e} for ${s.name || s.type}.${r}`, o.uuid);
|
|
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 h === "verbose" && console.warn("Assigned texture level is already higher: ", c.level, e, s, l, a), null;
|
|
535
568
|
}
|
|
536
|
-
s
|
|
569
|
+
this.assignTrackedTextureSlot(s, r, a);
|
|
537
570
|
}
|
|
538
|
-
return
|
|
539
|
-
} else
|
|
571
|
+
return a;
|
|
572
|
+
} else h == "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) && (h || J)) {
|
|
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;
|
|
545
643
|
constructor(t) {
|
|
546
644
|
const e = t.options.path;
|
|
547
|
-
|
|
645
|
+
h && console.log("Progressive extension registered for", e), this.parser = t, this.url = e;
|
|
548
646
|
}
|
|
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?.[U];
|
|
651
|
+
return e ? (this._isLoadingMesh = !0, this.parser.getDependency("mesh", t).then((s) => (this._isLoadingMesh = !1, s && p.registerMesh(this.url, e.guid, s, e.lods?.length, 0, e), s))) : null;
|
|
554
652
|
};
|
|
555
653
|
// private _isLoadingTexture;
|
|
556
654
|
// loadTexture = (textureIndex: number) => {
|
|
@@ -567,64 +665,82 @@ class m {
|
|
|
567
665
|
// });
|
|
568
666
|
// }
|
|
569
667
|
afterRoot(t) {
|
|
570
|
-
return
|
|
668
|
+
return h && 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[U];
|
|
573
671
|
if (r) {
|
|
574
672
|
if (!r.lods) {
|
|
575
|
-
|
|
673
|
+
h && 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, p.registerTexture(this.url, o, r.lods?.length, s, r));
|
|
679
|
+
n || this.parser.getDependency("texture", s).then((o) => {
|
|
680
|
+
o && p.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[U];
|
|
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 && p.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
|
+
h && console.error("!! gltf-progressive: Called register texture without texture");
|
|
605
711
|
return;
|
|
606
712
|
}
|
|
607
|
-
if (
|
|
608
|
-
const
|
|
609
|
-
console.log(`> gltf-progressive: register texture[${r}] "${e.name || e.uuid}", Current: ${
|
|
713
|
+
if (h) {
|
|
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[ue] =
|
|
612
|
-
const o =
|
|
613
|
-
|
|
717
|
+
e.source && (e.source[ue] = n);
|
|
718
|
+
const o = n.guid;
|
|
719
|
+
p.assignLODInformation(t, e, o, s, r), p.lodInfos.set(o, n), p.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 (!
|
|
621
|
-
|
|
734
|
+
static registerMesh = (t, e, s, r, n, o) => {
|
|
735
|
+
const u = s.geometry;
|
|
736
|
+
if (!u) {
|
|
737
|
+
h && 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 = {}), h && console.log("> Progressive: register mesh " + s.name, { index: n, uuid: s.uuid }, o, s), p.assignLODInformation(t, u, e, r, n), p.lodInfos.set(e, o);
|
|
741
|
+
let l = p.lowresCache.get(e)?.deref();
|
|
742
|
+
l ? l.push(s.geometry) : l = [s.geometry], p.lowresCache.set(e, new WeakRef(l)), r > 0 && !ee(s) && ut(s, u);
|
|
743
|
+
for (const c of q)
|
|
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,16 +814,16 @@ 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
|
-
(
|
|
703
|
-
${t}`), e instanceof WeakRef && (e.deref() || (
|
|
817
|
+
const e = p.cache.get(t);
|
|
818
|
+
(h || J) && console.debug(`[gltf-progressive] Memory: Resource GC'd
|
|
819
|
+
${t}`), e instanceof WeakRef && (e.deref() || (p.cache.delete(t), (h || J) && console.log("[gltf-progressive] ↪ Cache entry deleted (GC)")));
|
|
704
820
|
});
|
|
705
821
|
/**
|
|
706
822
|
* Track texture usage by incrementing reference count
|
|
707
823
|
*/
|
|
708
824
|
static trackTextureUsage(t) {
|
|
709
825
|
const e = t.uuid, s = this.textureRefCounts.get(e) || 0;
|
|
710
|
-
this.textureRefCounts.set(e, s + 1),
|
|
826
|
+
this.textureRefCounts.set(e, s + 1), h === "verbose" && console.log(`[gltf-progressive] Track texture ${e}, refCount: ${s} → ${s + 1}`);
|
|
711
827
|
}
|
|
712
828
|
/**
|
|
713
829
|
* Untrack texture usage by decrementing reference count.
|
|
@@ -717,172 +833,175 @@ ${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 (
|
|
836
|
+
return (h === "verbose" || J) && 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), (
|
|
724
|
-
return this.textureRefCounts.set(e, r),
|
|
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), (h || J) && n("[gltf-progressive] Memory: Dispose texture", r), t.dispose(), !0;
|
|
840
|
+
return this.textureRefCounts.set(e, r), h === "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 f = "N/A";
|
|
844
|
+
a && l && (f = `~${(it(t) / (1024 * 1024)).toFixed(2)} MB`), console.log(`${o} — ${t.name} ${c} (${f}), refCount: ${s} → ${u}
|
|
730
845
|
${e}`);
|
|
731
846
|
}
|
|
732
847
|
}
|
|
733
848
|
static workers = [];
|
|
734
849
|
static _workersIndex = 0;
|
|
735
850
|
static async getOrLoadLOD(t, e) {
|
|
736
|
-
const s =
|
|
851
|
+
const s = h == "verbose", r = this.getAssignedLODInformation(t);
|
|
737
852
|
if (!r)
|
|
738
|
-
return
|
|
739
|
-
const
|
|
853
|
+
return h && console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`, t), null;
|
|
854
|
+
const n = r?.key;
|
|
740
855
|
let o;
|
|
741
856
|
if (t.isTexture === !0) {
|
|
742
857
|
const a = t;
|
|
743
858
|
a.source && a.source[ue] && (o = a.source[ue]);
|
|
744
859
|
}
|
|
745
|
-
if (o || (o =
|
|
746
|
-
|
|
860
|
+
if (o || (o = p.lodInfos.get(n)), !o)
|
|
861
|
+
h && console.warn(`Can not load LOD ${e}: no LOD info found for "${n}" ${t.name}`, t.type, p.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 f = Array.isArray(o.lods);
|
|
866
|
+
if (f && e >= o.lods.length ? c = !0 : f || (c = !0), c) {
|
|
867
|
+
const y = this.lowresCache.get(n);
|
|
868
|
+
if (y) {
|
|
869
|
+
const T = y.deref();
|
|
870
|
+
if (T) return T;
|
|
871
|
+
this.lowresCache.delete(n), h && console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${n}`);
|
|
757
872
|
}
|
|
758
873
|
return null;
|
|
759
874
|
}
|
|
760
875
|
}
|
|
761
876
|
const a = Array.isArray(o.lods) ? o.lods[e]?.path : o.lods;
|
|
762
877
|
if (!a)
|
|
763
|
-
return
|
|
764
|
-
const
|
|
765
|
-
if (
|
|
878
|
+
return h && !o["missing:uri"] && (o["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + e, o)), null;
|
|
879
|
+
const l = nt(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
|
-
if (d) {
|
|
773
|
-
let g = d, b = !1;
|
|
774
|
-
if (g instanceof F && t instanceof F ? g.image?.data || g.source?.data ? g = this.copySettings(t, g) : b = !0 : g instanceof E && t instanceof E && (g.attributes.position?.array || (b = !0)), !b)
|
|
775
|
-
return g;
|
|
776
|
-
}
|
|
777
|
-
this.cache.delete(c), f && console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${c}`);
|
|
778
|
-
} else {
|
|
779
|
-
let d = await w.catch((b) => (console.error(`Error loading LOD ${e} from ${u}
|
|
780
|
-
`, b), null)), g = !1;
|
|
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
|
-
}
|
|
883
|
+
const c = l + "_" + o.guid, f = await this.tryResolveLODCacheEntry(this.cache.get(c), c, l, t, e, s);
|
|
884
|
+
if (f.found) return f.value;
|
|
885
|
+
const y = await this.queue.slot(l), T = await this.tryResolveLODCacheEntry(this.cache.get(c), c, l, t, e, s);
|
|
886
|
+
if (T.found) return T.value;
|
|
784
887
|
if (!y.use)
|
|
785
|
-
return
|
|
786
|
-
const _ = o,
|
|
787
|
-
if (
|
|
788
|
-
const
|
|
789
|
-
if (
|
|
790
|
-
for (const
|
|
791
|
-
let
|
|
792
|
-
return
|
|
888
|
+
return h && console.log(`LOD ${e} was aborted: ${l}`), null;
|
|
889
|
+
const _ = o, C = new Promise(async (m, B) => {
|
|
890
|
+
if (mt) {
|
|
891
|
+
const d = await (await gt({})).load(l);
|
|
892
|
+
if (d.textures.length > 0)
|
|
893
|
+
for (const g of d.textures) {
|
|
894
|
+
let w = g.texture;
|
|
895
|
+
return p.assignLODInformation(r.url, w, n, e, void 0), t instanceof W && (w = this.copySettings(t, w)), w && (w.guid = _.guid), m(w);
|
|
793
896
|
}
|
|
794
|
-
if (
|
|
795
|
-
const
|
|
796
|
-
for (const
|
|
797
|
-
const
|
|
798
|
-
|
|
897
|
+
if (d.geometries.length > 0) {
|
|
898
|
+
const g = new Array();
|
|
899
|
+
for (const w of d.geometries) {
|
|
900
|
+
const v = w.geometry;
|
|
901
|
+
p.assignLODInformation(r.url, v, n, e, w.primitiveIndex), g.push(v);
|
|
799
902
|
}
|
|
800
|
-
return
|
|
903
|
+
return m(g);
|
|
801
904
|
}
|
|
802
|
-
return
|
|
905
|
+
return m(null);
|
|
803
906
|
}
|
|
804
|
-
const
|
|
805
|
-
|
|
806
|
-
let
|
|
907
|
+
const G = new xe();
|
|
908
|
+
Pe(G), h && (await new Promise((b) => setTimeout(b, 1e3)), s && console.warn("Start loading (delayed) " + l, _.guid));
|
|
909
|
+
let A = l;
|
|
807
910
|
if (_ && Array.isArray(_.lods)) {
|
|
808
|
-
const
|
|
809
|
-
|
|
911
|
+
const b = _.lods[e];
|
|
912
|
+
b.hash && (A += "?v=" + b.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 S = await G.loadAsync(A).catch((b) => (console.error(`Error loading LOD ${e} from ${l}
|
|
915
|
+
`, b), m(null)));
|
|
916
|
+
if (!S)
|
|
917
|
+
return m(null);
|
|
918
|
+
const F = S.parser;
|
|
919
|
+
s && console.log("Loading finished " + l, _.guid);
|
|
920
|
+
let M = 0;
|
|
921
|
+
if (S.parser.json.textures) {
|
|
922
|
+
let b = !1;
|
|
923
|
+
for (const d of S.parser.json.textures) {
|
|
924
|
+
if (d?.extensions) {
|
|
925
|
+
const g = d?.extensions[U];
|
|
926
|
+
if (g?.guid && g.guid === _.guid) {
|
|
927
|
+
b = !0;
|
|
825
928
|
break;
|
|
826
929
|
}
|
|
827
930
|
}
|
|
828
|
-
|
|
931
|
+
M++;
|
|
829
932
|
}
|
|
830
|
-
if (
|
|
831
|
-
let
|
|
832
|
-
return
|
|
833
|
-
} else
|
|
933
|
+
if (b) {
|
|
934
|
+
let d = await F.getDependency("texture", M);
|
|
935
|
+
return d && p.assignLODInformation(r.url, d, n, e, void 0), s && console.log('change "' + t.name + '" → "' + d.name + '"', l, M, d, c), t instanceof W && (d = this.copySettings(t, d)), d && (d.guid = _.guid), m(d);
|
|
936
|
+
} else h && console.warn("Could not find texture with guid", _.guid, S.parser.json);
|
|
834
937
|
}
|
|
835
|
-
if (
|
|
836
|
-
let
|
|
837
|
-
for (const
|
|
838
|
-
if (
|
|
839
|
-
const
|
|
840
|
-
if (
|
|
841
|
-
|
|
938
|
+
if (M = 0, S.parser.json.meshes) {
|
|
939
|
+
let b = !1;
|
|
940
|
+
for (const d of S.parser.json.meshes) {
|
|
941
|
+
if (d?.extensions) {
|
|
942
|
+
const g = d?.extensions[U];
|
|
943
|
+
if (g?.guid && g.guid === _.guid) {
|
|
944
|
+
b = !0;
|
|
842
945
|
break;
|
|
843
946
|
}
|
|
844
947
|
}
|
|
845
|
-
|
|
948
|
+
M++;
|
|
846
949
|
}
|
|
847
|
-
if (
|
|
848
|
-
const
|
|
849
|
-
if (s && console.log(`Loaded Mesh "${
|
|
850
|
-
const
|
|
851
|
-
return
|
|
950
|
+
if (b) {
|
|
951
|
+
const d = await F.getDependency("mesh", M);
|
|
952
|
+
if (s && console.log(`Loaded Mesh "${d.name}"`, l, M, d, c), d.isMesh === !0) {
|
|
953
|
+
const g = d.geometry;
|
|
954
|
+
return p.assignLODInformation(r.url, g, n, e, 0), m(g);
|
|
852
955
|
} else {
|
|
853
|
-
const
|
|
854
|
-
for (let
|
|
855
|
-
const
|
|
856
|
-
if (
|
|
857
|
-
const
|
|
858
|
-
|
|
956
|
+
const g = new Array();
|
|
957
|
+
for (let w = 0; w < d.children.length; w++) {
|
|
958
|
+
const v = d.children[w];
|
|
959
|
+
if (v.isMesh === !0) {
|
|
960
|
+
const O = v.geometry;
|
|
961
|
+
p.assignLODInformation(r.url, O, n, e, w), g.push(O);
|
|
859
962
|
}
|
|
860
963
|
}
|
|
861
|
-
return
|
|
964
|
+
return m(g);
|
|
862
965
|
}
|
|
863
|
-
} else
|
|
966
|
+
} else h && console.warn("Could not find mesh with guid", _.guid, S.parser.json);
|
|
864
967
|
}
|
|
865
|
-
return
|
|
968
|
+
return m(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, C), y.use(C);
|
|
971
|
+
const x = await C;
|
|
972
|
+
return x != null ? x instanceof W ? (this.cache.set(c, new WeakRef(x)), p._resourceRegistry.register(x, c)) : Array.isArray(x) ? this.cache.set(c, Promise.resolve(x)) : this.cache.set(c, Promise.resolve(x)) : this.cache.set(c, Promise.resolve(null)), x;
|
|
973
|
+
} else if (t instanceof W) {
|
|
974
|
+
s && console.log("Load texture from uri: " + l);
|
|
975
|
+
const f = await new Ve().loadAsync(l);
|
|
976
|
+
return f ? (f.guid = o.guid, f.flipY = !1, f.needsUpdate = !0, f.colorSpace = t.colorSpace, s && console.log(o, f)) : h && console.warn("failed loading", l), f;
|
|
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, f = !1;
|
|
988
|
+
if (c instanceof W && r instanceof W ? c.image?.data || c.source?.data ? c = this.copySettings(r, c) : f = !0 : c instanceof V && r instanceof V && (c.attributes.position?.array || (f = !0)), !f)
|
|
989
|
+
return { found: !0, value: c };
|
|
990
|
+
}
|
|
991
|
+
return this.cache.delete(e), h && 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 W && r instanceof W ? u.image?.data || u.source?.data ? u = this.copySettings(r, u) : (a = !0, this.cache.delete(e)) : u instanceof V && r instanceof V && (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 ot(Le() ? 20 : 50, { debug: h != !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 yt(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) {
|
|
@@ -890,12 +1009,12 @@ ${e}`);
|
|
|
890
1009
|
}
|
|
891
1010
|
// private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
|
|
892
1011
|
static copySettings(t, e) {
|
|
893
|
-
return e ? (
|
|
1012
|
+
return e ? (h === "verbose" && console.debug(`Copy texture settings
|
|
894
1013
|
`, t.uuid, `
|
|
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 yt {
|
|
899
1018
|
url;
|
|
900
1019
|
/** the key to lookup the LOD information */
|
|
901
1020
|
key;
|
|
@@ -908,8 +1027,8 @@ class pt {
|
|
|
908
1027
|
}
|
|
909
1028
|
class ce {
|
|
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", () => {
|
|
@@ -955,15 +1074,15 @@ class ce {
|
|
|
955
1074
|
_seen = /* @__PURE__ */ new WeakMap();
|
|
956
1075
|
add(t, e, s) {
|
|
957
1076
|
if (this._resolved) {
|
|
958
|
-
|
|
1077
|
+
h && console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");
|
|
959
1078
|
return;
|
|
960
1079
|
}
|
|
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
|
+
h && console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");
|
|
967
1086
|
return;
|
|
968
1087
|
}
|
|
969
1088
|
this._seen.set(e, r + 1);
|
|
@@ -982,8 +1101,41 @@ class ce {
|
|
|
982
1101
|
});
|
|
983
1102
|
}
|
|
984
1103
|
}
|
|
985
|
-
const R =
|
|
986
|
-
|
|
1104
|
+
const R = N("debugprogressive"), xt = R === "colors", wt = N("noprogressive"), de = /* @__PURE__ */ Symbol("Needle:LODSManager"), fe = /* @__PURE__ */ Symbol("Needle:LODState"), z = /* @__PURE__ */ Symbol("Needle:CurrentLOD"), D = { mesh_lod: -1, texture_lod: -1 }, Lt = new ke(), be = [
|
|
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
|
+
];
|
|
1138
|
+
class L {
|
|
987
1139
|
/**
|
|
988
1140
|
* 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
1141
|
*/
|
|
@@ -993,11 +1145,11 @@ class v {
|
|
|
993
1145
|
return t[fe];
|
|
994
1146
|
}
|
|
995
1147
|
static addPlugin(t) {
|
|
996
|
-
|
|
1148
|
+
q.push(t);
|
|
997
1149
|
}
|
|
998
1150
|
static removePlugin(t) {
|
|
999
|
-
const e =
|
|
1000
|
-
e >= 0 &&
|
|
1151
|
+
const e = q.indexOf(t);
|
|
1152
|
+
e >= 0 && q.splice(e, 1);
|
|
1001
1153
|
}
|
|
1002
1154
|
/**
|
|
1003
1155
|
* Gets the LODsManager for the given renderer. If the LODsManager does not exist yet, it will be created.
|
|
@@ -1007,7 +1159,7 @@ class v {
|
|
|
1007
1159
|
static get(t, e) {
|
|
1008
1160
|
if (t[de])
|
|
1009
1161
|
return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), t[de];
|
|
1010
|
-
const s = new
|
|
1162
|
+
const s = new L(t, {
|
|
1011
1163
|
engine: "unknown",
|
|
1012
1164
|
...e
|
|
1013
1165
|
});
|
|
@@ -1018,7 +1170,7 @@ class v {
|
|
|
1018
1170
|
projectionScreenMatrix = new ve();
|
|
1019
1171
|
/** @deprecated use static `LODsManager.addPlugin()` method. This getter will be removed in later versions */
|
|
1020
1172
|
get plugins() {
|
|
1021
|
-
return
|
|
1173
|
+
return q;
|
|
1022
1174
|
}
|
|
1023
1175
|
/**
|
|
1024
1176
|
* Force override the LOD level for all objects (meshes + textures) rendered in the scene
|
|
@@ -1056,15 +1208,39 @@ class v {
|
|
|
1056
1208
|
_newPromiseGroups = [];
|
|
1057
1209
|
_promiseGroupIds = 0;
|
|
1058
1210
|
/**
|
|
1059
|
-
*
|
|
1211
|
+
* Returns a promise that resolves once all LOD requests initiated during the next render cycles have finished loading.
|
|
1212
|
+
* This is useful for hiding low-resolution placeholders (e.g. with a loading overlay or CSS blur) until high-quality assets are ready.
|
|
1213
|
+
*
|
|
1214
|
+
* By default, the returned promise captures LOD loading requests for 2 frames and resolves when all of them complete.
|
|
1215
|
+
* Use `waitForFirstCapture` if no LOD requests may happen immediately (e.g. after a scene switch).
|
|
1216
|
+
*
|
|
1217
|
+
* @param opts - Optional configuration for how long to capture and what to wait for. See {@link PromiseGroupOptions}.
|
|
1218
|
+
* @returns A promise that resolves with `{ cancelled, awaited_count, resolved_count }` once all captured LOD loads complete (or the signal aborts).
|
|
1219
|
+
*
|
|
1220
|
+
* @example
|
|
1221
|
+
* ```ts
|
|
1222
|
+
* // Wait for initial LODs to finish loading, then remove a blur overlay
|
|
1223
|
+
* const result = await lodsManager.awaitLoading({
|
|
1224
|
+
* frames: 5,
|
|
1225
|
+
* signal: AbortSignal.timeout(10_000),
|
|
1226
|
+
* });
|
|
1227
|
+
* console.log(`Loaded ${result.resolved_count} of ${result.awaited_count} LODs`);
|
|
1228
|
+
* document.querySelector('.blur-overlay')?.remove();
|
|
1229
|
+
* ```
|
|
1230
|
+
*
|
|
1231
|
+
* @example
|
|
1232
|
+
* ```ts
|
|
1233
|
+
* // Wait until at least one LOD starts loading before resolving
|
|
1234
|
+
* await lodsManager.awaitLoading({ waitForFirstCapture: true });
|
|
1235
|
+
* ```
|
|
1060
1236
|
*/
|
|
1061
1237
|
awaitLoading(t) {
|
|
1062
1238
|
const e = this._promiseGroupIds++, s = new ce(this.#r, { ...t });
|
|
1063
1239
|
this._newPromiseGroups.push(s);
|
|
1064
1240
|
const r = performance.now();
|
|
1065
1241
|
return s.ready.finally(() => {
|
|
1066
|
-
const
|
|
1067
|
-
|
|
1242
|
+
const n = this._newPromiseGroups.indexOf(s);
|
|
1243
|
+
n >= 0 && (this._newPromiseGroups.splice(n, 1), Me() && performance.measure("LODsManager:awaitLoading", {
|
|
1068
1244
|
start: r,
|
|
1069
1245
|
detail: { id: e, name: t?.name, awaited: s.awaitedCount, resolved: s.resolvedCount }
|
|
1070
1246
|
}));
|
|
@@ -1076,24 +1252,50 @@ class v {
|
|
|
1076
1252
|
this._newPromiseGroups[t].update(this.#r);
|
|
1077
1253
|
}
|
|
1078
1254
|
_lodchangedlisteners = [];
|
|
1255
|
+
/**
|
|
1256
|
+
* Register a listener that is called whenever a mesh or texture LOD level has finished loading and has been applied.
|
|
1257
|
+
* The listener receives the type of asset (`"mesh"` or `"texture"`), the new LOD level, and the affected object.
|
|
1258
|
+
*
|
|
1259
|
+
* @param evt - The event type. Currently only `"changed"` is supported.
|
|
1260
|
+
* @param listener - Callback invoked after a LOD swap completes.
|
|
1261
|
+
* @return A function to unregister the listener.
|
|
1262
|
+
*
|
|
1263
|
+
* @example
|
|
1264
|
+
* ```ts
|
|
1265
|
+
* lodsManager.addEventListener("changed", ({ type, level, object }) => {
|
|
1266
|
+
* console.log(`${type} LOD changed to level ${level}`, object);
|
|
1267
|
+
* });
|
|
1268
|
+
* ```
|
|
1269
|
+
*/
|
|
1079
1270
|
addEventListener(t, e) {
|
|
1080
|
-
t === "changed"
|
|
1271
|
+
return t === "changed" ? (this._lodchangedlisteners.push(e), () => {
|
|
1272
|
+
this.removeEventListener(t, e);
|
|
1273
|
+
}) : () => {
|
|
1274
|
+
};
|
|
1081
1275
|
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Remove a previously registered `"changed"` event listener.
|
|
1278
|
+
* @param evt - The event type (`"changed"`).
|
|
1279
|
+
* @param listener - The listener to remove.
|
|
1280
|
+
* @return `true` if the listener was found and removed, `false` otherwise.
|
|
1281
|
+
*/
|
|
1082
1282
|
removeEventListener(t, e) {
|
|
1283
|
+
let s = !1;
|
|
1083
1284
|
if (t === "changed") {
|
|
1084
|
-
const
|
|
1085
|
-
|
|
1285
|
+
const r = this._lodchangedlisteners.indexOf(e);
|
|
1286
|
+
r >= 0 && (this._lodchangedlisteners.splice(r, 1), s = !0);
|
|
1086
1287
|
}
|
|
1288
|
+
return s;
|
|
1087
1289
|
}
|
|
1088
1290
|
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
1089
1291
|
constructor(t, e) {
|
|
1090
1292
|
this.renderer = t, this.context = { ...e };
|
|
1091
1293
|
}
|
|
1092
1294
|
#t;
|
|
1093
|
-
#o = new
|
|
1295
|
+
#o = new Xe();
|
|
1094
1296
|
#r = 0;
|
|
1095
|
-
#i = 0;
|
|
1096
1297
|
#n = 0;
|
|
1298
|
+
#i = 0;
|
|
1097
1299
|
#s = 0;
|
|
1098
1300
|
_fpsBuffer = [60, 60, 60, 60, 60];
|
|
1099
1301
|
/**
|
|
@@ -1106,8 +1308,8 @@ class v {
|
|
|
1106
1308
|
this.#t = this.renderer.render;
|
|
1107
1309
|
const e = this;
|
|
1108
1310
|
we(this.renderer), this.renderer.render = function(s, r) {
|
|
1109
|
-
const
|
|
1110
|
-
(
|
|
1311
|
+
const n = e.renderer.getRenderTarget();
|
|
1312
|
+
(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, R && e.#r % 200 === 0 && console.log("FPS", Math.round(e.#s), "Interval:", e.#e));
|
|
1111
1313
|
const o = t++;
|
|
1112
1314
|
e.#t.call(this, s, r), e.onAfterRender(s, r, o);
|
|
1113
1315
|
};
|
|
@@ -1115,19 +1317,34 @@ class v {
|
|
|
1115
1317
|
disable() {
|
|
1116
1318
|
this.#t && (console.debug("[gltf-progressive] Disabling LODsManager for renderer"), this.renderer.render = this.#t, this.#t = void 0);
|
|
1117
1319
|
}
|
|
1320
|
+
/**
|
|
1321
|
+
* Manually trigger a LOD update for a scene and camera.
|
|
1322
|
+
* Only needed when {@link manual} is set to `true` — otherwise LOD updates happen automatically on each render call.
|
|
1323
|
+
*
|
|
1324
|
+
* @param scene - The scene containing objects with progressive LODs.
|
|
1325
|
+
* @param camera - The camera used to determine screen coverage and LOD levels.
|
|
1326
|
+
*
|
|
1327
|
+
* @example
|
|
1328
|
+
* ```ts
|
|
1329
|
+
* const lodsManager = LODsManager.get(renderer);
|
|
1330
|
+
* lodsManager.manual = true;
|
|
1331
|
+
* // ... later, trigger an update at a specific point:
|
|
1332
|
+
* lodsManager.update(scene, camera);
|
|
1333
|
+
* ```
|
|
1334
|
+
*/
|
|
1118
1335
|
update(t, e) {
|
|
1119
1336
|
this.internalUpdate(t, e);
|
|
1120
1337
|
}
|
|
1121
1338
|
onAfterRender(t, e, s) {
|
|
1122
1339
|
if (this.pause) return;
|
|
1123
|
-
const
|
|
1340
|
+
const n = this.renderer.renderLists.get(t, 0).opaque;
|
|
1124
1341
|
let o = !0;
|
|
1125
|
-
if (
|
|
1126
|
-
const
|
|
1127
|
-
(
|
|
1342
|
+
if (n.length === 1) {
|
|
1343
|
+
const u = n[0].material;
|
|
1344
|
+
(u.name === "EffectMaterial" || u.name === "CopyShader") && (o = !1);
|
|
1128
1345
|
}
|
|
1129
1346
|
if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (o = !1), o) {
|
|
1130
|
-
if (
|
|
1347
|
+
if (wt || (this.updateInterval === "auto" ? this.#s < 40 && this.#e < 10 ? (this.#e += 1, R && console.warn("↓ Reducing LOD updates", this.#e, this.#s.toFixed(0))) : this.#s >= 60 && this.#e > 1 && (this.#e -= 1, R && console.warn("↑ Increasing LOD updates", this.#e, this.#s.toFixed(0))) : this.#e = this.updateInterval, this.#e > 0 && this.#r % this.#e != 0))
|
|
1131
1348
|
return;
|
|
1132
1349
|
this.internalUpdate(t, e), this._postprocessPromiseGroups();
|
|
1133
1350
|
}
|
|
@@ -1138,7 +1355,7 @@ class v {
|
|
|
1138
1355
|
internalUpdate(t, e) {
|
|
1139
1356
|
const s = this.renderer.renderLists.get(t, 0), r = s.opaque;
|
|
1140
1357
|
this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix, e.matrixWorldInverse);
|
|
1141
|
-
const
|
|
1358
|
+
const n = this.targetTriangleDensity;
|
|
1142
1359
|
for (const a of r) {
|
|
1143
1360
|
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
1361
|
R && (a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] || (a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] = !0, console.warn("Ignoring skybox or BLIT object", a, a.material.name, a.material.type)));
|
|
@@ -1153,38 +1370,33 @@ class v {
|
|
|
1153
1370
|
case "MeshDepthMaterial":
|
|
1154
1371
|
continue;
|
|
1155
1372
|
}
|
|
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);
|
|
1373
|
+
const l = a.object;
|
|
1374
|
+
(l instanceof X || l.isMesh) && this.updateLODs(t, e, l, n);
|
|
1163
1375
|
}
|
|
1164
1376
|
const o = s.transparent;
|
|
1165
1377
|
for (const a of o) {
|
|
1166
|
-
const
|
|
1167
|
-
(
|
|
1378
|
+
const l = a.object;
|
|
1379
|
+
(l instanceof X || l.isMesh) && this.updateLODs(t, e, l, n);
|
|
1168
1380
|
}
|
|
1169
|
-
const
|
|
1170
|
-
for (const a of
|
|
1171
|
-
const
|
|
1172
|
-
(
|
|
1381
|
+
const u = s.transmissive;
|
|
1382
|
+
for (const a of u) {
|
|
1383
|
+
const l = a.object;
|
|
1384
|
+
(l instanceof X || l.isMesh) && this.updateLODs(t, e, l, n);
|
|
1173
1385
|
}
|
|
1174
1386
|
}
|
|
1175
1387
|
/** Update the LOD levels for the renderer. */
|
|
1176
1388
|
updateLODs(t, e, s, r) {
|
|
1177
1389
|
s.userData || (s.userData = {});
|
|
1178
|
-
let
|
|
1179
|
-
if (
|
|
1390
|
+
let n = s[fe];
|
|
1391
|
+
if (n || (n = new _t(), s[fe] = n), n.frames++ < 2)
|
|
1180
1392
|
return;
|
|
1181
|
-
for (const
|
|
1182
|
-
|
|
1183
|
-
const o = this.overrideLodLevel !== void 0 ? this.overrideLodLevel :
|
|
1184
|
-
o >= 0 ? (
|
|
1185
|
-
for (const
|
|
1186
|
-
|
|
1187
|
-
|
|
1393
|
+
for (const u of q)
|
|
1394
|
+
u.onBeforeUpdateLOD?.(this.renderer, t, e, s);
|
|
1395
|
+
const o = this.overrideLodLevel !== void 0 ? this.overrideLodLevel : E;
|
|
1396
|
+
o >= 0 ? (D.mesh_lod = o, D.texture_lod = o) : (this.calculateLodLevel(e, s, n, r, D), D.mesh_lod = Math.round(D.mesh_lod), D.texture_lod = Math.round(D.texture_lod)), D.mesh_lod >= 0 && this.loadProgressiveMeshes(s, D.mesh_lod), s.material && D.texture_lod >= 0 && this.loadProgressiveTextures(s.material, D.texture_lod, o), h && s.material && !s.isGizmo && Ie(s.material), xt && s.material && !s.isGizmo && !s.isBatchedMesh && $e(s.material, D.mesh_lod);
|
|
1397
|
+
for (const u of q)
|
|
1398
|
+
u.onAfterUpdatedLOD?.(this.renderer, t, e, s, D);
|
|
1399
|
+
n.lastLodLevel_Mesh = D.mesh_lod, n.lastLodLevel_Texture = D.texture_lod;
|
|
1188
1400
|
}
|
|
1189
1401
|
/** Load progressive textures for the given material
|
|
1190
1402
|
* @param material the material to load the textures for
|
|
@@ -1194,17 +1406,19 @@ class v {
|
|
|
1194
1406
|
loadProgressiveTextures(t, e, s) {
|
|
1195
1407
|
if (!t) return;
|
|
1196
1408
|
if (Array.isArray(t)) {
|
|
1197
|
-
for (const
|
|
1198
|
-
this.loadProgressiveTextures(
|
|
1409
|
+
for (const o of t)
|
|
1410
|
+
this.loadProgressiveTextures(o, e, s);
|
|
1199
1411
|
return;
|
|
1200
1412
|
}
|
|
1201
1413
|
let r = !1;
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1414
|
+
(t[z] === void 0 || e < t[z]) && (r = !0);
|
|
1415
|
+
const n = s !== void 0 && s >= 0;
|
|
1416
|
+
if (n && (r = t[z] != s, e = s), r) {
|
|
1417
|
+
t[z] = e;
|
|
1418
|
+
const o = n ? { force: !0 } : void 0, u = p.assignTextureLOD(t, e, o).then((a) => {
|
|
1205
1419
|
this._lodchangedlisteners.forEach((l) => l({ type: "texture", level: e, object: t }));
|
|
1206
1420
|
});
|
|
1207
|
-
ce.addPromise("texture", t,
|
|
1421
|
+
ce.addPromise("texture", t, u, this._newPromiseGroups);
|
|
1208
1422
|
}
|
|
1209
1423
|
}
|
|
1210
1424
|
/** Load progressive meshes for the given mesh
|
|
@@ -1215,143 +1429,143 @@ class v {
|
|
|
1215
1429
|
*/
|
|
1216
1430
|
loadProgressiveMeshes(t, e) {
|
|
1217
1431
|
if (!t) return Promise.resolve(null);
|
|
1218
|
-
let s = t[
|
|
1432
|
+
let s = t[z] !== e;
|
|
1219
1433
|
const r = t["DEBUG:LOD"];
|
|
1220
|
-
if (r != null && (s = t[
|
|
1221
|
-
t[
|
|
1222
|
-
const
|
|
1434
|
+
if (r != null && (s = t[z] != r, e = r), s) {
|
|
1435
|
+
t[z] = e;
|
|
1436
|
+
const n = t.geometry, o = p.assignMeshLOD(t, e).then((u) => (u && t[z] == e && n != t.geometry && this._lodchangedlisteners.forEach((a) => a({ type: "mesh", level: e, object: t })), u));
|
|
1223
1437
|
return ce.addPromise("mesh", t, o, this._newPromiseGroups), o;
|
|
1224
1438
|
}
|
|
1225
1439
|
return Promise.resolve(null);
|
|
1226
1440
|
}
|
|
1227
1441
|
// private testIfLODLevelsAreAvailable() {
|
|
1228
|
-
_sphere = new
|
|
1442
|
+
_sphere = new Oe();
|
|
1229
1443
|
_tempBox = new ge();
|
|
1230
1444
|
_tempBox2 = new ge();
|
|
1231
1445
|
tempMatrix = new ve();
|
|
1232
|
-
_tempWorldPosition = new
|
|
1233
|
-
_tempBoxSize = new
|
|
1234
|
-
_tempBox2Size = new
|
|
1235
|
-
static corner0 = new
|
|
1236
|
-
static corner1 = new
|
|
1237
|
-
static corner2 = new
|
|
1238
|
-
static corner3 = new
|
|
1239
|
-
static _tempPtInside = new
|
|
1446
|
+
_tempWorldPosition = new P();
|
|
1447
|
+
_tempBoxSize = new P();
|
|
1448
|
+
_tempBox2Size = new P();
|
|
1449
|
+
static corner0 = new P();
|
|
1450
|
+
static corner1 = new P();
|
|
1451
|
+
static corner2 = new P();
|
|
1452
|
+
static corner3 = new P();
|
|
1453
|
+
static _tempPtInside = new P();
|
|
1240
1454
|
static isInside(t, e) {
|
|
1241
|
-
const s = t.min, r = t.max,
|
|
1242
|
-
return this._tempPtInside.set(
|
|
1455
|
+
const s = t.min, r = t.max, n = (s.x + r.x) * 0.5, o = (s.y + r.y) * 0.5;
|
|
1456
|
+
return this._tempPtInside.set(n, o, s.z).applyMatrix4(e).z < 0;
|
|
1243
1457
|
}
|
|
1244
1458
|
static skinnedMeshBoundsFrameOffsetCounter = 0;
|
|
1245
1459
|
static $skinnedMeshBoundsOffset = /* @__PURE__ */ Symbol("gltf-progressive-skinnedMeshBoundsOffset");
|
|
1246
1460
|
// #region calculateLodLevel
|
|
1247
|
-
calculateLodLevel(t, e, s, r,
|
|
1461
|
+
calculateLodLevel(t, e, s, r, n) {
|
|
1248
1462
|
if (!e) {
|
|
1249
|
-
|
|
1463
|
+
n.mesh_lod = -1, n.texture_lod = -1;
|
|
1250
1464
|
return;
|
|
1251
1465
|
}
|
|
1252
1466
|
if (!t) {
|
|
1253
|
-
|
|
1467
|
+
n.mesh_lod = -1, n.texture_lod = -1;
|
|
1254
1468
|
return;
|
|
1255
1469
|
}
|
|
1256
|
-
let
|
|
1470
|
+
let u = 10 + 1, a = !1;
|
|
1257
1471
|
if (R && e["DEBUG:LOD"] != null)
|
|
1258
1472
|
return e["DEBUG:LOD"];
|
|
1259
|
-
const
|
|
1260
|
-
if (!
|
|
1261
|
-
|
|
1473
|
+
const l = p.getMeshLODExtension(e.geometry)?.lods, c = p.getPrimitiveIndex(e.geometry), f = l && l.length > 0, y = p.getMaterialMinMaxLODsCount(e.material), T = y.min_count !== 1 / 0 && y.min_count >= 0 && y.max_count >= 0;
|
|
1474
|
+
if (!f && !T) {
|
|
1475
|
+
n.mesh_lod = 0, n.texture_lod = 0;
|
|
1262
1476
|
return;
|
|
1263
1477
|
}
|
|
1264
|
-
|
|
1265
|
-
const
|
|
1266
|
-
let
|
|
1478
|
+
f || (a = !0, u = 0);
|
|
1479
|
+
const _ = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
|
|
1480
|
+
let C = e.geometry.boundingBox;
|
|
1267
1481
|
if (e.type === "SkinnedMesh") {
|
|
1268
|
-
const
|
|
1269
|
-
if (!
|
|
1270
|
-
|
|
1482
|
+
const x = e;
|
|
1483
|
+
if (!x.boundingBox)
|
|
1484
|
+
x.computeBoundingBox();
|
|
1271
1485
|
else if (this.skinnedMeshAutoUpdateBoundsInterval > 0) {
|
|
1272
|
-
if (!
|
|
1273
|
-
const
|
|
1274
|
-
|
|
1486
|
+
if (!x[L.$skinnedMeshBoundsOffset]) {
|
|
1487
|
+
const B = L.skinnedMeshBoundsFrameOffsetCounter++;
|
|
1488
|
+
x[L.$skinnedMeshBoundsOffset] = B;
|
|
1275
1489
|
}
|
|
1276
|
-
const
|
|
1277
|
-
if ((s.frames +
|
|
1278
|
-
const
|
|
1279
|
-
|
|
1490
|
+
const m = x[L.$skinnedMeshBoundsOffset];
|
|
1491
|
+
if ((s.frames + m) % this.skinnedMeshAutoUpdateBoundsInterval === 0) {
|
|
1492
|
+
const B = ee(x), G = x.geometry;
|
|
1493
|
+
B && (x.geometry = B), x.computeBoundingBox(), x.geometry = G;
|
|
1280
1494
|
}
|
|
1281
1495
|
}
|
|
1282
|
-
|
|
1496
|
+
C = x.boundingBox;
|
|
1283
1497
|
}
|
|
1284
|
-
if (
|
|
1285
|
-
const
|
|
1498
|
+
if (C) {
|
|
1499
|
+
const x = t;
|
|
1286
1500
|
if (e.geometry.attributes.color && e.geometry.attributes.color.count < 100 && e.geometry.boundingSphere) {
|
|
1287
1501
|
this._sphere.copy(e.geometry.boundingSphere), this._sphere.applyMatrix4(e.matrixWorld);
|
|
1288
|
-
const
|
|
1289
|
-
if (this._sphere.containsPoint(
|
|
1290
|
-
|
|
1502
|
+
const d = t.getWorldPosition(this._tempWorldPosition);
|
|
1503
|
+
if (this._sphere.containsPoint(d)) {
|
|
1504
|
+
n.mesh_lod = 0, n.texture_lod = 0;
|
|
1291
1505
|
return;
|
|
1292
1506
|
}
|
|
1293
1507
|
}
|
|
1294
|
-
if (this._tempBox.copy(
|
|
1295
|
-
|
|
1508
|
+
if (this._tempBox.copy(C), this._tempBox.applyMatrix4(e.matrixWorld), x.isPerspectiveCamera && L.isInside(this._tempBox, this.projectionScreenMatrix)) {
|
|
1509
|
+
n.mesh_lod = 0, n.texture_lod = 0;
|
|
1296
1510
|
return;
|
|
1297
1511
|
}
|
|
1298
|
-
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled &&
|
|
1299
|
-
const
|
|
1300
|
-
let
|
|
1301
|
-
const te = 2,
|
|
1302
|
-
|
|
1303
|
-
const
|
|
1304
|
-
s.lastCentrality = (
|
|
1512
|
+
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && x.isPerspectiveCamera && x.fov > 70) {
|
|
1513
|
+
const d = this._tempBox.min, g = this._tempBox.max;
|
|
1514
|
+
let w = d.x, v = d.y, O = g.x, Y = g.y;
|
|
1515
|
+
const te = 2, ie = 1.5, se = (d.x + g.x) * 0.5, re = (d.y + g.y) * 0.5;
|
|
1516
|
+
w = (w - se) * te + se, v = (v - re) * te + re, O = (O - se) * te + se, Y = (Y - re) * te + re;
|
|
1517
|
+
const We = w < 0 && O > 0 ? 0 : Math.min(Math.abs(d.x), Math.abs(g.x)), Fe = v < 0 && Y > 0 ? 0 : Math.min(Math.abs(d.y), Math.abs(g.y)), ae = Math.max(We, Fe);
|
|
1518
|
+
s.lastCentrality = (ie - ae) * (ie - ae) * (ie - ae);
|
|
1305
1519
|
} else
|
|
1306
1520
|
s.lastCentrality = 1;
|
|
1307
|
-
const
|
|
1308
|
-
|
|
1309
|
-
const
|
|
1310
|
-
|
|
1311
|
-
const
|
|
1312
|
-
if (Math.max(
|
|
1313
|
-
const
|
|
1314
|
-
|
|
1315
|
-
const
|
|
1316
|
-
|
|
1317
|
-
const Y = (
|
|
1318
|
-
|
|
1521
|
+
const m = this._tempBox.getSize(this._tempBoxSize);
|
|
1522
|
+
m.multiplyScalar(0.5), screen.availHeight > 0 && _ > 0 && m.multiplyScalar(_ / screen.availHeight), t.isPerspectiveCamera ? m.x *= t.aspect : t.isOrthographicCamera;
|
|
1523
|
+
const B = t.matrixWorldInverse, G = this._tempBox2;
|
|
1524
|
+
G.copy(C), G.applyMatrix4(e.matrixWorld), G.applyMatrix4(B);
|
|
1525
|
+
const A = G.getSize(this._tempBox2Size), S = Math.max(A.x, A.y);
|
|
1526
|
+
if (Math.max(m.x, m.y) != 0 && S != 0 && (m.z = A.z / Math.max(A.x, A.y) * Math.max(m.x, m.y)), s.lastScreenCoverage = Math.max(m.x, m.y, m.z), s.lastScreenspaceVolume.copy(m), s.lastScreenCoverage *= s.lastCentrality, R && L.debugDrawLine) {
|
|
1527
|
+
const d = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
1528
|
+
d.invert();
|
|
1529
|
+
const g = L.corner0, w = L.corner1, v = L.corner2, O = L.corner3;
|
|
1530
|
+
g.copy(this._tempBox.min), w.copy(this._tempBox.max), w.x = g.x, v.copy(this._tempBox.max), v.y = g.y, O.copy(this._tempBox.max);
|
|
1531
|
+
const Y = (g.z + O.z) * 0.5;
|
|
1532
|
+
g.z = w.z = v.z = O.z = Y, g.applyMatrix4(d), w.applyMatrix4(d), v.applyMatrix4(d), O.applyMatrix4(d), L.debugDrawLine(g, w, 255), L.debugDrawLine(g, v, 255), L.debugDrawLine(w, O, 255), L.debugDrawLine(v, O, 255);
|
|
1319
1533
|
}
|
|
1320
|
-
let
|
|
1321
|
-
if (
|
|
1322
|
-
for (let
|
|
1323
|
-
const
|
|
1324
|
-
if (c > 0 &&
|
|
1325
|
-
|
|
1534
|
+
let M = 999;
|
|
1535
|
+
if (l && s.lastScreenCoverage > 0)
|
|
1536
|
+
for (let d = 0; d < l.length; d++) {
|
|
1537
|
+
const g = l[d], v = (g.densities?.[c] || g.density || 1e-5) / s.lastScreenCoverage;
|
|
1538
|
+
if (c > 0 && Me() && !g.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.")), v < r) {
|
|
1539
|
+
M = d;
|
|
1326
1540
|
break;
|
|
1327
1541
|
}
|
|
1328
1542
|
}
|
|
1329
|
-
|
|
1543
|
+
M < u && (u = M, a = !0);
|
|
1330
1544
|
}
|
|
1331
|
-
if (a ?
|
|
1332
|
-
const
|
|
1333
|
-
|
|
1545
|
+
if (a ? n.mesh_lod = u : n.mesh_lod = s.lastLodLevel_Mesh, R && n.mesh_lod != s.lastLodLevel_Mesh) {
|
|
1546
|
+
const m = l?.[n.mesh_lod];
|
|
1547
|
+
m && console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${n.mesh_lod} (density: ${m.densities?.[c].toFixed(0)}) | ${e.name}`);
|
|
1334
1548
|
}
|
|
1335
|
-
if (
|
|
1336
|
-
const
|
|
1549
|
+
if (T) {
|
|
1550
|
+
const x = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
|
|
1337
1551
|
if (s.lastLodLevel_Texture < 0) {
|
|
1338
|
-
if (
|
|
1339
|
-
const
|
|
1340
|
-
R && console.log(`First Texture LOD ${
|
|
1552
|
+
if (n.texture_lod = y.max_count - 1, R) {
|
|
1553
|
+
const m = y.lods[y.max_count - 1];
|
|
1554
|
+
R && console.log(`First Texture LOD ${n.texture_lod} (${m.max_height}px) - ${e.name}`);
|
|
1341
1555
|
}
|
|
1342
1556
|
} 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: ${
|
|
1557
|
+
const m = s.lastScreenspaceVolume.x + s.lastScreenspaceVolume.y + s.lastScreenspaceVolume.z;
|
|
1558
|
+
let B = s.lastScreenCoverage * 4;
|
|
1559
|
+
this.context?.engine === "model-viewer" && (B *= 1.5);
|
|
1560
|
+
const A = _ / window.devicePixelRatio * B;
|
|
1561
|
+
let S = !1;
|
|
1562
|
+
for (let F = y.lods.length - 1; F >= 0; F--) {
|
|
1563
|
+
const M = y.lods[F];
|
|
1564
|
+
if (!(x && M.max_height >= 2048) && !(Le() && M.max_height > 4096) && (M.max_height > A || !S && F === 0)) {
|
|
1565
|
+
if (S = !0, n.texture_lod = F, R && n.texture_lod < s.lastLodLevel_Texture) {
|
|
1566
|
+
const b = M.max_height;
|
|
1567
|
+
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${n.texture_lod} = ${b}px
|
|
1568
|
+
Screensize: ${A.toFixed(0)}px, Coverage: ${(100 * s.lastScreenCoverage).toFixed(2)}%, Volume ${m.toFixed(1)}
|
|
1355
1569
|
${e.name}`);
|
|
1356
1570
|
}
|
|
1357
1571
|
break;
|
|
@@ -1359,83 +1573,98 @@ ${e.name}`);
|
|
|
1359
1573
|
}
|
|
1360
1574
|
}
|
|
1361
1575
|
} else
|
|
1362
|
-
|
|
1576
|
+
n.texture_lod = 0;
|
|
1363
1577
|
}
|
|
1364
1578
|
}
|
|
1365
|
-
class
|
|
1579
|
+
class _t {
|
|
1366
1580
|
frames = 0;
|
|
1367
1581
|
lastLodLevel_Mesh = -1;
|
|
1368
1582
|
lastLodLevel_Texture = -1;
|
|
1369
1583
|
lastScreenCoverage = 0;
|
|
1370
|
-
lastScreenspaceVolume = new
|
|
1584
|
+
lastScreenspaceVolume = new P();
|
|
1371
1585
|
lastCentrality = 0;
|
|
1372
1586
|
}
|
|
1373
|
-
|
|
1587
|
+
function $e(i, t) {
|
|
1588
|
+
if (!(t < 0)) {
|
|
1589
|
+
if (Array.isArray(i)) {
|
|
1590
|
+
for (const e of i)
|
|
1591
|
+
$e(e, t);
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1594
|
+
"color" in i && i.color instanceof ke && (i.color.copy(vt(t, Lt)), i.needsUpdate = !0);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
function vt(i, t) {
|
|
1598
|
+
const e = Math.max(0, Math.min(be.length - 1, Math.floor(i)));
|
|
1599
|
+
return t.setHex(be[e]);
|
|
1600
|
+
}
|
|
1601
|
+
const De = /* @__PURE__ */ Symbol("NEEDLE_mesh_lod"), ne = /* @__PURE__ */ Symbol("NEEDLE_texture_lod");
|
|
1374
1602
|
let he = null;
|
|
1375
|
-
function
|
|
1376
|
-
const
|
|
1377
|
-
|
|
1378
|
-
return
|
|
1379
|
-
}),
|
|
1603
|
+
function Be() {
|
|
1604
|
+
const i = Mt();
|
|
1605
|
+
i && (i.mapURLs(function(t) {
|
|
1606
|
+
return Te(), t;
|
|
1607
|
+
}), Te(), he?.disconnect(), he = new MutationObserver((t) => {
|
|
1380
1608
|
t.forEach((e) => {
|
|
1381
1609
|
e.addedNodes.forEach((s) => {
|
|
1382
|
-
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" &&
|
|
1610
|
+
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" && Ge(s);
|
|
1383
1611
|
});
|
|
1384
1612
|
});
|
|
1385
1613
|
}), he.observe(document, { childList: !0, subtree: !0 }));
|
|
1386
1614
|
}
|
|
1387
|
-
function
|
|
1615
|
+
function Mt() {
|
|
1388
1616
|
if (typeof customElements > "u") return null;
|
|
1389
|
-
const
|
|
1390
|
-
return
|
|
1391
|
-
console.debug("[gltf-progressive] model-viewer defined"),
|
|
1617
|
+
const i = customElements.get("model-viewer");
|
|
1618
|
+
return i || (customElements.whenDefined("model-viewer").then(() => {
|
|
1619
|
+
console.debug("[gltf-progressive] model-viewer defined"), Be();
|
|
1392
1620
|
}), null);
|
|
1393
1621
|
}
|
|
1394
|
-
function
|
|
1622
|
+
function Te() {
|
|
1395
1623
|
if (typeof document > "u") return;
|
|
1396
1624
|
document.querySelectorAll("model-viewer").forEach((t) => {
|
|
1397
|
-
|
|
1625
|
+
Ge(t);
|
|
1398
1626
|
});
|
|
1399
1627
|
}
|
|
1400
|
-
const
|
|
1401
|
-
let
|
|
1402
|
-
function
|
|
1403
|
-
if (!
|
|
1628
|
+
const Se = /* @__PURE__ */ new WeakSet();
|
|
1629
|
+
let bt = 0;
|
|
1630
|
+
function Ge(i) {
|
|
1631
|
+
if (!i || Se.has(i))
|
|
1404
1632
|
return null;
|
|
1405
|
-
|
|
1406
|
-
`,
|
|
1633
|
+
Se.add(i), console.debug("[gltf-progressive] found new model-viewer..." + ++bt + `
|
|
1634
|
+
`, i.getAttribute("src"));
|
|
1407
1635
|
let t = null, e = null, s = null;
|
|
1408
|
-
for (let r =
|
|
1409
|
-
const
|
|
1410
|
-
!t && o != null && (t =
|
|
1636
|
+
for (let r = i; r != null; r = Object.getPrototypeOf(r)) {
|
|
1637
|
+
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)");
|
|
1638
|
+
!t && o != null && (t = i[o].threeRenderer), !e && u != null && (e = i[u]), !s && a != null && (s = i[a]);
|
|
1411
1639
|
}
|
|
1412
1640
|
if (t && e) {
|
|
1413
1641
|
let r = function() {
|
|
1414
1642
|
if (s) {
|
|
1415
|
-
let o = 0
|
|
1643
|
+
let o = 0;
|
|
1644
|
+
const u = setInterval(() => {
|
|
1416
1645
|
if (o++ > 5) {
|
|
1417
|
-
clearInterval(
|
|
1646
|
+
clearInterval(u);
|
|
1418
1647
|
return;
|
|
1419
1648
|
}
|
|
1420
|
-
s?.call(
|
|
1649
|
+
s?.call(i);
|
|
1421
1650
|
}, 300);
|
|
1422
1651
|
}
|
|
1423
1652
|
};
|
|
1424
1653
|
console.debug("[gltf-progressive] setup model-viewer");
|
|
1425
|
-
const
|
|
1426
|
-
return
|
|
1427
|
-
s?.call(
|
|
1428
|
-
}),
|
|
1429
|
-
o.detail.visible && s?.call(
|
|
1430
|
-
}),
|
|
1654
|
+
const n = L.get(t, { engine: "model-viewer" });
|
|
1655
|
+
return L.addPlugin(new Dt()), n.enable(), n.addEventListener("changed", () => {
|
|
1656
|
+
s?.call(i);
|
|
1657
|
+
}), i.addEventListener("model-visibility", (o) => {
|
|
1658
|
+
o.detail.visible && s?.call(i);
|
|
1659
|
+
}), i.addEventListener("load", () => {
|
|
1431
1660
|
r();
|
|
1432
1661
|
}), () => {
|
|
1433
|
-
|
|
1662
|
+
n.disable();
|
|
1434
1663
|
};
|
|
1435
1664
|
}
|
|
1436
1665
|
return null;
|
|
1437
1666
|
}
|
|
1438
|
-
class
|
|
1667
|
+
class Dt {
|
|
1439
1668
|
_didWarnAboutMissingUrl = !1;
|
|
1440
1669
|
onBeforeUpdateLOD(t, e, s, r) {
|
|
1441
1670
|
this.tryParseMeshLOD(e, r), this.tryParseTextureLOD(e, r);
|
|
@@ -1453,101 +1682,103 @@ class _t {
|
|
|
1453
1682
|
return t.element;
|
|
1454
1683
|
}
|
|
1455
1684
|
tryParseTextureLOD(t, e) {
|
|
1456
|
-
if (e[
|
|
1457
|
-
e[
|
|
1458
|
-
const s = this.tryGetCurrentGLTF(t), r = this.tryGetCurrentModelViewer(t),
|
|
1459
|
-
if (
|
|
1685
|
+
if (e[ne] == !0) return;
|
|
1686
|
+
e[ne] = !0;
|
|
1687
|
+
const s = this.tryGetCurrentGLTF(t), r = this.tryGetCurrentModelViewer(t), n = this.getUrl(r);
|
|
1688
|
+
if (n && s && e.material) {
|
|
1460
1689
|
let o = function(a) {
|
|
1461
|
-
if (a[
|
|
1462
|
-
a[
|
|
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 " +
|
|
1690
|
+
if (a[ne] == !0) return;
|
|
1691
|
+
a[ne] = !0, a.userData && (a.userData.LOD = -1);
|
|
1692
|
+
const l = Object.keys(a);
|
|
1693
|
+
for (let c = 0; c < l.length; c++) {
|
|
1694
|
+
const f = l[c], y = a[f];
|
|
1695
|
+
if (y?.isTexture === !0) {
|
|
1696
|
+
const T = y.userData?.associations?.textures;
|
|
1697
|
+
if (T == null) continue;
|
|
1698
|
+
const _ = s.parser.json.textures[T];
|
|
1699
|
+
if (!_) {
|
|
1700
|
+
console.warn("Texture data not found for texture index " + T);
|
|
1472
1701
|
continue;
|
|
1473
1702
|
}
|
|
1474
|
-
if (
|
|
1475
|
-
const
|
|
1476
|
-
|
|
1703
|
+
if (_?.extensions?.[U]) {
|
|
1704
|
+
const C = _.extensions[U];
|
|
1705
|
+
C && n && p.registerTexture(n, y, C.lods.length, T, C);
|
|
1477
1706
|
}
|
|
1478
1707
|
}
|
|
1479
1708
|
}
|
|
1480
1709
|
};
|
|
1481
|
-
const
|
|
1482
|
-
if (Array.isArray(
|
|
1483
|
-
else o(
|
|
1710
|
+
const u = e.material;
|
|
1711
|
+
if (Array.isArray(u)) for (const a of u) o(a);
|
|
1712
|
+
else o(u);
|
|
1484
1713
|
}
|
|
1485
1714
|
}
|
|
1486
1715
|
tryParseMeshLOD(t, e) {
|
|
1487
|
-
if (e[
|
|
1488
|
-
e[
|
|
1716
|
+
if (e[De] == !0) return;
|
|
1717
|
+
e[De] = !0;
|
|
1489
1718
|
const s = this.tryGetCurrentModelViewer(t), r = this.getUrl(s);
|
|
1490
1719
|
if (!r)
|
|
1491
1720
|
return;
|
|
1492
|
-
const
|
|
1493
|
-
if (
|
|
1721
|
+
const n = e.userData?.gltfExtensions?.[U];
|
|
1722
|
+
if (n && r) {
|
|
1494
1723
|
const o = e.uuid;
|
|
1495
|
-
|
|
1724
|
+
p.registerMesh(r, o, e, 0, n.lods.length, n);
|
|
1496
1725
|
}
|
|
1497
1726
|
}
|
|
1498
1727
|
}
|
|
1499
|
-
function
|
|
1728
|
+
function Tt(...i) {
|
|
1500
1729
|
let t, e, s, r;
|
|
1501
|
-
switch (
|
|
1730
|
+
switch (i.length) {
|
|
1502
1731
|
case 2:
|
|
1503
|
-
[s, e] =
|
|
1732
|
+
[s, e] = i, r = {};
|
|
1504
1733
|
break;
|
|
1505
1734
|
case 3:
|
|
1506
|
-
[s, e, r] =
|
|
1735
|
+
[s, e, r] = i;
|
|
1507
1736
|
break;
|
|
1508
1737
|
case 4:
|
|
1509
|
-
[t, e, s, r] =
|
|
1738
|
+
[t, e, s, r] = i;
|
|
1510
1739
|
break;
|
|
1511
1740
|
default:
|
|
1512
1741
|
throw new Error("Invalid arguments");
|
|
1513
1742
|
}
|
|
1514
|
-
we(e),
|
|
1743
|
+
we(e), Pe(s), Re(s, {
|
|
1515
1744
|
progressive: !0,
|
|
1516
1745
|
...r?.hints
|
|
1517
|
-
}), s.register((o) => new
|
|
1518
|
-
const
|
|
1519
|
-
return r?.enableLODsManager !== !1 &&
|
|
1746
|
+
}), s.register((o) => new p(o));
|
|
1747
|
+
const n = L.get(e);
|
|
1748
|
+
return r?.enableLODsManager !== !1 && n.enable(), n;
|
|
1520
1749
|
}
|
|
1521
|
-
|
|
1522
|
-
if (!
|
|
1523
|
-
const
|
|
1750
|
+
Be();
|
|
1751
|
+
if (!lt) {
|
|
1752
|
+
const i = {
|
|
1524
1753
|
gltfProgressive: {
|
|
1525
|
-
useNeedleProgressive:
|
|
1526
|
-
LODsManager:
|
|
1527
|
-
configureLoader:
|
|
1754
|
+
useNeedleProgressive: Tt,
|
|
1755
|
+
LODsManager: L,
|
|
1756
|
+
configureLoader: Re,
|
|
1528
1757
|
getRaycastMesh: ee,
|
|
1529
|
-
useRaycastMeshes:
|
|
1758
|
+
useRaycastMeshes: ct
|
|
1530
1759
|
}
|
|
1531
1760
|
};
|
|
1532
1761
|
if (!globalThis.Needle)
|
|
1533
|
-
globalThis.Needle =
|
|
1762
|
+
globalThis.Needle = i;
|
|
1534
1763
|
else
|
|
1535
|
-
for (const t in
|
|
1536
|
-
globalThis.Needle[t] =
|
|
1764
|
+
for (const t in i)
|
|
1765
|
+
globalThis.Needle[t] = i[t];
|
|
1537
1766
|
}
|
|
1538
1767
|
export {
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1768
|
+
U as EXTENSION_NAME,
|
|
1769
|
+
L as LODsManager,
|
|
1770
|
+
p as NEEDLE_progressive,
|
|
1771
|
+
He as VERSION,
|
|
1772
|
+
Pe as addDracoAndKTX2Loaders,
|
|
1773
|
+
Re as configureLoader,
|
|
1545
1774
|
we as createLoaders,
|
|
1775
|
+
vt as getLODColor,
|
|
1546
1776
|
ee as getRaycastMesh,
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1777
|
+
be as lodDebugColors,
|
|
1778
|
+
Be as patchModelViewer,
|
|
1779
|
+
ut as registerRaycastMesh,
|
|
1780
|
+
et as setDracoDecoderLocation,
|
|
1781
|
+
tt as setKTX2TranscoderLocation,
|
|
1782
|
+
Tt as useNeedleProgressive,
|
|
1783
|
+
ct as useRaycastMeshes
|
|
1553
1784
|
};
|