@needle-tools/gltf-progressive 3.1.0 → 3.1.1-next.1039397
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 +79 -39
- package/gltf-progressive.js +881 -740
- package/gltf-progressive.min.js +7 -7
- package/gltf-progressive.umd.cjs +7 -7
- package/lib/extension.d.ts +3 -0
- package/lib/extension.js +96 -14
- package/lib/loaders.d.ts +8 -0
- package/lib/loaders.js +33 -22
- package/lib/lods.manager.js +24 -11
- package/lib/utils.internal.d.ts +4 -5
- package/lib/utils.internal.js +2 -2
- 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 +168 -0
- package/package.json +3 -3
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
|
-
}, q = (o, t, e, s) => (Be(o, t, "write to private field"), s ? s.call(o, e) : t.set(o, e), e);
|
|
12
|
-
import { BufferGeometry as xe, Mesh as se, Texture as oe, TextureLoader as Qe, Matrix4 as Ge, Clock as je, MeshStandardMaterial as Je, Sphere as Ze, Box3 as Ee, Vector3 as W } from "three";
|
|
13
|
-
import { GLTFLoader as Ce } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
14
|
-
import { MeshoptDecoder as et } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
15
|
-
import { DRACOLoader as tt } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
16
|
-
import { KTX2Loader as st } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
17
|
-
const rt = "";
|
|
18
|
-
globalThis.GLTF_PROGRESSIVE_VERSION = rt;
|
|
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 k = "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 = k, Ye = V, Oe = new URL(k + "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 ${k} (offline: ${typeof navigator < "u" ? navigator.onLine : "unknown"})`), k === je && Qe("./include/draco/"), V === Ye && Je("./include/ktx2/");
|
|
30
19
|
}).finally(() => {
|
|
31
|
-
|
|
20
|
+
Pe();
|
|
21
|
+
});
|
|
22
|
+
const He = () => ({
|
|
23
|
+
dracoDecoderPath: k,
|
|
24
|
+
ktx2TranscoderPath: V
|
|
32
25
|
});
|
|
33
|
-
function
|
|
34
|
-
|
|
26
|
+
function Qe(i) {
|
|
27
|
+
k = i, T && T[ge] != k ? (console.debug("Updating Draco decoder path to " + i), T[ge] = k, T.setDecoderPath(k), 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 Fe() {
|
|
42
|
-
I || (I = new tt(), I[Pe] = V, I.setDecoderPath(V), I.setDecoderConfig({ type: "js" }), I.preload()), U || (U = new st(), U.setTranscoderPath(re), U.init()), Le || (Le = et);
|
|
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] = k, T.setDecoderPath(k), 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
|
*/
|
|
@@ -113,8 +103,8 @@ class ft {
|
|
|
113
103
|
}
|
|
114
104
|
add(t, e) {
|
|
115
105
|
this._running.has(t) || (this._running.set(t, e), e.finally(() => {
|
|
116
|
-
this._running.delete(t), this.debug && console.debug(`[PromiseQueue]: Promise
|
|
117
|
-
}), this.debug && console.debug(`[PromiseQueue]:
|
|
106
|
+
this._running.delete(t), this.debug && console.debug(`[PromiseQueue]: Promise finished now running: ${this._running.size}, waiting: ${this._queue.length}. (finished ${t})`);
|
|
107
|
+
}), this.debug && console.debug(`[PromiseQueue]: Added new promise, now running: ${this._running.size}, waiting: ${this._queue.length}. (added ${t})`));
|
|
118
108
|
}
|
|
119
109
|
internalUpdate() {
|
|
120
110
|
const t = this.maxConcurrent - this._running.size;
|
|
@@ -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"
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
static async createWorker(t) {
|
|
203
|
+
const e = new Worker(new URL(
|
|
204
|
+
/* @vite-ignore */
|
|
205
|
+
"/assets/loader.worker-8olmVOL4.js",
|
|
206
|
+
import.meta.url
|
|
207
|
+
), {
|
|
208
|
+
type: "module"
|
|
197
209
|
});
|
|
198
|
-
|
|
210
|
+
return new we(e, t);
|
|
199
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 p = 0; p <
|
|
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"), D = 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"), D = 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
|
-
x && 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,290 +460,319 @@ const X = "NEEDLE_progressive", Oe = Symbol("needle-progressive-texture"), D = 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 null;
|
|
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
|
-
x == "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, e) {
|
|
520
|
+
g && console.log("Progressive extension registered for", e), this.parser = t, this.url = e;
|
|
521
|
+
}
|
|
522
|
+
_isLoadingMesh;
|
|
523
|
+
loadMesh = (t) => {
|
|
524
|
+
if (this._isLoadingMesh) return null;
|
|
525
|
+
const e = this.parser.json.meshes[t]?.extensions?.[F];
|
|
526
|
+
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;
|
|
527
|
+
};
|
|
528
|
+
// private _isLoadingTexture;
|
|
529
|
+
// loadTexture = (textureIndex: number) => {
|
|
530
|
+
// if (this._isLoadingTexture) return null;
|
|
531
|
+
// const ext = this.parser.json.textures[textureIndex]?.extensions?.[EXTENSION_NAME] as NEEDLE_ext_progressive_texture;
|
|
532
|
+
// if (!ext) return null;
|
|
533
|
+
// this._isLoadingTexture = true;
|
|
534
|
+
// return this.parser.getDependency("texture", textureIndex).then(tex => {
|
|
535
|
+
// this._isLoadingTexture = false;
|
|
536
|
+
// if (tex) {
|
|
537
|
+
// NEEDLE_progressive.registerTexture(this.url, tex as Texture, ext.lods?.length, textureIndex, ext);
|
|
538
|
+
// }
|
|
539
|
+
// return tex;
|
|
540
|
+
// });
|
|
541
|
+
// }
|
|
396
542
|
afterRoot(t) {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
if (!a.lods) {
|
|
404
|
-
x && console.warn("Texture has no LODs", a);
|
|
543
|
+
return g && console.log("AFTER", this.url, t), this.parser.json.textures?.forEach((e, s) => {
|
|
544
|
+
if (e?.extensions) {
|
|
545
|
+
const n = e?.extensions[F];
|
|
546
|
+
if (n) {
|
|
547
|
+
if (!n.lods) {
|
|
548
|
+
g && console.warn("Texture has no LODs", n);
|
|
405
549
|
return;
|
|
406
550
|
}
|
|
407
|
-
let
|
|
408
|
-
for (const
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
l || this.parser.getDependency("texture", r).then((c) => {
|
|
414
|
-
var d;
|
|
415
|
-
c && D.registerTexture(this.url, c, (d = a.lods) == null ? void 0 : d.length, r, a);
|
|
551
|
+
let r = !1;
|
|
552
|
+
for (const o of this.parser.associations.keys())
|
|
553
|
+
o.isTexture === !0 && this.parser.associations.get(o)?.textures === s && (r = !0, y.registerTexture(this.url, o, n.lods?.length, s, n));
|
|
554
|
+
r || this.parser.getDependency("texture", s).then((o) => {
|
|
555
|
+
o && y.registerTexture(this.url, o, n.lods?.length, s, n);
|
|
416
556
|
});
|
|
417
557
|
}
|
|
418
558
|
}
|
|
419
|
-
}),
|
|
420
|
-
if (
|
|
421
|
-
const
|
|
422
|
-
if (
|
|
423
|
-
for (const
|
|
424
|
-
if (
|
|
425
|
-
const
|
|
426
|
-
|
|
559
|
+
}), this.parser.json.meshes?.forEach((e, s) => {
|
|
560
|
+
if (e?.extensions) {
|
|
561
|
+
const n = e?.extensions[F];
|
|
562
|
+
if (n && n.lods) {
|
|
563
|
+
for (const r of this.parser.associations.keys())
|
|
564
|
+
if (r.isMesh) {
|
|
565
|
+
const o = this.parser.associations.get(r);
|
|
566
|
+
o?.meshes === s && y.registerMesh(this.url, n.guid, r, n.lods.length, o.primitives, n);
|
|
427
567
|
}
|
|
428
568
|
}
|
|
429
569
|
}
|
|
430
570
|
}), null;
|
|
431
571
|
}
|
|
572
|
+
/**
|
|
573
|
+
* Register a texture with LOD information
|
|
574
|
+
*/
|
|
575
|
+
static registerTexture = (t, e, s, n, r) => {
|
|
576
|
+
if (!e) {
|
|
577
|
+
g && console.error("gltf-progressive: Called register texture without texture");
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
if (g) {
|
|
581
|
+
const l = e.image?.width || e.source?.data?.width || 0, a = e.image?.height || e.source?.data?.height || 0;
|
|
582
|
+
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);
|
|
583
|
+
}
|
|
584
|
+
e.source && (e.source[le] = r);
|
|
585
|
+
const o = r.guid;
|
|
586
|
+
y.assignLODInformation(t, e, o, s, n), y.lodInfos.set(o, r), y.lowresCache.set(o, e);
|
|
587
|
+
};
|
|
588
|
+
/**
|
|
589
|
+
* Register a mesh with LOD information
|
|
590
|
+
*/
|
|
591
|
+
static registerMesh = (t, e, s, n, r, o) => {
|
|
592
|
+
const l = s.geometry;
|
|
593
|
+
if (!l) {
|
|
594
|
+
g && console.warn("gltf-progressive: Register mesh without geometry");
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
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);
|
|
598
|
+
let a = y.lowresCache.get(e);
|
|
599
|
+
a ? a.push(s.geometry) : a = [s.geometry], y.lowresCache.set(e, a), n > 0 && !J(s) && nt(s, l);
|
|
600
|
+
for (const u of W)
|
|
601
|
+
u.onRegisteredNewMesh?.(s, o);
|
|
602
|
+
};
|
|
603
|
+
/** A map of key = asset uuid and value = LOD information */
|
|
604
|
+
static lodInfos = /* @__PURE__ */ new Map();
|
|
605
|
+
/** cache of already loaded mesh lods */
|
|
606
|
+
static previouslyLoaded = /* @__PURE__ */ new Map();
|
|
607
|
+
/** this contains the geometry/textures that were originally loaded */
|
|
608
|
+
static lowresCache = /* @__PURE__ */ new Map();
|
|
609
|
+
static workers = [];
|
|
610
|
+
static _workersIndex = 0;
|
|
432
611
|
static async getOrLoadLOD(t, e) {
|
|
433
|
-
|
|
434
|
-
const s = x == "verbose", n = t.userData.LODS;
|
|
612
|
+
const s = g == "verbose", n = this.getAssignedLODInformation(t);
|
|
435
613
|
if (!n)
|
|
436
|
-
return null;
|
|
437
|
-
const r = n
|
|
438
|
-
let
|
|
614
|
+
return g && console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`, t), null;
|
|
615
|
+
const r = n?.key;
|
|
616
|
+
let o;
|
|
439
617
|
if (t.isTexture === !0) {
|
|
440
|
-
const
|
|
441
|
-
|
|
618
|
+
const a = t;
|
|
619
|
+
a.source && a.source[le] && (o = a.source[le]);
|
|
442
620
|
}
|
|
443
|
-
if (
|
|
621
|
+
if (o || (o = y.lodInfos.get(r)), o) {
|
|
444
622
|
if (e > 0) {
|
|
445
|
-
let
|
|
446
|
-
const
|
|
447
|
-
if (
|
|
623
|
+
let c = !1;
|
|
624
|
+
const p = Array.isArray(o.lods);
|
|
625
|
+
if (p && e >= o.lods.length ? c = !0 : p || (c = !0), c)
|
|
448
626
|
return this.lowresCache.get(r);
|
|
449
627
|
}
|
|
450
|
-
const
|
|
451
|
-
if (!
|
|
452
|
-
return
|
|
453
|
-
const
|
|
454
|
-
if (
|
|
455
|
-
if (!
|
|
456
|
-
return console.warn("missing pointer for glb/gltf texture",
|
|
457
|
-
const
|
|
458
|
-
if (
|
|
459
|
-
s && console.log(`LOD ${e} was already loading/loaded: ${
|
|
460
|
-
let
|
|
461
|
-
`,
|
|
462
|
-
if (
|
|
463
|
-
return
|
|
628
|
+
const a = Array.isArray(o.lods) ? o.lods[e]?.path : o.lods;
|
|
629
|
+
if (!a)
|
|
630
|
+
return g && !o["missing:uri"] && (o["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + e, o)), null;
|
|
631
|
+
const u = tt(n.url, a);
|
|
632
|
+
if (u.endsWith(".glb") || u.endsWith(".gltf")) {
|
|
633
|
+
if (!o.guid)
|
|
634
|
+
return console.warn("missing pointer for glb/gltf texture", o), null;
|
|
635
|
+
const c = u + "_" + o.guid, p = await this.queue.slot(u), _ = this.previouslyLoaded.get(c);
|
|
636
|
+
if (_ !== void 0) {
|
|
637
|
+
s && console.log(`LOD ${e} was already loading/loaded: ${c}`);
|
|
638
|
+
let d = await _.catch((O) => (console.error(`Error loading LOD ${e} from ${u}
|
|
639
|
+
`, O), null)), x = !1;
|
|
640
|
+
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)
|
|
641
|
+
return d;
|
|
464
642
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
643
|
+
if (!p.use)
|
|
644
|
+
return g && console.log(`LOD ${e} was aborted: ${u}`), null;
|
|
645
|
+
const v = o, I = new Promise(async (d, x) => {
|
|
646
|
+
if (ct) {
|
|
647
|
+
const m = await (await ut({})).load(u);
|
|
648
|
+
if (m.textures.length > 0)
|
|
649
|
+
for (const f of m.textures) {
|
|
650
|
+
let h = f.texture;
|
|
651
|
+
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);
|
|
652
|
+
}
|
|
653
|
+
if (m.geometries.length > 0) {
|
|
654
|
+
const f = new Array();
|
|
655
|
+
for (const h of m.geometries) {
|
|
656
|
+
const M = h.geometry;
|
|
657
|
+
y.assignLODInformation(n.url, M, r, e, h.primitiveIndex), f.push(M);
|
|
658
|
+
}
|
|
659
|
+
return d(f);
|
|
660
|
+
}
|
|
661
|
+
return d(null);
|
|
662
|
+
}
|
|
663
|
+
const O = new ye();
|
|
664
|
+
Se(O), g && (await new Promise((w) => setTimeout(w, 1e3)), s && console.warn("Start loading (delayed) " + u, v.guid));
|
|
665
|
+
let B = u;
|
|
666
|
+
if (v && Array.isArray(v.lods)) {
|
|
667
|
+
const w = v.lods[e];
|
|
668
|
+
w.hash && (B += "?v=" + w.hash);
|
|
475
669
|
}
|
|
476
|
-
const
|
|
477
|
-
`,
|
|
478
|
-
if (!
|
|
479
|
-
return
|
|
480
|
-
const
|
|
481
|
-
s && console.log("Loading finished " +
|
|
482
|
-
let
|
|
483
|
-
if (
|
|
484
|
-
let
|
|
485
|
-
for (const m of
|
|
486
|
-
if (m
|
|
487
|
-
const
|
|
488
|
-
if (
|
|
489
|
-
|
|
670
|
+
const b = await O.loadAsync(B).catch((w) => (console.error(`Error loading LOD ${e} from ${u}
|
|
671
|
+
`, w), d(null)));
|
|
672
|
+
if (!b)
|
|
673
|
+
return d(null);
|
|
674
|
+
const z = b.parser;
|
|
675
|
+
s && console.log("Loading finished " + u, v.guid);
|
|
676
|
+
let S = 0;
|
|
677
|
+
if (b.parser.json.textures) {
|
|
678
|
+
let w = !1;
|
|
679
|
+
for (const m of b.parser.json.textures) {
|
|
680
|
+
if (m?.extensions) {
|
|
681
|
+
const f = m?.extensions[F];
|
|
682
|
+
if (f?.guid && f.guid === v.guid) {
|
|
683
|
+
w = !0;
|
|
490
684
|
break;
|
|
491
685
|
}
|
|
492
686
|
}
|
|
493
|
-
|
|
687
|
+
S++;
|
|
494
688
|
}
|
|
495
|
-
if (
|
|
496
|
-
let m = await
|
|
497
|
-
return m &&
|
|
498
|
-
} else
|
|
499
|
-
x && console.warn("Could not find texture with guid", b.guid, S.parser.json);
|
|
689
|
+
if (w) {
|
|
690
|
+
let m = await z.getDependency("texture", S);
|
|
691
|
+
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);
|
|
692
|
+
} else g && console.warn("Could not find texture with guid", v.guid, b.parser.json);
|
|
500
693
|
}
|
|
501
|
-
if (
|
|
502
|
-
let
|
|
503
|
-
for (const m of
|
|
504
|
-
if (m
|
|
505
|
-
const
|
|
506
|
-
if (
|
|
507
|
-
|
|
694
|
+
if (S = 0, b.parser.json.meshes) {
|
|
695
|
+
let w = !1;
|
|
696
|
+
for (const m of b.parser.json.meshes) {
|
|
697
|
+
if (m?.extensions) {
|
|
698
|
+
const f = m?.extensions[F];
|
|
699
|
+
if (f?.guid && f.guid === v.guid) {
|
|
700
|
+
w = !0;
|
|
508
701
|
break;
|
|
509
702
|
}
|
|
510
703
|
}
|
|
511
|
-
|
|
704
|
+
S++;
|
|
512
705
|
}
|
|
513
|
-
if (
|
|
514
|
-
const m = await
|
|
515
|
-
if (s && console.log(`Loaded Mesh "${m.name}"`,
|
|
516
|
-
const
|
|
517
|
-
return
|
|
706
|
+
if (w) {
|
|
707
|
+
const m = await z.getDependency("mesh", S);
|
|
708
|
+
if (s && console.log(`Loaded Mesh "${m.name}"`, u, S, m, c), m.isMesh === !0) {
|
|
709
|
+
const f = m.geometry;
|
|
710
|
+
return y.assignLODInformation(n.url, f, r, e, 0), d(f);
|
|
518
711
|
} else {
|
|
519
|
-
const
|
|
520
|
-
for (let
|
|
521
|
-
const
|
|
522
|
-
if (
|
|
523
|
-
const
|
|
524
|
-
|
|
712
|
+
const f = new Array();
|
|
713
|
+
for (let h = 0; h < m.children.length; h++) {
|
|
714
|
+
const M = m.children[h];
|
|
715
|
+
if (M.isMesh === !0) {
|
|
716
|
+
const D = M.geometry;
|
|
717
|
+
y.assignLODInformation(n.url, D, r, e, h), f.push(D);
|
|
525
718
|
}
|
|
526
719
|
}
|
|
527
|
-
return
|
|
720
|
+
return d(f);
|
|
528
721
|
}
|
|
529
|
-
} else
|
|
530
|
-
x && console.warn("Could not find mesh with guid", b.guid, S.parser.json);
|
|
722
|
+
} else g && console.warn("Could not find mesh with guid", v.guid, b.parser.json);
|
|
531
723
|
}
|
|
532
|
-
return
|
|
724
|
+
return d(null);
|
|
533
725
|
});
|
|
534
|
-
return this.previouslyLoaded.set(
|
|
535
|
-
} else if (t instanceof
|
|
536
|
-
s && console.log("Load texture from uri: " +
|
|
537
|
-
const
|
|
538
|
-
return
|
|
726
|
+
return this.previouslyLoaded.set(c, I), p.use(I), await I;
|
|
727
|
+
} else if (t instanceof E) {
|
|
728
|
+
s && console.log("Load texture from uri: " + u);
|
|
729
|
+
const p = await new ze().loadAsync(u);
|
|
730
|
+
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;
|
|
539
731
|
}
|
|
540
732
|
} else
|
|
541
|
-
|
|
733
|
+
g && console.warn(`Can not load LOD ${e}: no LOD info found for "${r}" ${t.name}`, t.type);
|
|
542
734
|
return null;
|
|
543
735
|
}
|
|
736
|
+
static maxConcurrent = 50;
|
|
737
|
+
static queue = new st(y.maxConcurrent, { debug: g != !1 });
|
|
544
738
|
static assignLODInformation(t, e, s, n, r) {
|
|
545
|
-
if (!e)
|
|
546
|
-
return;
|
|
739
|
+
if (!e) return;
|
|
547
740
|
e.userData || (e.userData = {});
|
|
548
|
-
const
|
|
549
|
-
e.userData.LODS =
|
|
741
|
+
const o = new ht(t, s, n, r);
|
|
742
|
+
e.userData.LODS = o, "source" in e && typeof e.source == "object" && (e.source.LODS = o);
|
|
550
743
|
}
|
|
551
744
|
static getAssignedLODInformation(t) {
|
|
552
|
-
|
|
553
|
-
return ((e = t == null ? void 0 : t.userData) == null ? void 0 : e.LODS) || null;
|
|
745
|
+
return t ? t.userData?.LODS ? t.userData.LODS : "source" in t && t.source?.LODS ? t.source.LODS : null : null;
|
|
554
746
|
}
|
|
555
747
|
// private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
|
|
556
748
|
static copySettings(t, e) {
|
|
557
|
-
return e ? (
|
|
749
|
+
return e ? (g === "verbose" && console.debug(`Copy texture settings
|
|
558
750
|
`, t.uuid, `
|
|
559
751
|
`, 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;
|
|
560
752
|
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
return;
|
|
570
|
-
}
|
|
571
|
-
e.source && (e.source[Oe] = r);
|
|
572
|
-
const i = r.guid;
|
|
573
|
-
D.assignLODInformation(t, e, i, s, n), D.lodInfos.set(i, r), D.lowresCache.set(i, e);
|
|
574
|
-
}), /**
|
|
575
|
-
* Register a mesh with LOD information
|
|
576
|
-
*/
|
|
577
|
-
u(P, "registerMesh", (t, e, s, n, r, i) => {
|
|
578
|
-
var c;
|
|
579
|
-
const a = s.geometry;
|
|
580
|
-
if (!a) {
|
|
581
|
-
x && console.warn("gltf-progressive: Register mesh without geometry");
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
|
-
a.userData || (a.userData = {}), x && console.log("> Progressive: register mesh " + s.name, { index: r, uuid: s.uuid }, i, s), D.assignLODInformation(t, a, e, n, r), D.lodInfos.set(e, i);
|
|
585
|
-
let l = D.lowresCache.get(e);
|
|
586
|
-
l ? l.push(s.geometry) : l = [s.geometry], D.lowresCache.set(e, l), n > 0 && !ce(s) && gt(s, a);
|
|
587
|
-
for (const d of j)
|
|
588
|
-
(c = d.onRegisteredNewMesh) == null || c.call(d, s, i);
|
|
589
|
-
}), /** A map of key = asset uuid and value = LOD information */
|
|
590
|
-
u(P, "lodInfos", /* @__PURE__ */ new Map()), /** cache of already loaded mesh lods */
|
|
591
|
-
u(P, "previouslyLoaded", /* @__PURE__ */ new Map()), /** this contains the geometry/textures that were originally loaded */
|
|
592
|
-
u(P, "lowresCache", /* @__PURE__ */ new Map()), u(P, "queue", new ft(100, { debug: x != !1 }));
|
|
593
|
-
class yt {
|
|
753
|
+
}
|
|
754
|
+
class ht {
|
|
755
|
+
url;
|
|
756
|
+
/** the key to lookup the LOD information */
|
|
757
|
+
key;
|
|
758
|
+
level;
|
|
759
|
+
/** For multi objects (e.g. a group of meshes) this is the index of the object */
|
|
760
|
+
index;
|
|
594
761
|
constructor(t, e, s, n) {
|
|
595
|
-
u(this, "url");
|
|
596
|
-
/** the key to lookup the LOD information */
|
|
597
|
-
u(this, "key");
|
|
598
|
-
u(this, "level");
|
|
599
|
-
/** For multi objects (e.g. a group of meshes) this is the index of the object */
|
|
600
|
-
u(this, "index");
|
|
601
762
|
this.url = t, this.key = e, this.level = s, n != null && (this.index = n);
|
|
602
763
|
}
|
|
603
764
|
}
|
|
604
|
-
class
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
u(this, "_awaiting", []);
|
|
616
|
-
u(this, "_maxPromisesPerObject", 1);
|
|
617
|
-
u(this, "_currentFrame", 0);
|
|
618
|
-
u(this, "_seen", /* @__PURE__ */ new WeakMap());
|
|
619
|
-
var r;
|
|
620
|
-
const n = Math.max(e.frames ?? 2, 2);
|
|
621
|
-
this.frame_start = t, this.frame_capture_end = t + n, this.ready = new Promise((i) => {
|
|
622
|
-
this._resolve = i;
|
|
623
|
-
}), this.ready.finally(() => {
|
|
624
|
-
this._resolved = !0, this._awaiting.length = 0;
|
|
625
|
-
}), this._signal = e.signal, (r = this._signal) == null || r.addEventListener("abort", () => {
|
|
626
|
-
this.resolveNow();
|
|
627
|
-
}), this._maxPromisesPerObject = Math.max(1, e.maxPromisesPerObject ?? 1);
|
|
628
|
-
}
|
|
765
|
+
class ue {
|
|
766
|
+
static addPromise = (t, e, s, n) => {
|
|
767
|
+
n.forEach((r) => {
|
|
768
|
+
r.add(t, e, s);
|
|
769
|
+
});
|
|
770
|
+
};
|
|
771
|
+
frame_start;
|
|
772
|
+
frame_capture_end;
|
|
773
|
+
ready;
|
|
774
|
+
_resolve;
|
|
775
|
+
_signal;
|
|
629
776
|
/**
|
|
630
777
|
* The number of promises that have been added to this group so far.
|
|
631
778
|
*/
|
|
@@ -638,13 +785,30 @@ class ye {
|
|
|
638
785
|
get currentlyAwaiting() {
|
|
639
786
|
return this._awaiting.length;
|
|
640
787
|
}
|
|
788
|
+
_resolved = !1;
|
|
789
|
+
_addedCount = 0;
|
|
790
|
+
_resolvedCount = 0;
|
|
791
|
+
/** These promises are currently being awaited */
|
|
792
|
+
_awaiting = [];
|
|
793
|
+
_maxPromisesPerObject = 1;
|
|
794
|
+
constructor(t, e) {
|
|
795
|
+
const n = Math.max(e.frames ?? 2, 2);
|
|
796
|
+
this.frame_start = t, this.frame_capture_end = t + n, this.ready = new Promise((r) => {
|
|
797
|
+
this._resolve = r;
|
|
798
|
+
}), this.ready.finally(() => {
|
|
799
|
+
this._resolved = !0, this._awaiting.length = 0;
|
|
800
|
+
}), this._signal = e.signal, this._signal?.addEventListener("abort", () => {
|
|
801
|
+
this.resolveNow();
|
|
802
|
+
}), this._maxPromisesPerObject = Math.max(1, e.maxPromisesPerObject ?? 1);
|
|
803
|
+
}
|
|
804
|
+
_currentFrame = 0;
|
|
641
805
|
update(t) {
|
|
642
|
-
|
|
643
|
-
this._currentFrame = t, ((e = this._signal) != null && e.aborted || this._currentFrame > this.frame_capture_end && this._awaiting.length === 0) && this.resolveNow();
|
|
806
|
+
this._currentFrame = t, (this._signal?.aborted || this._currentFrame > this.frame_capture_end && this._awaiting.length === 0) && this.resolveNow();
|
|
644
807
|
}
|
|
808
|
+
_seen = /* @__PURE__ */ new WeakMap();
|
|
645
809
|
add(t, e, s) {
|
|
646
810
|
if (this._resolved) {
|
|
647
|
-
|
|
811
|
+
g && console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");
|
|
648
812
|
return;
|
|
649
813
|
}
|
|
650
814
|
if (!(this._currentFrame > this.frame_capture_end)) {
|
|
@@ -652,7 +816,7 @@ class ye {
|
|
|
652
816
|
if (this._seen.has(e)) {
|
|
653
817
|
let n = this._seen.get(e);
|
|
654
818
|
if (n >= this._maxPromisesPerObject) {
|
|
655
|
-
|
|
819
|
+
g && console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");
|
|
656
820
|
return;
|
|
657
821
|
}
|
|
658
822
|
this._seen.set(e, n + 1);
|
|
@@ -664,85 +828,33 @@ class ye {
|
|
|
664
828
|
}
|
|
665
829
|
}
|
|
666
830
|
resolveNow() {
|
|
667
|
-
|
|
668
|
-
this._resolved || (e = this._resolve) == null || e.call(this, {
|
|
831
|
+
this._resolved || this._resolve?.({
|
|
669
832
|
awaited_count: this._addedCount,
|
|
670
833
|
resolved_count: this._resolvedCount,
|
|
671
|
-
cancelled:
|
|
834
|
+
cancelled: this._signal?.aborted ?? !1
|
|
672
835
|
});
|
|
673
836
|
}
|
|
674
837
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
u(this, "renderer");
|
|
686
|
-
u(this, "context");
|
|
687
|
-
u(this, "projectionScreenMatrix", new Ge());
|
|
688
|
-
/**
|
|
689
|
-
* The target triangle density is the desired max amount of triangles on screen when the mesh is filling the screen.
|
|
690
|
-
* @default 200_000
|
|
691
|
-
*/
|
|
692
|
-
u(this, "targetTriangleDensity", 2e5);
|
|
693
|
-
/**
|
|
694
|
-
* The interval in frames to automatically update the bounds of skinned meshes.
|
|
695
|
-
* Set to 0 or a negative value to disable automatic bounds updates.
|
|
696
|
-
* @default 30
|
|
697
|
-
*/
|
|
698
|
-
u(this, "skinnedMeshAutoUpdateBoundsInterval", 30);
|
|
699
|
-
/**
|
|
700
|
-
* 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.
|
|
701
|
-
* @default "auto"
|
|
702
|
-
*/
|
|
703
|
-
u(this, "updateInterval", "auto");
|
|
704
|
-
H(this, k, 1);
|
|
705
|
-
/**
|
|
706
|
-
* If set to true, the LODsManager will not update the LODs.
|
|
707
|
-
* @default false
|
|
708
|
-
*/
|
|
709
|
-
u(this, "pause", !1);
|
|
710
|
-
/**
|
|
711
|
-
* When set to true the LODsManager will not update the LODs. This can be used to manually update the LODs using the `update` method.
|
|
712
|
-
* Otherwise the LODs will be updated automatically when the renderer renders the scene.
|
|
713
|
-
* @default false
|
|
714
|
-
*/
|
|
715
|
-
u(this, "manual", !1);
|
|
716
|
-
u(this, "_newPromiseGroups", []);
|
|
717
|
-
u(this, "_promiseGroupIds", 0);
|
|
718
|
-
u(this, "_lodchangedlisteners", []);
|
|
719
|
-
H(this, K, void 0);
|
|
720
|
-
H(this, _e, new je());
|
|
721
|
-
H(this, J, 0);
|
|
722
|
-
H(this, ie, 0);
|
|
723
|
-
H(this, we, 0);
|
|
724
|
-
H(this, Y, 0);
|
|
725
|
-
u(this, "_fpsBuffer", [60, 60, 60, 60, 60]);
|
|
726
|
-
// private testIfLODLevelsAreAvailable() {
|
|
727
|
-
u(this, "_sphere", new Ze());
|
|
728
|
-
u(this, "_tempBox", new Ee());
|
|
729
|
-
u(this, "_tempBox2", new Ee());
|
|
730
|
-
u(this, "tempMatrix", new Ge());
|
|
731
|
-
u(this, "_tempWorldPosition", new W());
|
|
732
|
-
u(this, "_tempBoxSize", new W());
|
|
733
|
-
u(this, "_tempBox2Size", new W());
|
|
734
|
-
this.renderer = t, this.context = { ...e };
|
|
735
|
-
}
|
|
838
|
+
const C = X("debugprogressive"), gt = X("noprogressive"), de = Symbol("Needle:LODSManager"), ce = Symbol("Needle:LODState"), U = Symbol("Needle:CurrentLOD"), P = { mesh_lod: -1, texture_lod: -1 };
|
|
839
|
+
class L {
|
|
840
|
+
/**
|
|
841
|
+
* 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.
|
|
842
|
+
*/
|
|
843
|
+
static debugDrawLine;
|
|
844
|
+
/**
|
|
845
|
+
* Force override the LOD level for all objects in the scene
|
|
846
|
+
*/
|
|
847
|
+
static overrideGlobalLodLevel;
|
|
736
848
|
/** @internal */
|
|
737
849
|
static getObjectLODState(t) {
|
|
738
|
-
return t[
|
|
850
|
+
return t[ce];
|
|
739
851
|
}
|
|
740
852
|
static addPlugin(t) {
|
|
741
|
-
|
|
853
|
+
W.push(t);
|
|
742
854
|
}
|
|
743
855
|
static removePlugin(t) {
|
|
744
|
-
const e =
|
|
745
|
-
e >= 0 &&
|
|
856
|
+
const e = W.indexOf(t);
|
|
857
|
+
e >= 0 && W.splice(e, 1);
|
|
746
858
|
}
|
|
747
859
|
/**
|
|
748
860
|
* Gets the LODsManager for the given renderer. If the LODsManager does not exist yet, it will be created.
|
|
@@ -750,38 +862,72 @@ const O = class {
|
|
|
750
862
|
* @returns The LODsManager instance.
|
|
751
863
|
*/
|
|
752
864
|
static get(t, e) {
|
|
753
|
-
if (t[
|
|
754
|
-
return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), t[
|
|
755
|
-
const s = new
|
|
865
|
+
if (t[de])
|
|
866
|
+
return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), t[de];
|
|
867
|
+
const s = new L(t, {
|
|
756
868
|
engine: "unknown",
|
|
757
869
|
...e
|
|
758
870
|
});
|
|
759
|
-
return t[
|
|
871
|
+
return t[de] = s, s;
|
|
760
872
|
}
|
|
873
|
+
renderer;
|
|
874
|
+
context;
|
|
875
|
+
projectionScreenMatrix = new Le();
|
|
761
876
|
/** @deprecated use static `LODsManager.addPlugin()` method. This getter will be removed in later versions */
|
|
762
877
|
get plugins() {
|
|
763
|
-
return
|
|
878
|
+
return W;
|
|
764
879
|
}
|
|
880
|
+
/**
|
|
881
|
+
* The target triangle density is the desired max amount of triangles on screen when the mesh is filling the screen.
|
|
882
|
+
* @default 200_000
|
|
883
|
+
*/
|
|
884
|
+
targetTriangleDensity = 2e5;
|
|
885
|
+
/**
|
|
886
|
+
* The interval in frames to automatically update the bounds of skinned meshes.
|
|
887
|
+
* Set to 0 or a negative value to disable automatic bounds updates.
|
|
888
|
+
* @default 30
|
|
889
|
+
*/
|
|
890
|
+
skinnedMeshAutoUpdateBoundsInterval = 30;
|
|
891
|
+
/**
|
|
892
|
+
* 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.
|
|
893
|
+
* @default "auto"
|
|
894
|
+
*/
|
|
895
|
+
updateInterval = "auto";
|
|
896
|
+
#e = 1;
|
|
897
|
+
/**
|
|
898
|
+
* If set to true, the LODsManager will not update the LODs.
|
|
899
|
+
* @default false
|
|
900
|
+
*/
|
|
901
|
+
pause = !1;
|
|
902
|
+
/**
|
|
903
|
+
* When set to true the LODsManager will not update the LODs. This can be used to manually update the LODs using the `update` method.
|
|
904
|
+
* Otherwise the LODs will be updated automatically when the renderer renders the scene.
|
|
905
|
+
* @default false
|
|
906
|
+
*/
|
|
907
|
+
manual = !1;
|
|
908
|
+
_newPromiseGroups = [];
|
|
909
|
+
_promiseGroupIds = 0;
|
|
765
910
|
/**
|
|
766
911
|
* Call to await LODs loading during the next render cycle.
|
|
767
912
|
*/
|
|
768
913
|
awaitLoading(t) {
|
|
769
|
-
const e = this._promiseGroupIds++, s = new
|
|
914
|
+
const e = this._promiseGroupIds++, s = new ue(this.#r, { ...t });
|
|
770
915
|
this._newPromiseGroups.push(s);
|
|
771
916
|
const n = performance.now();
|
|
772
917
|
return s.ready.finally(() => {
|
|
773
918
|
const r = this._newPromiseGroups.indexOf(s);
|
|
774
|
-
r >= 0 && (this._newPromiseGroups.splice(r, 1),
|
|
919
|
+
r >= 0 && (this._newPromiseGroups.splice(r, 1), _e() && performance.measure("LODsManager:awaitLoading", {
|
|
775
920
|
start: n,
|
|
776
|
-
detail: { id: e, name: t
|
|
921
|
+
detail: { id: e, name: t?.name, awaited: s.awaitedCount, resolved: s.resolvedCount }
|
|
777
922
|
}));
|
|
778
923
|
}), s.ready;
|
|
779
924
|
}
|
|
780
925
|
_postprocessPromiseGroups() {
|
|
781
926
|
if (this._newPromiseGroups.length !== 0)
|
|
782
927
|
for (let t = this._newPromiseGroups.length - 1; t >= 0; t--)
|
|
783
|
-
this._newPromiseGroups[t].update(
|
|
928
|
+
this._newPromiseGroups[t].update(this.#r);
|
|
784
929
|
}
|
|
930
|
+
_lodchangedlisteners = [];
|
|
785
931
|
addEventListener(t, e) {
|
|
786
932
|
t === "changed" && this._lodchangedlisteners.push(e);
|
|
787
933
|
}
|
|
@@ -791,40 +937,49 @@ const O = class {
|
|
|
791
937
|
s >= 0 && this._lodchangedlisteners.splice(s, 1);
|
|
792
938
|
}
|
|
793
939
|
}
|
|
940
|
+
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
941
|
+
constructor(t, e) {
|
|
942
|
+
this.renderer = t, this.context = { ...e };
|
|
943
|
+
}
|
|
944
|
+
#t;
|
|
945
|
+
#o = new Ee();
|
|
946
|
+
#r = 0;
|
|
947
|
+
#n = 0;
|
|
948
|
+
#i = 0;
|
|
949
|
+
#s = 0;
|
|
950
|
+
_fpsBuffer = [60, 60, 60, 60, 60];
|
|
794
951
|
/**
|
|
795
952
|
* Enable the LODsManager. This will replace the render method of the renderer with a method that updates the LODs.
|
|
796
953
|
*/
|
|
797
954
|
enable() {
|
|
798
|
-
if (
|
|
799
|
-
return;
|
|
955
|
+
if (this.#t) return;
|
|
800
956
|
console.debug("[gltf-progressive] Enabling LODsManager for renderer");
|
|
801
957
|
let t = 0;
|
|
802
|
-
|
|
958
|
+
this.#t = this.renderer.render;
|
|
803
959
|
const e = this;
|
|
804
|
-
|
|
960
|
+
xe(this.renderer), this.renderer.render = function(s, n) {
|
|
805
961
|
const r = e.renderer.getRenderTarget();
|
|
806
|
-
(r == null || "isXRRenderTarget" in r && r.isXRRenderTarget) && (t = 0,
|
|
807
|
-
const
|
|
808
|
-
|
|
962
|
+
(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, C && e.#r % 200 === 0 && console.log("FPS", Math.round(e.#s), "Interval:", e.#e));
|
|
963
|
+
const o = t++;
|
|
964
|
+
e.#t.call(this, s, n), e.onAfterRender(s, n, o);
|
|
809
965
|
};
|
|
810
966
|
}
|
|
811
967
|
disable() {
|
|
812
|
-
|
|
968
|
+
this.#t && (console.debug("[gltf-progressive] Disabling LODsManager for renderer"), this.renderer.render = this.#t, this.#t = void 0);
|
|
813
969
|
}
|
|
814
970
|
update(t, e) {
|
|
815
971
|
this.internalUpdate(t, e);
|
|
816
972
|
}
|
|
817
973
|
onAfterRender(t, e, s) {
|
|
818
|
-
if (this.pause)
|
|
819
|
-
return;
|
|
974
|
+
if (this.pause) return;
|
|
820
975
|
const r = this.renderer.renderLists.get(t, 0).opaque;
|
|
821
|
-
let
|
|
976
|
+
let o = !0;
|
|
822
977
|
if (r.length === 1) {
|
|
823
|
-
const
|
|
824
|
-
(
|
|
978
|
+
const l = r[0].material;
|
|
979
|
+
(l.name === "EffectMaterial" || l.name === "CopyShader") && (o = !1);
|
|
825
980
|
}
|
|
826
|
-
if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (
|
|
827
|
-
if (
|
|
981
|
+
if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (o = !1), o) {
|
|
982
|
+
if (gt || (this.updateInterval === "auto" ? this.#s < 40 && this.#e < 10 ? (this.#e += 1, C && console.warn("↓ Reducing LOD updates", this.#e, this.#s.toFixed(0))) : this.#s >= 60 && this.#e > 1 && (this.#e -= 1, C && console.warn("↑ Increasing LOD updates", this.#e, this.#s.toFixed(0))) : this.#e = this.updateInterval, this.#e > 0 && this.#r % this.#e != 0))
|
|
828
983
|
return;
|
|
829
984
|
this.internalUpdate(t, e), this._postprocessPromiseGroups();
|
|
830
985
|
}
|
|
@@ -833,16 +988,15 @@ const O = class {
|
|
|
833
988
|
* Update LODs in a scene
|
|
834
989
|
*/
|
|
835
990
|
internalUpdate(t, e) {
|
|
836
|
-
var l, c;
|
|
837
991
|
const s = this.renderer.renderLists.get(t, 0), n = s.opaque;
|
|
838
992
|
this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix, e.matrixWorldInverse);
|
|
839
993
|
const r = this.targetTriangleDensity;
|
|
840
|
-
for (const
|
|
841
|
-
if (
|
|
842
|
-
|
|
994
|
+
for (const a of n) {
|
|
995
|
+
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")) {
|
|
996
|
+
C && (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)));
|
|
843
997
|
continue;
|
|
844
998
|
}
|
|
845
|
-
switch (
|
|
999
|
+
switch (a.material.type) {
|
|
846
1000
|
case "LineBasicMaterial":
|
|
847
1001
|
case "LineDashedMaterial":
|
|
848
1002
|
case "PointsMaterial":
|
|
@@ -851,62 +1005,58 @@ const O = class {
|
|
|
851
1005
|
case "MeshDepthMaterial":
|
|
852
1006
|
continue;
|
|
853
1007
|
}
|
|
854
|
-
if (
|
|
855
|
-
|
|
856
|
-
const
|
|
857
|
-
|
|
1008
|
+
if (C === "color" && a.material && !a.object.progressive_debug_color) {
|
|
1009
|
+
a.object.progressive_debug_color = !0;
|
|
1010
|
+
const c = Math.random() * 16777215, p = new Ne({ color: c });
|
|
1011
|
+
a.object.material = p;
|
|
858
1012
|
}
|
|
859
|
-
const
|
|
860
|
-
(
|
|
1013
|
+
const u = a.object;
|
|
1014
|
+
(u instanceof q || u.isMesh) && this.updateLODs(t, e, u, r);
|
|
861
1015
|
}
|
|
862
|
-
const
|
|
863
|
-
for (const
|
|
864
|
-
const
|
|
865
|
-
(
|
|
1016
|
+
const o = s.transparent;
|
|
1017
|
+
for (const a of o) {
|
|
1018
|
+
const u = a.object;
|
|
1019
|
+
(u instanceof q || u.isMesh) && this.updateLODs(t, e, u, r);
|
|
866
1020
|
}
|
|
867
|
-
const
|
|
868
|
-
for (const
|
|
869
|
-
const
|
|
870
|
-
(
|
|
1021
|
+
const l = s.transmissive;
|
|
1022
|
+
for (const a of l) {
|
|
1023
|
+
const u = a.object;
|
|
1024
|
+
(u instanceof q || u.isMesh) && this.updateLODs(t, e, u, r);
|
|
871
1025
|
}
|
|
872
1026
|
}
|
|
873
1027
|
/** Update the LOD levels for the renderer. */
|
|
874
1028
|
updateLODs(t, e, s, n) {
|
|
875
|
-
var a, l;
|
|
876
1029
|
s.userData || (s.userData = {});
|
|
877
|
-
let r = s[
|
|
878
|
-
if (r || (r = new
|
|
1030
|
+
let r = s[ce];
|
|
1031
|
+
if (r || (r = new pt(), s[ce] = r), r.frames++ < 2)
|
|
879
1032
|
return;
|
|
880
|
-
for (const
|
|
881
|
-
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
for (const
|
|
885
|
-
|
|
886
|
-
r.lastLodLevel_Mesh =
|
|
1033
|
+
for (const l of W)
|
|
1034
|
+
l.onBeforeUpdateLOD?.(this.renderer, t, e, s);
|
|
1035
|
+
const o = L.overrideGlobalLodLevel !== void 0 ? L.overrideGlobalLodLevel : N;
|
|
1036
|
+
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);
|
|
1037
|
+
for (const l of W)
|
|
1038
|
+
l.onAfterUpdatedLOD?.(this.renderer, t, e, s, P);
|
|
1039
|
+
r.lastLodLevel_Mesh = P.mesh_lod, r.lastLodLevel_Texture = P.texture_lod;
|
|
887
1040
|
}
|
|
888
1041
|
/** Load progressive textures for the given material
|
|
889
1042
|
* @param material the material to load the textures for
|
|
890
1043
|
* @param level the LOD level to load. Level 0 is the best quality, higher levels are lower quality
|
|
891
1044
|
* @returns Promise with true if the LOD was loaded, false if not
|
|
892
1045
|
*/
|
|
893
|
-
loadProgressiveTextures(t, e) {
|
|
894
|
-
if (!t)
|
|
895
|
-
return;
|
|
1046
|
+
loadProgressiveTextures(t, e, s) {
|
|
1047
|
+
if (!t) return;
|
|
896
1048
|
if (Array.isArray(t)) {
|
|
897
1049
|
for (const r of t)
|
|
898
1050
|
this.loadProgressiveTextures(r, e);
|
|
899
1051
|
return;
|
|
900
1052
|
}
|
|
901
|
-
let
|
|
902
|
-
(t[
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
const r = P.assignTextureLOD(t, e).then((i) => {
|
|
907
|
-
this._lodchangedlisteners.forEach((a) => a({ type: "texture", level: e, object: t }));
|
|
1053
|
+
let n = !1;
|
|
1054
|
+
if ((t[U] === void 0 || e < t[U]) && (n = !0), s !== void 0 && s >= 0 && (n = t[U] != s, e = s), n) {
|
|
1055
|
+
t[U] = e;
|
|
1056
|
+
const r = y.assignTextureLOD(t, e).then((o) => {
|
|
1057
|
+
this._lodchangedlisteners.forEach((l) => l({ type: "texture", level: e, object: t }));
|
|
908
1058
|
});
|
|
909
|
-
|
|
1059
|
+
ue.addPromise("texture", t, r, this._newPromiseGroups);
|
|
910
1060
|
}
|
|
911
1061
|
}
|
|
912
1062
|
/** Load progressive meshes for the given mesh
|
|
@@ -916,23 +1066,37 @@ const O = class {
|
|
|
916
1066
|
* @returns Promise with true if the LOD was loaded, false if not
|
|
917
1067
|
*/
|
|
918
1068
|
loadProgressiveMeshes(t, e) {
|
|
919
|
-
if (!t)
|
|
920
|
-
|
|
921
|
-
let s = t[Q] !== e;
|
|
1069
|
+
if (!t) return Promise.resolve(null);
|
|
1070
|
+
let s = t[U] !== e;
|
|
922
1071
|
const n = t["DEBUG:LOD"];
|
|
923
|
-
if (n != null && (s = t[
|
|
924
|
-
t[
|
|
925
|
-
const r = t.geometry,
|
|
926
|
-
return
|
|
1072
|
+
if (n != null && (s = t[U] != n, e = n), s) {
|
|
1073
|
+
t[U] = e;
|
|
1074
|
+
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));
|
|
1075
|
+
return ue.addPromise("mesh", t, o, this._newPromiseGroups), o;
|
|
927
1076
|
}
|
|
928
1077
|
return Promise.resolve(null);
|
|
929
1078
|
}
|
|
1079
|
+
// private testIfLODLevelsAreAvailable() {
|
|
1080
|
+
_sphere = new De();
|
|
1081
|
+
_tempBox = new he();
|
|
1082
|
+
_tempBox2 = new he();
|
|
1083
|
+
tempMatrix = new Le();
|
|
1084
|
+
_tempWorldPosition = new A();
|
|
1085
|
+
_tempBoxSize = new A();
|
|
1086
|
+
_tempBox2Size = new A();
|
|
1087
|
+
static corner0 = new A();
|
|
1088
|
+
static corner1 = new A();
|
|
1089
|
+
static corner2 = new A();
|
|
1090
|
+
static corner3 = new A();
|
|
1091
|
+
static _tempPtInside = new A();
|
|
930
1092
|
static isInside(t, e) {
|
|
931
|
-
const s = t.min, n = t.max, r = (s.x + n.x) * 0.5,
|
|
932
|
-
return this._tempPtInside.set(r,
|
|
1093
|
+
const s = t.min, n = t.max, r = (s.x + n.x) * 0.5, o = (s.y + n.y) * 0.5;
|
|
1094
|
+
return this._tempPtInside.set(r, o, s.z).applyMatrix4(e).z < 0;
|
|
933
1095
|
}
|
|
1096
|
+
static skinnedMeshBoundsFrameOffsetCounter = 0;
|
|
1097
|
+
static $skinnedMeshBoundsOffset = Symbol("gltf-progressive-skinnedMeshBoundsOffset");
|
|
1098
|
+
// #region calculateLodLevel
|
|
934
1099
|
calculateLodLevel(t, e, s, n, r) {
|
|
935
|
-
var b, R, Z;
|
|
936
1100
|
if (!e) {
|
|
937
1101
|
r.mesh_lod = -1, r.texture_lod = -1;
|
|
938
1102
|
return;
|
|
@@ -941,105 +1105,105 @@ const O = class {
|
|
|
941
1105
|
r.mesh_lod = -1, r.texture_lod = -1;
|
|
942
1106
|
return;
|
|
943
1107
|
}
|
|
944
|
-
let
|
|
945
|
-
if (
|
|
1108
|
+
let l = 10 + 1, a = !1;
|
|
1109
|
+
if (C && e["DEBUG:LOD"] != null)
|
|
946
1110
|
return e["DEBUG:LOD"];
|
|
947
|
-
const
|
|
948
|
-
if (!p && !
|
|
1111
|
+
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;
|
|
1112
|
+
if (!p && !v) {
|
|
949
1113
|
r.mesh_lod = 0, r.texture_lod = 0;
|
|
950
1114
|
return;
|
|
951
1115
|
}
|
|
952
|
-
p || (
|
|
953
|
-
const
|
|
954
|
-
let
|
|
1116
|
+
p || (a = !0, l = 0);
|
|
1117
|
+
const I = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
|
|
1118
|
+
let G = e.geometry.boundingBox;
|
|
955
1119
|
if (e.type === "SkinnedMesh") {
|
|
956
|
-
const
|
|
957
|
-
if (!
|
|
958
|
-
|
|
1120
|
+
const d = e;
|
|
1121
|
+
if (!d.boundingBox)
|
|
1122
|
+
d.computeBoundingBox();
|
|
959
1123
|
else if (this.skinnedMeshAutoUpdateBoundsInterval > 0) {
|
|
960
|
-
if (!
|
|
961
|
-
const
|
|
962
|
-
|
|
1124
|
+
if (!d[L.$skinnedMeshBoundsOffset]) {
|
|
1125
|
+
const O = L.skinnedMeshBoundsFrameOffsetCounter++;
|
|
1126
|
+
d[L.$skinnedMeshBoundsOffset] = O;
|
|
963
1127
|
}
|
|
964
|
-
const
|
|
965
|
-
if ((s.frames +
|
|
966
|
-
const
|
|
967
|
-
|
|
1128
|
+
const x = d[L.$skinnedMeshBoundsOffset];
|
|
1129
|
+
if ((s.frames + x) % this.skinnedMeshAutoUpdateBoundsInterval === 0) {
|
|
1130
|
+
const O = J(d), B = d.geometry;
|
|
1131
|
+
O && (d.geometry = O), d.computeBoundingBox(), d.geometry = B;
|
|
968
1132
|
}
|
|
969
1133
|
}
|
|
970
|
-
|
|
1134
|
+
G = d.boundingBox;
|
|
971
1135
|
}
|
|
972
|
-
if (
|
|
973
|
-
const
|
|
1136
|
+
if (G) {
|
|
1137
|
+
const d = t;
|
|
974
1138
|
if (e.geometry.attributes.color && e.geometry.attributes.color.count < 100 && e.geometry.boundingSphere) {
|
|
975
1139
|
this._sphere.copy(e.geometry.boundingSphere), this._sphere.applyMatrix4(e.matrixWorld);
|
|
976
|
-
const
|
|
977
|
-
if (this._sphere.containsPoint(
|
|
1140
|
+
const f = t.getWorldPosition(this._tempWorldPosition);
|
|
1141
|
+
if (this._sphere.containsPoint(f)) {
|
|
978
1142
|
r.mesh_lod = 0, r.texture_lod = 0;
|
|
979
1143
|
return;
|
|
980
1144
|
}
|
|
981
1145
|
}
|
|
982
|
-
if (this._tempBox.copy(
|
|
1146
|
+
if (this._tempBox.copy(G), this._tempBox.applyMatrix4(e.matrixWorld), d.isPerspectiveCamera && L.isInside(this._tempBox, this.projectionScreenMatrix)) {
|
|
983
1147
|
r.mesh_lod = 0, r.texture_lod = 0;
|
|
984
1148
|
return;
|
|
985
1149
|
}
|
|
986
|
-
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled &&
|
|
987
|
-
const
|
|
988
|
-
let
|
|
989
|
-
const
|
|
990
|
-
|
|
991
|
-
const
|
|
992
|
-
s.lastCentrality = (
|
|
1150
|
+
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && d.isPerspectiveCamera && d.fov > 70) {
|
|
1151
|
+
const f = this._tempBox.min, h = this._tempBox.max;
|
|
1152
|
+
let M = f.x, D = f.y, $ = h.x, K = h.y;
|
|
1153
|
+
const Z = 2, oe = 1.5, ee = (f.x + h.x) * 0.5, te = (f.y + h.y) * 0.5;
|
|
1154
|
+
M = (M - ee) * Z + ee, D = (D - te) * Z + te, $ = ($ - ee) * Z + ee, K = (K - te) * Z + te;
|
|
1155
|
+
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);
|
|
1156
|
+
s.lastCentrality = (oe - ie) * (oe - ie) * (oe - ie);
|
|
993
1157
|
} else
|
|
994
1158
|
s.lastCentrality = 1;
|
|
995
|
-
const
|
|
996
|
-
|
|
997
|
-
const
|
|
998
|
-
|
|
999
|
-
const
|
|
1000
|
-
if (Math.max(
|
|
1001
|
-
const
|
|
1002
|
-
|
|
1003
|
-
const
|
|
1004
|
-
|
|
1005
|
-
const
|
|
1006
|
-
|
|
1159
|
+
const x = this._tempBox.getSize(this._tempBoxSize);
|
|
1160
|
+
x.multiplyScalar(0.5), screen.availHeight > 0 && I > 0 && x.multiplyScalar(I / screen.availHeight), t.isPerspectiveCamera ? x.x *= t.aspect : t.isOrthographicCamera;
|
|
1161
|
+
const O = t.matrixWorldInverse, B = this._tempBox2;
|
|
1162
|
+
B.copy(G), B.applyMatrix4(e.matrixWorld), B.applyMatrix4(O);
|
|
1163
|
+
const b = B.getSize(this._tempBox2Size), z = Math.max(b.x, b.y);
|
|
1164
|
+
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, C && L.debugDrawLine) {
|
|
1165
|
+
const f = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
1166
|
+
f.invert();
|
|
1167
|
+
const h = L.corner0, M = L.corner1, D = L.corner2, $ = L.corner3;
|
|
1168
|
+
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);
|
|
1169
|
+
const K = (h.z + $.z) * 0.5;
|
|
1170
|
+
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);
|
|
1007
1171
|
}
|
|
1008
|
-
let
|
|
1009
|
-
if (
|
|
1010
|
-
for (let
|
|
1011
|
-
const
|
|
1012
|
-
if ((
|
|
1013
|
-
|
|
1172
|
+
let w = 999;
|
|
1173
|
+
if (u && s.lastScreenCoverage > 0)
|
|
1174
|
+
for (let f = 0; f < u.length; f++) {
|
|
1175
|
+
const h = u[f], D = (h.densities?.[c] || h.density || 1e-5) / s.lastScreenCoverage;
|
|
1176
|
+
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) {
|
|
1177
|
+
w = f;
|
|
1014
1178
|
break;
|
|
1015
1179
|
}
|
|
1016
1180
|
}
|
|
1017
|
-
|
|
1181
|
+
w < l && (l = w, a = !0);
|
|
1018
1182
|
}
|
|
1019
|
-
if (
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1183
|
+
if (a ? r.mesh_lod = l : r.mesh_lod = s.lastLodLevel_Mesh, C && r.mesh_lod != s.lastLodLevel_Mesh) {
|
|
1184
|
+
const x = u?.[r.mesh_lod];
|
|
1185
|
+
x && console.debug(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (density: ${x.densities?.[c].toFixed(0)}) | ${e.name}`);
|
|
1022
1186
|
}
|
|
1023
|
-
if (
|
|
1024
|
-
const
|
|
1187
|
+
if (v) {
|
|
1188
|
+
const d = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
|
|
1025
1189
|
if (s.lastLodLevel_Texture < 0) {
|
|
1026
|
-
if (r.texture_lod =
|
|
1027
|
-
const
|
|
1028
|
-
|
|
1190
|
+
if (r.texture_lod = _.max_count - 1, C) {
|
|
1191
|
+
const x = _.lods[_.max_count - 1];
|
|
1192
|
+
C && console.log(`First Texture LOD ${r.texture_lod} (${x.max_height}px) - ${e.name}`);
|
|
1029
1193
|
}
|
|
1030
1194
|
} else {
|
|
1031
|
-
const
|
|
1032
|
-
let
|
|
1033
|
-
|
|
1034
|
-
const
|
|
1035
|
-
let
|
|
1036
|
-
for (let
|
|
1037
|
-
const
|
|
1038
|
-
if (!(
|
|
1039
|
-
if (
|
|
1040
|
-
const m =
|
|
1041
|
-
|
|
1042
|
-
Screensize: ${
|
|
1195
|
+
const x = s.lastScreenspaceVolume.x + s.lastScreenspaceVolume.y + s.lastScreenspaceVolume.z;
|
|
1196
|
+
let O = s.lastScreenCoverage * 4;
|
|
1197
|
+
this.context?.engine === "model-viewer" && (O *= 1.5);
|
|
1198
|
+
const b = I / window.devicePixelRatio * O;
|
|
1199
|
+
let z = !1;
|
|
1200
|
+
for (let S = _.lods.length - 1; S >= 0; S--) {
|
|
1201
|
+
const w = _.lods[S];
|
|
1202
|
+
if (!(d && w.max_height >= 2048) && !(Ae() && w.max_height > 4096) && (w.max_height > b || !z && S === 0)) {
|
|
1203
|
+
if (z = !0, r.texture_lod = S, C && r.texture_lod < s.lastLodLevel_Texture) {
|
|
1204
|
+
const m = w.max_height;
|
|
1205
|
+
console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${m}px
|
|
1206
|
+
Screensize: ${b.toFixed(0)}px, Coverage: ${(100 * s.lastScreenCoverage).toFixed(2)}%, Volume ${x.toFixed(1)}
|
|
1043
1207
|
${e.name}`);
|
|
1044
1208
|
}
|
|
1045
1209
|
break;
|
|
@@ -1049,85 +1213,73 @@ ${e.name}`);
|
|
|
1049
1213
|
} else
|
|
1050
1214
|
r.texture_lod = 0;
|
|
1051
1215
|
}
|
|
1052
|
-
};
|
|
1053
|
-
let T = O;
|
|
1054
|
-
k = new WeakMap(), K = new WeakMap(), _e = new WeakMap(), J = new WeakMap(), ie = new WeakMap(), we = new WeakMap(), Y = new WeakMap(), /**
|
|
1055
|
-
* 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.
|
|
1056
|
-
*/
|
|
1057
|
-
u(T, "debugDrawLine"), /**
|
|
1058
|
-
* Force override the LOD level for all objects in the scene
|
|
1059
|
-
*/
|
|
1060
|
-
u(T, "overrideGlobalLodLevel"), u(T, "corner0", new W()), u(T, "corner1", new W()), u(T, "corner2", new W()), u(T, "corner3", new W()), u(T, "_tempPtInside", new W()), u(T, "skinnedMeshBoundsFrameOffsetCounter", 0), u(T, "$skinnedMeshBoundsOffset", Symbol("gltf-progressive-skinnedMeshBoundsOffset"));
|
|
1061
|
-
class Lt {
|
|
1062
|
-
constructor() {
|
|
1063
|
-
u(this, "frames", 0);
|
|
1064
|
-
u(this, "lastLodLevel_Mesh", -1);
|
|
1065
|
-
u(this, "lastLodLevel_Texture", -1);
|
|
1066
|
-
u(this, "lastScreenCoverage", 0);
|
|
1067
|
-
u(this, "lastScreenspaceVolume", new W());
|
|
1068
|
-
u(this, "lastCentrality", 0);
|
|
1069
|
-
}
|
|
1070
1216
|
}
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1217
|
+
class pt {
|
|
1218
|
+
frames = 0;
|
|
1219
|
+
lastLodLevel_Mesh = -1;
|
|
1220
|
+
lastLodLevel_Texture = -1;
|
|
1221
|
+
lastScreenCoverage = 0;
|
|
1222
|
+
lastScreenspaceVolume = new A();
|
|
1223
|
+
lastCentrality = 0;
|
|
1224
|
+
}
|
|
1225
|
+
const ve = Symbol("NEEDLE_mesh_lod"), se = Symbol("NEEDLE_texture_lod");
|
|
1226
|
+
let fe = null;
|
|
1227
|
+
function Ce() {
|
|
1228
|
+
const i = mt();
|
|
1229
|
+
i && (i.mapURLs(function(t) {
|
|
1230
|
+
return be(), t;
|
|
1231
|
+
}), be(), fe?.disconnect(), fe = new MutationObserver((t) => {
|
|
1078
1232
|
t.forEach((e) => {
|
|
1079
1233
|
e.addedNodes.forEach((s) => {
|
|
1080
|
-
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" &&
|
|
1234
|
+
s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" && ke(s);
|
|
1081
1235
|
});
|
|
1082
1236
|
});
|
|
1083
|
-
}),
|
|
1237
|
+
}), fe.observe(document, { childList: !0, subtree: !0 }));
|
|
1084
1238
|
}
|
|
1085
|
-
function
|
|
1086
|
-
if (typeof customElements > "u")
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
console.debug("[gltf-progressive] model-viewer defined"), Ve();
|
|
1239
|
+
function mt() {
|
|
1240
|
+
if (typeof customElements > "u") return null;
|
|
1241
|
+
const i = customElements.get("model-viewer");
|
|
1242
|
+
return i || (customElements.whenDefined("model-viewer").then(() => {
|
|
1243
|
+
console.debug("[gltf-progressive] model-viewer defined"), Ce();
|
|
1091
1244
|
}), null);
|
|
1092
1245
|
}
|
|
1093
|
-
function
|
|
1094
|
-
if (typeof document > "u")
|
|
1095
|
-
return;
|
|
1246
|
+
function be() {
|
|
1247
|
+
if (typeof document > "u") return;
|
|
1096
1248
|
document.querySelectorAll("model-viewer").forEach((t) => {
|
|
1097
|
-
|
|
1249
|
+
ke(t);
|
|
1098
1250
|
});
|
|
1099
1251
|
}
|
|
1100
|
-
const
|
|
1101
|
-
let
|
|
1102
|
-
function
|
|
1103
|
-
if (!
|
|
1252
|
+
const Me = /* @__PURE__ */ new WeakSet();
|
|
1253
|
+
let yt = 0;
|
|
1254
|
+
function ke(i) {
|
|
1255
|
+
if (!i || Me.has(i))
|
|
1104
1256
|
return null;
|
|
1105
|
-
|
|
1106
|
-
`,
|
|
1257
|
+
Me.add(i), console.debug("[gltf-progressive] found new model-viewer..." + ++yt + `
|
|
1258
|
+
`, i.getAttribute("src"));
|
|
1107
1259
|
let t = null, e = null, s = null;
|
|
1108
|
-
for (let n =
|
|
1109
|
-
const r = Object.getOwnPropertySymbols(n),
|
|
1110
|
-
!t &&
|
|
1260
|
+
for (let n = i; n != null; n = Object.getPrototypeOf(n)) {
|
|
1261
|
+
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)");
|
|
1262
|
+
!t && o != null && (t = i[o].threeRenderer), !e && l != null && (e = i[l]), !s && a != null && (s = i[a]);
|
|
1111
1263
|
}
|
|
1112
1264
|
if (t && e) {
|
|
1113
1265
|
let n = function() {
|
|
1114
1266
|
if (s) {
|
|
1115
|
-
let
|
|
1116
|
-
if (
|
|
1117
|
-
clearInterval(
|
|
1267
|
+
let o = 0, l = setInterval(() => {
|
|
1268
|
+
if (o++ > 5) {
|
|
1269
|
+
clearInterval(l);
|
|
1118
1270
|
return;
|
|
1119
1271
|
}
|
|
1120
|
-
s
|
|
1272
|
+
s?.call(i);
|
|
1121
1273
|
}, 300);
|
|
1122
1274
|
}
|
|
1123
1275
|
};
|
|
1124
1276
|
console.debug("[gltf-progressive] setup model-viewer");
|
|
1125
|
-
const r =
|
|
1126
|
-
return
|
|
1127
|
-
s
|
|
1128
|
-
}),
|
|
1129
|
-
|
|
1130
|
-
}),
|
|
1277
|
+
const r = L.get(t, { engine: "model-viewer" });
|
|
1278
|
+
return L.addPlugin(new xt()), r.enable(), r.addEventListener("changed", () => {
|
|
1279
|
+
s?.call(i);
|
|
1280
|
+
}), i.addEventListener("model-visibility", (o) => {
|
|
1281
|
+
o.detail.visible && s?.call(i);
|
|
1282
|
+
}), i.addEventListener("load", () => {
|
|
1131
1283
|
n();
|
|
1132
1284
|
}), () => {
|
|
1133
1285
|
r.disable();
|
|
@@ -1135,10 +1287,8 @@ function We(o) {
|
|
|
1135
1287
|
}
|
|
1136
1288
|
return null;
|
|
1137
1289
|
}
|
|
1138
|
-
class
|
|
1139
|
-
|
|
1140
|
-
u(this, "_didWarnAboutMissingUrl", !1);
|
|
1141
|
-
}
|
|
1290
|
+
class xt {
|
|
1291
|
+
_didWarnAboutMissingUrl = !1;
|
|
1142
1292
|
onBeforeUpdateLOD(t, e, s, n) {
|
|
1143
1293
|
this.tryParseMeshLOD(e, n), this.tryParseTextureLOD(e, n);
|
|
1144
1294
|
}
|
|
@@ -1155,96 +1305,87 @@ class vt {
|
|
|
1155
1305
|
return t.element;
|
|
1156
1306
|
}
|
|
1157
1307
|
tryParseTextureLOD(t, e) {
|
|
1158
|
-
if (e[
|
|
1159
|
-
|
|
1160
|
-
e[pe] = !0;
|
|
1308
|
+
if (e[se] == !0) return;
|
|
1309
|
+
e[se] = !0;
|
|
1161
1310
|
const s = this.tryGetCurrentGLTF(t), n = this.tryGetCurrentModelViewer(t), r = this.getUrl(n);
|
|
1162
1311
|
if (r && s && e.material) {
|
|
1163
|
-
let
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
const
|
|
1173
|
-
if (
|
|
1174
|
-
|
|
1175
|
-
const R = s.parser.json.textures[b];
|
|
1176
|
-
if (!R) {
|
|
1177
|
-
console.warn("Texture data not found for texture index " + b);
|
|
1312
|
+
let o = function(a) {
|
|
1313
|
+
if (a[se] == !0) return;
|
|
1314
|
+
a[se] = !0, a.userData && (a.userData.LOD = -1);
|
|
1315
|
+
const u = Object.keys(a);
|
|
1316
|
+
for (let c = 0; c < u.length; c++) {
|
|
1317
|
+
const p = u[c], _ = a[p];
|
|
1318
|
+
if (_?.isTexture === !0) {
|
|
1319
|
+
const v = _.userData?.associations?.textures;
|
|
1320
|
+
if (v == null) continue;
|
|
1321
|
+
const I = s.parser.json.textures[v];
|
|
1322
|
+
if (!I) {
|
|
1323
|
+
console.warn("Texture data not found for texture index " + v);
|
|
1178
1324
|
continue;
|
|
1179
1325
|
}
|
|
1180
|
-
if (
|
|
1181
|
-
const
|
|
1182
|
-
|
|
1326
|
+
if (I?.extensions?.[F]) {
|
|
1327
|
+
const G = I.extensions[F];
|
|
1328
|
+
G && r && y.registerTexture(r, _, G.lods.length, v, G);
|
|
1183
1329
|
}
|
|
1184
1330
|
}
|
|
1185
1331
|
}
|
|
1186
1332
|
};
|
|
1187
|
-
const
|
|
1188
|
-
if (Array.isArray(a))
|
|
1189
|
-
|
|
1190
|
-
i(l);
|
|
1191
|
-
else
|
|
1192
|
-
i(a);
|
|
1333
|
+
const l = e.material;
|
|
1334
|
+
if (Array.isArray(l)) for (const a of l) o(a);
|
|
1335
|
+
else o(l);
|
|
1193
1336
|
}
|
|
1194
1337
|
}
|
|
1195
1338
|
tryParseMeshLOD(t, e) {
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
return;
|
|
1199
|
-
e[$e] = !0;
|
|
1339
|
+
if (e[ve] == !0) return;
|
|
1340
|
+
e[ve] = !0;
|
|
1200
1341
|
const s = this.tryGetCurrentModelViewer(t), n = this.getUrl(s);
|
|
1201
1342
|
if (!n)
|
|
1202
1343
|
return;
|
|
1203
|
-
const r =
|
|
1344
|
+
const r = e.userData?.gltfExtensions?.[F];
|
|
1204
1345
|
if (r && n) {
|
|
1205
|
-
const
|
|
1206
|
-
|
|
1346
|
+
const o = e.uuid;
|
|
1347
|
+
y.registerMesh(n, o, e, 0, r.lods.length, r);
|
|
1207
1348
|
}
|
|
1208
1349
|
}
|
|
1209
1350
|
}
|
|
1210
|
-
function
|
|
1211
|
-
|
|
1351
|
+
function wt(i, t, e, s) {
|
|
1352
|
+
xe(t), Se(e), Te(e, {
|
|
1212
1353
|
progressive: !0,
|
|
1213
|
-
...s
|
|
1214
|
-
}), e.register((r) => new
|
|
1215
|
-
const n =
|
|
1216
|
-
return
|
|
1354
|
+
...s?.hints
|
|
1355
|
+
}), e.register((r) => new y(r, i));
|
|
1356
|
+
const n = L.get(t);
|
|
1357
|
+
return s?.enableLODsManager !== !1 && n.enable(), n;
|
|
1217
1358
|
}
|
|
1218
|
-
|
|
1219
|
-
if (!
|
|
1220
|
-
const
|
|
1359
|
+
Ce();
|
|
1360
|
+
if (!rt) {
|
|
1361
|
+
const i = {
|
|
1221
1362
|
gltfProgressive: {
|
|
1222
|
-
useNeedleProgressive:
|
|
1223
|
-
LODsManager:
|
|
1224
|
-
configureLoader:
|
|
1225
|
-
getRaycastMesh:
|
|
1226
|
-
useRaycastMeshes:
|
|
1363
|
+
useNeedleProgressive: wt,
|
|
1364
|
+
LODsManager: L,
|
|
1365
|
+
configureLoader: Te,
|
|
1366
|
+
getRaycastMesh: J,
|
|
1367
|
+
useRaycastMeshes: ot
|
|
1227
1368
|
}
|
|
1228
1369
|
};
|
|
1229
1370
|
if (!globalThis.Needle)
|
|
1230
|
-
globalThis.Needle =
|
|
1371
|
+
globalThis.Needle = i;
|
|
1231
1372
|
else
|
|
1232
|
-
for (const t in
|
|
1233
|
-
globalThis.Needle[t] =
|
|
1373
|
+
for (const t in i)
|
|
1374
|
+
globalThis.Needle[t] = i[t];
|
|
1234
1375
|
}
|
|
1235
1376
|
export {
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1377
|
+
F as EXTENSION_NAME,
|
|
1378
|
+
L as LODsManager,
|
|
1379
|
+
y as NEEDLE_progressive,
|
|
1380
|
+
Ke as VERSION,
|
|
1381
|
+
Se as addDracoAndKTX2Loaders,
|
|
1382
|
+
Te as configureLoader,
|
|
1383
|
+
xe as createLoaders,
|
|
1384
|
+
J as getRaycastMesh,
|
|
1385
|
+
Ce as patchModelViewer,
|
|
1386
|
+
nt as registerRaycastMesh,
|
|
1387
|
+
Qe as setDracoDecoderLocation,
|
|
1388
|
+
Je as setKTX2TranscoderLocation,
|
|
1389
|
+
wt as useNeedleProgressive,
|
|
1390
|
+
ot as useRaycastMeshes
|
|
1250
1391
|
};
|