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