@needle-tools/gltf-progressive 1.0.0-alpha.4 → 1.0.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 +1 -1
- package/{dist/@needle-tools-gltf-progressive.js → gltf-progressive.js} +57 -39
- package/gltf-progressive.min.js +3 -0
- package/gltf-progressive.umd.cjs +3 -0
- package/lib/extension.d.ts +109 -109
- package/lib/extension.js +672 -672
- package/lib/extension.js.map +1 -1
- package/lib/index.d.ts +26 -10
- package/lib/index.js +37 -21
- package/lib/index.js.map +1 -1
- package/lib/loaders.d.ts +4 -4
- package/lib/loaders.js +35 -35
- package/lib/loaders.js.map +1 -1
- package/lib/lods_manager.d.ts +69 -51
- package/lib/lods_manager.js +354 -336
- package/lib/lods_manager.js.map +1 -1
- package/lib/plugins/index.d.ts +2 -2
- package/lib/plugins/index.js +2 -2
- package/lib/plugins/modelviewer.d.ts +4 -15
- package/lib/plugins/modelviewer.js +125 -102
- package/lib/plugins/modelviewer.js.map +1 -1
- package/lib/plugins/plugin.d.ts +24 -14
- package/lib/plugins/plugin.js +11 -4
- package/lib/plugins/plugin.js.map +1 -1
- package/lib/utils.d.ts +2 -2
- package/lib/utils.js +36 -36
- package/lib/utils.js.map +1 -1
- package/package.json +18 -3
- package/dist/@needle-tools-gltf-progressive.min.js +0 -3
- package/dist/@needle-tools-gltf-progressive.umd.cjs +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,8 @@ import { GLTFLoader as ge } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
|
6
6
|
import { MeshoptDecoder as he } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
7
7
|
import { DRACOLoader as pe } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
8
8
|
import { KTX2Loader as ye } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
9
|
-
|
|
9
|
+
const Le = "https://www.gstatic.com/draco/versioned/decoders/1.4.1/", De = "https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";
|
|
10
|
+
let U, V, I;
|
|
10
11
|
function se(l) {
|
|
11
12
|
U || (U = new pe(), U.setDecoderPath(Le), U.setDecoderConfig({ type: "js" })), I || (I = new ye(), I.setTranscoderPath(De)), V || (V = he), l ? I.detectSupport(l) : console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail");
|
|
12
13
|
}
|
|
@@ -14,7 +15,7 @@ function ie(l) {
|
|
|
14
15
|
l.dracoLoader || l.setDRACOLoader(U), l.ktx2Loader || l.setKTX2Loader(I), l.meshoptDecoder || l.setMeshoptDecoder(V);
|
|
15
16
|
}
|
|
16
17
|
function Q(l) {
|
|
17
|
-
|
|
18
|
+
const t = new URL(window.location.href).searchParams.get(l);
|
|
18
19
|
return t == null || t === "0" || t === "false" ? !1 : t === "" ? !0 : t;
|
|
19
20
|
}
|
|
20
21
|
function me(l, e) {
|
|
@@ -257,20 +258,20 @@ const v = class {
|
|
|
257
258
|
const g = L + "_" + s.guid, w = this.previouslyLoaded.get(g);
|
|
258
259
|
if (w !== void 0) {
|
|
259
260
|
r && console.log(`LOD ${t} was already loading/loaded: ${g}`);
|
|
260
|
-
let m = await w.catch((
|
|
261
|
-
`,
|
|
261
|
+
let m = await w.catch((G) => (console.error(`Error loading LOD ${t} from ${L}
|
|
262
|
+
`, G), null)), B = !1;
|
|
262
263
|
if (m == null || (m instanceof z && e instanceof z ? (n = m.image) != null && n.data || (a = m.source) != null && a.data ? m = this.copySettings(e, m) : (B = !0, this.previouslyLoaded.delete(g)) : m instanceof X && e instanceof X && ((d = m.attributes.position) != null && d.array || (B = !0, this.previouslyLoaded.delete(g)))), !B)
|
|
263
264
|
return m;
|
|
264
265
|
}
|
|
265
|
-
const D = s,
|
|
266
|
-
const
|
|
267
|
-
ie(
|
|
266
|
+
const D = s, A = new Promise(async (m, B) => {
|
|
267
|
+
const G = new ge();
|
|
268
|
+
ie(G), S && (await new Promise((p) => setTimeout(p, 1e3)), r && console.warn("Start loading (delayed) " + L, D.guid));
|
|
268
269
|
let y = L;
|
|
269
270
|
if (D && Array.isArray(D.lods)) {
|
|
270
271
|
const p = D.lods[t];
|
|
271
272
|
p.hash && (y += "?v=" + p.hash);
|
|
272
273
|
}
|
|
273
|
-
const h = await
|
|
274
|
+
const h = await G.loadAsync(y).catch((p) => (console.error(`Error loading LOD ${t} from ${L}
|
|
274
275
|
`, p), null));
|
|
275
276
|
if (!h)
|
|
276
277
|
return null;
|
|
@@ -326,7 +327,7 @@ const v = class {
|
|
|
326
327
|
}
|
|
327
328
|
return m(null);
|
|
328
329
|
});
|
|
329
|
-
return this.previouslyLoaded.set(g,
|
|
330
|
+
return this.previouslyLoaded.set(g, A), await A;
|
|
330
331
|
} else if (e instanceof z) {
|
|
331
332
|
r && console.log("Load texture from uri: " + L);
|
|
332
333
|
const w = await new ce().loadAsync(L);
|
|
@@ -389,13 +390,18 @@ class xe {
|
|
|
389
390
|
this.url = e, this.key = t, this.level = r, i != null && (this.index = i), o != null && (this.density = o);
|
|
390
391
|
}
|
|
391
392
|
}
|
|
392
|
-
|
|
393
|
-
const we = Q("noprogressive"), A = class {
|
|
393
|
+
const te = Q("debugprogressive"), we = Q("noprogressive"), P = class {
|
|
394
394
|
constructor(e) {
|
|
395
395
|
u(this, "renderer");
|
|
396
396
|
u(this, "projectionScreenMatrix", new Z());
|
|
397
397
|
u(this, "cameraFrustrum", new fe());
|
|
398
|
+
/**
|
|
399
|
+
* The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 1, the LODs will be updated every second frame, etc.
|
|
400
|
+
*/
|
|
398
401
|
u(this, "updateInterval", 0);
|
|
402
|
+
/**
|
|
403
|
+
* If set to true, the LODsManager will not update the LODs.
|
|
404
|
+
*/
|
|
399
405
|
u(this, "pause", !1);
|
|
400
406
|
u(this, "plugins", []);
|
|
401
407
|
u(this, "_originalRender");
|
|
@@ -408,6 +414,14 @@ const we = Q("noprogressive"), A = class {
|
|
|
408
414
|
u(this, "_tempBox2Size", new C());
|
|
409
415
|
this.renderer = e;
|
|
410
416
|
}
|
|
417
|
+
/** @internal */
|
|
418
|
+
static getObjectLODState(e) {
|
|
419
|
+
var t;
|
|
420
|
+
return (t = e.userData) == null ? void 0 : t.LOD_state;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Enable the LODsManager. This will replace the render method of the renderer with a method that updates the LODs.
|
|
424
|
+
*/
|
|
411
425
|
enable() {
|
|
412
426
|
if (this._originalRender)
|
|
413
427
|
return;
|
|
@@ -435,10 +449,6 @@ const we = Q("noprogressive"), A = class {
|
|
|
435
449
|
(d instanceof Y || d.isMesh) && this.updateLODs(e, t, d, o);
|
|
436
450
|
}
|
|
437
451
|
}
|
|
438
|
-
static getObjectLODState(e) {
|
|
439
|
-
var t;
|
|
440
|
-
return (t = e.userData) == null ? void 0 : t.LOD_state;
|
|
441
|
-
}
|
|
442
452
|
/** Update the LOD levels for the renderer. */
|
|
443
453
|
updateLODs(e, t, r, i) {
|
|
444
454
|
var a, d;
|
|
@@ -518,14 +528,14 @@ const we = Q("noprogressive"), A = class {
|
|
|
518
528
|
g.multiplyScalar(0.5), screen.availHeight > 0 && g.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), g.x *= L.aspect;
|
|
519
529
|
const w = e.matrixWorldInverse, D = new j();
|
|
520
530
|
D.copy(f), D.applyMatrix4(t.matrixWorld), D.applyMatrix4(w);
|
|
521
|
-
const
|
|
522
|
-
if (Math.max(g.x, g.y) != 0 &&
|
|
531
|
+
const A = D.getSize(this._tempBox2Size), E = Math.max(A.x, A.y);
|
|
532
|
+
if (Math.max(g.x, g.y) != 0 && E != 0 && (g.z = A.z / Math.max(A.x, A.y) * Math.max(g.x, g.y)), r.lastScreenCoverage = Math.max(g.x, g.y, g.z), r.lastScreenspaceVolume.copy(g), r.lastScreenCoverage *= r.lastCentrality, te && P.debugDrawLine) {
|
|
523
533
|
const y = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
524
534
|
y.invert();
|
|
525
|
-
const h =
|
|
535
|
+
const h = P.corner0, T = P.corner1, x = P.corner2, p = P.corner3;
|
|
526
536
|
h.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = h.x, x.copy(this._tempBox.max), x.y = h.y, p.copy(this._tempBox.max);
|
|
527
537
|
const c = (h.z + p.z) * 0.5;
|
|
528
|
-
h.z = T.z = x.z = p.z = c, h.applyMatrix4(y), T.applyMatrix4(y), x.applyMatrix4(y), p.applyMatrix4(y),
|
|
538
|
+
h.z = T.z = x.z = p.z = c, h.applyMatrix4(y), T.applyMatrix4(y), x.applyMatrix4(y), p.applyMatrix4(y), P.debugDrawLine(h, T, 255), P.debugDrawLine(h, x, 255), P.debugDrawLine(T, p, 255), P.debugDrawLine(x, p, 255);
|
|
529
539
|
}
|
|
530
540
|
let B = 999;
|
|
531
541
|
if (d && r.lastScreenCoverage > 0) {
|
|
@@ -541,8 +551,10 @@ const we = Q("noprogressive"), A = class {
|
|
|
541
551
|
return s;
|
|
542
552
|
}
|
|
543
553
|
};
|
|
544
|
-
let k =
|
|
545
|
-
|
|
554
|
+
let k = P;
|
|
555
|
+
/** 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.
|
|
556
|
+
*/
|
|
557
|
+
u(k, "debugDrawLine"), u(k, "corner0", new C()), u(k, "corner1", new C()), u(k, "corner2", new C()), u(k, "corner3", new C());
|
|
546
558
|
class Oe {
|
|
547
559
|
constructor() {
|
|
548
560
|
u(this, "lastLodLevel", 0);
|
|
@@ -552,20 +564,26 @@ class Oe {
|
|
|
552
564
|
}
|
|
553
565
|
}
|
|
554
566
|
const re = Symbol("NEEDLE_mesh_lod"), K = Symbol("NEEDLE_texture_lod");
|
|
555
|
-
function ve() {
|
|
556
|
-
const l = document.querySelector("model-viewer");
|
|
567
|
+
function ve(l) {
|
|
557
568
|
if (!l)
|
|
558
|
-
return;
|
|
559
|
-
let e = null;
|
|
560
|
-
for (let
|
|
561
|
-
const i = Object.getOwnPropertySymbols(
|
|
562
|
-
!e &&
|
|
569
|
+
return null;
|
|
570
|
+
let e = null, t = null;
|
|
571
|
+
for (let r = l; r != null; r = Object.getPrototypeOf(r)) {
|
|
572
|
+
const i = Object.getOwnPropertySymbols(r), o = i.find((n) => n.toString() == "Symbol(renderer)"), s = i.find((n) => n.toString() == "Symbol(scene)");
|
|
573
|
+
!e && o != null && (e = l[o].threeRenderer), !t && s != null && (t = l[s]);
|
|
563
574
|
}
|
|
564
575
|
if (e) {
|
|
565
576
|
console.log("Adding Needle LODs to modelviewer");
|
|
566
|
-
const
|
|
567
|
-
|
|
577
|
+
const r = new k(e);
|
|
578
|
+
if (r.plugins.push(new Me(l)), r.enable(), t) {
|
|
579
|
+
const i = t.camera || t.traverse((o) => o.type == "PerspectiveCamera")[0];
|
|
580
|
+
i && e.render(t, i);
|
|
581
|
+
}
|
|
582
|
+
return () => {
|
|
583
|
+
r.disable();
|
|
584
|
+
};
|
|
568
585
|
}
|
|
586
|
+
return null;
|
|
569
587
|
}
|
|
570
588
|
class Me {
|
|
571
589
|
constructor(e) {
|
|
@@ -600,9 +618,9 @@ class Me {
|
|
|
600
618
|
for (let g = 0; g < a.length; g++) {
|
|
601
619
|
const w = a[g], D = n[w];
|
|
602
620
|
if ((D == null ? void 0 : D.isTexture) === !0) {
|
|
603
|
-
const
|
|
604
|
-
if ((L =
|
|
605
|
-
const m =
|
|
621
|
+
const A = (f = (d = D.userData) == null ? void 0 : d.associations) == null ? void 0 : f.textures, E = r.parser.json.textures[A];
|
|
622
|
+
if ((L = E.extensions) != null && L[R]) {
|
|
623
|
+
const m = E.extensions[R];
|
|
606
624
|
m && i && M.registerTexture(i, D, m.lods.length, m);
|
|
607
625
|
}
|
|
608
626
|
}
|
|
@@ -633,13 +651,13 @@ class Me {
|
|
|
633
651
|
}
|
|
634
652
|
}
|
|
635
653
|
}
|
|
636
|
-
function Be(l, e, t) {
|
|
637
|
-
se(e), ie(t), t.register((
|
|
638
|
-
const
|
|
639
|
-
return r.enable(),
|
|
654
|
+
function Be(l, e, t, r) {
|
|
655
|
+
se(e), ie(t), t.register((o) => new M(o, l));
|
|
656
|
+
const i = new k(e);
|
|
657
|
+
return (r == null ? void 0 : r.enableLODsManager) !== !1 && i.enable(), i;
|
|
640
658
|
}
|
|
641
659
|
document.addEventListener("DOMContentLoaded", () => {
|
|
642
|
-
ve();
|
|
660
|
+
ve(document.querySelector("model-viewer"));
|
|
643
661
|
});
|
|
644
662
|
export {
|
|
645
663
|
R as EXTENSION_NAME,
|
|
@@ -647,5 +665,5 @@ export {
|
|
|
647
665
|
M as NEEDLE_progressive,
|
|
648
666
|
ve as patchModelViewer,
|
|
649
667
|
ke as registerPlugin,
|
|
650
|
-
Be as
|
|
668
|
+
Be as useNeedleProgressive
|
|
651
669
|
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var se=Object.defineProperty,ne=(r,e,t)=>e in r?se(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,u=(r,e,t)=>(ne(r,typeof e!="symbol"?e+"":e,t),t);import{Mesh as W,BufferGeometry as U,Material as oe,RawShaderMaterial as ie,Texture as C,TextureLoader as ae,Matrix4 as K,Frustum as le,Sphere as ue,Box3 as Y,Vector3 as E}from"three";import{GLTFLoader as ce}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as de}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as he}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as fe}from"three/examples/jsm/loaders/KTX2Loader.js";const ge="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",pe="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";let R,$,G;function J(r){R||(R=new he,R.setDecoderPath(ge),R.setDecoderConfig({type:"js"})),G||(G=new fe,G.setTranscoderPath(pe)),$||($=de),r?G.detectSupport(r):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function Q(r){r.dracoLoader||r.setDRACOLoader(R),r.ktx2Loader||r.setKTX2Loader(G),r.meshoptDecoder||r.setMeshoptDecoder($)}function q(r){const e=new URL(window.location.href).searchParams.get(r);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function me(r,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||r===void 0)return e;const t=r.lastIndexOf("/");if(t>=0){const n=r.substring(0,t+1);for(;n.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return n+e}return e}const V=new Array;function ye(r){V.push(r)}const B="NEEDLE_progressive",v=q("debugprogressive"),X=Symbol("needle-progressive-texture"),z=new Map,H=new Set;if(v){let r=function(){e+=1,console.log("Toggle LOD level",e,z),z.forEach((o,s)=>{for(const i of o.keys){const a=s[i];if(a.isBufferGeometry===!0){const l=O.getMeshLODInformation(a),d=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=d,O.assignMeshLOD(s,d),l&&(t=Math.max(t,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,O.assignTextureLOD(s,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,n=!1;window.addEventListener("keyup",o=>{o.key==="p"&&r(),o.key==="w"&&(n=!n,H&&H.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=n)}))})}function Z(r,e,t){var n;if(!v)return;z.has(r)||z.set(r,{keys:[],sourceId:t});const o=z.get(r);((n=o?.keys)==null?void 0:n.includes(e))==!1&&o.keys.push(e)}const L=class{constructor(r,e){u(this,"parser"),u(this,"url"),v&&console.log("Progressive extension registered for",e),this.parser=r,this.url=e}get name(){return B}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 i=r[s];if(i.isTexture&&this.hasLODLevelAvailable(i,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 n,o;if(r.isMesh?n=r.geometry:(r.isBufferGeometry||r.isTexture)&&(n=r),n&&(t=n?.userData)!=null&&t.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(r,e){var t;if(!r)return Promise.resolve(null);if(r instanceof W||r.isMesh===!0){const n=r.geometry,o=this.getAssignedLODInformation(n);if(!o)return Promise.resolve(null);for(const s of V)(t=s.onBeforeGetLODMesh)==null||t.call(s,r,e);return r["LOD:requested level"]=e,L.getOrLoadLOD(n,e).then(s=>{if(r["LOD:requested level"]===e){if(delete r["LOD:requested level"],Array.isArray(s)){const i=o.index||0;s=s[i]}s&&n!=s&&s instanceof U&&(r.geometry=s,v&&Z(r,"geometry",o.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 oe||r.isMaterial===!0){const t=r,n=[],o=new Array;if(v&&H.add(t),t instanceof ie)for(const s of Object.keys(t.uniforms)){const i=t.uniforms[s].value;if(i?.isTexture===!0){const a=this.assignTextureLODForSlot(i,e,t,s);n.push(a),o.push(s)}}else for(const s of Object.keys(t)){const i=t[s];if(i?.isTexture===!0){const a=this.assignTextureLODForSlot(i,e,t,s);n.push(a),o.push(s)}}return Promise.all(n).then(s=>{const i=new Array;for(let a=0;a<s.length;a++){const l=s[a],d=o[a];l&&l.isTexture===!0?i.push({material:t,slot:d,texture:l,level:e}):i.push({material:t,slot:d,texture:null,level:e})}return i})}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,n){return r?.isTexture!==!0?Promise.resolve(null):L.getOrLoadLOD(r,e).then(o=>{if(Array.isArray(o))return null;if(o?.isTexture===!0){if(o!=r&&(t&&n&&(t[n]=o),v&&n&&t)){const s=this.getAssignedLODInformation(r);s&&Z(t,n,s.url)}return o}else v=="verbose"&&console.warn("No LOD found for",r,e);return null}).catch(o=>(console.error("Error loading LOD",r,o),null))}afterRoot(r){var e,t;return v&&console.log("AFTER",this.url,r),(e=this.parser.json.textures)==null||e.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[B];if(s){let i=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===o&&(i=!0,L.registerTexture(this.url,a,o,s));i||this.parser.getDependency("texture",o).then(a=>{a&&L.registerTexture(this.url,a,o,s)})}}}),(t=this.parser.json.meshes)==null||t.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[B];if(s&&s.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const a=this.parser.associations.get(i);a.meshes===o&&L.registerMesh(this.url,i.uuid,i,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(r,e){var t,n,o;const s=v=="verbose",i=r.userData.LODS;if(!i)return null;const a=i?.key;let l;if(r.isTexture===!0){const d=r;d.source&&d.source[X]&&(l=d.source[X])}if(l||(l=L.lodInfos.get(a)),l){if(e>0){let g=!1;const M=Array.isArray(l.lods);if(M&&e>=l.lods.length?g=!0:M||(g=!0),g)return this.lowresCache.get(a)}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 c=me(i.url,d);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const g=c+"_"+l.guid,M=this.previouslyLoaded.get(g);if(M!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${g}`);let m=await M.catch(p=>(console.error(`Error loading LOD ${e} from ${c}
|
|
2
|
+
`,p),null)),f=!1;if(m==null||(m instanceof C&&r instanceof C?(t=m.image)!=null&&t.data||(n=m.source)!=null&&n.data?m=this.copySettings(r,m):(f=!0,this.previouslyLoaded.delete(g)):m instanceof U&&r instanceof U&&((o=m.attributes.position)!=null&&o.array||(f=!0,this.previouslyLoaded.delete(g)))),!f)return m}const y=l,P=new Promise(async(m,f)=>{const p=new ce;Q(p),v&&(await new Promise(D=>setTimeout(D,1e3)),s&&console.warn("Start loading (delayed) "+c,y.guid));let b=c;if(y&&Array.isArray(y.lods)){const D=y.lods[e];D.hash&&(b+="?v="+D.hash)}const x=await p.loadAsync(b).catch(D=>(console.error(`Error loading LOD ${e} from ${c}
|
|
3
|
+
`,D),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+c,y.guid);let T=0;if(x.parser.json.textures){let D=!1;for(const h of x.parser.json.textures){if(h!=null&&h.extensions){const w=h?.extensions[B];if(w!=null&&w.guid&&w.guid===y.guid){D=!0;break}}T++}if(D){let h=await S.getDependency("texture",T);return s&&console.log('change "'+r.name+'" \u2192 "'+h.name+'"',c,T,h,g),r instanceof C&&(h=this.copySettings(r,h)),h&&(h.guid=y.guid),m(h)}}if(T=0,x.parser.json.meshes){let D=!1;for(const h of x.parser.json.meshes){if(h!=null&&h.extensions){const w=h?.extensions[B];if(w!=null&&w.guid&&w.guid===y.guid){D=!0;break}}T++}if(D){const h=await S.getDependency("mesh",T),w=y;if(s&&console.log(`Loaded Mesh "${h.name}"`,c,T,h,g),h.isMesh===!0){const _=h.geometry;return L.assignLODInformation(i.url,_,a,e,void 0,w.density),m(_)}else{const _=new Array;for(let I=0;I<h.children.length;I++){const F=h.children[I];if(F instanceof W){const j=F.geometry;L.assignLODInformation(i.url,j,a,e,I,w.density),_.push(j)}}return m(_)}}}return m(null)});return this.previouslyLoaded.set(g,P),await P}else if(r instanceof C){s&&console.log("Load texture from uri: "+c);const g=await new ae().loadAsync(c);return g?(g.guid=l.guid,g.flipY=!1,g.needsUpdate=!0,g.colorSpace=r.colorSpace,s&&console.log(l,g)):v&&console.warn("failed loading",c),g}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${a}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,n,o,s){if(!e)return;e.userData||(e.userData={});const i=new xe(r,t,n,o,s);e.userData.LODS=i,e.userData.LOD=n}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 O=L;u(O,"registerTexture",(r,e,t,n)=>{v&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,n),e.source&&(e.source[X]=n);const o=e.uuid;L.assignLODInformation(r,e,o,0,0,void 0),L.lodInfos.set(o,n),L.lowresCache.set(o,e)}),u(O,"registerMesh",(r,e,t,n,o,s)=>{var i;v&&console.log("> Progressive: register mesh",o,t.name,s,t.uuid,t);const a=t.geometry;a.userData||(a.userData={}),L.assignLODInformation(r,a,e,n,o,s.density),L.lodInfos.set(e,s);let l=L.lowresCache.get(e);l?l.push(t.geometry):l=[t.geometry],L.lowresCache.set(e,l);for(const d of V)(i=d.onRegisteredNewMesh)==null||i.call(d,t,s)}),u(O,"lodInfos",new Map),u(O,"previouslyLoaded",new Map),u(O,"lowresCache",new Map),u(O,"_copiedTextures",new Map);class xe{constructor(e,t,n,o,s){u(this,"url"),u(this,"key"),u(this,"level"),u(this,"index"),u(this,"density"),this.url=e,this.key=t,this.level=n,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const ee=q("debugprogressive"),De=q("noprogressive"),A=class{constructor(r){u(this,"renderer"),u(this,"projectionScreenMatrix",new K),u(this,"cameraFrustrum",new le),u(this,"updateInterval",0),u(this,"pause",!1),u(this,"plugins",[]),u(this,"_originalRender"),u(this,"_sphere",new ue),u(this,"_tempBox",new Y),u(this,"tempMatrix",new K),u(this,"_tempWorldPosition",new E),u(this,"_tempBoxSize",new E),u(this,"_tempBox2Size",new E),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;let t=0;J(this.renderer),this.renderer.render=function(n,o){const s=t++,i=r++;e.onBeforeRender(n,o,i,s),e._originalRender.call(this,n,o),e.onAfterRender(n,o,i,s),r--}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(r,e,t,n){}onAfterRender(r,e,t,n){if(De||this.pause||this.updateInterval>0&&n%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const o=1e5,s=this.renderer.renderLists.get(r,t).opaque;for(const i of s){const a=i.object;(a instanceof W||a.isMesh)&&this.updateLODs(r,e,a,o)}}updateLODs(r,e,t,n){var o,s;for(const d of this.plugins)(o=d.onBeforeUpdateLOD)==null||o.call(d,this.renderer,r,e,t);let i=t.userData.LOD_state;i||(i=new ve,t.userData.LOD_state=i);let a=this.calculateLodLevel(e,t,i,n);a=Math.round(a),a>=0&&this.loadProgressiveMeshes(t,a);let l=0;if(t.material){const d=t["DEBUG:LOD"];if(d!=null&&(l=d),Array.isArray(t.material))for(const c of t.material)this.loadProgressiveTextures(c,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,a);i.lastLodLevel=a}loadProgressiveTextures(r,e){return r&&r.userData&&r.userData.LOD!==e?(r.userData.LOD=e,O.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 O.assignMeshLOD(r,e).then(n=>(n&&r.userData.LOD==e&&t!=r.geometry,n))}return Promise.resolve(null)}calculateLodLevel(r,e,t,n){var o;if(!e)return-1;let s=10+1;if(r){if(ee&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const i=O.getMeshLODInformation(e.geometry),a=i?.lods;if(!a||a.length<=0||!((o=this.cameraFrustrum)!=null&&o.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 f=r.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(f))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 f=this._tempBox.min,p=this._tempBox.max;let b=f.x,x=f.y,S=p.x,T=p.y;const D=2,h=1.5,w=(f.x+p.x)*.5,_=(f.y+p.y)*.5;b=(b-w)*D+w,x=(x-_)*D+_,S=(S-w)*D+w,T=(T-_)*D+_;const I=b<0&&S>0?0:Math.min(Math.abs(f.x),Math.abs(p.x)),F=x<0&&T>0?0:Math.min(Math.abs(f.y),Math.abs(p.y)),j=Math.max(I,F);t.lastCentrality=(h-j)*(h-j)*(h-j)}else t.lastCentrality=1;const c=this._tempBox.getSize(this._tempBoxSize);c.multiplyScalar(.5),screen.availHeight>0&&c.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),c.x*=d.aspect;const g=r.matrixWorldInverse,M=new Y;M.copy(l),M.applyMatrix4(e.matrixWorld),M.applyMatrix4(g);const y=M.getSize(this._tempBox2Size),P=Math.max(y.x,y.y);if(Math.max(c.x,c.y)!=0&&P!=0&&(c.z=y.z/Math.max(y.x,y.y)*Math.max(c.x,c.y)),t.lastScreenCoverage=Math.max(c.x,c.y,c.z),t.lastScreenspaceVolume.copy(c),t.lastScreenCoverage*=t.lastCentrality,ee&&A.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const p=A.corner0,b=A.corner1,x=A.corner2,S=A.corner3;p.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=p.x,x.copy(this._tempBox.max),x.y=p.y,S.copy(this._tempBox.max);const T=(p.z+S.z)*.5;p.z=b.z=x.z=S.z=T,p.applyMatrix4(f),b.applyMatrix4(f),x.applyMatrix4(f),S.applyMatrix4(f),A.debugDrawLine(p,b,255),A.debugDrawLine(p,x,255),A.debugDrawLine(b,S,255),A.debugDrawLine(x,S,255)}let m=999;if(a&&t.lastScreenCoverage>0){for(let f=0;f<a.length;f++)if(a[f].density/t.lastScreenCoverage<n){m=f;break}}m<s&&(s=m)}}return s}};let k=A;u(k,"debugDrawLine"),u(k,"corner0",new E),u(k,"corner1",new E),u(k,"corner2",new E),u(k,"corner3",new E);class ve{constructor(){u(this,"lastLodLevel",0),u(this,"lastScreenCoverage",0),u(this,"lastScreenspaceVolume",new E),u(this,"lastCentrality",0)}}const re=Symbol("NEEDLE_mesh_lod"),N=Symbol("NEEDLE_texture_lod");function te(r){if(!r)return null;let e=null,t=null;for(let n=r;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=r[s].threeRenderer),!t&&i!=null&&(t=r[i])}if(e){console.log("Adding Needle LODs to modelviewer");const n=new k(e);if(n.plugins.push(new Le(r)),n.enable(),t){const o=t.camera||t.traverse(s=>s.type=="PerspectiveCamera")[0];o&&e.render(t,o)}return()=>{n.disable()}}return null}class Le{constructor(e){u(this,"modelviewer"),this.modelviewer=e}onBeforeUpdateLOD(e,t,n,o){this.tryParseMeshLOD(t,o),this.tryParseTextureLOD(t,o)}getUrl(){return this.modelviewer.getAttribute("src")}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[N]==!0)return;t[N]=!0;const n=this.tryGetCurrentGLTF(e),o=this.getUrl();if(!o){console.error("No url found in modelviewer");return}if(n&&t.material){let s=function(a){var l,d,c;if(a[N]==!0)return;a[N]=!0,a.userData&&(a.userData.LOD=-1);const g=Object.keys(a);for(let M=0;M<g.length;M++){const y=g[M],P=a[y];if(P?.isTexture===!0){const m=(d=(l=P.userData)==null?void 0:l.associations)==null?void 0:d.textures,f=n.parser.json.textures[m];if((c=f.extensions)!=null&&c[B]){const p=f.extensions[B];p&&o&&O.registerTexture(o,P,p.lods.length,p)}}}};const i=t.material;if(Array.isArray(i))for(const a of i)s(a);else s(i)}}tryParseMeshLOD(e,t){var n,o;if(t[re]==!0)return;t[re]=!0;const s=this.getUrl();if(!s){console.error("No url found in modelviewer");return}const i=(o=(n=t.userData)==null?void 0:n.gltfExtensions)==null?void 0:o[B];if(i&&s){const a=t.uuid;O.registerMesh(s,a,t,0,i.lods.length,i)}}}function Oe(r,e,t,n){J(e),Q(t),t.register(s=>new O(s,r));const o=new k(e);return n?.enableLODsManager!==!1&&o.enable(),o}document.addEventListener("DOMContentLoaded",()=>{te(document.querySelector("model-viewer"))});export{B as EXTENSION_NAME,k as LODsManager,O as NEEDLE_progressive,te as patchModelViewer,ye as registerPlugin,Oe as useNeedleProgressive};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";var re=Object.defineProperty;var se=(l,e,t)=>e in l?re(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var u=(l,e,t)=>(se(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("three"),ie=require("three/examples/jsm/loaders/GLTFLoader.js"),oe=require("three/examples/jsm/libs/meshopt_decoder.module.js"),ne=require("three/examples/jsm/loaders/DRACOLoader.js"),ae=require("three/examples/jsm/loaders/KTX2Loader.js"),le="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ue="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";let z,$,U;function Z(l){z||(z=new ne.DRACOLoader,z.setDecoderPath(le),z.setDecoderConfig({type:"js"})),U||(U=new ae.KTX2Loader,U.setTranscoderPath(ue)),$||($=oe.MeshoptDecoder),l?U.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function j(l){l.dracoLoader||l.setDRACOLoader(z),l.ktx2Loader||l.setKTX2Loader(U),l.meshoptDecoder||l.setMeshoptDecoder($)}function Y(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function ce(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}const X=new Array;function fe(l){X.push(l)}const k="NEEDLE_progressive",T=Y("debugprogressive"),V=Symbol("needle-progressive-texture"),I=new Map,K=new Set;if(T){let l=function(){e+=1,console.log("Toggle LOD level",e,I),I.forEach((i,o)=>{for(const s of i.keys){const n=o[s];if(n.isBufferGeometry===!0){const a=w.getMeshLODInformation(n),d=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=d,w.assignMeshLOD(o,d),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,w.assignTextureLOD(o,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",i=>{i.key==="p"&&l(),i.key==="w"&&(r=!r,K&&K.forEach(o=>{o.name!="BackgroundCubeMaterial"&&"wireframe"in o&&(o.wireframe=r)}))})}function H(l,e,t){var i;if(!T)return;I.has(l)||I.set(l,{keys:[],sourceId:t});const r=I.get(l);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const S=class{constructor(e,t){u(this,"parser");u(this,"url");T&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return k}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static hasLODLevelAvailable(e,t){var o;if(e.isMaterial===!0){for(const s of Object.keys(e)){const n=e[s];if(n.isTexture&&this.hasLODLevelAvailable(n,t))return!0}return!1}else if(e.isGroup===!0){for(const s of e.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,t))return!0}let r,i;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const s=r.userData.LODS;if(i=this.lodInfos.get(s.key),t===void 0)return i!=null;if(i)return Array.isArray(i.lods)?t<i.lods.length:t===0}return!1}static assignMeshLOD(e,t){var r;if(!e)return Promise.resolve(null);if(e instanceof h.Mesh||e.isMesh===!0){const i=e.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of X)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,S.getOrLoadLOD(i,t).then(s=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(s)){const n=o.index||0;s=s[n]}s&&i!=s&&s instanceof h.BufferGeometry&&(e.geometry=s,T&&H(e,"geometry",o.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",e,s),null))}else T&&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 h.Material||e.isMaterial===!0){const r=e,i=[],o=new Array;if(T&&K.add(r),r instanceof h.RawShaderMaterial)for(const s of Object.keys(r.uniforms)){const n=r.uniforms[s].value;if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,t,r,s);i.push(a),o.push(s)}}else for(const s of Object.keys(r)){const n=r[s];if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,t,r,s);i.push(a),o.push(s)}}return Promise.all(i).then(s=>{const n=new Array;for(let a=0;a<s.length;a++){const d=s[a],f=o[a];d&&d.isTexture===!0?n.push({material:r,slot:f,texture:d,level:t}):n.push({material:r,slot:f,texture:null,level:t})}return n})}if(e instanceof h.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,i){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):S.getOrLoadLOD(e,t).then(o=>{if(Array.isArray(o))return null;if((o==null?void 0:o.isTexture)===!0){if(o!=e&&(r&&i&&(r[i]=o),T&&i&&r)){const s=this.getAssignedLODInformation(e);s&&H(r,i,s.url)}return o}else T=="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 T&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[k];if(s){let n=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===o&&(n=!0,S.registerTexture(this.url,a,o,s));n||this.parser.getDependency("texture",o).then(a=>{a&&S.registerTexture(this.url,a,o,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[k];if(s&&s.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const a=this.parser.associations.get(n);a.meshes===o&&S.registerMesh(this.url,n.uuid,n,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var n,a,d;const r=T=="verbose",i=e.userData.LODS;if(!i)return null;const o=i==null?void 0:i.key;let s;if(e.isTexture===!0){const f=e;f.source&&f.source[V]&&(s=f.source[V])}if(s||(s=S.lodInfos.get(o)),s){if(t>0){let g=!1;const M=Array.isArray(s.lods);if(M&&t>=s.lods.length?g=!0:M||(g=!0),g)return this.lowresCache.get(o)}const f=Array.isArray(s.lods)?s.lods[t].path:s.lods;if(!f)return T&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const D=ce(i.url,f);if(D.endsWith(".glb")||D.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const g=D+"_"+s.guid,M=this.previouslyLoaded.get(g);if(M!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${g}`);let m=await M.catch(F=>(console.error(`Error loading LOD ${t} from ${D}
|
|
2
|
+
`,F),null)),R=!1;if(m==null||(m instanceof h.Texture&&e instanceof h.Texture?(n=m.image)!=null&&n.data||(a=m.source)!=null&&a.data?m=this.copySettings(e,m):(R=!0,this.previouslyLoaded.delete(g)):m instanceof h.BufferGeometry&&e instanceof h.BufferGeometry&&((d=m.attributes.position)!=null&&d.array||(R=!0,this.previouslyLoaded.delete(g)))),!R)return m}const x=s,b=new Promise(async(m,R)=>{const F=new ie.GLTFLoader;j(F),T&&(await new Promise(y=>setTimeout(y,1e3)),r&&console.warn("Start loading (delayed) "+D,x.guid));let L=D;if(x&&Array.isArray(x.lods)){const y=x.lods[t];y.hash&&(L+="?v="+y.hash)}const p=await F.loadAsync(L).catch(y=>(console.error(`Error loading LOD ${t} from ${D}
|
|
3
|
+
`,y),null));if(!p)return null;const P=p.parser;r&&console.log("Loading finished "+D,x.guid);let O=0;if(p.parser.json.textures){let y=!1;for(const c of p.parser.json.textures){if(c!=null&&c.extensions){const v=c==null?void 0:c.extensions[k];if(v!=null&&v.guid&&v.guid===x.guid){y=!0;break}}O++}if(y){let c=await P.getDependency("texture",O);return r&&console.log('change "'+e.name+'" → "'+c.name+'"',D,O,c,g),e instanceof h.Texture&&(c=this.copySettings(e,c)),c&&(c.guid=x.guid),m(c)}}if(O=0,p.parser.json.meshes){let y=!1;for(const c of p.parser.json.meshes){if(c!=null&&c.extensions){const v=c==null?void 0:c.extensions[k];if(v!=null&&v.guid&&v.guid===x.guid){y=!0;break}}O++}if(y){const c=await P.getDependency("mesh",O),v=x;if(r&&console.log(`Loaded Mesh "${c.name}"`,D,O,c,g),c.isMesh===!0){const B=c.geometry;return S.assignLODInformation(i.url,B,o,t,void 0,v.density),m(B)}else{const B=new Array;for(let C=0;C<c.children.length;C++){const E=c.children[C];if(E instanceof h.Mesh){const N=E.geometry;S.assignLODInformation(i.url,N,o,t,C,v.density),B.push(N)}}return m(B)}}}return m(null)});return this.previouslyLoaded.set(g,b),await b}else if(e instanceof h.Texture){r&&console.log("Load texture from uri: "+D);const M=await new h.TextureLoader().loadAsync(D);return M?(M.guid=s.guid,M.flipY=!1,M.needsUpdate=!0,M.colorSpace=e.colorSpace,r&&console.log(s,M)):T&&console.warn("failed loading",D),M}}else T&&console.warn(`Can not load LOD ${t}: no LOD info found for "${o}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,i,o,s){if(!t)return;t.userData||(t.userData={});const n=new de(e,r,i,o,s);t.userData.LODS=n,t.userData.LOD=i}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){const r=this._copiedTextures.get(e);return r||(t=t.clone(),this._copiedTextures.set(e,t),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t)}};let w=S;u(w,"registerTexture",(e,t,r,i)=>{T&&console.log("> Progressive: register texture",r,t.name,t.uuid,t,i),t.source&&(t.source[V]=i);const o=t.uuid;S.assignLODInformation(e,t,o,0,0,void 0),S.lodInfos.set(o,i),S.lowresCache.set(o,t)}),u(w,"registerMesh",(e,t,r,i,o,s)=>{var d;T&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const n=r.geometry;n.userData||(n.userData={}),S.assignLODInformation(e,n,t,i,o,s.density),S.lodInfos.set(t,s);let a=S.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],S.lowresCache.set(t,a);for(const f of X)(d=f.onRegisteredNewMesh)==null||d.call(f,r,s)}),u(w,"lodInfos",new Map),u(w,"previouslyLoaded",new Map),u(w,"lowresCache",new Map),u(w,"_copiedTextures",new Map);class de{constructor(e,t,r,i,o){u(this,"url");u(this,"key");u(this,"level");u(this,"index");u(this,"density");this.url=e,this.key=t,this.level=r,i!=null&&(this.index=i),o!=null&&(this.density=o)}}const J=Y("debugprogressive"),ge=Y("noprogressive"),A=class{constructor(e){u(this,"renderer");u(this,"projectionScreenMatrix",new h.Matrix4);u(this,"cameraFrustrum",new h.Frustum);u(this,"updateInterval",0);u(this,"pause",!1);u(this,"plugins",[]);u(this,"_originalRender");u(this,"_sphere",new h.Sphere);u(this,"_tempBox",new h.Box3);u(this,"tempMatrix",new h.Matrix4);u(this,"_tempWorldPosition",new h.Vector3);u(this,"_tempBoxSize",new h.Vector3);u(this,"_tempBox2Size",new h.Vector3);this.renderer=e}static getObjectLODState(e){var t;return(t=e.userData)==null?void 0:t.LOD_state}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;let r=0;Z(this.renderer),this.renderer.render=function(i,o){const s=r++,n=e++;t.onBeforeRender(i,o,n,s),t._originalRender.call(this,i,o),t.onAfterRender(i,o,n,s),e--}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){if(ge||this.pause||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const o=1e5,n=this.renderer.renderLists.get(e,r).opaque;for(const a of n){const d=a.object;(d instanceof h.Mesh||d.isMesh)&&this.updateLODs(e,t,d,o)}}updateLODs(e,t,r,i){var a,d;for(const f of this.plugins)(a=f.onBeforeUpdateLOD)==null||a.call(f,this.renderer,e,t,r);let o=r.userData.LOD_state;o||(o=new he,r.userData.LOD_state=o);let s=this.calculateLodLevel(t,r,o,i);s=Math.round(s),s>=0&&this.loadProgressiveMeshes(r,s);let n=0;if(r.material){const f=r["DEBUG:LOD"];if(f!=null&&(n=f),Array.isArray(r.material))for(const D of r.material)this.loadProgressiveTextures(D,n);else this.loadProgressiveTextures(r.material,n)}for(const f of this.plugins)(d=f.onAfterUpdatedLOD)==null||d.call(f,this.renderer,e,t,r,s);o.lastLodLevel=s}loadProgressiveTextures(e,t){return e&&e.userData&&e.userData.LOD!==t?(e.userData.LOD=t,w.assignTextureLOD(e,t)):Promise.resolve(null)}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 w.assignMeshLOD(e,t).then(i=>(i&&e.userData.LOD==t&&r!=e.geometry,i))}return Promise.resolve(null)}calculateLodLevel(e,t,r,i){var n;if(!t)return-1;let s=10+1;if(e){if(J&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=w.getMeshLODInformation(t.geometry),d=a==null?void 0:a.lods;if(!d||d.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(t)))return 99;const f=t.geometry.boundingBox;if(f&&e.isPerspectiveCamera){const D=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))return 0}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(t.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&D.fov>70){const L=this._tempBox.min,p=this._tempBox.max;let P=L.x,O=L.y,y=p.x,c=p.y;const v=2,B=1.5,C=(L.x+p.x)*.5,E=(L.y+p.y)*.5;P=(P-C)*v+C,O=(O-E)*v+E,y=(y-C)*v+C,c=(c-E)*v+E;const N=P<0&&y>0?0:Math.min(Math.abs(L.x),Math.abs(p.x)),te=O<0&&c>0?0:Math.min(Math.abs(L.y),Math.abs(p.y)),q=Math.max(N,te);r.lastCentrality=(B-q)*(B-q)*(B-q)}else r.lastCentrality=1;const g=this._tempBox.getSize(this._tempBoxSize);g.multiplyScalar(.5),screen.availHeight>0&&g.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),g.x*=D.aspect;const M=e.matrixWorldInverse,x=new h.Box3;x.copy(f),x.applyMatrix4(t.matrixWorld),x.applyMatrix4(M);const b=x.getSize(this._tempBox2Size),G=Math.max(b.x,b.y);if(Math.max(g.x,g.y)!=0&&G!=0&&(g.z=b.z/Math.max(b.x,b.y)*Math.max(g.x,g.y)),r.lastScreenCoverage=Math.max(g.x,g.y,g.z),r.lastScreenspaceVolume.copy(g),r.lastScreenCoverage*=r.lastCentrality,J&&A.debugDrawLine){const L=this.tempMatrix.copy(this.projectionScreenMatrix);L.invert();const p=A.corner0,P=A.corner1,O=A.corner2,y=A.corner3;p.copy(this._tempBox.min),P.copy(this._tempBox.max),P.x=p.x,O.copy(this._tempBox.max),O.y=p.y,y.copy(this._tempBox.max);const c=(p.z+y.z)*.5;p.z=P.z=O.z=y.z=c,p.applyMatrix4(L),P.applyMatrix4(L),O.applyMatrix4(L),y.applyMatrix4(L),A.debugDrawLine(p,P,255),A.debugDrawLine(p,O,255),A.debugDrawLine(P,y,255),A.debugDrawLine(O,y,255)}let R=999;if(d&&r.lastScreenCoverage>0){for(let L=0;L<d.length;L++)if(d[L].density/r.lastScreenCoverage<i){R=L;break}}R<s&&(s=R)}}return s}};let _=A;u(_,"debugDrawLine"),u(_,"corner0",new h.Vector3),u(_,"corner1",new h.Vector3),u(_,"corner2",new h.Vector3),u(_,"corner3",new h.Vector3);class he{constructor(){u(this,"lastLodLevel",0);u(this,"lastScreenCoverage",0);u(this,"lastScreenspaceVolume",new h.Vector3);u(this,"lastCentrality",0)}}const Q=Symbol("NEEDLE_mesh_lod"),W=Symbol("NEEDLE_texture_lod");function ee(l){if(!l)return null;let e=null,t=null;for(let r=l;r!=null;r=Object.getPrototypeOf(r)){const i=Object.getOwnPropertySymbols(r),o=i.find(n=>n.toString()=="Symbol(renderer)"),s=i.find(n=>n.toString()=="Symbol(scene)");!e&&o!=null&&(e=l[o].threeRenderer),!t&&s!=null&&(t=l[s])}if(e){console.log("Adding Needle LODs to modelviewer");const r=new _(e);if(r.plugins.push(new pe(l)),r.enable(),t){const i=t.camera||t.traverse(o=>o.type=="PerspectiveCamera")[0];i&&e.render(t,i)}return()=>{r.disable()}}return null}class pe{constructor(e){u(this,"modelviewer");this.modelviewer=e}onBeforeUpdateLOD(e,t,r,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}getUrl(){return this.modelviewer.getAttribute("src")}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[W]==!0)return;t[W]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(!i){console.error("No url found in modelviewer");return}if(r&&t.material){let o=function(n){var d,f,D;if(n[W]==!0)return;n[W]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let g=0;g<a.length;g++){const M=a[g],x=n[M];if((x==null?void 0:x.isTexture)===!0){const b=(f=(d=x.userData)==null?void 0:d.associations)==null?void 0:f.textures,G=r.parser.json.textures[b];if((D=G.extensions)!=null&&D[k]){const m=G.extensions[k];m&&i&&w.registerTexture(i,x,m.lods.length,m)}}}};const s=t.material;if(Array.isArray(s))for(const n of s)o(n);else o(s)}}tryParseMeshLOD(e,t){var o,s;if(t[Q]==!0)return;t[Q]=!0;const r=this.getUrl();if(!r){console.error("No url found in modelviewer");return}const i=(s=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:s[k];if(i&&r){const n=t.uuid;w.registerMesh(r,n,t,0,i.lods.length,i)}}}function ye(l,e,t,r){Z(e),j(t),t.register(o=>new w(o,l));const i=new _(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{ee(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=k;exports.LODsManager=_;exports.NEEDLE_progressive=w;exports.patchModelViewer=ee;exports.registerPlugin=fe;exports.useNeedleProgressive=ye;
|
package/lib/extension.d.ts
CHANGED
|
@@ -1,109 +1,109 @@
|
|
|
1
|
-
import { BufferGeometry, Material, Mesh, Texture } from "three";
|
|
2
|
-
import { type GLTF, type GLTFLoaderPlugin, GLTFParser } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
3
|
-
export declare const EXTENSION_NAME = "NEEDLE_progressive";
|
|
4
|
-
declare type NEEDLE_progressive_model_LOD = {
|
|
5
|
-
path: string;
|
|
6
|
-
hash?: string;
|
|
7
|
-
};
|
|
8
|
-
/** This is the data structure we have in the NEEDLE_progressive extension */
|
|
9
|
-
declare type NEEDLE_progressive_model = {
|
|
10
|
-
guid: string;
|
|
11
|
-
lods: Array<NEEDLE_progressive_model_LOD>;
|
|
12
|
-
};
|
|
13
|
-
export declare type NEEDLE_progressive_texture_model = NEEDLE_progressive_model & {};
|
|
14
|
-
export declare type NEEDLE_progressive_mesh_model = NEEDLE_progressive_model & {
|
|
15
|
-
density: number;
|
|
16
|
-
lods: Array<NEEDLE_progressive_model_LOD & {
|
|
17
|
-
density: number;
|
|
18
|
-
indexCount: number;
|
|
19
|
-
vertexCount: number;
|
|
20
|
-
}>;
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* This is the result of a progressive texture loading event for a material's texture slot in {@link NEEDLE_progressive.assignTextureLOD}
|
|
24
|
-
* @internal
|
|
25
|
-
*/
|
|
26
|
-
export declare type ProgressiveMaterialTextureLoadingResult = {
|
|
27
|
-
/** the material the progressive texture was loaded for */
|
|
28
|
-
material: Material;
|
|
29
|
-
/** the slot in the material where the texture was loaded */
|
|
30
|
-
slot: string;
|
|
31
|
-
/** the texture that was loaded (if any) */
|
|
32
|
-
texture: Texture | null;
|
|
33
|
-
/** the level of detail that was loaded */
|
|
34
|
-
level: number;
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* The NEEDLE_progressive extension for the GLTFLoader is responsible for loading progressive LODs for meshes and textures.
|
|
38
|
-
* This extension can be used to load different resolutions of a mesh or texture at runtime (e.g. for LODs or progressive textures).
|
|
39
|
-
* @example
|
|
40
|
-
* ```javascript
|
|
41
|
-
* const loader = new GLTFLoader();
|
|
42
|
-
* loader.register(new NEEDLE_progressive());
|
|
43
|
-
* loader.load("model.glb", (gltf) => {
|
|
44
|
-
* const mesh = gltf.scene.children[0] as Mesh;
|
|
45
|
-
* NEEDLE_progressive.assignMeshLOD(context, sourceId, mesh, 1).then(mesh => {
|
|
46
|
-
* console.log("Mesh with LOD level 1 loaded", mesh);
|
|
47
|
-
* });
|
|
48
|
-
* });
|
|
49
|
-
* ```
|
|
50
|
-
*/
|
|
51
|
-
export declare class NEEDLE_progressive implements GLTFLoaderPlugin {
|
|
52
|
-
/** The name of the extension */
|
|
53
|
-
get name(): string;
|
|
54
|
-
static getMeshLODInformation(geo: BufferGeometry): NEEDLE_progressive_mesh_model | null;
|
|
55
|
-
/** Check if a LOD level is available for a mesh or a texture
|
|
56
|
-
* @param obj the mesh or texture to check
|
|
57
|
-
* @param level the level of detail to check for (0 is the highest resolution). If undefined, the function checks if any LOD level is available
|
|
58
|
-
* @returns true if the LOD level is available (or if any LOD level is available if level is undefined)
|
|
59
|
-
*/
|
|
60
|
-
static hasLODLevelAvailable(obj: Mesh | BufferGeometry | Texture | Material, level?: number): boolean;
|
|
61
|
-
/** Load a different resolution of a mesh (if available)
|
|
62
|
-
* @param context the context
|
|
63
|
-
* @param source the sourceid of the file from which the mesh is loaded (this is usually the component's sourceId)
|
|
64
|
-
* @param mesh the mesh to load the LOD for
|
|
65
|
-
* @param level the level of detail to load (0 is the highest resolution)
|
|
66
|
-
* @returns a promise that resolves to the mesh with the requested LOD level
|
|
67
|
-
* @example
|
|
68
|
-
* ```javascript
|
|
69
|
-
* const mesh = this.gameObject as Mesh;
|
|
70
|
-
* NEEDLE_progressive.assignMeshLOD(context, sourceId, mesh, 1).then(mesh => {
|
|
71
|
-
* console.log("Mesh with LOD level 1 loaded", mesh);
|
|
72
|
-
* });
|
|
73
|
-
* ```
|
|
74
|
-
*/
|
|
75
|
-
static assignMeshLOD(mesh: Mesh, level: number): Promise<BufferGeometry | null>;
|
|
76
|
-
/** Load a different resolution of a texture (if available)
|
|
77
|
-
* @param context the context
|
|
78
|
-
* @param source the sourceid of the file from which the texture is loaded (this is usually the component's sourceId)
|
|
79
|
-
* @param materialOrTexture the material or texture to load the LOD for (if passing in a material all textures in the material will be loaded)
|
|
80
|
-
* @param level the level of detail to load (0 is the highest resolution) - currently only 0 is supported
|
|
81
|
-
* @returns a promise that resolves to the material or texture with the requested LOD level
|
|
82
|
-
*/
|
|
83
|
-
static assignTextureLOD(materialOrTexture: Material | Texture, level?: number): Promise<Array<ProgressiveMaterialTextureLoadingResult> | Texture | null>;
|
|
84
|
-
private static assignTextureLODForSlot;
|
|
85
|
-
private readonly parser;
|
|
86
|
-
private readonly url;
|
|
87
|
-
constructor(parser: GLTFParser, url: string);
|
|
88
|
-
afterRoot(gltf: GLTF): null;
|
|
89
|
-
/**
|
|
90
|
-
* Register a texture with LOD information
|
|
91
|
-
*/
|
|
92
|
-
static registerTexture: (url: string, tex: Texture, index: number, ext: NEEDLE_progressive_texture_model) => void;
|
|
93
|
-
/**
|
|
94
|
-
* Register a mesh with LOD information
|
|
95
|
-
*/
|
|
96
|
-
static registerMesh: (url: string, key: string, mesh: Mesh, level: number, index: number | undefined, ext: NEEDLE_progressive_mesh_model) => void;
|
|
97
|
-
/** A map of key = asset uuid and value = LOD information */
|
|
98
|
-
private static readonly lodInfos;
|
|
99
|
-
/** cache of already loaded mesh lods */
|
|
100
|
-
private static readonly previouslyLoaded;
|
|
101
|
-
/** this contains the geometry/textures that were originally loaded */
|
|
102
|
-
private static readonly lowresCache;
|
|
103
|
-
private static getOrLoadLOD;
|
|
104
|
-
private static assignLODInformation;
|
|
105
|
-
private static getAssignedLODInformation;
|
|
106
|
-
private static readonly _copiedTextures;
|
|
107
|
-
private static copySettings;
|
|
108
|
-
}
|
|
109
|
-
export {};
|
|
1
|
+
import { BufferGeometry, Material, Mesh, Texture } from "three";
|
|
2
|
+
import { type GLTF, type GLTFLoaderPlugin, GLTFParser } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
3
|
+
export declare const EXTENSION_NAME = "NEEDLE_progressive";
|
|
4
|
+
declare type NEEDLE_progressive_model_LOD = {
|
|
5
|
+
path: string;
|
|
6
|
+
hash?: string;
|
|
7
|
+
};
|
|
8
|
+
/** This is the data structure we have in the NEEDLE_progressive extension */
|
|
9
|
+
declare type NEEDLE_progressive_model = {
|
|
10
|
+
guid: string;
|
|
11
|
+
lods: Array<NEEDLE_progressive_model_LOD>;
|
|
12
|
+
};
|
|
13
|
+
export declare type NEEDLE_progressive_texture_model = NEEDLE_progressive_model & {};
|
|
14
|
+
export declare type NEEDLE_progressive_mesh_model = NEEDLE_progressive_model & {
|
|
15
|
+
density: number;
|
|
16
|
+
lods: Array<NEEDLE_progressive_model_LOD & {
|
|
17
|
+
density: number;
|
|
18
|
+
indexCount: number;
|
|
19
|
+
vertexCount: number;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* This is the result of a progressive texture loading event for a material's texture slot in {@link NEEDLE_progressive.assignTextureLOD}
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export declare type ProgressiveMaterialTextureLoadingResult = {
|
|
27
|
+
/** the material the progressive texture was loaded for */
|
|
28
|
+
material: Material;
|
|
29
|
+
/** the slot in the material where the texture was loaded */
|
|
30
|
+
slot: string;
|
|
31
|
+
/** the texture that was loaded (if any) */
|
|
32
|
+
texture: Texture | null;
|
|
33
|
+
/** the level of detail that was loaded */
|
|
34
|
+
level: number;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* The NEEDLE_progressive extension for the GLTFLoader is responsible for loading progressive LODs for meshes and textures.
|
|
38
|
+
* This extension can be used to load different resolutions of a mesh or texture at runtime (e.g. for LODs or progressive textures).
|
|
39
|
+
* @example
|
|
40
|
+
* ```javascript
|
|
41
|
+
* const loader = new GLTFLoader();
|
|
42
|
+
* loader.register(new NEEDLE_progressive());
|
|
43
|
+
* loader.load("model.glb", (gltf) => {
|
|
44
|
+
* const mesh = gltf.scene.children[0] as Mesh;
|
|
45
|
+
* NEEDLE_progressive.assignMeshLOD(context, sourceId, mesh, 1).then(mesh => {
|
|
46
|
+
* console.log("Mesh with LOD level 1 loaded", mesh);
|
|
47
|
+
* });
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare class NEEDLE_progressive implements GLTFLoaderPlugin {
|
|
52
|
+
/** The name of the extension */
|
|
53
|
+
get name(): string;
|
|
54
|
+
static getMeshLODInformation(geo: BufferGeometry): NEEDLE_progressive_mesh_model | null;
|
|
55
|
+
/** Check if a LOD level is available for a mesh or a texture
|
|
56
|
+
* @param obj the mesh or texture to check
|
|
57
|
+
* @param level the level of detail to check for (0 is the highest resolution). If undefined, the function checks if any LOD level is available
|
|
58
|
+
* @returns true if the LOD level is available (or if any LOD level is available if level is undefined)
|
|
59
|
+
*/
|
|
60
|
+
static hasLODLevelAvailable(obj: Mesh | BufferGeometry | Texture | Material, level?: number): boolean;
|
|
61
|
+
/** Load a different resolution of a mesh (if available)
|
|
62
|
+
* @param context the context
|
|
63
|
+
* @param source the sourceid of the file from which the mesh is loaded (this is usually the component's sourceId)
|
|
64
|
+
* @param mesh the mesh to load the LOD for
|
|
65
|
+
* @param level the level of detail to load (0 is the highest resolution)
|
|
66
|
+
* @returns a promise that resolves to the mesh with the requested LOD level
|
|
67
|
+
* @example
|
|
68
|
+
* ```javascript
|
|
69
|
+
* const mesh = this.gameObject as Mesh;
|
|
70
|
+
* NEEDLE_progressive.assignMeshLOD(context, sourceId, mesh, 1).then(mesh => {
|
|
71
|
+
* console.log("Mesh with LOD level 1 loaded", mesh);
|
|
72
|
+
* });
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
static assignMeshLOD(mesh: Mesh, level: number): Promise<BufferGeometry | null>;
|
|
76
|
+
/** Load a different resolution of a texture (if available)
|
|
77
|
+
* @param context the context
|
|
78
|
+
* @param source the sourceid of the file from which the texture is loaded (this is usually the component's sourceId)
|
|
79
|
+
* @param materialOrTexture the material or texture to load the LOD for (if passing in a material all textures in the material will be loaded)
|
|
80
|
+
* @param level the level of detail to load (0 is the highest resolution) - currently only 0 is supported
|
|
81
|
+
* @returns a promise that resolves to the material or texture with the requested LOD level
|
|
82
|
+
*/
|
|
83
|
+
static assignTextureLOD(materialOrTexture: Material | Texture, level?: number): Promise<Array<ProgressiveMaterialTextureLoadingResult> | Texture | null>;
|
|
84
|
+
private static assignTextureLODForSlot;
|
|
85
|
+
private readonly parser;
|
|
86
|
+
private readonly url;
|
|
87
|
+
constructor(parser: GLTFParser, url: string);
|
|
88
|
+
afterRoot(gltf: GLTF): null;
|
|
89
|
+
/**
|
|
90
|
+
* Register a texture with LOD information
|
|
91
|
+
*/
|
|
92
|
+
static registerTexture: (url: string, tex: Texture, index: number, ext: NEEDLE_progressive_texture_model) => void;
|
|
93
|
+
/**
|
|
94
|
+
* Register a mesh with LOD information
|
|
95
|
+
*/
|
|
96
|
+
static registerMesh: (url: string, key: string, mesh: Mesh, level: number, index: number | undefined, ext: NEEDLE_progressive_mesh_model) => void;
|
|
97
|
+
/** A map of key = asset uuid and value = LOD information */
|
|
98
|
+
private static readonly lodInfos;
|
|
99
|
+
/** cache of already loaded mesh lods */
|
|
100
|
+
private static readonly previouslyLoaded;
|
|
101
|
+
/** this contains the geometry/textures that were originally loaded */
|
|
102
|
+
private static readonly lowresCache;
|
|
103
|
+
private static getOrLoadLOD;
|
|
104
|
+
private static assignLODInformation;
|
|
105
|
+
private static getAssignedLODInformation;
|
|
106
|
+
private static readonly _copiedTextures;
|
|
107
|
+
private static copySettings;
|
|
108
|
+
}
|
|
109
|
+
export {};
|