@needle-tools/gltf-progressive 3.4.0-next.dbcee85 → 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 +745 -576
- package/gltf-progressive.min.js +9 -8
- package/gltf-progressive.umd.cjs +8 -7
- package/lib/extension.d.ts +64 -4
- package/lib/extension.js +160 -27
- 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,91 +1,91 @@
|
|
|
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
|
-
}).catch((
|
|
18
|
-
console.debug(`Failed to fetch remote Draco decoder from ${
|
|
17
|
+
}).catch((n) => {
|
|
18
|
+
console.debug(`Failed to fetch remote Draco decoder from ${I} (offline: ${typeof navigator < "u" ? navigator.onLine : "unknown"})`), I === Ye && Je("./include/draco/"), j === He && Ze("./include/ktx2/");
|
|
19
19
|
}).finally(() => {
|
|
20
|
-
|
|
20
|
+
Ce();
|
|
21
21
|
});
|
|
22
|
-
const
|
|
23
|
-
dracoDecoderPath:
|
|
24
|
-
ktx2TranscoderPath:
|
|
22
|
+
const Qe = () => ({
|
|
23
|
+
dracoDecoderPath: I,
|
|
24
|
+
ktx2TranscoderPath: j
|
|
25
25
|
});
|
|
26
|
-
function
|
|
27
|
-
|
|
26
|
+
function Je(n) {
|
|
27
|
+
I = n, C && C[pe] != I ? (console.debug("Updating Draco decoder path to " + n), C[pe] = I, C.setDecoderPath(I), C.preload()) : console.debug("Setting Draco decoder path to " + n);
|
|
28
28
|
}
|
|
29
|
-
function
|
|
30
|
-
|
|
29
|
+
function Ze(n) {
|
|
30
|
+
j = n, $ && $.transcoderPath != j ? (console.debug("Updating KTX2 transcoder path to " + n), $.setTranscoderPath(j), $.init()) : console.debug("Setting KTX2 transcoder path to " + n);
|
|
31
31
|
}
|
|
32
|
-
function
|
|
33
|
-
return
|
|
32
|
+
function we(n) {
|
|
33
|
+
return 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
|
-
|
|
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 =
|
|
51
|
-
let e =
|
|
48
|
+
const et = xe.prototype.load;
|
|
49
|
+
function tt(...n) {
|
|
50
|
+
const t = me.get(this);
|
|
51
|
+
let e = n[0];
|
|
52
52
|
const s = new URL(e, window.location.href);
|
|
53
53
|
if (s.hostname.endsWith("needle.tools")) {
|
|
54
|
-
const
|
|
55
|
-
|
|
54
|
+
const i = t?.progressive !== void 0 ? t.progressive : !0, o = t?.usecase ? t.usecase : "default";
|
|
55
|
+
i ? this.requestHeader.Accept = `*/*;progressive=allowed;usecase=${o}` : this.requestHeader.Accept = `*/*;usecase=${o}`, e = s.toString();
|
|
56
56
|
}
|
|
57
|
-
return
|
|
57
|
+
return n[0] = e, et?.call(this, ...n);
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
function
|
|
59
|
+
xe.prototype.load = tt;
|
|
60
|
+
q("debugprogressive");
|
|
61
|
+
function q(n) {
|
|
62
62
|
if (typeof window > "u") return !1;
|
|
63
|
-
const e = new URL(window.location.href).searchParams.get(
|
|
63
|
+
const e = new URL(window.location.href).searchParams.get(n);
|
|
64
64
|
return e == null || e === "0" || e === "false" ? !1 : e === "" ? !0 : e;
|
|
65
65
|
}
|
|
66
|
-
function
|
|
67
|
-
if (t === void 0 ||
|
|
66
|
+
function st(n, t) {
|
|
67
|
+
if (t === void 0 || n === void 0 || t.startsWith("./") || t.startsWith("http") || t.startsWith("data:") || t.startsWith("blob:"))
|
|
68
68
|
return t;
|
|
69
|
-
const e =
|
|
69
|
+
const e = n.lastIndexOf("/");
|
|
70
70
|
if (e >= 0) {
|
|
71
|
-
const s =
|
|
71
|
+
const s = n.substring(0, e + 1);
|
|
72
72
|
for (; s.endsWith("/") && t.startsWith("/"); ) t = t.substring(1);
|
|
73
73
|
return s + t;
|
|
74
74
|
}
|
|
75
75
|
return t;
|
|
76
76
|
}
|
|
77
|
-
function
|
|
78
|
-
return
|
|
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
79
|
}
|
|
80
|
-
let
|
|
81
|
-
function
|
|
80
|
+
let H;
|
|
81
|
+
function be() {
|
|
82
82
|
if (typeof window > "u") return !1;
|
|
83
|
-
const
|
|
84
|
-
return
|
|
83
|
+
const n = new URL(window.location.href), t = n.hostname === "localhost" || /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(n.hostname);
|
|
84
|
+
return n.hostname === "127.0.0.1" || t;
|
|
85
85
|
}
|
|
86
|
-
class
|
|
87
|
-
constructor(t
|
|
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;
|
|
131
|
+
}
|
|
132
|
+
const nt = typeof window > "u" && typeof document > "u", ye = /* @__PURE__ */ Symbol("needle:raycast-mesh");
|
|
133
|
+
function ee(n) {
|
|
134
|
+
return n?.[ye] instanceof E ? n[ye] : null;
|
|
123
135
|
}
|
|
124
|
-
function
|
|
125
|
-
if ((
|
|
126
|
-
const s =
|
|
127
|
-
s.userData = { isRaycastMesh: !0 },
|
|
136
|
+
function at(n, t) {
|
|
137
|
+
if ((n.type === "Mesh" || n.type === "SkinnedMesh") && !ee(n)) {
|
|
138
|
+
const s = ut(t);
|
|
139
|
+
s.userData = { isRaycastMesh: !0 }, n[ye] = s;
|
|
128
140
|
}
|
|
129
141
|
}
|
|
130
|
-
function
|
|
131
|
-
if (
|
|
132
|
-
if (
|
|
133
|
-
const t =
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
let
|
|
137
|
-
|
|
142
|
+
function lt(n = !0) {
|
|
143
|
+
if (n) {
|
|
144
|
+
if (Q) return;
|
|
145
|
+
const t = Q = X.prototype.raycast;
|
|
146
|
+
X.prototype.raycast = function(e, s) {
|
|
147
|
+
const r = this, i = ee(r);
|
|
148
|
+
let o;
|
|
149
|
+
i && r.isMesh && (o = r.geometry, r.geometry = i), t.call(this, e, s), o && (r.geometry = o);
|
|
138
150
|
};
|
|
139
151
|
} else {
|
|
140
|
-
if (!
|
|
141
|
-
|
|
152
|
+
if (!Q) return;
|
|
153
|
+
X.prototype.raycast = Q, Q = null;
|
|
142
154
|
}
|
|
143
155
|
}
|
|
144
|
-
let
|
|
145
|
-
function
|
|
156
|
+
let Q = null;
|
|
157
|
+
function ut(n) {
|
|
146
158
|
const t = new E();
|
|
147
|
-
for (const e in
|
|
148
|
-
t.setAttribute(e,
|
|
149
|
-
return t.setIndex(
|
|
159
|
+
for (const e in n.attributes)
|
|
160
|
+
t.setAttribute(e, n.getAttribute(e));
|
|
161
|
+
return t.setIndex(n.getIndex()), t;
|
|
150
162
|
}
|
|
151
|
-
const z = new Array(),
|
|
152
|
-
let
|
|
153
|
-
if (
|
|
154
|
-
let
|
|
155
|
-
|
|
163
|
+
const z = new Array(), f = q("debugprogressive");
|
|
164
|
+
let Z, V = -1;
|
|
165
|
+
if (f) {
|
|
166
|
+
let n = function() {
|
|
167
|
+
V += 1, V >= t && (V = -1), console.log(`Toggle LOD level [${V}]`);
|
|
156
168
|
}, t = 6;
|
|
157
169
|
window.addEventListener("keyup", (e) => {
|
|
158
|
-
e.key === "p" &&
|
|
170
|
+
e.key === "p" && n(), e.key === "w" && (Z = !Z, console.log(`Toggle wireframe [${Z}]`));
|
|
159
171
|
const s = parseInt(e.key);
|
|
160
|
-
!isNaN(s) && s >= 0 && (
|
|
172
|
+
!isNaN(s) && s >= 0 && (V = s, console.log(`Set LOD level to [${V}]`));
|
|
161
173
|
});
|
|
162
174
|
}
|
|
163
|
-
function
|
|
164
|
-
if (
|
|
165
|
-
if (Array.isArray(
|
|
166
|
-
for (const t of
|
|
167
|
-
|
|
168
|
-
else
|
|
175
|
+
function ke(n) {
|
|
176
|
+
if (f && Z !== void 0)
|
|
177
|
+
if (Array.isArray(n))
|
|
178
|
+
for (const t of n)
|
|
179
|
+
ke(t);
|
|
180
|
+
else n && "wireframe" in n && (n.wireframe = Z === !0);
|
|
169
181
|
}
|
|
170
|
-
const
|
|
171
|
-
let
|
|
172
|
-
const
|
|
173
|
-
function
|
|
174
|
-
if (
|
|
175
|
-
const s =
|
|
176
|
-
|
|
177
|
-
const
|
|
178
|
-
return
|
|
179
|
-
}
|
|
180
|
-
const t =
|
|
181
|
-
return
|
|
182
|
+
const J = new Array();
|
|
183
|
+
let ct = 0;
|
|
184
|
+
const dt = _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
|
-
|
|
227
|
+
const s = Qe();
|
|
228
|
+
let r = e?.renderer;
|
|
229
|
+
r || (this._webglRenderer ??= (async () => {
|
|
218
230
|
const { WebGLRenderer: u } = await import("three");
|
|
219
231
|
return new u();
|
|
220
|
-
})(),
|
|
221
|
-
const l =
|
|
232
|
+
})(), r = await this._webglRenderer);
|
|
233
|
+
const l = we(r).ktx2Loader.workerConfig;
|
|
222
234
|
t instanceof URL ? t = t.toString() : t.startsWith("file:") ? t = URL.createObjectURL(new Blob([t])) : !t.startsWith("blob:") && !t.startsWith("http:") && !t.startsWith("https:") && (t = new URL(t, window.location.href).toString());
|
|
223
235
|
const a = {
|
|
224
236
|
type: "load",
|
|
@@ -236,51 +248,51 @@ class we {
|
|
|
236
248
|
}
|
|
237
249
|
_debug = !1;
|
|
238
250
|
}
|
|
239
|
-
function
|
|
240
|
-
for (const t of
|
|
251
|
+
function ht(n) {
|
|
252
|
+
for (const t of n.geometries) {
|
|
241
253
|
const e = t.geometry, s = new E();
|
|
242
254
|
if (s.name = e.name || "", e.index) {
|
|
243
|
-
const
|
|
244
|
-
s.setIndex(
|
|
255
|
+
const r = e.index;
|
|
256
|
+
s.setIndex(le(r));
|
|
245
257
|
}
|
|
246
|
-
for (const
|
|
247
|
-
const
|
|
248
|
-
s.setAttribute(
|
|
258
|
+
for (const r in e.attributes) {
|
|
259
|
+
const i = e.attributes[r], o = le(i);
|
|
260
|
+
s.setAttribute(r, o);
|
|
249
261
|
}
|
|
250
262
|
if (e.morphAttributes)
|
|
251
|
-
for (const
|
|
252
|
-
const
|
|
253
|
-
s.morphAttributes[
|
|
263
|
+
for (const r in e.morphAttributes) {
|
|
264
|
+
const o = e.morphAttributes[r].map((l) => le(l));
|
|
265
|
+
s.morphAttributes[r] = o;
|
|
254
266
|
}
|
|
255
|
-
if (s.morphTargetsRelative = e.morphTargetsRelative ?? !1, s.boundingBox = new
|
|
267
|
+
if (s.morphTargetsRelative = e.morphTargetsRelative ?? !1, s.boundingBox = new ge(), s.boundingBox.min = new A(
|
|
256
268
|
e.boundingBox?.min.x,
|
|
257
269
|
e.boundingBox?.min.y,
|
|
258
270
|
e.boundingBox?.min.z
|
|
259
|
-
), s.boundingBox.max = new
|
|
271
|
+
), s.boundingBox.max = new A(
|
|
260
272
|
e.boundingBox?.max.x,
|
|
261
273
|
e.boundingBox?.max.y,
|
|
262
274
|
e.boundingBox?.max.z
|
|
263
|
-
), s.boundingSphere = new
|
|
264
|
-
new
|
|
275
|
+
), s.boundingSphere = new 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
|
-
for (const t of
|
|
287
|
+
for (const t of n.textures) {
|
|
276
288
|
const e = t.texture;
|
|
277
289
|
let s = null;
|
|
278
290
|
if (e.isCompressedTexture) {
|
|
279
|
-
const
|
|
280
|
-
s = new
|
|
281
|
-
o,
|
|
291
|
+
const r = e.mipmaps, i = e.image?.width || e.source?.data?.width || -1, o = e.image?.height || e.source?.data?.height || -1;
|
|
292
|
+
s = new Ge(
|
|
282
293
|
r,
|
|
283
|
-
|
|
294
|
+
i,
|
|
295
|
+
o,
|
|
284
296
|
e.format,
|
|
285
297
|
e.type,
|
|
286
298
|
e.mapping,
|
|
@@ -303,41 +315,66 @@ function dt(i) {
|
|
|
303
315
|
e.type,
|
|
304
316
|
e.anisotropy,
|
|
305
317
|
e.colorSpace
|
|
306
|
-
), s.mipmaps = e.mipmaps, s.channel = e.channel, s.source.data = e.source.data, s.flipY = e.flipY, s.premultiplyAlpha = e.premultiplyAlpha, s.unpackAlignment = e.unpackAlignment, s.matrix = new
|
|
318
|
+
), s.mipmaps = e.mipmaps, s.channel = e.channel, s.source.data = e.source.data, s.flipY = e.flipY, s.premultiplyAlpha = e.premultiplyAlpha, s.unpackAlignment = e.unpackAlignment, s.matrix = new Fe(...e.matrix.elements);
|
|
307
319
|
if (!s) {
|
|
308
320
|
console.error("[Worker] Failed to create new texture from received data. Texture is not a CompressedTexture or Texture.");
|
|
309
321
|
continue;
|
|
310
322
|
}
|
|
311
323
|
t.texture = s;
|
|
312
324
|
}
|
|
313
|
-
return
|
|
325
|
+
return n;
|
|
314
326
|
}
|
|
315
|
-
function
|
|
316
|
-
let t =
|
|
317
|
-
if ("isInterleavedBufferAttribute" in
|
|
318
|
-
const e =
|
|
319
|
-
t = new
|
|
320
|
-
} else "isBufferAttribute" in
|
|
327
|
+
function le(n) {
|
|
328
|
+
let t = n;
|
|
329
|
+
if ("isInterleavedBufferAttribute" in n && n.isInterleavedBufferAttribute) {
|
|
330
|
+
const e = n.data, s = e.array, r = new We(s, e.stride);
|
|
331
|
+
t = new Ue(r, n.itemSize, s.byteOffset, n.normalized), t.offset = n.offset;
|
|
332
|
+
} else "isBufferAttribute" in n && n.isBufferAttribute && (t = new ze(n.array, n.itemSize, n.normalized), t.usage = n.usage, t.gpuType = n.gpuType, t.updateRanges = n.updateRanges);
|
|
321
333
|
return t;
|
|
322
334
|
}
|
|
323
|
-
const
|
|
335
|
+
const gt = 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
390
|
const u = l.uniforms[a].value;
|
|
354
|
-
u?.isTexture === !0 &&
|
|
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
|
|
399
|
+
f && console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);
|
|
400
|
+
return t[r] = e, e;
|
|
401
|
+
function o(l, a) {
|
|
365
402
|
const u = s.getAssignedLODInformation(l);
|
|
366
403
|
if (u) {
|
|
367
|
-
const
|
|
368
|
-
if (
|
|
369
|
-
a.min_count = Math.min(a.min_count,
|
|
370
|
-
for (let y = 0; y <
|
|
371
|
-
const w =
|
|
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 u = this.assignTextureLODForSlot(a, e, s, l).then((
|
|
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 u =
|
|
484
|
-
u && u.isTexture === !0 ? l.push({ material: s, slot:
|
|
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 = {}),
|
|
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);
|
|
601
666
|
let u = m.lowresCache.get(e)?.deref();
|
|
602
|
-
u ? u.push(s.geometry) : u = [s.geometry], m.lowresCache.set(e, new WeakRef(u)),
|
|
603
|
-
for (const
|
|
604
|
-
|
|
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,42 +682,48 @@ 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
708
|
for (const [, e] of this.cache)
|
|
641
709
|
this._disposeCacheEntry(e);
|
|
642
|
-
this.cache.clear();
|
|
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();
|
|
@@ -659,6 +731,8 @@ class m {
|
|
|
659
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.
|
|
@@ -666,91 +740,119 @@ class m {
|
|
|
666
740
|
*/
|
|
667
741
|
static _resourceRegistry = new FinalizationRegistry((t) => {
|
|
668
742
|
const e = m.cache.get(t);
|
|
669
|
-
|
|
670
|
-
${t}`), e instanceof WeakRef && (e.deref() || (m.cache.delete(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)")));
|
|
671
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
|
+
}
|
|
672
774
|
static workers = [];
|
|
673
775
|
static _workersIndex = 0;
|
|
674
776
|
static async getOrLoadLOD(t, e) {
|
|
675
|
-
const s =
|
|
676
|
-
if (!
|
|
677
|
-
return
|
|
678
|
-
const
|
|
679
|
-
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;
|
|
680
782
|
if (t.isTexture === !0) {
|
|
681
783
|
const a = t;
|
|
682
|
-
a.source && a.source[
|
|
784
|
+
a.source && a.source[ue] && (o = a.source[ue]);
|
|
683
785
|
}
|
|
684
|
-
if (
|
|
685
|
-
|
|
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);
|
|
686
788
|
else {
|
|
687
789
|
if (e > 0) {
|
|
688
|
-
let
|
|
689
|
-
const y = Array.isArray(
|
|
690
|
-
if (y && e >=
|
|
691
|
-
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);
|
|
692
794
|
if (w) {
|
|
693
795
|
const _ = w.deref();
|
|
694
796
|
if (_) return _;
|
|
695
|
-
this.lowresCache.delete(
|
|
797
|
+
this.lowresCache.delete(i), f && console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${i}`);
|
|
696
798
|
}
|
|
697
799
|
return null;
|
|
698
800
|
}
|
|
699
801
|
}
|
|
700
|
-
const a = Array.isArray(
|
|
802
|
+
const a = Array.isArray(o.lods) ? o.lods[e]?.path : o.lods;
|
|
701
803
|
if (!a)
|
|
702
|
-
return
|
|
703
|
-
const u =
|
|
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);
|
|
704
806
|
if (u.endsWith(".glb") || u.endsWith(".gltf")) {
|
|
705
|
-
if (!
|
|
706
|
-
return console.warn("missing pointer for glb/gltf texture",
|
|
707
|
-
const
|
|
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);
|
|
708
810
|
if (w !== void 0)
|
|
709
|
-
if (s && console.log(`LOD ${e} was already loading/loaded: ${
|
|
710
|
-
const
|
|
711
|
-
if (
|
|
712
|
-
let g =
|
|
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;
|
|
713
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)
|
|
714
816
|
return g;
|
|
715
817
|
}
|
|
716
|
-
this.cache.delete(
|
|
818
|
+
this.cache.delete(c), f && console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${c}`);
|
|
717
819
|
} else {
|
|
718
|
-
let
|
|
820
|
+
let d = await w.catch((b) => (console.error(`Error loading LOD ${e} from ${u}
|
|
719
821
|
`, b), null)), g = !1;
|
|
720
|
-
if (
|
|
721
|
-
return
|
|
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;
|
|
722
824
|
}
|
|
723
825
|
if (!y.use)
|
|
724
|
-
return
|
|
725
|
-
const _ =
|
|
726
|
-
if (
|
|
727
|
-
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);
|
|
728
830
|
if (x.textures.length > 0)
|
|
729
|
-
for (const
|
|
730
|
-
let p =
|
|
731
|
-
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);
|
|
732
834
|
}
|
|
733
835
|
if (x.geometries.length > 0) {
|
|
734
|
-
const
|
|
836
|
+
const h = new Array();
|
|
735
837
|
for (const p of x.geometries) {
|
|
736
838
|
const O = p.geometry;
|
|
737
|
-
m.assignLODInformation(
|
|
839
|
+
m.assignLODInformation(r.url, O, i, e, p.primitiveIndex), h.push(O);
|
|
738
840
|
}
|
|
739
|
-
return
|
|
841
|
+
return d(h);
|
|
740
842
|
}
|
|
741
|
-
return
|
|
843
|
+
return d(null);
|
|
742
844
|
}
|
|
743
|
-
const b = new
|
|
744
|
-
|
|
845
|
+
const b = new xe();
|
|
846
|
+
Te(b), f && (await new Promise((L) => setTimeout(L, 1e3)), s && console.warn("Start loading (delayed) " + u, _.guid));
|
|
745
847
|
let B = u;
|
|
746
848
|
if (_ && Array.isArray(_.lods)) {
|
|
747
849
|
const L = _.lods[e];
|
|
748
850
|
L.hash && (B += "?v=" + L.hash);
|
|
749
851
|
}
|
|
750
852
|
const D = await b.loadAsync(B).catch((L) => (console.error(`Error loading LOD ${e} from ${u}
|
|
751
|
-
`, L),
|
|
853
|
+
`, L), d(null)));
|
|
752
854
|
if (!D)
|
|
753
|
-
return
|
|
855
|
+
return d(null);
|
|
754
856
|
const N = D.parser;
|
|
755
857
|
s && console.log("Loading finished " + u, _.guid);
|
|
756
858
|
let P = 0;
|
|
@@ -758,8 +860,8 @@ ${t}`), e instanceof WeakRef && (e.deref() || (m.cache.delete(t), h && console.l
|
|
|
758
860
|
let L = !1;
|
|
759
861
|
for (const x of D.parser.json.textures) {
|
|
760
862
|
if (x?.extensions) {
|
|
761
|
-
const
|
|
762
|
-
if (
|
|
863
|
+
const h = x?.extensions[W];
|
|
864
|
+
if (h?.guid && h.guid === _.guid) {
|
|
763
865
|
L = !0;
|
|
764
866
|
break;
|
|
765
867
|
}
|
|
@@ -768,15 +870,15 @@ ${t}`), e instanceof WeakRef && (e.deref() || (m.cache.delete(t), h && console.l
|
|
|
768
870
|
}
|
|
769
871
|
if (L) {
|
|
770
872
|
let x = await N.getDependency("texture", P);
|
|
771
|
-
return x && m.assignLODInformation(
|
|
772
|
-
} 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);
|
|
773
875
|
}
|
|
774
876
|
if (P = 0, D.parser.json.meshes) {
|
|
775
877
|
let L = !1;
|
|
776
878
|
for (const x of D.parser.json.meshes) {
|
|
777
879
|
if (x?.extensions) {
|
|
778
|
-
const
|
|
779
|
-
if (
|
|
880
|
+
const h = x?.extensions[W];
|
|
881
|
+
if (h?.guid && h.guid === _.guid) {
|
|
780
882
|
L = !0;
|
|
781
883
|
break;
|
|
782
884
|
}
|
|
@@ -785,68 +887,70 @@ ${t}`), e instanceof WeakRef && (e.deref() || (m.cache.delete(t), h && console.l
|
|
|
785
887
|
}
|
|
786
888
|
if (L) {
|
|
787
889
|
const x = await N.getDependency("mesh", P);
|
|
788
|
-
if (s && console.log(`Loaded Mesh "${x.name}"`, u, P, x,
|
|
789
|
-
const
|
|
790
|
-
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);
|
|
791
893
|
} else {
|
|
792
|
-
const
|
|
894
|
+
const h = new Array();
|
|
793
895
|
for (let p = 0; p < x.children.length; p++) {
|
|
794
896
|
const O = x.children[p];
|
|
795
897
|
if (O.isMesh === !0) {
|
|
796
898
|
const S = O.geometry;
|
|
797
|
-
m.assignLODInformation(
|
|
899
|
+
m.assignLODInformation(r.url, S, i, e, p), h.push(S);
|
|
798
900
|
}
|
|
799
901
|
}
|
|
800
|
-
return
|
|
902
|
+
return d(h);
|
|
801
903
|
}
|
|
802
|
-
} else
|
|
904
|
+
} else f && console.warn("Could not find mesh with guid", _.guid, D.parser.json);
|
|
803
905
|
}
|
|
804
|
-
return
|
|
906
|
+
return d(null);
|
|
805
907
|
});
|
|
806
|
-
this.cache.set(
|
|
807
|
-
const M = await
|
|
808
|
-
return M != null ? M instanceof F ? (this.cache.set(
|
|
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;
|
|
809
911
|
} else if (t instanceof F) {
|
|
810
912
|
s && console.log("Load texture from uri: " + u);
|
|
811
|
-
const y = await new
|
|
812
|
-
return y ? (y.guid =
|
|
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;
|
|
813
915
|
}
|
|
814
916
|
}
|
|
815
917
|
return null;
|
|
816
918
|
}
|
|
817
|
-
static
|
|
818
|
-
static queue
|
|
819
|
-
|
|
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) {
|
|
820
924
|
if (!e) return;
|
|
821
925
|
e.userData || (e.userData = {});
|
|
822
|
-
const
|
|
823
|
-
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);
|
|
824
928
|
}
|
|
825
929
|
static getAssignedLODInformation(t) {
|
|
826
930
|
return t ? t.userData?.LODS ? t.userData.LODS : "source" in t && t.source?.LODS ? t.source.LODS : null : null;
|
|
827
931
|
}
|
|
828
932
|
// private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
|
|
829
933
|
static copySettings(t, e) {
|
|
830
|
-
return e ? (
|
|
934
|
+
return e ? (f === "verbose" && console.debug(`Copy texture settings
|
|
831
935
|
`, t.uuid, `
|
|
832
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;
|
|
833
937
|
}
|
|
834
938
|
}
|
|
835
|
-
class
|
|
939
|
+
class pt {
|
|
836
940
|
url;
|
|
837
941
|
/** the key to lookup the LOD information */
|
|
838
942
|
key;
|
|
839
943
|
level;
|
|
840
944
|
/** For multi objects (e.g. a group of meshes) this is the index of the object */
|
|
841
945
|
index;
|
|
842
|
-
constructor(t, e, s,
|
|
843
|
-
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);
|
|
844
948
|
}
|
|
845
949
|
}
|
|
846
|
-
class
|
|
847
|
-
static addPromise = (t, e, s,
|
|
848
|
-
|
|
849
|
-
|
|
950
|
+
class ce {
|
|
951
|
+
static addPromise = (t, e, s, r) => {
|
|
952
|
+
r.forEach((i) => {
|
|
953
|
+
i.add(t, e, s);
|
|
850
954
|
});
|
|
851
955
|
};
|
|
852
956
|
ready;
|
|
@@ -876,9 +980,9 @@ class ue {
|
|
|
876
980
|
_awaiting = [];
|
|
877
981
|
_maxPromisesPerObject = 1;
|
|
878
982
|
constructor(t, e) {
|
|
879
|
-
const
|
|
880
|
-
this._frame_start = e.waitForFirstCapture ? void 0 : t, this._frames_to_capture =
|
|
881
|
-
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;
|
|
882
986
|
}), this.ready.finally(() => {
|
|
883
987
|
this._resolved = !0, this._awaiting.length = 0;
|
|
884
988
|
}), this._signal = e.signal, this._signal?.addEventListener("abort", () => {
|
|
@@ -892,18 +996,18 @@ class ue {
|
|
|
892
996
|
_seen = /* @__PURE__ */ new WeakMap();
|
|
893
997
|
add(t, e, s) {
|
|
894
998
|
if (this._resolved) {
|
|
895
|
-
|
|
999
|
+
f && console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");
|
|
896
1000
|
return;
|
|
897
1001
|
}
|
|
898
1002
|
if (!(this._frame_start !== void 0 && this._currentFrame > this._frame_start + this._frames_to_capture)) {
|
|
899
1003
|
if (this._maxPromisesPerObject >= 1)
|
|
900
1004
|
if (this._seen.has(e)) {
|
|
901
|
-
let
|
|
902
|
-
if (
|
|
903
|
-
|
|
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.");
|
|
904
1008
|
return;
|
|
905
1009
|
}
|
|
906
|
-
this._seen.set(e,
|
|
1010
|
+
this._seen.set(e, r + 1);
|
|
907
1011
|
} else
|
|
908
1012
|
this._seen.set(e, 1);
|
|
909
1013
|
this._awaiting.push(s), this._addedCount++, s.finally(() => {
|
|
@@ -919,7 +1023,7 @@ class ue {
|
|
|
919
1023
|
});
|
|
920
1024
|
}
|
|
921
1025
|
}
|
|
922
|
-
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 };
|
|
923
1027
|
class v {
|
|
924
1028
|
/**
|
|
925
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.
|
|
@@ -927,7 +1031,7 @@ class v {
|
|
|
927
1031
|
static debugDrawLine;
|
|
928
1032
|
/** @internal */
|
|
929
1033
|
static getObjectLODState(t) {
|
|
930
|
-
return t[
|
|
1034
|
+
return t[fe];
|
|
931
1035
|
}
|
|
932
1036
|
static addPlugin(t) {
|
|
933
1037
|
z.push(t);
|
|
@@ -952,7 +1056,7 @@ class v {
|
|
|
952
1056
|
}
|
|
953
1057
|
renderer;
|
|
954
1058
|
context;
|
|
955
|
-
projectionScreenMatrix = new
|
|
1059
|
+
projectionScreenMatrix = new ve();
|
|
956
1060
|
/** @deprecated use static `LODsManager.addPlugin()` method. This getter will be removed in later versions */
|
|
957
1061
|
get plugins() {
|
|
958
1062
|
return z;
|
|
@@ -993,16 +1097,40 @@ class v {
|
|
|
993
1097
|
_newPromiseGroups = [];
|
|
994
1098
|
_promiseGroupIds = 0;
|
|
995
1099
|
/**
|
|
996
|
-
*
|
|
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
|
+
* ```
|
|
997
1125
|
*/
|
|
998
1126
|
awaitLoading(t) {
|
|
999
|
-
const e = this._promiseGroupIds++, s = new
|
|
1127
|
+
const e = this._promiseGroupIds++, s = new ce(this.#r, { ...t });
|
|
1000
1128
|
this._newPromiseGroups.push(s);
|
|
1001
|
-
const
|
|
1129
|
+
const r = performance.now();
|
|
1002
1130
|
return s.ready.finally(() => {
|
|
1003
|
-
const
|
|
1004
|
-
|
|
1005
|
-
start:
|
|
1131
|
+
const i = this._newPromiseGroups.indexOf(s);
|
|
1132
|
+
i >= 0 && (this._newPromiseGroups.splice(i, 1), be() && performance.measure("LODsManager:awaitLoading", {
|
|
1133
|
+
start: r,
|
|
1006
1134
|
detail: { id: e, name: t?.name, awaited: s.awaitedCount, resolved: s.resolvedCount }
|
|
1007
1135
|
}));
|
|
1008
1136
|
}), s.ready;
|
|
@@ -1013,24 +1141,50 @@ class v {
|
|
|
1013
1141
|
this._newPromiseGroups[t].update(this.#r);
|
|
1014
1142
|
}
|
|
1015
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
|
+
*/
|
|
1016
1159
|
addEventListener(t, e) {
|
|
1017
|
-
t === "changed"
|
|
1160
|
+
return t === "changed" ? (this._lodchangedlisteners.push(e), () => {
|
|
1161
|
+
this.removeEventListener(t, e);
|
|
1162
|
+
}) : () => {
|
|
1163
|
+
};
|
|
1018
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
|
+
*/
|
|
1019
1171
|
removeEventListener(t, e) {
|
|
1172
|
+
let s = !1;
|
|
1020
1173
|
if (t === "changed") {
|
|
1021
|
-
const
|
|
1022
|
-
|
|
1174
|
+
const r = this._lodchangedlisteners.indexOf(e);
|
|
1175
|
+
r >= 0 && (this._lodchangedlisteners.splice(r, 1), s = !0);
|
|
1023
1176
|
}
|
|
1177
|
+
return s;
|
|
1024
1178
|
}
|
|
1025
1179
|
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
1026
1180
|
constructor(t, e) {
|
|
1027
1181
|
this.renderer = t, this.context = { ...e };
|
|
1028
1182
|
}
|
|
1029
1183
|
#t;
|
|
1030
|
-
#
|
|
1184
|
+
#o = new Ne();
|
|
1031
1185
|
#r = 0;
|
|
1032
|
-
#o = 0;
|
|
1033
1186
|
#i = 0;
|
|
1187
|
+
#n = 0;
|
|
1034
1188
|
#s = 0;
|
|
1035
1189
|
_fpsBuffer = [60, 60, 60, 60, 60];
|
|
1036
1190
|
/**
|
|
@@ -1042,29 +1196,44 @@ class v {
|
|
|
1042
1196
|
let t = 0;
|
|
1043
1197
|
this.#t = this.renderer.render;
|
|
1044
1198
|
const e = this;
|
|
1045
|
-
|
|
1046
|
-
const
|
|
1047
|
-
(
|
|
1048
|
-
const
|
|
1049
|
-
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);
|
|
1050
1204
|
};
|
|
1051
1205
|
}
|
|
1052
1206
|
disable() {
|
|
1053
1207
|
this.#t && (console.debug("[gltf-progressive] Disabling LODsManager for renderer"), this.renderer.render = this.#t, this.#t = void 0);
|
|
1054
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
|
+
*/
|
|
1055
1224
|
update(t, e) {
|
|
1056
1225
|
this.internalUpdate(t, e);
|
|
1057
1226
|
}
|
|
1058
1227
|
onAfterRender(t, e, s) {
|
|
1059
1228
|
if (this.pause) return;
|
|
1060
|
-
const
|
|
1061
|
-
let
|
|
1062
|
-
if (
|
|
1063
|
-
const l =
|
|
1064
|
-
(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);
|
|
1065
1234
|
}
|
|
1066
|
-
if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (
|
|
1067
|
-
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))
|
|
1068
1237
|
return;
|
|
1069
1238
|
this.internalUpdate(t, e), this._postprocessPromiseGroups();
|
|
1070
1239
|
}
|
|
@@ -1073,12 +1242,12 @@ class v {
|
|
|
1073
1242
|
* Update LODs in a scene
|
|
1074
1243
|
*/
|
|
1075
1244
|
internalUpdate(t, e) {
|
|
1076
|
-
const s = this.renderer.renderLists.get(t, 0),
|
|
1245
|
+
const s = this.renderer.renderLists.get(t, 0), r = s.opaque;
|
|
1077
1246
|
this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix, e.matrixWorldInverse);
|
|
1078
|
-
const
|
|
1079
|
-
for (const a of
|
|
1247
|
+
const i = this.targetTriangleDensity;
|
|
1248
|
+
for (const a of r) {
|
|
1080
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")) {
|
|
1081
|
-
|
|
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)));
|
|
1082
1251
|
continue;
|
|
1083
1252
|
}
|
|
1084
1253
|
switch (a.material.type) {
|
|
@@ -1090,38 +1259,38 @@ class v {
|
|
|
1090
1259
|
case "MeshDepthMaterial":
|
|
1091
1260
|
continue;
|
|
1092
1261
|
}
|
|
1093
|
-
if (
|
|
1262
|
+
if (R === "color" && a.material && !a.object.progressive_debug_color) {
|
|
1094
1263
|
a.object.progressive_debug_color = !0;
|
|
1095
|
-
const
|
|
1264
|
+
const c = Math.random() * 16777215, y = new Ve({ color: c });
|
|
1096
1265
|
a.object.material = y;
|
|
1097
1266
|
}
|
|
1098
1267
|
const u = a.object;
|
|
1099
|
-
(u instanceof
|
|
1268
|
+
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1100
1269
|
}
|
|
1101
|
-
const
|
|
1102
|
-
for (const a of
|
|
1270
|
+
const o = s.transparent;
|
|
1271
|
+
for (const a of o) {
|
|
1103
1272
|
const u = a.object;
|
|
1104
|
-
(u instanceof
|
|
1273
|
+
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1105
1274
|
}
|
|
1106
1275
|
const l = s.transmissive;
|
|
1107
1276
|
for (const a of l) {
|
|
1108
1277
|
const u = a.object;
|
|
1109
|
-
(u instanceof
|
|
1278
|
+
(u instanceof X || u.isMesh) && this.updateLODs(t, e, u, i);
|
|
1110
1279
|
}
|
|
1111
1280
|
}
|
|
1112
1281
|
/** Update the LOD levels for the renderer. */
|
|
1113
|
-
updateLODs(t, e, s,
|
|
1282
|
+
updateLODs(t, e, s, r) {
|
|
1114
1283
|
s.userData || (s.userData = {});
|
|
1115
|
-
let
|
|
1116
|
-
if (
|
|
1284
|
+
let i = s[fe];
|
|
1285
|
+
if (i || (i = new yt(), s[fe] = i), i.frames++ < 2)
|
|
1117
1286
|
return;
|
|
1118
1287
|
for (const l of z)
|
|
1119
1288
|
l.onBeforeUpdateLOD?.(this.renderer, t, e, s);
|
|
1120
|
-
const
|
|
1121
|
-
|
|
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);
|
|
1122
1291
|
for (const l of z)
|
|
1123
1292
|
l.onAfterUpdatedLOD?.(this.renderer, t, e, s, T);
|
|
1124
|
-
|
|
1293
|
+
i.lastLodLevel_Mesh = T.mesh_lod, i.lastLodLevel_Texture = T.texture_lod;
|
|
1125
1294
|
}
|
|
1126
1295
|
/** Load progressive textures for the given material
|
|
1127
1296
|
* @param material the material to load the textures for
|
|
@@ -1131,17 +1300,17 @@ class v {
|
|
|
1131
1300
|
loadProgressiveTextures(t, e, s) {
|
|
1132
1301
|
if (!t) return;
|
|
1133
1302
|
if (Array.isArray(t)) {
|
|
1134
|
-
for (const
|
|
1135
|
-
this.loadProgressiveTextures(
|
|
1303
|
+
for (const i of t)
|
|
1304
|
+
this.loadProgressiveTextures(i, e);
|
|
1136
1305
|
return;
|
|
1137
1306
|
}
|
|
1138
|
-
let
|
|
1139
|
-
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) {
|
|
1140
1309
|
t[U] = e;
|
|
1141
|
-
const
|
|
1310
|
+
const i = m.assignTextureLOD(t, e).then((o) => {
|
|
1142
1311
|
this._lodchangedlisteners.forEach((l) => l({ type: "texture", level: e, object: t }));
|
|
1143
1312
|
});
|
|
1144
|
-
|
|
1313
|
+
ce.addPromise("texture", t, i, this._newPromiseGroups);
|
|
1145
1314
|
}
|
|
1146
1315
|
}
|
|
1147
1316
|
/** Load progressive meshes for the given mesh
|
|
@@ -1153,141 +1322,141 @@ class v {
|
|
|
1153
1322
|
loadProgressiveMeshes(t, e) {
|
|
1154
1323
|
if (!t) return Promise.resolve(null);
|
|
1155
1324
|
let s = t[U] !== e;
|
|
1156
|
-
const
|
|
1157
|
-
if (
|
|
1325
|
+
const r = t["DEBUG:LOD"];
|
|
1326
|
+
if (r != null && (s = t[U] != r, e = r), s) {
|
|
1158
1327
|
t[U] = e;
|
|
1159
|
-
const
|
|
1160
|
-
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;
|
|
1161
1330
|
}
|
|
1162
1331
|
return Promise.resolve(null);
|
|
1163
1332
|
}
|
|
1164
1333
|
// private testIfLODLevelsAreAvailable() {
|
|
1165
|
-
_sphere = new
|
|
1166
|
-
_tempBox = new
|
|
1167
|
-
_tempBox2 = new
|
|
1168
|
-
tempMatrix = new
|
|
1169
|
-
_tempWorldPosition = new
|
|
1170
|
-
_tempBoxSize = new
|
|
1171
|
-
_tempBox2Size = new
|
|
1172
|
-
static corner0 = new
|
|
1173
|
-
static corner1 = new
|
|
1174
|
-
static corner2 = new
|
|
1175
|
-
static corner3 = new
|
|
1176
|
-
static _tempPtInside = new
|
|
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();
|
|
1177
1346
|
static isInside(t, e) {
|
|
1178
|
-
const s = t.min,
|
|
1179
|
-
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;
|
|
1180
1349
|
}
|
|
1181
1350
|
static skinnedMeshBoundsFrameOffsetCounter = 0;
|
|
1182
1351
|
static $skinnedMeshBoundsOffset = /* @__PURE__ */ Symbol("gltf-progressive-skinnedMeshBoundsOffset");
|
|
1183
1352
|
// #region calculateLodLevel
|
|
1184
|
-
calculateLodLevel(t, e, s,
|
|
1353
|
+
calculateLodLevel(t, e, s, r, i) {
|
|
1185
1354
|
if (!e) {
|
|
1186
|
-
|
|
1355
|
+
i.mesh_lod = -1, i.texture_lod = -1;
|
|
1187
1356
|
return;
|
|
1188
1357
|
}
|
|
1189
1358
|
if (!t) {
|
|
1190
|
-
|
|
1359
|
+
i.mesh_lod = -1, i.texture_lod = -1;
|
|
1191
1360
|
return;
|
|
1192
1361
|
}
|
|
1193
1362
|
let l = 10 + 1, a = !1;
|
|
1194
|
-
if (
|
|
1363
|
+
if (R && e["DEBUG:LOD"] != null)
|
|
1195
1364
|
return e["DEBUG:LOD"];
|
|
1196
|
-
const u = m.getMeshLODExtension(e.geometry)?.lods,
|
|
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;
|
|
1197
1366
|
if (!y && !_) {
|
|
1198
|
-
|
|
1367
|
+
i.mesh_lod = 0, i.texture_lod = 0;
|
|
1199
1368
|
return;
|
|
1200
1369
|
}
|
|
1201
1370
|
y || (a = !0, l = 0);
|
|
1202
|
-
const
|
|
1371
|
+
const k = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
|
|
1203
1372
|
let M = e.geometry.boundingBox;
|
|
1204
1373
|
if (e.type === "SkinnedMesh") {
|
|
1205
|
-
const
|
|
1206
|
-
if (!
|
|
1207
|
-
|
|
1374
|
+
const d = e;
|
|
1375
|
+
if (!d.boundingBox)
|
|
1376
|
+
d.computeBoundingBox();
|
|
1208
1377
|
else if (this.skinnedMeshAutoUpdateBoundsInterval > 0) {
|
|
1209
|
-
if (!
|
|
1378
|
+
if (!d[v.$skinnedMeshBoundsOffset]) {
|
|
1210
1379
|
const b = v.skinnedMeshBoundsFrameOffsetCounter++;
|
|
1211
|
-
|
|
1380
|
+
d[v.$skinnedMeshBoundsOffset] = b;
|
|
1212
1381
|
}
|
|
1213
|
-
const g =
|
|
1382
|
+
const g = d[v.$skinnedMeshBoundsOffset];
|
|
1214
1383
|
if ((s.frames + g) % this.skinnedMeshAutoUpdateBoundsInterval === 0) {
|
|
1215
|
-
const b =
|
|
1216
|
-
b && (
|
|
1384
|
+
const b = ee(d), B = d.geometry;
|
|
1385
|
+
b && (d.geometry = b), d.computeBoundingBox(), d.geometry = B;
|
|
1217
1386
|
}
|
|
1218
1387
|
}
|
|
1219
|
-
M =
|
|
1388
|
+
M = d.boundingBox;
|
|
1220
1389
|
}
|
|
1221
1390
|
if (M) {
|
|
1222
|
-
const
|
|
1391
|
+
const d = t;
|
|
1223
1392
|
if (e.geometry.attributes.color && e.geometry.attributes.color.count < 100 && e.geometry.boundingSphere) {
|
|
1224
1393
|
this._sphere.copy(e.geometry.boundingSphere), this._sphere.applyMatrix4(e.matrixWorld);
|
|
1225
|
-
const
|
|
1226
|
-
if (this._sphere.containsPoint(
|
|
1227
|
-
|
|
1394
|
+
const h = t.getWorldPosition(this._tempWorldPosition);
|
|
1395
|
+
if (this._sphere.containsPoint(h)) {
|
|
1396
|
+
i.mesh_lod = 0, i.texture_lod = 0;
|
|
1228
1397
|
return;
|
|
1229
1398
|
}
|
|
1230
1399
|
}
|
|
1231
|
-
if (this._tempBox.copy(M), this._tempBox.applyMatrix4(e.matrixWorld),
|
|
1232
|
-
|
|
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;
|
|
1233
1402
|
return;
|
|
1234
1403
|
}
|
|
1235
|
-
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled &&
|
|
1236
|
-
const
|
|
1237
|
-
let O =
|
|
1238
|
-
const
|
|
1239
|
-
O = (O -
|
|
1240
|
-
const
|
|
1241
|
-
s.lastCentrality = (ne -
|
|
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);
|
|
1242
1411
|
} else
|
|
1243
1412
|
s.lastCentrality = 1;
|
|
1244
1413
|
const g = this._tempBox.getSize(this._tempBoxSize);
|
|
1245
|
-
g.multiplyScalar(0.5), screen.availHeight > 0 &&
|
|
1414
|
+
g.multiplyScalar(0.5), screen.availHeight > 0 && k > 0 && g.multiplyScalar(k / screen.availHeight), t.isPerspectiveCamera ? g.x *= t.aspect : t.isOrthographicCamera;
|
|
1246
1415
|
const b = t.matrixWorldInverse, B = this._tempBox2;
|
|
1247
1416
|
B.copy(M), B.applyMatrix4(e.matrixWorld), B.applyMatrix4(b);
|
|
1248
1417
|
const D = B.getSize(this._tempBox2Size), N = Math.max(D.x, D.y);
|
|
1249
|
-
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,
|
|
1250
|
-
const
|
|
1251
|
-
|
|
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();
|
|
1252
1421
|
const p = v.corner0, O = v.corner1, S = v.corner2, G = v.corner3;
|
|
1253
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);
|
|
1254
1423
|
const Y = (p.z + G.z) * 0.5;
|
|
1255
|
-
p.z = O.z = S.z = G.z = Y, p.applyMatrix4(
|
|
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);
|
|
1256
1425
|
}
|
|
1257
1426
|
let L = 999;
|
|
1258
1427
|
if (u && s.lastScreenCoverage > 0)
|
|
1259
|
-
for (let
|
|
1260
|
-
const p = u[
|
|
1261
|
-
if (
|
|
1262
|
-
L =
|
|
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;
|
|
1263
1432
|
break;
|
|
1264
1433
|
}
|
|
1265
1434
|
}
|
|
1266
1435
|
L < l && (l = L, a = !0);
|
|
1267
1436
|
}
|
|
1268
|
-
if (a ?
|
|
1269
|
-
const g = u?.[
|
|
1270
|
-
g && console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${
|
|
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}`);
|
|
1271
1440
|
}
|
|
1272
1441
|
if (_) {
|
|
1273
|
-
const
|
|
1442
|
+
const d = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
|
|
1274
1443
|
if (s.lastLodLevel_Texture < 0) {
|
|
1275
|
-
if (
|
|
1444
|
+
if (i.texture_lod = w.max_count - 1, R) {
|
|
1276
1445
|
const g = w.lods[w.max_count - 1];
|
|
1277
|
-
|
|
1446
|
+
R && console.log(`First Texture LOD ${i.texture_lod} (${g.max_height}px) - ${e.name}`);
|
|
1278
1447
|
}
|
|
1279
1448
|
} else {
|
|
1280
1449
|
const g = s.lastScreenspaceVolume.x + s.lastScreenspaceVolume.y + s.lastScreenspaceVolume.z;
|
|
1281
1450
|
let b = s.lastScreenCoverage * 4;
|
|
1282
1451
|
this.context?.engine === "model-viewer" && (b *= 1.5);
|
|
1283
|
-
const D =
|
|
1452
|
+
const D = k / window.devicePixelRatio * b;
|
|
1284
1453
|
let N = !1;
|
|
1285
1454
|
for (let P = w.lods.length - 1; P >= 0; P--) {
|
|
1286
1455
|
const L = w.lods[P];
|
|
1287
|
-
if (!(
|
|
1288
|
-
if (N = !0,
|
|
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) {
|
|
1289
1458
|
const x = L.max_height;
|
|
1290
|
-
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${
|
|
1459
|
+
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${i.texture_lod} = ${x}px
|
|
1291
1460
|
Screensize: ${D.toFixed(0)}px, Coverage: ${(100 * s.lastScreenCoverage).toFixed(2)}%, Volume ${g.toFixed(1)}
|
|
1292
1461
|
${e.name}`);
|
|
1293
1462
|
}
|
|
@@ -1296,86 +1465,86 @@ ${e.name}`);
|
|
|
1296
1465
|
}
|
|
1297
1466
|
}
|
|
1298
1467
|
} else
|
|
1299
|
-
|
|
1468
|
+
i.texture_lod = 0;
|
|
1300
1469
|
}
|
|
1301
1470
|
}
|
|
1302
|
-
class
|
|
1471
|
+
class yt {
|
|
1303
1472
|
frames = 0;
|
|
1304
1473
|
lastLodLevel_Mesh = -1;
|
|
1305
1474
|
lastLodLevel_Texture = -1;
|
|
1306
1475
|
lastScreenCoverage = 0;
|
|
1307
|
-
lastScreenspaceVolume = new
|
|
1476
|
+
lastScreenspaceVolume = new A();
|
|
1308
1477
|
lastCentrality = 0;
|
|
1309
1478
|
}
|
|
1310
|
-
const
|
|
1311
|
-
let
|
|
1312
|
-
function
|
|
1313
|
-
const
|
|
1314
|
-
|
|
1315
|
-
return
|
|
1316
|
-
}),
|
|
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();
|
|
1483
|
+
n && (n.mapURLs(function(t) {
|
|
1484
|
+
return De(), t;
|
|
1485
|
+
}), De(), he?.disconnect(), he = new MutationObserver((t) => {
|
|
1317
1486
|
t.forEach((e) => {
|
|
1318
1487
|
e.addedNodes.forEach((s) => {
|
|
1319
|
-
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" &&
|
|
1488
|
+
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" && Ie(s);
|
|
1320
1489
|
});
|
|
1321
1490
|
});
|
|
1322
|
-
}),
|
|
1491
|
+
}), he.observe(document, { childList: !0, subtree: !0 }));
|
|
1323
1492
|
}
|
|
1324
|
-
function
|
|
1493
|
+
function xt() {
|
|
1325
1494
|
if (typeof customElements > "u") return null;
|
|
1326
|
-
const
|
|
1327
|
-
return
|
|
1328
|
-
console.debug("[gltf-progressive] model-viewer defined"),
|
|
1495
|
+
const n = customElements.get("model-viewer");
|
|
1496
|
+
return n || (customElements.whenDefined("model-viewer").then(() => {
|
|
1497
|
+
console.debug("[gltf-progressive] model-viewer defined"), Re();
|
|
1329
1498
|
}), null);
|
|
1330
1499
|
}
|
|
1331
|
-
function
|
|
1500
|
+
function De() {
|
|
1332
1501
|
if (typeof document > "u") return;
|
|
1333
1502
|
document.querySelectorAll("model-viewer").forEach((t) => {
|
|
1334
|
-
|
|
1503
|
+
Ie(t);
|
|
1335
1504
|
});
|
|
1336
1505
|
}
|
|
1337
|
-
const
|
|
1338
|
-
let
|
|
1339
|
-
function
|
|
1340
|
-
if (!
|
|
1506
|
+
const Oe = /* @__PURE__ */ new WeakSet();
|
|
1507
|
+
let wt = 0;
|
|
1508
|
+
function Ie(n) {
|
|
1509
|
+
if (!n || Oe.has(n))
|
|
1341
1510
|
return null;
|
|
1342
|
-
|
|
1343
|
-
`,
|
|
1511
|
+
Oe.add(n), console.debug("[gltf-progressive] found new model-viewer..." + ++wt + `
|
|
1512
|
+
`, n.getAttribute("src"));
|
|
1344
1513
|
let t = null, e = null, s = null;
|
|
1345
|
-
for (let
|
|
1346
|
-
const
|
|
1347
|
-
!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]);
|
|
1348
1517
|
}
|
|
1349
1518
|
if (t && e) {
|
|
1350
|
-
let
|
|
1519
|
+
let r = function() {
|
|
1351
1520
|
if (s) {
|
|
1352
|
-
let
|
|
1353
|
-
if (
|
|
1521
|
+
let o = 0, l = setInterval(() => {
|
|
1522
|
+
if (o++ > 5) {
|
|
1354
1523
|
clearInterval(l);
|
|
1355
1524
|
return;
|
|
1356
1525
|
}
|
|
1357
|
-
s?.call(
|
|
1526
|
+
s?.call(n);
|
|
1358
1527
|
}, 300);
|
|
1359
1528
|
}
|
|
1360
1529
|
};
|
|
1361
1530
|
console.debug("[gltf-progressive] setup model-viewer");
|
|
1362
|
-
const
|
|
1363
|
-
return v.addPlugin(new
|
|
1364
|
-
s?.call(
|
|
1365
|
-
}),
|
|
1366
|
-
|
|
1367
|
-
}),
|
|
1368
|
-
|
|
1531
|
+
const i = v.get(t, { engine: "model-viewer" });
|
|
1532
|
+
return v.addPlugin(new _t()), i.enable(), i.addEventListener("changed", () => {
|
|
1533
|
+
s?.call(n);
|
|
1534
|
+
}), n.addEventListener("model-visibility", (o) => {
|
|
1535
|
+
o.detail.visible && s?.call(n);
|
|
1536
|
+
}), n.addEventListener("load", () => {
|
|
1537
|
+
r();
|
|
1369
1538
|
}), () => {
|
|
1370
|
-
|
|
1539
|
+
i.disable();
|
|
1371
1540
|
};
|
|
1372
1541
|
}
|
|
1373
1542
|
return null;
|
|
1374
1543
|
}
|
|
1375
|
-
class
|
|
1544
|
+
class _t {
|
|
1376
1545
|
_didWarnAboutMissingUrl = !1;
|
|
1377
|
-
onBeforeUpdateLOD(t, e, s,
|
|
1378
|
-
this.tryParseMeshLOD(e,
|
|
1546
|
+
onBeforeUpdateLOD(t, e, s, r) {
|
|
1547
|
+
this.tryParseMeshLOD(e, r), this.tryParseTextureLOD(e, r);
|
|
1379
1548
|
}
|
|
1380
1549
|
getUrl(t) {
|
|
1381
1550
|
if (!t)
|
|
@@ -1390,101 +1559,101 @@ class xt {
|
|
|
1390
1559
|
return t.element;
|
|
1391
1560
|
}
|
|
1392
1561
|
tryParseTextureLOD(t, e) {
|
|
1393
|
-
if (e[
|
|
1394
|
-
e[
|
|
1395
|
-
const s = this.tryGetCurrentGLTF(t),
|
|
1396
|
-
if (
|
|
1397
|
-
let
|
|
1398
|
-
if (a[
|
|
1399
|
-
a[
|
|
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);
|
|
1400
1569
|
const u = Object.keys(a);
|
|
1401
|
-
for (let
|
|
1402
|
-
const y = u[
|
|
1570
|
+
for (let c = 0; c < u.length; c++) {
|
|
1571
|
+
const y = u[c], w = a[y];
|
|
1403
1572
|
if (w?.isTexture === !0) {
|
|
1404
1573
|
const _ = w.userData?.associations?.textures;
|
|
1405
1574
|
if (_ == null) continue;
|
|
1406
|
-
const
|
|
1407
|
-
if (!
|
|
1575
|
+
const k = s.parser.json.textures[_];
|
|
1576
|
+
if (!k) {
|
|
1408
1577
|
console.warn("Texture data not found for texture index " + _);
|
|
1409
1578
|
continue;
|
|
1410
1579
|
}
|
|
1411
|
-
if (
|
|
1412
|
-
const M =
|
|
1413
|
-
M &&
|
|
1580
|
+
if (k?.extensions?.[W]) {
|
|
1581
|
+
const M = k.extensions[W];
|
|
1582
|
+
M && i && m.registerTexture(i, w, M.lods.length, _, M);
|
|
1414
1583
|
}
|
|
1415
1584
|
}
|
|
1416
1585
|
}
|
|
1417
1586
|
};
|
|
1418
1587
|
const l = e.material;
|
|
1419
|
-
if (Array.isArray(l)) for (const a of l)
|
|
1420
|
-
else
|
|
1588
|
+
if (Array.isArray(l)) for (const a of l) o(a);
|
|
1589
|
+
else o(l);
|
|
1421
1590
|
}
|
|
1422
1591
|
}
|
|
1423
1592
|
tryParseMeshLOD(t, e) {
|
|
1424
|
-
if (e[
|
|
1425
|
-
e[
|
|
1426
|
-
const s = this.tryGetCurrentModelViewer(t),
|
|
1427
|
-
if (!
|
|
1593
|
+
if (e[Me] == !0) return;
|
|
1594
|
+
e[Me] = !0;
|
|
1595
|
+
const s = this.tryGetCurrentModelViewer(t), r = this.getUrl(s);
|
|
1596
|
+
if (!r)
|
|
1428
1597
|
return;
|
|
1429
|
-
const
|
|
1430
|
-
if (
|
|
1431
|
-
const
|
|
1432
|
-
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);
|
|
1433
1602
|
}
|
|
1434
1603
|
}
|
|
1435
1604
|
}
|
|
1436
|
-
function
|
|
1437
|
-
let t, e, s,
|
|
1438
|
-
switch (
|
|
1605
|
+
function Lt(...n) {
|
|
1606
|
+
let t, e, s, r;
|
|
1607
|
+
switch (n.length) {
|
|
1439
1608
|
case 2:
|
|
1440
|
-
[s, e] =
|
|
1609
|
+
[s, e] = n, r = {};
|
|
1441
1610
|
break;
|
|
1442
1611
|
case 3:
|
|
1443
|
-
[s, e,
|
|
1612
|
+
[s, e, r] = n;
|
|
1444
1613
|
break;
|
|
1445
1614
|
case 4:
|
|
1446
|
-
[t, e, s,
|
|
1615
|
+
[t, e, s, r] = n;
|
|
1447
1616
|
break;
|
|
1448
1617
|
default:
|
|
1449
1618
|
throw new Error("Invalid arguments");
|
|
1450
1619
|
}
|
|
1451
|
-
|
|
1620
|
+
we(e), Te(s), Ae(s, {
|
|
1452
1621
|
progressive: !0,
|
|
1453
|
-
...
|
|
1454
|
-
}), s.register((
|
|
1455
|
-
const
|
|
1456
|
-
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;
|
|
1457
1626
|
}
|
|
1458
|
-
|
|
1459
|
-
if (!
|
|
1460
|
-
const
|
|
1627
|
+
Re();
|
|
1628
|
+
if (!nt) {
|
|
1629
|
+
const n = {
|
|
1461
1630
|
gltfProgressive: {
|
|
1462
|
-
useNeedleProgressive:
|
|
1631
|
+
useNeedleProgressive: Lt,
|
|
1463
1632
|
LODsManager: v,
|
|
1464
|
-
configureLoader:
|
|
1465
|
-
getRaycastMesh:
|
|
1466
|
-
useRaycastMeshes:
|
|
1633
|
+
configureLoader: Ae,
|
|
1634
|
+
getRaycastMesh: ee,
|
|
1635
|
+
useRaycastMeshes: lt
|
|
1467
1636
|
}
|
|
1468
1637
|
};
|
|
1469
1638
|
if (!globalThis.Needle)
|
|
1470
|
-
globalThis.Needle =
|
|
1639
|
+
globalThis.Needle = n;
|
|
1471
1640
|
else
|
|
1472
|
-
for (const t in
|
|
1473
|
-
globalThis.Needle[t] =
|
|
1641
|
+
for (const t in n)
|
|
1642
|
+
globalThis.Needle[t] = n[t];
|
|
1474
1643
|
}
|
|
1475
1644
|
export {
|
|
1476
1645
|
W as EXTENSION_NAME,
|
|
1477
1646
|
v as LODsManager,
|
|
1478
1647
|
m as NEEDLE_progressive,
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
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
|
|
1490
1659
|
};
|