@needle-tools/gltf-progressive 3.1.1 → 3.2.0
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 +4 -0
- package/README.md +14 -3
- package/examples/react-three-fiber/src/App.tsx +1 -1
- package/examples/threejs/main.js +1 -1
- package/gltf-progressive.js +877 -740
- package/gltf-progressive.min.js +7 -7
- package/gltf-progressive.umd.cjs +7 -7
- package/lib/extension.d.ts +4 -1
- package/lib/extension.js +64 -10
- package/lib/index.d.ts +3 -17
- package/lib/index.js +29 -3
- package/lib/loaders.d.ts +8 -0
- package/lib/loaders.js +33 -22
- package/lib/lods.manager.js +20 -11
- package/lib/utils.internal.d.ts +4 -5
- package/lib/version.js +1 -1
- package/lib/worker/loader.mainthread.d.ts +45 -0
- package/lib/worker/loader.mainthread.js +193 -0
- package/lib/worker/loader.worker.js +165 -0
- package/package.json +2 -2
package/gltf-progressive.js
CHANGED
|
@@ -1,108 +1,98 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (t.has(o))
|
|
9
|
-
throw TypeError("Cannot add the same private member more than once");
|
|
10
|
-
t instanceof WeakSet ? t.add(o) : t.set(o, e);
|
|
11
|
-
}, V = (o, t, e, s) => (Ee(o, t, "write to private field"), s ? s.call(o, e) : t.set(o, e), e);
|
|
12
|
-
import { BufferGeometry as Le, Mesh as se, Texture as oe, TextureLoader as je, Matrix4 as Ie, Clock as Je, MeshStandardMaterial as Ze, Sphere as et, Box3 as $e, Vector3 as W } from "three";
|
|
13
|
-
import { GLTFLoader as Ce } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
14
|
-
import { MeshoptDecoder as tt } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
15
|
-
import { DRACOLoader as st } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
16
|
-
import { KTX2Loader as rt } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
17
|
-
const it = "";
|
|
18
|
-
globalThis.GLTF_PROGRESSIVE_VERSION = it;
|
|
1
|
+
import { BufferGeometry as Q, Mesh as q, Box3 as he, Vector3 as A, Sphere as De, CompressedTexture as $e, Texture as E, Matrix3 as Ge, InterleavedBuffer as Fe, InterleavedBufferAttribute as Ue, BufferAttribute as We, TextureLoader as ze, Matrix4 as Le, Clock as Ee, MeshStandardMaterial as Ne } from "three";
|
|
2
|
+
import { GLTFLoader as ye } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
3
|
+
import { MeshoptDecoder as qe } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
4
|
+
import { DRACOLoader as Ve } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
5
|
+
import { KTX2Loader as Xe } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
6
|
+
const Ke = "";
|
|
7
|
+
globalThis.GLTF_PROGRESSIVE_VERSION = Ke;
|
|
19
8
|
console.debug("[gltf-progressive] version -");
|
|
20
|
-
let
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
fetch(
|
|
9
|
+
let C = "https://www.gstatic.com/draco/versioned/decoders/1.5.7/", V = "https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";
|
|
10
|
+
const je = C, Ye = V, Oe = new URL(C + "draco_decoder.js");
|
|
11
|
+
Oe.searchParams.append("range", "true");
|
|
12
|
+
fetch(Oe, {
|
|
24
13
|
method: "GET",
|
|
25
14
|
headers: {
|
|
26
15
|
Range: "bytes=0-1"
|
|
27
16
|
}
|
|
28
|
-
}).catch((
|
|
29
|
-
console.debug(`Failed to fetch remote Draco decoder from ${
|
|
17
|
+
}).catch((i) => {
|
|
18
|
+
console.debug(`Failed to fetch remote Draco decoder from ${C} (offline: ${typeof navigator < "u" ? navigator.onLine : "unknown"})`), C === je && Qe("./include/draco/"), V === Ye && Je("./include/ktx2/");
|
|
30
19
|
}).finally(() => {
|
|
31
|
-
|
|
20
|
+
Pe();
|
|
21
|
+
});
|
|
22
|
+
const He = () => ({
|
|
23
|
+
dracoDecoderPath: C,
|
|
24
|
+
ktx2TranscoderPath: V
|
|
32
25
|
});
|
|
33
|
-
function
|
|
34
|
-
|
|
26
|
+
function Qe(i) {
|
|
27
|
+
C = i, T && T[ge] != C ? (console.debug("Updating Draco decoder path to " + i), T[ge] = C, T.setDecoderPath(C), T.preload()) : console.debug("Setting Draco decoder path to " + i);
|
|
35
28
|
}
|
|
36
|
-
function
|
|
37
|
-
|
|
29
|
+
function Je(i) {
|
|
30
|
+
V = i, R && R.transcoderPath != V ? (console.debug("Updating KTX2 transcoder path to " + i), R.setTranscoderPath(V), R.init()) : console.debug("Setting KTX2 transcoder path to " + i);
|
|
38
31
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
function Ne() {
|
|
42
|
-
k || (k = new st(), k[Pe] = q, k.setDecoderPath(q), k.setDecoderConfig({ type: "js" }), k.preload()), N || (N = new rt(), N.setTranscoderPath(re), N.init()), xe || (xe = tt);
|
|
32
|
+
function xe(i) {
|
|
33
|
+
return Pe(), i ? R.detectSupport(i) : i !== null && console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"), { dracoLoader: T, ktx2Loader: R, meshoptDecoder: ne };
|
|
43
34
|
}
|
|
44
|
-
function
|
|
45
|
-
|
|
35
|
+
function Se(i) {
|
|
36
|
+
i.dracoLoader || i.setDRACOLoader(T), i.ktx2Loader || i.setKTX2Loader(R), i.meshoptDecoder || i.setMeshoptDecoder(ne);
|
|
46
37
|
}
|
|
47
|
-
|
|
48
|
-
|
|
38
|
+
const ge = Symbol("dracoDecoderPath");
|
|
39
|
+
let T, ne, R;
|
|
40
|
+
function Pe() {
|
|
41
|
+
T || (T = new Ve(), T[ge] = C, T.setDecoderPath(C), T.setDecoderConfig({ type: "js" }), T.preload()), R || (R = new Xe(), R.setTranscoderPath(V), R.init()), ne || (ne = qe);
|
|
49
42
|
}
|
|
50
|
-
const
|
|
51
|
-
function
|
|
52
|
-
let e =
|
|
53
|
-
e ? e = Object.assign(e, t) : e = t,
|
|
43
|
+
const pe = /* @__PURE__ */ new WeakMap();
|
|
44
|
+
function Te(i, t) {
|
|
45
|
+
let e = pe.get(i);
|
|
46
|
+
e ? e = Object.assign(e, t) : e = t, pe.set(i, e);
|
|
54
47
|
}
|
|
55
|
-
const
|
|
56
|
-
function
|
|
57
|
-
const t =
|
|
58
|
-
let e =
|
|
48
|
+
const Ze = ye.prototype.load;
|
|
49
|
+
function et(...i) {
|
|
50
|
+
const t = pe.get(this);
|
|
51
|
+
let e = i[0];
|
|
59
52
|
const s = new URL(e, window.location.href);
|
|
60
53
|
if (s.hostname.endsWith("needle.tools")) {
|
|
61
|
-
const r =
|
|
62
|
-
r ? this.requestHeader.Accept = `*/*;progressive=allowed;usecase=${
|
|
54
|
+
const r = t?.progressive !== void 0 ? t.progressive : !0, o = t?.usecase ? t.usecase : "default";
|
|
55
|
+
r ? this.requestHeader.Accept = `*/*;progressive=allowed;usecase=${o}` : this.requestHeader.Accept = `*/*;usecase=${o}`, e = s.toString();
|
|
63
56
|
}
|
|
64
|
-
return
|
|
57
|
+
return i[0] = e, Ze?.call(this, ...i);
|
|
65
58
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
function
|
|
69
|
-
if (typeof window > "u")
|
|
70
|
-
|
|
71
|
-
const e = new URL(window.location.href).searchParams.get(o);
|
|
59
|
+
ye.prototype.load = et;
|
|
60
|
+
X("debugprogressive");
|
|
61
|
+
function X(i) {
|
|
62
|
+
if (typeof window > "u") return !1;
|
|
63
|
+
const e = new URL(window.location.href).searchParams.get(i);
|
|
72
64
|
return e == null || e === "0" || e === "false" ? !1 : e === "" ? !0 : e;
|
|
73
65
|
}
|
|
74
|
-
function
|
|
75
|
-
if (t === void 0 || t.startsWith("./") || t.startsWith("http") ||
|
|
66
|
+
function tt(i, t) {
|
|
67
|
+
if (t === void 0 || t.startsWith("./") || t.startsWith("http") || i === void 0)
|
|
76
68
|
return t;
|
|
77
|
-
const e =
|
|
69
|
+
const e = i.lastIndexOf("/");
|
|
78
70
|
if (e >= 0) {
|
|
79
|
-
const s =
|
|
80
|
-
for (; s.endsWith("/") && t.startsWith("/"); )
|
|
81
|
-
t = t.substring(1);
|
|
71
|
+
const s = i.substring(0, e + 1);
|
|
72
|
+
for (; s.endsWith("/") && t.startsWith("/"); ) t = t.substring(1);
|
|
82
73
|
return s + t;
|
|
83
74
|
}
|
|
84
75
|
return t;
|
|
85
76
|
}
|
|
86
|
-
let
|
|
87
|
-
function
|
|
88
|
-
return
|
|
77
|
+
let j;
|
|
78
|
+
function Ae() {
|
|
79
|
+
return j !== void 0 || (j = /iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent), X("debugprogressive") && console.log("[glTF Progressive]: isMobileDevice", j)), j;
|
|
89
80
|
}
|
|
90
|
-
function
|
|
91
|
-
if (typeof window > "u")
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return o.hostname === "127.0.0.1" || t;
|
|
81
|
+
function _e() {
|
|
82
|
+
if (typeof window > "u") return !1;
|
|
83
|
+
const i = new URL(window.location.href), t = i.hostname === "localhost" || /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(i.hostname);
|
|
84
|
+
return i.hostname === "127.0.0.1" || t;
|
|
95
85
|
}
|
|
96
|
-
class
|
|
86
|
+
class st {
|
|
97
87
|
constructor(t = 100, e = {}) {
|
|
98
|
-
u(this, "_running", /* @__PURE__ */ new Map());
|
|
99
|
-
u(this, "_queue", []);
|
|
100
|
-
u(this, "debug", !1);
|
|
101
|
-
u(this, "tick", () => {
|
|
102
|
-
this.internalUpdate(), setTimeout(this.tick, 10);
|
|
103
|
-
});
|
|
104
88
|
this.maxConcurrent = t, this.debug = e.debug ?? !1, window.requestAnimationFrame(this.tick);
|
|
105
89
|
}
|
|
90
|
+
_running = /* @__PURE__ */ new Map();
|
|
91
|
+
_queue = [];
|
|
92
|
+
debug = !1;
|
|
93
|
+
tick = () => {
|
|
94
|
+
this.internalUpdate(), setTimeout(this.tick, 10);
|
|
95
|
+
};
|
|
106
96
|
/**
|
|
107
97
|
* Request a slot for a promise with a specific key. This function returns a promise with a `use` method that can be called to add the promise to the queue.
|
|
108
98
|
*/
|
|
@@ -127,123 +117,258 @@ class ft {
|
|
|
127
117
|
}
|
|
128
118
|
}
|
|
129
119
|
}
|
|
130
|
-
const
|
|
131
|
-
function
|
|
132
|
-
return
|
|
120
|
+
const rt = typeof window > "u" && typeof document > "u", me = Symbol("needle:raycast-mesh");
|
|
121
|
+
function J(i) {
|
|
122
|
+
return i?.[me] instanceof Q ? i[me] : null;
|
|
133
123
|
}
|
|
134
|
-
function
|
|
135
|
-
if ((
|
|
136
|
-
const s =
|
|
137
|
-
s.userData = { isRaycastMesh: !0 },
|
|
124
|
+
function nt(i, t) {
|
|
125
|
+
if ((i.type === "Mesh" || i.type === "SkinnedMesh") && !J(i)) {
|
|
126
|
+
const s = it(t);
|
|
127
|
+
s.userData = { isRaycastMesh: !0 }, i[me] = s;
|
|
138
128
|
}
|
|
139
129
|
}
|
|
140
|
-
function
|
|
141
|
-
if (
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
r && n.isMesh && (i = n.geometry, n.geometry = r), t.call(this, e, s), i && (n.geometry = i);
|
|
130
|
+
function ot(i = !0) {
|
|
131
|
+
if (i) {
|
|
132
|
+
if (Y) return;
|
|
133
|
+
const t = Y = q.prototype.raycast;
|
|
134
|
+
q.prototype.raycast = function(e, s) {
|
|
135
|
+
const n = this, r = J(n);
|
|
136
|
+
let o;
|
|
137
|
+
r && n.isMesh && (o = n.geometry, n.geometry = r), t.call(this, e, s), o && (n.geometry = o);
|
|
149
138
|
};
|
|
150
139
|
} else {
|
|
151
|
-
if (!
|
|
152
|
-
|
|
153
|
-
se.prototype.raycast = le, le = null;
|
|
140
|
+
if (!Y) return;
|
|
141
|
+
q.prototype.raycast = Y, Y = null;
|
|
154
142
|
}
|
|
155
143
|
}
|
|
156
|
-
let
|
|
157
|
-
function
|
|
158
|
-
const t = new
|
|
159
|
-
for (const e in
|
|
160
|
-
t.setAttribute(e,
|
|
161
|
-
return t.setIndex(
|
|
144
|
+
let Y = null;
|
|
145
|
+
function it(i) {
|
|
146
|
+
const t = new Q();
|
|
147
|
+
for (const e in i.attributes)
|
|
148
|
+
t.setAttribute(e, i.getAttribute(e));
|
|
149
|
+
return t.setIndex(i.getIndex()), t;
|
|
162
150
|
}
|
|
163
|
-
const
|
|
164
|
-
let
|
|
165
|
-
if (
|
|
166
|
-
let
|
|
167
|
-
|
|
151
|
+
const W = new Array(), g = X("debugprogressive");
|
|
152
|
+
let re, N = -1;
|
|
153
|
+
if (g) {
|
|
154
|
+
let i = function() {
|
|
155
|
+
N += 1, N >= t && (N = -1), console.log(`Toggle LOD level [${N}]`);
|
|
168
156
|
}, t = 6;
|
|
169
157
|
window.addEventListener("keyup", (e) => {
|
|
170
|
-
e.key === "p" &&
|
|
158
|
+
e.key === "p" && i(), e.key === "w" && (re = !re, console.log(`Toggle wireframe [${re}]`));
|
|
171
159
|
const s = parseInt(e.key);
|
|
172
|
-
!isNaN(s) && s >= 0 && (
|
|
160
|
+
!isNaN(s) && s >= 0 && (N = s, console.log(`Set LOD level to [${N}]`));
|
|
173
161
|
});
|
|
174
162
|
}
|
|
175
|
-
function
|
|
176
|
-
if (
|
|
177
|
-
if (Array.isArray(
|
|
178
|
-
for (const t of
|
|
179
|
-
|
|
180
|
-
else
|
|
181
|
-
|
|
163
|
+
function Ie(i) {
|
|
164
|
+
if (g)
|
|
165
|
+
if (Array.isArray(i))
|
|
166
|
+
for (const t of i)
|
|
167
|
+
Ie(t);
|
|
168
|
+
else i && "wireframe" in i && (i.wireframe = re === !0);
|
|
169
|
+
}
|
|
170
|
+
const H = new Array();
|
|
171
|
+
let at = 0;
|
|
172
|
+
const lt = Ae() ? 2 : 10;
|
|
173
|
+
function ut(i) {
|
|
174
|
+
if (H.length < lt) {
|
|
175
|
+
const s = H.length;
|
|
176
|
+
g && console.warn(`[Worker] Creating new worker #${s}`);
|
|
177
|
+
const n = we.createWorker(i || {});
|
|
178
|
+
return H.push(n), n;
|
|
179
|
+
}
|
|
180
|
+
const t = at++ % H.length;
|
|
181
|
+
return H[t];
|
|
182
182
|
}
|
|
183
|
-
|
|
183
|
+
class we {
|
|
184
184
|
constructor(t, e) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
185
|
+
this.worker = t, this._debug = e.debug ?? !1, t.onmessage = (s) => {
|
|
186
|
+
const n = s.data;
|
|
187
|
+
switch (this._debug && console.log("[Worker] EVENT", n), n.type) {
|
|
188
|
+
case "loaded-gltf":
|
|
189
|
+
for (const r of this._running)
|
|
190
|
+
if (r.url === n.result.url) {
|
|
191
|
+
dt(n.result), r.resolve(n.result);
|
|
192
|
+
const o = r.url;
|
|
193
|
+
o.startsWith("blob:") && URL.revokeObjectURL(o);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}, t.onerror = (s) => {
|
|
197
|
+
console.error("[Worker] Error in gltf-progressive worker:", s);
|
|
198
|
+
}, t.postMessage({
|
|
199
|
+
type: "init"
|
|
197
200
|
});
|
|
198
|
-
y && console.log("Progressive extension registered for", e), this.parser = t, this.url = e;
|
|
199
201
|
}
|
|
202
|
+
static async createWorker(t) {
|
|
203
|
+
const e = new Worker(new URL(
|
|
204
|
+
/* @vite-ignore */
|
|
205
|
+
"/assets/loader.worker-CwaLRBn2.js",
|
|
206
|
+
import.meta.url
|
|
207
|
+
), {
|
|
208
|
+
type: "module"
|
|
209
|
+
});
|
|
210
|
+
return new we(e, t);
|
|
211
|
+
}
|
|
212
|
+
_running = [];
|
|
213
|
+
_webglRenderer = null;
|
|
214
|
+
async load(t, e) {
|
|
215
|
+
const s = He();
|
|
216
|
+
let n = e?.renderer;
|
|
217
|
+
n || (this._webglRenderer ??= (async () => {
|
|
218
|
+
const { WebGLRenderer: u } = await import("three");
|
|
219
|
+
return new u();
|
|
220
|
+
})(), n = await this._webglRenderer);
|
|
221
|
+
const l = xe(n).ktx2Loader.workerConfig;
|
|
222
|
+
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
|
+
const a = {
|
|
224
|
+
type: "load",
|
|
225
|
+
url: t,
|
|
226
|
+
dracoDecoderPath: s.dracoDecoderPath,
|
|
227
|
+
ktx2TranscoderPath: s.ktx2TranscoderPath,
|
|
228
|
+
ktx2LoaderConfig: l
|
|
229
|
+
};
|
|
230
|
+
return this._debug && console.debug("[Worker] Sending load request", a), this.worker.postMessage(a), new Promise((u) => {
|
|
231
|
+
this._running.push({
|
|
232
|
+
url: t.toString(),
|
|
233
|
+
resolve: u
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
_debug = !1;
|
|
238
|
+
}
|
|
239
|
+
function dt(i) {
|
|
240
|
+
for (const t of i.geometries) {
|
|
241
|
+
const e = t.geometry, s = new Q();
|
|
242
|
+
if (s.name = e.name || "", e.index) {
|
|
243
|
+
const n = e.index;
|
|
244
|
+
s.setIndex(ae(n));
|
|
245
|
+
}
|
|
246
|
+
for (const n in e.attributes) {
|
|
247
|
+
const r = e.attributes[n], o = ae(r);
|
|
248
|
+
s.setAttribute(n, o);
|
|
249
|
+
}
|
|
250
|
+
if (e.morphAttributes)
|
|
251
|
+
for (const n in e.morphAttributes) {
|
|
252
|
+
const o = e.morphAttributes[n].map((l) => ae(l));
|
|
253
|
+
s.morphAttributes[n] = o;
|
|
254
|
+
}
|
|
255
|
+
if (s.morphTargetsRelative = e.morphTargetsRelative ?? !1, s.boundingBox = new he(), s.boundingBox.min = new A(
|
|
256
|
+
e.boundingBox?.min.x,
|
|
257
|
+
e.boundingBox?.min.y,
|
|
258
|
+
e.boundingBox?.min.z
|
|
259
|
+
), s.boundingBox.max = new A(
|
|
260
|
+
e.boundingBox?.max.x,
|
|
261
|
+
e.boundingBox?.max.y,
|
|
262
|
+
e.boundingBox?.max.z
|
|
263
|
+
), s.boundingSphere = new De(
|
|
264
|
+
new A(
|
|
265
|
+
e.boundingSphere?.center.x,
|
|
266
|
+
e.boundingSphere?.center.y,
|
|
267
|
+
e.boundingSphere?.center.z
|
|
268
|
+
),
|
|
269
|
+
e.boundingSphere?.radius
|
|
270
|
+
), e.groups)
|
|
271
|
+
for (const n of e.groups)
|
|
272
|
+
s.addGroup(n.start, n.count, n.materialIndex);
|
|
273
|
+
e.userData && (s.userData = e.userData), t.geometry = s;
|
|
274
|
+
}
|
|
275
|
+
for (const t of i.textures) {
|
|
276
|
+
const e = t.texture;
|
|
277
|
+
let s = null;
|
|
278
|
+
if (e.isCompressedTexture) {
|
|
279
|
+
const n = e.mipmaps, r = e.image?.width || e.source?.data?.width || -1, o = e.image?.height || e.source?.data?.height || -1;
|
|
280
|
+
s = new $e(
|
|
281
|
+
n,
|
|
282
|
+
r,
|
|
283
|
+
o,
|
|
284
|
+
e.format,
|
|
285
|
+
e.type,
|
|
286
|
+
e.mapping,
|
|
287
|
+
e.wrapS,
|
|
288
|
+
e.wrapT,
|
|
289
|
+
e.magFilter,
|
|
290
|
+
e.minFilter,
|
|
291
|
+
e.anisotropy,
|
|
292
|
+
e.colorSpace
|
|
293
|
+
);
|
|
294
|
+
} else
|
|
295
|
+
s = new E(
|
|
296
|
+
e.image,
|
|
297
|
+
e.mapping,
|
|
298
|
+
e.wrapS,
|
|
299
|
+
e.wrapT,
|
|
300
|
+
e.magFilter,
|
|
301
|
+
e.minFilter,
|
|
302
|
+
e.format,
|
|
303
|
+
e.type,
|
|
304
|
+
e.anisotropy,
|
|
305
|
+
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 Ge(...e.matrix.elements);
|
|
307
|
+
if (!s) {
|
|
308
|
+
console.error("[Worker] Failed to create new texture from received data. Texture is not a CompressedTexture or Texture.");
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
t.texture = s;
|
|
312
|
+
}
|
|
313
|
+
return i;
|
|
314
|
+
}
|
|
315
|
+
function ae(i) {
|
|
316
|
+
let t = i;
|
|
317
|
+
if ("isInterleavedBufferAttribute" in i && i.isInterleavedBufferAttribute) {
|
|
318
|
+
const e = i.data, s = e.array, n = new Fe(s, e.stride);
|
|
319
|
+
t = new Ue(n, i.itemSize, s.byteOffset, i.normalized), t.offset = i.offset;
|
|
320
|
+
} else "isBufferAttribute" in i && i.isBufferAttribute && (t = new We(i.array, i.itemSize, i.normalized), t.usage = i.usage, t.gpuType = i.gpuType, t.updateRanges = i.updateRanges);
|
|
321
|
+
return t;
|
|
322
|
+
}
|
|
323
|
+
const ct = X("gltf-progressive-worker"), ft = X("gltf-progressive-reduce-mipmaps"), le = Symbol("needle-progressive-texture"), F = "NEEDLE_progressive";
|
|
324
|
+
class y {
|
|
200
325
|
/** The name of the extension */
|
|
201
326
|
get name() {
|
|
202
|
-
return
|
|
327
|
+
return F;
|
|
203
328
|
}
|
|
204
329
|
static getMeshLODExtension(t) {
|
|
205
330
|
const e = this.getAssignedLODInformation(t);
|
|
206
|
-
return e
|
|
331
|
+
return e?.key ? this.lodInfos.get(e.key) : null;
|
|
207
332
|
}
|
|
208
333
|
static getPrimitiveIndex(t) {
|
|
209
|
-
|
|
210
|
-
const e = (s = this.getAssignedLODInformation(t)) == null ? void 0 : s.index;
|
|
334
|
+
const e = this.getAssignedLODInformation(t)?.index;
|
|
211
335
|
return e ?? -1;
|
|
212
336
|
}
|
|
213
337
|
static getMaterialMinMaxLODsCount(t, e) {
|
|
214
338
|
const s = this, n = "LODS:minmax", r = t[n];
|
|
215
|
-
if (r != null)
|
|
216
|
-
return r;
|
|
339
|
+
if (r != null) return r;
|
|
217
340
|
if (e || (e = {
|
|
218
341
|
min_count: 1 / 0,
|
|
219
342
|
max_count: 0,
|
|
220
343
|
lods: []
|
|
221
344
|
}), Array.isArray(t)) {
|
|
222
|
-
for (const
|
|
223
|
-
this.getMaterialMinMaxLODsCount(
|
|
345
|
+
for (const l of t)
|
|
346
|
+
this.getMaterialMinMaxLODsCount(l, e);
|
|
224
347
|
return t[n] = e, e;
|
|
225
348
|
}
|
|
226
|
-
if (
|
|
227
|
-
const
|
|
228
|
-
for (const
|
|
229
|
-
const
|
|
230
|
-
|
|
349
|
+
if (g === "verbose" && console.log("getMaterialMinMaxLODsCount", t), t.type === "ShaderMaterial" || t.type === "RawShaderMaterial") {
|
|
350
|
+
const l = t;
|
|
351
|
+
for (const a of Object.keys(l.uniforms)) {
|
|
352
|
+
const u = l.uniforms[a].value;
|
|
353
|
+
u?.isTexture === !0 && o(u, e);
|
|
231
354
|
}
|
|
232
355
|
} else if (t.isMaterial)
|
|
233
|
-
for (const
|
|
234
|
-
const
|
|
235
|
-
|
|
356
|
+
for (const l of Object.keys(t)) {
|
|
357
|
+
const a = t[l];
|
|
358
|
+
a?.isTexture === !0 && o(a, e);
|
|
236
359
|
}
|
|
360
|
+
else
|
|
361
|
+
g && console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);
|
|
237
362
|
return t[n] = e, e;
|
|
238
|
-
function
|
|
239
|
-
const
|
|
240
|
-
if (
|
|
241
|
-
const
|
|
242
|
-
if (
|
|
243
|
-
|
|
244
|
-
for (let
|
|
245
|
-
const
|
|
246
|
-
|
|
363
|
+
function o(l, a) {
|
|
364
|
+
const u = s.getAssignedLODInformation(l);
|
|
365
|
+
if (u) {
|
|
366
|
+
const c = s.lodInfos.get(u.key);
|
|
367
|
+
if (c && c.lods) {
|
|
368
|
+
a.min_count = Math.min(a.min_count, c.lods.length), a.max_count = Math.max(a.max_count, c.lods.length);
|
|
369
|
+
for (let p = 0; p < c.lods.length; p++) {
|
|
370
|
+
const _ = c.lods[p];
|
|
371
|
+
_.width && (a.lods[p] = a.lods[p] || { min_height: 1 / 0, max_height: 0 }, a.lods[p].min_height = Math.min(a.lods[p].min_height, _.height), a.lods[p].max_height = Math.max(a.lods[p].max_height, _.height));
|
|
247
372
|
}
|
|
248
373
|
}
|
|
249
374
|
}
|
|
@@ -255,30 +380,27 @@ const X = "NEEDLE_progressive", Oe = Symbol("needle-progressive-texture"), O = c
|
|
|
255
380
|
* @returns true if the LOD level is available (or if any LOD level is available if level is undefined)
|
|
256
381
|
*/
|
|
257
382
|
static hasLODLevelAvailable(t, e) {
|
|
258
|
-
var r;
|
|
259
383
|
if (Array.isArray(t)) {
|
|
260
|
-
for (const
|
|
261
|
-
if (this.hasLODLevelAvailable(
|
|
262
|
-
return !0;
|
|
384
|
+
for (const r of t)
|
|
385
|
+
if (this.hasLODLevelAvailable(r, e)) return !0;
|
|
263
386
|
return !1;
|
|
264
387
|
}
|
|
265
388
|
if (t.isMaterial === !0) {
|
|
266
|
-
for (const
|
|
267
|
-
const
|
|
268
|
-
if (
|
|
389
|
+
for (const r of Object.keys(t)) {
|
|
390
|
+
const o = t[r];
|
|
391
|
+
if (o && o.isTexture && this.hasLODLevelAvailable(o, e))
|
|
269
392
|
return !0;
|
|
270
393
|
}
|
|
271
394
|
return !1;
|
|
272
395
|
} else if (t.isGroup === !0) {
|
|
273
|
-
for (const
|
|
274
|
-
if (
|
|
396
|
+
for (const r of t.children)
|
|
397
|
+
if (r.isMesh === !0 && this.hasLODLevelAvailable(r, e))
|
|
275
398
|
return !0;
|
|
276
399
|
}
|
|
277
400
|
let s, n;
|
|
278
|
-
if (t.isMesh ? s = t.geometry : (t.isBufferGeometry || t.isTexture) && (s = t), s &&
|
|
279
|
-
const
|
|
280
|
-
if (n = this.lodInfos.get(
|
|
281
|
-
return n != null;
|
|
401
|
+
if (t.isMesh ? s = t.geometry : (t.isBufferGeometry || t.isTexture) && (s = t), s && s?.userData?.LODS) {
|
|
402
|
+
const r = s.userData.LODS;
|
|
403
|
+
if (n = this.lodInfos.get(r.key), e === void 0) return n != null;
|
|
282
404
|
if (n)
|
|
283
405
|
return Array.isArray(n.lods) ? e < n.lods.length : e === 0;
|
|
284
406
|
}
|
|
@@ -299,42 +421,38 @@ const X = "NEEDLE_progressive", Oe = Symbol("needle-progressive-texture"), O = c
|
|
|
299
421
|
* ```
|
|
300
422
|
*/
|
|
301
423
|
static assignMeshLOD(t, e) {
|
|
302
|
-
|
|
303
|
-
if (!
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const n = t.geometry, r = this.getAssignedLODInformation(n);
|
|
307
|
-
if (!r)
|
|
424
|
+
if (!t) return Promise.resolve(null);
|
|
425
|
+
if (t instanceof q || t.isMesh === !0) {
|
|
426
|
+
const s = t.geometry, n = this.getAssignedLODInformation(s);
|
|
427
|
+
if (!n)
|
|
308
428
|
return Promise.resolve(null);
|
|
309
|
-
for (const
|
|
310
|
-
|
|
311
|
-
return t["LOD:requested level"] = e,
|
|
312
|
-
if (Array.isArray(
|
|
313
|
-
const
|
|
314
|
-
|
|
429
|
+
for (const r of W)
|
|
430
|
+
r.onBeforeGetLODMesh?.(t, e);
|
|
431
|
+
return t["LOD:requested level"] = e, y.getOrLoadLOD(s, e).then((r) => {
|
|
432
|
+
if (Array.isArray(r)) {
|
|
433
|
+
const o = n.index || 0;
|
|
434
|
+
r = r[o];
|
|
315
435
|
}
|
|
316
|
-
return t["LOD:requested level"] === e && (delete t["LOD:requested level"],
|
|
317
|
-
}).catch((
|
|
318
|
-
} else
|
|
319
|
-
y && console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh", t);
|
|
436
|
+
return t["LOD:requested level"] === e && (delete t["LOD:requested level"], r && s != r && (r?.isBufferGeometry ? t.geometry = r : g && console.error("Invalid LOD geometry", r))), r;
|
|
437
|
+
}).catch((r) => (console.error("Error loading mesh LOD", t, r), null));
|
|
438
|
+
} else g && console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh", t);
|
|
320
439
|
return Promise.resolve(null);
|
|
321
440
|
}
|
|
322
441
|
static assignTextureLOD(t, e = 0) {
|
|
323
|
-
if (!t)
|
|
324
|
-
return Promise.resolve(null);
|
|
442
|
+
if (!t) return Promise.resolve(null);
|
|
325
443
|
if (t.isMesh === !0) {
|
|
326
444
|
const s = t;
|
|
327
445
|
if (Array.isArray(s.material)) {
|
|
328
446
|
const n = new Array();
|
|
329
447
|
for (const r of s.material) {
|
|
330
|
-
const
|
|
331
|
-
n.push(
|
|
448
|
+
const o = this.assignTextureLOD(r, e);
|
|
449
|
+
n.push(o);
|
|
332
450
|
}
|
|
333
451
|
return Promise.all(n).then((r) => {
|
|
334
|
-
const
|
|
335
|
-
for (const
|
|
336
|
-
Array.isArray(
|
|
337
|
-
return
|
|
452
|
+
const o = new Array();
|
|
453
|
+
for (const l of r)
|
|
454
|
+
Array.isArray(l) && o.push(...l);
|
|
455
|
+
return o;
|
|
338
456
|
});
|
|
339
457
|
} else
|
|
340
458
|
return this.assignTextureLOD(s.material, e);
|
|
@@ -342,57 +460,72 @@ const X = "NEEDLE_progressive", Oe = Symbol("needle-progressive-texture"), O = c
|
|
|
342
460
|
if (t.isMaterial === !0) {
|
|
343
461
|
const s = t, n = [], r = new Array();
|
|
344
462
|
if (s.uniforms && (s.isRawShaderMaterial || s.isShaderMaterial === !0)) {
|
|
345
|
-
const
|
|
346
|
-
for (const
|
|
347
|
-
const
|
|
348
|
-
if (
|
|
349
|
-
const
|
|
350
|
-
n.push(
|
|
463
|
+
const o = s;
|
|
464
|
+
for (const l of Object.keys(o.uniforms)) {
|
|
465
|
+
const a = o.uniforms[l].value;
|
|
466
|
+
if (a?.isTexture === !0) {
|
|
467
|
+
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));
|
|
468
|
+
n.push(u), r.push(l);
|
|
351
469
|
}
|
|
352
470
|
}
|
|
353
471
|
} else
|
|
354
|
-
for (const
|
|
355
|
-
const
|
|
356
|
-
if (
|
|
357
|
-
const
|
|
358
|
-
n.push(
|
|
472
|
+
for (const o of Object.keys(s)) {
|
|
473
|
+
const l = s[o];
|
|
474
|
+
if (l?.isTexture === !0) {
|
|
475
|
+
const a = this.assignTextureLODForSlot(l, e, s, o);
|
|
476
|
+
n.push(a), r.push(o);
|
|
359
477
|
}
|
|
360
478
|
}
|
|
361
|
-
return Promise.all(n).then((
|
|
362
|
-
const
|
|
363
|
-
for (let
|
|
364
|
-
const
|
|
365
|
-
|
|
479
|
+
return Promise.all(n).then((o) => {
|
|
480
|
+
const l = new Array();
|
|
481
|
+
for (let a = 0; a < o.length; a++) {
|
|
482
|
+
const u = o[a], c = r[a];
|
|
483
|
+
u && u.isTexture === !0 ? l.push({ material: s, slot: c, texture: u, level: e }) : l.push({ material: s, slot: c, texture: null, level: e });
|
|
366
484
|
}
|
|
367
|
-
return
|
|
485
|
+
return l;
|
|
368
486
|
});
|
|
369
487
|
}
|
|
370
|
-
if (t instanceof
|
|
488
|
+
if (t instanceof E || t.isTexture === !0) {
|
|
371
489
|
const s = t;
|
|
372
490
|
return this.assignTextureLODForSlot(s, e, null, null);
|
|
373
491
|
}
|
|
374
492
|
return Promise.resolve(null);
|
|
375
493
|
}
|
|
376
494
|
static assignTextureLODForSlot(t, e, s, n) {
|
|
377
|
-
return
|
|
495
|
+
return t?.isTexture !== !0 ? Promise.resolve(null) : n === "glyphMap" ? Promise.resolve(t) : y.getOrLoadLOD(t, e).then((r) => {
|
|
378
496
|
if (Array.isArray(r))
|
|
379
|
-
return console.warn("Progressive: Got an array of textures for a texture slot, this should not happen"
|
|
380
|
-
if (
|
|
497
|
+
return console.warn("Progressive: Got an array of textures for a texture slot, this should not happen..."), null;
|
|
498
|
+
if (r?.isTexture === !0) {
|
|
381
499
|
if (r != t && s && n) {
|
|
382
|
-
const
|
|
383
|
-
if (
|
|
384
|
-
const
|
|
385
|
-
if (
|
|
386
|
-
return
|
|
500
|
+
const o = s[n];
|
|
501
|
+
if (o && !g) {
|
|
502
|
+
const l = this.getAssignedLODInformation(o);
|
|
503
|
+
if (l && l?.level < e)
|
|
504
|
+
return g === "verbose" && console.warn("Assigned texture level is already higher: ", l.level, e, s, o, r), null;
|
|
505
|
+
}
|
|
506
|
+
if (ft && r.mipmaps) {
|
|
507
|
+
const l = r.mipmaps.length;
|
|
508
|
+
r.mipmaps.length = Math.min(r.mipmaps.length, 3), l !== r.mipmaps.length && g && console.debug(`Reduced mipmap count from ${l} to ${r.mipmaps.length} for ${r.uuid}: ${r.image?.width}x${r.image?.height}.`);
|
|
387
509
|
}
|
|
388
510
|
s[n] = r;
|
|
389
511
|
}
|
|
390
512
|
return r;
|
|
391
|
-
} else
|
|
392
|
-
y == "verbose" && console.warn("No LOD found for", t, e);
|
|
513
|
+
} else g == "verbose" && console.warn("No LOD found for", t, e);
|
|
393
514
|
return null;
|
|
394
515
|
}).catch((r) => (console.error("Error loading LOD", t, r), null));
|
|
395
516
|
}
|
|
517
|
+
parser;
|
|
518
|
+
url;
|
|
519
|
+
constructor(t) {
|
|
520
|
+
const e = t.options.path;
|
|
521
|
+
g && console.log("Progressive extension registered for", e), this.parser = t, this.url = e;
|
|
522
|
+
}
|
|
523
|
+
_isLoadingMesh;
|
|
524
|
+
loadMesh = (t) => {
|
|
525
|
+
if (this._isLoadingMesh) return null;
|
|
526
|
+
const e = this.parser.json.meshes[t]?.extensions?.[F];
|
|
527
|
+
return e ? (this._isLoadingMesh = !0, this.parser.getDependency("mesh", t).then((s) => (this._isLoadingMesh = !1, s && y.registerMesh(this.url, e.guid, s, e.lods?.length, 0, e), s))) : null;
|
|
528
|
+
};
|
|
396
529
|
// private _isLoadingTexture;
|
|
397
530
|
// loadTexture = (textureIndex: number) => {
|
|
398
531
|
// if (this._isLoadingTexture) return null;
|
|
@@ -408,243 +541,239 @@ const X = "NEEDLE_progressive", Oe = Symbol("needle-progressive-texture"), O = c
|
|
|
408
541
|
// });
|
|
409
542
|
// }
|
|
410
543
|
afterRoot(t) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
if (!a.lods) {
|
|
418
|
-
y && console.warn("Texture has no LODs", a);
|
|
544
|
+
return g && console.log("AFTER", this.url, t), this.parser.json.textures?.forEach((e, s) => {
|
|
545
|
+
if (e?.extensions) {
|
|
546
|
+
const n = e?.extensions[F];
|
|
547
|
+
if (n) {
|
|
548
|
+
if (!n.lods) {
|
|
549
|
+
g && console.warn("Texture has no LODs", n);
|
|
419
550
|
return;
|
|
420
551
|
}
|
|
421
|
-
let
|
|
422
|
-
for (const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
}
|
|
427
|
-
l || this.parser.getDependency("texture", r).then((c) => {
|
|
428
|
-
var d;
|
|
429
|
-
c && O.registerTexture(this.url, c, (d = a.lods) == null ? void 0 : d.length, r, a);
|
|
552
|
+
let r = !1;
|
|
553
|
+
for (const o of this.parser.associations.keys())
|
|
554
|
+
o.isTexture === !0 && this.parser.associations.get(o)?.textures === s && (r = !0, y.registerTexture(this.url, o, n.lods?.length, s, n));
|
|
555
|
+
r || this.parser.getDependency("texture", s).then((o) => {
|
|
556
|
+
o && y.registerTexture(this.url, o, n.lods?.length, s, n);
|
|
430
557
|
});
|
|
431
558
|
}
|
|
432
559
|
}
|
|
433
|
-
}),
|
|
434
|
-
if (
|
|
435
|
-
const
|
|
436
|
-
if (
|
|
437
|
-
for (const
|
|
438
|
-
if (
|
|
439
|
-
const
|
|
440
|
-
|
|
560
|
+
}), this.parser.json.meshes?.forEach((e, s) => {
|
|
561
|
+
if (e?.extensions) {
|
|
562
|
+
const n = e?.extensions[F];
|
|
563
|
+
if (n && n.lods) {
|
|
564
|
+
for (const r of this.parser.associations.keys())
|
|
565
|
+
if (r.isMesh) {
|
|
566
|
+
const o = this.parser.associations.get(r);
|
|
567
|
+
o?.meshes === s && y.registerMesh(this.url, n.guid, r, n.lods.length, o.primitives, n);
|
|
441
568
|
}
|
|
442
569
|
}
|
|
443
570
|
}
|
|
444
571
|
}), null;
|
|
445
572
|
}
|
|
573
|
+
/**
|
|
574
|
+
* Register a texture with LOD information
|
|
575
|
+
*/
|
|
576
|
+
static registerTexture = (t, e, s, n, r) => {
|
|
577
|
+
if (!e) {
|
|
578
|
+
g && console.error("gltf-progressive: Called register texture without texture");
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
if (g) {
|
|
582
|
+
const l = e.image?.width || e.source?.data?.width || 0, a = e.image?.height || e.source?.data?.height || 0;
|
|
583
|
+
console.log(`> Progressive: register texture[${n}] "${e.name || e.uuid}", Current: ${l}x${a}, Max: ${r.lods[0]?.width}x${r.lods[0]?.height}, uuid: ${e.uuid}`, r, e);
|
|
584
|
+
}
|
|
585
|
+
e.source && (e.source[le] = r);
|
|
586
|
+
const o = r.guid;
|
|
587
|
+
y.assignLODInformation(t, e, o, s, n), y.lodInfos.set(o, r), y.lowresCache.set(o, e);
|
|
588
|
+
};
|
|
589
|
+
/**
|
|
590
|
+
* Register a mesh with LOD information
|
|
591
|
+
*/
|
|
592
|
+
static registerMesh = (t, e, s, n, r, o) => {
|
|
593
|
+
const l = s.geometry;
|
|
594
|
+
if (!l) {
|
|
595
|
+
g && console.warn("gltf-progressive: Register mesh without geometry");
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
l.userData || (l.userData = {}), g && console.log("> Progressive: register mesh " + s.name, { index: r, uuid: s.uuid }, o, s), y.assignLODInformation(t, l, e, n, r), y.lodInfos.set(e, o);
|
|
599
|
+
let a = y.lowresCache.get(e);
|
|
600
|
+
a ? a.push(s.geometry) : a = [s.geometry], y.lowresCache.set(e, a), n > 0 && !J(s) && nt(s, l);
|
|
601
|
+
for (const u of W)
|
|
602
|
+
u.onRegisteredNewMesh?.(s, o);
|
|
603
|
+
};
|
|
604
|
+
/** A map of key = asset uuid and value = LOD information */
|
|
605
|
+
static lodInfos = /* @__PURE__ */ new Map();
|
|
606
|
+
/** cache of already loaded mesh lods */
|
|
607
|
+
static previouslyLoaded = /* @__PURE__ */ new Map();
|
|
608
|
+
/** this contains the geometry/textures that were originally loaded */
|
|
609
|
+
static lowresCache = /* @__PURE__ */ new Map();
|
|
610
|
+
static workers = [];
|
|
611
|
+
static _workersIndex = 0;
|
|
446
612
|
static async getOrLoadLOD(t, e) {
|
|
447
|
-
|
|
448
|
-
const s = y == "verbose", n = this.getAssignedLODInformation(t);
|
|
613
|
+
const s = g == "verbose", n = this.getAssignedLODInformation(t);
|
|
449
614
|
if (!n)
|
|
450
|
-
return
|
|
451
|
-
const r = n
|
|
452
|
-
let
|
|
615
|
+
return g && console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`, t), null;
|
|
616
|
+
const r = n?.key;
|
|
617
|
+
let o;
|
|
453
618
|
if (t.isTexture === !0) {
|
|
454
|
-
const
|
|
455
|
-
|
|
619
|
+
const a = t;
|
|
620
|
+
a.source && a.source[le] && (o = a.source[le]);
|
|
456
621
|
}
|
|
457
|
-
if (
|
|
622
|
+
if (o || (o = y.lodInfos.get(r)), o) {
|
|
458
623
|
if (e > 0) {
|
|
459
|
-
let
|
|
460
|
-
const
|
|
461
|
-
if (
|
|
624
|
+
let c = !1;
|
|
625
|
+
const p = Array.isArray(o.lods);
|
|
626
|
+
if (p && e >= o.lods.length ? c = !0 : p || (c = !0), c)
|
|
462
627
|
return this.lowresCache.get(r);
|
|
463
628
|
}
|
|
464
|
-
const
|
|
465
|
-
if (!
|
|
466
|
-
return
|
|
467
|
-
const
|
|
468
|
-
if (
|
|
469
|
-
if (!
|
|
470
|
-
return console.warn("missing pointer for glb/gltf texture",
|
|
471
|
-
const
|
|
472
|
-
if (
|
|
473
|
-
s && console.log(`LOD ${e} was already loading/loaded: ${
|
|
474
|
-
let
|
|
475
|
-
`,
|
|
476
|
-
if (
|
|
477
|
-
return
|
|
629
|
+
const a = Array.isArray(o.lods) ? o.lods[e]?.path : o.lods;
|
|
630
|
+
if (!a)
|
|
631
|
+
return g && !o["missing:uri"] && (o["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + e, o)), null;
|
|
632
|
+
const u = tt(n.url, a);
|
|
633
|
+
if (u.endsWith(".glb") || u.endsWith(".gltf")) {
|
|
634
|
+
if (!o.guid)
|
|
635
|
+
return console.warn("missing pointer for glb/gltf texture", o), null;
|
|
636
|
+
const c = u + "_" + o.guid, p = await this.queue.slot(u), _ = this.previouslyLoaded.get(c);
|
|
637
|
+
if (_ !== void 0) {
|
|
638
|
+
s && console.log(`LOD ${e} was already loading/loaded: ${c}`);
|
|
639
|
+
let d = await _.catch((O) => (console.error(`Error loading LOD ${e} from ${u}
|
|
640
|
+
`, O), null)), x = !1;
|
|
641
|
+
if (d == null || (d instanceof E && t instanceof E ? d.image?.data || d.source?.data ? d = this.copySettings(t, d) : (x = !0, this.previouslyLoaded.delete(c)) : d instanceof Q && t instanceof Q && (d.attributes.position?.array || (x = !0, this.previouslyLoaded.delete(c)))), !x)
|
|
642
|
+
return d;
|
|
478
643
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
644
|
+
if (!p.use)
|
|
645
|
+
return g && console.log(`LOD ${e} was aborted: ${u}`), null;
|
|
646
|
+
const v = o, I = new Promise(async (d, x) => {
|
|
647
|
+
if (ct) {
|
|
648
|
+
const m = await (await ut({})).load(u);
|
|
649
|
+
if (m.textures.length > 0)
|
|
650
|
+
for (const f of m.textures) {
|
|
651
|
+
let h = f.texture;
|
|
652
|
+
return y.assignLODInformation(n.url, h, r, e, void 0), t instanceof E && (h = this.copySettings(t, h)), h && (h.guid = v.guid), d(h);
|
|
653
|
+
}
|
|
654
|
+
if (m.geometries.length > 0) {
|
|
655
|
+
const f = new Array();
|
|
656
|
+
for (const h of m.geometries) {
|
|
657
|
+
const M = h.geometry;
|
|
658
|
+
y.assignLODInformation(n.url, M, r, e, h.primitiveIndex), f.push(M);
|
|
659
|
+
}
|
|
660
|
+
return d(f);
|
|
661
|
+
}
|
|
662
|
+
return d(null);
|
|
663
|
+
}
|
|
664
|
+
const O = new ye();
|
|
665
|
+
Se(O), g && (await new Promise((w) => setTimeout(w, 1e3)), s && console.warn("Start loading (delayed) " + u, v.guid));
|
|
666
|
+
let B = u;
|
|
667
|
+
if (v && Array.isArray(v.lods)) {
|
|
668
|
+
const w = v.lods[e];
|
|
669
|
+
w.hash && (B += "?v=" + w.hash);
|
|
489
670
|
}
|
|
490
|
-
const
|
|
491
|
-
`,
|
|
492
|
-
if (!
|
|
493
|
-
return
|
|
494
|
-
const
|
|
495
|
-
s && console.log("Loading finished " +
|
|
496
|
-
let
|
|
497
|
-
if (
|
|
498
|
-
let
|
|
499
|
-
for (const m of
|
|
500
|
-
if (m
|
|
501
|
-
const
|
|
502
|
-
if (
|
|
503
|
-
|
|
671
|
+
const b = await O.loadAsync(B).catch((w) => (console.error(`Error loading LOD ${e} from ${u}
|
|
672
|
+
`, w), d(null)));
|
|
673
|
+
if (!b)
|
|
674
|
+
return d(null);
|
|
675
|
+
const z = b.parser;
|
|
676
|
+
s && console.log("Loading finished " + u, v.guid);
|
|
677
|
+
let S = 0;
|
|
678
|
+
if (b.parser.json.textures) {
|
|
679
|
+
let w = !1;
|
|
680
|
+
for (const m of b.parser.json.textures) {
|
|
681
|
+
if (m?.extensions) {
|
|
682
|
+
const f = m?.extensions[F];
|
|
683
|
+
if (f?.guid && f.guid === v.guid) {
|
|
684
|
+
w = !0;
|
|
504
685
|
break;
|
|
505
686
|
}
|
|
506
687
|
}
|
|
507
|
-
|
|
688
|
+
S++;
|
|
508
689
|
}
|
|
509
|
-
if (
|
|
510
|
-
let m = await
|
|
511
|
-
return m &&
|
|
512
|
-
} else
|
|
513
|
-
y && console.warn("Could not find texture with guid", M.guid, S.parser.json);
|
|
690
|
+
if (w) {
|
|
691
|
+
let m = await z.getDependency("texture", S);
|
|
692
|
+
return m && y.assignLODInformation(n.url, m, r, e, void 0), s && console.log('change "' + t.name + '" → "' + m.name + '"', u, S, m, c), t instanceof E && (m = this.copySettings(t, m)), m && (m.guid = v.guid), d(m);
|
|
693
|
+
} else g && console.warn("Could not find texture with guid", v.guid, b.parser.json);
|
|
514
694
|
}
|
|
515
|
-
if (
|
|
516
|
-
let
|
|
517
|
-
for (const m of
|
|
518
|
-
if (m
|
|
519
|
-
const
|
|
520
|
-
if (
|
|
521
|
-
|
|
695
|
+
if (S = 0, b.parser.json.meshes) {
|
|
696
|
+
let w = !1;
|
|
697
|
+
for (const m of b.parser.json.meshes) {
|
|
698
|
+
if (m?.extensions) {
|
|
699
|
+
const f = m?.extensions[F];
|
|
700
|
+
if (f?.guid && f.guid === v.guid) {
|
|
701
|
+
w = !0;
|
|
522
702
|
break;
|
|
523
703
|
}
|
|
524
704
|
}
|
|
525
|
-
|
|
705
|
+
S++;
|
|
526
706
|
}
|
|
527
|
-
if (
|
|
528
|
-
const m = await
|
|
529
|
-
if (s && console.log(`Loaded Mesh "${m.name}"`,
|
|
530
|
-
const
|
|
531
|
-
return
|
|
707
|
+
if (w) {
|
|
708
|
+
const m = await z.getDependency("mesh", S);
|
|
709
|
+
if (s && console.log(`Loaded Mesh "${m.name}"`, u, S, m, c), m.isMesh === !0) {
|
|
710
|
+
const f = m.geometry;
|
|
711
|
+
return y.assignLODInformation(n.url, f, r, e, 0), d(f);
|
|
532
712
|
} else {
|
|
533
|
-
const
|
|
534
|
-
for (let
|
|
535
|
-
const
|
|
536
|
-
if (
|
|
537
|
-
const
|
|
538
|
-
|
|
713
|
+
const f = new Array();
|
|
714
|
+
for (let h = 0; h < m.children.length; h++) {
|
|
715
|
+
const M = m.children[h];
|
|
716
|
+
if (M.isMesh === !0) {
|
|
717
|
+
const D = M.geometry;
|
|
718
|
+
y.assignLODInformation(n.url, D, r, e, h), f.push(D);
|
|
539
719
|
}
|
|
540
720
|
}
|
|
541
|
-
return
|
|
721
|
+
return d(f);
|
|
542
722
|
}
|
|
543
|
-
} else
|
|
544
|
-
y && console.warn("Could not find mesh with guid", M.guid, S.parser.json);
|
|
723
|
+
} else g && console.warn("Could not find mesh with guid", v.guid, b.parser.json);
|
|
545
724
|
}
|
|
546
|
-
return
|
|
725
|
+
return d(null);
|
|
547
726
|
});
|
|
548
|
-
return this.previouslyLoaded.set(
|
|
549
|
-
} else if (t instanceof
|
|
550
|
-
s && console.log("Load texture from uri: " +
|
|
551
|
-
const
|
|
552
|
-
return
|
|
727
|
+
return this.previouslyLoaded.set(c, I), p.use(I), await I;
|
|
728
|
+
} else if (t instanceof E) {
|
|
729
|
+
s && console.log("Load texture from uri: " + u);
|
|
730
|
+
const p = await new ze().loadAsync(u);
|
|
731
|
+
return p ? (p.guid = o.guid, p.flipY = !1, p.needsUpdate = !0, p.colorSpace = t.colorSpace, s && console.log(o, p)) : g && console.warn("failed loading", u), p;
|
|
553
732
|
}
|
|
554
733
|
} else
|
|
555
|
-
|
|
734
|
+
g && console.warn(`Can not load LOD ${e}: no LOD info found for "${r}" ${t.name}`, t.type);
|
|
556
735
|
return null;
|
|
557
736
|
}
|
|
737
|
+
static maxConcurrent = 50;
|
|
738
|
+
static queue = new st(y.maxConcurrent, { debug: g != !1 });
|
|
558
739
|
static assignLODInformation(t, e, s, n, r) {
|
|
559
|
-
if (!e)
|
|
560
|
-
return;
|
|
740
|
+
if (!e) return;
|
|
561
741
|
e.userData || (e.userData = {});
|
|
562
|
-
const
|
|
563
|
-
e.userData.LODS =
|
|
742
|
+
const o = new ht(t, s, n, r);
|
|
743
|
+
e.userData.LODS = o, "source" in e && typeof e.source == "object" && (e.source.LODS = o);
|
|
564
744
|
}
|
|
565
745
|
static getAssignedLODInformation(t) {
|
|
566
|
-
|
|
567
|
-
return t ? (e = t.userData) != null && e.LODS ? t.userData.LODS : "source" in t && ((s = t.source) != null && s.LODS) ? t.source.LODS : null : null;
|
|
746
|
+
return t ? t.userData?.LODS ? t.userData.LODS : "source" in t && t.source?.LODS ? t.source.LODS : null : null;
|
|
568
747
|
}
|
|
569
748
|
// private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
|
|
570
749
|
static copySettings(t, e) {
|
|
571
|
-
return e ? (
|
|
750
|
+
return e ? (g === "verbose" && console.debug(`Copy texture settings
|
|
572
751
|
`, t.uuid, `
|
|
573
752
|
`, 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;
|
|
574
753
|
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
y && console.error("gltf-progressive: Called register texture without texture");
|
|
584
|
-
return;
|
|
585
|
-
}
|
|
586
|
-
if (y) {
|
|
587
|
-
const P = ((a = e.image) == null ? void 0 : a.width) || ((c = (l = e.source) == null ? void 0 : l.data) == null ? void 0 : c.width) || 0, M = ((d = e.image) == null ? void 0 : d.height) || ((f = (h = e.source) == null ? void 0 : h.data) == null ? void 0 : f.height) || 0;
|
|
588
|
-
console.log(`> Progressive: register texture[${n}] "${e.name || e.uuid}", Current: ${P}x${M}, Max: ${(w = r.lods[0]) == null ? void 0 : w.width}x${(v = r.lods[0]) == null ? void 0 : v.height}, uuid: ${e.uuid}`, r, e);
|
|
589
|
-
}
|
|
590
|
-
e.source && (e.source[Oe] = r);
|
|
591
|
-
const i = r.guid;
|
|
592
|
-
O.assignLODInformation(t, e, i, s, n), O.lodInfos.set(i, r), O.lowresCache.set(i, e);
|
|
593
|
-
}), /**
|
|
594
|
-
* Register a mesh with LOD information
|
|
595
|
-
*/
|
|
596
|
-
u(T, "registerMesh", (t, e, s, n, r, i) => {
|
|
597
|
-
var c;
|
|
598
|
-
const a = s.geometry;
|
|
599
|
-
if (!a) {
|
|
600
|
-
y && console.warn("gltf-progressive: Register mesh without geometry");
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
603
|
-
a.userData || (a.userData = {}), y && console.log("> Progressive: register mesh " + s.name, { index: r, uuid: s.uuid }, i, s), O.assignLODInformation(t, a, e, n, r), O.lodInfos.set(e, i);
|
|
604
|
-
let l = O.lowresCache.get(e);
|
|
605
|
-
l ? l.push(s.geometry) : l = [s.geometry], O.lowresCache.set(e, l), n > 0 && !ce(s) && gt(s, a);
|
|
606
|
-
for (const d of j)
|
|
607
|
-
(c = d.onRegisteredNewMesh) == null || c.call(d, s, i);
|
|
608
|
-
}), /** A map of key = asset uuid and value = LOD information */
|
|
609
|
-
u(T, "lodInfos", /* @__PURE__ */ new Map()), /** cache of already loaded mesh lods */
|
|
610
|
-
u(T, "previouslyLoaded", /* @__PURE__ */ new Map()), /** this contains the geometry/textures that were originally loaded */
|
|
611
|
-
u(T, "lowresCache", /* @__PURE__ */ new Map()), u(T, "queue", new ft(100, { debug: y != !1 }));
|
|
612
|
-
class yt {
|
|
754
|
+
}
|
|
755
|
+
class ht {
|
|
756
|
+
url;
|
|
757
|
+
/** the key to lookup the LOD information */
|
|
758
|
+
key;
|
|
759
|
+
level;
|
|
760
|
+
/** For multi objects (e.g. a group of meshes) this is the index of the object */
|
|
761
|
+
index;
|
|
613
762
|
constructor(t, e, s, n) {
|
|
614
|
-
u(this, "url");
|
|
615
|
-
/** the key to lookup the LOD information */
|
|
616
|
-
u(this, "key");
|
|
617
|
-
u(this, "level");
|
|
618
|
-
/** For multi objects (e.g. a group of meshes) this is the index of the object */
|
|
619
|
-
u(this, "index");
|
|
620
763
|
this.url = t, this.key = e, this.level = s, n != null && (this.index = n);
|
|
621
764
|
}
|
|
622
765
|
}
|
|
623
|
-
class
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
u(this, "_awaiting", []);
|
|
635
|
-
u(this, "_maxPromisesPerObject", 1);
|
|
636
|
-
u(this, "_currentFrame", 0);
|
|
637
|
-
u(this, "_seen", /* @__PURE__ */ new WeakMap());
|
|
638
|
-
var r;
|
|
639
|
-
const n = Math.max(e.frames ?? 2, 2);
|
|
640
|
-
this.frame_start = t, this.frame_capture_end = t + n, this.ready = new Promise((i) => {
|
|
641
|
-
this._resolve = i;
|
|
642
|
-
}), this.ready.finally(() => {
|
|
643
|
-
this._resolved = !0, this._awaiting.length = 0;
|
|
644
|
-
}), this._signal = e.signal, (r = this._signal) == null || r.addEventListener("abort", () => {
|
|
645
|
-
this.resolveNow();
|
|
646
|
-
}), this._maxPromisesPerObject = Math.max(1, e.maxPromisesPerObject ?? 1);
|
|
647
|
-
}
|
|
766
|
+
class ue {
|
|
767
|
+
static addPromise = (t, e, s, n) => {
|
|
768
|
+
n.forEach((r) => {
|
|
769
|
+
r.add(t, e, s);
|
|
770
|
+
});
|
|
771
|
+
};
|
|
772
|
+
frame_start;
|
|
773
|
+
frame_capture_end;
|
|
774
|
+
ready;
|
|
775
|
+
_resolve;
|
|
776
|
+
_signal;
|
|
648
777
|
/**
|
|
649
778
|
* The number of promises that have been added to this group so far.
|
|
650
779
|
*/
|
|
@@ -657,13 +786,30 @@ class ye {
|
|
|
657
786
|
get currentlyAwaiting() {
|
|
658
787
|
return this._awaiting.length;
|
|
659
788
|
}
|
|
789
|
+
_resolved = !1;
|
|
790
|
+
_addedCount = 0;
|
|
791
|
+
_resolvedCount = 0;
|
|
792
|
+
/** These promises are currently being awaited */
|
|
793
|
+
_awaiting = [];
|
|
794
|
+
_maxPromisesPerObject = 1;
|
|
795
|
+
constructor(t, e) {
|
|
796
|
+
const n = Math.max(e.frames ?? 2, 2);
|
|
797
|
+
this.frame_start = t, this.frame_capture_end = t + n, this.ready = new Promise((r) => {
|
|
798
|
+
this._resolve = r;
|
|
799
|
+
}), this.ready.finally(() => {
|
|
800
|
+
this._resolved = !0, this._awaiting.length = 0;
|
|
801
|
+
}), this._signal = e.signal, this._signal?.addEventListener("abort", () => {
|
|
802
|
+
this.resolveNow();
|
|
803
|
+
}), this._maxPromisesPerObject = Math.max(1, e.maxPromisesPerObject ?? 1);
|
|
804
|
+
}
|
|
805
|
+
_currentFrame = 0;
|
|
660
806
|
update(t) {
|
|
661
|
-
|
|
662
|
-
this._currentFrame = t, ((e = this._signal) != null && e.aborted || this._currentFrame > this.frame_capture_end && this._awaiting.length === 0) && this.resolveNow();
|
|
807
|
+
this._currentFrame = t, (this._signal?.aborted || this._currentFrame > this.frame_capture_end && this._awaiting.length === 0) && this.resolveNow();
|
|
663
808
|
}
|
|
809
|
+
_seen = /* @__PURE__ */ new WeakMap();
|
|
664
810
|
add(t, e, s) {
|
|
665
811
|
if (this._resolved) {
|
|
666
|
-
|
|
812
|
+
g && console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");
|
|
667
813
|
return;
|
|
668
814
|
}
|
|
669
815
|
if (!(this._currentFrame > this.frame_capture_end)) {
|
|
@@ -671,7 +817,7 @@ class ye {
|
|
|
671
817
|
if (this._seen.has(e)) {
|
|
672
818
|
let n = this._seen.get(e);
|
|
673
819
|
if (n >= this._maxPromisesPerObject) {
|
|
674
|
-
|
|
820
|
+
g && console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");
|
|
675
821
|
return;
|
|
676
822
|
}
|
|
677
823
|
this._seen.set(e, n + 1);
|
|
@@ -683,85 +829,33 @@ class ye {
|
|
|
683
829
|
}
|
|
684
830
|
}
|
|
685
831
|
resolveNow() {
|
|
686
|
-
|
|
687
|
-
this._resolved || (e = this._resolve) == null || e.call(this, {
|
|
832
|
+
this._resolved || this._resolve?.({
|
|
688
833
|
awaited_count: this._addedCount,
|
|
689
834
|
resolved_count: this._resolvedCount,
|
|
690
|
-
cancelled:
|
|
835
|
+
cancelled: this._signal?.aborted ?? !1
|
|
691
836
|
});
|
|
692
837
|
}
|
|
693
838
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
u(this, "renderer");
|
|
705
|
-
u(this, "context");
|
|
706
|
-
u(this, "projectionScreenMatrix", new Ie());
|
|
707
|
-
/**
|
|
708
|
-
* The target triangle density is the desired max amount of triangles on screen when the mesh is filling the screen.
|
|
709
|
-
* @default 200_000
|
|
710
|
-
*/
|
|
711
|
-
u(this, "targetTriangleDensity", 2e5);
|
|
712
|
-
/**
|
|
713
|
-
* The interval in frames to automatically update the bounds of skinned meshes.
|
|
714
|
-
* Set to 0 or a negative value to disable automatic bounds updates.
|
|
715
|
-
* @default 30
|
|
716
|
-
*/
|
|
717
|
-
u(this, "skinnedMeshAutoUpdateBoundsInterval", 30);
|
|
718
|
-
/**
|
|
719
|
-
* The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 2, the LODs will be updated every second frame, etc.
|
|
720
|
-
* @default "auto"
|
|
721
|
-
*/
|
|
722
|
-
u(this, "updateInterval", "auto");
|
|
723
|
-
H(this, B, 1);
|
|
724
|
-
/**
|
|
725
|
-
* If set to true, the LODsManager will not update the LODs.
|
|
726
|
-
* @default false
|
|
727
|
-
*/
|
|
728
|
-
u(this, "pause", !1);
|
|
729
|
-
/**
|
|
730
|
-
* When set to true the LODsManager will not update the LODs. This can be used to manually update the LODs using the `update` method.
|
|
731
|
-
* Otherwise the LODs will be updated automatically when the renderer renders the scene.
|
|
732
|
-
* @default false
|
|
733
|
-
*/
|
|
734
|
-
u(this, "manual", !1);
|
|
735
|
-
u(this, "_newPromiseGroups", []);
|
|
736
|
-
u(this, "_promiseGroupIds", 0);
|
|
737
|
-
u(this, "_lodchangedlisteners", []);
|
|
738
|
-
H(this, K, void 0);
|
|
739
|
-
H(this, we, new Je());
|
|
740
|
-
H(this, J, 0);
|
|
741
|
-
H(this, ie, 0);
|
|
742
|
-
H(this, _e, 0);
|
|
743
|
-
H(this, Y, 0);
|
|
744
|
-
u(this, "_fpsBuffer", [60, 60, 60, 60, 60]);
|
|
745
|
-
// private testIfLODLevelsAreAvailable() {
|
|
746
|
-
u(this, "_sphere", new et());
|
|
747
|
-
u(this, "_tempBox", new $e());
|
|
748
|
-
u(this, "_tempBox2", new $e());
|
|
749
|
-
u(this, "tempMatrix", new Ie());
|
|
750
|
-
u(this, "_tempWorldPosition", new W());
|
|
751
|
-
u(this, "_tempBoxSize", new W());
|
|
752
|
-
u(this, "_tempBox2Size", new W());
|
|
753
|
-
this.renderer = t, this.context = { ...e };
|
|
754
|
-
}
|
|
839
|
+
const k = X("debugprogressive"), gt = X("noprogressive"), de = Symbol("Needle:LODSManager"), ce = Symbol("Needle:LODState"), U = Symbol("Needle:CurrentLOD"), P = { mesh_lod: -1, texture_lod: -1 };
|
|
840
|
+
class L {
|
|
841
|
+
/**
|
|
842
|
+
* 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.
|
|
843
|
+
*/
|
|
844
|
+
static debugDrawLine;
|
|
845
|
+
/**
|
|
846
|
+
* Force override the LOD level for all objects in the scene
|
|
847
|
+
*/
|
|
848
|
+
static overrideGlobalLodLevel;
|
|
755
849
|
/** @internal */
|
|
756
850
|
static getObjectLODState(t) {
|
|
757
|
-
return t[
|
|
851
|
+
return t[ce];
|
|
758
852
|
}
|
|
759
853
|
static addPlugin(t) {
|
|
760
|
-
|
|
854
|
+
W.push(t);
|
|
761
855
|
}
|
|
762
856
|
static removePlugin(t) {
|
|
763
|
-
const e =
|
|
764
|
-
e >= 0 &&
|
|
857
|
+
const e = W.indexOf(t);
|
|
858
|
+
e >= 0 && W.splice(e, 1);
|
|
765
859
|
}
|
|
766
860
|
/**
|
|
767
861
|
* Gets the LODsManager for the given renderer. If the LODsManager does not exist yet, it will be created.
|
|
@@ -769,38 +863,72 @@ const b = class {
|
|
|
769
863
|
* @returns The LODsManager instance.
|
|
770
864
|
*/
|
|
771
865
|
static get(t, e) {
|
|
772
|
-
if (t[
|
|
773
|
-
return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), t[
|
|
774
|
-
const s = new
|
|
866
|
+
if (t[de])
|
|
867
|
+
return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), t[de];
|
|
868
|
+
const s = new L(t, {
|
|
775
869
|
engine: "unknown",
|
|
776
870
|
...e
|
|
777
871
|
});
|
|
778
|
-
return t[
|
|
872
|
+
return t[de] = s, s;
|
|
779
873
|
}
|
|
874
|
+
renderer;
|
|
875
|
+
context;
|
|
876
|
+
projectionScreenMatrix = new Le();
|
|
780
877
|
/** @deprecated use static `LODsManager.addPlugin()` method. This getter will be removed in later versions */
|
|
781
878
|
get plugins() {
|
|
782
|
-
return
|
|
879
|
+
return W;
|
|
783
880
|
}
|
|
881
|
+
/**
|
|
882
|
+
* The target triangle density is the desired max amount of triangles on screen when the mesh is filling the screen.
|
|
883
|
+
* @default 200_000
|
|
884
|
+
*/
|
|
885
|
+
targetTriangleDensity = 2e5;
|
|
886
|
+
/**
|
|
887
|
+
* The interval in frames to automatically update the bounds of skinned meshes.
|
|
888
|
+
* Set to 0 or a negative value to disable automatic bounds updates.
|
|
889
|
+
* @default 30
|
|
890
|
+
*/
|
|
891
|
+
skinnedMeshAutoUpdateBoundsInterval = 30;
|
|
892
|
+
/**
|
|
893
|
+
* The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 2, the LODs will be updated every second frame, etc.
|
|
894
|
+
* @default "auto"
|
|
895
|
+
*/
|
|
896
|
+
updateInterval = "auto";
|
|
897
|
+
#e = 1;
|
|
898
|
+
/**
|
|
899
|
+
* If set to true, the LODsManager will not update the LODs.
|
|
900
|
+
* @default false
|
|
901
|
+
*/
|
|
902
|
+
pause = !1;
|
|
903
|
+
/**
|
|
904
|
+
* When set to true the LODsManager will not update the LODs. This can be used to manually update the LODs using the `update` method.
|
|
905
|
+
* Otherwise the LODs will be updated automatically when the renderer renders the scene.
|
|
906
|
+
* @default false
|
|
907
|
+
*/
|
|
908
|
+
manual = !1;
|
|
909
|
+
_newPromiseGroups = [];
|
|
910
|
+
_promiseGroupIds = 0;
|
|
784
911
|
/**
|
|
785
912
|
* Call to await LODs loading during the next render cycle.
|
|
786
913
|
*/
|
|
787
914
|
awaitLoading(t) {
|
|
788
|
-
const e = this._promiseGroupIds++, s = new
|
|
915
|
+
const e = this._promiseGroupIds++, s = new ue(this.#r, { ...t });
|
|
789
916
|
this._newPromiseGroups.push(s);
|
|
790
917
|
const n = performance.now();
|
|
791
918
|
return s.ready.finally(() => {
|
|
792
919
|
const r = this._newPromiseGroups.indexOf(s);
|
|
793
|
-
r >= 0 && (this._newPromiseGroups.splice(r, 1),
|
|
920
|
+
r >= 0 && (this._newPromiseGroups.splice(r, 1), _e() && performance.measure("LODsManager:awaitLoading", {
|
|
794
921
|
start: n,
|
|
795
|
-
detail: { id: e, name: t
|
|
922
|
+
detail: { id: e, name: t?.name, awaited: s.awaitedCount, resolved: s.resolvedCount }
|
|
796
923
|
}));
|
|
797
924
|
}), s.ready;
|
|
798
925
|
}
|
|
799
926
|
_postprocessPromiseGroups() {
|
|
800
927
|
if (this._newPromiseGroups.length !== 0)
|
|
801
928
|
for (let t = this._newPromiseGroups.length - 1; t >= 0; t--)
|
|
802
|
-
this._newPromiseGroups[t].update(
|
|
929
|
+
this._newPromiseGroups[t].update(this.#r);
|
|
803
930
|
}
|
|
931
|
+
_lodchangedlisteners = [];
|
|
804
932
|
addEventListener(t, e) {
|
|
805
933
|
t === "changed" && this._lodchangedlisteners.push(e);
|
|
806
934
|
}
|
|
@@ -810,40 +938,49 @@ const b = class {
|
|
|
810
938
|
s >= 0 && this._lodchangedlisteners.splice(s, 1);
|
|
811
939
|
}
|
|
812
940
|
}
|
|
941
|
+
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
942
|
+
constructor(t, e) {
|
|
943
|
+
this.renderer = t, this.context = { ...e };
|
|
944
|
+
}
|
|
945
|
+
#t;
|
|
946
|
+
#o = new Ee();
|
|
947
|
+
#r = 0;
|
|
948
|
+
#n = 0;
|
|
949
|
+
#i = 0;
|
|
950
|
+
#s = 0;
|
|
951
|
+
_fpsBuffer = [60, 60, 60, 60, 60];
|
|
813
952
|
/**
|
|
814
953
|
* Enable the LODsManager. This will replace the render method of the renderer with a method that updates the LODs.
|
|
815
954
|
*/
|
|
816
955
|
enable() {
|
|
817
|
-
if (
|
|
818
|
-
return;
|
|
956
|
+
if (this.#t) return;
|
|
819
957
|
console.debug("[gltf-progressive] Enabling LODsManager for renderer");
|
|
820
958
|
let t = 0;
|
|
821
|
-
|
|
959
|
+
this.#t = this.renderer.render;
|
|
822
960
|
const e = this;
|
|
823
|
-
|
|
961
|
+
xe(this.renderer), this.renderer.render = function(s, n) {
|
|
824
962
|
const r = e.renderer.getRenderTarget();
|
|
825
|
-
(r == null || "isXRRenderTarget" in r && r.isXRRenderTarget) && (t = 0,
|
|
826
|
-
const
|
|
827
|
-
|
|
963
|
+
(r == null || "isXRRenderTarget" in r && r.isXRRenderTarget) && (t = 0, e.#r += 1, e.#n = e.#o.getDelta(), e.#i += e.#n, e._fpsBuffer.shift(), e._fpsBuffer.push(1 / e.#n), e.#s = e._fpsBuffer.reduce((l, a) => l + a) / e._fpsBuffer.length, k && e.#r % 200 === 0 && console.log("FPS", Math.round(e.#s), "Interval:", e.#e));
|
|
964
|
+
const o = t++;
|
|
965
|
+
e.#t.call(this, s, n), e.onAfterRender(s, n, o);
|
|
828
966
|
};
|
|
829
967
|
}
|
|
830
968
|
disable() {
|
|
831
|
-
|
|
969
|
+
this.#t && (console.debug("[gltf-progressive] Disabling LODsManager for renderer"), this.renderer.render = this.#t, this.#t = void 0);
|
|
832
970
|
}
|
|
833
971
|
update(t, e) {
|
|
834
972
|
this.internalUpdate(t, e);
|
|
835
973
|
}
|
|
836
974
|
onAfterRender(t, e, s) {
|
|
837
|
-
if (this.pause)
|
|
838
|
-
return;
|
|
975
|
+
if (this.pause) return;
|
|
839
976
|
const r = this.renderer.renderLists.get(t, 0).opaque;
|
|
840
|
-
let
|
|
977
|
+
let o = !0;
|
|
841
978
|
if (r.length === 1) {
|
|
842
|
-
const
|
|
843
|
-
(
|
|
979
|
+
const l = r[0].material;
|
|
980
|
+
(l.name === "EffectMaterial" || l.name === "CopyShader") && (o = !1);
|
|
844
981
|
}
|
|
845
|
-
if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (
|
|
846
|
-
if (
|
|
982
|
+
if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (o = !1), o) {
|
|
983
|
+
if (gt || (this.updateInterval === "auto" ? this.#s < 40 && this.#e < 10 ? (this.#e += 1, k && console.warn("↓ Reducing LOD updates", this.#e, this.#s.toFixed(0))) : this.#s >= 60 && this.#e > 1 && (this.#e -= 1, k && console.warn("↑ Increasing LOD updates", this.#e, this.#s.toFixed(0))) : this.#e = this.updateInterval, this.#e > 0 && this.#r % this.#e != 0))
|
|
847
984
|
return;
|
|
848
985
|
this.internalUpdate(t, e), this._postprocessPromiseGroups();
|
|
849
986
|
}
|
|
@@ -852,16 +989,15 @@ const b = class {
|
|
|
852
989
|
* Update LODs in a scene
|
|
853
990
|
*/
|
|
854
991
|
internalUpdate(t, e) {
|
|
855
|
-
var l, c;
|
|
856
992
|
const s = this.renderer.renderLists.get(t, 0), n = s.opaque;
|
|
857
993
|
this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix, e.matrixWorldInverse);
|
|
858
994
|
const r = this.targetTriangleDensity;
|
|
859
|
-
for (const
|
|
860
|
-
if (
|
|
861
|
-
|
|
995
|
+
for (const a of n) {
|
|
996
|
+
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")) {
|
|
997
|
+
k && (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)));
|
|
862
998
|
continue;
|
|
863
999
|
}
|
|
864
|
-
switch (
|
|
1000
|
+
switch (a.material.type) {
|
|
865
1001
|
case "LineBasicMaterial":
|
|
866
1002
|
case "LineDashedMaterial":
|
|
867
1003
|
case "PointsMaterial":
|
|
@@ -870,62 +1006,58 @@ const b = class {
|
|
|
870
1006
|
case "MeshDepthMaterial":
|
|
871
1007
|
continue;
|
|
872
1008
|
}
|
|
873
|
-
if (
|
|
874
|
-
|
|
875
|
-
const
|
|
876
|
-
|
|
1009
|
+
if (k === "color" && a.material && !a.object.progressive_debug_color) {
|
|
1010
|
+
a.object.progressive_debug_color = !0;
|
|
1011
|
+
const c = Math.random() * 16777215, p = new Ne({ color: c });
|
|
1012
|
+
a.object.material = p;
|
|
877
1013
|
}
|
|
878
|
-
const
|
|
879
|
-
(
|
|
1014
|
+
const u = a.object;
|
|
1015
|
+
(u instanceof q || u.isMesh) && this.updateLODs(t, e, u, r);
|
|
880
1016
|
}
|
|
881
|
-
const
|
|
882
|
-
for (const
|
|
883
|
-
const
|
|
884
|
-
(
|
|
1017
|
+
const o = s.transparent;
|
|
1018
|
+
for (const a of o) {
|
|
1019
|
+
const u = a.object;
|
|
1020
|
+
(u instanceof q || u.isMesh) && this.updateLODs(t, e, u, r);
|
|
885
1021
|
}
|
|
886
|
-
const
|
|
887
|
-
for (const
|
|
888
|
-
const
|
|
889
|
-
(
|
|
1022
|
+
const l = s.transmissive;
|
|
1023
|
+
for (const a of l) {
|
|
1024
|
+
const u = a.object;
|
|
1025
|
+
(u instanceof q || u.isMesh) && this.updateLODs(t, e, u, r);
|
|
890
1026
|
}
|
|
891
1027
|
}
|
|
892
1028
|
/** Update the LOD levels for the renderer. */
|
|
893
1029
|
updateLODs(t, e, s, n) {
|
|
894
|
-
var a, l;
|
|
895
1030
|
s.userData || (s.userData = {});
|
|
896
|
-
let r = s[
|
|
897
|
-
if (r || (r = new
|
|
1031
|
+
let r = s[ce];
|
|
1032
|
+
if (r || (r = new pt(), s[ce] = r), r.frames++ < 2)
|
|
898
1033
|
return;
|
|
899
|
-
for (const
|
|
900
|
-
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
for (const
|
|
904
|
-
|
|
905
|
-
r.lastLodLevel_Mesh =
|
|
1034
|
+
for (const l of W)
|
|
1035
|
+
l.onBeforeUpdateLOD?.(this.renderer, t, e, s);
|
|
1036
|
+
const o = L.overrideGlobalLodLevel !== void 0 ? L.overrideGlobalLodLevel : N;
|
|
1037
|
+
o >= 0 ? (P.mesh_lod = o, P.texture_lod = o) : (this.calculateLodLevel(e, s, r, n, P), P.mesh_lod = Math.round(P.mesh_lod), P.texture_lod = Math.round(P.texture_lod)), P.mesh_lod >= 0 && this.loadProgressiveMeshes(s, P.mesh_lod), s.material && P.texture_lod >= 0 && this.loadProgressiveTextures(s.material, P.texture_lod, o), g && s.material && !s.isGizmo && Ie(s.material);
|
|
1038
|
+
for (const l of W)
|
|
1039
|
+
l.onAfterUpdatedLOD?.(this.renderer, t, e, s, P);
|
|
1040
|
+
r.lastLodLevel_Mesh = P.mesh_lod, r.lastLodLevel_Texture = P.texture_lod;
|
|
906
1041
|
}
|
|
907
1042
|
/** Load progressive textures for the given material
|
|
908
1043
|
* @param material the material to load the textures for
|
|
909
1044
|
* @param level the LOD level to load. Level 0 is the best quality, higher levels are lower quality
|
|
910
1045
|
* @returns Promise with true if the LOD was loaded, false if not
|
|
911
1046
|
*/
|
|
912
|
-
loadProgressiveTextures(t, e) {
|
|
913
|
-
if (!t)
|
|
914
|
-
return;
|
|
1047
|
+
loadProgressiveTextures(t, e, s) {
|
|
1048
|
+
if (!t) return;
|
|
915
1049
|
if (Array.isArray(t)) {
|
|
916
1050
|
for (const r of t)
|
|
917
1051
|
this.loadProgressiveTextures(r, e);
|
|
918
1052
|
return;
|
|
919
1053
|
}
|
|
920
|
-
let
|
|
921
|
-
(t[
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
const r = T.assignTextureLOD(t, e).then((i) => {
|
|
926
|
-
this._lodchangedlisteners.forEach((a) => a({ type: "texture", level: e, object: t }));
|
|
1054
|
+
let n = !1;
|
|
1055
|
+
if ((t[U] === void 0 || e < t[U]) && (n = !0), s !== void 0 && s >= 0 && (n = t[U] != s, e = s), n) {
|
|
1056
|
+
t[U] = e;
|
|
1057
|
+
const r = y.assignTextureLOD(t, e).then((o) => {
|
|
1058
|
+
this._lodchangedlisteners.forEach((l) => l({ type: "texture", level: e, object: t }));
|
|
927
1059
|
});
|
|
928
|
-
|
|
1060
|
+
ue.addPromise("texture", t, r, this._newPromiseGroups);
|
|
929
1061
|
}
|
|
930
1062
|
}
|
|
931
1063
|
/** Load progressive meshes for the given mesh
|
|
@@ -935,23 +1067,37 @@ const b = class {
|
|
|
935
1067
|
* @returns Promise with true if the LOD was loaded, false if not
|
|
936
1068
|
*/
|
|
937
1069
|
loadProgressiveMeshes(t, e) {
|
|
938
|
-
if (!t)
|
|
939
|
-
|
|
940
|
-
let s = t[Q] !== e;
|
|
1070
|
+
if (!t) return Promise.resolve(null);
|
|
1071
|
+
let s = t[U] !== e;
|
|
941
1072
|
const n = t["DEBUG:LOD"];
|
|
942
|
-
if (n != null && (s = t[
|
|
943
|
-
t[
|
|
944
|
-
const r = t.geometry,
|
|
945
|
-
return
|
|
1073
|
+
if (n != null && (s = t[U] != n, e = n), s) {
|
|
1074
|
+
t[U] = e;
|
|
1075
|
+
const r = t.geometry, o = y.assignMeshLOD(t, e).then((l) => (l && t[U] == e && r != t.geometry && this._lodchangedlisteners.forEach((a) => a({ type: "mesh", level: e, object: t })), l));
|
|
1076
|
+
return ue.addPromise("mesh", t, o, this._newPromiseGroups), o;
|
|
946
1077
|
}
|
|
947
1078
|
return Promise.resolve(null);
|
|
948
1079
|
}
|
|
1080
|
+
// private testIfLODLevelsAreAvailable() {
|
|
1081
|
+
_sphere = new De();
|
|
1082
|
+
_tempBox = new he();
|
|
1083
|
+
_tempBox2 = new he();
|
|
1084
|
+
tempMatrix = new Le();
|
|
1085
|
+
_tempWorldPosition = new A();
|
|
1086
|
+
_tempBoxSize = new A();
|
|
1087
|
+
_tempBox2Size = new A();
|
|
1088
|
+
static corner0 = new A();
|
|
1089
|
+
static corner1 = new A();
|
|
1090
|
+
static corner2 = new A();
|
|
1091
|
+
static corner3 = new A();
|
|
1092
|
+
static _tempPtInside = new A();
|
|
949
1093
|
static isInside(t, e) {
|
|
950
|
-
const s = t.min, n = t.max, r = (s.x + n.x) * 0.5,
|
|
951
|
-
return this._tempPtInside.set(r,
|
|
1094
|
+
const s = t.min, n = t.max, r = (s.x + n.x) * 0.5, o = (s.y + n.y) * 0.5;
|
|
1095
|
+
return this._tempPtInside.set(r, o, s.z).applyMatrix4(e).z < 0;
|
|
952
1096
|
}
|
|
1097
|
+
static skinnedMeshBoundsFrameOffsetCounter = 0;
|
|
1098
|
+
static $skinnedMeshBoundsOffset = Symbol("gltf-progressive-skinnedMeshBoundsOffset");
|
|
1099
|
+
// #region calculateLodLevel
|
|
953
1100
|
calculateLodLevel(t, e, s, n, r) {
|
|
954
|
-
var M, R, Z;
|
|
955
1101
|
if (!e) {
|
|
956
1102
|
r.mesh_lod = -1, r.texture_lod = -1;
|
|
957
1103
|
return;
|
|
@@ -960,105 +1106,105 @@ const b = class {
|
|
|
960
1106
|
r.mesh_lod = -1, r.texture_lod = -1;
|
|
961
1107
|
return;
|
|
962
1108
|
}
|
|
963
|
-
let
|
|
964
|
-
if (
|
|
1109
|
+
let l = 10 + 1, a = !1;
|
|
1110
|
+
if (k && e["DEBUG:LOD"] != null)
|
|
965
1111
|
return e["DEBUG:LOD"];
|
|
966
|
-
const
|
|
967
|
-
if (!
|
|
1112
|
+
const u = y.getMeshLODExtension(e.geometry)?.lods, c = y.getPrimitiveIndex(e.geometry), p = u && u.length > 0, _ = y.getMaterialMinMaxLODsCount(e.material), v = _.min_count !== 1 / 0 && _.min_count >= 0 && _.max_count >= 0;
|
|
1113
|
+
if (!p && !v) {
|
|
968
1114
|
r.mesh_lod = 0, r.texture_lod = 0;
|
|
969
1115
|
return;
|
|
970
1116
|
}
|
|
971
|
-
|
|
972
|
-
const
|
|
973
|
-
let
|
|
1117
|
+
p || (a = !0, l = 0);
|
|
1118
|
+
const I = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
|
|
1119
|
+
let G = e.geometry.boundingBox;
|
|
974
1120
|
if (e.type === "SkinnedMesh") {
|
|
975
|
-
const
|
|
976
|
-
if (!
|
|
977
|
-
|
|
1121
|
+
const d = e;
|
|
1122
|
+
if (!d.boundingBox)
|
|
1123
|
+
d.computeBoundingBox();
|
|
978
1124
|
else if (this.skinnedMeshAutoUpdateBoundsInterval > 0) {
|
|
979
|
-
if (!
|
|
980
|
-
const
|
|
981
|
-
|
|
1125
|
+
if (!d[L.$skinnedMeshBoundsOffset]) {
|
|
1126
|
+
const O = L.skinnedMeshBoundsFrameOffsetCounter++;
|
|
1127
|
+
d[L.$skinnedMeshBoundsOffset] = O;
|
|
982
1128
|
}
|
|
983
|
-
const x =
|
|
1129
|
+
const x = d[L.$skinnedMeshBoundsOffset];
|
|
984
1130
|
if ((s.frames + x) % this.skinnedMeshAutoUpdateBoundsInterval === 0) {
|
|
985
|
-
const
|
|
986
|
-
|
|
1131
|
+
const O = J(d), B = d.geometry;
|
|
1132
|
+
O && (d.geometry = O), d.computeBoundingBox(), d.geometry = B;
|
|
987
1133
|
}
|
|
988
1134
|
}
|
|
989
|
-
|
|
1135
|
+
G = d.boundingBox;
|
|
990
1136
|
}
|
|
991
|
-
if (
|
|
992
|
-
const
|
|
1137
|
+
if (G) {
|
|
1138
|
+
const d = t;
|
|
993
1139
|
if (e.geometry.attributes.color && e.geometry.attributes.color.count < 100 && e.geometry.boundingSphere) {
|
|
994
1140
|
this._sphere.copy(e.geometry.boundingSphere), this._sphere.applyMatrix4(e.matrixWorld);
|
|
995
|
-
const
|
|
996
|
-
if (this._sphere.containsPoint(
|
|
1141
|
+
const f = t.getWorldPosition(this._tempWorldPosition);
|
|
1142
|
+
if (this._sphere.containsPoint(f)) {
|
|
997
1143
|
r.mesh_lod = 0, r.texture_lod = 0;
|
|
998
1144
|
return;
|
|
999
1145
|
}
|
|
1000
1146
|
}
|
|
1001
|
-
if (this._tempBox.copy(
|
|
1147
|
+
if (this._tempBox.copy(G), this._tempBox.applyMatrix4(e.matrixWorld), d.isPerspectiveCamera && L.isInside(this._tempBox, this.projectionScreenMatrix)) {
|
|
1002
1148
|
r.mesh_lod = 0, r.texture_lod = 0;
|
|
1003
1149
|
return;
|
|
1004
1150
|
}
|
|
1005
|
-
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled &&
|
|
1006
|
-
const
|
|
1007
|
-
let
|
|
1008
|
-
const
|
|
1009
|
-
|
|
1010
|
-
const
|
|
1011
|
-
s.lastCentrality = (
|
|
1151
|
+
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && d.isPerspectiveCamera && d.fov > 70) {
|
|
1152
|
+
const f = this._tempBox.min, h = this._tempBox.max;
|
|
1153
|
+
let M = f.x, D = f.y, $ = h.x, K = h.y;
|
|
1154
|
+
const Z = 2, oe = 1.5, ee = (f.x + h.x) * 0.5, te = (f.y + h.y) * 0.5;
|
|
1155
|
+
M = (M - ee) * Z + ee, D = (D - te) * Z + te, $ = ($ - ee) * Z + ee, K = (K - te) * Z + te;
|
|
1156
|
+
const Re = M < 0 && $ > 0 ? 0 : Math.min(Math.abs(f.x), Math.abs(h.x)), Be = D < 0 && K > 0 ? 0 : Math.min(Math.abs(f.y), Math.abs(h.y)), ie = Math.max(Re, Be);
|
|
1157
|
+
s.lastCentrality = (oe - ie) * (oe - ie) * (oe - ie);
|
|
1012
1158
|
} else
|
|
1013
1159
|
s.lastCentrality = 1;
|
|
1014
1160
|
const x = this._tempBox.getSize(this._tempBoxSize);
|
|
1015
|
-
x.multiplyScalar(0.5), screen.availHeight > 0 &&
|
|
1016
|
-
const
|
|
1017
|
-
|
|
1018
|
-
const
|
|
1019
|
-
if (Math.max(x.x, x.y) != 0 &&
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1161
|
+
x.multiplyScalar(0.5), screen.availHeight > 0 && I > 0 && x.multiplyScalar(I / screen.availHeight), t.isPerspectiveCamera ? x.x *= t.aspect : t.isOrthographicCamera;
|
|
1162
|
+
const O = t.matrixWorldInverse, B = this._tempBox2;
|
|
1163
|
+
B.copy(G), B.applyMatrix4(e.matrixWorld), B.applyMatrix4(O);
|
|
1164
|
+
const b = B.getSize(this._tempBox2Size), z = Math.max(b.x, b.y);
|
|
1165
|
+
if (Math.max(x.x, x.y) != 0 && z != 0 && (x.z = b.z / Math.max(b.x, b.y) * Math.max(x.x, x.y)), s.lastScreenCoverage = Math.max(x.x, x.y, x.z), s.lastScreenspaceVolume.copy(x), s.lastScreenCoverage *= s.lastCentrality, k && L.debugDrawLine) {
|
|
1166
|
+
const f = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
1167
|
+
f.invert();
|
|
1168
|
+
const h = L.corner0, M = L.corner1, D = L.corner2, $ = L.corner3;
|
|
1169
|
+
h.copy(this._tempBox.min), M.copy(this._tempBox.max), M.x = h.x, D.copy(this._tempBox.max), D.y = h.y, $.copy(this._tempBox.max);
|
|
1170
|
+
const K = (h.z + $.z) * 0.5;
|
|
1171
|
+
h.z = M.z = D.z = $.z = K, h.applyMatrix4(f), M.applyMatrix4(f), D.applyMatrix4(f), $.applyMatrix4(f), L.debugDrawLine(h, M, 255), L.debugDrawLine(h, D, 255), L.debugDrawLine(M, $, 255), L.debugDrawLine(D, $, 255);
|
|
1026
1172
|
}
|
|
1027
|
-
let
|
|
1028
|
-
if (
|
|
1029
|
-
for (let
|
|
1030
|
-
const
|
|
1031
|
-
if (
|
|
1032
|
-
|
|
1173
|
+
let w = 999;
|
|
1174
|
+
if (u && s.lastScreenCoverage > 0)
|
|
1175
|
+
for (let f = 0; f < u.length; f++) {
|
|
1176
|
+
const h = u[f], D = (h.densities?.[c] || h.density || 1e-5) / s.lastScreenCoverage;
|
|
1177
|
+
if (c > 0 && _e() && !h.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.")), D < n) {
|
|
1178
|
+
w = f;
|
|
1033
1179
|
break;
|
|
1034
1180
|
}
|
|
1035
1181
|
}
|
|
1036
|
-
|
|
1182
|
+
w < l && (l = w, a = !0);
|
|
1037
1183
|
}
|
|
1038
|
-
if (
|
|
1039
|
-
const x =
|
|
1040
|
-
x && console.
|
|
1184
|
+
if (a ? r.mesh_lod = l : r.mesh_lod = s.lastLodLevel_Mesh, k && r.mesh_lod != s.lastLodLevel_Mesh) {
|
|
1185
|
+
const x = u?.[r.mesh_lod];
|
|
1186
|
+
x && console.debug(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (density: ${x.densities?.[c].toFixed(0)}) | ${e.name}`);
|
|
1041
1187
|
}
|
|
1042
|
-
if (
|
|
1043
|
-
const
|
|
1188
|
+
if (v) {
|
|
1189
|
+
const d = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
|
|
1044
1190
|
if (s.lastLodLevel_Texture < 0) {
|
|
1045
|
-
if (r.texture_lod =
|
|
1046
|
-
const x =
|
|
1047
|
-
|
|
1191
|
+
if (r.texture_lod = _.max_count - 1, k) {
|
|
1192
|
+
const x = _.lods[_.max_count - 1];
|
|
1193
|
+
k && console.log(`First Texture LOD ${r.texture_lod} (${x.max_height}px) - ${e.name}`);
|
|
1048
1194
|
}
|
|
1049
1195
|
} else {
|
|
1050
1196
|
const x = s.lastScreenspaceVolume.x + s.lastScreenspaceVolume.y + s.lastScreenspaceVolume.z;
|
|
1051
|
-
let
|
|
1052
|
-
|
|
1053
|
-
const
|
|
1054
|
-
let
|
|
1055
|
-
for (let
|
|
1056
|
-
const
|
|
1057
|
-
if (!(
|
|
1058
|
-
if (
|
|
1059
|
-
const m =
|
|
1060
|
-
|
|
1061
|
-
Screensize: ${
|
|
1197
|
+
let O = s.lastScreenCoverage * 4;
|
|
1198
|
+
this.context?.engine === "model-viewer" && (O *= 1.5);
|
|
1199
|
+
const b = I / window.devicePixelRatio * O;
|
|
1200
|
+
let z = !1;
|
|
1201
|
+
for (let S = _.lods.length - 1; S >= 0; S--) {
|
|
1202
|
+
const w = _.lods[S];
|
|
1203
|
+
if (!(d && w.max_height >= 2048) && !(Ae() && w.max_height > 4096) && (w.max_height > b || !z && S === 0)) {
|
|
1204
|
+
if (z = !0, r.texture_lod = S, k && r.texture_lod < s.lastLodLevel_Texture) {
|
|
1205
|
+
const m = w.max_height;
|
|
1206
|
+
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${m}px
|
|
1207
|
+
Screensize: ${b.toFixed(0)}px, Coverage: ${(100 * s.lastScreenCoverage).toFixed(2)}%, Volume ${x.toFixed(1)}
|
|
1062
1208
|
${e.name}`);
|
|
1063
1209
|
}
|
|
1064
1210
|
break;
|
|
@@ -1068,85 +1214,73 @@ ${e.name}`);
|
|
|
1068
1214
|
} else
|
|
1069
1215
|
r.texture_lod = 0;
|
|
1070
1216
|
}
|
|
1071
|
-
};
|
|
1072
|
-
let C = b;
|
|
1073
|
-
B = new WeakMap(), K = new WeakMap(), we = new WeakMap(), J = new WeakMap(), ie = new WeakMap(), _e = new WeakMap(), Y = new WeakMap(), /**
|
|
1074
|
-
* 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.
|
|
1075
|
-
*/
|
|
1076
|
-
u(C, "debugDrawLine"), /**
|
|
1077
|
-
* Force override the LOD level for all objects in the scene
|
|
1078
|
-
*/
|
|
1079
|
-
u(C, "overrideGlobalLodLevel"), u(C, "corner0", new W()), u(C, "corner1", new W()), u(C, "corner2", new W()), u(C, "corner3", new W()), u(C, "_tempPtInside", new W()), u(C, "skinnedMeshBoundsFrameOffsetCounter", 0), u(C, "$skinnedMeshBoundsOffset", Symbol("gltf-progressive-skinnedMeshBoundsOffset"));
|
|
1080
|
-
class xt {
|
|
1081
|
-
constructor() {
|
|
1082
|
-
u(this, "frames", 0);
|
|
1083
|
-
u(this, "lastLodLevel_Mesh", -1);
|
|
1084
|
-
u(this, "lastLodLevel_Texture", -1);
|
|
1085
|
-
u(this, "lastScreenCoverage", 0);
|
|
1086
|
-
u(this, "lastScreenspaceVolume", new W());
|
|
1087
|
-
u(this, "lastCentrality", 0);
|
|
1088
|
-
}
|
|
1089
1217
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1218
|
+
class pt {
|
|
1219
|
+
frames = 0;
|
|
1220
|
+
lastLodLevel_Mesh = -1;
|
|
1221
|
+
lastLodLevel_Texture = -1;
|
|
1222
|
+
lastScreenCoverage = 0;
|
|
1223
|
+
lastScreenspaceVolume = new A();
|
|
1224
|
+
lastCentrality = 0;
|
|
1225
|
+
}
|
|
1226
|
+
const ve = Symbol("NEEDLE_mesh_lod"), se = Symbol("NEEDLE_texture_lod");
|
|
1227
|
+
let fe = null;
|
|
1228
|
+
function ke() {
|
|
1229
|
+
const i = mt();
|
|
1230
|
+
i && (i.mapURLs(function(t) {
|
|
1231
|
+
return be(), t;
|
|
1232
|
+
}), be(), fe?.disconnect(), fe = new MutationObserver((t) => {
|
|
1097
1233
|
t.forEach((e) => {
|
|
1098
1234
|
e.addedNodes.forEach((s) => {
|
|
1099
|
-
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" &&
|
|
1235
|
+
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" && Ce(s);
|
|
1100
1236
|
});
|
|
1101
1237
|
});
|
|
1102
|
-
}),
|
|
1238
|
+
}), fe.observe(document, { childList: !0, subtree: !0 }));
|
|
1103
1239
|
}
|
|
1104
|
-
function
|
|
1105
|
-
if (typeof customElements > "u")
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
console.debug("[gltf-progressive] model-viewer defined"), We();
|
|
1240
|
+
function mt() {
|
|
1241
|
+
if (typeof customElements > "u") return null;
|
|
1242
|
+
const i = customElements.get("model-viewer");
|
|
1243
|
+
return i || (customElements.whenDefined("model-viewer").then(() => {
|
|
1244
|
+
console.debug("[gltf-progressive] model-viewer defined"), ke();
|
|
1110
1245
|
}), null);
|
|
1111
1246
|
}
|
|
1112
|
-
function
|
|
1113
|
-
if (typeof document > "u")
|
|
1114
|
-
return;
|
|
1247
|
+
function be() {
|
|
1248
|
+
if (typeof document > "u") return;
|
|
1115
1249
|
document.querySelectorAll("model-viewer").forEach((t) => {
|
|
1116
|
-
|
|
1250
|
+
Ce(t);
|
|
1117
1251
|
});
|
|
1118
1252
|
}
|
|
1119
|
-
const
|
|
1120
|
-
let
|
|
1121
|
-
function
|
|
1122
|
-
if (!
|
|
1253
|
+
const Me = /* @__PURE__ */ new WeakSet();
|
|
1254
|
+
let yt = 0;
|
|
1255
|
+
function Ce(i) {
|
|
1256
|
+
if (!i || Me.has(i))
|
|
1123
1257
|
return null;
|
|
1124
|
-
|
|
1125
|
-
`,
|
|
1258
|
+
Me.add(i), console.debug("[gltf-progressive] found new model-viewer..." + ++yt + `
|
|
1259
|
+
`, i.getAttribute("src"));
|
|
1126
1260
|
let t = null, e = null, s = null;
|
|
1127
|
-
for (let n =
|
|
1128
|
-
const r = Object.getOwnPropertySymbols(n),
|
|
1129
|
-
!t &&
|
|
1261
|
+
for (let n = i; n != null; n = Object.getPrototypeOf(n)) {
|
|
1262
|
+
const r = Object.getOwnPropertySymbols(n), o = r.find((u) => u.toString() == "Symbol(renderer)"), l = r.find((u) => u.toString() == "Symbol(scene)"), a = r.find((u) => u.toString() == "Symbol(needsRender)");
|
|
1263
|
+
!t && o != null && (t = i[o].threeRenderer), !e && l != null && (e = i[l]), !s && a != null && (s = i[a]);
|
|
1130
1264
|
}
|
|
1131
1265
|
if (t && e) {
|
|
1132
1266
|
let n = function() {
|
|
1133
1267
|
if (s) {
|
|
1134
|
-
let
|
|
1135
|
-
if (
|
|
1136
|
-
clearInterval(
|
|
1268
|
+
let o = 0, l = setInterval(() => {
|
|
1269
|
+
if (o++ > 5) {
|
|
1270
|
+
clearInterval(l);
|
|
1137
1271
|
return;
|
|
1138
1272
|
}
|
|
1139
|
-
s
|
|
1273
|
+
s?.call(i);
|
|
1140
1274
|
}, 300);
|
|
1141
1275
|
}
|
|
1142
1276
|
};
|
|
1143
1277
|
console.debug("[gltf-progressive] setup model-viewer");
|
|
1144
|
-
const r =
|
|
1145
|
-
return
|
|
1146
|
-
s
|
|
1147
|
-
}),
|
|
1148
|
-
|
|
1149
|
-
}),
|
|
1278
|
+
const r = L.get(t, { engine: "model-viewer" });
|
|
1279
|
+
return L.addPlugin(new xt()), r.enable(), r.addEventListener("changed", () => {
|
|
1280
|
+
s?.call(i);
|
|
1281
|
+
}), i.addEventListener("model-visibility", (o) => {
|
|
1282
|
+
o.detail.visible && s?.call(i);
|
|
1283
|
+
}), i.addEventListener("load", () => {
|
|
1150
1284
|
n();
|
|
1151
1285
|
}), () => {
|
|
1152
1286
|
r.disable();
|
|
@@ -1154,10 +1288,8 @@ function Xe(o) {
|
|
|
1154
1288
|
}
|
|
1155
1289
|
return null;
|
|
1156
1290
|
}
|
|
1157
|
-
class
|
|
1158
|
-
|
|
1159
|
-
u(this, "_didWarnAboutMissingUrl", !1);
|
|
1160
|
-
}
|
|
1291
|
+
class xt {
|
|
1292
|
+
_didWarnAboutMissingUrl = !1;
|
|
1161
1293
|
onBeforeUpdateLOD(t, e, s, n) {
|
|
1162
1294
|
this.tryParseMeshLOD(e, n), this.tryParseTextureLOD(e, n);
|
|
1163
1295
|
}
|
|
@@ -1174,96 +1306,101 @@ class vt {
|
|
|
1174
1306
|
return t.element;
|
|
1175
1307
|
}
|
|
1176
1308
|
tryParseTextureLOD(t, e) {
|
|
1177
|
-
if (e[
|
|
1178
|
-
|
|
1179
|
-
e[pe] = !0;
|
|
1309
|
+
if (e[se] == !0) return;
|
|
1310
|
+
e[se] = !0;
|
|
1180
1311
|
const s = this.tryGetCurrentGLTF(t), n = this.tryGetCurrentModelViewer(t), r = this.getUrl(n);
|
|
1181
1312
|
if (r && s && e.material) {
|
|
1182
|
-
let
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
const
|
|
1192
|
-
if (
|
|
1193
|
-
|
|
1194
|
-
const R = s.parser.json.textures[M];
|
|
1195
|
-
if (!R) {
|
|
1196
|
-
console.warn("Texture data not found for texture index " + M);
|
|
1313
|
+
let o = function(a) {
|
|
1314
|
+
if (a[se] == !0) return;
|
|
1315
|
+
a[se] = !0, a.userData && (a.userData.LOD = -1);
|
|
1316
|
+
const u = Object.keys(a);
|
|
1317
|
+
for (let c = 0; c < u.length; c++) {
|
|
1318
|
+
const p = u[c], _ = a[p];
|
|
1319
|
+
if (_?.isTexture === !0) {
|
|
1320
|
+
const v = _.userData?.associations?.textures;
|
|
1321
|
+
if (v == null) continue;
|
|
1322
|
+
const I = s.parser.json.textures[v];
|
|
1323
|
+
if (!I) {
|
|
1324
|
+
console.warn("Texture data not found for texture index " + v);
|
|
1197
1325
|
continue;
|
|
1198
1326
|
}
|
|
1199
|
-
if (
|
|
1200
|
-
const
|
|
1201
|
-
|
|
1327
|
+
if (I?.extensions?.[F]) {
|
|
1328
|
+
const G = I.extensions[F];
|
|
1329
|
+
G && r && y.registerTexture(r, _, G.lods.length, v, G);
|
|
1202
1330
|
}
|
|
1203
1331
|
}
|
|
1204
1332
|
}
|
|
1205
1333
|
};
|
|
1206
|
-
const
|
|
1207
|
-
if (Array.isArray(a))
|
|
1208
|
-
|
|
1209
|
-
i(l);
|
|
1210
|
-
else
|
|
1211
|
-
i(a);
|
|
1334
|
+
const l = e.material;
|
|
1335
|
+
if (Array.isArray(l)) for (const a of l) o(a);
|
|
1336
|
+
else o(l);
|
|
1212
1337
|
}
|
|
1213
1338
|
}
|
|
1214
1339
|
tryParseMeshLOD(t, e) {
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
return;
|
|
1218
|
-
e[Be] = !0;
|
|
1340
|
+
if (e[ve] == !0) return;
|
|
1341
|
+
e[ve] = !0;
|
|
1219
1342
|
const s = this.tryGetCurrentModelViewer(t), n = this.getUrl(s);
|
|
1220
1343
|
if (!n)
|
|
1221
1344
|
return;
|
|
1222
|
-
const r =
|
|
1345
|
+
const r = e.userData?.gltfExtensions?.[F];
|
|
1223
1346
|
if (r && n) {
|
|
1224
|
-
const
|
|
1225
|
-
|
|
1347
|
+
const o = e.uuid;
|
|
1348
|
+
y.registerMesh(n, o, e, 0, r.lods.length, r);
|
|
1226
1349
|
}
|
|
1227
1350
|
}
|
|
1228
1351
|
}
|
|
1229
|
-
function
|
|
1230
|
-
|
|
1352
|
+
function wt(...i) {
|
|
1353
|
+
let t, e, s, n;
|
|
1354
|
+
switch (i.length) {
|
|
1355
|
+
case 2:
|
|
1356
|
+
[s, e] = i, n = {};
|
|
1357
|
+
break;
|
|
1358
|
+
case 3:
|
|
1359
|
+
[s, e, n] = i;
|
|
1360
|
+
break;
|
|
1361
|
+
case 4:
|
|
1362
|
+
[t, e, s, n] = i;
|
|
1363
|
+
break;
|
|
1364
|
+
default:
|
|
1365
|
+
throw new Error("Invalid arguments");
|
|
1366
|
+
}
|
|
1367
|
+
xe(e), Se(s), Te(s, {
|
|
1231
1368
|
progressive: !0,
|
|
1232
|
-
...
|
|
1233
|
-
}),
|
|
1234
|
-
const
|
|
1235
|
-
return
|
|
1369
|
+
...n?.hints
|
|
1370
|
+
}), s.register((o) => new y(o));
|
|
1371
|
+
const r = L.get(e);
|
|
1372
|
+
return n?.enableLODsManager !== !1 && r.enable(), r;
|
|
1236
1373
|
}
|
|
1237
|
-
|
|
1238
|
-
if (!
|
|
1239
|
-
const
|
|
1374
|
+
ke();
|
|
1375
|
+
if (!rt) {
|
|
1376
|
+
const i = {
|
|
1240
1377
|
gltfProgressive: {
|
|
1241
|
-
useNeedleProgressive:
|
|
1242
|
-
LODsManager:
|
|
1243
|
-
configureLoader:
|
|
1244
|
-
getRaycastMesh:
|
|
1245
|
-
useRaycastMeshes:
|
|
1378
|
+
useNeedleProgressive: wt,
|
|
1379
|
+
LODsManager: L,
|
|
1380
|
+
configureLoader: Te,
|
|
1381
|
+
getRaycastMesh: J,
|
|
1382
|
+
useRaycastMeshes: ot
|
|
1246
1383
|
}
|
|
1247
1384
|
};
|
|
1248
1385
|
if (!globalThis.Needle)
|
|
1249
|
-
globalThis.Needle =
|
|
1386
|
+
globalThis.Needle = i;
|
|
1250
1387
|
else
|
|
1251
|
-
for (const t in
|
|
1252
|
-
globalThis.Needle[t] =
|
|
1388
|
+
for (const t in i)
|
|
1389
|
+
globalThis.Needle[t] = i[t];
|
|
1253
1390
|
}
|
|
1254
1391
|
export {
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1392
|
+
F as EXTENSION_NAME,
|
|
1393
|
+
L as LODsManager,
|
|
1394
|
+
y as NEEDLE_progressive,
|
|
1395
|
+
Ke as VERSION,
|
|
1396
|
+
Se as addDracoAndKTX2Loaders,
|
|
1397
|
+
Te as configureLoader,
|
|
1398
|
+
xe as createLoaders,
|
|
1399
|
+
J as getRaycastMesh,
|
|
1400
|
+
ke as patchModelViewer,
|
|
1401
|
+
nt as registerRaycastMesh,
|
|
1402
|
+
Qe as setDracoDecoderLocation,
|
|
1403
|
+
Je as setKTX2TranscoderLocation,
|
|
1404
|
+
wt as useNeedleProgressive,
|
|
1405
|
+
ot as useRaycastMeshes
|
|
1269
1406
|
};
|