@needle-tools/gltf-progressive 1.2.0-alpha.4 → 1.2.0-alpha.5
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 +12 -4
- package/examples/threejs/main.js +32 -1
- package/gltf-progressive.js +91 -83
- package/gltf-progressive.min.js +4 -4
- package/gltf-progressive.umd.cjs +4 -4
- package/lib/extension.js +10 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,10 @@ All notable changes to this package will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [1.2.0-alpha.5] - 2023-06-10
|
|
8
|
+
- fix: safeguard when `registerMesh` or `registerTexture` are being called with invalid data
|
|
9
|
+
- examples: update vanilla threejs example
|
|
10
|
+
|
|
7
11
|
## [1.2.0-alpha.4] - 2023-06-07
|
|
8
12
|
- add: `useRaycastMeshes` method:
|
|
9
13
|
```ts
|
package/README.md
CHANGED
|
@@ -12,11 +12,17 @@ Support for loading of glTF or GLB files with progressive mesh or texture data f
|
|
|
12
12
|
|
|
13
13
|
Examples are in the `/examples` directory. Live versions can be found in the links below.
|
|
14
14
|
|
|
15
|
-
- [Vanilla three.js](https://engine.needle.tools/demos/gltf-progressive/threejs/)
|
|
15
|
+
- [Vanilla three.js](https://engine.needle.tools/demos/gltf-progressive/threejs/) - multiple models and animations
|
|
16
16
|
- [\<model-viewer\>](https://engine.needle.tools/demos/gltf-progressive/modelviewer)
|
|
17
17
|
- [React Three Fiber](https://engine.needle.tools/demos/gltf-progressive/r3f/)
|
|
18
18
|
|
|
19
19
|
|
|
20
|
+
<br/>
|
|
21
|
+
<video width="320" controls autoplay src="https://engine.needle.tools/demos/gltf-progressive/video.mp4">
|
|
22
|
+
<source src="https://engine.needle.tools/demos/gltf-progressive/video.mp4" type="video/mp4">
|
|
23
|
+
</video>
|
|
24
|
+
|
|
25
|
+
|
|
20
26
|
## Usage
|
|
21
27
|
|
|
22
28
|
### react three fiber
|
|
@@ -74,11 +80,11 @@ gltfLoader.load(url, gltf => {
|
|
|
74
80
|
|
|
75
81
|
### \<model-viewer\>
|
|
76
82
|
|
|
77
|
-
The
|
|
83
|
+
The example can be found in `examples/modelviewer.html`
|
|
78
84
|
|
|
79
85
|
```html
|
|
80
86
|
<head>
|
|
81
|
-
<!-- Include
|
|
87
|
+
<!-- Include threejs import map -->
|
|
82
88
|
<script type="importmap">
|
|
83
89
|
{
|
|
84
90
|
"imports": {
|
|
@@ -87,14 +93,16 @@ The full example can be found in `examples/modelviewer.html`
|
|
|
87
93
|
}
|
|
88
94
|
}
|
|
89
95
|
</script>
|
|
96
|
+
<!-- Include gltf-progressive -->
|
|
90
97
|
<script type="module" src="https://www.unpkg.com/@needle-tools/gltf-progressive@latest"></script>
|
|
98
|
+
<!-- Include model-viewer -->
|
|
91
99
|
<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"></script>
|
|
92
100
|
</head>
|
|
93
101
|
<body>
|
|
94
102
|
|
|
95
103
|
<model-viewer src="https://engine.needle.tools/demos/gltf-progressive/assets/church/model.glb" camera-controls auto-rotate></model-viewer>
|
|
96
104
|
|
|
97
|
-
|
|
105
|
+
</body>
|
|
98
106
|
```
|
|
99
107
|
|
|
100
108
|
|
package/examples/threejs/main.js
CHANGED
|
@@ -58,6 +58,7 @@ new EXRLoader().load(environmentTextureUrl, texture => {
|
|
|
58
58
|
|
|
59
59
|
const modelUrls = [
|
|
60
60
|
"https://engine.needle.tools/demos/gltf-progressive/assets/putti gruppe/model.glb",
|
|
61
|
+
"https://engine.needle.tools/demos/gltf-progressive/assets/cyberpunk/model.glb",
|
|
61
62
|
"https://engine.needle.tools/demos/gltf-progressive/assets/robot/model.glb",
|
|
62
63
|
"https://engine.needle.tools/demos/gltf-progressive/assets/vase/model.glb",
|
|
63
64
|
"https://engine.needle.tools/demos/gltf-progressive/assets/jupiter_und_ganymed/model.glb",
|
|
@@ -67,6 +68,8 @@ let currentUrl = "";
|
|
|
67
68
|
/** @type {null | THREE.Scene} */
|
|
68
69
|
let currentScene = null;
|
|
69
70
|
let wireframe = false;
|
|
71
|
+
/** @type {null | THREE.AnimationMixer} */
|
|
72
|
+
let animationMixer = null;
|
|
70
73
|
|
|
71
74
|
function loadScene() {
|
|
72
75
|
let currentIndex = modelUrls.indexOf(currentUrl);
|
|
@@ -77,6 +80,10 @@ function loadScene() {
|
|
|
77
80
|
const url = modelUrls[currentIndex];
|
|
78
81
|
currentUrl = url;
|
|
79
82
|
wireframe = false;
|
|
83
|
+
if (animationMixer) {
|
|
84
|
+
animationMixer.stopAllAction();
|
|
85
|
+
animationMixer = null;
|
|
86
|
+
}
|
|
80
87
|
|
|
81
88
|
// Integrate @needle-tools/gltf-progressive
|
|
82
89
|
// Create a new GLTFLoader instance
|
|
@@ -99,11 +106,33 @@ function loadScene() {
|
|
|
99
106
|
if (url.includes("church")) {
|
|
100
107
|
gltf.scene.scale.multiplyScalar(.1);
|
|
101
108
|
}
|
|
109
|
+
else if (url.includes("cyberpunk")) {
|
|
110
|
+
gltf.scene.scale.multiplyScalar(15);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (gltf.animations?.length) {
|
|
114
|
+
console.log("Playing animation", gltf.animations)
|
|
115
|
+
animationMixer = new THREE.AnimationMixer(gltf.scene);
|
|
116
|
+
const action = animationMixer.clipAction(gltf.animations[0]);
|
|
117
|
+
action.setLoop(THREE.LoopRepeat);
|
|
118
|
+
action.play();
|
|
119
|
+
}
|
|
102
120
|
})
|
|
103
121
|
}
|
|
104
122
|
loadScene();
|
|
105
123
|
|
|
106
124
|
|
|
125
|
+
const clock = new THREE.Clock();
|
|
126
|
+
function loop() {
|
|
127
|
+
const dt = clock.getDelta();
|
|
128
|
+
if (animationMixer) {
|
|
129
|
+
animationMixer.update(dt);
|
|
130
|
+
}
|
|
131
|
+
window.requestAnimationFrame(loop);
|
|
132
|
+
}
|
|
133
|
+
window.requestAnimationFrame(loop);
|
|
134
|
+
|
|
135
|
+
|
|
107
136
|
useRaycastMeshes();
|
|
108
137
|
const raycaster = new THREE.Raycaster();
|
|
109
138
|
raycaster.params.Line.threshold = 0;
|
|
@@ -115,7 +144,9 @@ window.addEventListener("click", evt => {
|
|
|
115
144
|
raycaster.setFromCamera(mousePos, camera);
|
|
116
145
|
const hits = raycaster.intersectObjects(scene.children, true);
|
|
117
146
|
if (hits?.length) {
|
|
118
|
-
const
|
|
147
|
+
const hit = hits[0];
|
|
148
|
+
const obj = hit.object;
|
|
149
|
+
console.log("HIT", obj.name, hit)
|
|
119
150
|
const raycastMesh = getRaycastMesh(obj);
|
|
120
151
|
if (raycastMesh) {
|
|
121
152
|
const newMesh = new THREE.Mesh(raycastMesh, new THREE.MeshBasicMaterial({ color: 0xffddff, wireframe: true, transparent: true, opacity: .5, depthTest: false }));
|
package/gltf-progressive.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
var me = Object.defineProperty;
|
|
2
|
-
var
|
|
3
|
-
var c = (l, e, t) => (
|
|
4
|
-
import { MeshoptDecoder as
|
|
2
|
+
var xe = (l, e, t) => e in l ? me(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
|
|
3
|
+
var c = (l, e, t) => (xe(l, typeof e != "symbol" ? e + "" : e, t), t);
|
|
4
|
+
import { MeshoptDecoder as Le } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
5
5
|
import { DRACOLoader as De } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
6
6
|
import { KTX2Loader as Me } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
7
|
-
import { BufferGeometry as Y, Mesh as F, Material as
|
|
7
|
+
import { BufferGeometry as Y, Mesh as F, Material as we, Texture as N, TextureLoader as Oe, Matrix4 as le, Frustum as _e, Sphere as ve, Box3 as ce, Vector3 as k } from "three";
|
|
8
8
|
import { GLTFLoader as Se } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
9
9
|
let Z = "https://www.gstatic.com/draco/versioned/decoders/1.4.1/", oe = "https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";
|
|
10
10
|
fetch(Z + "draco_decoder.js", { method: "head" }).catch((l) => {
|
|
@@ -18,7 +18,7 @@ function We(l) {
|
|
|
18
18
|
}
|
|
19
19
|
let q, ie, X;
|
|
20
20
|
function he(l) {
|
|
21
|
-
q || (q = new De(), q.setDecoderPath(Z), q.setDecoderConfig({ type: "js" })), X || (X = new Me(), X.setTranscoderPath(oe)), ie || (ie =
|
|
21
|
+
q || (q = new De(), q.setDecoderPath(Z), q.setDecoderConfig({ type: "js" })), X || (X = new Me(), X.setTranscoderPath(oe)), ie || (ie = Le), l ? X.detectSupport(l) : console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail");
|
|
22
22
|
}
|
|
23
23
|
function ge(l) {
|
|
24
24
|
l.dracoLoader || l.setDRACOLoader(q), l.ktx2Loader || l.setKTX2Loader(X), l.meshoptDecoder || l.setMeshoptDecoder(ie);
|
|
@@ -76,8 +76,8 @@ function Pe(l) {
|
|
|
76
76
|
e.setAttribute(t, l.getAttribute(t));
|
|
77
77
|
return e.setIndex(l.getIndex()), e;
|
|
78
78
|
}
|
|
79
|
-
const I = new Array(),
|
|
80
|
-
if (
|
|
79
|
+
const I = new Array(), B = "NEEDLE_progressive", O = j("debugprogressive"), se = Symbol("needle-progressive-texture"), V = /* @__PURE__ */ new Map(), ne = /* @__PURE__ */ new Set();
|
|
80
|
+
if (O) {
|
|
81
81
|
let l = function() {
|
|
82
82
|
e += 1, console.log("Toggle LOD level", e, V), V.forEach((s, n) => {
|
|
83
83
|
for (const i of s.keys) {
|
|
@@ -100,7 +100,7 @@ if (w) {
|
|
|
100
100
|
}
|
|
101
101
|
function ue(l, e, t) {
|
|
102
102
|
var s;
|
|
103
|
-
if (!
|
|
103
|
+
if (!O)
|
|
104
104
|
return;
|
|
105
105
|
V.has(l) || V.set(l, { keys: [], sourceId: t });
|
|
106
106
|
const r = V.get(l);
|
|
@@ -115,14 +115,14 @@ const _ = class {
|
|
|
115
115
|
var r, s;
|
|
116
116
|
if (this._isLoadingMesh)
|
|
117
117
|
return null;
|
|
118
|
-
const t = (s = (r = this.parser.json.meshes[e]) == null ? void 0 : r.extensions) == null ? void 0 : s[
|
|
118
|
+
const t = (s = (r = this.parser.json.meshes[e]) == null ? void 0 : r.extensions) == null ? void 0 : s[B];
|
|
119
119
|
return t ? (this._isLoadingMesh = !0, this.parser.getDependency("mesh", e).then((n) => (this._isLoadingMesh = !1, n && _.registerMesh(this.url, t.guid, n, t.lods.length, void 0, t), n))) : null;
|
|
120
120
|
});
|
|
121
|
-
|
|
121
|
+
O && console.log("Progressive extension registered for", t), this.parser = e, this.url = t;
|
|
122
122
|
}
|
|
123
123
|
/** The name of the extension */
|
|
124
124
|
get name() {
|
|
125
|
-
return
|
|
125
|
+
return B;
|
|
126
126
|
}
|
|
127
127
|
static getMeshLODInformation(e) {
|
|
128
128
|
const t = this.getAssignedLODInformation(e);
|
|
@@ -141,7 +141,7 @@ const _ = class {
|
|
|
141
141
|
this.getMaterialMinMaxLODsCount(o, t);
|
|
142
142
|
return e[s] = t, t;
|
|
143
143
|
}
|
|
144
|
-
if (
|
|
144
|
+
if (O === "verbose" && console.log("getMaterialMinMaxLODsCount", e), e.type === "ShaderMaterial" || e.type === "RawShaderMaterial") {
|
|
145
145
|
const o = e;
|
|
146
146
|
for (const a of Object.keys(o.uniforms)) {
|
|
147
147
|
const h = o.uniforms[a].value;
|
|
@@ -232,12 +232,12 @@ const _ = class {
|
|
|
232
232
|
const o = n.index || 0;
|
|
233
233
|
i = i[o];
|
|
234
234
|
}
|
|
235
|
-
i && s != i && i instanceof Y && (e.geometry = i,
|
|
235
|
+
i && s != i && i instanceof Y && (e.geometry = i, O && ue(e, "geometry", n.url));
|
|
236
236
|
}
|
|
237
237
|
return i;
|
|
238
238
|
}).catch((i) => (console.error("Error loading mesh LOD", e, i), null));
|
|
239
239
|
} else
|
|
240
|
-
|
|
240
|
+
O && console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh", e);
|
|
241
241
|
return Promise.resolve(null);
|
|
242
242
|
}
|
|
243
243
|
/** Load a different resolution of a texture (if available)
|
|
@@ -250,9 +250,9 @@ const _ = class {
|
|
|
250
250
|
static assignTextureLOD(e, t = 0) {
|
|
251
251
|
if (!e)
|
|
252
252
|
return Promise.resolve(null);
|
|
253
|
-
if (e instanceof
|
|
253
|
+
if (e instanceof we || e.isMaterial === !0) {
|
|
254
254
|
const r = e, s = [], n = new Array();
|
|
255
|
-
if (
|
|
255
|
+
if (O && ne.add(r), r.uniforms && r.isRawShaderMaterial || r.isShaderMaterial === !0) {
|
|
256
256
|
const i = r;
|
|
257
257
|
for (const o of Object.keys(i.uniforms)) {
|
|
258
258
|
const a = i.uniforms[o].value;
|
|
@@ -295,26 +295,26 @@ const _ = class {
|
|
|
295
295
|
if (i) {
|
|
296
296
|
const o = this.getAssignedLODInformation(i);
|
|
297
297
|
if (o && (o == null ? void 0 : o.level) < t)
|
|
298
|
-
return
|
|
298
|
+
return O === "verbose" && console.warn("Assigned texture level is already higher: ", o.level, t, r, i, n), null;
|
|
299
299
|
}
|
|
300
300
|
r[s] = n;
|
|
301
301
|
}
|
|
302
|
-
if (
|
|
302
|
+
if (O && s && r) {
|
|
303
303
|
const i = this.getAssignedLODInformation(e);
|
|
304
304
|
i && ue(r, s, i.url);
|
|
305
305
|
}
|
|
306
306
|
}
|
|
307
307
|
return n;
|
|
308
308
|
} else
|
|
309
|
-
|
|
309
|
+
O == "verbose" && console.warn("No LOD found for", e, t);
|
|
310
310
|
return null;
|
|
311
311
|
}).catch((n) => (console.error("Error loading LOD", e, n), null));
|
|
312
312
|
}
|
|
313
313
|
afterRoot(e) {
|
|
314
314
|
var t, r;
|
|
315
|
-
return
|
|
315
|
+
return O && console.log("AFTER", this.url, e), (t = this.parser.json.textures) == null || t.forEach((s, n) => {
|
|
316
316
|
if (s != null && s.extensions) {
|
|
317
|
-
const i = s == null ? void 0 : s.extensions[
|
|
317
|
+
const i = s == null ? void 0 : s.extensions[B];
|
|
318
318
|
if (i) {
|
|
319
319
|
let o = !1;
|
|
320
320
|
for (const a of this.parser.associations.keys())
|
|
@@ -326,7 +326,7 @@ const _ = class {
|
|
|
326
326
|
}
|
|
327
327
|
}), (r = this.parser.json.meshes) == null || r.forEach((s, n) => {
|
|
328
328
|
if (s != null && s.extensions) {
|
|
329
|
-
const i = s == null ? void 0 : s.extensions[
|
|
329
|
+
const i = s == null ? void 0 : s.extensions[B];
|
|
330
330
|
if (i && i.lods) {
|
|
331
331
|
for (const o of this.parser.associations.keys())
|
|
332
332
|
if (o.isMesh) {
|
|
@@ -339,7 +339,7 @@ const _ = class {
|
|
|
339
339
|
}
|
|
340
340
|
static async getOrLoadLOD(e, t) {
|
|
341
341
|
var o, a, h, d;
|
|
342
|
-
const r =
|
|
342
|
+
const r = O == "verbose", s = e.userData.LODS;
|
|
343
343
|
if (!s)
|
|
344
344
|
return null;
|
|
345
345
|
const n = s == null ? void 0 : s.key;
|
|
@@ -357,7 +357,7 @@ const _ = class {
|
|
|
357
357
|
}
|
|
358
358
|
const g = Array.isArray(i.lods) ? (o = i.lods[t]) == null ? void 0 : o.path : i.lods;
|
|
359
359
|
if (!g)
|
|
360
|
-
return
|
|
360
|
+
return O && !i["missing:uri"] && (i["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + t, i)), null;
|
|
361
361
|
const f = Te(s.url, g);
|
|
362
362
|
if (f.endsWith(".glb") || f.endsWith(".gltf")) {
|
|
363
363
|
if (!i.guid)
|
|
@@ -365,14 +365,14 @@ const _ = class {
|
|
|
365
365
|
const m = f + "_" + i.guid, D = this.previouslyLoaded.get(m);
|
|
366
366
|
if (D !== void 0) {
|
|
367
367
|
r && console.log(`LOD ${t} was already loading/loaded: ${m}`);
|
|
368
|
-
let
|
|
368
|
+
let x = await D.catch((z) => (console.error(`Error loading LOD ${t} from ${f}
|
|
369
369
|
`, z), null)), T = !1;
|
|
370
|
-
if (
|
|
371
|
-
return
|
|
370
|
+
if (x == null || (x instanceof N && e instanceof N ? (a = x.image) != null && a.data || (h = x.source) != null && h.data ? x = this.copySettings(e, x) : (T = !0, this.previouslyLoaded.delete(m)) : x instanceof Y && e instanceof Y && ((d = x.attributes.position) != null && d.array || (T = !0, this.previouslyLoaded.delete(m)))), !T)
|
|
371
|
+
return x;
|
|
372
372
|
}
|
|
373
|
-
const M = i,
|
|
373
|
+
const M = i, w = new Promise(async (x, T) => {
|
|
374
374
|
const z = new Se();
|
|
375
|
-
ge(z),
|
|
375
|
+
ge(z), O && (await new Promise((p) => setTimeout(p, 1e3)), r && console.warn("Start loading (delayed) " + f, M.guid));
|
|
376
376
|
let ee = f;
|
|
377
377
|
if (M && Array.isArray(M.lods)) {
|
|
378
378
|
const p = M.lods[t];
|
|
@@ -389,8 +389,8 @@ const _ = class {
|
|
|
389
389
|
let p = !1;
|
|
390
390
|
for (const u of E.parser.json.textures) {
|
|
391
391
|
if (u != null && u.extensions) {
|
|
392
|
-
const
|
|
393
|
-
if (
|
|
392
|
+
const L = u == null ? void 0 : u.extensions[B];
|
|
393
|
+
if (L != null && L.guid && L.guid === M.guid) {
|
|
394
394
|
p = !0;
|
|
395
395
|
break;
|
|
396
396
|
}
|
|
@@ -399,16 +399,16 @@ const _ = class {
|
|
|
399
399
|
}
|
|
400
400
|
if (p) {
|
|
401
401
|
let u = await te.getDependency("texture", y);
|
|
402
|
-
return u && _.assignLODInformation(s.url, u, n, t, void 0, void 0), r && console.log('change "' + e.name + '" → "' + u.name + '"', f, y, u, m), e instanceof N && (u = this.copySettings(e, u)), u && (u.guid = M.guid),
|
|
402
|
+
return u && _.assignLODInformation(s.url, u, n, t, void 0, void 0), r && console.log('change "' + e.name + '" → "' + u.name + '"', f, y, u, m), e instanceof N && (u = this.copySettings(e, u)), u && (u.guid = M.guid), x(u);
|
|
403
403
|
} else
|
|
404
|
-
|
|
404
|
+
O && console.warn("Could not find texture with guid", M.guid);
|
|
405
405
|
}
|
|
406
406
|
if (y = 0, E.parser.json.meshes) {
|
|
407
407
|
let p = !1;
|
|
408
408
|
for (const u of E.parser.json.meshes) {
|
|
409
409
|
if (u != null && u.extensions) {
|
|
410
|
-
const
|
|
411
|
-
if (
|
|
410
|
+
const L = u == null ? void 0 : u.extensions[B];
|
|
411
|
+
if (L != null && L.guid && L.guid === M.guid) {
|
|
412
412
|
p = !0;
|
|
413
413
|
break;
|
|
414
414
|
}
|
|
@@ -416,33 +416,33 @@ const _ = class {
|
|
|
416
416
|
y++;
|
|
417
417
|
}
|
|
418
418
|
if (p) {
|
|
419
|
-
const u = await te.getDependency("mesh", y),
|
|
419
|
+
const u = await te.getDependency("mesh", y), L = M;
|
|
420
420
|
if (r && console.log(`Loaded Mesh "${u.name}"`, f, y, u, m), u.isMesh === !0) {
|
|
421
421
|
const S = u.geometry;
|
|
422
|
-
return _.assignLODInformation(s.url, S, n, t, void 0,
|
|
422
|
+
return _.assignLODInformation(s.url, S, n, t, void 0, L.density), x(S);
|
|
423
423
|
} else {
|
|
424
424
|
const S = new Array();
|
|
425
425
|
for (let C = 0; C < u.children.length; C++) {
|
|
426
426
|
const G = u.children[C];
|
|
427
427
|
if (G instanceof F) {
|
|
428
428
|
const $ = G.geometry;
|
|
429
|
-
_.assignLODInformation(s.url, $, n, t, C,
|
|
429
|
+
_.assignLODInformation(s.url, $, n, t, C, L.density), S.push($);
|
|
430
430
|
}
|
|
431
431
|
}
|
|
432
|
-
return
|
|
432
|
+
return x(S);
|
|
433
433
|
}
|
|
434
434
|
}
|
|
435
435
|
}
|
|
436
|
-
return
|
|
436
|
+
return x(null);
|
|
437
437
|
});
|
|
438
|
-
return this.previouslyLoaded.set(m,
|
|
438
|
+
return this.previouslyLoaded.set(m, w), await w;
|
|
439
439
|
} else if (e instanceof N) {
|
|
440
440
|
r && console.log("Load texture from uri: " + f);
|
|
441
|
-
const D = await new
|
|
442
|
-
return D ? (D.guid = i.guid, D.flipY = !1, D.needsUpdate = !0, D.colorSpace = e.colorSpace, r && console.log(i, D)) :
|
|
441
|
+
const D = await new Oe().loadAsync(f);
|
|
442
|
+
return D ? (D.guid = i.guid, D.flipY = !1, D.needsUpdate = !0, D.colorSpace = e.colorSpace, r && console.log(i, D)) : O && console.warn("failed loading", f), D;
|
|
443
443
|
}
|
|
444
444
|
} else
|
|
445
|
-
|
|
445
|
+
O && console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`, e.type);
|
|
446
446
|
return null;
|
|
447
447
|
}
|
|
448
448
|
static assignLODInformation(e, t, r, s, n, i) {
|
|
@@ -458,7 +458,7 @@ const _ = class {
|
|
|
458
458
|
}
|
|
459
459
|
// private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
|
|
460
460
|
static copySettings(e, t) {
|
|
461
|
-
return t = t.clone(),
|
|
461
|
+
return t = t.clone(), O && console.warn(`Copying texture settings
|
|
462
462
|
`, e.uuid, `
|
|
463
463
|
`, t.uuid), t.offset = e.offset, t.repeat = e.repeat, t.colorSpace = e.colorSpace, t.magFilter = e.magFilter, t.minFilter = e.minFilter, t.wrapS = e.wrapS, t.wrapT = e.wrapT, t.flipY = e.flipY, t.anisotropy = e.anisotropy, t.mipmaps || (t.generateMipmaps = e.generateMipmaps), t;
|
|
464
464
|
}
|
|
@@ -468,7 +468,11 @@ let v = _;
|
|
|
468
468
|
* Register a texture with LOD information
|
|
469
469
|
*/
|
|
470
470
|
c(v, "registerTexture", (e, t, r, s, n) => {
|
|
471
|
-
|
|
471
|
+
if (O && console.log("> Progressive: register texture", s, t.name, t.uuid, t, n), !t) {
|
|
472
|
+
O && console.error("gltf-progressive: Register texture without texture");
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
t.source && (t.source[se] = n);
|
|
472
476
|
const i = n.guid;
|
|
473
477
|
_.assignLODInformation(e, t, i, r, s, void 0), _.lodInfos.set(i, n), _.lowresCache.set(i, t);
|
|
474
478
|
}), /**
|
|
@@ -476,8 +480,12 @@ c(v, "registerTexture", (e, t, r, s, n) => {
|
|
|
476
480
|
*/
|
|
477
481
|
c(v, "registerMesh", (e, t, r, s, n, i) => {
|
|
478
482
|
var h;
|
|
479
|
-
|
|
483
|
+
O && console.log("> Progressive: register mesh", n, r.name, i, r.uuid, r);
|
|
480
484
|
const o = r.geometry;
|
|
485
|
+
if (!o) {
|
|
486
|
+
O && console.warn("gltf-progressive: Register mesh without geometry");
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
481
489
|
o.userData || (o.userData = {}), _.assignLODInformation(e, o, t, s, n, i.density), _.lodInfos.set(t, i);
|
|
482
490
|
let a = _.lowresCache.get(t);
|
|
483
491
|
a ? a.push(r.geometry) : a = [r.geometry], _.lowresCache.set(t, a), s > 0 && !ae(r) && be(r, o);
|
|
@@ -526,9 +534,9 @@ const U = j("debugprogressive"), Ce = j("noprogressive"), fe = Symbol("Needle:LO
|
|
|
526
534
|
c(this, "_tempBox", new ce());
|
|
527
535
|
c(this, "_tempBox2", new ce());
|
|
528
536
|
c(this, "tempMatrix", new le());
|
|
529
|
-
c(this, "_tempWorldPosition", new
|
|
530
|
-
c(this, "_tempBoxSize", new
|
|
531
|
-
c(this, "_tempBox2Size", new
|
|
537
|
+
c(this, "_tempWorldPosition", new k());
|
|
538
|
+
c(this, "_tempBoxSize", new k());
|
|
539
|
+
c(this, "_tempBox2Size", new k());
|
|
532
540
|
this.renderer = e;
|
|
533
541
|
}
|
|
534
542
|
/** @internal */
|
|
@@ -619,7 +627,7 @@ const U = j("debugprogressive"), Ce = j("noprogressive"), fe = Symbol("Needle:LO
|
|
|
619
627
|
var a, h;
|
|
620
628
|
r.userData || (r.userData = {});
|
|
621
629
|
let i = r.userData.LOD_state;
|
|
622
|
-
if (i || (i = new
|
|
630
|
+
if (i || (i = new Re(), r.userData.LOD_state = i), i.frames++ < 2)
|
|
623
631
|
return;
|
|
624
632
|
for (const d of I)
|
|
625
633
|
(a = d.onBeforeUpdateLOD) == null || a.call(d, this.renderer, e, t, r);
|
|
@@ -709,25 +717,25 @@ const U = j("debugprogressive"), Ce = j("noprogressive"), fe = Symbol("Needle:LO
|
|
|
709
717
|
}
|
|
710
718
|
if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && M.fov > 70) {
|
|
711
719
|
const y = this._tempBox.min, p = this._tempBox.max;
|
|
712
|
-
let u = y.x,
|
|
720
|
+
let u = y.x, L = y.y, S = p.x, C = p.y;
|
|
713
721
|
const G = 2, $ = 1.5, H = (y.x + p.x) * 0.5, J = (y.y + p.y) * 0.5;
|
|
714
|
-
u = (u - H) * G + H,
|
|
715
|
-
const pe = u < 0 && S > 0 ? 0 : Math.min(Math.abs(y.x), Math.abs(p.x)), ye =
|
|
722
|
+
u = (u - H) * G + H, L = (L - J) * G + J, S = (S - H) * G + H, C = (C - J) * G + J;
|
|
723
|
+
const pe = u < 0 && S > 0 ? 0 : Math.min(Math.abs(y.x), Math.abs(p.x)), ye = L < 0 && C > 0 ? 0 : Math.min(Math.abs(y.y), Math.abs(p.y)), re = Math.max(pe, ye);
|
|
716
724
|
r.lastCentrality = ($ - re) * ($ - re) * ($ - re);
|
|
717
725
|
} else
|
|
718
726
|
r.lastCentrality = 1;
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
const T =
|
|
724
|
-
if (Math.max(
|
|
727
|
+
const w = this._tempBox.getSize(this._tempBoxSize);
|
|
728
|
+
w.multiplyScalar(0.5), screen.availHeight > 0 && w.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), w.x *= M.aspect;
|
|
729
|
+
const R = e.matrixWorldInverse, x = this._tempBox2;
|
|
730
|
+
x.copy(m), x.applyMatrix4(t.matrixWorld), x.applyMatrix4(R);
|
|
731
|
+
const T = x.getSize(this._tempBox2Size), z = Math.max(T.x, T.y);
|
|
732
|
+
if (Math.max(w.x, w.y) != 0 && z != 0 && (w.z = T.z / Math.max(T.x, T.y) * Math.max(w.x, w.y)), r.lastScreenCoverage = Math.max(w.x, w.y, w.z), r.lastScreenspaceVolume.copy(w), r.lastScreenCoverage *= r.lastCentrality, U && A.debugDrawLine) {
|
|
725
733
|
const y = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
726
734
|
y.invert();
|
|
727
|
-
const p = A.corner0, u = A.corner1,
|
|
728
|
-
p.copy(this._tempBox.min), u.copy(this._tempBox.max), u.x = p.x,
|
|
735
|
+
const p = A.corner0, u = A.corner1, L = A.corner2, S = A.corner3;
|
|
736
|
+
p.copy(this._tempBox.min), u.copy(this._tempBox.max), u.x = p.x, L.copy(this._tempBox.max), L.y = p.y, S.copy(this._tempBox.max);
|
|
729
737
|
const C = (p.z + S.z) * 0.5;
|
|
730
|
-
p.z = u.z =
|
|
738
|
+
p.z = u.z = L.z = S.z = C, p.applyMatrix4(y), u.applyMatrix4(y), L.applyMatrix4(y), S.applyMatrix4(y), A.debugDrawLine(p, u, 255), A.debugDrawLine(p, L, 255), A.debugDrawLine(u, S, 255), A.debugDrawLine(L, S, 255);
|
|
731
739
|
}
|
|
732
740
|
let E = 999;
|
|
733
741
|
if (h && r.lastScreenCoverage > 0) {
|
|
@@ -746,11 +754,11 @@ const U = j("debugprogressive"), Ce = j("noprogressive"), fe = Symbol("Needle:LO
|
|
|
746
754
|
U && console.log(`First Texture LOD ${n.texture_lod} (${M.max_height}px) - ${t.name}`);
|
|
747
755
|
}
|
|
748
756
|
} else {
|
|
749
|
-
const M = r.lastScreenCoverage * 1.5,
|
|
750
|
-
for (let
|
|
751
|
-
const T = g.lods[
|
|
752
|
-
if (!(Ae() && T.max_height > 4096) && T.max_height >
|
|
753
|
-
n.texture_lod =
|
|
757
|
+
const M = r.lastScreenCoverage * 1.5, R = this.renderer.domElement.clientHeight / window.devicePixelRatio * M;
|
|
758
|
+
for (let x = g.lods.length - 1; x >= 0; x--) {
|
|
759
|
+
const T = g.lods[x];
|
|
760
|
+
if (!(Ae() && T.max_height > 4096) && T.max_height > R) {
|
|
761
|
+
n.texture_lod = x, n.texture_lod < r.lastLodLevel_Texture && U && console.log(`Texture LOD changed ${r.lastLodLevel_Texture} → ${n.texture_lod} (${T.max_height}px: ${(100 * r.lastScreenCoverage).toFixed(2)} % = ${R.toFixed(0)}px) - ${t.name}`);
|
|
754
762
|
break;
|
|
755
763
|
}
|
|
756
764
|
}
|
|
@@ -762,19 +770,19 @@ const U = j("debugprogressive"), Ce = j("noprogressive"), fe = Symbol("Needle:LO
|
|
|
762
770
|
let P = A;
|
|
763
771
|
/** 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.
|
|
764
772
|
*/
|
|
765
|
-
c(P, "debugDrawLine"), c(P, "corner0", new
|
|
766
|
-
class
|
|
773
|
+
c(P, "debugDrawLine"), c(P, "corner0", new k()), c(P, "corner1", new k()), c(P, "corner2", new k()), c(P, "corner3", new k()), c(P, "_tempPtInside", new k());
|
|
774
|
+
class Re {
|
|
767
775
|
constructor() {
|
|
768
776
|
c(this, "frames", 0);
|
|
769
777
|
c(this, "lastLodLevel_Mesh", -1);
|
|
770
778
|
c(this, "lastLodLevel_Texture", -1);
|
|
771
779
|
c(this, "lastScreenCoverage", 0);
|
|
772
|
-
c(this, "lastScreenspaceVolume", new
|
|
780
|
+
c(this, "lastScreenspaceVolume", new k());
|
|
773
781
|
c(this, "lastCentrality", 0);
|
|
774
782
|
}
|
|
775
783
|
}
|
|
776
784
|
const de = Symbol("NEEDLE_mesh_lod"), Q = Symbol("NEEDLE_texture_lod");
|
|
777
|
-
function
|
|
785
|
+
function ke(l) {
|
|
778
786
|
if (!l)
|
|
779
787
|
return null;
|
|
780
788
|
let e = null, t = null;
|
|
@@ -785,7 +793,7 @@ function Be(l) {
|
|
|
785
793
|
if (e) {
|
|
786
794
|
console.log("Adding Needle LODs to modelviewer");
|
|
787
795
|
const r = P.get(e);
|
|
788
|
-
if (P.addPlugin(new
|
|
796
|
+
if (P.addPlugin(new Be(l)), r.enable(), t) {
|
|
789
797
|
const s = t.camera || t.traverse((n) => n.type == "PerspectiveCamera")[0];
|
|
790
798
|
s && e.render(t, s);
|
|
791
799
|
}
|
|
@@ -795,7 +803,7 @@ function Be(l) {
|
|
|
795
803
|
}
|
|
796
804
|
return null;
|
|
797
805
|
}
|
|
798
|
-
class
|
|
806
|
+
class Be {
|
|
799
807
|
constructor(e) {
|
|
800
808
|
c(this, "modelviewer");
|
|
801
809
|
c(this, "_didWarnAboutMissingUrl", !1);
|
|
@@ -826,14 +834,14 @@ class Re {
|
|
|
826
834
|
for (let f = 0; f < a.length; f++) {
|
|
827
835
|
const m = a[f], D = o[m];
|
|
828
836
|
if ((D == null ? void 0 : D.isTexture) === !0) {
|
|
829
|
-
const M = (d = (h = D.userData) == null ? void 0 : h.associations) == null ? void 0 : d.textures,
|
|
830
|
-
if (!
|
|
837
|
+
const M = (d = (h = D.userData) == null ? void 0 : h.associations) == null ? void 0 : d.textures, w = r.parser.json.textures[M];
|
|
838
|
+
if (!w) {
|
|
831
839
|
console.warn("Texture data not found for texture index " + M);
|
|
832
840
|
continue;
|
|
833
841
|
}
|
|
834
|
-
if ((g =
|
|
835
|
-
const
|
|
836
|
-
|
|
842
|
+
if ((g = w == null ? void 0 : w.extensions) != null && g[B]) {
|
|
843
|
+
const R = w.extensions[B];
|
|
844
|
+
R && s && v.registerTexture(s, D, R.lods.length, M, R);
|
|
837
845
|
}
|
|
838
846
|
}
|
|
839
847
|
}
|
|
@@ -854,7 +862,7 @@ class Re {
|
|
|
854
862
|
const r = this.getUrl();
|
|
855
863
|
if (!r)
|
|
856
864
|
return;
|
|
857
|
-
const s = (i = (n = t.userData) == null ? void 0 : n.gltfExtensions) == null ? void 0 : i[
|
|
865
|
+
const s = (i = (n = t.userData) == null ? void 0 : n.gltfExtensions) == null ? void 0 : i[B];
|
|
858
866
|
if (s && r) {
|
|
859
867
|
const o = t.uuid;
|
|
860
868
|
v.registerMesh(r, o, t, 0, s.lods.length, s);
|
|
@@ -867,16 +875,16 @@ function qe(l, e, t, r) {
|
|
|
867
875
|
return (r == null ? void 0 : r.enableLODsManager) !== !1 && s.enable(), s;
|
|
868
876
|
}
|
|
869
877
|
document.addEventListener("DOMContentLoaded", () => {
|
|
870
|
-
|
|
878
|
+
ke(document.querySelector("model-viewer"));
|
|
871
879
|
});
|
|
872
880
|
export {
|
|
873
|
-
|
|
881
|
+
B as EXTENSION_NAME,
|
|
874
882
|
P as LODsManager,
|
|
875
883
|
v as NEEDLE_progressive,
|
|
876
884
|
ge as addDracoAndKTX2Loaders,
|
|
877
885
|
he as createLoaders,
|
|
878
886
|
ae as getRaycastMesh,
|
|
879
|
-
|
|
887
|
+
ke as patchModelViewer,
|
|
880
888
|
Ne as setDracoDecoderLocation,
|
|
881
889
|
We as setKTX2TranscoderLocation,
|
|
882
890
|
be as setRaycastMesh,
|
package/gltf-progressive.min.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
var me=Object.defineProperty,pe=(t,e,r)=>e in t?me(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,c=(t,e,r)=>(pe(t,typeof e!="symbol"?e+"":e,r),r);import{MeshoptDecoder as xe}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as ye}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as ve}from"three/examples/jsm/loaders/KTX2Loader.js";import{BufferGeometry as $,Mesh as G,Material as
|
|
2
|
-
`,N),null)),b=!1;if(p==null||(p instanceof z&&t instanceof z?(n=p.image)!=null&&n.data||(o=p.source)!=null&&o.data?p=this.copySettings(t,p):(b=!0,this.previouslyLoaded.delete(f)):p instanceof $&&t instanceof $&&((s=p.attributes.position)!=null&&s.array||(b=!0,this.previouslyLoaded.delete(f)))),!b)return p}const m=l,S=new Promise(async(p,b)=>{const N=new
|
|
3
|
-
`,y),null));if(!x)return null;const
|
|
1
|
+
var me=Object.defineProperty,pe=(t,e,r)=>e in t?me(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,c=(t,e,r)=>(pe(t,typeof e!="symbol"?e+"":e,r),r);import{MeshoptDecoder as xe}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as ye}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as ve}from"three/examples/jsm/loaders/KTX2Loader.js";import{BufferGeometry as $,Mesh as G,Material as Le,Texture as z,TextureLoader as De,Matrix4 as ie,Frustum as Me,Sphere as _e,Box3 as ae,Vector3 as B}from"three";import{GLTFLoader as Oe}from"three/examples/jsm/loaders/GLTFLoader.js";let X="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ee="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(X+"draco_decoder.js",{method:"head"}).catch(t=>{X="./include/draco/",ee="./include/ktx2/"});function we(t){X=t}function be(t){ee=t}let U,te,q;function re(t){U||(U=new ye,U.setDecoderPath(X),U.setDecoderConfig({type:"js"})),q||(q=new ve,q.setTranscoderPath(ee)),te||(te=xe),t?q.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function se(t){t.dracoLoader||t.setDRACOLoader(U),t.ktx2Loader||t.setKTX2Loader(q),t.meshoptDecoder||t.setMeshoptDecoder(te)}function H(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Se(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const r=t.lastIndexOf("/");if(r>=0){const n=t.substring(0,r+1);for(;n.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return n+e}return e}let Y;function Te(){return Y!==void 0||(Y=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),H("debugprogressive")&&console.log("isMobileDevice",Y)),Y}function J(t){var e;return((e=t?.userData)==null?void 0:e["needle:raycast-mesh"])instanceof $?t.userData["needle:raycast-mesh"]:null}function le(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!J(t)){const r=Ae(e);r.userData={isRaycastMesh:!0},t.userData||(t.userData={}),t.userData["needle:raycast-mesh"]=r}}function Ee(t=!0){if(t){if(V)return;const e=V=G.prototype.raycast;G.prototype.raycast=function(r,n){const o=this,s=J(o);let a;s&&o.isMesh&&(a=o.geometry,o.geometry=s),e.call(this,r,n),a&&(o.geometry=a)}}else{if(!V)return;G.prototype.raycast=V,V=null}}let V=null;function Ae(t){const e=new $;for(const r in t.attributes)e.setAttribute(r,t.getAttribute(r));return e.setIndex(t.getIndex()),e}const R=new Array,P="NEEDLE_progressive",v=H("debugprogressive"),oe=Symbol("needle-progressive-texture"),K=new Map,ne=new Set;if(v){let t=function(){e+=1,console.log("Toggle LOD level",e,K),K.forEach((o,s)=>{for(const a of o.keys){const i=s[a];if(i.isBufferGeometry===!0){const u=O.getMeshLODInformation(i),l=u?Math.min(e,u.lods.length):0;s["DEBUG:LOD"]=e,O.assignMeshLOD(s,l),u&&(r=Math.max(r,u.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,O.assignTextureLOD(s,e);break}}}),e>=r&&(e=-1)},e=-1,r=2,n=!1;window.addEventListener("keyup",o=>{o.key==="p"&&t(),o.key==="w"&&(n=!n,ne&&ne.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=n)}))})}function ue(t,e,r){var n;if(!v)return;K.has(t)||K.set(t,{keys:[],sourceId:r});const o=K.get(t);((n=o?.keys)==null?void 0:n.includes(e))==!1&&o.keys.push(e)}const M=class{constructor(t,e){c(this,"parser"),c(this,"url"),c(this,"_isLoadingMesh"),c(this,"loadMesh",r=>{var n,o;if(this._isLoadingMesh)return null;const s=(o=(n=this.parser.json.meshes[r])==null?void 0:n.extensions)==null?void 0:o[P];return s?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",r).then(a=>(this._isLoadingMesh=!1,a&&M.registerMesh(this.url,s.guid,a,s.lods.length,void 0,s),a))):null}),v&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return P}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const r=this,n="LODS:minmax",o=t[n];if(o!=null)return o;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const a of t)this.getMaterialMinMaxLODsCount(a,e);return t[n]=e,e}if(v==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const a=t;for(const i of Object.keys(a.uniforms)){const u=a.uniforms[i].value;u?.isTexture===!0&&s(u,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const i=t[a];i?.isTexture===!0&&s(i,e)}return t[n]=e,e;function s(a,i){const u=r.getAssignedLODInformation(a);if(u){const l=r.lodInfos.get(u.key);if(l&&l.lods){i.min_count=Math.min(i.min_count,l.lods.length),i.max_count=Math.max(i.max_count,l.lods.length);for(let g=0;g<l.lods.length;g++){const d=l.lods[g];d.width&&(i.lods[g]=i.lods[g]||{min_height:1/0,max_height:0},i.lods[g].min_height=Math.min(i.lods[g].min_height,d.height),i.lods[g].max_height=Math.max(i.lods[g].max_height,d.height))}}}}}static hasLODLevelAvailable(t,e){var r;if(Array.isArray(t)){for(const s of t)if(this.hasLODLevelAvailable(s,e))return!0;return!1}if(t.isMaterial===!0){for(const s of Object.keys(t)){const a=t[s];if(a&&a.isTexture&&this.hasLODLevelAvailable(a,e))return!0}return!1}else if(t.isGroup===!0){for(const s of t.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let n,o;if(t.isMesh?n=t.geometry:(t.isBufferGeometry||t.isTexture)&&(n=t),n&&(r=n?.userData)!=null&&r.LODS){const s=n.userData.LODS;if(o=this.lodInfos.get(s.key),e===void 0)return o!=null;if(o)return Array.isArray(o.lods)?e<o.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof G||t.isMesh===!0){const n=t.geometry,o=this.getAssignedLODInformation(n);if(!o)return Promise.resolve(null);for(const s of R)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,M.getOrLoadLOD(n,e).then(s=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(s)){const a=o.index||0;s=s[a]}s&&n!=s&&s instanceof $&&(t.geometry=s,v&&ue(t,"geometry",o.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",t,s),null))}else v&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof Le||t.isMaterial===!0){const r=t,n=[],o=new Array;if(v&&ne.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const a of Object.keys(s.uniforms)){const i=s.uniforms[a].value;if(i?.isTexture===!0){const u=this.assignTextureLODForSlot(i,e,r,a);n.push(u),o.push(a)}}}else for(const s of Object.keys(r)){const a=r[s];if(a?.isTexture===!0){const i=this.assignTextureLODForSlot(a,e,r,s);n.push(i),o.push(s)}}return Promise.all(n).then(s=>{const a=new Array;for(let i=0;i<s.length;i++){const u=s[i],l=o[i];u&&u.isTexture===!0?a.push({material:r,slot:l,texture:u,level:e}):a.push({material:r,slot:l,texture:null,level:e})}return a})}if(t instanceof z||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,n){return t?.isTexture!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):M.getOrLoadLOD(t,e).then(o=>{if(Array.isArray(o))return null;if(o?.isTexture===!0){if(o!=t){if(r&&n){const s=r[n];if(s){const a=this.getAssignedLODInformation(s);if(a&&a?.level<e)return v==="verbose"&&console.warn("Assigned texture level is already higher: ",a.level,e,r,s,o),null}r[n]=o}if(v&&n&&r){const s=this.getAssignedLODInformation(t);s&&ue(r,n,s.url)}}return o}else v=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(o=>(console.error("Error loading LOD",t,o),null))}afterRoot(t){var e,r;return v&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[P];if(s){let a=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i).textures===o&&(a=!0,M.registerTexture(this.url,i,s.lods.length,o,s));a||this.parser.getDependency("texture",o).then(i=>{i&&M.registerTexture(this.url,i,s.lods.length,o,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[P];if(s&&s.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const i=this.parser.associations.get(a);i.meshes===o&&M.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(t,e){var r,n,o,s;const a=v=="verbose",i=t.userData.LODS;if(!i)return null;const u=i?.key;let l;if(t.isTexture===!0){const g=t;g.source&&g.source[oe]&&(l=g.source[oe])}if(l||(l=M.lodInfos.get(u)),l){if(e>0){let f=!1;const w=Array.isArray(l.lods);if(w&&e>=l.lods.length?f=!0:w||(f=!0),f)return this.lowresCache.get(u)}const g=Array.isArray(l.lods)?(r=l.lods[e])==null?void 0:r.path:l.lods;if(!g)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const d=Se(i.url,g);if(d.endsWith(".glb")||d.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const f=d+"_"+l.guid,w=this.previouslyLoaded.get(f);if(w!==void 0){a&&console.log(`LOD ${e} was already loading/loaded: ${f}`);let p=await w.catch(N=>(console.error(`Error loading LOD ${e} from ${d}
|
|
2
|
+
`,N),null)),b=!1;if(p==null||(p instanceof z&&t instanceof z?(n=p.image)!=null&&n.data||(o=p.source)!=null&&o.data?p=this.copySettings(t,p):(b=!0,this.previouslyLoaded.delete(f)):p instanceof $&&t instanceof $&&((s=p.attributes.position)!=null&&s.array||(b=!0,this.previouslyLoaded.delete(f)))),!b)return p}const m=l,S=new Promise(async(p,b)=>{const N=new Oe;se(N),v&&(await new Promise(y=>setTimeout(y,1e3)),a&&console.warn("Start loading (delayed) "+d,m.guid));let F=d;if(m&&Array.isArray(m.lods)){const y=m.lods[e];y.hash&&(F+="?v="+y.hash)}const x=await N.loadAsync(F).catch(y=>(console.error(`Error loading LOD ${e} from ${d}
|
|
3
|
+
`,y),null));if(!x)return null;const L=x.parser;a&&console.log("Loading finished "+d,m.guid);let D=0;if(x.parser.json.textures){let y=!1;for(const h of x.parser.json.textures){if(h!=null&&h.extensions){const _=h?.extensions[P];if(_!=null&&_.guid&&_.guid===m.guid){y=!0;break}}D++}if(y){let h=await L.getDependency("texture",D);return h&&M.assignLODInformation(i.url,h,u,e,void 0,void 0),a&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',d,D,h,f),t instanceof z&&(h=this.copySettings(t,h)),h&&(h.guid=m.guid),p(h)}else v&&console.warn("Could not find texture with guid",m.guid)}if(D=0,x.parser.json.meshes){let y=!1;for(const h of x.parser.json.meshes){if(h!=null&&h.extensions){const _=h?.extensions[P];if(_!=null&&_.guid&&_.guid===m.guid){y=!0;break}}D++}if(y){const h=await L.getDependency("mesh",D),_=m;if(a&&console.log(`Loaded Mesh "${h.name}"`,d,D,h,f),h.isMesh===!0){const A=h.geometry;return M.assignLODInformation(i.url,A,u,e,void 0,_.density),p(A)}else{const A=new Array;for(let C=0;C<h.children.length;C++){const k=h.children[C];if(k instanceof G){const j=k.geometry;M.assignLODInformation(i.url,j,u,e,C,_.density),A.push(j)}}return p(A)}}}return p(null)});return this.previouslyLoaded.set(f,S),await S}else if(t instanceof z){a&&console.log("Load texture from uri: "+d);const f=await new De().loadAsync(d);return f?(f.guid=l.guid,f.flipY=!1,f.needsUpdate=!0,f.colorSpace=t.colorSpace,a&&console.log(l,f)):v&&console.warn("failed loading",d),f}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,n,o,s){if(!e)return;e.userData||(e.userData={});const a=new Pe(t,r,n,o,s);e.userData.LODS=a,e.userData.LOD=n}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),v&&console.warn(`Copying texture settings
|
|
4
4
|
`,t.uuid,`
|
|
5
|
-
`,e.uuid),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}};let _=M;c(_,"registerTexture",(t,e,r,n,o)=>{v&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,o),e.source&&(e.source[oe]=o);const s=o.guid;M.assignLODInformation(t,e,s,r,n,void 0),M.lodInfos.set(s,o),M.lowresCache.set(s,e)}),c(_,"registerMesh",(t,e,r,n,o,s)=>{var i;v&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const a=r.geometry;a.userData||(a.userData={}),M.assignLODInformation(t,a,e,n,o,s.density),M.lodInfos.set(e,s);let u=M.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],M.lowresCache.set(e,u),n>0&&!J(r)&&le(r,a);for(const l of k)(i=l.onRegisteredNewMesh)==null||i.call(l,r,s)}),c(_,"lodInfos",new Map),c(_,"previouslyLoaded",new Map),c(_,"lowresCache",new Map);class Pe{constructor(e,r,n,o,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=r,this.level=n,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const W=H("debugprogressive"),Ie=H("noprogressive"),ce=Symbol("Needle:LODSManager"),E={mesh_lod:-1,texture_lod:-1},T=class{constructor(t){c(this,"renderer"),c(this,"projectionScreenMatrix",new ie),c(this,"cameraFrustrum",new Me),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new Oe),c(this,"_tempBox",new ae),c(this,"_tempBox2",new ae),c(this,"tempMatrix",new ie),c(this,"_tempWorldPosition",new B),c(this,"_tempBoxSize",new B),c(this,"_tempBox2Size",new B),this.renderer=t}static getObjectLODState(t){var e;return(e=t.userData)==null?void 0:e.LOD_state}static addPlugin(t){k.push(t)}static removePlugin(t){const e=k.indexOf(t);e>=0&&k.splice(e,1)}static get(t){return t[ce]?t[ce]:new T(t)}get plugins(){return k}enable(){if(this._originalRender)return;let t=0;this._originalRender=this.renderer.render;const e=this;re(this.renderer),this.renderer.render=function(r,n){e.renderer.getRenderTarget()==null&&(t=0,e._frame+=1);const o=e._frame,s=t++;e.onBeforeRender(r,n,s,o),e._originalRender.call(this,r,n),e.onAfterRender(r,n,s,o)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,n){}onAfterRender(t,e,r,n){var o,s;if(this.pause)return;const i=this.renderer.renderLists.get(t,0),a=i.opaque;let u=!0;if(a.length===1){const l=a[0].material;(l.name==="EffectMaterial"||l.name==="CopyShader")&&(u=!1)}if(e.parent&&e.parent.type==="CubeCamera"&&(u=!1),u){if(Ie||this.updateInterval>0&&n%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const l=this.targetTriangleDensity;for(const d of a){if(d.material&&(((o=d.geometry)==null?void 0:o.type)==="BoxGeometry"||((s=d.geometry)==null?void 0:s.type)==="BufferGeometry")&&(d.material.name==="SphericalGaussianBlur"||d.material.name=="BackgroundCubeMaterial"||d.material.name==="CubemapFromEquirect"||d.material.name==="EquirectangularToCubeUV")){W&&(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",d,d.material.name,d.material.type)));continue}switch(d.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const f=d.object;(f instanceof G||f.isMesh)&&this.updateLODs(t,e,f,l,n)}const g=i.transparent;for(const d of g){const f=d.object;(f instanceof G||f.isMesh)&&this.updateLODs(t,e,f,l,n)}}}updateLODs(t,e,r,n,o){var s,i;r.userData||(r.userData={});let a=r.userData.LOD_state;if(a||(a=new Be,r.userData.LOD_state=a),a.frames++<2)return;for(const l of k)(s=l.onBeforeUpdateLOD)==null||s.call(l,this.renderer,t,e,r);this.calculateLodLevel(e,r,a,n,E),E.mesh_lod=Math.round(E.mesh_lod),E.texture_lod=Math.round(E.texture_lod),E.mesh_lod>=0&&this.loadProgressiveMeshes(r,E.mesh_lod);let u=E.texture_lod;if(r.material&&u>=0){const l=r["DEBUG:LOD"];l!=null&&(u=l),this.loadProgressiveTextures(r.material,u)}for(const l of k)(i=l.onAfterUpdatedLOD)==null||i.call(l,this.renderer,t,e,r,E);a.lastLodLevel_Mesh=E.mesh_lod,a.lastLodLevel_Texture=E.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}const r=t;let n=!1;(r.NEEDLE_LOD==null||e<r.NEEDLE_LOD)&&(n=!0),n&&(r.NEEDLE_LOD=e,_.assignTextureLOD(t,e))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t.userData||(t.userData={}),t.userData.LOD!==e){t.userData.LOD=e;const r=t.geometry;return _.assignMeshLOD(t,e).then(n=>(n&&t.userData.LOD==e&&r!=t.geometry,n))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,n=t.max,o=(r.x+n.x)*.5,s=(r.y+n.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,n,o){var s;if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let i=10+1;if(W&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=_.getMeshLODInformation(e.geometry),u=a?.lods,l=u&&u.length>0,g=_.getMaterialMinMaxLODsCount(e.material),d=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!l&&!d){o.mesh_lod=0,o.texture_lod=0;return}if(l||(i=0),!((s=this.cameraFrustrum)!=null&&s.intersectsObject(e))){o.mesh_lod=99,o.texture_lod=99;return}const f=e.geometry.boundingBox;if(f&&t.isPerspectiveCamera){const w=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const x=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(x)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(e.matrixWorld),T.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&w.fov>70){const x=this._tempBox.min,D=this._tempBox.max;let L=x.x,y=x.y,h=D.x,O=D.y;const A=2,C=1.5,R=(x.x+D.x)*.5,j=(x.y+D.y)*.5;L=(L-R)*A+R,y=(y-j)*A+j,h=(h-R)*A+R,O=(O-j)*A+j;const fe=L<0&&h>0?0:Math.min(Math.abs(x.x),Math.abs(D.x)),ge=y<0&&O>0?0:Math.min(Math.abs(x.y),Math.abs(D.y)),Z=Math.max(fe,ge);r.lastCentrality=(C-Z)*(C-Z)*(C-Z)}else r.lastCentrality=1;const m=this._tempBox.getSize(this._tempBoxSize);m.multiplyScalar(.5),screen.availHeight>0&&m.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),m.x*=w.aspect;const S=t.matrixWorldInverse,p=this._tempBox2;p.copy(f),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(S);const b=p.getSize(this._tempBox2Size),N=Math.max(b.x,b.y);if(Math.max(m.x,m.y)!=0&&N!=0&&(m.z=b.z/Math.max(b.x,b.y)*Math.max(m.x,m.y)),r.lastScreenCoverage=Math.max(m.x,m.y,m.z),r.lastScreenspaceVolume.copy(m),r.lastScreenCoverage*=r.lastCentrality,W&&T.debugDrawLine){const x=this.tempMatrix.copy(this.projectionScreenMatrix);x.invert();const D=T.corner0,L=T.corner1,y=T.corner2,h=T.corner3;D.copy(this._tempBox.min),L.copy(this._tempBox.max),L.x=D.x,y.copy(this._tempBox.max),y.y=D.y,h.copy(this._tempBox.max);const O=(D.z+h.z)*.5;D.z=L.z=y.z=h.z=O,D.applyMatrix4(x),L.applyMatrix4(x),y.applyMatrix4(x),h.applyMatrix4(x),T.debugDrawLine(D,L,255),T.debugDrawLine(D,y,255),T.debugDrawLine(L,h,255),T.debugDrawLine(y,h,255)}let F=999;if(u&&r.lastScreenCoverage>0){for(let x=0;x<u.length;x++)if(u[x].density/r.lastScreenCoverage<n){F=x;break}}F<i&&(i=F)}if(o.mesh_lod=i,d)if(r.lastLodLevel_Texture<0){if(o.texture_lod=g.max_count-1,W){const w=g.lods[g.max_count-1];W&&console.log(`First Texture LOD ${o.texture_lod} (${w.max_height}px) - ${e.name}`)}}else{const w=r.lastScreenCoverage*1.5,m=this.renderer.domElement.clientHeight/window.devicePixelRatio*w;for(let S=g.lods.length-1;S>=0;S--){const p=g.lods[S];if(!(Te()&&p.max_height>4096)&&p.max_height>m){o.texture_lod=S,o.texture_lod<r.lastLodLevel_Texture&&W&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} \u2192 ${o.texture_lod} (${p.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${m.toFixed(0)}px) - ${e.name}`);break}}}else o.texture_lod=0}};let I=T;c(I,"debugDrawLine"),c(I,"corner0",new B),c(I,"corner1",new B),c(I,"corner2",new B),c(I,"corner3",new B),c(I,"_tempPtInside",new B);class Be{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",-1),c(this,"lastLodLevel_Texture",-1),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const de=Symbol("NEEDLE_mesh_lod"),Q=Symbol("NEEDLE_texture_lod");function he(t){if(!t)return null;let e=null,r=null;for(let n=t;n!=null;n=Object.getPrototypeOf(n)){const o=Object.getOwnPropertySymbols(n),s=o.find(a=>a.toString()=="Symbol(renderer)"),i=o.find(a=>a.toString()=="Symbol(scene)");!e&&s!=null&&(e=t[s].threeRenderer),!r&&i!=null&&(r=t[i])}if(e){console.log("Adding Needle LODs to modelviewer");const n=I.get(e);if(I.addPlugin(new Ce(t)),n.enable(),r){const o=r.camera||r.traverse(s=>s.type=="PerspectiveCamera")[0];o&&e.render(r,o)}return()=>{n.disable()}}return null}class Ce{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,r,n,o){this.tryParseMeshLOD(r,o),this.tryParseTextureLOD(r,o)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,r){if(r[Q]==!0)return;r[Q]=!0;const n=this.tryGetCurrentGLTF(e),o=this.getUrl();if(o&&n&&r.material){let s=function(a){var u,l,g;if(a[Q]==!0)return;a[Q]=!0,a.userData&&(a.userData.LOD=-1);const d=Object.keys(a);for(let f=0;f<d.length;f++){const w=d[f],m=a[w];if(m?.isTexture===!0){const S=(l=(u=m.userData)==null?void 0:u.associations)==null?void 0:l.textures,p=n.parser.json.textures[S];if(!p){console.warn("Texture data not found for texture index "+S);continue}if((g=p?.extensions)!=null&&g[P]){const b=p.extensions[P];b&&o&&_.registerTexture(o,m,b.lods.length,S,b)}}}};const i=r.material;if(Array.isArray(i))for(const a of i)s(a);else s(i)}}tryParseMeshLOD(e,r){var n,o;if(r[de]==!0)return;r[de]=!0;const s=this.getUrl();if(!s)return;const i=(o=(n=r.userData)==null?void 0:n.gltfExtensions)==null?void 0:o[P];if(i&&s){const a=r.uuid;_.registerMesh(s,a,r,0,i.lods.length,i)}}}function ke(t,e,r,n){re(e),se(r),r.register(s=>new _(s,t));const o=I.get(e);return n?.enableLODsManager!==!1&&o.enable(),o}document.addEventListener("DOMContentLoaded",()=>{he(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,_ as NEEDLE_progressive,se as addDracoAndKTX2Loaders,re as createLoaders,J as getRaycastMesh,he as patchModelViewer,we as setDracoDecoderLocation,be as setKTX2TranscoderLocation,le as setRaycastMesh,ke as useNeedleProgressive,Ee as useRaycastMeshes};
|
|
5
|
+
`,e.uuid),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}};let O=M;c(O,"registerTexture",(t,e,r,n,o)=>{if(v&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,o),!e){v&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[oe]=o);const s=o.guid;M.assignLODInformation(t,e,s,r,n,void 0),M.lodInfos.set(s,o),M.lowresCache.set(s,e)}),c(O,"registerMesh",(t,e,r,n,o,s)=>{var a;v&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const i=r.geometry;if(!i){v&&console.warn("gltf-progressive: Register mesh without geometry");return}i.userData||(i.userData={}),M.assignLODInformation(t,i,e,n,o,s.density),M.lodInfos.set(e,s);let u=M.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],M.lowresCache.set(e,u),n>0&&!J(r)&&le(r,i);for(const l of R)(a=l.onRegisteredNewMesh)==null||a.call(l,r,s)}),c(O,"lodInfos",new Map),c(O,"previouslyLoaded",new Map),c(O,"lowresCache",new Map);class Pe{constructor(e,r,n,o,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=r,this.level=n,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const W=H("debugprogressive"),Ie=H("noprogressive"),ce=Symbol("Needle:LODSManager"),E={mesh_lod:-1,texture_lod:-1},T=class{constructor(t){c(this,"renderer"),c(this,"projectionScreenMatrix",new ie),c(this,"cameraFrustrum",new Me),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new _e),c(this,"_tempBox",new ae),c(this,"_tempBox2",new ae),c(this,"tempMatrix",new ie),c(this,"_tempWorldPosition",new B),c(this,"_tempBoxSize",new B),c(this,"_tempBox2Size",new B),this.renderer=t}static getObjectLODState(t){var e;return(e=t.userData)==null?void 0:e.LOD_state}static addPlugin(t){R.push(t)}static removePlugin(t){const e=R.indexOf(t);e>=0&&R.splice(e,1)}static get(t){return t[ce]?t[ce]:new T(t)}get plugins(){return R}enable(){if(this._originalRender)return;let t=0;this._originalRender=this.renderer.render;const e=this;re(this.renderer),this.renderer.render=function(r,n){e.renderer.getRenderTarget()==null&&(t=0,e._frame+=1);const o=e._frame,s=t++;e.onBeforeRender(r,n,s,o),e._originalRender.call(this,r,n),e.onAfterRender(r,n,s,o)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,n){}onAfterRender(t,e,r,n){var o,s;if(this.pause)return;const a=this.renderer.renderLists.get(t,0),i=a.opaque;let u=!0;if(i.length===1){const l=i[0].material;(l.name==="EffectMaterial"||l.name==="CopyShader")&&(u=!1)}if(e.parent&&e.parent.type==="CubeCamera"&&(u=!1),u){if(Ie||this.updateInterval>0&&n%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const l=this.targetTriangleDensity;for(const d of i){if(d.material&&(((o=d.geometry)==null?void 0:o.type)==="BoxGeometry"||((s=d.geometry)==null?void 0:s.type)==="BufferGeometry")&&(d.material.name==="SphericalGaussianBlur"||d.material.name=="BackgroundCubeMaterial"||d.material.name==="CubemapFromEquirect"||d.material.name==="EquirectangularToCubeUV")){W&&(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",d,d.material.name,d.material.type)));continue}switch(d.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const f=d.object;(f instanceof G||f.isMesh)&&this.updateLODs(t,e,f,l,n)}const g=a.transparent;for(const d of g){const f=d.object;(f instanceof G||f.isMesh)&&this.updateLODs(t,e,f,l,n)}}}updateLODs(t,e,r,n,o){var s,a;r.userData||(r.userData={});let i=r.userData.LOD_state;if(i||(i=new Be,r.userData.LOD_state=i),i.frames++<2)return;for(const l of R)(s=l.onBeforeUpdateLOD)==null||s.call(l,this.renderer,t,e,r);this.calculateLodLevel(e,r,i,n,E),E.mesh_lod=Math.round(E.mesh_lod),E.texture_lod=Math.round(E.texture_lod),E.mesh_lod>=0&&this.loadProgressiveMeshes(r,E.mesh_lod);let u=E.texture_lod;if(r.material&&u>=0){const l=r["DEBUG:LOD"];l!=null&&(u=l),this.loadProgressiveTextures(r.material,u)}for(const l of R)(a=l.onAfterUpdatedLOD)==null||a.call(l,this.renderer,t,e,r,E);i.lastLodLevel_Mesh=E.mesh_lod,i.lastLodLevel_Texture=E.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}const r=t;let n=!1;(r.NEEDLE_LOD==null||e<r.NEEDLE_LOD)&&(n=!0),n&&(r.NEEDLE_LOD=e,O.assignTextureLOD(t,e))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t.userData||(t.userData={}),t.userData.LOD!==e){t.userData.LOD=e;const r=t.geometry;return O.assignMeshLOD(t,e).then(n=>(n&&t.userData.LOD==e&&r!=t.geometry,n))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,n=t.max,o=(r.x+n.x)*.5,s=(r.y+n.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,n,o){var s;if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let a=10+1;if(W&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const i=O.getMeshLODInformation(e.geometry),u=i?.lods,l=u&&u.length>0,g=O.getMaterialMinMaxLODsCount(e.material),d=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!l&&!d){o.mesh_lod=0,o.texture_lod=0;return}if(l||(a=0),!((s=this.cameraFrustrum)!=null&&s.intersectsObject(e))){o.mesh_lod=99,o.texture_lod=99;return}const f=e.geometry.boundingBox;if(f&&t.isPerspectiveCamera){const w=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const x=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(x)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(e.matrixWorld),T.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&w.fov>70){const x=this._tempBox.min,L=this._tempBox.max;let D=x.x,y=x.y,h=L.x,_=L.y;const A=2,C=1.5,k=(x.x+L.x)*.5,j=(x.y+L.y)*.5;D=(D-k)*A+k,y=(y-j)*A+j,h=(h-k)*A+k,_=(_-j)*A+j;const fe=D<0&&h>0?0:Math.min(Math.abs(x.x),Math.abs(L.x)),ge=y<0&&_>0?0:Math.min(Math.abs(x.y),Math.abs(L.y)),Z=Math.max(fe,ge);r.lastCentrality=(C-Z)*(C-Z)*(C-Z)}else r.lastCentrality=1;const m=this._tempBox.getSize(this._tempBoxSize);m.multiplyScalar(.5),screen.availHeight>0&&m.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),m.x*=w.aspect;const S=t.matrixWorldInverse,p=this._tempBox2;p.copy(f),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(S);const b=p.getSize(this._tempBox2Size),N=Math.max(b.x,b.y);if(Math.max(m.x,m.y)!=0&&N!=0&&(m.z=b.z/Math.max(b.x,b.y)*Math.max(m.x,m.y)),r.lastScreenCoverage=Math.max(m.x,m.y,m.z),r.lastScreenspaceVolume.copy(m),r.lastScreenCoverage*=r.lastCentrality,W&&T.debugDrawLine){const x=this.tempMatrix.copy(this.projectionScreenMatrix);x.invert();const L=T.corner0,D=T.corner1,y=T.corner2,h=T.corner3;L.copy(this._tempBox.min),D.copy(this._tempBox.max),D.x=L.x,y.copy(this._tempBox.max),y.y=L.y,h.copy(this._tempBox.max);const _=(L.z+h.z)*.5;L.z=D.z=y.z=h.z=_,L.applyMatrix4(x),D.applyMatrix4(x),y.applyMatrix4(x),h.applyMatrix4(x),T.debugDrawLine(L,D,255),T.debugDrawLine(L,y,255),T.debugDrawLine(D,h,255),T.debugDrawLine(y,h,255)}let F=999;if(u&&r.lastScreenCoverage>0){for(let x=0;x<u.length;x++)if(u[x].density/r.lastScreenCoverage<n){F=x;break}}F<a&&(a=F)}if(o.mesh_lod=a,d)if(r.lastLodLevel_Texture<0){if(o.texture_lod=g.max_count-1,W){const w=g.lods[g.max_count-1];W&&console.log(`First Texture LOD ${o.texture_lod} (${w.max_height}px) - ${e.name}`)}}else{const w=r.lastScreenCoverage*1.5,m=this.renderer.domElement.clientHeight/window.devicePixelRatio*w;for(let S=g.lods.length-1;S>=0;S--){const p=g.lods[S];if(!(Te()&&p.max_height>4096)&&p.max_height>m){o.texture_lod=S,o.texture_lod<r.lastLodLevel_Texture&&W&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} \u2192 ${o.texture_lod} (${p.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${m.toFixed(0)}px) - ${e.name}`);break}}}else o.texture_lod=0}};let I=T;c(I,"debugDrawLine"),c(I,"corner0",new B),c(I,"corner1",new B),c(I,"corner2",new B),c(I,"corner3",new B),c(I,"_tempPtInside",new B);class Be{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",-1),c(this,"lastLodLevel_Texture",-1),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const de=Symbol("NEEDLE_mesh_lod"),Q=Symbol("NEEDLE_texture_lod");function he(t){if(!t)return null;let e=null,r=null;for(let n=t;n!=null;n=Object.getPrototypeOf(n)){const o=Object.getOwnPropertySymbols(n),s=o.find(i=>i.toString()=="Symbol(renderer)"),a=o.find(i=>i.toString()=="Symbol(scene)");!e&&s!=null&&(e=t[s].threeRenderer),!r&&a!=null&&(r=t[a])}if(e){console.log("Adding Needle LODs to modelviewer");const n=I.get(e);if(I.addPlugin(new Ce(t)),n.enable(),r){const o=r.camera||r.traverse(s=>s.type=="PerspectiveCamera")[0];o&&e.render(r,o)}return()=>{n.disable()}}return null}class Ce{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,r,n,o){this.tryParseMeshLOD(r,o),this.tryParseTextureLOD(r,o)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,r){if(r[Q]==!0)return;r[Q]=!0;const n=this.tryGetCurrentGLTF(e),o=this.getUrl();if(o&&n&&r.material){let s=function(i){var u,l,g;if(i[Q]==!0)return;i[Q]=!0,i.userData&&(i.userData.LOD=-1);const d=Object.keys(i);for(let f=0;f<d.length;f++){const w=d[f],m=i[w];if(m?.isTexture===!0){const S=(l=(u=m.userData)==null?void 0:u.associations)==null?void 0:l.textures,p=n.parser.json.textures[S];if(!p){console.warn("Texture data not found for texture index "+S);continue}if((g=p?.extensions)!=null&&g[P]){const b=p.extensions[P];b&&o&&O.registerTexture(o,m,b.lods.length,S,b)}}}};const a=r.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,r){var n,o;if(r[de]==!0)return;r[de]=!0;const s=this.getUrl();if(!s)return;const a=(o=(n=r.userData)==null?void 0:n.gltfExtensions)==null?void 0:o[P];if(a&&s){const i=r.uuid;O.registerMesh(s,i,r,0,a.lods.length,a)}}}function Re(t,e,r,n){re(e),se(r),r.register(s=>new O(s,t));const o=I.get(e);return n?.enableLODsManager!==!1&&o.enable(),o}document.addEventListener("DOMContentLoaded",()=>{he(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,O as NEEDLE_progressive,se as addDracoAndKTX2Loaders,re as createLoaders,J as getRaycastMesh,he as patchModelViewer,we as setDracoDecoderLocation,be as setKTX2TranscoderLocation,le as setRaycastMesh,Re as useNeedleProgressive,Ee as useRaycastMeshes};
|
package/gltf-progressive.umd.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"use strict";var ge=Object.defineProperty;var pe=(l,e,t)=>e in l?ge(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var c=(l,e,t)=>(pe(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ye=require("three/examples/jsm/libs/meshopt_decoder.module.js"),Le=require("three/examples/jsm/loaders/DRACOLoader.js"),xe=require("three/examples/jsm/loaders/KTX2Loader.js"),g=require("three"),me=require("three/examples/jsm/loaders/GLTFLoader.js");let H="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ie="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(H+"draco_decoder.js",{method:"head"}).catch(l=>{H="./include/draco/",ie="./include/ktx2/"});function De(l){H=l}function Me(l){ie=l}let W,re,V;function oe(l){W||(W=new Le.DRACOLoader,W.setDecoderPath(H),W.setDecoderConfig({type:"js"})),V||(V=new xe.KTX2Loader,V.setTranscoderPath(ie)),re||(re=ye.MeshoptDecoder),l?V.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ne(l){l.dracoLoader||l.setDRACOLoader(W),l.ktx2Loader||l.setKTX2Loader(V),l.meshoptDecoder||l.setMeshoptDecoder(re)}function J(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function _e(l,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||l===void 0)return e;const t=l.lastIndexOf("/");if(t>=0){const r=l.substring(0,t+1);for(;r.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return r+e}return e}let $;function Oe(){return $!==void 0||($=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),J("debugprogressive")&&console.log("isMobileDevice",$)),$}function Q(l){var e;return((e=l==null?void 0:l.userData)==null?void 0:e["needle:raycast-mesh"])instanceof g.BufferGeometry?l.userData["needle:raycast-mesh"]:null}function ue(l,e){if((l.type==="Mesh"||l.type==="SkinnedMesh")&&!Q(l)){const r=ve(e);r.userData={isRaycastMesh:!0},l.userData||(l.userData={}),l.userData["needle:raycast-mesh"]=r}}function we(l=!0){if(l){if(U)return;const e=U=g.Mesh.prototype.raycast;g.Mesh.prototype.raycast=function(t,r){const s=this,o=Q(s);let i;o&&s.isMesh&&(i=s.geometry,s.geometry=o),e.call(this,t,r),i&&(s.geometry=i)}}else{if(!U)return;g.Mesh.prototype.raycast=U,U=null}}let U=null;function ve(l){const e=new g.BufferGeometry;for(const t in l.attributes)e.setAttribute(t,l.getAttribute(t));return e.setIndex(l.getIndex()),e}const I=new Array,
|
|
2
|
-
`,F),null)),A=!1;if(m==null||(m instanceof g.Texture&&e instanceof g.Texture?(a=m.image)!=null&&a.data||(h=m.source)!=null&&h.data?m=this.copySettings(e,m):(A=!0,this.previouslyLoaded.delete(x)):m instanceof g.BufferGeometry&&e instanceof g.BufferGeometry&&((d=m.attributes.position)!=null&&d.array||(A=!0,this.previouslyLoaded.delete(x)))),!A)return m}const _=i,O=new Promise(async(m,A)=>{const F=new me.GLTFLoader;ne(F),w&&(await new Promise(y=>setTimeout(y,1e3)),r&&console.warn("Start loading (delayed) "+f,_.guid));let Z=f;if(_&&Array.isArray(_.lods)){const y=_.lods[t];y.hash&&(Z+="?v="+y.hash)}const
|
|
3
|
-
`,y),null));if(!
|
|
1
|
+
"use strict";var ge=Object.defineProperty;var pe=(l,e,t)=>e in l?ge(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var c=(l,e,t)=>(pe(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ye=require("three/examples/jsm/libs/meshopt_decoder.module.js"),Le=require("three/examples/jsm/loaders/DRACOLoader.js"),xe=require("three/examples/jsm/loaders/KTX2Loader.js"),g=require("three"),me=require("three/examples/jsm/loaders/GLTFLoader.js");let H="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ie="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(H+"draco_decoder.js",{method:"head"}).catch(l=>{H="./include/draco/",ie="./include/ktx2/"});function De(l){H=l}function Me(l){ie=l}let W,re,V;function oe(l){W||(W=new Le.DRACOLoader,W.setDecoderPath(H),W.setDecoderConfig({type:"js"})),V||(V=new xe.KTX2Loader,V.setTranscoderPath(ie)),re||(re=ye.MeshoptDecoder),l?V.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ne(l){l.dracoLoader||l.setDRACOLoader(W),l.ktx2Loader||l.setKTX2Loader(V),l.meshoptDecoder||l.setMeshoptDecoder(re)}function J(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function _e(l,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||l===void 0)return e;const t=l.lastIndexOf("/");if(t>=0){const r=l.substring(0,t+1);for(;r.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return r+e}return e}let $;function Oe(){return $!==void 0||($=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),J("debugprogressive")&&console.log("isMobileDevice",$)),$}function Q(l){var e;return((e=l==null?void 0:l.userData)==null?void 0:e["needle:raycast-mesh"])instanceof g.BufferGeometry?l.userData["needle:raycast-mesh"]:null}function ue(l,e){if((l.type==="Mesh"||l.type==="SkinnedMesh")&&!Q(l)){const r=ve(e);r.userData={isRaycastMesh:!0},l.userData||(l.userData={}),l.userData["needle:raycast-mesh"]=r}}function we(l=!0){if(l){if(U)return;const e=U=g.Mesh.prototype.raycast;g.Mesh.prototype.raycast=function(t,r){const s=this,o=Q(s);let i;o&&s.isMesh&&(i=s.geometry,s.geometry=o),e.call(this,t,r),i&&(s.geometry=i)}}else{if(!U)return;g.Mesh.prototype.raycast=U,U=null}}let U=null;function ve(l){const e=new g.BufferGeometry;for(const t in l.attributes)e.setAttribute(t,l.getAttribute(t));return e.setIndex(l.getIndex()),e}const I=new Array,C="NEEDLE_progressive",w=J("debugprogressive"),te=Symbol("needle-progressive-texture"),q=new Map,se=new Set;if(w){let l=function(){e+=1,console.log("Toggle LOD level",e,q),q.forEach((s,o)=>{for(const i of s.keys){const n=o[i];if(n.isBufferGeometry===!0){const a=S.getMeshLODInformation(n),h=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,S.assignMeshLOD(o,h),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,S.assignTextureLOD(o,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",s=>{s.key==="p"&&l(),s.key==="w"&&(r=!r,se&&se.forEach(o=>{o.name!="BackgroundCubeMaterial"&&"wireframe"in o&&(o.wireframe=r)}))})}function ae(l,e,t){var s;if(!w)return;q.has(l)||q.set(l,{keys:[],sourceId:t});const r=q.get(l);((s=r==null?void 0:r.keys)==null?void 0:s.includes(e))==!1&&r.keys.push(e)}const v=class{constructor(e,t){c(this,"parser");c(this,"url");c(this,"_isLoadingMesh");c(this,"loadMesh",e=>{var r,s;if(this._isLoadingMesh)return null;const t=(s=(r=this.parser.json.meshes[e])==null?void 0:r.extensions)==null?void 0:s[C];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(o=>(this._isLoadingMesh=!1,o&&v.registerMesh(this.url,t.guid,o,t.lods.length,void 0,t),o))):null});w&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return C}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static getMaterialMinMaxLODsCount(e,t){const r=this,s="LODS:minmax",o=e[s];if(o!=null)return o;if(t||(t={min_count:1/0,max_count:0,lods:[]}),Array.isArray(e)){for(const n of e)this.getMaterialMinMaxLODsCount(n,t);return e[s]=t,t}if(w==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const n=e;for(const a of Object.keys(n.uniforms)){const h=n.uniforms[a].value;(h==null?void 0:h.isTexture)===!0&&i(h,t)}}else if(e.isMaterial)for(const n of Object.keys(e)){const a=e[n];(a==null?void 0:a.isTexture)===!0&&i(a,t)}return e[s]=t,t;function i(n,a){const h=r.getAssignedLODInformation(n);if(h){const d=r.lodInfos.get(h.key);if(d&&d.lods){a.min_count=Math.min(a.min_count,d.lods.length),a.max_count=Math.max(a.max_count,d.lods.length);for(let p=0;p<d.lods.length;p++){const f=d.lods[p];f.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,f.height),a.lods[p].max_height=Math.max(a.lods[p].max_height,f.height))}}}}}static hasLODLevelAvailable(e,t){var o;if(Array.isArray(e)){for(const i of e)if(this.hasLODLevelAvailable(i,t))return!0;return!1}if(e.isMaterial===!0){for(const i of Object.keys(e)){const n=e[i];if(n&&n.isTexture&&this.hasLODLevelAvailable(n,t))return!0}return!1}else if(e.isGroup===!0){for(const i of e.children)if(i.isMesh===!0&&this.hasLODLevelAvailable(i,t))return!0}let r,s;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const i=r.userData.LODS;if(s=this.lodInfos.get(i.key),t===void 0)return s!=null;if(s)return Array.isArray(s.lods)?t<s.lods.length:t===0}return!1}static assignMeshLOD(e,t){var r;if(!e)return Promise.resolve(null);if(e instanceof g.Mesh||e.isMesh===!0){const s=e.geometry,o=this.getAssignedLODInformation(s);if(!o)return Promise.resolve(null);for(const i of I)(r=i.onBeforeGetLODMesh)==null||r.call(i,e,t);return e["LOD:requested level"]=t,v.getOrLoadLOD(s,t).then(i=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(i)){const n=o.index||0;i=i[n]}i&&s!=i&&i instanceof g.BufferGeometry&&(e.geometry=i,w&&ae(e,"geometry",o.url))}return i}).catch(i=>(console.error("Error loading mesh LOD",e,i),null))}else w&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e instanceof g.Material||e.isMaterial===!0){const r=e,s=[],o=new Array;if(w&&se.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const i=r;for(const n of Object.keys(i.uniforms)){const a=i.uniforms[n].value;if((a==null?void 0:a.isTexture)===!0){const h=this.assignTextureLODForSlot(a,t,r,n);s.push(h),o.push(n)}}}else for(const i of Object.keys(r)){const n=r[i];if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,t,r,i);s.push(a),o.push(i)}}return Promise.all(s).then(i=>{const n=new Array;for(let a=0;a<i.length;a++){const h=i[a],d=o[a];h&&h.isTexture===!0?n.push({material:r,slot:d,texture:h,level:t}):n.push({material:r,slot:d,texture:null,level:t})}return n})}if(e instanceof g.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,s){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):s==="glyphMap"?Promise.resolve(e):v.getOrLoadLOD(e,t).then(o=>{if(Array.isArray(o))return null;if((o==null?void 0:o.isTexture)===!0){if(o!=e){if(r&&s){const i=r[s];if(i){const n=this.getAssignedLODInformation(i);if(n&&(n==null?void 0:n.level)<t)return w==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,t,r,i,o),null}r[s]=o}if(w&&s&&r){const i=this.getAssignedLODInformation(e);i&&ae(r,s,i.url)}}return o}else w=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(o=>(console.error("Error loading LOD",e,o),null))}afterRoot(e){var t,r;return w&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((s,o)=>{if(s!=null&&s.extensions){const i=s==null?void 0:s.extensions[C];if(i){let n=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===o&&(n=!0,v.registerTexture(this.url,a,i.lods.length,o,i));n||this.parser.getDependency("texture",o).then(a=>{a&&v.registerTexture(this.url,a,i.lods.length,o,i)})}}}),(r=this.parser.json.meshes)==null||r.forEach((s,o)=>{if(s!=null&&s.extensions){const i=s==null?void 0:s.extensions[C];if(i&&i.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const a=this.parser.associations.get(n);a.meshes===o&&v.registerMesh(this.url,i.guid,n,i.lods.length,a.primitives,i)}}}}),null}static async getOrLoadLOD(e,t){var n,a,h,d;const r=w=="verbose",s=e.userData.LODS;if(!s)return null;const o=s==null?void 0:s.key;let i;if(e.isTexture===!0){const p=e;p.source&&p.source[te]&&(i=p.source[te])}if(i||(i=v.lodInfos.get(o)),i){if(t>0){let x=!1;const M=Array.isArray(i.lods);if(M&&t>=i.lods.length?x=!0:M||(x=!0),x)return this.lowresCache.get(o)}const p=Array.isArray(i.lods)?(n=i.lods[t])==null?void 0:n.path:i.lods;if(!p)return w&&!i["missing:uri"]&&(i["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,i)),null;const f=_e(s.url,p);if(f.endsWith(".glb")||f.endsWith(".gltf")){if(!i.guid)return console.warn("missing pointer for glb/gltf texture",i),null;const x=f+"_"+i.guid,M=this.previouslyLoaded.get(x);if(M!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${x}`);let m=await M.catch(F=>(console.error(`Error loading LOD ${t} from ${f}
|
|
2
|
+
`,F),null)),A=!1;if(m==null||(m instanceof g.Texture&&e instanceof g.Texture?(a=m.image)!=null&&a.data||(h=m.source)!=null&&h.data?m=this.copySettings(e,m):(A=!0,this.previouslyLoaded.delete(x)):m instanceof g.BufferGeometry&&e instanceof g.BufferGeometry&&((d=m.attributes.position)!=null&&d.array||(A=!0,this.previouslyLoaded.delete(x)))),!A)return m}const _=i,O=new Promise(async(m,A)=>{const F=new me.GLTFLoader;ne(F),w&&(await new Promise(y=>setTimeout(y,1e3)),r&&console.warn("Start loading (delayed) "+f,_.guid));let Z=f;if(_&&Array.isArray(_.lods)){const y=_.lods[t];y.hash&&(Z+="?v="+y.hash)}const R=await F.loadAsync(Z).catch(y=>(console.error(`Error loading LOD ${t} from ${f}
|
|
3
|
+
`,y),null));if(!R)return null;const j=R.parser;r&&console.log("Loading finished "+f,_.guid);let L=0;if(R.parser.json.textures){let y=!1;for(const u of R.parser.json.textures){if(u!=null&&u.extensions){const D=u==null?void 0:u.extensions[C];if(D!=null&&D.guid&&D.guid===_.guid){y=!0;break}}L++}if(y){let u=await j.getDependency("texture",L);return u&&v.assignLODInformation(s.url,u,o,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+u.name+'"',f,L,u,x),e instanceof g.Texture&&(u=this.copySettings(e,u)),u&&(u.guid=_.guid),m(u)}else w&&console.warn("Could not find texture with guid",_.guid)}if(L=0,R.parser.json.meshes){let y=!1;for(const u of R.parser.json.meshes){if(u!=null&&u.extensions){const D=u==null?void 0:u.extensions[C];if(D!=null&&D.guid&&D.guid===_.guid){y=!0;break}}L++}if(y){const u=await j.getDependency("mesh",L),D=_;if(r&&console.log(`Loaded Mesh "${u.name}"`,f,L,u,x),u.isMesh===!0){const T=u.geometry;return v.assignLODInformation(s.url,T,o,t,void 0,D.density),m(T)}else{const T=new Array;for(let B=0;B<u.children.length;B++){const G=u.children[B];if(G instanceof g.Mesh){const N=G.geometry;v.assignLODInformation(s.url,N,o,t,B,D.density),T.push(N)}}return m(T)}}}return m(null)});return this.previouslyLoaded.set(x,O),await O}else if(e instanceof g.Texture){r&&console.log("Load texture from uri: "+f);const M=await new g.TextureLoader().loadAsync(f);return M?(M.guid=i.guid,M.flipY=!1,M.needsUpdate=!0,M.colorSpace=e.colorSpace,r&&console.log(i,M)):w&&console.warn("failed loading",f),M}}else w&&console.warn(`Can not load LOD ${t}: no LOD info found for "${o}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,s,o,i){if(!t)return;t.userData||(t.userData={});const n=new Se(e,r,s,o,i);t.userData.LODS=n,t.userData.LOD=s}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){return t=t.clone(),w&&console.warn(`Copying texture settings
|
|
4
4
|
`,e.uuid,`
|
|
5
|
-
`,t.uuid),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.mipmaps||(t.generateMipmaps=e.generateMipmaps),t}};let S=v;c(S,"registerTexture",(e,t,r,s,o)=>{w&&console.log("> Progressive: register texture",s,t.name,t.uuid,t,o),t.source&&(t.source[te]=o);const i=o.guid;v.assignLODInformation(e,t,i,r,s,void 0),v.lodInfos.set(i,o),v.lowresCache.set(i,t)}),c(S,"registerMesh",(e,t,r,s,o,i)=>{var h;w&&console.log("> Progressive: register mesh",o,r.name,i,r.uuid,r);const n=r.geometry;n.userData||(n.userData={}),v.assignLODInformation(e,n,t,s,o,i.density),v.lodInfos.set(t,i);let a=v.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],v.lowresCache.set(t,a),s>0&&!Q(r)&&ue(r,n);for(const d of I)(h=d.onRegisteredNewMesh)==null||h.call(d,r,i)}),c(S,"lodInfos",new Map),c(S,"previouslyLoaded",new Map),c(S,"lowresCache",new Map);class Se{constructor(e,t,r,s,o){c(this,"url");c(this,"key");c(this,"level");c(this,"index");c(this,"density");this.url=e,this.key=t,this.level=r,s!=null&&(this.index=s),o!=null&&(this.density=o)}}const z=J("debugprogressive"),Te=J("noprogressive"),le=Symbol("Needle:LODSManager"),E={mesh_lod:-1,texture_lod:-1},b=class{constructor(e){c(this,"renderer");c(this,"projectionScreenMatrix",new g.Matrix4);c(this,"cameraFrustrum",new g.Frustum);c(this,"targetTriangleDensity",2e5);c(this,"updateInterval",0);c(this,"pause",!1);c(this,"_frame",0);c(this,"_originalRender");c(this,"_sphere",new g.Sphere);c(this,"_tempBox",new g.Box3);c(this,"_tempBox2",new g.Box3);c(this,"tempMatrix",new g.Matrix4);c(this,"_tempWorldPosition",new g.Vector3);c(this,"_tempBoxSize",new g.Vector3);c(this,"_tempBox2Size",new g.Vector3);this.renderer=e}static getObjectLODState(e){var t;return(t=e.userData)==null?void 0:t.LOD_state}static addPlugin(e){I.push(e)}static removePlugin(e){const t=I.indexOf(e);t>=0&&I.splice(t,1)}static get(e){return e[le]?e[le]:new b(e)}get plugins(){return I}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;oe(this.renderer),this.renderer.render=function(r,s){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const i=t._frame,n=e++;t.onBeforeRender(r,s,n,i),t._originalRender.call(this,r,s),t.onAfterRender(r,s,n,i)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,s){}onAfterRender(e,t,r,s){var a,h;if(this.pause)return;const o=this.renderer.renderLists.get(e,0),i=o.opaque;let n=!0;if(i.length===1){const d=i[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(n=!1)}if(t.parent&&t.parent.type==="CubeCamera"&&(n=!1),n){if(Te||this.updateInterval>0&&s%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=this.targetTriangleDensity;for(const f of i){if(f.material&&(((a=f.geometry)==null?void 0:a.type)==="BoxGeometry"||((h=f.geometry)==null?void 0:h.type)==="BufferGeometry")&&(f.material.name==="SphericalGaussianBlur"||f.material.name=="BackgroundCubeMaterial"||f.material.name==="CubemapFromEquirect"||f.material.name==="EquirectangularToCubeUV")){z&&(f.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(f.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",f,f.material.name,f.material.type)));continue}switch(f.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const x=f.object;(x instanceof g.Mesh||x.isMesh)&&this.updateLODs(e,t,x,d,s)}const p=o.transparent;for(const f of p){const x=f.object;(x instanceof g.Mesh||x.isMesh)&&this.updateLODs(e,t,x,d,s)}}}updateLODs(e,t,r,s,o){var a,h;r.userData||(r.userData={});let i=r.userData.LOD_state;if(i||(i=new Ae,r.userData.LOD_state=i),i.frames++<2)return;for(const d of I)(a=d.onBeforeUpdateLOD)==null||a.call(d,this.renderer,e,t,r);this.calculateLodLevel(t,r,i,s,E),E.mesh_lod=Math.round(E.mesh_lod),E.texture_lod=Math.round(E.texture_lod),E.mesh_lod>=0&&this.loadProgressiveMeshes(r,E.mesh_lod);let n=E.texture_lod;if(r.material&&n>=0){const d=r["DEBUG:LOD"];d!=null&&(n=d),this.loadProgressiveTextures(r.material,n)}for(const d of I)(h=d.onAfterUpdatedLOD)==null||h.call(d,this.renderer,e,t,r,E);i.lastLodLevel_Mesh=E.mesh_lod,i.lastLodLevel_Texture=E.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const o of e)this.loadProgressiveTextures(o,t);return}const r=e;let s=!1;(r.NEEDLE_LOD==null||t<r.NEEDLE_LOD)&&(s=!0),s&&(r.NEEDLE_LOD=t,S.assignTextureLOD(e,t))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e.userData||(e.userData={}),e.userData.LOD!==t){e.userData.LOD=t;const r=e.geometry;return S.assignMeshLOD(e,t).then(s=>(s&&e.userData.LOD==t&&r!=e.geometry,s))}return Promise.resolve(null)}static isInside(e,t){const r=e.min,s=e.max,o=(r.x+s.x)*.5,i=(r.y+s.y)*.5;return this._tempPtInside.set(o,i,r.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,r,s,o){var M;if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}let n=10+1;if(z&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=S.getMeshLODInformation(t.geometry),h=a==null?void 0:a.lods,d=h&&h.length>0,p=S.getMaterialMinMaxLODsCount(t.material),f=(p==null?void 0:p.min_count)!=1/0&&p.min_count>0&&p.max_count>0;if(!d&&!f){o.mesh_lod=0,o.texture_lod=0;return}if(d||(n=0),!((M=this.cameraFrustrum)!=null&&M.intersectsObject(t))){o.mesh_lod=99,o.texture_lod=99;return}const x=t.geometry.boundingBox;if(x&&e.isPerspectiveCamera){const _=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const L=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(L)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(x),this._tempBox.applyMatrix4(t.matrixWorld),b.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&_.fov>70){const L=this._tempBox.min,y=this._tempBox.max;let u=L.x,D=L.y,T=y.x,C=y.y;const G=2,N=1.5,K=(L.x+y.x)*.5,X=(L.y+y.y)*.5;u=(u-K)*G+K,D=(D-X)*G+X,T=(T-K)*G+K,C=(C-X)*G+X;const de=u<0&&T>0?0:Math.min(Math.abs(L.x),Math.abs(y.x)),he=D<0&&C>0?0:Math.min(Math.abs(L.y),Math.abs(y.y)),ee=Math.max(de,he);r.lastCentrality=(N-ee)*(N-ee)*(N-ee)}else r.lastCentrality=1;const O=this._tempBox.getSize(this._tempBoxSize);O.multiplyScalar(.5),screen.availHeight>0&&O.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),O.x*=_.aspect;const k=e.matrixWorldInverse,m=this._tempBox2;m.copy(x),m.applyMatrix4(t.matrixWorld),m.applyMatrix4(k);const A=m.getSize(this._tempBox2Size),F=Math.max(A.x,A.y);if(Math.max(O.x,O.y)!=0&&F!=0&&(O.z=A.z/Math.max(A.x,A.y)*Math.max(O.x,O.y)),r.lastScreenCoverage=Math.max(O.x,O.y,O.z),r.lastScreenspaceVolume.copy(O),r.lastScreenCoverage*=r.lastCentrality,z&&b.debugDrawLine){const L=this.tempMatrix.copy(this.projectionScreenMatrix);L.invert();const y=b.corner0,u=b.corner1,D=b.corner2,T=b.corner3;y.copy(this._tempBox.min),u.copy(this._tempBox.max),u.x=y.x,D.copy(this._tempBox.max),D.y=y.y,T.copy(this._tempBox.max);const C=(y.z+T.z)*.5;y.z=u.z=D.z=T.z=C,y.applyMatrix4(L),u.applyMatrix4(L),D.applyMatrix4(L),T.applyMatrix4(L),b.debugDrawLine(y,u,255),b.debugDrawLine(y,D,255),b.debugDrawLine(u,T,255),b.debugDrawLine(D,T,255)}let B=999;if(h&&r.lastScreenCoverage>0){for(let L=0;L<h.length;L++)if(h[L].density/r.lastScreenCoverage<s){B=L;break}}B<n&&(n=B)}if(o.mesh_lod=n,f)if(r.lastLodLevel_Texture<0){if(o.texture_lod=p.max_count-1,z){const _=p.lods[p.max_count-1];z&&console.log(`First Texture LOD ${o.texture_lod} (${_.max_height}px) - ${t.name}`)}}else{const _=r.lastScreenCoverage*1.5,k=this.renderer.domElement.clientHeight/window.devicePixelRatio*_;for(let m=p.lods.length-1;m>=0;m--){const A=p.lods[m];if(!(Oe()&&A.max_height>4096)&&A.max_height>k){o.texture_lod=m,o.texture_lod<r.lastLodLevel_Texture&&z&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} → ${o.texture_lod} (${A.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${k.toFixed(0)}px) - ${t.name}`);break}}}else o.texture_lod=0}};let P=b;c(P,"debugDrawLine"),c(P,"corner0",new g.Vector3),c(P,"corner1",new g.Vector3),c(P,"corner2",new g.Vector3),c(P,"corner3",new g.Vector3),c(P,"_tempPtInside",new g.Vector3);class Ae{constructor(){c(this,"frames",0);c(this,"lastLodLevel_Mesh",-1);c(this,"lastLodLevel_Texture",-1);c(this,"lastScreenCoverage",0);c(this,"lastScreenspaceVolume",new g.Vector3);c(this,"lastCentrality",0)}}const ce=Symbol("NEEDLE_mesh_lod"),Y=Symbol("NEEDLE_texture_lod");function fe(l){if(!l)return null;let e=null,t=null;for(let r=l;r!=null;r=Object.getPrototypeOf(r)){const s=Object.getOwnPropertySymbols(r),o=s.find(n=>n.toString()=="Symbol(renderer)"),i=s.find(n=>n.toString()=="Symbol(scene)");!e&&o!=null&&(e=l[o].threeRenderer),!t&&i!=null&&(t=l[i])}if(e){console.log("Adding Needle LODs to modelviewer");const r=P.get(e);if(P.addPlugin(new be(l)),r.enable(),t){const s=t.camera||t.traverse(o=>o.type=="PerspectiveCamera")[0];s&&e.render(t,s)}return()=>{r.disable()}}return null}class be{constructor(e){c(this,"modelviewer");c(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,s){this.tryParseMeshLOD(t,s),this.tryParseTextureLOD(t,s)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[Y]==!0)return;t[Y]=!0;const r=this.tryGetCurrentGLTF(e),s=this.getUrl();if(s&&r&&t.material){let o=function(n){var h,d,p;if(n[Y]==!0)return;n[Y]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let f=0;f<a.length;f++){const x=a[f],M=n[x];if((M==null?void 0:M.isTexture)===!0){const _=(d=(h=M.userData)==null?void 0:h.associations)==null?void 0:d.textures,O=r.parser.json.textures[_];if(!O){console.warn("Texture data not found for texture index "+_);continue}if((p=O==null?void 0:O.extensions)!=null&&p[R]){const k=O.extensions[R];k&&s&&S.registerTexture(s,M,k.lods.length,_,k)}}}};const i=t.material;if(Array.isArray(i))for(const n of i)o(n);else o(i)}}tryParseMeshLOD(e,t){var o,i;if(t[ce]==!0)return;t[ce]=!0;const r=this.getUrl();if(!r)return;const s=(i=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:i[R];if(s&&r){const n=t.uuid;S.registerMesh(r,n,t,0,s.lods.length,s)}}}function Pe(l,e,t,r){oe(e),ne(t),t.register(o=>new S(o,l));const s=P.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&s.enable(),s}document.addEventListener("DOMContentLoaded",()=>{fe(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=R;exports.LODsManager=P;exports.NEEDLE_progressive=S;exports.addDracoAndKTX2Loaders=ne;exports.createLoaders=oe;exports.getRaycastMesh=Q;exports.patchModelViewer=fe;exports.setDracoDecoderLocation=De;exports.setKTX2TranscoderLocation=Me;exports.setRaycastMesh=ue;exports.useNeedleProgressive=Pe;exports.useRaycastMeshes=we;
|
|
5
|
+
`,t.uuid),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.mipmaps||(t.generateMipmaps=e.generateMipmaps),t}};let S=v;c(S,"registerTexture",(e,t,r,s,o)=>{if(w&&console.log("> Progressive: register texture",s,t.name,t.uuid,t,o),!t){w&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[te]=o);const i=o.guid;v.assignLODInformation(e,t,i,r,s,void 0),v.lodInfos.set(i,o),v.lowresCache.set(i,t)}),c(S,"registerMesh",(e,t,r,s,o,i)=>{var h;w&&console.log("> Progressive: register mesh",o,r.name,i,r.uuid,r);const n=r.geometry;if(!n){w&&console.warn("gltf-progressive: Register mesh without geometry");return}n.userData||(n.userData={}),v.assignLODInformation(e,n,t,s,o,i.density),v.lodInfos.set(t,i);let a=v.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],v.lowresCache.set(t,a),s>0&&!Q(r)&&ue(r,n);for(const d of I)(h=d.onRegisteredNewMesh)==null||h.call(d,r,i)}),c(S,"lodInfos",new Map),c(S,"previouslyLoaded",new Map),c(S,"lowresCache",new Map);class Se{constructor(e,t,r,s,o){c(this,"url");c(this,"key");c(this,"level");c(this,"index");c(this,"density");this.url=e,this.key=t,this.level=r,s!=null&&(this.index=s),o!=null&&(this.density=o)}}const z=J("debugprogressive"),Te=J("noprogressive"),le=Symbol("Needle:LODSManager"),E={mesh_lod:-1,texture_lod:-1},b=class{constructor(e){c(this,"renderer");c(this,"projectionScreenMatrix",new g.Matrix4);c(this,"cameraFrustrum",new g.Frustum);c(this,"targetTriangleDensity",2e5);c(this,"updateInterval",0);c(this,"pause",!1);c(this,"_frame",0);c(this,"_originalRender");c(this,"_sphere",new g.Sphere);c(this,"_tempBox",new g.Box3);c(this,"_tempBox2",new g.Box3);c(this,"tempMatrix",new g.Matrix4);c(this,"_tempWorldPosition",new g.Vector3);c(this,"_tempBoxSize",new g.Vector3);c(this,"_tempBox2Size",new g.Vector3);this.renderer=e}static getObjectLODState(e){var t;return(t=e.userData)==null?void 0:t.LOD_state}static addPlugin(e){I.push(e)}static removePlugin(e){const t=I.indexOf(e);t>=0&&I.splice(t,1)}static get(e){return e[le]?e[le]:new b(e)}get plugins(){return I}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;oe(this.renderer),this.renderer.render=function(r,s){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const i=t._frame,n=e++;t.onBeforeRender(r,s,n,i),t._originalRender.call(this,r,s),t.onAfterRender(r,s,n,i)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,s){}onAfterRender(e,t,r,s){var a,h;if(this.pause)return;const o=this.renderer.renderLists.get(e,0),i=o.opaque;let n=!0;if(i.length===1){const d=i[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(n=!1)}if(t.parent&&t.parent.type==="CubeCamera"&&(n=!1),n){if(Te||this.updateInterval>0&&s%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=this.targetTriangleDensity;for(const f of i){if(f.material&&(((a=f.geometry)==null?void 0:a.type)==="BoxGeometry"||((h=f.geometry)==null?void 0:h.type)==="BufferGeometry")&&(f.material.name==="SphericalGaussianBlur"||f.material.name=="BackgroundCubeMaterial"||f.material.name==="CubemapFromEquirect"||f.material.name==="EquirectangularToCubeUV")){z&&(f.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(f.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",f,f.material.name,f.material.type)));continue}switch(f.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const x=f.object;(x instanceof g.Mesh||x.isMesh)&&this.updateLODs(e,t,x,d,s)}const p=o.transparent;for(const f of p){const x=f.object;(x instanceof g.Mesh||x.isMesh)&&this.updateLODs(e,t,x,d,s)}}}updateLODs(e,t,r,s,o){var a,h;r.userData||(r.userData={});let i=r.userData.LOD_state;if(i||(i=new Ae,r.userData.LOD_state=i),i.frames++<2)return;for(const d of I)(a=d.onBeforeUpdateLOD)==null||a.call(d,this.renderer,e,t,r);this.calculateLodLevel(t,r,i,s,E),E.mesh_lod=Math.round(E.mesh_lod),E.texture_lod=Math.round(E.texture_lod),E.mesh_lod>=0&&this.loadProgressiveMeshes(r,E.mesh_lod);let n=E.texture_lod;if(r.material&&n>=0){const d=r["DEBUG:LOD"];d!=null&&(n=d),this.loadProgressiveTextures(r.material,n)}for(const d of I)(h=d.onAfterUpdatedLOD)==null||h.call(d,this.renderer,e,t,r,E);i.lastLodLevel_Mesh=E.mesh_lod,i.lastLodLevel_Texture=E.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const o of e)this.loadProgressiveTextures(o,t);return}const r=e;let s=!1;(r.NEEDLE_LOD==null||t<r.NEEDLE_LOD)&&(s=!0),s&&(r.NEEDLE_LOD=t,S.assignTextureLOD(e,t))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e.userData||(e.userData={}),e.userData.LOD!==t){e.userData.LOD=t;const r=e.geometry;return S.assignMeshLOD(e,t).then(s=>(s&&e.userData.LOD==t&&r!=e.geometry,s))}return Promise.resolve(null)}static isInside(e,t){const r=e.min,s=e.max,o=(r.x+s.x)*.5,i=(r.y+s.y)*.5;return this._tempPtInside.set(o,i,r.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,r,s,o){var M;if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}let n=10+1;if(z&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=S.getMeshLODInformation(t.geometry),h=a==null?void 0:a.lods,d=h&&h.length>0,p=S.getMaterialMinMaxLODsCount(t.material),f=(p==null?void 0:p.min_count)!=1/0&&p.min_count>0&&p.max_count>0;if(!d&&!f){o.mesh_lod=0,o.texture_lod=0;return}if(d||(n=0),!((M=this.cameraFrustrum)!=null&&M.intersectsObject(t))){o.mesh_lod=99,o.texture_lod=99;return}const x=t.geometry.boundingBox;if(x&&e.isPerspectiveCamera){const _=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const L=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(L)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(x),this._tempBox.applyMatrix4(t.matrixWorld),b.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&_.fov>70){const L=this._tempBox.min,y=this._tempBox.max;let u=L.x,D=L.y,T=y.x,B=y.y;const G=2,N=1.5,K=(L.x+y.x)*.5,X=(L.y+y.y)*.5;u=(u-K)*G+K,D=(D-X)*G+X,T=(T-K)*G+K,B=(B-X)*G+X;const de=u<0&&T>0?0:Math.min(Math.abs(L.x),Math.abs(y.x)),he=D<0&&B>0?0:Math.min(Math.abs(L.y),Math.abs(y.y)),ee=Math.max(de,he);r.lastCentrality=(N-ee)*(N-ee)*(N-ee)}else r.lastCentrality=1;const O=this._tempBox.getSize(this._tempBoxSize);O.multiplyScalar(.5),screen.availHeight>0&&O.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),O.x*=_.aspect;const k=e.matrixWorldInverse,m=this._tempBox2;m.copy(x),m.applyMatrix4(t.matrixWorld),m.applyMatrix4(k);const A=m.getSize(this._tempBox2Size),F=Math.max(A.x,A.y);if(Math.max(O.x,O.y)!=0&&F!=0&&(O.z=A.z/Math.max(A.x,A.y)*Math.max(O.x,O.y)),r.lastScreenCoverage=Math.max(O.x,O.y,O.z),r.lastScreenspaceVolume.copy(O),r.lastScreenCoverage*=r.lastCentrality,z&&b.debugDrawLine){const L=this.tempMatrix.copy(this.projectionScreenMatrix);L.invert();const y=b.corner0,u=b.corner1,D=b.corner2,T=b.corner3;y.copy(this._tempBox.min),u.copy(this._tempBox.max),u.x=y.x,D.copy(this._tempBox.max),D.y=y.y,T.copy(this._tempBox.max);const B=(y.z+T.z)*.5;y.z=u.z=D.z=T.z=B,y.applyMatrix4(L),u.applyMatrix4(L),D.applyMatrix4(L),T.applyMatrix4(L),b.debugDrawLine(y,u,255),b.debugDrawLine(y,D,255),b.debugDrawLine(u,T,255),b.debugDrawLine(D,T,255)}let R=999;if(h&&r.lastScreenCoverage>0){for(let L=0;L<h.length;L++)if(h[L].density/r.lastScreenCoverage<s){R=L;break}}R<n&&(n=R)}if(o.mesh_lod=n,f)if(r.lastLodLevel_Texture<0){if(o.texture_lod=p.max_count-1,z){const _=p.lods[p.max_count-1];z&&console.log(`First Texture LOD ${o.texture_lod} (${_.max_height}px) - ${t.name}`)}}else{const _=r.lastScreenCoverage*1.5,k=this.renderer.domElement.clientHeight/window.devicePixelRatio*_;for(let m=p.lods.length-1;m>=0;m--){const A=p.lods[m];if(!(Oe()&&A.max_height>4096)&&A.max_height>k){o.texture_lod=m,o.texture_lod<r.lastLodLevel_Texture&&z&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} → ${o.texture_lod} (${A.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${k.toFixed(0)}px) - ${t.name}`);break}}}else o.texture_lod=0}};let P=b;c(P,"debugDrawLine"),c(P,"corner0",new g.Vector3),c(P,"corner1",new g.Vector3),c(P,"corner2",new g.Vector3),c(P,"corner3",new g.Vector3),c(P,"_tempPtInside",new g.Vector3);class Ae{constructor(){c(this,"frames",0);c(this,"lastLodLevel_Mesh",-1);c(this,"lastLodLevel_Texture",-1);c(this,"lastScreenCoverage",0);c(this,"lastScreenspaceVolume",new g.Vector3);c(this,"lastCentrality",0)}}const ce=Symbol("NEEDLE_mesh_lod"),Y=Symbol("NEEDLE_texture_lod");function fe(l){if(!l)return null;let e=null,t=null;for(let r=l;r!=null;r=Object.getPrototypeOf(r)){const s=Object.getOwnPropertySymbols(r),o=s.find(n=>n.toString()=="Symbol(renderer)"),i=s.find(n=>n.toString()=="Symbol(scene)");!e&&o!=null&&(e=l[o].threeRenderer),!t&&i!=null&&(t=l[i])}if(e){console.log("Adding Needle LODs to modelviewer");const r=P.get(e);if(P.addPlugin(new be(l)),r.enable(),t){const s=t.camera||t.traverse(o=>o.type=="PerspectiveCamera")[0];s&&e.render(t,s)}return()=>{r.disable()}}return null}class be{constructor(e){c(this,"modelviewer");c(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,s){this.tryParseMeshLOD(t,s),this.tryParseTextureLOD(t,s)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[Y]==!0)return;t[Y]=!0;const r=this.tryGetCurrentGLTF(e),s=this.getUrl();if(s&&r&&t.material){let o=function(n){var h,d,p;if(n[Y]==!0)return;n[Y]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let f=0;f<a.length;f++){const x=a[f],M=n[x];if((M==null?void 0:M.isTexture)===!0){const _=(d=(h=M.userData)==null?void 0:h.associations)==null?void 0:d.textures,O=r.parser.json.textures[_];if(!O){console.warn("Texture data not found for texture index "+_);continue}if((p=O==null?void 0:O.extensions)!=null&&p[C]){const k=O.extensions[C];k&&s&&S.registerTexture(s,M,k.lods.length,_,k)}}}};const i=t.material;if(Array.isArray(i))for(const n of i)o(n);else o(i)}}tryParseMeshLOD(e,t){var o,i;if(t[ce]==!0)return;t[ce]=!0;const r=this.getUrl();if(!r)return;const s=(i=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:i[C];if(s&&r){const n=t.uuid;S.registerMesh(r,n,t,0,s.lods.length,s)}}}function Pe(l,e,t,r){oe(e),ne(t),t.register(o=>new S(o,l));const s=P.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&s.enable(),s}document.addEventListener("DOMContentLoaded",()=>{fe(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=C;exports.LODsManager=P;exports.NEEDLE_progressive=S;exports.addDracoAndKTX2Loaders=ne;exports.createLoaders=oe;exports.getRaycastMesh=Q;exports.patchModelViewer=fe;exports.setDracoDecoderLocation=De;exports.setKTX2TranscoderLocation=Me;exports.setRaycastMesh=ue;exports.useNeedleProgressive=Pe;exports.useRaycastMeshes=we;
|
package/lib/extension.js
CHANGED
|
@@ -473,6 +473,11 @@ export class NEEDLE_progressive {
|
|
|
473
473
|
static registerTexture = (url, tex, level, index, ext) => {
|
|
474
474
|
if (debug)
|
|
475
475
|
console.log("> Progressive: register texture", index, tex.name, tex.uuid, tex, ext);
|
|
476
|
+
if (!tex) {
|
|
477
|
+
if (debug)
|
|
478
|
+
console.error("gltf-progressive: Register texture without texture");
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
476
481
|
// Put the extension info into the source (seems like tiled textures are cloned and the userdata etc is not properly copied BUT the source of course is not cloned)
|
|
477
482
|
// see https://github.com/needle-tools/needle-engine-support/issues/133
|
|
478
483
|
if (tex.source)
|
|
@@ -489,6 +494,11 @@ export class NEEDLE_progressive {
|
|
|
489
494
|
if (debug)
|
|
490
495
|
console.log("> Progressive: register mesh", index, mesh.name, ext, mesh.uuid, mesh);
|
|
491
496
|
const geometry = mesh.geometry;
|
|
497
|
+
if (!geometry) {
|
|
498
|
+
if (debug)
|
|
499
|
+
console.warn("gltf-progressive: Register mesh without geometry");
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
492
502
|
if (!geometry.userData)
|
|
493
503
|
geometry.userData = {};
|
|
494
504
|
NEEDLE_progressive.assignLODInformation(url, geometry, key, level, index, ext.density);
|
package/package.json
CHANGED