@needle-tools/gltf-progressive 1.0.0-alpha.13 → 1.0.0-alpha.15
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 +8 -0
- package/README.md +6 -0
- package/examples/modelviewer.html +4 -4
- package/examples/threejs/index.html +1 -1
- package/examples/threejs/main.js +8 -8
- package/gltf-progressive.js +182 -154
- package/gltf-progressive.min.js +3 -3
- package/gltf-progressive.umd.cjs +3 -3
- package/lib/extension.js +4 -1
- package/lib/index.d.ts +4 -4
- package/lib/index.js +5 -4
- package/lib/lods_manager.d.ts +37 -2
- package/lib/lods_manager.js +54 -4
- 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 +0 -4
- 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,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
`,m),null)),
|
|
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
|
+
var le=Object.defineProperty,ue=(r,e,t)=>e in r?le(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,c=(r,e,t)=>(ue(r,typeof e!="symbol"?e+"":e,t),t);import{MeshoptDecoder as ce}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as de}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as he}from"three/examples/jsm/loaders/KTX2Loader.js";import{BufferGeometry as U,Mesh as z,Material as fe,Texture as C,TextureLoader as ge,Matrix4 as ee,Frustum as me,Sphere as pe,Box3 as re,Vector3 as I}from"three";import{GLTFLoader as ye}from"three/examples/jsm/loaders/GLTFLoader.js";let $="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",V="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch($+"draco_decoder.js",{method:"head"}).catch(r=>{$="./include/draco/",V="./include/ktx2/"});function De(r){$=r}function xe(r){V=r}let G,X,N;function K(r){G||(G=new de,G.setDecoderPath($),G.setDecoderConfig({type:"js"})),N||(N=new he,N.setTranscoderPath(V)),X||(X=ce),r?N.detectSupport(r):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function H(r){r.dracoLoader||r.setDRACOLoader(G),r.ktx2Loader||r.setKTX2Loader(N),r.meshoptDecoder||r.setMeshoptDecoder(X)}function Y(r){const e=new URL(window.location.href).searchParams.get(r);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Le(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}function te(r){var e;return((e=r.userData)==null?void 0:e["needle:raycast-mesh"])instanceof U?r.userData["needle:raycast-mesh"]:null}function se(r,e){(r.type==="Mesh"||r.type==="SkinnedMesh")&&(r.userData||(r.userData={}),r.userData["needle:raycast-mesh"]=e)}const R=new Array,P="NEEDLE_progressive",v=Y("debugprogressive"),J=Symbol("needle-progressive-texture"),F=new Map,Q=new Set;if(v){let r=function(){e+=1,console.log("Toggle LOD level",e,F),F.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 oe(r,e,t){var o;if(!v)return;F.has(r)||F.set(r,{keys:[],sourceId:t});const n=F.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 z||r.isMesh===!0){const o=r.geometry,n=this.getAssignedLODInformation(o);if(!n)return Promise.resolve(null);for(const s of R)(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 U&&(r.geometry=s,v&&oe(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 fe||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&&oe(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=Le(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)),f=!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):(f=!0,this.previouslyLoaded.delete(u)):y instanceof U&&r instanceof U&&((n=y.attributes.position)!=null&&n.array||(f=!0,this.previouslyLoaded.delete(u)))),!f)return y}const D=l,A=new Promise(async(y,f)=>{const m=new ye;H(m),v&&(await new Promise(L=>setTimeout(L,1e3)),s&&console.warn("Start loading (delayed) "+h,D.guid));let b=h;if(D&&Array.isArray(D.lods)){const L=D.lods[e];L.hash&&(b+="?v="+L.hash)}const x=await m.loadAsync(b).catch(L=>(console.error(`Error loading LOD ${e} from ${h}
|
|
3
|
+
`,L),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+h,D.guid);let T=0;if(x.parser.json.textures){let L=!1;for(const g of x.parser.json.textures){if(g!=null&&g.extensions){const M=g?.extensions[P];if(M!=null&&M.guid&&M.guid===D.guid){L=!0;break}}T++}if(L){let g=await S.getDependency("texture",T);return s&&console.log('change "'+r.name+'" \u2192 "'+g.name+'"',h,T,g,u),r instanceof C&&(g=this.copySettings(r,g)),g&&(g.guid=D.guid),y(g)}}if(T=0,x.parser.json.meshes){let L=!1;for(const g of x.parser.json.meshes){if(g!=null&&g.extensions){const M=g?.extensions[P];if(M!=null&&M.guid&&M.guid===D.guid){L=!0;break}}T++}if(L){const g=await S.getDependency("mesh",T),M=D;if(s&&console.log(`Loaded Mesh "${g.name}"`,h,T,g,u),g.isMesh===!0){const E=g.geometry;return O.assignLODInformation(a.url,E,i,e,void 0,M.density),y(E)}else{const E=new Array;for(let k=0;k<g.children.length;k++){const W=g.children[k];if(W instanceof z){const j=W.geometry;O.assignLODInformation(a.url,j,i,e,k,M.density),E.push(j)}}return y(E)}}}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 ge().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 ve(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),o>0&&!te(t)&&se(t,i);for(const d of R)(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 ve{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=Y("debugprogressive"),Oe=Y("noprogressive"),ne=Symbol("Needle:LODSManager"),_=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new ee),c(this,"cameraFrustrum",new me),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new pe),c(this,"_tempBox",new re),c(this,"tempMatrix",new ee),c(this,"_tempWorldPosition",new I),c(this,"_tempBoxSize",new I),c(this,"_tempBox2Size",new I),this.renderer=r}static getObjectLODState(r){var e;return(e=r.userData)==null?void 0:e.LOD_state}static addPlugin(r){R.push(r)}static removePlugin(r){const e=R.indexOf(r);e>=0&&R.splice(e,1)}static get(r){return r[ne]?r[ne]:new _(r)}enable(){if(this._originalRender)return;let r=0;this._originalRender=this.renderer.render;const e=this;K(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(Oe||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=this.targetTriangleDensity;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 z||p.isMesh)&&this.updateLODs(r,e,p,d)}const h=a.transparent;for(const u of h){const p=u.object;(p instanceof z||p.isMesh)&&this.updateLODs(r,e,p,d)}}}updateLODs(r,e,t,o){var n,s;for(const d of R)(n=d.onBeforeUpdateLOD)==null||n.call(d,this.renderer,r,e,t);let a=t.userData.LOD_state;a||(a=new we,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 R)(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 f=r.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(f))return 0}if(this._tempBox.copy(l),this._tempBox.applyMatrix4(e.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&d.fov>70){const f=this._tempBox.min,m=this._tempBox.max;let b=f.x,x=f.y,S=m.x,T=m.y;const L=2,g=1.5,M=(f.x+m.x)*.5,E=(f.y+m.y)*.5;b=(b-M)*L+M,x=(x-E)*L+E,S=(S-M)*L+M,T=(T-E)*L+E;const k=b<0&&S>0?0:Math.min(Math.abs(f.x),Math.abs(m.x)),W=x<0&&T>0?0:Math.min(Math.abs(f.y),Math.abs(m.y)),j=Math.max(k,W);t.lastCentrality=(g-j)*(g-j)*(g-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 D=p.getSize(this._tempBox2Size),A=Math.max(D.x,D.y);if(Math.max(h.x,h.y)!=0&&A!=0&&(h.z=D.z/Math.max(D.x,D.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&&_.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const m=_.corner0,b=_.corner1,x=_.corner2,S=_.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 T=(m.z+S.z)*.5;m.z=b.z=x.z=S.z=T,m.applyMatrix4(f),b.applyMatrix4(f),x.applyMatrix4(f),S.applyMatrix4(f),_.debugDrawLine(m,b,255),_.debugDrawLine(m,x,255),_.debugDrawLine(b,S,255),_.debugDrawLine(x,S,255)}let y=999;if(i&&t.lastScreenCoverage>0){for(let f=0;f<i.length;f++)if(i[f].density/t.lastScreenCoverage<o){y=f;break}}y<s&&(s=y)}}return s}};let B=_;c(B,"debugDrawLine"),c(B,"corner0",new I),c(B,"corner1",new I),c(B,"corner2",new I),c(B,"corner3",new I);class we{constructor(){c(this,"lastLodLevel",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new I),c(this,"lastCentrality",0)}}const ie=Symbol("NEEDLE_mesh_lod"),q=Symbol("NEEDLE_texture_lod");function ae(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=B.get(e);if(B.addPlugin(new Me(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 Me{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[q]==!0)return;t[q]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&t.material){let s=function(i){var l,d,h;if(i[q]==!0)return;i[q]=!0,i.userData&&(i.userData.LOD=-1);const u=Object.keys(i);for(let p=0;p<u.length;p++){const D=u[p],A=i[D];if(A?.isTexture===!0){const y=(d=(l=A.userData)==null?void 0:l.associations)==null?void 0:d.textures,f=o.parser.json.textures[y];if(!f){console.warn("Texture data not found for texture index "+y);continue}if((h=f?.extensions)!=null&&h[P]){const m=f.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[ie]==!0)return;t[ie]=!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 be(r,e,t,o){K(e),H(t),t.register(s=>new w(s,r));const n=B.get(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{ae(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,B as LODsManager,w as NEEDLE_progressive,H as addDracoAndKTX2Loaders,K as createLoaders,te as getRaycastMesh,ae as patchModelViewer,De as setDracoDecoderLocation,xe as setKTX2TranscoderLocation,se as setRaycastMesh,be as useNeedleProgressive};
|
package/gltf-progressive.umd.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`,
|
|
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;
|
|
1
|
+
"use strict";var ae=Object.defineProperty;var le=(a,e,t)=>e in a?ae(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var u=(a,e,t)=>(le(a,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ce=require("three/examples/jsm/libs/meshopt_decoder.module.js"),ue=require("three/examples/jsm/loaders/DRACOLoader.js"),fe=require("three/examples/jsm/loaders/KTX2Loader.js"),h=require("three"),de=require("three/examples/jsm/loaders/GLTFLoader.js");let q="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",J="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(q+"draco_decoder.js",{method:"head"}).catch(a=>{q="./include/draco/",J="./include/ktx2/"});function ge(a){q=a}function he(a){J=a}let N,Y,U;function Q(a){N||(N=new ue.DRACOLoader,N.setDecoderPath(q),N.setDecoderConfig({type:"js"})),U||(U=new fe.KTX2Loader,U.setTranscoderPath(J)),Y||(Y=ce.MeshoptDecoder),a?U.detectSupport(a):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function Z(a){a.dracoLoader||a.setDRACOLoader(N),a.ktx2Loader||a.setKTX2Loader(U),a.meshoptDecoder||a.setMeshoptDecoder(Y)}function j(a){const t=new URL(window.location.href).searchParams.get(a);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function pe(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 se(a){var e;return((e=a.userData)==null?void 0:e["needle:raycast-mesh"])instanceof h.BufferGeometry?a.userData["needle:raycast-mesh"]:null}function ie(a,e){(a.type==="Mesh"||a.type==="SkinnedMesh")&&(a.userData||(a.userData={}),a.userData["needle:raycast-mesh"]=e)}const F=new Array,R="NEEDLE_progressive",T=j("debugprogressive"),$=Symbol("needle-progressive-texture"),W=new Map,H=new Set;if(T){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=M.getMeshLODInformation(o),g=l?Math.min(e,l.lods.length):0;n["DEBUG:LOD"]=e,M.assignMeshLOD(n,g),l&&(t=Math.max(t,l.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"&&a(),i.key==="w"&&(r=!r,H&&H.forEach(n=>{n.name!="BackgroundCubeMaterial"&&"wireframe"in n&&(n.wireframe=r)}))})}function ee(a,e,t){var i;if(!T)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 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 R}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 F)(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 l=s.uniforms[o].value;if((l==null?void 0:l.isTexture)===!0){const g=this.assignTextureLODForSlot(l,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 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 g=s[l],f=n[l];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[R];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,S.registerTexture(this.url,l,n,s));o||this.parser.getDependency("texture",n).then(l=>{l&&S.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[R];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&&S.registerMesh(this.url,s.guid,o,s.lods.length,l.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var o,l,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[$]&&(s=f.source[$])}if(s||(s=S.lodInfos.get(n)),s){if(t>0){let c=!1;const p=Array.isArray(s.lods);if(p&&t>=s.lods.length?c=!0:p||(c=!0),c)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=pe(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 c=y+"_"+s.guid,p=this.previouslyLoaded.get(c);if(p!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${c}`);let O=await p.catch(I=>(console.error(`Error loading LOD ${t} from ${y}
|
|
2
|
+
`,I),null)),C=!1;if(O==null||(O instanceof h.Texture&&e instanceof h.Texture?(o=O.image)!=null&&o.data||(l=O.source)!=null&&l.data?O=this.copySettings(e,O):(C=!0,this.previouslyLoaded.delete(c)):O instanceof h.BufferGeometry&&e instanceof h.BufferGeometry&&((g=O.attributes.position)!=null&&g.array||(C=!0,this.previouslyLoaded.delete(c)))),!C)return O}const x=s,P=new Promise(async(O,C)=>{const I=new de.GLTFLoader;Z(I),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 I.loadAsync(D).catch(L=>(console.error(`Error loading LOD ${t} from ${y}
|
|
3
|
+
`,L),null));if(!m)return null;const A=m.parser;r&&console.log("Loading finished "+y,x.guid);let w=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[R];if(v!=null&&v.guid&&v.guid===x.guid){L=!0;break}}w++}if(L){let d=await A.getDependency("texture",w);return r&&console.log('change "'+e.name+'" → "'+d.name+'"',y,w,d,c),e instanceof h.Texture&&(d=this.copySettings(e,d)),d&&(d.guid=x.guid),O(d)}}if(w=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[R];if(v!=null&&v.guid&&v.guid===x.guid){L=!0;break}}w++}if(L){const d=await A.getDependency("mesh",w),v=x;if(r&&console.log(`Loaded Mesh "${d.name}"`,y,w,d,c),d.isMesh===!0){const B=d.geometry;return S.assignLODInformation(i.url,B,n,t,void 0,v.density),O(B)}else{const B=new Array;for(let E=0;E<d.children.length;E++){const G=d.children[E];if(G instanceof h.Mesh){const z=G.geometry;S.assignLODInformation(i.url,z,n,t,E,v.density),B.push(z)}}return O(B)}}}return O(null)});return this.previouslyLoaded.set(c,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 ye(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;u(M,"registerTexture",(e,t,r,i)=>{T&&console.log("> Progressive: register texture",r,t.name,t.uuid,t,i),t.source&&(t.source[$]=i);const n=i.guid;S.assignLODInformation(e,t,n,0,0,void 0),S.lodInfos.set(n,i),S.lowresCache.set(n,t)}),u(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 l=S.lowresCache.get(t);l?l.push(r.geometry):l=[r.geometry],S.lowresCache.set(t,l),i>0&&!se(r)&&ie(r,o);for(const f of F)(g=f.onRegisteredNewMesh)==null||g.call(f,r,s)}),u(M,"lodInfos",new Map),u(M,"previouslyLoaded",new Map),u(M,"lowresCache",new Map),u(M,"_copiedTextures",new Map);class ye{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 K=j("debugprogressive"),me=j("noprogressive"),te=Symbol("Needle:LODSManager"),b=class{constructor(e){u(this,"renderer");u(this,"projectionScreenMatrix",new h.Matrix4);u(this,"cameraFrustrum",new h.Frustum);u(this,"targetTriangleDensity",2e5);u(this,"updateInterval",0);u(this,"pause",!1);u(this,"_frame",0);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}static addPlugin(e){F.push(e)}static removePlugin(e){const t=F.indexOf(e);t>=0&&F.splice(t,1)}static get(e){return e[te]?e[te]:new b(e)}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 l,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(me||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=this.targetTriangleDensity;for(const c of s){if(c.material&&(((l=c.geometry)==null?void 0:l.type)==="BoxGeometry"||((g=c.geometry)==null?void 0:g.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){K&&(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 p=c.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}const y=n.transparent;for(const c of y){const p=c.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}}}updateLODs(e,t,r,i){var l,g;for(const f of F)(l=f.onBeforeUpdateLOD)==null||l.call(f,this.renderer,e,t,r);let n=r.userData.LOD_state;n||(n=new Le,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 F)(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 l=M.getMeshLODInformation(t.geometry),g=l==null?void 0:l.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 A=D.x,w=D.y,L=m.x,d=m.y;const v=2,B=1.5,E=(D.x+m.x)*.5,G=(D.y+m.y)*.5;A=(A-E)*v+E,w=(w-G)*v+G,L=(L-E)*v+E,d=(d-G)*v+G;const z=A<0&&L>0?0:Math.min(Math.abs(D.x),Math.abs(m.x)),oe=w<0&&d>0?0:Math.min(Math.abs(D.y),Math.abs(m.y)),X=Math.max(z,oe);r.lastCentrality=(B-X)*(B-X)*(B-X)}else r.lastCentrality=1;const c=this._tempBox.getSize(this._tempBoxSize);c.multiplyScalar(.5),screen.availHeight>0&&c.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),c.x*=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),k=Math.max(P.x,P.y);if(Math.max(c.x,c.y)!=0&&k!=0&&(c.z=P.z/Math.max(P.x,P.y)*Math.max(c.x,c.y)),r.lastScreenCoverage=Math.max(c.x,c.y,c.z),r.lastScreenspaceVolume.copy(c),r.lastScreenCoverage*=r.lastCentrality,K&&b.debugDrawLine){const D=this.tempMatrix.copy(this.projectionScreenMatrix);D.invert();const m=b.corner0,A=b.corner1,w=b.corner2,L=b.corner3;m.copy(this._tempBox.min),A.copy(this._tempBox.max),A.x=m.x,w.copy(this._tempBox.max),w.y=m.y,L.copy(this._tempBox.max);const d=(m.z+L.z)*.5;m.z=A.z=w.z=L.z=d,m.applyMatrix4(D),A.applyMatrix4(D),w.applyMatrix4(D),L.applyMatrix4(D),b.debugDrawLine(m,A,255),b.debugDrawLine(m,w,255),b.debugDrawLine(A,L,255),b.debugDrawLine(w,L,255)}let C=999;if(g&&r.lastScreenCoverage>0){for(let D=0;D<g.length;D++)if(g[D].density/r.lastScreenCoverage<i){C=D;break}}C<s&&(s=C)}}return s}};let _=b;u(_,"debugDrawLine"),u(_,"corner0",new h.Vector3),u(_,"corner1",new h.Vector3),u(_,"corner2",new h.Vector3),u(_,"corner3",new h.Vector3);class Le{constructor(){u(this,"lastLodLevel",0);u(this,"lastScreenCoverage",0);u(this,"lastScreenspaceVolume",new h.Vector3);u(this,"lastCentrality",0)}}const re=Symbol("NEEDLE_mesh_lod"),V=Symbol("NEEDLE_texture_lod");function ne(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=_.get(e);if(_.addPlugin(new De(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 De{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[V]==!0)return;t[V]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let n=function(o){var g,f,y;if(o[V]==!0)return;o[V]=!0,o.userData&&(o.userData.LOD=-1);const l=Object.keys(o);for(let c=0;c<l.length;c++){const p=l[c],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,k=r.parser.json.textures[P];if(!k){console.warn("Texture data not found for texture index "+P);continue}if((y=k==null?void 0:k.extensions)!=null&&y[R]){const O=k.extensions[R];O&&i&&M.registerTexture(i,x,O.lods.length,O)}}}};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[re]==!0)return;t[re]=!0;const r=this.getUrl();if(!r)return;const i=(s=(n=t.userData)==null?void 0:n.gltfExtensions)==null?void 0:s[R];if(i&&r){const o=t.uuid;M.registerMesh(r,o,t,0,i.lods.length,i)}}}function xe(a,e,t,r){Q(e),Z(t),t.register(n=>new M(n,a));const i=_.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{ne(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=R;exports.LODsManager=_;exports.NEEDLE_progressive=M;exports.addDracoAndKTX2Loaders=Z;exports.createLoaders=Q;exports.getRaycastMesh=se;exports.patchModelViewer=ne;exports.setDracoDecoderLocation=ge;exports.setKTX2TranscoderLocation=he;exports.setRaycastMesh=ie;exports.useNeedleProgressive=xe;
|
package/lib/extension.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
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";
|
|
@@ -394,6 +394,9 @@ export class NEEDLE_progressive {
|
|
|
394
394
|
else
|
|
395
395
|
existing = [mesh.geometry];
|
|
396
396
|
NEEDLE_progressive.lowresCache.set(key, existing);
|
|
397
|
+
if (level > 0 && !getRaycastMesh(mesh)) {
|
|
398
|
+
setRaycastMesh(mesh, geometry);
|
|
399
|
+
}
|
|
397
400
|
for (const plugin of plugins) {
|
|
398
401
|
plugin.onRegisteredNewMesh?.(mesh, ext);
|
|
399
402
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { WebGLRenderer } from "three";
|
|
2
|
+
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
3
|
+
import { LODsManager } from "./lods_manager.js";
|
|
1
4
|
export * from "./extension.js";
|
|
2
5
|
export * from "./plugins/index.js";
|
|
3
6
|
export { LODsManager } from "./lods_manager.js";
|
|
4
7
|
export { setDracoDecoderLocation, setKTX2TranscoderLocation, createLoaders, addDracoAndKTX2Loaders } from "./loaders.js";
|
|
5
|
-
|
|
6
|
-
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
7
|
-
import { LODsManager } from "./lods_manager.js";
|
|
8
|
+
export { getRaycastMesh, setRaycastMesh } from "./utils.js";
|
|
8
9
|
declare class UseNeedleGLTFProgressive {
|
|
9
|
-
/** */
|
|
10
10
|
enableLODsManager?: boolean;
|
|
11
11
|
}
|
|
12
12
|
/** Use this function to enable progressive loading of gltf models.
|
package/lib/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { addDracoAndKTX2Loaders, createLoaders } from "./loaders.js";
|
|
2
|
+
import { NEEDLE_progressive } from "./extension.js";
|
|
3
|
+
import { LODsManager } from "./lods_manager.js";
|
|
1
4
|
export * from "./extension.js";
|
|
2
5
|
export * from "./plugins/index.js";
|
|
3
6
|
export { LODsManager } from "./lods_manager.js";
|
|
4
7
|
export { setDracoDecoderLocation, setKTX2TranscoderLocation, createLoaders, addDracoAndKTX2Loaders } from "./loaders.js";
|
|
5
|
-
|
|
6
|
-
import { NEEDLE_progressive } from "./extension.js";
|
|
7
|
-
import { LODsManager } from "./lods_manager.js";
|
|
8
|
+
export { getRaycastMesh, setRaycastMesh } from "./utils.js";
|
|
8
9
|
;
|
|
9
10
|
/** Use this function to enable progressive loading of gltf models.
|
|
10
11
|
* @param url The url of the gltf model.
|
|
@@ -25,7 +26,7 @@ export function useNeedleProgressive(url, renderer, loader, opts) {
|
|
|
25
26
|
createLoaders(renderer);
|
|
26
27
|
addDracoAndKTX2Loaders(loader);
|
|
27
28
|
loader.register(p => new NEEDLE_progressive(p, url));
|
|
28
|
-
const lod =
|
|
29
|
+
const lod = LODsManager.get(renderer);
|
|
29
30
|
if (opts?.enableLODsManager !== false) {
|
|
30
31
|
lod.enable();
|
|
31
32
|
}
|
package/lib/lods_manager.d.ts
CHANGED
|
@@ -5,6 +5,29 @@ import { NEEDLE_progressive_plugin } from "./plugins/plugin.js";
|
|
|
5
5
|
* It must be enabled by calling the `enable` method.
|
|
6
6
|
*
|
|
7
7
|
* Instead of using the LODs manager directly you can also call `useNeedleProgressive` to enable progressive loading for a GLTFLoader
|
|
8
|
+
*
|
|
9
|
+
* ### Plugins
|
|
10
|
+
* Use {@link LODsManager.addPlugin} to add a plugin to the LODsManager. A plugin can be used to hook into the LOD update process and modify the LOD levels or perform other actions.
|
|
11
|
+
*
|
|
12
|
+
* @example Adding a LODsManager to a Three.js scene:
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { LODsManager } from "@needle-tools/gltf-progressive";
|
|
15
|
+
* import { WebGLRenderer, Scene, Camera, Mesh } from "three";
|
|
16
|
+
*
|
|
17
|
+
* const renderer = new WebGLRenderer();
|
|
18
|
+
* const lodsManager = LODsManager.get(renderer);
|
|
19
|
+
* lodsManager.enable();
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example Using the LODsManager with a GLTFLoader:
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { useNeedleProgressive } from "@needle-tools/gltf-progressive";
|
|
25
|
+
* import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
26
|
+
*
|
|
27
|
+
* const url = 'https://yourdomain.com/yourmodel.glb';
|
|
28
|
+
* const loader = new GLTFLoader();
|
|
29
|
+
* const lodsManager = useNeedleProgressive(url, renderer, loader);
|
|
30
|
+
* ```
|
|
8
31
|
*/
|
|
9
32
|
export declare class LODsManager {
|
|
10
33
|
/** Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
|
|
@@ -12,9 +35,22 @@ export declare class LODsManager {
|
|
|
12
35
|
static debugDrawLine?: (a: Vector3, b: Vector3, color: number) => void;
|
|
13
36
|
/** @internal */
|
|
14
37
|
static getObjectLODState(object: Object3D): LOD_state | undefined;
|
|
38
|
+
static addPlugin(plugin: NEEDLE_progressive_plugin): void;
|
|
39
|
+
static removePlugin(plugin: NEEDLE_progressive_plugin): void;
|
|
40
|
+
/**
|
|
41
|
+
* Gets the LODsManager for the given renderer. If the LODsManager does not exist yet, it will be created.
|
|
42
|
+
* @param renderer The renderer to get the LODsManager for.
|
|
43
|
+
* @returns The LODsManager instance.
|
|
44
|
+
*/
|
|
45
|
+
static get(renderer: WebGLRenderer): LODsManager;
|
|
15
46
|
readonly renderer: WebGLRenderer;
|
|
16
47
|
readonly projectionScreenMatrix: Matrix4;
|
|
17
48
|
readonly cameraFrustrum: Frustum;
|
|
49
|
+
/**
|
|
50
|
+
* The target triangle density is the desired max amount of triangles on screen when the mesh is filling the screen.
|
|
51
|
+
* @default 200_000
|
|
52
|
+
*/
|
|
53
|
+
targetTriangleDensity: number;
|
|
18
54
|
/**
|
|
19
55
|
* The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 1, the LODs will be updated every second frame, etc.
|
|
20
56
|
*/
|
|
@@ -23,8 +59,7 @@ export declare class LODsManager {
|
|
|
23
59
|
* If set to true, the LODsManager will not update the LODs.
|
|
24
60
|
*/
|
|
25
61
|
pause: boolean;
|
|
26
|
-
|
|
27
|
-
constructor(renderer: WebGLRenderer);
|
|
62
|
+
private constructor();
|
|
28
63
|
private _frame;
|
|
29
64
|
private _originalRender?;
|
|
30
65
|
/**
|
package/lib/lods_manager.js
CHANGED
|
@@ -2,13 +2,38 @@ import { Box3, Frustum, Matrix4, Mesh, Sphere, Vector3 } from "three";
|
|
|
2
2
|
import { NEEDLE_progressive } from "./extension.js";
|
|
3
3
|
import { createLoaders } from "./loaders.js";
|
|
4
4
|
import { getParam } from "./utils.js";
|
|
5
|
+
import { plugins } from "./plugins/plugin.js";
|
|
5
6
|
const debugProgressiveLoading = getParam("debugprogressive");
|
|
6
7
|
const suppressProgressiveLoading = getParam("noprogressive");
|
|
8
|
+
const $lodsManager = Symbol("Needle:LODSManager");
|
|
7
9
|
/**
|
|
8
10
|
* The LODsManager class is responsible for managing the LODs and progressive assets in the scene. It will automatically update the LODs based on the camera position, screen coverage and mesh density of the objects.
|
|
9
11
|
* It must be enabled by calling the `enable` method.
|
|
10
12
|
*
|
|
11
13
|
* Instead of using the LODs manager directly you can also call `useNeedleProgressive` to enable progressive loading for a GLTFLoader
|
|
14
|
+
*
|
|
15
|
+
* ### Plugins
|
|
16
|
+
* Use {@link LODsManager.addPlugin} to add a plugin to the LODsManager. A plugin can be used to hook into the LOD update process and modify the LOD levels or perform other actions.
|
|
17
|
+
*
|
|
18
|
+
* @example Adding a LODsManager to a Three.js scene:
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { LODsManager } from "@needle-tools/gltf-progressive";
|
|
21
|
+
* import { WebGLRenderer, Scene, Camera, Mesh } from "three";
|
|
22
|
+
*
|
|
23
|
+
* const renderer = new WebGLRenderer();
|
|
24
|
+
* const lodsManager = LODsManager.get(renderer);
|
|
25
|
+
* lodsManager.enable();
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example Using the LODsManager with a GLTFLoader:
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { useNeedleProgressive } from "@needle-tools/gltf-progressive";
|
|
31
|
+
* import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
32
|
+
*
|
|
33
|
+
* const url = 'https://yourdomain.com/yourmodel.glb';
|
|
34
|
+
* const loader = new GLTFLoader();
|
|
35
|
+
* const lodsManager = useNeedleProgressive(url, renderer, loader);
|
|
36
|
+
* ```
|
|
12
37
|
*/
|
|
13
38
|
export class LODsManager {
|
|
14
39
|
/** Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
|
|
@@ -18,9 +43,34 @@ export class LODsManager {
|
|
|
18
43
|
static getObjectLODState(object) {
|
|
19
44
|
return object.userData?.LOD_state;
|
|
20
45
|
}
|
|
46
|
+
static addPlugin(plugin) {
|
|
47
|
+
plugins.push(plugin);
|
|
48
|
+
}
|
|
49
|
+
static removePlugin(plugin) {
|
|
50
|
+
const index = plugins.indexOf(plugin);
|
|
51
|
+
if (index >= 0)
|
|
52
|
+
plugins.splice(index, 1);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Gets the LODsManager for the given renderer. If the LODsManager does not exist yet, it will be created.
|
|
56
|
+
* @param renderer The renderer to get the LODsManager for.
|
|
57
|
+
* @returns The LODsManager instance.
|
|
58
|
+
*/
|
|
59
|
+
static get(renderer) {
|
|
60
|
+
if (renderer[$lodsManager]) {
|
|
61
|
+
return renderer[$lodsManager];
|
|
62
|
+
}
|
|
63
|
+
const lodsManager = new LODsManager(renderer);
|
|
64
|
+
return lodsManager;
|
|
65
|
+
}
|
|
21
66
|
renderer;
|
|
22
67
|
projectionScreenMatrix = new Matrix4();
|
|
23
68
|
cameraFrustrum = new Frustum();
|
|
69
|
+
/**
|
|
70
|
+
* The target triangle density is the desired max amount of triangles on screen when the mesh is filling the screen.
|
|
71
|
+
* @default 200_000
|
|
72
|
+
*/
|
|
73
|
+
targetTriangleDensity = 200_000;
|
|
24
74
|
/**
|
|
25
75
|
* The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 1, the LODs will be updated every second frame, etc.
|
|
26
76
|
*/
|
|
@@ -29,7 +79,7 @@ export class LODsManager {
|
|
|
29
79
|
* If set to true, the LODsManager will not update the LODs.
|
|
30
80
|
*/
|
|
31
81
|
pause = false;
|
|
32
|
-
plugins = [];
|
|
82
|
+
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
33
83
|
constructor(renderer) {
|
|
34
84
|
this.renderer = renderer;
|
|
35
85
|
}
|
|
@@ -95,7 +145,7 @@ export class LODsManager {
|
|
|
95
145
|
return;
|
|
96
146
|
this.projectionScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
97
147
|
this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix, this.renderer.coordinateSystem);
|
|
98
|
-
const desiredDensity =
|
|
148
|
+
const desiredDensity = this.targetTriangleDensity;
|
|
99
149
|
// const isLowPerformanceDevice = false;// isMobileDevice();
|
|
100
150
|
// Experiment: quick & dirty performance-adaptive LODs
|
|
101
151
|
/*
|
|
@@ -135,7 +185,7 @@ export class LODsManager {
|
|
|
135
185
|
}
|
|
136
186
|
/** Update the LOD levels for the renderer. */
|
|
137
187
|
updateLODs(scene, camera, object, desiredDensity) {
|
|
138
|
-
for (const plugin of
|
|
188
|
+
for (const plugin of plugins) {
|
|
139
189
|
plugin.onBeforeUpdateLOD?.(this.renderer, scene, camera, object);
|
|
140
190
|
}
|
|
141
191
|
let state = object.userData.LOD_state;
|
|
@@ -164,7 +214,7 @@ export class LODsManager {
|
|
|
164
214
|
this.loadProgressiveTextures(object.material, textureLOD);
|
|
165
215
|
}
|
|
166
216
|
}
|
|
167
|
-
for (const plugin of
|
|
217
|
+
for (const plugin of plugins) {
|
|
168
218
|
plugin.onAfterUpdatedLOD?.(this.renderer, scene, camera, object, level);
|
|
169
219
|
}
|
|
170
220
|
state.lastLodLevel = level;
|
package/lib/plugins/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { patchModelViewer } from "./modelviewer.js";
|
|
2
|
-
export {
|
|
2
|
+
export { type NEEDLE_progressive_plugin } from "./plugin.js";
|
package/lib/plugins/index.js
CHANGED
|
@@ -23,8 +23,8 @@ export function patchModelViewer(modelviewer) {
|
|
|
23
23
|
}
|
|
24
24
|
if (renderer) {
|
|
25
25
|
console.log("Adding Needle LODs to modelviewer");
|
|
26
|
-
const lod =
|
|
27
|
-
|
|
26
|
+
const lod = LODsManager.get(renderer);
|
|
27
|
+
LODsManager.addPlugin(new RegisterModelviewerDataPlugin(modelviewer));
|
|
28
28
|
lod.enable();
|
|
29
29
|
if (scene) {
|
|
30
30
|
const camera = scene["camera"] || scene.traverse((o) => o.type == "PerspectiveCamera")[0];
|
|
@@ -104,7 +104,11 @@ class RegisterModelviewerDataPlugin {
|
|
|
104
104
|
if (value?.isTexture === true) {
|
|
105
105
|
const textureIndex = value.userData?.associations?.textures;
|
|
106
106
|
const textureData = currentGLTF.parser.json.textures[textureIndex];
|
|
107
|
-
if (textureData
|
|
107
|
+
if (!textureData) {
|
|
108
|
+
console.warn("Texture data not found for texture index " + textureIndex);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (textureData?.extensions?.[EXTENSION_NAME]) {
|
|
108
112
|
const ext = textureData.extensions[EXTENSION_NAME];
|
|
109
113
|
if (ext && url) {
|
|
110
114
|
NEEDLE_progressive.registerTexture(url, value, ext.lods.length, ext);
|
package/lib/plugins/plugin.d.ts
CHANGED
|
@@ -18,7 +18,3 @@ export interface NEEDLE_progressive_plugin {
|
|
|
18
18
|
* @internal
|
|
19
19
|
*/
|
|
20
20
|
export declare const plugins: NEEDLE_progressive_plugin[];
|
|
21
|
-
/**
|
|
22
|
-
* Register a plugin for the progressive extension. The plugin callbacks will be called at different stages of the progressive extension.
|
|
23
|
-
*/
|
|
24
|
-
export declare function registerPlugin(plugin: NEEDLE_progressive_plugin): void;
|
package/lib/plugins/plugin.js
CHANGED
|
@@ -3,9 +3,3 @@
|
|
|
3
3
|
* @internal
|
|
4
4
|
*/
|
|
5
5
|
export const plugins = new Array();
|
|
6
|
-
/**
|
|
7
|
-
* Register a plugin for the progressive extension. The plugin callbacks will be called at different stages of the progressive extension.
|
|
8
|
-
*/
|
|
9
|
-
export function registerPlugin(plugin) {
|
|
10
|
-
plugins.push(plugin);
|
|
11
|
-
}
|
package/lib/utils.d.ts
CHANGED
|
@@ -1,2 +1,15 @@
|
|
|
1
|
+
import { BufferGeometry, Object3D } from "three";
|
|
1
2
|
export declare function getParam(name: string): boolean | string;
|
|
2
3
|
export declare function resolveUrl(source: string | undefined, uri: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* The raycast mesh is a low poly version of the mesh used for raycasting. It is set when a mesh that has LOD level with more vertices is discovered for the first time
|
|
6
|
+
* @param obj the object to get the raycast mesh from
|
|
7
|
+
* @returns the raycast mesh or null if not set
|
|
8
|
+
*/
|
|
9
|
+
export declare function getRaycastMesh(obj: Object3D): BufferGeometry<any> | null;
|
|
10
|
+
/**
|
|
11
|
+
* Set the raycast mesh for an object. The raycast mesh is a low poly version of the mesh used for raycasting. It is set when a mesh that has LOD level with more vertices is discovered for the first time
|
|
12
|
+
* @param obj the object to set the raycast mesh for
|
|
13
|
+
* @param geom the raycast mesh
|
|
14
|
+
*/
|
|
15
|
+
export declare function setRaycastMesh(obj: Object3D, geom: BufferGeometry): void;
|
package/lib/utils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BufferGeometry } from "three";
|
|
1
2
|
export function getParam(name) {
|
|
2
3
|
const url = new URL(window.location.href);
|
|
3
4
|
const param = url.searchParams.get(name);
|
|
@@ -34,3 +35,26 @@ export function resolveUrl(source, uri) {
|
|
|
34
35
|
}
|
|
35
36
|
return uri;
|
|
36
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* The raycast mesh is a low poly version of the mesh used for raycasting. It is set when a mesh that has LOD level with more vertices is discovered for the first time
|
|
40
|
+
* @param obj the object to get the raycast mesh from
|
|
41
|
+
* @returns the raycast mesh or null if not set
|
|
42
|
+
*/
|
|
43
|
+
export function getRaycastMesh(obj) {
|
|
44
|
+
if (obj.userData?.["needle:raycast-mesh"] instanceof BufferGeometry) {
|
|
45
|
+
return obj.userData["needle:raycast-mesh"];
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Set the raycast mesh for an object. The raycast mesh is a low poly version of the mesh used for raycasting. It is set when a mesh that has LOD level with more vertices is discovered for the first time
|
|
51
|
+
* @param obj the object to set the raycast mesh for
|
|
52
|
+
* @param geom the raycast mesh
|
|
53
|
+
*/
|
|
54
|
+
export function setRaycastMesh(obj, geom) {
|
|
55
|
+
if (obj.type === "Mesh" || obj.type === "SkinnedMesh") {
|
|
56
|
+
if (!obj.userData)
|
|
57
|
+
obj.userData = {};
|
|
58
|
+
obj.userData["needle:raycast-mesh"] = geom;
|
|
59
|
+
}
|
|
60
|
+
}
|
package/package.json
CHANGED