@needle-tools/gltf-progressive 1.0.0-alpha.8 → 1.1.0-alpha
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 +42 -0
- package/README.md +92 -0
- package/examples/modelviewer.html +27 -0
- package/examples/react-three-fiber/.prettierrc +10 -0
- package/examples/react-three-fiber/favicon.png +0 -0
- package/examples/react-three-fiber/index.html +24 -0
- package/examples/react-three-fiber/package-lock.json +4023 -0
- package/examples/react-three-fiber/package.json +34 -0
- package/examples/react-three-fiber/tsconfig.json +22 -0
- package/examples/react-three-fiber/vite.config.js +39 -0
- package/examples/threejs/index.html +51 -0
- package/examples/threejs/main.js +76 -0
- package/gltf-progressive.js +465 -318
- package/gltf-progressive.min.js +5 -3
- package/gltf-progressive.umd.cjs +5 -3
- package/lib/extension.d.ts +8 -2
- package/lib/extension.js +108 -15
- package/lib/index.d.ts +5 -4
- package/lib/index.js +6 -4
- package/lib/loaders.d.ts +10 -0
- package/lib/loaders.js +21 -2
- package/lib/lods_manager.d.ts +50 -3
- package/lib/lods_manager.js +354 -219
- package/lib/plugins/index.d.ts +1 -1
- package/lib/plugins/index.js +0 -1
- package/lib/plugins/modelviewer.js +7 -3
- package/lib/plugins/plugin.d.ts +4 -5
- package/lib/plugins/plugin.js +0 -6
- package/lib/utils.d.ts +13 -0
- package/lib/utils.js +24 -0
- package/package.json +1 -1
package/gltf-progressive.min.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
var
|
|
2
|
-
`,
|
|
3
|
-
`,v),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+l,y.guid);let _=0;if(x.parser.json.textures){let v=!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){v=!0;break}}_++}if(v){let f=await S.getDependency("texture",_);return s&&console.log('change "'+r.name+'" \u2192 "'+f.name+'"',l,_,f,d),r instanceof k&&(f=this.copySettings(r,f)),f&&(f.guid=y.guid),p(f)}}if(_=0,x.parser.json.meshes){let v=!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){v=!0;break}}_++}if(v){const f=await S.getDependency("mesh",_),w=y;if(s&&console.log(`Loaded Mesh "${f.name}"`,l,_,f,d),f.isMesh===!0){const E=f.geometry;return D.assignLODInformation(i.url,E,a,e,void 0,w.density),p(E)}else{const E=new Array;for(let C=0;C<f.children.length;C++){const W=f.children[C];if(W instanceof U){const j=W.geometry;D.assignLODInformation(i.url,j,a,e,C,w.density),E.push(j)}}return p(E)}}}return p(null)});return this.previouslyLoaded.set(d,A),await A}else if(r instanceof k){s&&console.log("Load texture from uri: "+l);const d=await new ae().loadAsync(l);return d?(d.guid=u.guid,d.flipY=!1,d.needsUpdate=!0,d.colorSpace=r.colorSpace,s&&console.log(u,d)):L&&console.warn("failed loading",l),d}}else L&&console.warn(`Can not load LOD ${e}: no LOD info found for "${a}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,o,n,s){if(!e)return;e.userData||(e.userData={});const i=new xe(r,t,o,n,s);e.userData.LODS=i,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)=>{L&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,o),e.source&&(e.source[X]=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 i;L&&console.log("> Progressive: register mesh",n,t.name,s,t.uuid,t);const a=t.geometry;a.userData||(a.userData={}),D.assignLODInformation(r,a,e,o,n,s.density),D.lodInfos.set(e,s);let u=D.lowresCache.get(e);u?u.push(t.geometry):u=[t.geometry],D.lowresCache.set(e,u);for(const h of V)(i=h.onRegisteredNewMesh)==null||i.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 xe{constructor(e,t,o,n,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=t,this.level=o,n!=null&&(this.index=n),s!=null&&(this.density=s)}}const K=q("debugprogressive"),ve=q("noprogressive"),T=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new Y),c(this,"cameraFrustrum",new le),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"plugins",[]),c(this,"_originalRender"),c(this,"_sphere",new ue),c(this,"_tempBox",new J),c(this,"tempMatrix",new Y),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;let t=0;Q(this.renderer),this.renderer.render=function(o,n){const s=t++,i=r++;e.onBeforeRender(o,n,i,s),e._originalRender.call(this,o,n),e.onAfterRender(o,n,i,s),r--}}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(ve||this.pause||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const i=1e5,a=this.renderer.renderLists.get(r,t),u=a.opaque;for(const l of u){if(l.material&&(((n=l.geometry)==null?void 0:n.type)==="BoxGeometry"||((s=l.geometry)==null?void 0:s.type)==="BufferGeometry")&&(l.material.name==="SphericalGaussianBlur"||l.material.name=="BackgroundCubeMaterial"||l.material.name==="CubemapFromEquirect"||l.material.name==="EquirectangularToCubeUV")){K&&(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",l,l.material.name,l.material.type)));continue}const d=l.object;(d instanceof U||d.isMesh)&&this.updateLODs(r,e,d,i)}const h=a.transparent;for(const l of h){const d=l.object;(d instanceof U||d.isMesh)&&this.updateLODs(r,e,d,i)}}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 i=t.userData.LOD_state;i||(i=new Le,t.userData.LOD_state=i);let a=this.calculateLodLevel(e,t,i,o);a=Math.round(a),a>=0&&this.loadProgressiveMeshes(t,a);let u=0;if(t.material){const h=t["DEBUG:LOD"];if(h!=null&&(u=h),Array.isArray(t.material))for(const l of t.material)this.loadProgressiveTextures(l,u);else this.loadProgressiveTextures(t.material,u)}for(const h of this.plugins)(s=h.onAfterUpdatedLOD)==null||s.call(h,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(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(K&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const i=O.getMeshLODInformation(e.geometry),a=i?.lods;if(!a||a.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e)))return 99;const u=e.geometry.boundingBox;if(u&&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(u),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 v=2,f=1.5,w=(g.x+m.x)*.5,E=(g.y+m.y)*.5;b=(b-w)*v+w,x=(x-E)*v+E,S=(S-w)*v+w,_=(_-E)*v+E;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)),j=Math.max(C,W);t.lastCentrality=(f-j)*(f-j)*(f-j)}else t.lastCentrality=1;const l=this._tempBox.getSize(this._tempBoxSize);l.multiplyScalar(.5),screen.availHeight>0&&l.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),l.x*=h.aspect;const d=r.matrixWorldInverse,M=new J;M.copy(u),M.applyMatrix4(e.matrixWorld),M.applyMatrix4(d);const y=M.getSize(this._tempBox2Size),A=Math.max(y.x,y.y);if(Math.max(l.x,l.y)!=0&&A!=0&&(l.z=y.z/Math.max(y.x,y.y)*Math.max(l.x,l.y)),t.lastScreenCoverage=Math.max(l.x,l.y,l.z),t.lastScreenspaceVolume.copy(l),t.lastScreenCoverage*=t.lastCentrality,K&&T.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const m=T.corner0,b=T.corner1,x=T.corner2,S=T.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),T.debugDrawLine(m,b,255),T.debugDrawLine(m,x,255),T.debugDrawLine(b,S,255),T.debugDrawLine(x,S,255)}let p=999;if(a&&t.lastScreenCoverage>0){for(let g=0;g<a.length;g++)if(a[g].density/t.lastScreenCoverage<o){p=g;break}}p<s&&(s=p)}}return s}};let I=T;c(I,"debugDrawLine"),c(I,"corner0",new B),c(I,"corner1",new B),c(I,"corner2",new B),c(I,"corner3",new B);class Le{constructor(){c(this,"lastLodLevel",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const re=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function te(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(a=>a.toString()=="Symbol(renderer)"),i=n.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 o=new I(e);if(o.plugins.push(new De(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 De{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(a){var u,h,l;if(a[z]==!0)return;a[z]=!0,a.userData&&(a.userData.LOD=-1);const d=Object.keys(a);for(let M=0;M<d.length;M++){const y=d[M],A=a[y];if(A?.isTexture===!0){const p=(h=(u=A.userData)==null?void 0:u.associations)==null?void 0:h.textures,g=o.parser.json.textures[p];if((l=g.extensions)!=null&&l[P]){const m=g.extensions[P];m&&n&&O.registerTexture(n,A,m.lods.length,m)}}}};const i=t.material;if(Array.isArray(i))for(const a of i)s(a);else s(i)}}tryParseMeshLOD(e,t){var o,n;if(t[re]==!0)return;t[re]=!0;const s=this.getUrl();if(!s)return;const i=(n=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:n[P];if(i&&s){const a=t.uuid;O.registerMesh(s,a,t,0,i.lods.length,i)}}}function Oe(r,e,t,o){Q(e),Z(t),t.register(s=>new O(s,r));const n=new I(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{te(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,O as NEEDLE_progressive,te as patchModelViewer,ye as registerPlugin,Oe as useNeedleProgressive};
|
|
1
|
+
var fe=Object.defineProperty,me=(t,e,r)=>e in t?fe(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,c=(t,e,r)=>(me(t,typeof e!="symbol"?e+"":e,r),r);import{MeshoptDecoder as ge}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as pe}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as ye}from"three/examples/jsm/loaders/KTX2Loader.js";import{BufferGeometry as $,Mesh as q,Material as xe,Texture as F,TextureLoader as Le,Matrix4 as se,Frustum as De,Sphere as ve,Box3 as oe,Vector3 as P}from"three";import{GLTFLoader as Me}from"three/examples/jsm/loaders/GLTFLoader.js";let V="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",H="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(V+"draco_decoder.js",{method:"head"}).catch(t=>{V="./include/draco/",H="./include/ktx2/"});function Oe(t){V=t}function we(t){H=t}let U,Y,W;function J(t){U||(U=new pe,U.setDecoderPath(V),U.setDecoderConfig({type:"js"})),W||(W=new ye,W.setTranscoderPath(H)),Y||(Y=ge),t?W.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function Q(t){t.dracoLoader||t.setDRACOLoader(U),t.ktx2Loader||t.setKTX2Loader(W),t.meshoptDecoder||t.setMeshoptDecoder(Y)}function Z(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function _e(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const r=t.lastIndexOf("/");if(r>=0){const o=t.substring(0,r+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}function ne(t){var e;return((e=t.userData)==null?void 0:e["needle:raycast-mesh"])instanceof $?t.userData["needle:raycast-mesh"]:null}function ie(t,e){(t.type==="Mesh"||t.type==="SkinnedMesh")&&(t.userData||(t.userData={}),t.userData["needle:raycast-mesh"]=e)}const C=new Array,I="NEEDLE_progressive",v=Z("debugprogressive"),ee=Symbol("needle-progressive-texture"),z=new Map,te=new Set;if(v){let t=function(){e+=1,console.log("Toggle LOD level",e,z),z.forEach((n,s)=>{for(const a of n.keys){const i=s[a];if(i.isBufferGeometry===!0){const u=w.getMeshLODInformation(i),l=u?Math.min(e,u.lods.length):0;s["DEBUG:LOD"]=e,w.assignMeshLOD(s,l),u&&(r=Math.max(r,u.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,w.assignTextureLOD(s,e);break}}}),e>=r&&(e=-1)},e=-1,r=2,o=!1;window.addEventListener("keyup",n=>{n.key==="p"&&t(),n.key==="w"&&(o=!o,te&&te.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=o)}))})}function ae(t,e,r){var o;if(!v)return;z.has(t)||z.set(t,{keys:[],sourceId:r});const n=z.get(t);((o=n?.keys)==null?void 0:o.includes(e))==!1&&n.keys.push(e)}const M=class{constructor(t,e){c(this,"parser"),c(this,"url"),v&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return I}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e={min:1/0,max:-1}){if(Array.isArray(t)){for(const n of t)this.getMaterialMinMaxLODsCount(n,e);return e}let r=e.min,o=e.max;if(t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const n=t;for(const s of Object.keys(n.uniforms)){const a=n.uniforms[s].value;if(a?.isTexture===!0){const i=this.getAssignedLODInformation(a);if(i){const u=this.lodInfos.get(i.key);u&&u.lods&&(r=Math.min(r,u.lods.length),o=Math.max(o,u.lods.length))}}}}else if(t.isMaterial)for(const n of Object.keys(t)){const s=t[n];if(s?.isTexture===!0){const a=this.getAssignedLODInformation(s);if(a){const i=this.lodInfos.get(a.key);i&&i.lods&&(r=Math.min(r,i.lods.length),o=Math.max(o,i.lods.length))}}}return e.min=r,e.max=o,e}static hasLODLevelAvailable(t,e){var r;if(Array.isArray(t)){for(const s of t)if(this.hasLODLevelAvailable(s,e))return!0;return!1}if(t.isMaterial===!0){for(const s of Object.keys(t)){const a=t[s];if(a&&a.isTexture&&this.hasLODLevelAvailable(a,e))return!0}return!1}else if(t.isGroup===!0){for(const s of t.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let o,n;if(t.isMesh?o=t.geometry:(t.isBufferGeometry||t.isTexture)&&(o=t),o&&(r=o?.userData)!=null&&r.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(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof q||t.isMesh===!0){const o=t.geometry,n=this.getAssignedLODInformation(o);if(!n)return Promise.resolve(null);for(const s of C)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,M.getOrLoadLOD(o,e).then(s=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(s)){const a=n.index||0;s=s[a]}s&&o!=s&&s instanceof $&&(t.geometry=s,v&&ae(t,"geometry",n.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",t,s),null))}else v&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof xe||t.isMaterial===!0){const r=t,o=[],n=new Array;if(v&&te.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const a of Object.keys(s.uniforms)){const i=s.uniforms[a].value;if(i?.isTexture===!0){const u=this.assignTextureLODForSlot(i,e,r,a);o.push(u),n.push(a)}}}else for(const s of Object.keys(r)){const a=r[s];if(a?.isTexture===!0){const i=this.assignTextureLODForSlot(a,e,r,s);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 u=s[i],l=n[i];u&&u.isTexture===!0?a.push({material:r,slot:l,texture:u,level:e}):a.push({material:r,slot:l,texture:null,level:e})}return a})}if(t instanceof F||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,o){if(t?.isTexture!==!0)return Promise.resolve(null);if(o==="glyphMap")return Promise.resolve(t);const n="LOD:requested level:"+o;return r&&(r[n]=e),M.getOrLoadLOD(t,e).then(s=>{if(r&&r[n]!=e||Array.isArray(s))return null;if(s?.isTexture===!0){if(s!=t&&(r&&o&&(r[o]=s),v&&o&&r)){const a=this.getAssignedLODInformation(t);a&&ae(r,o,a.url)}return s}else v=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(s=>(console.error("Error loading LOD",t,s),null))}afterRoot(t){var e,r;return v&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[I];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,M.registerTexture(this.url,i,n,s));a||this.parser.getDependency("texture",n).then(i=>{i&&M.registerTexture(this.url,i,n,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[I];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&&M.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(t,e){var r,o,n,s;const a=v=="verbose",i=t.userData.LODS;if(!i)return null;const u=i?.key;let l;if(t.isTexture===!0){const x=t;x.source&&x.source[ee]&&(l=x.source[ee])}if(l||(l=M.lodInfos.get(u)),l){if(e>0){let f=!1;const b=Array.isArray(l.lods);if(b&&e>=l.lods.length?f=!0:b||(f=!0),f)return this.lowresCache.get(u)}const x=Array.isArray(l.lods)?(r=l.lods[e])==null?void 0:r.path:l.lods;if(!x)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const h=_e(i.url,x);if(h.endsWith(".glb")||h.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const f=h+"_"+l.guid,b=this.previouslyLoaded.get(f);if(b!==void 0){a&&console.log(`LOD ${e} was already loading/loaded: ${f}`);let p=await b.catch(G=>(console.error(`Error loading LOD ${e} from ${h}
|
|
2
|
+
`,G),null)),_=!1;if(p==null||(p instanceof F&&t instanceof F?(o=p.image)!=null&&o.data||(n=p.source)!=null&&n.data?p=this.copySettings(t,p):(_=!0,this.previouslyLoaded.delete(f)):p instanceof $&&t instanceof $&&((s=p.attributes.position)!=null&&s.array||(_=!0,this.previouslyLoaded.delete(f)))),!_)return p}const m=l,k=new Promise(async(p,_)=>{const G=new Me;Q(G),v&&(await new Promise(y=>setTimeout(y,1e3)),a&&console.warn("Start loading (delayed) "+h,m.guid));let N=h;if(m&&Array.isArray(m.lods)){const y=m.lods[e];y.hash&&(N+="?v="+y.hash)}const g=await G.loadAsync(N).catch(y=>(console.error(`Error loading LOD ${e} from ${h}
|
|
3
|
+
`,y),null));if(!g)return null;const L=g.parser;a&&console.log("Loading finished "+h,m.guid);let D=0;if(g.parser.json.textures){let y=!1;for(const d of g.parser.json.textures){if(d!=null&&d.extensions){const O=d?.extensions[I];if(O!=null&&O.guid&&O.guid===m.guid){y=!0;break}}D++}if(y){let d=await L.getDependency("texture",D);return d&&M.assignLODInformation(i.url,d,u,e,void 0,void 0),a&&console.log('change "'+t.name+'" \u2192 "'+d.name+'"',h,D,d,f),t instanceof F&&(d=this.copySettings(t,d)),d&&(d.guid=m.guid),p(d)}else v&&console.warn("Could not find texture with guid",m.guid)}if(D=0,g.parser.json.meshes){let y=!1;for(const d of g.parser.json.meshes){if(d!=null&&d.extensions){const O=d?.extensions[I];if(O!=null&&O.guid&&O.guid===m.guid){y=!0;break}}D++}if(y){const d=await L.getDependency("mesh",D),O=m;if(a&&console.log(`Loaded Mesh "${d.name}"`,h,D,d,f),d.isMesh===!0){const T=d.geometry;return M.assignLODInformation(i.url,T,u,e,void 0,O.density),p(T)}else{const T=new Array;for(let B=0;B<d.children.length;B++){const j=d.children[B];if(j instanceof q){const R=j.geometry;M.assignLODInformation(i.url,R,u,e,B,O.density),T.push(R)}}return p(T)}}}return p(null)});return this.previouslyLoaded.set(f,k),await k}else if(t instanceof F){a&&console.log("Load texture from uri: "+h);const f=await new Le().loadAsync(h);return f?(f.guid=l.guid,f.flipY=!1,f.needsUpdate=!0,f.colorSpace=t.colorSpace,a&&console.log(l,f)):v&&console.warn("failed loading",h),f}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,o,n,s){if(!e)return;e.userData||(e.userData={});const a=new be(t,r,o,n,s);e.userData.LODS=a,e.userData.LOD=o}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),v&&console.warn(`Copying texture settings
|
|
4
|
+
`,t.uuid,`
|
|
5
|
+
`,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let w=M;c(w,"registerTexture",(t,e,r,o)=>{v&&console.log("> Progressive: register texture",r,e.name,e.uuid,e,o),e.source&&(e.source[ee]=o);const n=o.guid;M.assignLODInformation(t,e,n,0,0,void 0),M.lodInfos.set(n,o),M.lowresCache.set(n,e)}),c(w,"registerMesh",(t,e,r,o,n,s)=>{var a;v&&console.log("> Progressive: register mesh",n,r.name,s,r.uuid,r);const i=r.geometry;i.userData||(i.userData={}),M.assignLODInformation(t,i,e,o,n,s.density),M.lodInfos.set(e,s);let u=M.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],M.lowresCache.set(e,u),o>0&&!ne(r)&&ie(r,i);for(const l of C)(a=l.onRegisteredNewMesh)==null||a.call(l,r,s)}),c(w,"lodInfos",new Map),c(w,"previouslyLoaded",new Map),c(w,"lowresCache",new Map);class be{constructor(e,r,o,n,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=r,this.level=o,n!=null&&(this.index=n),s!=null&&(this.density=s)}}const re=Z("debugprogressive"),Se=Z("noprogressive"),le=Symbol("Needle:LODSManager"),E={mesh_lod:-1,texture_lod:-1},S=class{constructor(t){c(this,"renderer"),c(this,"projectionScreenMatrix",new se),c(this,"cameraFrustrum",new De),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new ve),c(this,"_tempBox",new oe),c(this,"_tempBox2",new oe),c(this,"tempMatrix",new se),c(this,"_tempWorldPosition",new P),c(this,"_tempBoxSize",new P),c(this,"_tempBox2Size",new P),this.renderer=t}static getObjectLODState(t){var e;return(e=t.userData)==null?void 0:e.LOD_state}static addPlugin(t){C.push(t)}static removePlugin(t){const e=C.indexOf(t);e>=0&&C.splice(e,1)}static get(t){return t[le]?t[le]:new S(t)}get plugins(){return C}enable(){if(this._originalRender)return;let t=0;this._originalRender=this.renderer.render;const e=this;J(this.renderer),this.renderer.render=function(r,o){e.renderer.getRenderTarget()==null&&(t=0,e._frame+=1);const n=e._frame,s=t++;e.onBeforeRender(r,o,s,n),e._originalRender.call(this,r,o),e.onAfterRender(r,o,s,n)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,o){}onAfterRender(t,e,r,o){var n,s;if(this.pause)return;const a=this.renderer.renderLists.get(t,0),i=a.opaque;let u=!0;if(i.length===1){const l=i[0].material;(l.name==="EffectMaterial"||l.name==="CopyShader")&&(u=!1)}if(e.parent&&e.parent.type==="CubeCamera"&&(u=!1),u){if(Se||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const l=this.targetTriangleDensity;for(const h of i){if(h.material&&(((n=h.geometry)==null?void 0:n.type)==="BoxGeometry"||((s=h.geometry)==null?void 0:s.type)==="BufferGeometry")&&(h.material.name==="SphericalGaussianBlur"||h.material.name=="BackgroundCubeMaterial"||h.material.name==="CubemapFromEquirect"||h.material.name==="EquirectangularToCubeUV")){re&&(h.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(h.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",h,h.material.name,h.material.type)));continue}switch(h.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const f=h.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,l,o)}const x=a.transparent;for(const h of x){const f=h.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,l,o)}}}updateLODs(t,e,r,o,n){var s,a;let i=r.userData.LOD_state;if(i||(i=new Te,r.userData.LOD_state=i),i.frames++<2)return;for(const l of C)(s=l.onBeforeUpdateLOD)==null||s.call(l,this.renderer,t,e,r);this.calculateLodLevel(e,r,i,o,E),E.mesh_lod=Math.round(E.mesh_lod),E.texture_lod=Math.round(E.texture_lod),E.mesh_lod>=0&&this.loadProgressiveMeshes(r,E.mesh_lod);let u=E.texture_lod;if(r.material&&u>=0){const l=r["DEBUG:LOD"];l!=null&&(u=l),this.loadProgressiveTextures(r.material,u)}for(const l of C)(a=l.onAfterUpdatedLOD)==null||a.call(l,this.renderer,t,e,r,E);i.lastLodLevel_Mesh=E.mesh_lod,i.lasLodLevel_Texture=E.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const n of t)this.loadProgressiveTextures(n,e);return}const r=t;let o=!1;(r.NEEDLE_LOD==null||e<r.NEEDLE_LOD)&&(o=!0),o&&(r.NEEDLE_LOD=e,w.assignTextureLOD(t,e))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t.userData||(t.userData={}),t.userData.LOD!==e){t.userData.LOD=e;const r=t.geometry;return w.assignMeshLOD(t,e).then(o=>(o&&t.userData.LOD==e&&r!=t.geometry,o))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,o=t.max,n=(r.x+o.x)*.5,s=(r.y+o.y)*.5;return this._tempPtInside.set(n,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,o,n){var s;if(!e){n.mesh_lod=-1,n.texture_lod=-1;return}if(!t){n.mesh_lod=-1,n.texture_lod=-1;return}let a=10+1;if(re&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const i=w.getMeshLODInformation(e.geometry),u=i?.lods,l=u&&u.length>0,x=w.getMaterialMinMaxLODsCount(e.material),h=x?.min!=1/0&&x.min>0&&x.max>0;if(!l&&!h){n.mesh_lod=0,n.texture_lod=0;return}if(l||(a=0),!((s=this.cameraFrustrum)!=null&&s.intersectsObject(e))){n.mesh_lod=99,n.texture_lod=99;return}const f=e.geometry.boundingBox;if(f&&t.isPerspectiveCamera){const b=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const g=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g)){n.mesh_lod=0,n.texture_lod=0;return}}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(e.matrixWorld),S.isInside(this._tempBox,this.projectionScreenMatrix)){n.mesh_lod=0,n.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&b.fov>70){const g=this._tempBox.min,L=this._tempBox.max;let D=g.x,y=g.y,d=L.x,O=L.y;const T=2,B=1.5,j=(g.x+L.x)*.5,R=(g.y+L.y)*.5;D=(D-j)*T+j,y=(y-R)*T+R,d=(d-j)*T+j,O=(O-R)*T+R;const de=D<0&&d>0?0:Math.min(Math.abs(g.x),Math.abs(L.x)),he=y<0&&O>0?0:Math.min(Math.abs(g.y),Math.abs(L.y)),K=Math.max(de,he);r.lastCentrality=(B-K)*(B-K)*(B-K)}else r.lastCentrality=1;const m=this._tempBox.getSize(this._tempBoxSize);m.multiplyScalar(.5),screen.availHeight>0&&m.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),m.x*=b.aspect;const k=t.matrixWorldInverse,p=this._tempBox2;p.copy(f),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(k);const _=p.getSize(this._tempBox2Size),G=Math.max(_.x,_.y);if(Math.max(m.x,m.y)!=0&&G!=0&&(m.z=_.z/Math.max(_.x,_.y)*Math.max(m.x,m.y)),r.lastScreenCoverage=Math.max(m.x,m.y,m.z),r.lastScreenspaceVolume.copy(m),r.lastScreenCoverage*=r.lastCentrality,re&&S.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const L=S.corner0,D=S.corner1,y=S.corner2,d=S.corner3;L.copy(this._tempBox.min),D.copy(this._tempBox.max),D.x=L.x,y.copy(this._tempBox.max),y.y=L.y,d.copy(this._tempBox.max);const O=(L.z+d.z)*.5;L.z=D.z=y.z=d.z=O,L.applyMatrix4(g),D.applyMatrix4(g),y.applyMatrix4(g),d.applyMatrix4(g),S.debugDrawLine(L,D,255),S.debugDrawLine(L,y,255),S.debugDrawLine(D,d,255),S.debugDrawLine(y,d,255)}let N=999;if(u&&r.lastScreenCoverage>0){for(let g=0;g<u.length;g++)if(u[g].density/r.lastScreenCoverage<o){N=g;break}}N<a&&(a=N)}if(n.mesh_lod=a,x!=null&&x.min&&x.min>0&&x.max>0){const b=Math.min(1,Math.max(0,r.lastScreenCoverage*3));n.texture_lod=Ee(x.max,0,b)}else n.texture_lod=0}};let A=S;c(A,"debugDrawLine"),c(A,"corner0",new P),c(A,"corner1",new P),c(A,"corner2",new P),c(A,"corner3",new P),c(A,"_tempPtInside",new P);function Ee(t,e,r){return t+(e-t)*r}class Te{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",0),c(this,"lasLodLevel_Texture",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new P),c(this,"lastCentrality",0)}}const ue=Symbol("NEEDLE_mesh_lod"),X=Symbol("NEEDLE_texture_lod");function ce(t){if(!t)return null;let e=null,r=null;for(let o=t;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=t[s].threeRenderer),!r&&a!=null&&(r=t[a])}if(e){console.log("Adding Needle LODs to modelviewer");const o=A.get(e);if(A.addPlugin(new Ae(t)),o.enable(),r){const n=r.camera||r.traverse(s=>s.type=="PerspectiveCamera")[0];n&&e.render(r,n)}return()=>{o.disable()}}return null}class Ae{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,r,o,n){this.tryParseMeshLOD(r,n),this.tryParseTextureLOD(r,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,r){if(r[X]==!0)return;r[X]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&r.material){let s=function(i){var u,l,x;if(i[X]==!0)return;i[X]=!0,i.userData&&(i.userData.LOD=-1);const h=Object.keys(i);for(let f=0;f<h.length;f++){const b=h[f],m=i[b];if(m?.isTexture===!0){const k=(l=(u=m.userData)==null?void 0:u.associations)==null?void 0:l.textures,p=o.parser.json.textures[k];if(!p){console.warn("Texture data not found for texture index "+k);continue}if((x=p?.extensions)!=null&&x[I]){const _=p.extensions[I];_&&n&&w.registerTexture(n,m,_.lods.length,_)}}}};const a=r.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,r){var o,n;if(r[ue]==!0)return;r[ue]=!0;const s=this.getUrl();if(!s)return;const a=(n=(o=r.userData)==null?void 0:o.gltfExtensions)==null?void 0:n[I];if(a&&s){const i=r.uuid;w.registerMesh(s,i,r,0,a.lods.length,a)}}}function Pe(t,e,r,o){J(e),Q(r),r.register(s=>new w(s,t));const n=A.get(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{ce(document.querySelector("model-viewer"))});export{I as EXTENSION_NAME,A as LODsManager,w as NEEDLE_progressive,Q as addDracoAndKTX2Loaders,J as createLoaders,ne as getRaycastMesh,ce as patchModelViewer,Oe as setDracoDecoderLocation,we as setKTX2TranscoderLocation,ie as setRaycastMesh,Pe as useNeedleProgressive};
|
package/gltf-progressive.umd.cjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`,
|
|
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 g of y.parser.json.textures){if(g!=null&&g.extensions){const v=g==null?void 0:g.extensions[C];if(v!=null&&v.guid&&v.guid===D.guid){L=!0;break}}O++}if(L){let g=await b.getDependency("texture",O);return r&&console.log('change "'+e.name+'" → "'+g.name+'"',c,O,g,f),e instanceof h.Texture&&(g=this.copySettings(e,g)),g&&(g.guid=D.guid),x(g)}}if(O=0,y.parser.json.meshes){let L=!1;for(const g of y.parser.json.meshes){if(g!=null&&g.extensions){const v=g==null?void 0:g.extensions[C];if(v!=null&&v.guid&&v.guid===D.guid){L=!0;break}}O++}if(L){const g=await b.getDependency("mesh",O),v=D;if(r&&console.log(`Loaded Mesh "${g.name}"`,c,O,g,f),g.isMesh===!0){const B=g.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<g.children.length;E++){const k=g.children[E];if(k instanceof h.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 h.Texture){r&&console.log("Load texture from uri: "+c);const M=await new h.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 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[q]=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 p;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 d of K)(p=d.onRegisteredNewMesh)==null||p.call(d,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 $=H("debugprogressive"),ge=H("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){var p,d;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,s=this.renderer.renderLists.get(e,r),n=s.opaque;for(const c of n){if(c.material&&(((p=c.geometry)==null?void 0:p.type)==="BoxGeometry"||((d=c.geometry)==null?void 0:d.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 h.Mesh||f.isMesh)&&this.updateLODs(e,t,f,o)}const a=s.transparent;for(const c of a){const f=c.object;(f instanceof h.Mesh||f.isMesh)&&this.updateLODs(e,t,f,o)}}updateLODs(e,t,r,i){var a,p;for(const d of this.plugins)(a=d.onBeforeUpdateLOD)==null||a.call(d,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 d=r["DEBUG:LOD"];if(d!=null&&(n=d),Array.isArray(r.material))for(const c of r.material)this.loadProgressiveTextures(c,n);else this.loadProgressiveTextures(r.material,n)}for(const d of this.plugins)(p=d.onAfterUpdatedLOD)==null||p.call(d,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),p=a==null?void 0:a.lods;if(!p||p.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(t)))return 99;const d=t.geometry.boundingBox;if(d&&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(d),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,g=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,g=(g-k)*v+k;const W=b<0&&L>0?0:Math.min(Math.abs(m.x),Math.abs(y.x)),te=O<0&&g>0?0:Math.min(Math.abs(m.y),Math.abs(y.y)),V=Math.max(W,te);r.lastCentrality=(B-V)*(B-V)*(B-V)}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 h.Box3;D.copy(d),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 g=(y.z+L.z)*.5;y.z=b.z=O.z=L.z=g,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(p&&r.lastScreenCoverage>0){for(let m=0;m<p.length;m++)if(p[m].density/r.lastScreenCoverage<i){R=m;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"),z=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");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 p,d,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=(d=(p=D.userData)==null?void 0:p.associations)==null?void 0:d.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[Q]==!0)return;t[Q]=!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 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=C;exports.LODsManager=_;exports.NEEDLE_progressive=w;exports.patchModelViewer=ee;exports.registerPlugin=fe;exports.useNeedleProgressive=ye;
|
|
1
|
+
"use strict";var de=Object.defineProperty;var he=(a,e,t)=>e in a?de(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var u=(a,e,t)=>(he(a,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ge=require("three/examples/jsm/libs/meshopt_decoder.module.js"),pe=require("three/examples/jsm/loaders/DRACOLoader.js"),ye=require("three/examples/jsm/loaders/KTX2Loader.js"),g=require("three"),me=require("three/examples/jsm/loaders/GLTFLoader.js");let $="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ee="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch($+"draco_decoder.js",{method:"head"}).catch(a=>{$="./include/draco/",ee="./include/ktx2/"});function Le(a){$=a}function xe(a){ee=a}let U,Z,z;function te(a){U||(U=new pe.DRACOLoader,U.setDecoderPath($),U.setDecoderConfig({type:"js"})),z||(z=new ye.KTX2Loader,z.setTranscoderPath(ee)),Z||(Z=ge.MeshoptDecoder),a?z.detectSupport(a):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function re(a){a.dracoLoader||a.setDRACOLoader(U),a.ktx2Loader||a.setKTX2Loader(z),a.meshoptDecoder||a.setMeshoptDecoder(Z)}function se(a){const t=new URL(window.location.href).searchParams.get(a);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function De(a,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||a===void 0)return e;const t=a.lastIndexOf("/");if(t>=0){const r=a.substring(0,t+1);for(;r.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return r+e}return e}function ae(a){var e;return((e=a.userData)==null?void 0:e["needle:raycast-mesh"])instanceof g.BufferGeometry?a.userData["needle:raycast-mesh"]:null}function le(a,e){(a.type==="Mesh"||a.type==="SkinnedMesh")&&(a.userData||(a.userData={}),a.userData["needle:raycast-mesh"]=e)}const R=new Array,k="NEEDLE_progressive",_=se("debugprogressive"),J=Symbol("needle-progressive-texture"),W=new Map,j=new Set;if(_){let a=function(){e+=1,console.log("Toggle LOD level",e,W),W.forEach((i,n)=>{for(const s of i.keys){const o=n[s];if(o.isBufferGeometry===!0){const l=S.getMeshLODInformation(o),d=l?Math.min(e,l.lods.length):0;n["DEBUG:LOD"]=e,S.assignMeshLOD(n,d),l&&(t=Math.max(t,l.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,S.assignTextureLOD(n,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",i=>{i.key==="p"&&a(),i.key==="w"&&(r=!r,j&&j.forEach(n=>{n.name!="BackgroundCubeMaterial"&&"wireframe"in n&&(n.wireframe=r)}))})}function ie(a,e,t){var i;if(!_)return;W.has(a)||W.set(a,{keys:[],sourceId:t});const r=W.get(a);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const v=class{constructor(e,t){u(this,"parser");u(this,"url");_&&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 getMaterialMinMaxLODsCount(e,t={min:1/0,max:-1}){if(Array.isArray(e)){for(const n of e)this.getMaterialMinMaxLODsCount(n,t);return t}let r=t.min,i=t.max;if(e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const n=e;for(const s of Object.keys(n.uniforms)){const o=n.uniforms[s].value;if((o==null?void 0:o.isTexture)===!0){const l=this.getAssignedLODInformation(o);if(l){const d=this.lodInfos.get(l.key);d&&d.lods&&(r=Math.min(r,d.lods.length),i=Math.max(i,d.lods.length))}}}}else if(e.isMaterial)for(const n of Object.keys(e)){const s=e[n];if((s==null?void 0:s.isTexture)===!0){const o=this.getAssignedLODInformation(s);if(o){const l=this.lodInfos.get(o.key);l&&l.lods&&(r=Math.min(r,l.lods.length),i=Math.max(i,l.lods.length))}}}return t.min=r,t.max=i,t}static hasLODLevelAvailable(e,t){var n;if(Array.isArray(e)){for(const s of e)if(this.hasLODLevelAvailable(s,t))return!0;return!1}if(e.isMaterial===!0){for(const s of Object.keys(e)){const o=e[s];if(o&&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 g.Mesh||e.isMesh===!0){const i=e.geometry,n=this.getAssignedLODInformation(i);if(!n)return Promise.resolve(null);for(const s of R)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,v.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 g.BufferGeometry&&(e.geometry=s,_&&ie(e,"geometry",n.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",e,s),null))}else _&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e instanceof g.Material||e.isMaterial===!0){const r=e,i=[],n=new Array;if(_&&j.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const o of Object.keys(s.uniforms)){const l=s.uniforms[o].value;if((l==null?void 0:l.isTexture)===!0){const d=this.assignTextureLODForSlot(l,t,r,o);i.push(d),n.push(o)}}}else for(const s of Object.keys(r)){const o=r[s];if((o==null?void 0:o.isTexture)===!0){const l=this.assignTextureLODForSlot(o,t,r,s);i.push(l),n.push(s)}}return Promise.all(i).then(s=>{const o=new Array;for(let l=0;l<s.length;l++){const d=s[l],h=n[l];d&&d.isTexture===!0?o.push({material:r,slot:h,texture:d,level:t}):o.push({material:r,slot:h,texture:null,level:t})}return o})}if(e instanceof g.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,i){if((e==null?void 0:e.isTexture)!==!0)return Promise.resolve(null);if(i==="glyphMap")return Promise.resolve(e);const n="LOD:requested level:"+i;return r&&(r[n]=t),v.getOrLoadLOD(e,t).then(s=>{if(r&&r[n]!=t||Array.isArray(s))return null;if((s==null?void 0:s.isTexture)===!0){if(s!=e&&(r&&i&&(r[i]=s),_&&i&&r)){const o=this.getAssignedLODInformation(e);o&&ie(r,i,o.url)}return s}else _=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(s=>(console.error("Error loading LOD",e,s),null))}afterRoot(e){var t,r;return _&&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[k];if(s){let o=!1;for(const l of this.parser.associations.keys())l.isTexture===!0&&this.parser.associations.get(l).textures===n&&(o=!0,v.registerTexture(this.url,l,n,s));o||this.parser.getDependency("texture",n).then(l=>{l&&v.registerTexture(this.url,l,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[k];if(s&&s.lods){for(const o of this.parser.associations.keys())if(o.isMesh){const l=this.parser.associations.get(o);l.meshes===n&&v.registerMesh(this.url,s.guid,o,s.lods.length,l.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var o,l,d,h;const r=_=="verbose",i=e.userData.LODS;if(!i)return null;const n=i==null?void 0:i.key;let s;if(e.isTexture===!0){const L=e;L.source&&L.source[J]&&(s=L.source[J])}if(s||(s=v.lodInfos.get(n)),s){if(t>0){let m=!1;const D=Array.isArray(s.lods);if(D&&t>=s.lods.length?m=!0:D||(m=!0),m)return this.lowresCache.get(n)}const L=Array.isArray(s.lods)?(o=s.lods[t])==null?void 0:o.path:s.lods;if(!L)return _&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const f=De(i.url,L);if(f.endsWith(".glb")||f.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const m=f+"_"+s.guid,D=this.previouslyLoaded.get(m);if(D!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${m}`);let w=await D.catch(F=>(console.error(`Error loading LOD ${t} from ${f}
|
|
2
|
+
`,F),null)),E=!1;if(w==null||(w instanceof g.Texture&&e instanceof g.Texture?(l=w.image)!=null&&l.data||(d=w.source)!=null&&d.data?w=this.copySettings(e,w):(E=!0,this.previouslyLoaded.delete(m)):w instanceof g.BufferGeometry&&e instanceof g.BufferGeometry&&((h=w.attributes.position)!=null&&h.array||(E=!0,this.previouslyLoaded.delete(m)))),!E)return w}const O=s,M=new Promise(async(w,E)=>{const F=new me.GLTFLoader;re(F),_&&(await new Promise(p=>setTimeout(p,1e3)),r&&console.warn("Start loading (delayed) "+f,O.guid));let K=f;if(O&&Array.isArray(O.lods)){const p=O.lods[t];p.hash&&(K+="?v="+p.hash)}const B=await F.loadAsync(K).catch(p=>(console.error(`Error loading LOD ${t} from ${f}
|
|
3
|
+
`,p),null));if(!B)return null;const Y=B.parser;r&&console.log("Loading finished "+f,O.guid);let y=0;if(B.parser.json.textures){let p=!1;for(const c of B.parser.json.textures){if(c!=null&&c.extensions){const x=c==null?void 0:c.extensions[k];if(x!=null&&x.guid&&x.guid===O.guid){p=!0;break}}y++}if(p){let c=await Y.getDependency("texture",y);return c&&v.assignLODInformation(i.url,c,n,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+c.name+'"',f,y,c,m),e instanceof g.Texture&&(c=this.copySettings(e,c)),c&&(c.guid=O.guid),w(c)}else _&&console.warn("Could not find texture with guid",O.guid)}if(y=0,B.parser.json.meshes){let p=!1;for(const c of B.parser.json.meshes){if(c!=null&&c.extensions){const x=c==null?void 0:c.extensions[k];if(x!=null&&x.guid&&x.guid===O.guid){p=!0;break}}y++}if(p){const c=await Y.getDependency("mesh",y),x=O;if(r&&console.log(`Loaded Mesh "${c.name}"`,f,y,c,m),c.isMesh===!0){const T=c.geometry;return v.assignLODInformation(i.url,T,n,t,void 0,x.density),w(T)}else{const T=new Array;for(let C=0;C<c.children.length;C++){const I=c.children[C];if(I instanceof g.Mesh){const N=I.geometry;v.assignLODInformation(i.url,N,n,t,C,x.density),T.push(N)}}return w(T)}}}return w(null)});return this.previouslyLoaded.set(m,M),await M}else if(e instanceof g.Texture){r&&console.log("Load texture from uri: "+f);const D=await new g.TextureLoader().loadAsync(f);return D?(D.guid=s.guid,D.flipY=!1,D.needsUpdate=!0,D.colorSpace=e.colorSpace,r&&console.log(s,D)):_&&console.warn("failed loading",f),D}}else _&&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 Me(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){return t=t.clone(),_&&console.warn(`Copying texture settings
|
|
4
|
+
`,e.uuid,`
|
|
5
|
+
`,t.uuid),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.mipmaps||(t.generateMipmaps=e.generateMipmaps),t}};let S=v;u(S,"registerTexture",(e,t,r,i)=>{_&&console.log("> Progressive: register texture",r,t.name,t.uuid,t,i),t.source&&(t.source[J]=i);const n=i.guid;v.assignLODInformation(e,t,n,0,0,void 0),v.lodInfos.set(n,i),v.lowresCache.set(n,t)}),u(S,"registerMesh",(e,t,r,i,n,s)=>{var d;_&&console.log("> Progressive: register mesh",n,r.name,s,r.uuid,r);const o=r.geometry;o.userData||(o.userData={}),v.assignLODInformation(e,o,t,i,n,s.density),v.lodInfos.set(t,s);let l=v.lowresCache.get(t);l?l.push(r.geometry):l=[r.geometry],v.lowresCache.set(t,l),i>0&&!ae(r)&&le(r,o);for(const h of R)(d=h.onRegisteredNewMesh)==null||d.call(h,r,s)}),u(S,"lodInfos",new Map),u(S,"previouslyLoaded",new Map),u(S,"lowresCache",new Map);class Me{constructor(e,t,r,i,n){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),n!=null&&(this.density=n)}}const Q=se("debugprogressive"),Oe=se("noprogressive"),ne=Symbol("Needle:LODSManager"),P={mesh_lod:-1,texture_lod:-1},A=class{constructor(e){u(this,"renderer");u(this,"projectionScreenMatrix",new g.Matrix4);u(this,"cameraFrustrum",new g.Frustum);u(this,"targetTriangleDensity",2e5);u(this,"updateInterval",0);u(this,"pause",!1);u(this,"_frame",0);u(this,"_originalRender");u(this,"_sphere",new g.Sphere);u(this,"_tempBox",new g.Box3);u(this,"_tempBox2",new g.Box3);u(this,"tempMatrix",new g.Matrix4);u(this,"_tempWorldPosition",new g.Vector3);u(this,"_tempBoxSize",new g.Vector3);u(this,"_tempBox2Size",new g.Vector3);this.renderer=e}static getObjectLODState(e){var t;return(t=e.userData)==null?void 0:t.LOD_state}static addPlugin(e){R.push(e)}static removePlugin(e){const t=R.indexOf(e);t>=0&&R.splice(t,1)}static get(e){return e[ne]?e[ne]:new A(e)}get plugins(){return R}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;te(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 l,d;if(this.pause)return;const n=this.renderer.renderLists.get(e,0),s=n.opaque;let o=!0;if(s.length===1){const h=s[0].material;(h.name==="EffectMaterial"||h.name==="CopyShader")&&(o=!1)}if(t.parent&&t.parent.type==="CubeCamera"&&(o=!1),o){if(Oe||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const h=this.targetTriangleDensity;for(const f of s){if(f.material&&(((l=f.geometry)==null?void 0:l.type)==="BoxGeometry"||((d=f.geometry)==null?void 0:d.type)==="BufferGeometry")&&(f.material.name==="SphericalGaussianBlur"||f.material.name=="BackgroundCubeMaterial"||f.material.name==="CubemapFromEquirect"||f.material.name==="EquirectangularToCubeUV")){Q&&(f.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(f.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",f,f.material.name,f.material.type)));continue}switch(f.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const m=f.object;(m instanceof g.Mesh||m.isMesh)&&this.updateLODs(e,t,m,h,i)}const L=n.transparent;for(const f of L){const m=f.object;(m instanceof g.Mesh||m.isMesh)&&this.updateLODs(e,t,m,h,i)}}}updateLODs(e,t,r,i,n){var l,d;let s=r.userData.LOD_state;if(s||(s=new _e,r.userData.LOD_state=s),s.frames++<2)return;for(const h of R)(l=h.onBeforeUpdateLOD)==null||l.call(h,this.renderer,e,t,r);this.calculateLodLevel(t,r,s,i,P),P.mesh_lod=Math.round(P.mesh_lod),P.texture_lod=Math.round(P.texture_lod),P.mesh_lod>=0&&this.loadProgressiveMeshes(r,P.mesh_lod);let o=P.texture_lod;if(r.material&&o>=0){const h=r["DEBUG:LOD"];h!=null&&(o=h),this.loadProgressiveTextures(r.material,o)}for(const h of R)(d=h.onAfterUpdatedLOD)==null||d.call(h,this.renderer,e,t,r,P);s.lastLodLevel_Mesh=P.mesh_lod,s.lasLodLevel_Texture=P.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const n of e)this.loadProgressiveTextures(n,t);return}const r=e;let i=!1;(r.NEEDLE_LOD==null||t<r.NEEDLE_LOD)&&(i=!0),i&&(r.NEEDLE_LOD=t,S.assignTextureLOD(e,t))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e.userData||(e.userData={}),e.userData.LOD!==t){e.userData.LOD=t;const r=e.geometry;return S.assignMeshLOD(e,t).then(i=>(i&&e.userData.LOD==t&&r!=e.geometry,i))}return Promise.resolve(null)}static isInside(e,t){const r=e.min,i=e.max,n=(r.x+i.x)*.5,s=(r.y+i.y)*.5;return this._tempPtInside.set(n,s,r.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,r,i,n){var D;if(!t){n.mesh_lod=-1,n.texture_lod=-1;return}if(!e){n.mesh_lod=-1,n.texture_lod=-1;return}let o=10+1;if(Q&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const l=S.getMeshLODInformation(t.geometry),d=l==null?void 0:l.lods,h=d&&d.length>0,L=S.getMaterialMinMaxLODsCount(t.material),f=(L==null?void 0:L.min)!=1/0&&L.min>0&&L.max>0;if(!h&&!f){n.mesh_lod=0,n.texture_lod=0;return}if(h||(o=0),!((D=this.cameraFrustrum)!=null&&D.intersectsObject(t))){n.mesh_lod=99,n.texture_lod=99;return}const m=t.geometry.boundingBox;if(m&&e.isPerspectiveCamera){const O=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 y=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(y)){n.mesh_lod=0,n.texture_lod=0;return}}if(this._tempBox.copy(m),this._tempBox.applyMatrix4(t.matrixWorld),A.isInside(this._tempBox,this.projectionScreenMatrix)){n.mesh_lod=0,n.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&O.fov>70){const y=this._tempBox.min,p=this._tempBox.max;let c=y.x,x=y.y,T=p.x,C=p.y;const I=2,N=1.5,V=(y.x+p.x)*.5,q=(y.y+p.y)*.5;c=(c-V)*I+V,x=(x-q)*I+q,T=(T-V)*I+V,C=(C-q)*I+q;const ue=c<0&&T>0?0:Math.min(Math.abs(y.x),Math.abs(p.x)),fe=x<0&&C>0?0:Math.min(Math.abs(y.y),Math.abs(p.y)),H=Math.max(ue,fe);r.lastCentrality=(N-H)*(N-H)*(N-H)}else r.lastCentrality=1;const M=this._tempBox.getSize(this._tempBoxSize);M.multiplyScalar(.5),screen.availHeight>0&&M.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),M.x*=O.aspect;const G=e.matrixWorldInverse,w=this._tempBox2;w.copy(m),w.applyMatrix4(t.matrixWorld),w.applyMatrix4(G);const E=w.getSize(this._tempBox2Size),F=Math.max(E.x,E.y);if(Math.max(M.x,M.y)!=0&&F!=0&&(M.z=E.z/Math.max(E.x,E.y)*Math.max(M.x,M.y)),r.lastScreenCoverage=Math.max(M.x,M.y,M.z),r.lastScreenspaceVolume.copy(M),r.lastScreenCoverage*=r.lastCentrality,Q&&A.debugDrawLine){const y=this.tempMatrix.copy(this.projectionScreenMatrix);y.invert();const p=A.corner0,c=A.corner1,x=A.corner2,T=A.corner3;p.copy(this._tempBox.min),c.copy(this._tempBox.max),c.x=p.x,x.copy(this._tempBox.max),x.y=p.y,T.copy(this._tempBox.max);const C=(p.z+T.z)*.5;p.z=c.z=x.z=T.z=C,p.applyMatrix4(y),c.applyMatrix4(y),x.applyMatrix4(y),T.applyMatrix4(y),A.debugDrawLine(p,c,255),A.debugDrawLine(p,x,255),A.debugDrawLine(c,T,255),A.debugDrawLine(x,T,255)}let B=999;if(d&&r.lastScreenCoverage>0){for(let y=0;y<d.length;y++)if(d[y].density/r.lastScreenCoverage<i){B=y;break}}B<o&&(o=B)}if(n.mesh_lod=o,L!=null&&L.min&&L.min>0&&L.max>0){const O=Math.min(1,Math.max(0,r.lastScreenCoverage*3));n.texture_lod=we(L.max,0,O)}else n.texture_lod=0}};let b=A;u(b,"debugDrawLine"),u(b,"corner0",new g.Vector3),u(b,"corner1",new g.Vector3),u(b,"corner2",new g.Vector3),u(b,"corner3",new g.Vector3),u(b,"_tempPtInside",new g.Vector3);function we(a,e,t){return a+(e-a)*t}class _e{constructor(){u(this,"frames",0);u(this,"lastLodLevel_Mesh",0);u(this,"lasLodLevel_Texture",0);u(this,"lastScreenCoverage",0);u(this,"lastScreenspaceVolume",new g.Vector3);u(this,"lastCentrality",0)}}const oe=Symbol("NEEDLE_mesh_lod"),X=Symbol("NEEDLE_texture_lod");function ce(a){if(!a)return null;let e=null,t=null;for(let r=a;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=a[n].threeRenderer),!t&&s!=null&&(t=a[s])}if(e){console.log("Adding Needle LODs to modelviewer");const r=b.get(e);if(b.addPlugin(new ve(a)),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 ve{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[X]==!0)return;t[X]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let n=function(o){var d,h,L;if(o[X]==!0)return;o[X]=!0,o.userData&&(o.userData.LOD=-1);const l=Object.keys(o);for(let f=0;f<l.length;f++){const m=l[f],D=o[m];if((D==null?void 0:D.isTexture)===!0){const O=(h=(d=D.userData)==null?void 0:d.associations)==null?void 0:h.textures,M=r.parser.json.textures[O];if(!M){console.warn("Texture data not found for texture index "+O);continue}if((L=M==null?void 0:M.extensions)!=null&&L[k]){const G=M.extensions[k];G&&i&&S.registerTexture(i,D,G.lods.length,G)}}}};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[oe]==!0)return;t[oe]=!0;const r=this.getUrl();if(!r)return;const i=(s=(n=t.userData)==null?void 0:n.gltfExtensions)==null?void 0:s[k];if(i&&r){const o=t.uuid;S.registerMesh(r,o,t,0,i.lods.length,i)}}}function Se(a,e,t,r){te(e),re(t),t.register(n=>new S(n,a));const i=b.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{ce(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=k;exports.LODsManager=b;exports.NEEDLE_progressive=S;exports.addDracoAndKTX2Loaders=re;exports.createLoaders=te;exports.getRaycastMesh=ae;exports.patchModelViewer=ce;exports.setDracoDecoderLocation=Le;exports.setKTX2TranscoderLocation=xe;exports.setRaycastMesh=le;exports.useNeedleProgressive=Se;
|
package/lib/extension.d.ts
CHANGED
|
@@ -52,12 +52,19 @@ export declare class NEEDLE_progressive implements GLTFLoaderPlugin {
|
|
|
52
52
|
/** The name of the extension */
|
|
53
53
|
get name(): string;
|
|
54
54
|
static getMeshLODInformation(geo: BufferGeometry): NEEDLE_progressive_mesh_model | null;
|
|
55
|
+
static getMaterialMinMaxLODsCount(material: Material | Material[], minmax?: {
|
|
56
|
+
min: number;
|
|
57
|
+
max: number;
|
|
58
|
+
}): {
|
|
59
|
+
min: number;
|
|
60
|
+
max: number;
|
|
61
|
+
};
|
|
55
62
|
/** Check if a LOD level is available for a mesh or a texture
|
|
56
63
|
* @param obj the mesh or texture to check
|
|
57
64
|
* @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
65
|
* @returns true if the LOD level is available (or if any LOD level is available if level is undefined)
|
|
59
66
|
*/
|
|
60
|
-
static hasLODLevelAvailable(obj: Mesh | BufferGeometry | Texture | Material, level?: number): boolean;
|
|
67
|
+
static hasLODLevelAvailable(obj: Mesh | BufferGeometry | Texture | Material | Material[], level?: number): boolean;
|
|
61
68
|
/** Load a different resolution of a mesh (if available)
|
|
62
69
|
* @param context the context
|
|
63
70
|
* @param source the sourceid of the file from which the mesh is loaded (this is usually the component's sourceId)
|
|
@@ -103,7 +110,6 @@ export declare class NEEDLE_progressive implements GLTFLoaderPlugin {
|
|
|
103
110
|
private static getOrLoadLOD;
|
|
104
111
|
private static assignLODInformation;
|
|
105
112
|
private static getAssignedLODInformation;
|
|
106
|
-
private static readonly _copiedTextures;
|
|
107
113
|
private static copySettings;
|
|
108
114
|
}
|
|
109
115
|
export {};
|
package/lib/extension.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { BufferGeometry, Material, Mesh,
|
|
1
|
+
import { BufferGeometry, Material, Mesh, Texture, TextureLoader } from "three";
|
|
2
2
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
3
3
|
import { addDracoAndKTX2Loaders } from "./loaders.js";
|
|
4
|
-
import { getParam, resolveUrl } from "./utils.js";
|
|
4
|
+
import { getParam, getRaycastMesh, resolveUrl, setRaycastMesh } from "./utils.js";
|
|
5
5
|
// All of this has to be removed
|
|
6
6
|
// import { getRaycastMesh, setRaycastMesh } from "../../engine_physics.js";
|
|
7
7
|
// import { PromiseAllWithErrors, resolveUrl } from "../../engine_utils.js";
|
|
@@ -95,16 +95,67 @@ export class NEEDLE_progressive {
|
|
|
95
95
|
}
|
|
96
96
|
return null;
|
|
97
97
|
}
|
|
98
|
+
static getMaterialMinMaxLODsCount(material, minmax = { min: Infinity, max: -1 }) {
|
|
99
|
+
if (Array.isArray(material)) {
|
|
100
|
+
for (const mat of material) {
|
|
101
|
+
this.getMaterialMinMaxLODsCount(mat, minmax);
|
|
102
|
+
}
|
|
103
|
+
return minmax;
|
|
104
|
+
}
|
|
105
|
+
let min = minmax.min;
|
|
106
|
+
let max = minmax.max;
|
|
107
|
+
if (material.type === "ShaderMaterial" || material.type === "RawShaderMaterial") {
|
|
108
|
+
const mat = material;
|
|
109
|
+
for (const slot of Object.keys(mat.uniforms)) {
|
|
110
|
+
const val = mat.uniforms[slot].value;
|
|
111
|
+
if (val?.isTexture === true) {
|
|
112
|
+
const info = this.getAssignedLODInformation(val);
|
|
113
|
+
if (info) {
|
|
114
|
+
const model = this.lodInfos.get(info.key);
|
|
115
|
+
if (model && model.lods) {
|
|
116
|
+
min = Math.min(min, model.lods.length);
|
|
117
|
+
max = Math.max(max, model.lods.length);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else if (material.isMaterial) {
|
|
124
|
+
for (const slot of Object.keys(material)) {
|
|
125
|
+
const val = material[slot];
|
|
126
|
+
if (val?.isTexture === true) {
|
|
127
|
+
const info = this.getAssignedLODInformation(val);
|
|
128
|
+
if (info) {
|
|
129
|
+
const model = this.lodInfos.get(info.key);
|
|
130
|
+
if (model && model.lods) {
|
|
131
|
+
min = Math.min(min, model.lods.length);
|
|
132
|
+
max = Math.max(max, model.lods.length);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
minmax.min = min;
|
|
139
|
+
minmax.max = max;
|
|
140
|
+
return minmax;
|
|
141
|
+
}
|
|
98
142
|
/** Check if a LOD level is available for a mesh or a texture
|
|
99
143
|
* @param obj the mesh or texture to check
|
|
100
144
|
* @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
|
|
101
145
|
* @returns true if the LOD level is available (or if any LOD level is available if level is undefined)
|
|
102
146
|
*/
|
|
103
147
|
static hasLODLevelAvailable(obj, level) {
|
|
148
|
+
if (Array.isArray(obj)) {
|
|
149
|
+
for (const mat of obj) {
|
|
150
|
+
if (this.hasLODLevelAvailable(mat, level))
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
104
155
|
if (obj.isMaterial === true) {
|
|
105
156
|
for (const slot of Object.keys(obj)) {
|
|
106
157
|
const val = obj[slot];
|
|
107
|
-
if (val.isTexture) {
|
|
158
|
+
if (val && val.isTexture) {
|
|
108
159
|
if (this.hasLODLevelAvailable(val, level))
|
|
109
160
|
return true;
|
|
110
161
|
}
|
|
@@ -219,10 +270,12 @@ export class NEEDLE_progressive {
|
|
|
219
270
|
const slots = new Array();
|
|
220
271
|
if (debug)
|
|
221
272
|
debug_materials.add(material);
|
|
222
|
-
|
|
273
|
+
// Handle custom shaders / uniforms progressive textures. This includes support for VRM shaders
|
|
274
|
+
if (material.uniforms && material.isRawShaderMaterial || material.isShaderMaterial === true) {
|
|
223
275
|
// iterate uniforms of custom shaders
|
|
224
|
-
|
|
225
|
-
|
|
276
|
+
const shaderMaterial = material;
|
|
277
|
+
for (const slot of Object.keys(shaderMaterial.uniforms)) {
|
|
278
|
+
const val = shaderMaterial.uniforms[slot].value;
|
|
226
279
|
if (val?.isTexture === true) {
|
|
227
280
|
const task = this.assignTextureLODForSlot(val, level, material, slot);
|
|
228
281
|
promises.push(task);
|
|
@@ -265,8 +318,18 @@ export class NEEDLE_progressive {
|
|
|
265
318
|
if (current?.isTexture !== true)
|
|
266
319
|
return Promise.resolve(null);
|
|
267
320
|
// if (debug) console.log("-----------\n", "FIND", material?.name, slot, current?.name, current?.userData, current, material);
|
|
268
|
-
|
|
321
|
+
if (slot === "glyphMap") {
|
|
322
|
+
return Promise.resolve(current);
|
|
323
|
+
}
|
|
324
|
+
// save which texture level was requested last
|
|
325
|
+
const key = "LOD:requested level:" + slot;
|
|
326
|
+
if (material)
|
|
327
|
+
material[key] = level;
|
|
269
328
|
return NEEDLE_progressive.getOrLoadLOD(current, level).then(tex => {
|
|
329
|
+
// check if the requested level has changed in the meantime
|
|
330
|
+
if (material && material[key] != level)
|
|
331
|
+
return null;
|
|
332
|
+
// if (material) delete material[key];
|
|
270
333
|
// this can currently not happen
|
|
271
334
|
if (Array.isArray(tex))
|
|
272
335
|
return null;
|
|
@@ -392,6 +455,9 @@ export class NEEDLE_progressive {
|
|
|
392
455
|
else
|
|
393
456
|
existing = [mesh.geometry];
|
|
394
457
|
NEEDLE_progressive.lowresCache.set(key, existing);
|
|
458
|
+
if (level > 0 && !getRaycastMesh(mesh)) {
|
|
459
|
+
setRaycastMesh(mesh, geometry);
|
|
460
|
+
}
|
|
395
461
|
for (const plugin of plugins) {
|
|
396
462
|
plugin.onRegisteredNewMesh?.(mesh, ext);
|
|
397
463
|
}
|
|
@@ -435,7 +501,7 @@ export class NEEDLE_progressive {
|
|
|
435
501
|
}
|
|
436
502
|
}
|
|
437
503
|
/** the unresolved LOD url */
|
|
438
|
-
const unresolved_lod_url = Array.isArray(progressiveInfo.lods) ? progressiveInfo.lods[level]
|
|
504
|
+
const unresolved_lod_url = Array.isArray(progressiveInfo.lods) ? progressiveInfo.lods[level]?.path : progressiveInfo.lods;
|
|
439
505
|
// check if we have a uri
|
|
440
506
|
if (!unresolved_lod_url) {
|
|
441
507
|
if (debug && !progressiveInfo["missing:uri"]) {
|
|
@@ -535,6 +601,9 @@ export class NEEDLE_progressive {
|
|
|
535
601
|
}
|
|
536
602
|
if (found) {
|
|
537
603
|
let tex = await parser.getDependency("texture", index);
|
|
604
|
+
if (tex) {
|
|
605
|
+
NEEDLE_progressive.assignLODInformation(LOD.url, tex, LODKEY, level, undefined, undefined);
|
|
606
|
+
}
|
|
538
607
|
if (debugverbose)
|
|
539
608
|
console.log("change \"" + current.name + "\" → \"" + tex.name + "\"", lod_url, index, tex, KEY);
|
|
540
609
|
if (current instanceof Texture)
|
|
@@ -544,6 +613,9 @@ export class NEEDLE_progressive {
|
|
|
544
613
|
}
|
|
545
614
|
return resolve(tex);
|
|
546
615
|
}
|
|
616
|
+
else if (debug) {
|
|
617
|
+
console.warn("Could not find texture with guid", ext.guid);
|
|
618
|
+
}
|
|
547
619
|
}
|
|
548
620
|
index = 0;
|
|
549
621
|
if (gltf.parser.json.meshes) {
|
|
@@ -630,22 +702,43 @@ export class NEEDLE_progressive {
|
|
|
630
702
|
static getAssignedLODInformation(res) {
|
|
631
703
|
return res?.userData?.LODS || null;
|
|
632
704
|
}
|
|
633
|
-
static _copiedTextures = new Map();
|
|
705
|
+
// private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
|
|
634
706
|
static copySettings(source, target) {
|
|
707
|
+
// const existingCopy = source["LODS:COPY"];
|
|
635
708
|
// don't copy again if the texture was processed before
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
709
|
+
// we clone the source if it's animated
|
|
710
|
+
// const existingClone = this._copiedTextures.get(source);
|
|
711
|
+
// if (existingClone) {
|
|
712
|
+
// return existingClone;
|
|
713
|
+
// }
|
|
640
714
|
// We need to clone e.g. when the same texture is used multiple times (but with e.g. different wrap settings)
|
|
641
715
|
// This is relatively cheap since it only stores settings
|
|
642
716
|
// This should only happen once ever for every texture
|
|
643
|
-
|
|
644
|
-
|
|
717
|
+
// const original = target;
|
|
718
|
+
{
|
|
719
|
+
target = target.clone();
|
|
720
|
+
if (debug)
|
|
721
|
+
console.warn("Copying texture settings\n", source.uuid, "\n", target.uuid);
|
|
722
|
+
}
|
|
723
|
+
// else {
|
|
724
|
+
// source = existingCopy;
|
|
725
|
+
// }
|
|
726
|
+
// this._copiedTextures.set(original, target);
|
|
645
727
|
// we re-use the offset and repeat settings because it might be animated
|
|
646
728
|
target.offset = source.offset;
|
|
647
729
|
target.repeat = source.repeat;
|
|
648
730
|
target.colorSpace = source.colorSpace;
|
|
731
|
+
target.magFilter = source.magFilter;
|
|
732
|
+
target.minFilter = source.minFilter;
|
|
733
|
+
target.wrapS = source.wrapS;
|
|
734
|
+
target.wrapT = source.wrapT;
|
|
735
|
+
target.flipY = source.flipY;
|
|
736
|
+
target.anisotropy = source.anisotropy;
|
|
737
|
+
if (!target.mipmaps)
|
|
738
|
+
target.generateMipmaps = source.generateMipmaps;
|
|
739
|
+
// if (!target.userData) target.userData = {};
|
|
740
|
+
// target["LODS:COPY"] = source;
|
|
741
|
+
// related: NE-4937
|
|
649
742
|
return target;
|
|
650
743
|
}
|
|
651
744
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
export * from "./extension.js";
|
|
2
|
-
export * from "./plugins/index.js";
|
|
3
|
-
export { LODsManager } from "./lods_manager.js";
|
|
4
1
|
import { WebGLRenderer } from "three";
|
|
5
2
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
6
3
|
import { LODsManager } from "./lods_manager.js";
|
|
4
|
+
export * from "./extension.js";
|
|
5
|
+
export * from "./plugins/index.js";
|
|
6
|
+
export { LODsManager } from "./lods_manager.js";
|
|
7
|
+
export { setDracoDecoderLocation, setKTX2TranscoderLocation, createLoaders, addDracoAndKTX2Loaders } from "./loaders.js";
|
|
8
|
+
export { getRaycastMesh, setRaycastMesh } from "./utils.js";
|
|
7
9
|
declare class UseNeedleGLTFProgressive {
|
|
8
|
-
/** */
|
|
9
10
|
enableLODsManager?: boolean;
|
|
10
11
|
}
|
|
11
12
|
/** Use this function to enable progressive loading of gltf models.
|
package/lib/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
export * from "./extension.js";
|
|
2
|
-
export * from "./plugins/index.js";
|
|
3
|
-
export { LODsManager } from "./lods_manager.js";
|
|
4
1
|
import { addDracoAndKTX2Loaders, createLoaders } from "./loaders.js";
|
|
5
2
|
import { NEEDLE_progressive } from "./extension.js";
|
|
6
3
|
import { LODsManager } from "./lods_manager.js";
|
|
4
|
+
export * from "./extension.js";
|
|
5
|
+
export * from "./plugins/index.js";
|
|
6
|
+
export { LODsManager } from "./lods_manager.js";
|
|
7
|
+
export { setDracoDecoderLocation, setKTX2TranscoderLocation, createLoaders, addDracoAndKTX2Loaders } from "./loaders.js";
|
|
8
|
+
export { getRaycastMesh, setRaycastMesh } from "./utils.js";
|
|
7
9
|
;
|
|
8
10
|
/** Use this function to enable progressive loading of gltf models.
|
|
9
11
|
* @param url The url of the gltf model.
|
|
@@ -24,7 +26,7 @@ export function useNeedleProgressive(url, renderer, loader, opts) {
|
|
|
24
26
|
createLoaders(renderer);
|
|
25
27
|
addDracoAndKTX2Loaders(loader);
|
|
26
28
|
loader.register(p => new NEEDLE_progressive(p, url));
|
|
27
|
-
const lod =
|
|
29
|
+
const lod = LODsManager.get(renderer);
|
|
28
30
|
if (opts?.enableLODsManager !== false) {
|
|
29
31
|
lod.enable();
|
|
30
32
|
}
|
package/lib/loaders.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import { WebGLRenderer } from 'three';
|
|
2
2
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
3
|
+
/**
|
|
4
|
+
* Set the location of the Draco decoder.
|
|
5
|
+
* @default 'https://www.gstatic.com/draco/versioned/decoders/1.4.1/'
|
|
6
|
+
*/
|
|
7
|
+
export declare function setDracoDecoderLocation(location: string): void;
|
|
8
|
+
/**
|
|
9
|
+
* Set the location of the KTX2 transcoder.
|
|
10
|
+
* @default 'https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/'
|
|
11
|
+
*/
|
|
12
|
+
export declare function setKTX2TranscoderLocation(location: string): void;
|
|
3
13
|
export declare function createLoaders(renderer: WebGLRenderer): void;
|
|
4
14
|
export declare function addDracoAndKTX2Loaders(loader: GLTFLoader): void;
|
package/lib/loaders.js
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js';
|
|
2
2
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
3
3
|
import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
let DEFAULT_DRACO_DECODER_LOCATION = 'https://www.gstatic.com/draco/versioned/decoders/1.4.1/';
|
|
5
|
+
let DEFAULT_KTX2_TRANSCODER_LOCATION = 'https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/';
|
|
6
|
+
fetch(DEFAULT_DRACO_DECODER_LOCATION + "draco_decoder.js", { method: "head" })
|
|
7
|
+
.catch(_ => {
|
|
8
|
+
DEFAULT_DRACO_DECODER_LOCATION = "./include/draco/";
|
|
9
|
+
DEFAULT_KTX2_TRANSCODER_LOCATION = "./include/ktx2/";
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* Set the location of the Draco decoder.
|
|
13
|
+
* @default 'https://www.gstatic.com/draco/versioned/decoders/1.4.1/'
|
|
14
|
+
*/
|
|
15
|
+
export function setDracoDecoderLocation(location) {
|
|
16
|
+
DEFAULT_DRACO_DECODER_LOCATION = location;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Set the location of the KTX2 transcoder.
|
|
20
|
+
* @default 'https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/'
|
|
21
|
+
*/
|
|
22
|
+
export function setKTX2TranscoderLocation(location) {
|
|
23
|
+
DEFAULT_KTX2_TRANSCODER_LOCATION = location;
|
|
24
|
+
}
|
|
6
25
|
let dracoLoader;
|
|
7
26
|
let meshoptDecoder;
|
|
8
27
|
let ktx2Loader;
|