@needle-tools/gltf-progressive 1.0.0-alpha.11 → 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.
@@ -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 U,BufferGeometry as $,Material as ae,Texture as j,TextureLoader as le,Matrix4 as Q,Frustum as ue,Sphere as ce,Box3 as Z,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 z="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",q="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(z+"draco_decoder.js",{method:"head"}).catch(r=>{z="./include/draco/",q="./include/ktx2/"});function me(r){z=r}function pe(r){q=r}let k,V,G;function ee(r){k||(k=new fe,k.setDecoderPath(z),k.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 re(r){r.dracoLoader||r.setDRACOLoader(k),r.ktx2Loader||r.setKTX2Loader(G),r.meshoptDecoder||r.setMeshoptDecoder(V)}function X(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 K=new Array;function xe(r){K.push(r)}const P="NEEDLE_progressive",v=X("debugprogressive"),H=Symbol("needle-progressive-texture"),N=new Map,Y=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=O.getMeshLODInformation(i),h=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=e,O.assignMeshLOD(s,h),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,o=!1;window.addEventListener("keyup",n=>{n.key==="p"&&r(),n.key==="w"&&(o=!o,Y&&Y.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 D=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 U||r.isMesh===!0){const o=r.geometry,n=this.getAssignedLODInformation(o);if(!n)return Promise.resolve(null);for(const s of K)(t=s.onBeforeGetLODMesh)==null||t.call(s,r,e);return r["LOD:requested level"]=e,D.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&&Y.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],h=n[i];l&&l.isTexture===!0?a.push({material:t,slot:h,texture:l,level:e}):a.push({material:t,slot:h,texture:null,level:e})}return a})}if(r instanceof j||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):D.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,D.registerTexture(this.url,i,n,s));a||this.parser.getDependency("texture",n).then(i=>{i&&D.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&&D.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 h=r;h.source&&h.source[H]&&(l=h.source[H])}if(l||(l=D.lodInfos.get(i)),l){if(e>0){let d=!1;const M=Array.isArray(l.lods);if(M&&e>=l.lods.length?d=!0:M||(d=!0),d)return this.lowresCache.get(i)}const h=Array.isArray(l.lods)?l.lods[e].path:l.lods;if(!h)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const u=ye(a.url,h);if(u.endsWith(".glb")||u.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const d=u+"_"+l.guid,M=this.previouslyLoaded.get(d);if(M!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${d}`);let p=await M.catch(m=>(console.error(`Error loading LOD ${e} from ${u}
2
- `,m),null)),g=!1;if(p==null||(p instanceof j&&r instanceof j?(t=p.image)!=null&&t.data||(o=p.source)!=null&&o.data?p=this.copySettings(r,p):(g=!0,this.previouslyLoaded.delete(d)):p instanceof $&&r instanceof $&&((n=p.attributes.position)!=null&&n.array||(g=!0,this.previouslyLoaded.delete(d)))),!g)return p}const y=l,A=new Promise(async(p,g)=>{const m=new de;re(m),v&&(await new Promise(L=>setTimeout(L,1e3)),s&&console.warn("Start loading (delayed) "+u,y.guid));let b=u;if(y&&Array.isArray(y.lods)){const L=y.lods[e];L.hash&&(b+="?v="+L.hash)}const x=await m.loadAsync(b).catch(L=>(console.error(`Error loading LOD ${e} from ${u}
3
- `,L),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+u,y.guid);let _=0;if(x.parser.json.textures){let L=!1;for(const f of x.parser.json.textures){if(f!=null&&f.extensions){const w=f?.extensions[P];if(w!=null&&w.guid&&w.guid===y.guid){L=!0;break}}_++}if(L){let f=await S.getDependency("texture",_);return s&&console.log('change "'+r.name+'" \u2192 "'+f.name+'"',u,_,f,d),r instanceof j&&(f=this.copySettings(r,f)),f&&(f.guid=y.guid),p(f)}}if(_=0,x.parser.json.meshes){let L=!1;for(const f of x.parser.json.meshes){if(f!=null&&f.extensions){const w=f?.extensions[P];if(w!=null&&w.guid&&w.guid===y.guid){L=!0;break}}_++}if(L){const f=await S.getDependency("mesh",_),w=y;if(s&&console.log(`Loaded Mesh "${f.name}"`,u,_,f,d),f.isMesh===!0){const T=f.geometry;return D.assignLODInformation(a.url,T,i,e,void 0,w.density),p(T)}else{const T=new Array;for(let C=0;C<f.children.length;C++){const W=f.children[C];if(W instanceof U){const R=W.geometry;D.assignLODInformation(a.url,R,i,e,C,w.density),T.push(R)}}return p(T)}}}return p(null)});return this.previouslyLoaded.set(d,A),await A}else if(r instanceof j){s&&console.log("Load texture from uri: "+u);const d=await new le().loadAsync(u);return d?(d.guid=l.guid,d.flipY=!1,d.needsUpdate=!0,d.colorSpace=r.colorSpace,s&&console.log(l,d)):v&&console.warn("failed loading",u),d}}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 Le(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 O=D;c(O,"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;D.assignLODInformation(r,e,n,0,0,void 0),D.lodInfos.set(n,o),D.lowresCache.set(n,e)}),c(O,"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={}),D.assignLODInformation(r,i,e,o,n,s.density),D.lodInfos.set(e,s);let l=D.lowresCache.get(e);l?l.push(t.geometry):l=[t.geometry],D.lowresCache.set(e,l);for(const h of K)(a=h.onRegisteredNewMesh)==null||a.call(h,t,s)}),c(O,"lodInfos",new Map),c(O,"previouslyLoaded",new Map),c(O,"lowresCache",new Map),c(O,"_copiedTextures",new Map);class Le{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"),ve=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&&t==0){if(ve||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const a=1e5,i=this.renderer.renderLists.get(r,t),l=i.opaque;for(const u of l){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 d=u.object;(d instanceof U||d.isMesh)&&this.updateLODs(r,e,d,a)}const h=i.transparent;for(const u of h){const d=u.object;(d instanceof U||d.isMesh)&&this.updateLODs(r,e,d,a)}}}updateLODs(r,e,t,o){var n,s;for(const h of this.plugins)(n=h.onBeforeUpdateLOD)==null||n.call(h,this.renderer,r,e,t);let a=t.userData.LOD_state;a||(a=new De,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 h=t["DEBUG:LOD"];if(h!=null&&(l=h),Array.isArray(t.material))for(const u of t.material)this.loadProgressiveTextures(u,l);else this.loadProgressiveTextures(t.material,l)}for(const h of this.plugins)(s=h.onAfterUpdatedLOD)==null||s.call(h,this.renderer,r,e,t,i);a.lastLodLevel=i}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(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=O.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 h=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&&h.fov>70){const g=this._tempBox.min,m=this._tempBox.max;let b=g.x,x=g.y,S=m.x,_=m.y;const L=2,f=1.5,w=(g.x+m.x)*.5,T=(g.y+m.y)*.5;b=(b-w)*L+w,x=(x-T)*L+T,S=(S-w)*L+w,_=(_-T)*L+T;const C=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)),R=Math.max(C,W);t.lastCentrality=(f-R)*(f-R)*(f-R)}else t.lastCentrality=1;const u=this._tempBox.getSize(this._tempBoxSize);u.multiplyScalar(.5),screen.availHeight>0&&u.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),u.x*=h.aspect;const d=r.matrixWorldInverse,M=new Z;M.copy(l),M.applyMatrix4(e.matrixWorld),M.applyMatrix4(d);const y=M.getSize(this._tempBox2Size),A=Math.max(y.x,y.y);if(Math.max(u.x,u.y)!=0&&A!=0&&(u.z=y.z/Math.max(y.x,y.y)*Math.max(u.x,u.y)),t.lastScreenCoverage=Math.max(u.x,u.y,u.z),t.lastScreenspaceVolume.copy(u),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 p=999;if(i&&t.lastScreenCoverage>0){for(let g=0;g<i.length;g++)if(i[g].density/t.lastScreenCoverage<o){p=g;break}}p<s&&(s=p)}}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 De{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,h,u;if(i[F]==!0)return;i[F]=!0,i.userData&&(i.userData.LOD=-1);const d=Object.keys(i);for(let M=0;M<d.length;M++){const y=d[M],A=i[y];if(A?.isTexture===!0){const p=(h=(l=A.userData)==null?void 0:l.associations)==null?void 0:h.textures,g=o.parser.json.textures[p];if((u=g.extensions)!=null&&u[P]){const m=g.extensions[P];m&&n&&O.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;O.registerMesh(s,i,t,0,a.lods.length,a)}}}function we(r,e,t,o){ee(e),re(t),t.register(s=>new O(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,O as NEEDLE_progressive,oe as patchModelViewer,xe 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};
@@ -1,3 +1,3 @@
1
- "use strict";var ie=Object.defineProperty;var oe=(l,e,t)=>e in l?ie(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var u=(l,e,t)=>(oe(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("three"),ne=require("three/examples/jsm/loaders/GLTFLoader.js"),ae=require("three/examples/jsm/libs/meshopt_decoder.module.js"),le=require("three/examples/jsm/loaders/DRACOLoader.js"),ue=require("three/examples/jsm/loaders/KTX2Loader.js");let V="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",J="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(V+"draco_decoder.js",{method:"head"}).catch(l=>{V="./include/draco/",J="./include/ktx2/"});function ce(l){V=l}function fe(l){J=l}let F,K,U;function ee(l){F||(F=new le.DRACOLoader,F.setDecoderPath(V),F.setDecoderConfig({type:"js"})),U||(U=new ue.KTX2Loader,U.setTranscoderPath(J)),K||(K=ae.MeshoptDecoder),l?U.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function te(l){l.dracoLoader||l.setDRACOLoader(F),l.ktx2Loader||l.setKTX2Loader(U),l.meshoptDecoder||l.setMeshoptDecoder(K)}function Q(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function de(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 Y=new Array;function ge(l){Y.push(l)}const C="NEEDLE_progressive",T=Q("debugprogressive"),X=Symbol("needle-progressive-texture"),N=new Map,H=new Set;if(T){let l=function(){e+=1,console.log("Toggle LOD level",e,N),N.forEach((i,o)=>{for(const s of i.keys){const n=o[s];if(n.isBufferGeometry===!0){const a=w.getMeshLODInformation(n),h=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,w.assignMeshLOD(o,h),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,H&&H.forEach(o=>{o.name!="BackgroundCubeMaterial"&&"wireframe"in o&&(o.wireframe=r)}))})}function Z(l,e,t){var i;if(!T)return;N.has(l)||N.set(l,{keys:[],sourceId:t});const r=N.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 C}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 p.Mesh||e.isMesh===!0){const i=e.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of Y)(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 p.BufferGeometry&&(e.geometry=s,T&&Z(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 p.Material||e.isMaterial===!0){const r=e,i=[],o=new Array;if(T&&H.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const n of Object.keys(s.uniforms)){const a=s.uniforms[n].value;if((a==null?void 0:a.isTexture)===!0){const h=this.assignTextureLODForSlot(a,t,r,n);i.push(h),o.push(n)}}}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 h=s[a],g=o[a];h&&h.isTexture===!0?n.push({material:r,slot:g,texture:h,level:t}):n.push({material:r,slot:g,texture:null,level:t})}return n})}if(e instanceof p.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&&Z(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[C];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[C];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,s.guid,n,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var n,a,h;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 g=e;g.source&&g.source[X]&&(s=g.source[X])}if(s||(s=S.lodInfos.get(o)),s){if(t>0){let f=!1;const M=Array.isArray(s.lods);if(M&&t>=s.lods.length?f=!0:M||(f=!0),f)return this.lowresCache.get(o)}const g=Array.isArray(s.lods)?s.lods[t].path:s.lods;if(!g)return T&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const c=de(i.url,g);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const f=c+"_"+s.guid,M=this.previouslyLoaded.get(f);if(M!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${f}`);let x=await M.catch(I=>(console.error(`Error loading LOD ${t} from ${c}
2
- `,I),null)),R=!1;if(x==null||(x instanceof p.Texture&&e instanceof p.Texture?(n=x.image)!=null&&n.data||(a=x.source)!=null&&a.data?x=this.copySettings(e,x):(R=!0,this.previouslyLoaded.delete(f)):x instanceof p.BufferGeometry&&e instanceof p.BufferGeometry&&((h=x.attributes.position)!=null&&h.array||(R=!0,this.previouslyLoaded.delete(f)))),!R)return x}const D=s,P=new Promise(async(x,R)=>{const I=new ne.GLTFLoader;te(I),T&&(await new Promise(L=>setTimeout(L,1e3)),r&&console.warn("Start loading (delayed) "+c,D.guid));let m=c;if(D&&Array.isArray(D.lods)){const L=D.lods[t];L.hash&&(m+="?v="+L.hash)}const y=await I.loadAsync(m).catch(L=>(console.error(`Error loading LOD ${t} from ${c}
3
- `,L),null));if(!y)return null;const b=y.parser;r&&console.log("Loading finished "+c,D.guid);let O=0;if(y.parser.json.textures){let L=!1;for(const d of y.parser.json.textures){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===D.guid){L=!0;break}}O++}if(L){let d=await b.getDependency("texture",O);return r&&console.log('change "'+e.name+'" → "'+d.name+'"',c,O,d,f),e instanceof p.Texture&&(d=this.copySettings(e,d)),d&&(d.guid=D.guid),x(d)}}if(O=0,y.parser.json.meshes){let L=!1;for(const d of y.parser.json.meshes){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===D.guid){L=!0;break}}O++}if(L){const d=await b.getDependency("mesh",O),v=D;if(r&&console.log(`Loaded Mesh "${d.name}"`,c,O,d,f),d.isMesh===!0){const B=d.geometry;return S.assignLODInformation(i.url,B,o,t,void 0,v.density),x(B)}else{const B=new Array;for(let E=0;E<d.children.length;E++){const k=d.children[E];if(k instanceof p.Mesh){const W=k.geometry;S.assignLODInformation(i.url,W,o,t,E,v.density),B.push(W)}}return x(B)}}}return x(null)});return this.previouslyLoaded.set(f,P),await P}else if(e instanceof p.Texture){r&&console.log("Load texture from uri: "+c);const M=await new p.TextureLoader().loadAsync(c);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",c),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 he(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[X]=i);const o=i.guid;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 h;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 g of Y)(h=g.onRegisteredNewMesh)==null||h.call(g,r,s)}),u(w,"lodInfos",new Map),u(w,"previouslyLoaded",new Map),u(w,"lowresCache",new Map),u(w,"_copiedTextures",new Map);class he{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 $=Q("debugprogressive"),pe=Q("noprogressive"),A=class{constructor(e){u(this,"renderer");u(this,"projectionScreenMatrix",new p.Matrix4);u(this,"cameraFrustrum",new p.Frustum);u(this,"updateInterval",0);u(this,"pause",!1);u(this,"plugins",[]);u(this,"_frame",0);u(this,"_originalRender");u(this,"_sphere",new p.Sphere);u(this,"_tempBox",new p.Box3);u(this,"tempMatrix",new p.Matrix4);u(this,"_tempWorldPosition",new p.Vector3);u(this,"_tempBoxSize",new p.Vector3);u(this,"_tempBox2Size",new p.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;ee(this.renderer),this.renderer.render=function(r,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,n=e++;t.onBeforeRender(r,i,n,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,n,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var o,s;if(!this.pause&&r==0){if(pe||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const n=1e5,a=this.renderer.renderLists.get(e,r),h=a.opaque;for(const c of h){if(c.material&&(((o=c.geometry)==null?void 0:o.type)==="BoxGeometry"||((s=c.geometry)==null?void 0:s.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){$&&(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",c,c.material.name,c.material.type)));continue}const f=c.object;(f instanceof p.Mesh||f.isMesh)&&this.updateLODs(e,t,f,n)}const g=a.transparent;for(const c of g){const f=c.object;(f instanceof p.Mesh||f.isMesh)&&this.updateLODs(e,t,f,n)}}}updateLODs(e,t,r,i){var a,h;for(const g of this.plugins)(a=g.onBeforeUpdateLOD)==null||a.call(g,this.renderer,e,t,r);let o=r.userData.LOD_state;o||(o=new ye,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 g=r["DEBUG:LOD"];if(g!=null&&(n=g),Array.isArray(r.material))for(const c of r.material)this.loadProgressiveTextures(c,n);else this.loadProgressiveTextures(r.material,n)}for(const g of this.plugins)(h=g.onAfterUpdatedLOD)==null||h.call(g,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($&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=w.getMeshLODInformation(t.geometry),h=a==null?void 0:a.lods;if(!h||h.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(t)))return 99;const g=t.geometry.boundingBox;if(g&&e.isPerspectiveCamera){const c=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 m=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(m))return 0}if(this._tempBox.copy(g),this._tempBox.applyMatrix4(t.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&c.fov>70){const m=this._tempBox.min,y=this._tempBox.max;let b=m.x,O=m.y,L=y.x,d=y.y;const v=2,B=1.5,E=(m.x+y.x)*.5,k=(m.y+y.y)*.5;b=(b-E)*v+E,O=(O-k)*v+k,L=(L-E)*v+E,d=(d-k)*v+k;const W=b<0&&L>0?0:Math.min(Math.abs(m.x),Math.abs(y.x)),se=O<0&&d>0?0:Math.min(Math.abs(m.y),Math.abs(y.y)),q=Math.max(W,se);r.lastCentrality=(B-q)*(B-q)*(B-q)}else r.lastCentrality=1;const f=this._tempBox.getSize(this._tempBoxSize);f.multiplyScalar(.5),screen.availHeight>0&&f.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),f.x*=c.aspect;const M=e.matrixWorldInverse,D=new p.Box3;D.copy(g),D.applyMatrix4(t.matrixWorld),D.applyMatrix4(M);const P=D.getSize(this._tempBox2Size),G=Math.max(P.x,P.y);if(Math.max(f.x,f.y)!=0&&G!=0&&(f.z=P.z/Math.max(P.x,P.y)*Math.max(f.x,f.y)),r.lastScreenCoverage=Math.max(f.x,f.y,f.z),r.lastScreenspaceVolume.copy(f),r.lastScreenCoverage*=r.lastCentrality,$&&A.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const y=A.corner0,b=A.corner1,O=A.corner2,L=A.corner3;y.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=y.x,O.copy(this._tempBox.max),O.y=y.y,L.copy(this._tempBox.max);const d=(y.z+L.z)*.5;y.z=b.z=O.z=L.z=d,y.applyMatrix4(m),b.applyMatrix4(m),O.applyMatrix4(m),L.applyMatrix4(m),A.debugDrawLine(y,b,255),A.debugDrawLine(y,O,255),A.debugDrawLine(b,L,255),A.debugDrawLine(O,L,255)}let R=999;if(h&&r.lastScreenCoverage>0){for(let m=0;m<h.length;m++)if(h[m].density/r.lastScreenCoverage<i){R=m;break}}R<s&&(s=R)}}return s}};let _=A;u(_,"debugDrawLine"),u(_,"corner0",new p.Vector3),u(_,"corner1",new p.Vector3),u(_,"corner2",new p.Vector3),u(_,"corner3",new p.Vector3);class ye{constructor(){u(this,"lastLodLevel",0);u(this,"lastScreenCoverage",0);u(this,"lastScreenspaceVolume",new p.Vector3);u(this,"lastCentrality",0)}}const j=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function re(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 Le(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 Le{constructor(e){u(this,"modelviewer");u(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}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 r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let o=function(n){var h,g,c;if(n[z]==!0)return;n[z]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let f=0;f<a.length;f++){const M=a[f],D=n[M];if((D==null?void 0:D.isTexture)===!0){const P=(g=(h=D.userData)==null?void 0:h.associations)==null?void 0:g.textures,G=r.parser.json.textures[P];if((c=G.extensions)!=null&&c[C]){const x=G.extensions[C];x&&i&&w.registerTexture(i,D,x.lods.length,x)}}}};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[j]==!0)return;t[j]=!0;const r=this.getUrl();if(!r)return;const i=(s=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:s[C];if(i&&r){const n=t.uuid;w.registerMesh(r,n,t,0,i.lods.length,i)}}}function me(l,e,t,r){ee(e),te(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",()=>{re(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=C;exports.LODsManager=_;exports.NEEDLE_progressive=w;exports.patchModelViewer=re;exports.registerPlugin=ge;exports.setDracoDecoderLocation=ce;exports.setKTX2TranscoderLocation=fe;exports.useNeedleProgressive=me;
1
+ "use strict";var ie=Object.defineProperty;var ne=(l,e,t)=>e in l?ie(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var c=(l,e,t)=>(ne(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("three"),oe=require("three/examples/jsm/loaders/GLTFLoader.js"),ae=require("three/examples/jsm/libs/meshopt_decoder.module.js"),le=require("three/examples/jsm/loaders/DRACOLoader.js"),ue=require("three/examples/jsm/loaders/KTX2Loader.js");let V="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",J="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(V+"draco_decoder.js",{method:"head"}).catch(l=>{V="./include/draco/",J="./include/ktx2/"});function ce(l){V=l}function fe(l){J=l}let I,$,U;function Q(l){I||(I=new le.DRACOLoader,I.setDecoderPath(V),I.setDecoderConfig({type:"js"})),U||(U=new ue.KTX2Loader,U.setTranscoderPath(J)),$||($=ae.MeshoptDecoder),l?U.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function Z(l){l.dracoLoader||l.setDRACOLoader(I),l.ktx2Loader||l.setKTX2Loader(U),l.meshoptDecoder||l.setMeshoptDecoder($)}function j(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function de(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 Y=new Array;function ge(l){Y.push(l)}const C="NEEDLE_progressive",T=j("debugprogressive"),X=Symbol("needle-progressive-texture"),N=new Map,H=new Set;if(T){let l=function(){e+=1,console.log("Toggle LOD level",e,N),N.forEach((i,n)=>{for(const s of i.keys){const o=n[s];if(o.isBufferGeometry===!0){const a=M.getMeshLODInformation(o),g=a?Math.min(e,a.lods.length):0;n["DEBUG:LOD"]=e,M.assignMeshLOD(n,g),a&&(t=Math.max(t,a.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,M.assignTextureLOD(n,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,H&&H.forEach(n=>{n.name!="BackgroundCubeMaterial"&&"wireframe"in n&&(n.wireframe=r)}))})}function ee(l,e,t){var i;if(!T)return;N.has(l)||N.set(l,{keys:[],sourceId:t});const r=N.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){c(this,"parser");c(this,"url");T&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return C}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static hasLODLevelAvailable(e,t){var n;if(e.isMaterial===!0){for(const s of Object.keys(e)){const o=e[s];if(o.isTexture&&this.hasLODLevelAvailable(o,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&&(n=r==null?void 0:r.userData)!=null&&n.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,n=this.getAssignedLODInformation(i);if(!n)return Promise.resolve(null);for(const s of Y)(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 o=n.index||0;s=s[o]}s&&i!=s&&s instanceof h.BufferGeometry&&(e.geometry=s,T&&ee(e,"geometry",n.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=[],n=new Array;if(T&&H.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const o of Object.keys(s.uniforms)){const a=s.uniforms[o].value;if((a==null?void 0:a.isTexture)===!0){const g=this.assignTextureLODForSlot(a,t,r,o);i.push(g),n.push(o)}}}else for(const s of Object.keys(r)){const o=r[s];if((o==null?void 0:o.isTexture)===!0){const a=this.assignTextureLODForSlot(o,t,r,s);i.push(a),n.push(s)}}return Promise.all(i).then(s=>{const o=new Array;for(let a=0;a<s.length;a++){const g=s[a],f=n[a];g&&g.isTexture===!0?o.push({material:r,slot:f,texture:g,level:t}):o.push({material:r,slot:f,texture:null,level:t})}return o})}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(n=>{if(Array.isArray(n))return null;if((n==null?void 0:n.isTexture)===!0){if(n!=e&&(r&&i&&(r[i]=n),T&&i&&r)){const s=this.getAssignedLODInformation(e);s&&ee(r,i,s.url)}return n}else T=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(n=>(console.error("Error loading LOD",e,n),null))}afterRoot(e){var t,r;return T&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((i,n)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[C];if(s){let o=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===n&&(o=!0,S.registerTexture(this.url,a,n,s));o||this.parser.getDependency("texture",n).then(a=>{a&&S.registerTexture(this.url,a,n,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((i,n)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[C];if(s&&s.lods){for(const o of this.parser.associations.keys())if(o.isMesh){const a=this.parser.associations.get(o);a.meshes===n&&S.registerMesh(this.url,s.guid,o,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var o,a,g;const r=T=="verbose",i=e.userData.LODS;if(!i)return null;const n=i==null?void 0:i.key;let s;if(e.isTexture===!0){const f=e;f.source&&f.source[X]&&(s=f.source[X])}if(s||(s=S.lodInfos.get(n)),s){if(t>0){let u=!1;const p=Array.isArray(s.lods);if(p&&t>=s.lods.length?u=!0:p||(u=!0),u)return this.lowresCache.get(n)}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 y=de(i.url,f);if(y.endsWith(".glb")||y.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const u=y+"_"+s.guid,p=this.previouslyLoaded.get(u);if(p!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${u}`);let w=await p.catch(F=>(console.error(`Error loading LOD ${t} from ${y}
2
+ `,F),null)),k=!1;if(w==null||(w instanceof h.Texture&&e instanceof h.Texture?(o=w.image)!=null&&o.data||(a=w.source)!=null&&a.data?w=this.copySettings(e,w):(k=!0,this.previouslyLoaded.delete(u)):w instanceof h.BufferGeometry&&e instanceof h.BufferGeometry&&((g=w.attributes.position)!=null&&g.array||(k=!0,this.previouslyLoaded.delete(u)))),!k)return w}const x=s,P=new Promise(async(w,k)=>{const F=new oe.GLTFLoader;Z(F),T&&(await new Promise(L=>setTimeout(L,1e3)),r&&console.warn("Start loading (delayed) "+y,x.guid));let D=y;if(x&&Array.isArray(x.lods)){const L=x.lods[t];L.hash&&(D+="?v="+L.hash)}const m=await F.loadAsync(D).catch(L=>(console.error(`Error loading LOD ${t} from ${y}
3
+ `,L),null));if(!m)return null;const b=m.parser;r&&console.log("Loading finished "+y,x.guid);let O=0;if(m.parser.json.textures){let L=!1;for(const d of m.parser.json.textures){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===x.guid){L=!0;break}}O++}if(L){let d=await b.getDependency("texture",O);return r&&console.log('change "'+e.name+'" → "'+d.name+'"',y,O,d,u),e instanceof h.Texture&&(d=this.copySettings(e,d)),d&&(d.guid=x.guid),w(d)}}if(O=0,m.parser.json.meshes){let L=!1;for(const d of m.parser.json.meshes){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===x.guid){L=!0;break}}O++}if(L){const d=await b.getDependency("mesh",O),v=x;if(r&&console.log(`Loaded Mesh "${d.name}"`,y,O,d,u),d.isMesh===!0){const B=d.geometry;return S.assignLODInformation(i.url,B,n,t,void 0,v.density),w(B)}else{const B=new Array;for(let E=0;E<d.children.length;E++){const R=d.children[E];if(R instanceof h.Mesh){const W=R.geometry;S.assignLODInformation(i.url,W,n,t,E,v.density),B.push(W)}}return w(B)}}}return w(null)});return this.previouslyLoaded.set(u,P),await P}else if(e instanceof h.Texture){r&&console.log("Load texture from uri: "+y);const p=await new h.TextureLoader().loadAsync(y);return p?(p.guid=s.guid,p.flipY=!1,p.needsUpdate=!0,p.colorSpace=e.colorSpace,r&&console.log(s,p)):T&&console.warn("failed loading",y),p}}else T&&console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,i,n,s){if(!t)return;t.userData||(t.userData={});const o=new he(e,r,i,n,s);t.userData.LODS=o,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.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)}};let M=S;c(M,"registerTexture",(e,t,r,i)=>{T&&console.log("> Progressive: register texture",r,t.name,t.uuid,t,i),t.source&&(t.source[X]=i);const n=i.guid;S.assignLODInformation(e,t,n,0,0,void 0),S.lodInfos.set(n,i),S.lowresCache.set(n,t)}),c(M,"registerMesh",(e,t,r,i,n,s)=>{var g;T&&console.log("> Progressive: register mesh",n,r.name,s,r.uuid,r);const o=r.geometry;o.userData||(o.userData={}),S.assignLODInformation(e,o,t,i,n,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 Y)(g=f.onRegisteredNewMesh)==null||g.call(f,r,s)}),c(M,"lodInfos",new Map),c(M,"previouslyLoaded",new Map),c(M,"lowresCache",new Map),c(M,"_copiedTextures",new Map);class he{constructor(e,t,r,i,n){c(this,"url");c(this,"key");c(this,"level");c(this,"index");c(this,"density");this.url=e,this.key=t,this.level=r,i!=null&&(this.index=i),n!=null&&(this.density=n)}}const K=j("debugprogressive"),pe=j("noprogressive"),A=class{constructor(e){c(this,"renderer");c(this,"projectionScreenMatrix",new h.Matrix4);c(this,"cameraFrustrum",new h.Frustum);c(this,"updateInterval",0);c(this,"pause",!1);c(this,"plugins",[]);c(this,"_frame",0);c(this,"_originalRender");c(this,"_sphere",new h.Sphere);c(this,"_tempBox",new h.Box3);c(this,"tempMatrix",new h.Matrix4);c(this,"_tempWorldPosition",new h.Vector3);c(this,"_tempBoxSize",new h.Vector3);c(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;Q(this.renderer),this.renderer.render=function(r,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,o=e++;t.onBeforeRender(r,i,o,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,o,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var a,g;if(this.pause)return;const n=this.renderer.renderLists.get(e,0),s=n.opaque;let o=!0;if(s.length===1){const f=s[0].material;(f.name==="EffectMaterial"||f.name==="CopyShader")&&(o=!1)}if(o){if(pe||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const f=1e5;for(const u of s){if(u.material&&(((a=u.geometry)==null?void 0:a.type)==="BoxGeometry"||((g=u.geometry)==null?void 0:g.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){K&&(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 h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}const y=n.transparent;for(const u of y){const p=u.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}}}updateLODs(e,t,r,i){var a,g;for(const f of this.plugins)(a=f.onBeforeUpdateLOD)==null||a.call(f,this.renderer,e,t,r);let n=r.userData.LOD_state;n||(n=new ye,r.userData.LOD_state=n);let s=this.calculateLodLevel(t,r,n,i);s=Math.round(s),s>=0&&this.loadProgressiveMeshes(r,s);let o=0;if(r.material){const f=r["DEBUG:LOD"];if(f!=null&&(o=f),Array.isArray(r.material))for(const y of r.material)this.loadProgressiveTextures(y,o);else this.loadProgressiveTextures(r.material,o)}for(const f of this.plugins)(g=f.onAfterUpdatedLOD)==null||g.call(f,this.renderer,e,t,r,s);n.lastLodLevel=s}loadProgressiveTextures(e,t){return e&&e.userData&&e.userData.LOD!==t?(e.userData.LOD=t,M.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 M.assignMeshLOD(e,t).then(i=>(i&&e.userData.LOD==t&&r!=e.geometry,i))}return Promise.resolve(null)}calculateLodLevel(e,t,r,i){var o;if(!t)return-1;let s=10+1;if(e){if(K&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=M.getMeshLODInformation(t.geometry),g=a==null?void 0:a.lods;if(!g||g.length<=0||!((o=this.cameraFrustrum)!=null&&o.intersectsObject(t)))return 99;const f=t.geometry.boundingBox;if(f&&e.isPerspectiveCamera){const y=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 D=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(D))return 0}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(t.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&y.fov>70){const D=this._tempBox.min,m=this._tempBox.max;let b=D.x,O=D.y,L=m.x,d=m.y;const v=2,B=1.5,E=(D.x+m.x)*.5,R=(D.y+m.y)*.5;b=(b-E)*v+E,O=(O-R)*v+R,L=(L-E)*v+E,d=(d-R)*v+R;const W=b<0&&L>0?0:Math.min(Math.abs(D.x),Math.abs(m.x)),se=O<0&&d>0?0:Math.min(Math.abs(D.y),Math.abs(m.y)),q=Math.max(W,se);r.lastCentrality=(B-q)*(B-q)*(B-q)}else r.lastCentrality=1;const u=this._tempBox.getSize(this._tempBoxSize);u.multiplyScalar(.5),screen.availHeight>0&&u.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),u.x*=y.aspect;const p=e.matrixWorldInverse,x=new h.Box3;x.copy(f),x.applyMatrix4(t.matrixWorld),x.applyMatrix4(p);const P=x.getSize(this._tempBox2Size),G=Math.max(P.x,P.y);if(Math.max(u.x,u.y)!=0&&G!=0&&(u.z=P.z/Math.max(P.x,P.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,K&&A.debugDrawLine){const D=this.tempMatrix.copy(this.projectionScreenMatrix);D.invert();const m=A.corner0,b=A.corner1,O=A.corner2,L=A.corner3;m.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=m.x,O.copy(this._tempBox.max),O.y=m.y,L.copy(this._tempBox.max);const d=(m.z+L.z)*.5;m.z=b.z=O.z=L.z=d,m.applyMatrix4(D),b.applyMatrix4(D),O.applyMatrix4(D),L.applyMatrix4(D),A.debugDrawLine(m,b,255),A.debugDrawLine(m,O,255),A.debugDrawLine(b,L,255),A.debugDrawLine(O,L,255)}let k=999;if(g&&r.lastScreenCoverage>0){for(let D=0;D<g.length;D++)if(g[D].density/r.lastScreenCoverage<i){k=D;break}}k<s&&(s=k)}}return s}};let _=A;c(_,"debugDrawLine"),c(_,"corner0",new h.Vector3),c(_,"corner1",new h.Vector3),c(_,"corner2",new h.Vector3),c(_,"corner3",new h.Vector3);class ye{constructor(){c(this,"lastLodLevel",0);c(this,"lastScreenCoverage",0);c(this,"lastScreenspaceVolume",new h.Vector3);c(this,"lastCentrality",0)}}const te=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function re(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),n=i.find(o=>o.toString()=="Symbol(renderer)"),s=i.find(o=>o.toString()=="Symbol(scene)");!e&&n!=null&&(e=l[n].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 me(l)),r.enable(),t){const i=t.camera||t.traverse(n=>n.type=="PerspectiveCamera")[0];i&&e.render(t,i)}return()=>{r.disable()}}return null}class me{constructor(e){c(this,"modelviewer");c(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}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 r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let n=function(o){var g,f,y;if(o[z]==!0)return;o[z]=!0,o.userData&&(o.userData.LOD=-1);const a=Object.keys(o);for(let u=0;u<a.length;u++){const p=a[u],x=o[p];if((x==null?void 0:x.isTexture)===!0){const P=(f=(g=x.userData)==null?void 0:g.associations)==null?void 0:f.textures,G=r.parser.json.textures[P];if((y=G.extensions)!=null&&y[C]){const w=G.extensions[C];w&&i&&M.registerTexture(i,x,w.lods.length,w)}}}};const s=t.material;if(Array.isArray(s))for(const o of s)n(o);else n(s)}}tryParseMeshLOD(e,t){var n,s;if(t[te]==!0)return;t[te]=!0;const r=this.getUrl();if(!r)return;const i=(s=(n=t.userData)==null?void 0:n.gltfExtensions)==null?void 0:s[C];if(i&&r){const o=t.uuid;M.registerMesh(r,o,t,0,i.lods.length,i)}}}function Le(l,e,t,r){Q(e),Z(t),t.register(n=>new M(n,l));const i=new _(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{re(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=C;exports.LODsManager=_;exports.NEEDLE_progressive=M;exports.addDracoAndKTX2Loaders=Z;exports.createLoaders=Q;exports.patchModelViewer=re;exports.registerPlugin=ge;exports.setDracoDecoderLocation=ce;exports.setKTX2TranscoderLocation=fe;exports.useNeedleProgressive=Le;
package/lib/extension.js CHANGED
@@ -648,6 +648,14 @@ export class NEEDLE_progressive {
648
648
  target.offset = source.offset;
649
649
  target.repeat = source.repeat;
650
650
  target.colorSpace = source.colorSpace;
651
+ target.magFilter = source.magFilter;
652
+ target.minFilter = source.minFilter;
653
+ target.wrapS = source.wrapS;
654
+ target.wrapT = source.wrapT;
655
+ target.flipY = source.flipY;
656
+ target.anisotropy = source.anisotropy;
657
+ target.generateMipmaps = source.generateMipmaps;
658
+ // related: NE-4937
651
659
  return target;
652
660
  }
653
661
  }
package/lib/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from "./extension.js";
2
2
  export * from "./plugins/index.js";
3
3
  export { LODsManager } from "./lods_manager.js";
4
- export { setDracoDecoderLocation, setKTX2TranscoderLocation } from "./loaders.js";
4
+ export { setDracoDecoderLocation, setKTX2TranscoderLocation, createLoaders, addDracoAndKTX2Loaders } from "./loaders.js";
5
5
  import { WebGLRenderer } from "three";
6
6
  import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
7
7
  import { LODsManager } from "./lods_manager.js";
package/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from "./extension.js";
2
2
  export * from "./plugins/index.js";
3
3
  export { LODsManager } from "./lods_manager.js";
4
- export { setDracoDecoderLocation, setKTX2TranscoderLocation } from "./loaders.js";
4
+ export { setDracoDecoderLocation, setKTX2TranscoderLocation, createLoaders, addDracoAndKTX2Loaders } from "./loaders.js";
5
5
  import { addDracoAndKTX2Loaders, createLoaders } from "./loaders.js";
6
6
  import { NEEDLE_progressive } from "./extension.js";
7
7
  import { LODsManager } from "./lods_manager.js";
@@ -70,11 +70,25 @@ export class LODsManager {
70
70
  }
71
71
  onBeforeRender(_scene, _camera, _stack, _frame) {
72
72
  }
73
- onAfterRender(scene, camera, stack, frame) {
73
+ onAfterRender(scene, camera, _stack, frame) {
74
74
  if (this.pause)
75
75
  return;
76
- // we only want to update LODs during the main render call
77
- if (stack == 0) {
76
+ const renderList = this.renderer.renderLists.get(scene, 0);
77
+ const opaque = renderList.opaque;
78
+ let updateLODs = true;
79
+ // check if we're rendering a postprocessing pass
80
+ if (opaque.length === 1) {
81
+ const material = opaque[0].material;
82
+ // pmndrs postprocessing
83
+ if (material.name === "EffectMaterial") {
84
+ updateLODs = false;
85
+ }
86
+ // builtin three postprocessing
87
+ else if (material.name === "CopyShader") {
88
+ updateLODs = false;
89
+ }
90
+ }
91
+ if (updateLODs) {
78
92
  if (suppressProgressiveLoading)
79
93
  return;
80
94
  if (this.updateInterval > 0 && frame % this.updateInterval != 0)
@@ -92,8 +106,6 @@ export class LODsManager {
92
106
  currentAllowedDensity *= 1.25;
93
107
  }
94
108
  */
95
- const renderList = this.renderer.renderLists.get(scene, stack);
96
- const opaque = renderList.opaque;
97
109
  for (const entry of opaque) {
98
110
  if (entry.material && (entry.geometry?.type === "BoxGeometry" || entry.geometry?.type === "BufferGeometry")) {
99
111
  // Ignore the skybox
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-progressive",
3
- "version": "1.0.0-alpha.11",
3
+ "version": "1.0.0-alpha.13",
4
4
  "description": "three.js support for loading glTF or GLB files that contain progressive loading data",
5
5
  "homepage": "https://needle.tools",
6
6
  "author": {