@needle-tools/gltf-progressive 1.0.0-alpha.12 → 1.0.0-alpha.13
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/examples/modelviewer.html +27 -0
- package/examples/react-three-fiber/.prettierrc +10 -0
- package/examples/react-three-fiber/index.html +26 -0
- package/examples/react-three-fiber/package-lock.json +3587 -0
- package/examples/react-three-fiber/package.json +35 -0
- package/examples/react-three-fiber/tsconfig.json +22 -0
- package/examples/react-three-fiber/vite.config.js +44 -0
- package/examples/threejs/index.html +51 -0
- package/examples/threejs/main.js +76 -0
- package/gltf-progressive.js +45 -43
- package/gltf-progressive.min.js +3 -3
- package/gltf-progressive.umd.cjs +3 -3
- package/lib/extension.js +8 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-typescript",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "src/index.tsx",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@needle-tools/gltf-progressive": "file:../..",
|
|
7
|
+
"react": "^18.0.0",
|
|
8
|
+
"react-dom": "^18.0.0",
|
|
9
|
+
"@react-three/drei": "^9.0.1",
|
|
10
|
+
"@react-three/fiber": "^8.0.6",
|
|
11
|
+
"three": "0.162.0",
|
|
12
|
+
"typescript": "4.7.4"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/react": "18.0.15",
|
|
16
|
+
"@types/react-dom": "17.0.0",
|
|
17
|
+
"@types/three": "0.162.0",
|
|
18
|
+
"typescript": "4.1.3",
|
|
19
|
+
"@vitejs/plugin-basic-ssl": "^1.0.1",
|
|
20
|
+
"vite": "<= 4.3.9",
|
|
21
|
+
"@vitejs/plugin-react": "^1.3.0"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"start": "vite --host",
|
|
25
|
+
"build": "react-scripts build",
|
|
26
|
+
"test": "react-scripts test --env=jsdom",
|
|
27
|
+
"eject": "react-scripts eject"
|
|
28
|
+
},
|
|
29
|
+
"browserslist": [
|
|
30
|
+
">0.2%",
|
|
31
|
+
"not dead",
|
|
32
|
+
"not ie <= 11",
|
|
33
|
+
"not op_mini all"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"jsx": "react",
|
|
4
|
+
"target": "ESNext",
|
|
5
|
+
"useDefineForClassFields": true,
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"lib": ["ESNext", "DOM"],
|
|
8
|
+
"moduleResolution": "Node",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"sourceMap": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"noUnusedLocals": false,
|
|
15
|
+
"noUnusedParameters": true,
|
|
16
|
+
"noImplicitReturns": true,
|
|
17
|
+
"noImplicitAny": false,
|
|
18
|
+
"experimentalDecorators": true,
|
|
19
|
+
"skipLibCheck": true
|
|
20
|
+
},
|
|
21
|
+
"include": ["./src"]
|
|
22
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import { defineConfig } from 'vite';
|
|
3
|
+
import react from '@vitejs/plugin-react';
|
|
4
|
+
import basicSsl from '@vitejs/plugin-basic-ssl'
|
|
5
|
+
|
|
6
|
+
export default defineConfig(async (command) => {
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
base: "./",
|
|
11
|
+
assetsInclude: ['*'],
|
|
12
|
+
|
|
13
|
+
plugins: [
|
|
14
|
+
react(),
|
|
15
|
+
basicSsl(),
|
|
16
|
+
],
|
|
17
|
+
|
|
18
|
+
server: {
|
|
19
|
+
https: true,
|
|
20
|
+
proxy: { // workaround: specifying a proxy skips HTTP2 which is currently problematic in Vite since it causes session memory timeouts.
|
|
21
|
+
'https://localhost:3000': 'https://localhost:3000'
|
|
22
|
+
},
|
|
23
|
+
watch: {
|
|
24
|
+
awaitWriteFinish: {
|
|
25
|
+
stabilityThreshold: 500,
|
|
26
|
+
pollInterval: 1000
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
strictPort: true,
|
|
30
|
+
port: 3001
|
|
31
|
+
},
|
|
32
|
+
build: {
|
|
33
|
+
outDir: "./dist",
|
|
34
|
+
emptyOutDir: true,
|
|
35
|
+
keepNames: true,
|
|
36
|
+
},
|
|
37
|
+
resolve: {
|
|
38
|
+
alias: {
|
|
39
|
+
'react': () => path.resolve(__dirname, 'node_modules/react'),
|
|
40
|
+
'@react-three/fiber': () => path.resolve(__dirname, 'node_modules/@react-three/fiber'),
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>My first three.js app</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
margin: 0;
|
|
10
|
+
}
|
|
11
|
+
</style>
|
|
12
|
+
<script type="importmap">
|
|
13
|
+
{
|
|
14
|
+
"imports": {
|
|
15
|
+
"three": "https://cdn.jsdelivr.net/npm/three@latest/build/three.module.js",
|
|
16
|
+
"three/addons/": "https://cdn.jsdelivr.net/npm/three@latest/examples/jsm/",
|
|
17
|
+
"three/examples/": "https://cdn.jsdelivr.net/npm/three@latest/examples/",
|
|
18
|
+
"@needle-engine/gltf-progressive": "https://www.unpkg.com/@needle-tools/gltf-progressive@latest"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
</script>
|
|
22
|
+
</head>
|
|
23
|
+
|
|
24
|
+
<body>
|
|
25
|
+
<script type="module" src="./main.js"></script>
|
|
26
|
+
<button class="show-source">Show Source</button>
|
|
27
|
+
</body>
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
<style>
|
|
31
|
+
.show-source {
|
|
32
|
+
position: fixed;
|
|
33
|
+
right: 1rem;
|
|
34
|
+
bottom: 1rem;
|
|
35
|
+
z-index: 100;
|
|
36
|
+
border-radius: .5rem;
|
|
37
|
+
border: none;
|
|
38
|
+
padding: .3rem .5rem;
|
|
39
|
+
}
|
|
40
|
+
</style>
|
|
41
|
+
<script>
|
|
42
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
43
|
+
document.querySelector('.show-source').addEventListener('click', () => {
|
|
44
|
+
const scriptSource = document.querySelector('script[type="module"]').src;
|
|
45
|
+
console.log(scriptSource);
|
|
46
|
+
window.open(scriptSource);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
</html>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { EXRLoader } from 'three/addons/loaders/EXRLoader.js';
|
|
3
|
+
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
4
|
+
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
|
5
|
+
import { useNeedleProgressive, } from "@needle-engine/gltf-progressive"
|
|
6
|
+
|
|
7
|
+
const scene = new THREE.Scene();
|
|
8
|
+
scene.background = new THREE.Color(0x555555);
|
|
9
|
+
const renderer = new THREE.WebGLRenderer();
|
|
10
|
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
11
|
+
document.body.appendChild(renderer.domElement);
|
|
12
|
+
|
|
13
|
+
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
window.addEventListener('resize', () => {
|
|
17
|
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
18
|
+
camera.aspect = window.innerWidth / window.innerHeight;
|
|
19
|
+
camera.updateProjectionMatrix();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const orbit = new OrbitControls(camera, renderer.domElement);
|
|
23
|
+
orbit.target = new THREE.Vector3(0, .6, 0);
|
|
24
|
+
camera.position.x = -1;
|
|
25
|
+
camera.position.y = 1.5;
|
|
26
|
+
camera.position.z = 1.8;
|
|
27
|
+
|
|
28
|
+
const grid = new THREE.GridHelper(10, 10, 0x444444, 0x666666);
|
|
29
|
+
scene.add(grid);
|
|
30
|
+
|
|
31
|
+
const directionalLight = new THREE.DirectionalLight(0xffffff, .2);
|
|
32
|
+
directionalLight.position.set(1, 1, 0);
|
|
33
|
+
scene.add(directionalLight);
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
// Animate the scene
|
|
37
|
+
function animate() {
|
|
38
|
+
requestAnimationFrame(animate);
|
|
39
|
+
orbit.update();
|
|
40
|
+
renderer.render(scene, camera);
|
|
41
|
+
}
|
|
42
|
+
animate();
|
|
43
|
+
|
|
44
|
+
const environmentTextureUrl = "https://dl.polyhaven.org/file/ph-assets/HDRIs/exr/1k/studio_small_09_1k.exr";
|
|
45
|
+
const pmremGenerator = new THREE.PMREMGenerator(renderer);
|
|
46
|
+
pmremGenerator.compileEquirectangularShader();
|
|
47
|
+
new EXRLoader().load(environmentTextureUrl, texture => {
|
|
48
|
+
const envMap = pmremGenerator.fromEquirectangular(texture).texture;
|
|
49
|
+
scene.environment = envMap;
|
|
50
|
+
texture.dispose();
|
|
51
|
+
pmremGenerator.dispose();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
// Integrate @needle-tools/gltf-progressive
|
|
58
|
+
// This is the model we want to load
|
|
59
|
+
const url = "https://engine.needle.tools/demos/gltf-progressive/threejs/assets/model.glb";
|
|
60
|
+
|
|
61
|
+
const gltfLoader = new GLTFLoader();
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Call this method to register the progressive loader
|
|
65
|
+
*/
|
|
66
|
+
useNeedleProgressive(url, renderer, gltfLoader)
|
|
67
|
+
|
|
68
|
+
// just call the load method as usual
|
|
69
|
+
gltfLoader.load(url, gltf => {
|
|
70
|
+
console.log(gltf)
|
|
71
|
+
scene.add(gltf.scene)
|
|
72
|
+
gltf.scene.position.y += .95;
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
package/gltf-progressive.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var le = Object.defineProperty;
|
|
2
2
|
var ue = (l, e, t) => e in l ? le(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
|
|
3
3
|
var c = (l, e, t) => (ue(l, typeof e != "symbol" ? e + "" : e, t), t);
|
|
4
|
-
import { Mesh as q, BufferGeometry as
|
|
4
|
+
import { Mesh as q, BufferGeometry as Y, Material as ce, Texture as I, TextureLoader as fe, Matrix4 as te, Frustum as de, Sphere as ge, Box3 as re, Vector3 as C } from "three";
|
|
5
5
|
import { GLTFLoader as he } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
6
6
|
import { MeshoptDecoder as pe } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
7
7
|
import { DRACOLoader as ye } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
@@ -16,12 +16,12 @@ function _e(l) {
|
|
|
16
16
|
function Be(l) {
|
|
17
17
|
j = l;
|
|
18
18
|
}
|
|
19
|
-
let
|
|
19
|
+
let U, J, W;
|
|
20
20
|
function ne(l) {
|
|
21
|
-
|
|
21
|
+
U || (U = new ye(), U.setDecoderPath(K), U.setDecoderConfig({ type: "js" })), W || (W = new me(), W.setTranscoderPath(j)), J || (J = pe), l ? W.detectSupport(l) : console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail");
|
|
22
22
|
}
|
|
23
23
|
function oe(l) {
|
|
24
|
-
l.dracoLoader || l.setDRACOLoader(
|
|
24
|
+
l.dracoLoader || l.setDRACOLoader(U), l.ktx2Loader || l.setKTX2Loader(W), l.meshoptDecoder || l.setMeshoptDecoder(J);
|
|
25
25
|
}
|
|
26
26
|
function ee(l) {
|
|
27
27
|
const t = new URL(window.location.href).searchParams.get(l);
|
|
@@ -43,7 +43,7 @@ const Q = new Array();
|
|
|
43
43
|
function ke(l) {
|
|
44
44
|
Q.push(l);
|
|
45
45
|
}
|
|
46
|
-
const R = "NEEDLE_progressive", S = ee("debugprogressive"),
|
|
46
|
+
const R = "NEEDLE_progressive", S = ee("debugprogressive"), V = Symbol("needle-progressive-texture"), z = /* @__PURE__ */ new Map(), Z = /* @__PURE__ */ new Set();
|
|
47
47
|
if (S) {
|
|
48
48
|
let l = function() {
|
|
49
49
|
e += 1, console.log("Toggle LOD level", e, z), z.forEach((i, n) => {
|
|
@@ -146,7 +146,7 @@ const M = class {
|
|
|
146
146
|
const o = n.index || 0;
|
|
147
147
|
s = s[o];
|
|
148
148
|
}
|
|
149
|
-
s && i != s && s instanceof
|
|
149
|
+
s && i != s && s instanceof Y && (e.geometry = s, S && se(e, "geometry", n.url));
|
|
150
150
|
}
|
|
151
151
|
return s;
|
|
152
152
|
}).catch((s) => (console.error("Error loading mesh LOD", e, s), null));
|
|
@@ -192,7 +192,7 @@ const M = class {
|
|
|
192
192
|
return o;
|
|
193
193
|
});
|
|
194
194
|
}
|
|
195
|
-
if (e instanceof
|
|
195
|
+
if (e instanceof I || e.isTexture === !0) {
|
|
196
196
|
const r = e;
|
|
197
197
|
return this.assignTextureLODForSlot(r, t, null, null);
|
|
198
198
|
}
|
|
@@ -249,7 +249,7 @@ const M = class {
|
|
|
249
249
|
let s;
|
|
250
250
|
if (e.isTexture === !0) {
|
|
251
251
|
const f = e;
|
|
252
|
-
f.source && f.source[
|
|
252
|
+
f.source && f.source[V] && (s = f.source[V]);
|
|
253
253
|
}
|
|
254
254
|
if (s || (s = M.lodInfos.get(n)), s) {
|
|
255
255
|
if (t > 0) {
|
|
@@ -268,67 +268,67 @@ const M = class {
|
|
|
268
268
|
const u = p + "_" + s.guid, h = this.previouslyLoaded.get(u);
|
|
269
269
|
if (h !== void 0) {
|
|
270
270
|
r && console.log(`LOD ${t} was already loading/loaded: ${u}`);
|
|
271
|
-
let x = await h.catch((
|
|
272
|
-
`,
|
|
273
|
-
if (x == null || (x instanceof
|
|
271
|
+
let x = await h.catch((F) => (console.error(`Error loading LOD ${t} from ${p}
|
|
272
|
+
`, F), null)), k = !1;
|
|
273
|
+
if (x == null || (x instanceof I && e instanceof I ? (o = x.image) != null && o.data || (a = x.source) != null && a.data ? x = this.copySettings(e, x) : (k = !0, this.previouslyLoaded.delete(u)) : x instanceof Y && e instanceof Y && ((g = x.attributes.position) != null && g.array || (k = !0, this.previouslyLoaded.delete(u)))), !k)
|
|
274
274
|
return x;
|
|
275
275
|
}
|
|
276
276
|
const D = s, A = new Promise(async (x, k) => {
|
|
277
|
-
const
|
|
278
|
-
oe(
|
|
277
|
+
const F = new he();
|
|
278
|
+
oe(F), S && (await new Promise((m) => setTimeout(m, 1e3)), r && console.warn("Start loading (delayed) " + p, D.guid));
|
|
279
279
|
let L = p;
|
|
280
280
|
if (D && Array.isArray(D.lods)) {
|
|
281
281
|
const m = D.lods[t];
|
|
282
282
|
m.hash && (L += "?v=" + m.hash);
|
|
283
283
|
}
|
|
284
|
-
const y = await
|
|
284
|
+
const y = await F.loadAsync(L).catch((m) => (console.error(`Error loading LOD ${t} from ${p}
|
|
285
285
|
`, m), null));
|
|
286
286
|
if (!y)
|
|
287
287
|
return null;
|
|
288
288
|
const T = y.parser;
|
|
289
289
|
r && console.log("Loading finished " + p, D.guid);
|
|
290
|
-
let
|
|
290
|
+
let w = 0;
|
|
291
291
|
if (y.parser.json.textures) {
|
|
292
292
|
let m = !1;
|
|
293
293
|
for (const d of y.parser.json.textures) {
|
|
294
294
|
if (d != null && d.extensions) {
|
|
295
|
-
const
|
|
296
|
-
if (
|
|
295
|
+
const O = d == null ? void 0 : d.extensions[R];
|
|
296
|
+
if (O != null && O.guid && O.guid === D.guid) {
|
|
297
297
|
m = !0;
|
|
298
298
|
break;
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
|
-
|
|
301
|
+
w++;
|
|
302
302
|
}
|
|
303
303
|
if (m) {
|
|
304
|
-
let d = await T.getDependency("texture",
|
|
305
|
-
return r && console.log('change "' + e.name + '" → "' + d.name + '"', p,
|
|
304
|
+
let d = await T.getDependency("texture", w);
|
|
305
|
+
return r && console.log('change "' + e.name + '" → "' + d.name + '"', p, w, d, u), e instanceof I && (d = this.copySettings(e, d)), d && (d.guid = D.guid), x(d);
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
|
-
if (
|
|
308
|
+
if (w = 0, y.parser.json.meshes) {
|
|
309
309
|
let m = !1;
|
|
310
310
|
for (const d of y.parser.json.meshes) {
|
|
311
311
|
if (d != null && d.extensions) {
|
|
312
|
-
const
|
|
313
|
-
if (
|
|
312
|
+
const O = d == null ? void 0 : d.extensions[R];
|
|
313
|
+
if (O != null && O.guid && O.guid === D.guid) {
|
|
314
314
|
m = !0;
|
|
315
315
|
break;
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
|
-
|
|
318
|
+
w++;
|
|
319
319
|
}
|
|
320
320
|
if (m) {
|
|
321
|
-
const d = await T.getDependency("mesh",
|
|
322
|
-
if (r && console.log(`Loaded Mesh "${d.name}"`, p,
|
|
321
|
+
const d = await T.getDependency("mesh", w), O = D;
|
|
322
|
+
if (r && console.log(`Loaded Mesh "${d.name}"`, p, w, d, u), d.isMesh === !0) {
|
|
323
323
|
const P = d.geometry;
|
|
324
|
-
return M.assignLODInformation(i.url, P, n, t, void 0,
|
|
324
|
+
return M.assignLODInformation(i.url, P, n, t, void 0, O.density), x(P);
|
|
325
325
|
} else {
|
|
326
326
|
const P = new Array();
|
|
327
327
|
for (let _ = 0; _ < d.children.length; _++) {
|
|
328
328
|
const E = d.children[_];
|
|
329
329
|
if (E instanceof q) {
|
|
330
330
|
const N = E.geometry;
|
|
331
|
-
M.assignLODInformation(i.url, N, n, t, _,
|
|
331
|
+
M.assignLODInformation(i.url, N, n, t, _, O.density), P.push(N);
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
334
|
return x(P);
|
|
@@ -338,7 +338,7 @@ const M = class {
|
|
|
338
338
|
return x(null);
|
|
339
339
|
});
|
|
340
340
|
return this.previouslyLoaded.set(u, A), await A;
|
|
341
|
-
} else if (e instanceof
|
|
341
|
+
} else if (e instanceof I) {
|
|
342
342
|
r && console.log("Load texture from uri: " + p);
|
|
343
343
|
const h = await new fe().loadAsync(p);
|
|
344
344
|
return h ? (h.guid = s.guid, h.flipY = !1, h.needsUpdate = !0, h.colorSpace = e.colorSpace, r && console.log(s, h)) : S && console.warn("failed loading", p), h;
|
|
@@ -360,7 +360,7 @@ const M = class {
|
|
|
360
360
|
}
|
|
361
361
|
static copySettings(e, t) {
|
|
362
362
|
const r = this._copiedTextures.get(e);
|
|
363
|
-
return r || (t = t.clone(), this._copiedTextures.set(e, t), t.offset = e.offset, t.repeat = e.repeat, t.colorSpace = e.colorSpace, t);
|
|
363
|
+
return r || (t = t.clone(), this._copiedTextures.set(e, t), 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.generateMipmaps = e.generateMipmaps, t);
|
|
364
364
|
}
|
|
365
365
|
};
|
|
366
366
|
let v = M;
|
|
@@ -368,7 +368,7 @@ let v = M;
|
|
|
368
368
|
* Register a texture with LOD information
|
|
369
369
|
*/
|
|
370
370
|
c(v, "registerTexture", (e, t, r, i) => {
|
|
371
|
-
S && console.log("> Progressive: register texture", r, t.name, t.uuid, t, i), t.source && (t.source[
|
|
371
|
+
S && console.log("> Progressive: register texture", r, t.name, t.uuid, t, i), t.source && (t.source[V] = i);
|
|
372
372
|
const n = i.guid;
|
|
373
373
|
M.assignLODInformation(e, t, n, 0, 0, void 0), M.lodInfos.set(n, i), M.lowresCache.set(n, t);
|
|
374
374
|
}), /**
|
|
@@ -486,7 +486,7 @@ const H = ee("debugprogressive"), xe = ee("noprogressive"), b = class {
|
|
|
486
486
|
for (const f of this.plugins)
|
|
487
487
|
(a = f.onBeforeUpdateLOD) == null || a.call(f, this.renderer, e, t, r);
|
|
488
488
|
let n = r.userData.LOD_state;
|
|
489
|
-
n || (n = new
|
|
489
|
+
n || (n = new we(), r.userData.LOD_state = n);
|
|
490
490
|
let s = this.calculateLodLevel(t, r, n, i);
|
|
491
491
|
s = Math.round(s), s >= 0 && this.loadProgressiveMeshes(r, s);
|
|
492
492
|
let o = 0;
|
|
@@ -548,10 +548,10 @@ const H = ee("debugprogressive"), xe = ee("noprogressive"), b = class {
|
|
|
548
548
|
}
|
|
549
549
|
if (this._tempBox.copy(f), this._tempBox.applyMatrix4(t.matrixWorld), this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && p.fov > 70) {
|
|
550
550
|
const L = this._tempBox.min, y = this._tempBox.max;
|
|
551
|
-
let T = L.x,
|
|
552
|
-
const
|
|
553
|
-
T = (T - _) *
|
|
554
|
-
const N = T < 0 && m > 0 ? 0 : Math.min(Math.abs(L.x), Math.abs(y.x)), ae =
|
|
551
|
+
let T = L.x, w = L.y, m = y.x, d = y.y;
|
|
552
|
+
const O = 2, P = 1.5, _ = (L.x + y.x) * 0.5, E = (L.y + y.y) * 0.5;
|
|
553
|
+
T = (T - _) * O + _, w = (w - E) * O + E, m = (m - _) * O + _, d = (d - E) * O + E;
|
|
554
|
+
const N = T < 0 && m > 0 ? 0 : Math.min(Math.abs(L.x), Math.abs(y.x)), ae = w < 0 && d > 0 ? 0 : Math.min(Math.abs(L.y), Math.abs(y.y)), X = Math.max(N, ae);
|
|
555
555
|
r.lastCentrality = (P - X) * (P - X) * (P - X);
|
|
556
556
|
} else
|
|
557
557
|
r.lastCentrality = 1;
|
|
@@ -563,10 +563,10 @@ const H = ee("debugprogressive"), xe = ee("noprogressive"), b = class {
|
|
|
563
563
|
if (Math.max(u.x, u.y) != 0 && G != 0 && (u.z = A.z / Math.max(A.x, A.y) * Math.max(u.x, u.y)), r.lastScreenCoverage = Math.max(u.x, u.y, u.z), r.lastScreenspaceVolume.copy(u), r.lastScreenCoverage *= r.lastCentrality, H && b.debugDrawLine) {
|
|
564
564
|
const L = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
565
565
|
L.invert();
|
|
566
|
-
const y = b.corner0, T = b.corner1,
|
|
567
|
-
y.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = y.x,
|
|
566
|
+
const y = b.corner0, T = b.corner1, w = b.corner2, m = b.corner3;
|
|
567
|
+
y.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = y.x, w.copy(this._tempBox.max), w.y = y.y, m.copy(this._tempBox.max);
|
|
568
568
|
const d = (y.z + m.z) * 0.5;
|
|
569
|
-
y.z = T.z =
|
|
569
|
+
y.z = T.z = w.z = m.z = d, y.applyMatrix4(L), T.applyMatrix4(L), w.applyMatrix4(L), m.applyMatrix4(L), b.debugDrawLine(y, T, 255), b.debugDrawLine(y, w, 255), b.debugDrawLine(T, m, 255), b.debugDrawLine(w, m, 255);
|
|
570
570
|
}
|
|
571
571
|
let k = 999;
|
|
572
572
|
if (g && r.lastScreenCoverage > 0) {
|
|
@@ -586,7 +586,7 @@ let B = b;
|
|
|
586
586
|
/** 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.
|
|
587
587
|
*/
|
|
588
588
|
c(B, "debugDrawLine"), c(B, "corner0", new C()), c(B, "corner1", new C()), c(B, "corner2", new C()), c(B, "corner3", new C());
|
|
589
|
-
class
|
|
589
|
+
class we {
|
|
590
590
|
constructor() {
|
|
591
591
|
c(this, "lastLodLevel", 0);
|
|
592
592
|
c(this, "lastScreenCoverage", 0);
|
|
@@ -595,7 +595,7 @@ class Oe {
|
|
|
595
595
|
}
|
|
596
596
|
}
|
|
597
597
|
const ie = Symbol("NEEDLE_mesh_lod"), $ = Symbol("NEEDLE_texture_lod");
|
|
598
|
-
function
|
|
598
|
+
function Oe(l) {
|
|
599
599
|
if (!l)
|
|
600
600
|
return null;
|
|
601
601
|
let e = null, t = null;
|
|
@@ -684,13 +684,15 @@ function Ce(l, e, t, r) {
|
|
|
684
684
|
return (r == null ? void 0 : r.enableLODsManager) !== !1 && i.enable(), i;
|
|
685
685
|
}
|
|
686
686
|
document.addEventListener("DOMContentLoaded", () => {
|
|
687
|
-
|
|
687
|
+
Oe(document.querySelector("model-viewer"));
|
|
688
688
|
});
|
|
689
689
|
export {
|
|
690
690
|
R as EXTENSION_NAME,
|
|
691
691
|
B as LODsManager,
|
|
692
692
|
v as NEEDLE_progressive,
|
|
693
|
-
|
|
693
|
+
oe as addDracoAndKTX2Loaders,
|
|
694
|
+
ne as createLoaders,
|
|
695
|
+
Oe as patchModelViewer,
|
|
694
696
|
ke as registerPlugin,
|
|
695
697
|
_e as setDracoDecoderLocation,
|
|
696
698
|
Be as setKTX2TranscoderLocation,
|
package/gltf-progressive.min.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var ne=Object.defineProperty,ie=(r,e,t)=>e in r?ne(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,c=(r,e,t)=>(ie(r,typeof e!="symbol"?e+"":e,t),t);import{Mesh as
|
|
2
|
-
`,m),null)),g=!1;if(y==null||(y instanceof C&&r instanceof C?(t=y.image)!=null&&t.data||(o=y.source)!=null&&o.data?y=this.copySettings(r,y):(g=!0,this.previouslyLoaded.delete(u)):y instanceof $&&r instanceof $&&((n=y.attributes.position)!=null&&n.array||(g=!0,this.previouslyLoaded.delete(u)))),!g)return y}const L=l,A=new Promise(async(y,g)=>{const m=new de;
|
|
3
|
-
`,D),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+h,L.guid);let _=0;if(x.parser.json.textures){let D=!1;for(const f of x.parser.json.textures){if(f!=null&&f.extensions){const M=f?.extensions[P];if(M!=null&&M.guid&&M.guid===L.guid){D=!0;break}}_++}if(D){let f=await S.getDependency("texture",_);return s&&console.log('change "'+r.name+'" \u2192 "'+f.name+'"',h,_,f,u),r instanceof C&&(f=this.copySettings(r,f)),f&&(f.guid=L.guid),y(f)}}if(_=0,x.parser.json.meshes){let D=!1;for(const f of x.parser.json.meshes){if(f!=null&&f.extensions){const M=f?.extensions[P];if(M!=null&&M.guid&&M.guid===L.guid){D=!0;break}}_++}if(D){const f=await S.getDependency("mesh",_),M=L;if(s&&console.log(`Loaded Mesh "${f.name}"`,h,_,f,u),f.isMesh===!0){const T=f.geometry;return O.assignLODInformation(a.url,T,i,e,void 0,M.density),y(T)}else{const T=new Array;for(let k=0;k<f.children.length;k++){const W=f.children[k];if(W instanceof U){const j=W.geometry;O.assignLODInformation(a.url,j,i,e,k,M.density),T.push(j)}}return y(T)}}}return y(null)});return this.previouslyLoaded.set(u,A),await A}else if(r instanceof C){s&&console.log("Load texture from uri: "+h);const u=await new le().loadAsync(h);return u?(u.guid=l.guid,u.flipY=!1,u.needsUpdate=!0,u.colorSpace=r.colorSpace,s&&console.log(l,u)):v&&console.warn("failed loading",h),u}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,o,n,s){if(!e)return;e.userData||(e.userData={});const a=new xe(r,t,o,n,s);e.userData.LODS=a,e.userData.LOD=o}static getAssignedLODInformation(r){var e;return((e=r?.userData)==null?void 0:e.LODS)||null}static copySettings(r,e){return this._copiedTextures.get(r)||(e=e.clone(),this._copiedTextures.set(r,e),e.offset=r.offset,e.repeat=r.repeat,e.colorSpace=r.colorSpace,e)}};let w=O;c(w,"registerTexture",(r,e,t,o)=>{v&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,o),e.source&&(e.source[H]=o);const n=o.guid;O.assignLODInformation(r,e,n,0,0,void 0),O.lodInfos.set(n,o),O.lowresCache.set(n,e)}),c(w,"registerMesh",(r,e,t,o,n,s)=>{var a;v&&console.log("> Progressive: register mesh",n,t.name,s,t.uuid,t);const i=t.geometry;i.userData||(i.userData={}),O.assignLODInformation(r,i,e,o,n,s.density),O.lodInfos.set(e,s);let l=O.lowresCache.get(e);l?l.push(t.geometry):l=[t.geometry],O.lowresCache.set(e,l);for(const d of K)(a=d.onRegisteredNewMesh)==null||a.call(d,t,s)}),c(w,"lodInfos",new Map),c(w,"previouslyLoaded",new Map),c(w,"lowresCache",new Map),c(w,"_copiedTextures",new Map);class xe{constructor(e,t,o,n,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=t,this.level=o,n!=null&&(this.index=n),s!=null&&(this.density=s)}}const J=X("debugprogressive"),De=X("noprogressive"),E=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new Q),c(this,"cameraFrustrum",new ue),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"plugins",[]),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new ce),c(this,"_tempBox",new Z),c(this,"tempMatrix",new Q),c(this,"_tempWorldPosition",new B),c(this,"_tempBoxSize",new B),c(this,"_tempBox2Size",new B),this.renderer=r}static getObjectLODState(r){var e;return(e=r.userData)==null?void 0:e.LOD_state}enable(){if(this._originalRender)return;let r=0;this._originalRender=this.renderer.render;const e=this;ee(this.renderer),this.renderer.render=function(t,o){e.renderer.getRenderTarget()==null&&(r=0,e._frame+=1);const n=e._frame,s=r++;e.onBeforeRender(t,o,s,n),e._originalRender.call(this,t,o),e.onAfterRender(t,o,s,n)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(r,e,t,o){}onAfterRender(r,e,t,o){var n,s;if(this.pause)return;const a=this.renderer.renderLists.get(r,0),i=a.opaque;let l=!0;if(i.length===1){const d=i[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(l=!1)}if(l){if(De||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=1e5;for(const u of i){if(u.material&&(((n=u.geometry)==null?void 0:n.type)==="BoxGeometry"||((s=u.geometry)==null?void 0:s.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){J&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}const p=u.object;(p instanceof U||p.isMesh)&&this.updateLODs(r,e,p,d)}const h=a.transparent;for(const u of h){const p=u.object;(p instanceof U||p.isMesh)&&this.updateLODs(r,e,p,d)}}}updateLODs(r,e,t,o){var n,s;for(const d of this.plugins)(n=d.onBeforeUpdateLOD)==null||n.call(d,this.renderer,r,e,t);let a=t.userData.LOD_state;a||(a=new ve,t.userData.LOD_state=a);let i=this.calculateLodLevel(e,t,a,o);i=Math.round(i),i>=0&&this.loadProgressiveMeshes(t,i);let l=0;if(t.material){const d=t["DEBUG:LOD"];if(d!=null&&(l=d),Array.isArray(t.material))for(const h of t.material)this.loadProgressiveTextures(h,l);else this.loadProgressiveTextures(t.material,l)}for(const d of this.plugins)(s=d.onAfterUpdatedLOD)==null||s.call(d,this.renderer,r,e,t,i);a.lastLodLevel=i}loadProgressiveTextures(r,e){return r&&r.userData&&r.userData.LOD!==e?(r.userData.LOD=e,w.assignTextureLOD(r,e)):Promise.resolve(null)}loadProgressiveMeshes(r,e){if(!r)return Promise.resolve(null);if(r.userData||(r.userData={}),r.userData.LOD!==e){r.userData.LOD=e;const t=r.geometry;return w.assignMeshLOD(r,e).then(o=>(o&&r.userData.LOD==e&&t!=r.geometry,o))}return Promise.resolve(null)}calculateLodLevel(r,e,t,o){var n;if(!e)return-1;let s=10+1;if(r){if(J&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=w.getMeshLODInformation(e.geometry),i=a?.lods;if(!i||i.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e)))return 99;const l=e.geometry.boundingBox;if(l&&r.isPerspectiveCamera){const d=r;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 g=r.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g))return 0}if(this._tempBox.copy(l),this._tempBox.applyMatrix4(e.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&d.fov>70){const g=this._tempBox.min,m=this._tempBox.max;let b=g.x,x=g.y,S=m.x,_=m.y;const D=2,f=1.5,M=(g.x+m.x)*.5,T=(g.y+m.y)*.5;b=(b-M)*D+M,x=(x-T)*D+T,S=(S-M)*D+M,_=(_-T)*D+T;const k=b<0&&S>0?0:Math.min(Math.abs(g.x),Math.abs(m.x)),W=x<0&&_>0?0:Math.min(Math.abs(g.y),Math.abs(m.y)),j=Math.max(k,W);t.lastCentrality=(f-j)*(f-j)*(f-j)}else t.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&h.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),h.x*=d.aspect;const u=r.matrixWorldInverse,p=new Z;p.copy(l),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(u);const L=p.getSize(this._tempBox2Size),A=Math.max(L.x,L.y);if(Math.max(h.x,h.y)!=0&&A!=0&&(h.z=L.z/Math.max(L.x,L.y)*Math.max(h.x,h.y)),t.lastScreenCoverage=Math.max(h.x,h.y,h.z),t.lastScreenspaceVolume.copy(h),t.lastScreenCoverage*=t.lastCentrality,J&&E.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const m=E.corner0,b=E.corner1,x=E.corner2,S=E.corner3;m.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=m.x,x.copy(this._tempBox.max),x.y=m.y,S.copy(this._tempBox.max);const _=(m.z+S.z)*.5;m.z=b.z=x.z=S.z=_,m.applyMatrix4(g),b.applyMatrix4(g),x.applyMatrix4(g),S.applyMatrix4(g),E.debugDrawLine(m,b,255),E.debugDrawLine(m,x,255),E.debugDrawLine(b,S,255),E.debugDrawLine(x,S,255)}let y=999;if(i&&t.lastScreenCoverage>0){for(let g=0;g<i.length;g++)if(i[g].density/t.lastScreenCoverage<o){y=g;break}}y<s&&(s=y)}}return s}};let I=E;c(I,"debugDrawLine"),c(I,"corner0",new B),c(I,"corner1",new B),c(I,"corner2",new B),c(I,"corner3",new B);class ve{constructor(){c(this,"lastLodLevel",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const se=Symbol("NEEDLE_mesh_lod"),F=Symbol("NEEDLE_texture_lod");function oe(r){if(!r)return null;let e=null,t=null;for(let o=r;o!=null;o=Object.getPrototypeOf(o)){const n=Object.getOwnPropertySymbols(o),s=n.find(i=>i.toString()=="Symbol(renderer)"),a=n.find(i=>i.toString()=="Symbol(scene)");!e&&s!=null&&(e=r[s].threeRenderer),!t&&a!=null&&(t=r[a])}if(e){console.log("Adding Needle LODs to modelviewer");const o=new I(e);if(o.plugins.push(new Oe(r)),o.enable(),t){const n=t.camera||t.traverse(s=>s.type=="PerspectiveCamera")[0];n&&e.render(t,n)}return()=>{o.disable()}}return null}class Oe{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,t,o,n){this.tryParseMeshLOD(t,n),this.tryParseTextureLOD(t,n)}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[F]==!0)return;t[F]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&t.material){let s=function(i){var l,d,h;if(i[F]==!0)return;i[F]=!0,i.userData&&(i.userData.LOD=-1);const u=Object.keys(i);for(let p=0;p<u.length;p++){const L=u[p],A=i[L];if(A?.isTexture===!0){const y=(d=(l=A.userData)==null?void 0:l.associations)==null?void 0:d.textures,g=o.parser.json.textures[y];if((h=g.extensions)!=null&&h[P]){const m=g.extensions[P];m&&n&&w.registerTexture(n,A,m.lods.length,m)}}}};const a=t.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,t){var o,n;if(t[se]==!0)return;t[se]=!0;const s=this.getUrl();if(!s)return;const a=(n=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:n[P];if(a&&s){const i=t.uuid;w.registerMesh(s,i,t,0,a.lods.length,a)}}}function we(r,e,t,o){ee(e),re(t),t.register(s=>new w(s,r));const n=new I(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{oe(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,w as NEEDLE_progressive,oe as patchModelViewer,Le as registerPlugin,me as setDracoDecoderLocation,pe as setKTX2TranscoderLocation,we as useNeedleProgressive};
|
|
1
|
+
var ne=Object.defineProperty,ie=(r,e,t)=>e in r?ne(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,c=(r,e,t)=>(ie(r,typeof e!="symbol"?e+"":e,t),t);import{Mesh as W,BufferGeometry as $,Material as ae,Texture as C,TextureLoader as le,Matrix4 as ee,Frustum as ue,Sphere as ce,Box3 as re,Vector3 as B}from"three";import{GLTFLoader as de}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as he}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as fe}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as ge}from"three/examples/jsm/loaders/KTX2Loader.js";let U="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",q="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(U+"draco_decoder.js",{method:"head"}).catch(r=>{U="./include/draco/",q="./include/ktx2/"});function me(r){U=r}function pe(r){q=r}let R,V,G;function X(r){R||(R=new fe,R.setDecoderPath(U),R.setDecoderConfig({type:"js"})),G||(G=new ge,G.setTranscoderPath(q)),V||(V=he),r?G.detectSupport(r):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function K(r){r.dracoLoader||r.setDRACOLoader(R),r.ktx2Loader||r.setKTX2Loader(G),r.meshoptDecoder||r.setMeshoptDecoder(V)}function H(r){const e=new URL(window.location.href).searchParams.get(r);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function ye(r,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||r===void 0)return e;const t=r.lastIndexOf("/");if(t>=0){const o=r.substring(0,t+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}const Y=new Array;function Le(r){Y.push(r)}const P="NEEDLE_progressive",v=H("debugprogressive"),J=Symbol("needle-progressive-texture"),N=new Map,Q=new Set;if(v){let r=function(){e+=1,console.log("Toggle LOD level",e,N),N.forEach((n,s)=>{for(const a of n.keys){const i=s[a];if(i.isBufferGeometry===!0){const l=w.getMeshLODInformation(i),d=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=e,w.assignMeshLOD(s,d),l&&(t=Math.max(t,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,w.assignTextureLOD(s,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,o=!1;window.addEventListener("keyup",n=>{n.key==="p"&&r(),n.key==="w"&&(o=!o,Q&&Q.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=o)}))})}function te(r,e,t){var o;if(!v)return;N.has(r)||N.set(r,{keys:[],sourceId:t});const n=N.get(r);((o=n?.keys)==null?void 0:o.includes(e))==!1&&n.keys.push(e)}const O=class{constructor(r,e){c(this,"parser"),c(this,"url"),v&&console.log("Progressive extension registered for",e),this.parser=r,this.url=e}get name(){return P}static getMeshLODInformation(r){const e=this.getAssignedLODInformation(r);return e!=null&&e.key?this.lodInfos.get(e.key):null}static hasLODLevelAvailable(r,e){var t;if(r.isMaterial===!0){for(const s of Object.keys(r)){const a=r[s];if(a.isTexture&&this.hasLODLevelAvailable(a,e))return!0}return!1}else if(r.isGroup===!0){for(const s of r.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let o,n;if(r.isMesh?o=r.geometry:(r.isBufferGeometry||r.isTexture)&&(o=r),o&&(t=o?.userData)!=null&&t.LODS){const s=o.userData.LODS;if(n=this.lodInfos.get(s.key),e===void 0)return n!=null;if(n)return Array.isArray(n.lods)?e<n.lods.length:e===0}return!1}static assignMeshLOD(r,e){var t;if(!r)return Promise.resolve(null);if(r instanceof W||r.isMesh===!0){const o=r.geometry,n=this.getAssignedLODInformation(o);if(!n)return Promise.resolve(null);for(const s of Y)(t=s.onBeforeGetLODMesh)==null||t.call(s,r,e);return r["LOD:requested level"]=e,O.getOrLoadLOD(o,e).then(s=>{if(r["LOD:requested level"]===e){if(delete r["LOD:requested level"],Array.isArray(s)){const a=n.index||0;s=s[a]}s&&o!=s&&s instanceof $&&(r.geometry=s,v&&te(r,"geometry",n.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",r,s),null))}else v&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",r);return Promise.resolve(null)}static assignTextureLOD(r,e=0){if(!r)return Promise.resolve(null);if(r instanceof ae||r.isMaterial===!0){const t=r,o=[],n=new Array;if(v&&Q.add(t),t.uniforms&&t.isRawShaderMaterial||t.isShaderMaterial===!0){const s=t;for(const a of Object.keys(s.uniforms)){const i=s.uniforms[a].value;if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,t,a);o.push(l),n.push(a)}}}else for(const s of Object.keys(t)){const a=t[s];if(a?.isTexture===!0){const i=this.assignTextureLODForSlot(a,e,t,s);o.push(i),n.push(s)}}return Promise.all(o).then(s=>{const a=new Array;for(let i=0;i<s.length;i++){const l=s[i],d=n[i];l&&l.isTexture===!0?a.push({material:t,slot:d,texture:l,level:e}):a.push({material:t,slot:d,texture:null,level:e})}return a})}if(r instanceof C||r.isTexture===!0){const t=r;return this.assignTextureLODForSlot(t,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(r,e,t,o){return r?.isTexture!==!0?Promise.resolve(null):O.getOrLoadLOD(r,e).then(n=>{if(Array.isArray(n))return null;if(n?.isTexture===!0){if(n!=r&&(t&&o&&(t[o]=n),v&&o&&t)){const s=this.getAssignedLODInformation(r);s&&te(t,o,s.url)}return n}else v=="verbose"&&console.warn("No LOD found for",r,e);return null}).catch(n=>(console.error("Error loading LOD",r,n),null))}afterRoot(r){var e,t;return v&&console.log("AFTER",this.url,r),(e=this.parser.json.textures)==null||e.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[P];if(s){let a=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i).textures===n&&(a=!0,O.registerTexture(this.url,i,n,s));a||this.parser.getDependency("texture",n).then(i=>{i&&O.registerTexture(this.url,i,n,s)})}}}),(t=this.parser.json.meshes)==null||t.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.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===n&&O.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(r,e){var t,o,n;const s=v=="verbose",a=r.userData.LODS;if(!a)return null;const i=a?.key;let l;if(r.isTexture===!0){const d=r;d.source&&d.source[J]&&(l=d.source[J])}if(l||(l=O.lodInfos.get(i)),l){if(e>0){let u=!1;const p=Array.isArray(l.lods);if(p&&e>=l.lods.length?u=!0:p||(u=!0),u)return this.lowresCache.get(i)}const d=Array.isArray(l.lods)?l.lods[e].path:l.lods;if(!d)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const h=ye(a.url,d);if(h.endsWith(".glb")||h.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const u=h+"_"+l.guid,p=this.previouslyLoaded.get(u);if(p!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${u}`);let y=await p.catch(m=>(console.error(`Error loading LOD ${e} from ${h}
|
|
2
|
+
`,m),null)),g=!1;if(y==null||(y instanceof C&&r instanceof C?(t=y.image)!=null&&t.data||(o=y.source)!=null&&o.data?y=this.copySettings(r,y):(g=!0,this.previouslyLoaded.delete(u)):y instanceof $&&r instanceof $&&((n=y.attributes.position)!=null&&n.array||(g=!0,this.previouslyLoaded.delete(u)))),!g)return y}const L=l,A=new Promise(async(y,g)=>{const m=new de;K(m),v&&(await new Promise(x=>setTimeout(x,1e3)),s&&console.warn("Start loading (delayed) "+h,L.guid));let b=h;if(L&&Array.isArray(L.lods)){const x=L.lods[e];x.hash&&(b+="?v="+x.hash)}const D=await m.loadAsync(b).catch(x=>(console.error(`Error loading LOD ${e} from ${h}
|
|
3
|
+
`,x),null));if(!D)return null;const S=D.parser;s&&console.log("Loading finished "+h,L.guid);let T=0;if(D.parser.json.textures){let x=!1;for(const f of D.parser.json.textures){if(f!=null&&f.extensions){const M=f?.extensions[P];if(M!=null&&M.guid&&M.guid===L.guid){x=!0;break}}T++}if(x){let f=await S.getDependency("texture",T);return s&&console.log('change "'+r.name+'" \u2192 "'+f.name+'"',h,T,f,u),r instanceof C&&(f=this.copySettings(r,f)),f&&(f.guid=L.guid),y(f)}}if(T=0,D.parser.json.meshes){let x=!1;for(const f of D.parser.json.meshes){if(f!=null&&f.extensions){const M=f?.extensions[P];if(M!=null&&M.guid&&M.guid===L.guid){x=!0;break}}T++}if(x){const f=await S.getDependency("mesh",T),M=L;if(s&&console.log(`Loaded Mesh "${f.name}"`,h,T,f,u),f.isMesh===!0){const _=f.geometry;return O.assignLODInformation(a.url,_,i,e,void 0,M.density),y(_)}else{const _=new Array;for(let k=0;k<f.children.length;k++){const F=f.children[k];if(F instanceof W){const j=F.geometry;O.assignLODInformation(a.url,j,i,e,k,M.density),_.push(j)}}return y(_)}}}return y(null)});return this.previouslyLoaded.set(u,A),await A}else if(r instanceof C){s&&console.log("Load texture from uri: "+h);const u=await new le().loadAsync(h);return u?(u.guid=l.guid,u.flipY=!1,u.needsUpdate=!0,u.colorSpace=r.colorSpace,s&&console.log(l,u)):v&&console.warn("failed loading",h),u}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,o,n,s){if(!e)return;e.userData||(e.userData={});const a=new De(r,t,o,n,s);e.userData.LODS=a,e.userData.LOD=o}static getAssignedLODInformation(r){var e;return((e=r?.userData)==null?void 0:e.LODS)||null}static copySettings(r,e){return this._copiedTextures.get(r)||(e=e.clone(),this._copiedTextures.set(r,e),e.offset=r.offset,e.repeat=r.repeat,e.colorSpace=r.colorSpace,e.magFilter=r.magFilter,e.minFilter=r.minFilter,e.wrapS=r.wrapS,e.wrapT=r.wrapT,e.flipY=r.flipY,e.anisotropy=r.anisotropy,e.generateMipmaps=r.generateMipmaps,e)}};let w=O;c(w,"registerTexture",(r,e,t,o)=>{v&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,o),e.source&&(e.source[J]=o);const n=o.guid;O.assignLODInformation(r,e,n,0,0,void 0),O.lodInfos.set(n,o),O.lowresCache.set(n,e)}),c(w,"registerMesh",(r,e,t,o,n,s)=>{var a;v&&console.log("> Progressive: register mesh",n,t.name,s,t.uuid,t);const i=t.geometry;i.userData||(i.userData={}),O.assignLODInformation(r,i,e,o,n,s.density),O.lodInfos.set(e,s);let l=O.lowresCache.get(e);l?l.push(t.geometry):l=[t.geometry],O.lowresCache.set(e,l);for(const d of Y)(a=d.onRegisteredNewMesh)==null||a.call(d,t,s)}),c(w,"lodInfos",new Map),c(w,"previouslyLoaded",new Map),c(w,"lowresCache",new Map),c(w,"_copiedTextures",new Map);class De{constructor(e,t,o,n,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=t,this.level=o,n!=null&&(this.index=n),s!=null&&(this.density=s)}}const Z=H("debugprogressive"),xe=H("noprogressive"),E=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new ee),c(this,"cameraFrustrum",new ue),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"plugins",[]),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new ce),c(this,"_tempBox",new re),c(this,"tempMatrix",new ee),c(this,"_tempWorldPosition",new B),c(this,"_tempBoxSize",new B),c(this,"_tempBox2Size",new B),this.renderer=r}static getObjectLODState(r){var e;return(e=r.userData)==null?void 0:e.LOD_state}enable(){if(this._originalRender)return;let r=0;this._originalRender=this.renderer.render;const e=this;X(this.renderer),this.renderer.render=function(t,o){e.renderer.getRenderTarget()==null&&(r=0,e._frame+=1);const n=e._frame,s=r++;e.onBeforeRender(t,o,s,n),e._originalRender.call(this,t,o),e.onAfterRender(t,o,s,n)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(r,e,t,o){}onAfterRender(r,e,t,o){var n,s;if(this.pause)return;const a=this.renderer.renderLists.get(r,0),i=a.opaque;let l=!0;if(i.length===1){const d=i[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(l=!1)}if(l){if(xe||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=1e5;for(const u of i){if(u.material&&(((n=u.geometry)==null?void 0:n.type)==="BoxGeometry"||((s=u.geometry)==null?void 0:s.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){Z&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}const p=u.object;(p instanceof W||p.isMesh)&&this.updateLODs(r,e,p,d)}const h=a.transparent;for(const u of h){const p=u.object;(p instanceof W||p.isMesh)&&this.updateLODs(r,e,p,d)}}}updateLODs(r,e,t,o){var n,s;for(const d of this.plugins)(n=d.onBeforeUpdateLOD)==null||n.call(d,this.renderer,r,e,t);let a=t.userData.LOD_state;a||(a=new ve,t.userData.LOD_state=a);let i=this.calculateLodLevel(e,t,a,o);i=Math.round(i),i>=0&&this.loadProgressiveMeshes(t,i);let l=0;if(t.material){const d=t["DEBUG:LOD"];if(d!=null&&(l=d),Array.isArray(t.material))for(const h of t.material)this.loadProgressiveTextures(h,l);else this.loadProgressiveTextures(t.material,l)}for(const d of this.plugins)(s=d.onAfterUpdatedLOD)==null||s.call(d,this.renderer,r,e,t,i);a.lastLodLevel=i}loadProgressiveTextures(r,e){return r&&r.userData&&r.userData.LOD!==e?(r.userData.LOD=e,w.assignTextureLOD(r,e)):Promise.resolve(null)}loadProgressiveMeshes(r,e){if(!r)return Promise.resolve(null);if(r.userData||(r.userData={}),r.userData.LOD!==e){r.userData.LOD=e;const t=r.geometry;return w.assignMeshLOD(r,e).then(o=>(o&&r.userData.LOD==e&&t!=r.geometry,o))}return Promise.resolve(null)}calculateLodLevel(r,e,t,o){var n;if(!e)return-1;let s=10+1;if(r){if(Z&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=w.getMeshLODInformation(e.geometry),i=a?.lods;if(!i||i.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e)))return 99;const l=e.geometry.boundingBox;if(l&&r.isPerspectiveCamera){const d=r;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 g=r.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g))return 0}if(this._tempBox.copy(l),this._tempBox.applyMatrix4(e.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&d.fov>70){const g=this._tempBox.min,m=this._tempBox.max;let b=g.x,D=g.y,S=m.x,T=m.y;const x=2,f=1.5,M=(g.x+m.x)*.5,_=(g.y+m.y)*.5;b=(b-M)*x+M,D=(D-_)*x+_,S=(S-M)*x+M,T=(T-_)*x+_;const k=b<0&&S>0?0:Math.min(Math.abs(g.x),Math.abs(m.x)),F=D<0&&T>0?0:Math.min(Math.abs(g.y),Math.abs(m.y)),j=Math.max(k,F);t.lastCentrality=(f-j)*(f-j)*(f-j)}else t.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&h.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),h.x*=d.aspect;const u=r.matrixWorldInverse,p=new re;p.copy(l),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(u);const L=p.getSize(this._tempBox2Size),A=Math.max(L.x,L.y);if(Math.max(h.x,h.y)!=0&&A!=0&&(h.z=L.z/Math.max(L.x,L.y)*Math.max(h.x,h.y)),t.lastScreenCoverage=Math.max(h.x,h.y,h.z),t.lastScreenspaceVolume.copy(h),t.lastScreenCoverage*=t.lastCentrality,Z&&E.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const m=E.corner0,b=E.corner1,D=E.corner2,S=E.corner3;m.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=m.x,D.copy(this._tempBox.max),D.y=m.y,S.copy(this._tempBox.max);const T=(m.z+S.z)*.5;m.z=b.z=D.z=S.z=T,m.applyMatrix4(g),b.applyMatrix4(g),D.applyMatrix4(g),S.applyMatrix4(g),E.debugDrawLine(m,b,255),E.debugDrawLine(m,D,255),E.debugDrawLine(b,S,255),E.debugDrawLine(D,S,255)}let y=999;if(i&&t.lastScreenCoverage>0){for(let g=0;g<i.length;g++)if(i[g].density/t.lastScreenCoverage<o){y=g;break}}y<s&&(s=y)}}return s}};let I=E;c(I,"debugDrawLine"),c(I,"corner0",new B),c(I,"corner1",new B),c(I,"corner2",new B),c(I,"corner3",new B);class ve{constructor(){c(this,"lastLodLevel",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const se=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function oe(r){if(!r)return null;let e=null,t=null;for(let o=r;o!=null;o=Object.getPrototypeOf(o)){const n=Object.getOwnPropertySymbols(o),s=n.find(i=>i.toString()=="Symbol(renderer)"),a=n.find(i=>i.toString()=="Symbol(scene)");!e&&s!=null&&(e=r[s].threeRenderer),!t&&a!=null&&(t=r[a])}if(e){console.log("Adding Needle LODs to modelviewer");const o=new I(e);if(o.plugins.push(new Oe(r)),o.enable(),t){const n=t.camera||t.traverse(s=>s.type=="PerspectiveCamera")[0];n&&e.render(t,n)}return()=>{o.disable()}}return null}class Oe{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,t,o,n){this.tryParseMeshLOD(t,n),this.tryParseTextureLOD(t,n)}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[z]==!0)return;t[z]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&t.material){let s=function(i){var l,d,h;if(i[z]==!0)return;i[z]=!0,i.userData&&(i.userData.LOD=-1);const u=Object.keys(i);for(let p=0;p<u.length;p++){const L=u[p],A=i[L];if(A?.isTexture===!0){const y=(d=(l=A.userData)==null?void 0:l.associations)==null?void 0:d.textures,g=o.parser.json.textures[y];if((h=g.extensions)!=null&&h[P]){const m=g.extensions[P];m&&n&&w.registerTexture(n,A,m.lods.length,m)}}}};const a=t.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,t){var o,n;if(t[se]==!0)return;t[se]=!0;const s=this.getUrl();if(!s)return;const a=(n=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:n[P];if(a&&s){const i=t.uuid;w.registerMesh(s,i,t,0,a.lods.length,a)}}}function we(r,e,t,o){X(e),K(t),t.register(s=>new w(s,r));const n=new I(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{oe(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,w as NEEDLE_progressive,K as addDracoAndKTX2Loaders,X as createLoaders,oe as patchModelViewer,Le as registerPlugin,me as setDracoDecoderLocation,pe as setKTX2TranscoderLocation,we as useNeedleProgressive};
|