@needle-tools/gltf-progressive 1.2.0-alpha.9 → 1.2.1-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/gltf-progressive.js +323 -325
- package/gltf-progressive.min.js +4 -4
- package/gltf-progressive.umd.cjs +4 -4
- package/lib/extension.js +4 -5
- package/lib/lods_manager.js +11 -12
- package/lib/utils.js +4 -5
- package/package.json +1 -1
package/gltf-progressive.min.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
var
|
|
2
|
-
`,
|
|
3
|
-
`,
|
|
1
|
+
var ye=Object.defineProperty,ve=(t,e,r)=>e in t?ye(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,d=(t,e,r)=>(ve(t,typeof e!="symbol"?e+"":e,r),r);import{MeshoptDecoder as Le}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Me}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as De}from"three/examples/jsm/loaders/KTX2Loader.js";import{BufferGeometry as z,Mesh as N,Material as _e,Texture as U,TextureLoader as we,Matrix4 as de,Frustum as Oe,Sphere as be,Box3 as he,Vector3 as j}from"three";import{GLTFLoader as Se}from"three/examples/jsm/loaders/GLTFLoader.js";let J="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",se="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(J+"draco_decoder.js",{method:"head"}).catch(t=>{J="./include/draco/",se="./include/ktx2/"});function Te(t){J=t}function Ae(t){se=t}let q,oe,V;function ne(t){q||(q=new Me,q.setDecoderPath(J),q.setDecoderConfig({type:"js"})),V||(V=new De,V.setTranscoderPath(se)),oe||(oe=Le),t?V.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ie(t){t.dracoLoader||t.setDRACOLoader(q),t.ktx2Loader||t.setKTX2Loader(V),t.meshoptDecoder||t.setMeshoptDecoder(oe)}function Q(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Pe(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const r=t.lastIndexOf("/");if(r>=0){const n=t.substring(0,r+1);for(;n.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return n+e}return e}let Z;function Ee(){return Z!==void 0||(Z=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),Q("debugprogressive")&&console.log("isMobileDevice",Z)),Z}const ae=Symbol("needle:raycast-mesh");function ee(t){return t?.[ae]instanceof z?t[ae]:null}function fe(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!ee(t)){const r=Be(e);r.userData={isRaycastMesh:!0},t[ae]=r}}function Ie(t=!0){if(t){if(X)return;const e=X=N.prototype.raycast;N.prototype.raycast=function(r,n){const o=this,s=ee(o);let a;s&&o.isMesh&&(a=o.geometry,o.geometry=s),e.call(this,r,n),a&&(o.geometry=a)}}else{if(!X)return;N.prototype.raycast=X,X=null}}let X=null;function Be(t){const e=new z;for(const r in t.attributes)e.setAttribute(r,t.getAttribute(r));return e.setIndex(t.getIndex()),e}const F=new Array,C="NEEDLE_progressive",v=Q("debugprogressive"),le=Symbol("needle-progressive-texture"),K=new Map,ue=new Set;if(v){let t=function(){e+=1,console.log("Toggle LOD level",e,K),K.forEach((o,s)=>{for(const a of o.keys){const i=s[a];if(i!=null){if(i.isBufferGeometry===!0){const l=S.getMeshLODInformation(i),c=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=e,S.assignMeshLOD(s,c),l&&(r=Math.max(r,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,S.assignTextureLOD(s,e);break}}}}),e>=r&&(e=-1)},e=-1,r=2,n=!1;window.addEventListener("keyup",o=>{o.key==="p"&&t(),o.key==="w"&&(n=!n,ue&&ue.forEach(s=>{s.name!="BackgroundCubeMaterial"&&s.glyphMap==null&&"wireframe"in s&&(s.wireframe=n)}))})}function ge(t,e,r){var n;if(!v)return;K.has(t)||K.set(t,{keys:[],sourceId:r});const o=K.get(t);((n=o?.keys)==null?void 0:n.includes(e))==!1&&o.keys.push(e)}const _=class{constructor(t,e){d(this,"parser"),d(this,"url"),d(this,"_isLoadingMesh"),d(this,"loadMesh",r=>{var n,o;if(this._isLoadingMesh)return null;const s=(o=(n=this.parser.json.meshes[r])==null?void 0:n.extensions)==null?void 0:o[C];return s?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",r).then(a=>(this._isLoadingMesh=!1,a&&_.registerMesh(this.url,s.guid,a,s.lods.length,void 0,s),a))):null}),v&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return C}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const r=this,n="LODS:minmax",o=t[n];if(o!=null)return o;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const a of t)this.getMaterialMinMaxLODsCount(a,e);return t[n]=e,e}if(v==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const a=t;for(const i of Object.keys(a.uniforms)){const l=a.uniforms[i].value;l?.isTexture===!0&&s(l,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const i=t[a];i?.isTexture===!0&&s(i,e)}return t[n]=e,e;function s(a,i){const l=r.getAssignedLODInformation(a);if(l){const c=r.lodInfos.get(l.key);if(c&&c.lods){i.min_count=Math.min(i.min_count,c.lods.length),i.max_count=Math.max(i.max_count,c.lods.length);for(let f=0;f<c.lods.length;f++){const u=c.lods[f];u.width&&(i.lods[f]=i.lods[f]||{min_height:1/0,max_height:0},i.lods[f].min_height=Math.min(i.lods[f].min_height,u.height),i.lods[f].max_height=Math.max(i.lods[f].max_height,u.height))}}}}}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 n,o;if(t.isMesh?n=t.geometry:(t.isBufferGeometry||t.isTexture)&&(n=t),n&&(r=n?.userData)!=null&&r.LODS){const s=n.userData.LODS();if(o=this.lodInfos.get(s.key),e===void 0)return o!=null;if(o)return Array.isArray(o.lods)?e<o.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof N||t.isMesh===!0){const n=t.geometry,o=this.getAssignedLODInformation(n);if(!o)return Promise.resolve(null);for(const s of F)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,_.getOrLoadLOD(n,e).then(s=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(s)){const a=o.index||0;s=s[a]}s&&n!=s&&s instanceof z&&(t.geometry=s,v&&ge(t,"geometry",o.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 _e||t.isMaterial===!0){const r=t,n=[],o=new Array;if(v&&ue.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 l=this.assignTextureLODForSlot(i,e,r,a);n.push(l),o.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);n.push(i),o.push(s)}}return Promise.all(n).then(s=>{const a=new Array;for(let i=0;i<s.length;i++){const l=s[i],c=o[i];l&&l.isTexture===!0?a.push({material:r,slot:c,texture:l,level:e}):a.push({material:r,slot:c,texture:null,level:e})}return a})}if(t instanceof U||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,n){return t?.isTexture!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):_.getOrLoadLOD(t,e).then(o=>{if(Array.isArray(o))return null;if(o?.isTexture===!0){if(o!=t){if(r&&n){const s=r[n];if(s){const a=this.getAssignedLODInformation(s);if(a&&a?.level<e)return v==="verbose"&&console.warn("Assigned texture level is already higher: ",a.level,e,r,s,o),null}r[n]=o}if(v&&n&&r){const s=this.getAssignedLODInformation(t);s&&ge(r,n,s.url)}}return o}else v=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(o=>(console.error("Error loading LOD",t,o),null))}afterRoot(t){var e,r;return v&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[C];if(s){if(!s.lods){v&&console.warn("Texture has no LODs",s);return}let a=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i).textures===o&&(a=!0,_.registerTexture(this.url,i,s.lods.length,o,s));a||this.parser.getDependency("texture",o).then(i=>{i&&_.registerTexture(this.url,i,s.lods.length,o,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[C];if(s&&s.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const i=this.parser.associations.get(a);i.meshes===o&&_.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(t,e){var r,n,o,s,a,i;const l=v=="verbose",c=(n=(r=t.userData).LODS)==null?void 0:n.call(r);if(!c)return null;const f=c?.key;let u;if(t.isTexture===!0){const y=t;y.source&&y.source[le]&&(u=y.source[le])}if(u||(u=_.lodInfos.get(f)),u){if(e>0){let h=!1;const O=Array.isArray(u.lods);if(O&&e>=u.lods.length?h=!0:O||(h=!0),h)return this.lowresCache.get(f)}const y=Array.isArray(u.lods)?(o=u.lods[e])==null?void 0:o.path:u.lods;if(!y)return v&&!u["missing:uri"]&&(u["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,u)),null;const m=Pe(c.url,y);if(m.endsWith(".glb")||m.endsWith(".gltf")){if(!u.guid)return console.warn("missing pointer for glb/gltf texture",u),null;const h=m+"_"+u.guid,O=this.previouslyLoaded.get(h);if(O!==void 0){l&&console.log(`LOD ${e} was already loading/loaded: ${h}`);let b=await O.catch(x=>(console.error(`Error loading LOD ${e} from ${m}
|
|
2
|
+
`,x),null)),G=!1;if(b==null||(b instanceof U&&t instanceof U?(s=b.image)!=null&&s.data||(a=b.source)!=null&&a.data?b=this.copySettings(t,b):(G=!0,this.previouslyLoaded.delete(h)):b instanceof z&&t instanceof z&&((i=b.attributes.position)!=null&&i.array||(G=!0,this.previouslyLoaded.delete(h)))),!G)return b}const p=u,P=new Promise(async(b,G)=>{const x=new Se;ie(x),v&&(await new Promise(D=>setTimeout(D,1e3)),l&&console.warn("Start loading (delayed) "+m,p.guid));let L=m;if(p&&Array.isArray(p.lods)){const D=p.lods[e];D.hash&&(L+="?v="+D.hash)}const w=await x.loadAsync(L).catch(D=>(console.error(`Error loading LOD ${e} from ${m}
|
|
3
|
+
`,D),null));if(!w)return null;const A=w.parser;l&&console.log("Loading finished "+m,p.guid);let M=0;if(w.parser.json.textures){let D=!1;for(const g of w.parser.json.textures){if(g!=null&&g.extensions){const T=g?.extensions[C];if(T!=null&&T.guid&&T.guid===p.guid){D=!0;break}}M++}if(D){let g=await A.getDependency("texture",M);return g&&_.assignLODInformation(c.url,g,f,e,void 0,void 0),l&&console.log('change "'+t.name+'" \u2192 "'+g.name+'"',m,M,g,h),t instanceof U&&(g=this.copySettings(t,g)),g&&(g.guid=p.guid),b(g)}else v&&console.warn("Could not find texture with guid",p.guid)}if(M=0,w.parser.json.meshes){let D=!1;for(const g of w.parser.json.meshes){if(g!=null&&g.extensions){const T=g?.extensions[C];if(T!=null&&T.guid&&T.guid===p.guid){D=!0;break}}M++}if(D){const g=await A.getDependency("mesh",M),T=p;if(l&&console.log(`Loaded Mesh "${g.name}"`,m,M,g,h),g.isMesh===!0){const B=g.geometry;return _.assignLODInformation(c.url,B,f,e,void 0,T.density),b(B)}else{const B=new Array;for(let k=0;k<g.children.length;k++){const H=g.children[k];if(H instanceof N){const Y=H.geometry;_.assignLODInformation(c.url,Y,f,e,k,T.density),B.push(Y)}}return b(B)}}}return b(null)});return this.previouslyLoaded.set(h,P),await P}else if(t instanceof U){l&&console.log("Load texture from uri: "+m);const h=await new we().loadAsync(m);return h?(h.guid=u.guid,h.flipY=!1,h.needsUpdate=!0,h.colorSpace=t.colorSpace,l&&console.log(u,h)):v&&console.warn("failed loading",m),h}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${f}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,n,o,s){if(!e)return;e.userData||(e.userData={});const a=new Ce(t,r,n,o,s);e.userData.LODS=()=>a}static getAssignedLODInformation(t){var e,r;return((r=(e=t?.userData)==null?void 0:e.LODS)==null?void 0:r.call(e))||null}static copySettings(t,e){return e=e.clone(),v&&console.warn(`Copying texture settings
|
|
4
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=O;c(w,"registerTexture",(t,e,r,n,o)=>{if(v&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,o),!e){v&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[oe]=o);const s=o.guid;O.assignLODInformation(t,e,s,r,n,void 0),O.lodInfos.set(s,o),O.lowresCache.set(s,e)}),c(w,"registerMesh",(t,e,r,n,o,s)=>{var a;v&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const i=r.geometry;if(!i){v&&console.warn("gltf-progressive: Register mesh without geometry");return}i.userData||(i.userData={}),O.assignLODInformation(t,i,e,n,o,s.density),O.lodInfos.set(e,s);let u=O.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],O.lowresCache.set(e,u),n>0&&!J(r)&&le(r,i);for(const l of R)(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 Pe{constructor(e,r,n,o,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=r,this.level=n,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const W=H("debugprogressive"),Be=H("noprogressive"),ce=Symbol("Needle:LODSManager"),E={mesh_lod:-1,texture_lod:-1},T=class{constructor(t){c(this,"renderer"),c(this,"projectionScreenMatrix",new ie),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 Oe),c(this,"_tempBox",new ae),c(this,"_tempBox2",new ae),c(this,"tempMatrix",new ie),c(this,"_tempWorldPosition",new I),c(this,"_tempBoxSize",new I),c(this,"_tempBox2Size",new I),this.renderer=t}static getObjectLODState(t){var e;return(e=t.userData)==null?void 0:e.LOD_state}static addPlugin(t){R.push(t)}static removePlugin(t){const e=R.indexOf(t);e>=0&&R.splice(e,1)}static get(t){return t[ce]?t[ce]:new T(t)}get plugins(){return R}enable(){if(this._originalRender)return;let t=0;this._originalRender=this.renderer.render;const e=this;re(this.renderer),this.renderer.render=function(r,n){e.renderer.getRenderTarget()==null&&(t=0,e._frame+=1);const o=e._frame,s=t++;e.onBeforeRender(r,n,s,o),e._originalRender.call(this,r,n),e.onAfterRender(r,n,s,o)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,n){}onAfterRender(t,e,r,n){var o,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(Be||this.updateInterval>0&&n%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 d of i){if(d.material&&(((o=d.geometry)==null?void 0:o.type)==="BoxGeometry"||((s=d.geometry)==null?void 0:s.type)==="BufferGeometry")&&(d.material.name==="SphericalGaussianBlur"||d.material.name=="BackgroundCubeMaterial"||d.material.name==="CubemapFromEquirect"||d.material.name==="EquirectangularToCubeUV")){W&&(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",d,d.material.name,d.material.type)));continue}switch(d.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const f=d.object;(f instanceof G||f.isMesh)&&this.updateLODs(t,e,f,l,n)}const g=a.transparent;for(const d of g){const f=d.object;(f instanceof G||f.isMesh)&&this.updateLODs(t,e,f,l,n)}}}updateLODs(t,e,r,n,o){var s,a;r.userData||(r.userData={});let i=r.userData.LOD_state;if(i||(i=new Ie,r.userData.LOD_state=i),i.frames++<2)return;for(const l of R)(s=l.onBeforeUpdateLOD)==null||s.call(l,this.renderer,t,e,r);this.calculateLodLevel(e,r,i,n,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 R)(a=l.onAfterUpdatedLOD)==null||a.call(l,this.renderer,t,e,r,E);i.lastLodLevel_Mesh=E.mesh_lod,i.lastLodLevel_Texture=E.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}const r=t;let n=!1;(r.NEEDLE_LOD==null||e<r.NEEDLE_LOD)&&(n=!0),n&&(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(n=>(n&&t.userData.LOD==e&&r!=t.geometry,n))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,n=t.max,o=(r.x+n.x)*.5,s=(r.y+n.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,n,o){var s;if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let a=10+1;if(W&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const i=w.getMeshLODInformation(e.geometry),u=i?.lods,l=u&&u.length>0,g=w.getMaterialMinMaxLODsCount(e.material),d=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!l&&!d){o.mesh_lod=0,o.texture_lod=0;return}if(l||(a=0),!((s=this.cameraFrustrum)!=null&&s.intersectsObject(e))){o.mesh_lod=99,o.texture_lod=99;return}let f=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const D=e;D.boundingBox||D.computeBoundingBox(),f=D.boundingBox}if(f&&t.isPerspectiveCamera){const D=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 x=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(x)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(f),e.type==="SkinnedMesh"?e.parent&&this._tempBox.applyMatrix4(e.parent.matrixWorld):this._tempBox.applyMatrix4(e.matrixWorld),T.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&D.fov>70){const x=this._tempBox.min,L=this._tempBox.max;let M=x.x,y=x.y,h=L.x,_=L.y;const A=2,C=1.5,k=(x.x+L.x)*.5,j=(x.y+L.y)*.5;M=(M-k)*A+k,y=(y-j)*A+j,h=(h-k)*A+k,_=(_-j)*A+j;const fe=M<0&&h>0?0:Math.min(Math.abs(x.x),Math.abs(L.x)),ge=y<0&&_>0?0:Math.min(Math.abs(x.y),Math.abs(L.y)),Z=Math.max(fe,ge);r.lastCentrality=(C-Z)*(C-Z)*(C-Z)}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*=D.aspect;const S=t.matrixWorldInverse,p=this._tempBox2;p.copy(f),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(S);const b=p.getSize(this._tempBox2Size),N=Math.max(b.x,b.y);if(Math.max(m.x,m.y)!=0&&N!=0&&(m.z=b.z/Math.max(b.x,b.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,W&&T.debugDrawLine){const x=this.tempMatrix.copy(this.projectionScreenMatrix);x.invert();const L=T.corner0,M=T.corner1,y=T.corner2,h=T.corner3;L.copy(this._tempBox.min),M.copy(this._tempBox.max),M.x=L.x,y.copy(this._tempBox.max),y.y=L.y,h.copy(this._tempBox.max);const _=(L.z+h.z)*.5;L.z=M.z=y.z=h.z=_,L.applyMatrix4(x),M.applyMatrix4(x),y.applyMatrix4(x),h.applyMatrix4(x),T.debugDrawLine(L,M,255),T.debugDrawLine(L,y,255),T.debugDrawLine(M,h,255),T.debugDrawLine(y,h,255)}let F=999;if(u&&r.lastScreenCoverage>0){for(let x=0;x<u.length;x++)if(u[x].density/r.lastScreenCoverage<n){F=x;break}}F<a&&(a=F)}if(o.mesh_lod=a,d)if(r.lastLodLevel_Texture<0){if(o.texture_lod=g.max_count-1,W){const D=g.lods[g.max_count-1];W&&console.log(`First Texture LOD ${o.texture_lod} (${D.max_height}px) - ${e.name}`)}}else{const D=r.lastScreenCoverage*1.5,m=this.renderer.domElement.clientHeight/window.devicePixelRatio*D;for(let S=g.lods.length-1;S>=0;S--){const p=g.lods[S];if(!(Te()&&p.max_height>4096)&&p.max_height>m){o.texture_lod=S,o.texture_lod<r.lastLodLevel_Texture&&W&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} \u2192 ${o.texture_lod} (${p.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${m.toFixed(0)}px) - ${e.name}`);break}}}else o.texture_lod=0}};let B=T;c(B,"debugDrawLine"),c(B,"corner0",new I),c(B,"corner1",new I),c(B,"corner2",new I),c(B,"corner3",new I),c(B,"_tempPtInside",new I);class Ie{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",-1),c(this,"lastLodLevel_Texture",-1),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new I),c(this,"lastCentrality",0)}}const de=Symbol("NEEDLE_mesh_lod"),Q=Symbol("NEEDLE_texture_lod");function he(t){if(!t)return null;let e=null,r=null;for(let n=t;n!=null;n=Object.getPrototypeOf(n)){const o=Object.getOwnPropertySymbols(n),s=o.find(i=>i.toString()=="Symbol(renderer)"),a=o.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 n=B.get(e);if(B.addPlugin(new Ce(t)),n.enable(),r){const o=r.camera||r.traverse(s=>s.type=="PerspectiveCamera")[0];o&&e.render(r,o)}return()=>{n.disable()}}return null}class Ce{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,r,n,o){this.tryParseMeshLOD(r,o),this.tryParseTextureLOD(r,o)}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[Q]==!0)return;r[Q]=!0;const n=this.tryGetCurrentGLTF(e),o=this.getUrl();if(o&&n&&r.material){let s=function(i){var u,l,g;if(i[Q]==!0)return;i[Q]=!0,i.userData&&(i.userData.LOD=-1);const d=Object.keys(i);for(let f=0;f<d.length;f++){const D=d[f],m=i[D];if(m?.isTexture===!0){const S=(l=(u=m.userData)==null?void 0:u.associations)==null?void 0:l.textures,p=n.parser.json.textures[S];if(!p){console.warn("Texture data not found for texture index "+S);continue}if((g=p?.extensions)!=null&&g[P]){const b=p.extensions[P];b&&o&&w.registerTexture(o,m,b.lods.length,S,b)}}}};const a=r.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,r){var n,o;if(r[de]==!0)return;r[de]=!0;const s=this.getUrl();if(!s)return;const a=(o=(n=r.userData)==null?void 0:n.gltfExtensions)==null?void 0:o[P];if(a&&s){const i=r.uuid;w.registerMesh(s,i,r,0,a.lods.length,a)}}}function Re(t,e,r,n){re(e),se(r),r.register(s=>new w(s,t));const o=B.get(e);return n?.enableLODsManager!==!1&&o.enable(),o}document.addEventListener("DOMContentLoaded",()=>{he(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,B as LODsManager,w as NEEDLE_progressive,se as addDracoAndKTX2Loaders,re as createLoaders,J as getRaycastMesh,he as patchModelViewer,we as setDracoDecoderLocation,be as setKTX2TranscoderLocation,le as setRaycastMesh,Re as useNeedleProgressive,Ee as useRaycastMeshes};
|
|
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 S=_;d(S,"registerTexture",(t,e,r,n,o)=>{if(v&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,o),!e){v&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[le]=o);const s=o.guid;_.assignLODInformation(t,e,s,r,n,void 0),_.lodInfos.set(s,o),_.lowresCache.set(s,e)}),d(S,"registerMesh",(t,e,r,n,o,s)=>{var a;v&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const i=r.geometry;if(!i){v&&console.warn("gltf-progressive: Register mesh without geometry");return}i.userData||(i.userData={}),_.assignLODInformation(t,i,e,n,o,s.density),_.lodInfos.set(e,s);let l=_.lowresCache.get(e);l?l.push(r.geometry):l=[r.geometry],_.lowresCache.set(e,l),n>0&&!ee(r)&&fe(r,i);for(const c of F)(a=c.onRegisteredNewMesh)==null||a.call(c,r,s)}),d(S,"lodInfos",new Map),d(S,"previouslyLoaded",new Map),d(S,"lowresCache",new Map);class Ce{constructor(e,r,n,o,s){d(this,"url"),d(this,"key"),d(this,"level"),d(this,"index"),d(this,"density"),this.url=e,this.key=r,this.level=n,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const W=Q("debugprogressive"),Re=Q("noprogressive"),me=Symbol("Needle:LODSManager"),ce=Symbol("Needle:LODState"),$=Symbol("Needle:CurrentLOD"),I={mesh_lod:-1,texture_lod:-1},E=class{constructor(t){d(this,"renderer"),d(this,"projectionScreenMatrix",new de),d(this,"cameraFrustrum",new Oe),d(this,"targetTriangleDensity",2e5),d(this,"updateInterval",0),d(this,"pause",!1),d(this,"_frame",0),d(this,"_originalRender"),d(this,"_sphere",new be),d(this,"_tempBox",new he),d(this,"_tempBox2",new he),d(this,"tempMatrix",new de),d(this,"_tempWorldPosition",new j),d(this,"_tempBoxSize",new j),d(this,"_tempBox2Size",new j),this.renderer=t}static getObjectLODState(t){return t[ce]}static addPlugin(t){F.push(t)}static removePlugin(t){const e=F.indexOf(t);e>=0&&F.splice(e,1)}static get(t){return t[me]?t[me]:new E(t)}get plugins(){return F}enable(){if(this._originalRender)return;let t=0;this._originalRender=this.renderer.render;const e=this;ne(this.renderer),this.renderer.render=function(r,n){e.renderer.getRenderTarget()==null&&(t=0,e._frame+=1);const o=e._frame,s=t++;e.onBeforeRender(r,n,s,o),e._originalRender.call(this,r,n),e.onAfterRender(r,n,s,o)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,n){}onAfterRender(t,e,r,n){var o,s;if(this.pause)return;const a=this.renderer.renderLists.get(t,0),i=a.opaque;let l=!0;if(i.length===1){const c=i[0].material;(c.name==="EffectMaterial"||c.name==="CopyShader")&&(l=!1)}if(e.parent&&e.parent.type==="CubeCamera"&&(l=!1),l){if(Re||this.updateInterval>0&&n%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const c=this.targetTriangleDensity;for(const u of i){if(u.material&&(((o=u.geometry)==null?void 0:o.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")){W&&(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}switch(u.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const y=u.object;(y instanceof N||y.isMesh)&&this.updateLODs(t,e,y,c,n)}const f=a.transparent;for(const u of f){const y=u.object;(y instanceof N||y.isMesh)&&this.updateLODs(t,e,y,c,n)}}}updateLODs(t,e,r,n,o){var s,a;r.userData||(r.userData={});let i=r[ce];if(i||(i=new ke,r[ce]=i),i.frames++<2)return;for(const c of F)(s=c.onBeforeUpdateLOD)==null||s.call(c,this.renderer,t,e,r);this.calculateLodLevel(e,r,i,n,I),I.mesh_lod=Math.round(I.mesh_lod),I.texture_lod=Math.round(I.texture_lod),I.mesh_lod>=0&&this.loadProgressiveMeshes(r,I.mesh_lod);let l=I.texture_lod;if(r.material&&l>=0){const c=r["DEBUG:LOD"];c!=null&&(l=c),this.loadProgressiveTextures(r.material,l)}for(const c of F)(a=c.onAfterUpdatedLOD)==null||a.call(c,this.renderer,t,e,r,I);i.lastLodLevel_Mesh=I.mesh_lod,i.lastLodLevel_Texture=I.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const n of t)this.loadProgressiveTextures(n,e);return}let r=!1;(t[$]==null||e<t[$])&&(r=!0),r&&(t[$]=e,S.assignTextureLOD(t,e))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[$]!==e){t[$]=e;const r=t.geometry;return S.assignMeshLOD(t,e).then(n=>(n&&t[$]==e&&r!=t.geometry,n))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,n=t.max,o=(r.x+n.x)*.5,s=(r.y+n.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,n,o){var s;if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let a=10+1;if(W&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const i=S.getMeshLODInformation(e.geometry),l=i?.lods,c=l&&l.length>0,f=S.getMaterialMinMaxLODsCount(e.material),u=f?.min_count!=1/0&&f.min_count>0&&f.max_count>0;if(!c&&!u){o.mesh_lod=0,o.texture_lod=0;return}if(c||(a=0),!((s=this.cameraFrustrum)!=null&&s.intersectsObject(e))){o.mesh_lod=99,o.texture_lod=99;return}let y=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const m=e;m.boundingBox||m.computeBoundingBox(),y=m.boundingBox}if(y&&t.isPerspectiveCamera){const m=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 x=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(x)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(y),e.type==="SkinnedMesh"?e.parent&&this._tempBox.applyMatrix4(e.parent.matrixWorld):this._tempBox.applyMatrix4(e.matrixWorld),E.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&m.fov>70){const x=this._tempBox.min,L=this._tempBox.max;let w=x.x,A=x.y,M=L.x,D=L.y;const g=2,T=1.5,B=(x.x+L.x)*.5,k=(x.y+L.y)*.5;w=(w-B)*g+B,A=(A-k)*g+k,M=(M-B)*g+B,D=(D-k)*g+k;const H=w<0&&M>0?0:Math.min(Math.abs(x.x),Math.abs(L.x)),Y=A<0&&D>0?0:Math.min(Math.abs(x.y),Math.abs(L.y)),re=Math.max(H,Y);r.lastCentrality=(T-re)*(T-re)*(T-re)}else r.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*=m.aspect;const O=t.matrixWorldInverse,p=this._tempBox2;p.copy(y),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(O);const P=p.getSize(this._tempBox2Size),b=Math.max(P.x,P.y);if(Math.max(h.x,h.y)!=0&&b!=0&&(h.z=P.z/Math.max(P.x,P.y)*Math.max(h.x,h.y)),r.lastScreenCoverage=Math.max(h.x,h.y,h.z),r.lastScreenspaceVolume.copy(h),r.lastScreenCoverage*=r.lastCentrality,W&&E.debugDrawLine){const x=this.tempMatrix.copy(this.projectionScreenMatrix);x.invert();const L=E.corner0,w=E.corner1,A=E.corner2,M=E.corner3;L.copy(this._tempBox.min),w.copy(this._tempBox.max),w.x=L.x,A.copy(this._tempBox.max),A.y=L.y,M.copy(this._tempBox.max);const D=(L.z+M.z)*.5;L.z=w.z=A.z=M.z=D,L.applyMatrix4(x),w.applyMatrix4(x),A.applyMatrix4(x),M.applyMatrix4(x),E.debugDrawLine(L,w,255),E.debugDrawLine(L,A,255),E.debugDrawLine(w,M,255),E.debugDrawLine(A,M,255)}let G=999;if(l&&r.lastScreenCoverage>0){for(let x=0;x<l.length;x++)if(l[x].density/r.lastScreenCoverage<n){G=x;break}}G<a&&(a=G)}if(o.mesh_lod=a,u)if(r.lastLodLevel_Texture<0){if(o.texture_lod=f.max_count-1,W){const m=f.lods[f.max_count-1];W&&console.log(`First Texture LOD ${o.texture_lod} (${m.max_height}px) - ${e.name}`)}}else{const m=r.lastScreenCoverage*1.5,h=this.renderer.domElement.clientHeight/window.devicePixelRatio*m;for(let O=f.lods.length-1;O>=0;O--){const p=f.lods[O];if(!(Ee()&&p.max_height>4096)&&p.max_height>h){o.texture_lod=O,o.texture_lod<r.lastLodLevel_Texture&&W&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} \u2192 ${o.texture_lod} (${p.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${h.toFixed(0)}px) - ${e.name}`);break}}}else o.texture_lod=0}};let R=E;d(R,"debugDrawLine"),d(R,"corner0",new j),d(R,"corner1",new j),d(R,"corner2",new j),d(R,"corner3",new j),d(R,"_tempPtInside",new j);class ke{constructor(){d(this,"frames",0),d(this,"lastLodLevel_Mesh",-1),d(this,"lastLodLevel_Texture",-1),d(this,"lastScreenCoverage",0),d(this,"lastScreenspaceVolume",new j),d(this,"lastCentrality",0)}}const pe=Symbol("NEEDLE_mesh_lod"),te=Symbol("NEEDLE_texture_lod");function xe(t){if(!t)return null;let e=null,r=null;for(let n=t;n!=null;n=Object.getPrototypeOf(n)){const o=Object.getOwnPropertySymbols(n),s=o.find(i=>i.toString()=="Symbol(renderer)"),a=o.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 n=R.get(e);if(R.addPlugin(new je(t)),n.enable(),r){const o=r.camera||r.traverse(s=>s.type=="PerspectiveCamera")[0];o&&e.render(r,o)}return()=>{n.disable()}}return null}class je{constructor(e){d(this,"modelviewer"),d(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,r,n,o){this.tryParseMeshLOD(r,o),this.tryParseTextureLOD(r,o)}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[te]==!0)return;r[te]=!0;const n=this.tryGetCurrentGLTF(e),o=this.getUrl();if(o&&n&&r.material){let s=function(i){var l,c,f;if(i[te]==!0)return;i[te]=!0,i.userData&&(i.userData.LOD=-1);const u=Object.keys(i);for(let y=0;y<u.length;y++){const m=u[y],h=i[m];if(h?.isTexture===!0){const O=(c=(l=h.userData)==null?void 0:l.associations)==null?void 0:c.textures,p=n.parser.json.textures[O];if(!p){console.warn("Texture data not found for texture index "+O);continue}if((f=p?.extensions)!=null&&f[C]){const P=p.extensions[C];P&&o&&S.registerTexture(o,h,P.lods.length,O,P)}}}};const a=r.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,r){var n,o;if(r[pe]==!0)return;r[pe]=!0;const s=this.getUrl();if(!s)return;const a=(o=(n=r.userData)==null?void 0:n.gltfExtensions)==null?void 0:o[C];if(a&&s){const i=r.uuid;S.registerMesh(s,i,r,0,a.lods.length,a)}}}function Ge(t,e,r,n){ne(e),ie(r),r.register(s=>new S(s,t));const o=R.get(e);return n?.enableLODsManager!==!1&&o.enable(),o}document.addEventListener("DOMContentLoaded",()=>{xe(document.querySelector("model-viewer"))});export{C as EXTENSION_NAME,R as LODsManager,S as NEEDLE_progressive,ie as addDracoAndKTX2Loaders,ne as createLoaders,ee as getRaycastMesh,xe as patchModelViewer,Te as setDracoDecoderLocation,Ae as setKTX2TranscoderLocation,fe as setRaycastMesh,Ge as useNeedleProgressive,Ie as useRaycastMeshes};
|
package/gltf-progressive.umd.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`,
|
|
3
|
-
`,
|
|
1
|
+
"use strict";var xe=Object.defineProperty;var me=(l,e,t)=>e in l?xe(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var c=(l,e,t)=>(me(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Le=require("three/examples/jsm/libs/meshopt_decoder.module.js"),Me=require("three/examples/jsm/loaders/DRACOLoader.js"),De=require("three/examples/jsm/loaders/KTX2Loader.js"),h=require("three"),we=require("three/examples/jsm/loaders/GLTFLoader.js");let Q="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ae="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(Q+"draco_decoder.js",{method:"head"}).catch(l=>{Q="./include/draco/",ae="./include/ktx2/"});function _e(l){Q=l}function Oe(l){ae=l}let X,ie,Y;function le(l){X||(X=new Me.DRACOLoader,X.setDecoderPath(Q),X.setDecoderConfig({type:"js"})),Y||(Y=new De.KTX2Loader,Y.setTranscoderPath(ae)),ie||(ie=Le.MeshoptDecoder),l?Y.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ce(l){l.dracoLoader||l.setDRACOLoader(X),l.ktx2Loader||l.setKTX2Loader(Y),l.meshoptDecoder||l.setMeshoptDecoder(ie)}function Z(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function ve(l,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||l===void 0)return e;const t=l.lastIndexOf("/");if(t>=0){const r=l.substring(0,t+1);for(;r.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return r+e}return e}let q;function Se(){return q!==void 0||(q=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),Z("debugprogressive")&&console.log("isMobileDevice",q)),q}const oe=Symbol("needle:raycast-mesh");function j(l){return(l==null?void 0:l[oe])instanceof h.BufferGeometry?l[oe]:null}function he(l,e){if((l.type==="Mesh"||l.type==="SkinnedMesh")&&!j(l)){const r=be(e);r.userData={isRaycastMesh:!0},l[oe]=r}}function Te(l=!0){if(l){if(K)return;const e=K=h.Mesh.prototype.raycast;h.Mesh.prototype.raycast=function(t,r){const i=this,o=j(i);let s;o&&i.isMesh&&(s=i.geometry,i.geometry=o),e.call(this,t,r),s&&(i.geometry=s)}}else{if(!K)return;h.Mesh.prototype.raycast=K,K=null}}let K=null;function be(l){const e=new h.BufferGeometry;for(const t in l.attributes)e.setAttribute(t,l.getAttribute(t));return e.setIndex(l.getIndex()),e}const $=new Array,I="NEEDLE_progressive",M=Z("debugprogressive"),re=Symbol("needle-progressive-texture"),H=new Map,ne=new Set;if(M){let l=function(){e+=1,console.log("Toggle LOD level",e,H),H.forEach((i,o)=>{for(const s of i.keys){const n=o[s];if(n!=null){if(n.isBufferGeometry===!0){const a=b.getMeshLODInformation(n),d=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,b.assignMeshLOD(o,d),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,b.assignTextureLOD(o,e);break}}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",i=>{i.key==="p"&&l(),i.key==="w"&&(r=!r,ne&&ne.forEach(o=>{o.name!="BackgroundCubeMaterial"&&o.glyphMap==null&&"wireframe"in o&&(o.wireframe=r)}))})}function ue(l,e,t){var i;if(!M)return;H.has(l)||H.set(l,{keys:[],sourceId:t});const r=H.get(l);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const S=class{constructor(e,t){c(this,"parser");c(this,"url");c(this,"_isLoadingMesh");c(this,"loadMesh",e=>{var r,i;if(this._isLoadingMesh)return null;const t=(i=(r=this.parser.json.meshes[e])==null?void 0:r.extensions)==null?void 0:i[I];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(o=>(this._isLoadingMesh=!1,o&&S.registerMesh(this.url,t.guid,o,t.lods.length,void 0,t),o))):null});M&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return I}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static getMaterialMinMaxLODsCount(e,t){const r=this,i="LODS:minmax",o=e[i];if(o!=null)return o;if(t||(t={min_count:1/0,max_count:0,lods:[]}),Array.isArray(e)){for(const n of e)this.getMaterialMinMaxLODsCount(n,t);return e[i]=t,t}if(M==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const n=e;for(const a of Object.keys(n.uniforms)){const d=n.uniforms[a].value;(d==null?void 0:d.isTexture)===!0&&s(d,t)}}else if(e.isMaterial)for(const n of Object.keys(e)){const a=e[n];(a==null?void 0:a.isTexture)===!0&&s(a,t)}return e[i]=t,t;function s(n,a){const d=r.getAssignedLODInformation(n);if(d){const f=r.lodInfos.get(d.key);if(f&&f.lods){a.min_count=Math.min(a.min_count,f.lods.length),a.max_count=Math.max(a.max_count,f.lods.length);for(let y=0;y<f.lods.length;y++){const p=f.lods[y];p.width&&(a.lods[y]=a.lods[y]||{min_height:1/0,max_height:0},a.lods[y].min_height=Math.min(a.lods[y].min_height,p.height),a.lods[y].max_height=Math.max(a.lods[y].max_height,p.height))}}}}}static hasLODLevelAvailable(e,t){var o;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 n=e[s];if(n&&n.isTexture&&this.hasLODLevelAvailable(n,t))return!0}return!1}else if(e.isGroup===!0){for(const s of e.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,t))return!0}let r,i;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const s=r.userData.LODS();if(i=this.lodInfos.get(s.key),t===void 0)return i!=null;if(i)return Array.isArray(i.lods)?t<i.lods.length:t===0}return!1}static assignMeshLOD(e,t){var r;if(!e)return Promise.resolve(null);if(e instanceof h.Mesh||e.isMesh===!0){const i=e.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of $)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,S.getOrLoadLOD(i,t).then(s=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(s)){const n=o.index||0;s=s[n]}s&&i!=s&&s instanceof h.BufferGeometry&&(e.geometry=s,M&&ue(e,"geometry",o.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",e,s),null))}else M&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e instanceof h.Material||e.isMaterial===!0){const r=e,i=[],o=new Array;if(M&&ne.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const n of Object.keys(s.uniforms)){const a=s.uniforms[n].value;if((a==null?void 0:a.isTexture)===!0){const d=this.assignTextureLODForSlot(a,t,r,n);i.push(d),o.push(n)}}}else for(const s of Object.keys(r)){const n=r[s];if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,t,r,s);i.push(a),o.push(s)}}return Promise.all(i).then(s=>{const n=new Array;for(let a=0;a<s.length;a++){const d=s[a],f=o[a];d&&d.isTexture===!0?n.push({material:r,slot:f,texture:d,level:t}):n.push({material:r,slot:f,texture:null,level:t})}return n})}if(e instanceof h.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,i){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):i==="glyphMap"?Promise.resolve(e):S.getOrLoadLOD(e,t).then(o=>{if(Array.isArray(o))return null;if((o==null?void 0:o.isTexture)===!0){if(o!=e){if(r&&i){const s=r[i];if(s){const n=this.getAssignedLODInformation(s);if(n&&(n==null?void 0:n.level)<t)return M==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,t,r,s,o),null}r[i]=o}if(M&&i&&r){const s=this.getAssignedLODInformation(e);s&&ue(r,i,s.url)}}return o}else M=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(o=>(console.error("Error loading LOD",e,o),null))}afterRoot(e){var t,r;return M&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[I];if(s){if(!s.lods){M&&console.warn("Texture has no LODs",s);return}let n=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===o&&(n=!0,S.registerTexture(this.url,a,s.lods.length,o,s));n||this.parser.getDependency("texture",o).then(a=>{a&&S.registerTexture(this.url,a,s.lods.length,o,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[I];if(s&&s.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const a=this.parser.associations.get(n);a.meshes===o&&S.registerMesh(this.url,s.guid,n,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var n,a,d,f,y,p;const r=M=="verbose",i=(a=(n=e.userData).LODS)==null?void 0:a.call(n);if(!i)return null;const o=i==null?void 0:i.key;let s;if(e.isTexture===!0){const w=e;w.source&&w.source[re]&&(s=w.source[re])}if(s||(s=S.lodInfos.get(o)),s){if(t>0){let x=!1;const g=Array.isArray(s.lods);if(g&&t>=s.lods.length?x=!0:g||(x=!0),x)return this.lowresCache.get(o)}const w=Array.isArray(s.lods)?(d=s.lods[t])==null?void 0:d.path:s.lods;if(!w)return M&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const D=ve(i.url,w);if(D.endsWith(".glb")||D.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const x=D+"_"+s.guid,g=this.previouslyLoaded.get(x);if(g!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${x}`);let A=await g.catch(G=>(console.error(`Error loading LOD ${t} from ${D}
|
|
2
|
+
`,G),null)),V=!1;if(A==null||(A instanceof h.Texture&&e instanceof h.Texture?(f=A.image)!=null&&f.data||(y=A.source)!=null&&y.data?A=this.copySettings(e,A):(V=!0,this.previouslyLoaded.delete(x)):A instanceof h.BufferGeometry&&e instanceof h.BufferGeometry&&((p=A.attributes.position)!=null&&p.array||(V=!0,this.previouslyLoaded.delete(x)))),!V)return A}const _=s,B=new Promise(async(A,V)=>{const G=new we.GLTFLoader;ce(G),M&&(await new Promise(L=>setTimeout(L,1e3)),r&&console.warn("Start loading (delayed) "+D,_.guid));let ee=D;if(_&&Array.isArray(_.lods)){const L=_.lods[t];L.hash&&(ee+="?v="+L.hash)}const m=await G.loadAsync(ee).catch(L=>(console.error(`Error loading LOD ${t} from ${D}
|
|
3
|
+
`,L),null));if(!m)return null;const O=m.parser;r&&console.log("Loading finished "+D,_.guid);let v=0;if(m.parser.json.textures){let L=!1;for(const u of m.parser.json.textures){if(u!=null&&u.extensions){const T=u==null?void 0:u.extensions[I];if(T!=null&&T.guid&&T.guid===_.guid){L=!0;break}}v++}if(L){let u=await O.getDependency("texture",v);return u&&S.assignLODInformation(i.url,u,o,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+u.name+'"',D,v,u,x),e instanceof h.Texture&&(u=this.copySettings(e,u)),u&&(u.guid=_.guid),A(u)}else M&&console.warn("Could not find texture with guid",_.guid)}if(v=0,m.parser.json.meshes){let L=!1;for(const u of m.parser.json.meshes){if(u!=null&&u.extensions){const T=u==null?void 0:u.extensions[I];if(T!=null&&T.guid&&T.guid===_.guid){L=!0;break}}v++}if(L){const u=await O.getDependency("mesh",v),T=_;if(r&&console.log(`Loaded Mesh "${u.name}"`,D,v,u,x),u.isMesh===!0){const E=u.geometry;return S.assignLODInformation(i.url,E,o,t,void 0,T.density),A(E)}else{const E=new Array;for(let F=0;F<u.children.length;F++){const N=u.children[F];if(N instanceof h.Mesh){const z=N.geometry;S.assignLODInformation(i.url,z,o,t,F,T.density),E.push(z)}}return A(E)}}}return A(null)});return this.previouslyLoaded.set(x,B),await B}else if(e instanceof h.Texture){r&&console.log("Load texture from uri: "+D);const g=await new h.TextureLoader().loadAsync(D);return g?(g.guid=s.guid,g.flipY=!1,g.needsUpdate=!0,g.colorSpace=e.colorSpace,r&&console.log(s,g)):M&&console.warn("failed loading",D),g}}else M&&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 Ae(e,r,i,o,s);t.userData.LODS=()=>n}static getAssignedLODInformation(e){var t,r;return((r=(t=e==null?void 0:e.userData)==null?void 0:t.LODS)==null?void 0:r.call(t))||null}static copySettings(e,t){return t=t.clone(),M&&console.warn(`Copying texture settings
|
|
4
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;c(S,"registerTexture",(e,t,r,i,o)=>{if(_&&console.log("> Progressive: register texture",i,t.name,t.uuid,t,o),!t){_&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[te]=o);const s=o.guid;v.assignLODInformation(e,t,s,r,i,void 0),v.lodInfos.set(s,o),v.lowresCache.set(s,t)}),c(S,"registerMesh",(e,t,r,i,o,s)=>{var h;_&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const n=r.geometry;if(!n){_&&console.warn("gltf-progressive: Register mesh without geometry");return}n.userData||(n.userData={}),v.assignLODInformation(e,n,t,i,o,s.density),v.lodInfos.set(t,s);let a=v.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],v.lowresCache.set(t,a),i>0&&!Q(r)&&ue(r,n);for(const d of I)(h=d.onRegisteredNewMesh)==null||h.call(d,r,s)}),c(S,"lodInfos",new Map),c(S,"previouslyLoaded",new Map),c(S,"lowresCache",new Map);class Se{constructor(e,t,r,i,o){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),o!=null&&(this.density=o)}}const z=J("debugprogressive"),Te=J("noprogressive"),le=Symbol("Needle:LODSManager"),E={mesh_lod:-1,texture_lod:-1},b=class{constructor(e){c(this,"renderer");c(this,"projectionScreenMatrix",new g.Matrix4);c(this,"cameraFrustrum",new g.Frustum);c(this,"targetTriangleDensity",2e5);c(this,"updateInterval",0);c(this,"pause",!1);c(this,"_frame",0);c(this,"_originalRender");c(this,"_sphere",new g.Sphere);c(this,"_tempBox",new g.Box3);c(this,"_tempBox2",new g.Box3);c(this,"tempMatrix",new g.Matrix4);c(this,"_tempWorldPosition",new g.Vector3);c(this,"_tempBoxSize",new g.Vector3);c(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){I.push(e)}static removePlugin(e){const t=I.indexOf(e);t>=0&&I.splice(t,1)}static get(e){return e[le]?e[le]:new b(e)}get plugins(){return I}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;oe(this.renderer),this.renderer.render=function(r,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,n=e++;t.onBeforeRender(r,i,n,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,n,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var a,h;if(this.pause)return;const o=this.renderer.renderLists.get(e,0),s=o.opaque;let n=!0;if(s.length===1){const d=s[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(n=!1)}if(t.parent&&t.parent.type==="CubeCamera"&&(n=!1),n){if(Te||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=this.targetTriangleDensity;for(const f of s){if(f.material&&(((a=f.geometry)==null?void 0:a.type)==="BoxGeometry"||((h=f.geometry)==null?void 0:h.type)==="BufferGeometry")&&(f.material.name==="SphericalGaussianBlur"||f.material.name=="BackgroundCubeMaterial"||f.material.name==="CubemapFromEquirect"||f.material.name==="EquirectangularToCubeUV")){z&&(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 x=f.object;(x instanceof g.Mesh||x.isMesh)&&this.updateLODs(e,t,x,d,i)}const p=o.transparent;for(const f of p){const x=f.object;(x instanceof g.Mesh||x.isMesh)&&this.updateLODs(e,t,x,d,i)}}}updateLODs(e,t,r,i,o){var a,h;r.userData||(r.userData={});let s=r.userData.LOD_state;if(s||(s=new Ae,r.userData.LOD_state=s),s.frames++<2)return;for(const d of I)(a=d.onBeforeUpdateLOD)==null||a.call(d,this.renderer,e,t,r);this.calculateLodLevel(t,r,s,i,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 n=E.texture_lod;if(r.material&&n>=0){const d=r["DEBUG:LOD"];d!=null&&(n=d),this.loadProgressiveTextures(r.material,n)}for(const d of I)(h=d.onAfterUpdatedLOD)==null||h.call(d,this.renderer,e,t,r,E);s.lastLodLevel_Mesh=E.mesh_lod,s.lastLodLevel_Texture=E.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const o of e)this.loadProgressiveTextures(o,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,o=(r.x+i.x)*.5,s=(r.y+i.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,r,i,o){var O;if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}let n=10+1;if(z&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=S.getMeshLODInformation(t.geometry),h=a==null?void 0:a.lods,d=h&&h.length>0,p=S.getMaterialMinMaxLODsCount(t.material),f=(p==null?void 0:p.min_count)!=1/0&&p.min_count>0&&p.max_count>0;if(!d&&!f){o.mesh_lod=0,o.texture_lod=0;return}if(d||(n=0),!((O=this.cameraFrustrum)!=null&&O.intersectsObject(t))){o.mesh_lod=99,o.texture_lod=99;return}let x=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const m=t;m.boundingBox||m.computeBoundingBox(),x=m.boundingBox}if(x&&e.isPerspectiveCamera){const m=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const L=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(L)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(x),t.type==="SkinnedMesh"?t.parent&&this._tempBox.applyMatrix4(t.parent.matrixWorld):this._tempBox.applyMatrix4(t.matrixWorld),b.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&m.fov>70){const L=this._tempBox.min,y=this._tempBox.max;let u=L.x,M=L.y,T=y.x,R=y.y;const G=2,N=1.5,K=(L.x+y.x)*.5,X=(L.y+y.y)*.5;u=(u-K)*G+K,M=(M-X)*G+X,T=(T-K)*G+K,R=(R-X)*G+X;const de=u<0&&T>0?0:Math.min(Math.abs(L.x),Math.abs(y.x)),he=M<0&&R>0?0:Math.min(Math.abs(L.y),Math.abs(y.y)),ee=Math.max(de,he);r.lastCentrality=(N-ee)*(N-ee)*(N-ee)}else r.lastCentrality=1;const w=this._tempBox.getSize(this._tempBoxSize);w.multiplyScalar(.5),screen.availHeight>0&&w.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),w.x*=m.aspect;const k=e.matrixWorldInverse,D=this._tempBox2;D.copy(x),D.applyMatrix4(t.matrixWorld),D.applyMatrix4(k);const A=D.getSize(this._tempBox2Size),F=Math.max(A.x,A.y);if(Math.max(w.x,w.y)!=0&&F!=0&&(w.z=A.z/Math.max(A.x,A.y)*Math.max(w.x,w.y)),r.lastScreenCoverage=Math.max(w.x,w.y,w.z),r.lastScreenspaceVolume.copy(w),r.lastScreenCoverage*=r.lastCentrality,z&&b.debugDrawLine){const L=this.tempMatrix.copy(this.projectionScreenMatrix);L.invert();const y=b.corner0,u=b.corner1,M=b.corner2,T=b.corner3;y.copy(this._tempBox.min),u.copy(this._tempBox.max),u.x=y.x,M.copy(this._tempBox.max),M.y=y.y,T.copy(this._tempBox.max);const R=(y.z+T.z)*.5;y.z=u.z=M.z=T.z=R,y.applyMatrix4(L),u.applyMatrix4(L),M.applyMatrix4(L),T.applyMatrix4(L),b.debugDrawLine(y,u,255),b.debugDrawLine(y,M,255),b.debugDrawLine(u,T,255),b.debugDrawLine(M,T,255)}let B=999;if(h&&r.lastScreenCoverage>0){for(let L=0;L<h.length;L++)if(h[L].density/r.lastScreenCoverage<i){B=L;break}}B<n&&(n=B)}if(o.mesh_lod=n,f)if(r.lastLodLevel_Texture<0){if(o.texture_lod=p.max_count-1,z){const m=p.lods[p.max_count-1];z&&console.log(`First Texture LOD ${o.texture_lod} (${m.max_height}px) - ${t.name}`)}}else{const m=r.lastScreenCoverage*1.5,k=this.renderer.domElement.clientHeight/window.devicePixelRatio*m;for(let D=p.lods.length-1;D>=0;D--){const A=p.lods[D];if(!(Oe()&&A.max_height>4096)&&A.max_height>k){o.texture_lod=D,o.texture_lod<r.lastLodLevel_Texture&&z&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} → ${o.texture_lod} (${A.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${k.toFixed(0)}px) - ${t.name}`);break}}}else o.texture_lod=0}};let P=b;c(P,"debugDrawLine"),c(P,"corner0",new g.Vector3),c(P,"corner1",new g.Vector3),c(P,"corner2",new g.Vector3),c(P,"corner3",new g.Vector3),c(P,"_tempPtInside",new g.Vector3);class Ae{constructor(){c(this,"frames",0);c(this,"lastLodLevel_Mesh",-1);c(this,"lastLodLevel_Texture",-1);c(this,"lastScreenCoverage",0);c(this,"lastScreenspaceVolume",new g.Vector3);c(this,"lastCentrality",0)}}const ce=Symbol("NEEDLE_mesh_lod"),Y=Symbol("NEEDLE_texture_lod");function fe(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=P.get(e);if(P.addPlugin(new be(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 be{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[Y]==!0)return;t[Y]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let o=function(n){var h,d,p;if(n[Y]==!0)return;n[Y]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let f=0;f<a.length;f++){const x=a[f],O=n[x];if((O==null?void 0:O.isTexture)===!0){const m=(d=(h=O.userData)==null?void 0:h.associations)==null?void 0:d.textures,w=r.parser.json.textures[m];if(!w){console.warn("Texture data not found for texture index "+m);continue}if((p=w==null?void 0:w.extensions)!=null&&p[C]){const k=w.extensions[C];k&&i&&S.registerTexture(i,O,k.lods.length,m,k)}}}};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[ce]==!0)return;t[ce]=!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;S.registerMesh(r,n,t,0,i.lods.length,i)}}}function Pe(l,e,t,r){oe(e),ne(t),t.register(o=>new S(o,l));const i=P.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{fe(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=C;exports.LODsManager=P;exports.NEEDLE_progressive=S;exports.addDracoAndKTX2Loaders=ne;exports.createLoaders=oe;exports.getRaycastMesh=Q;exports.patchModelViewer=fe;exports.setDracoDecoderLocation=De;exports.setKTX2TranscoderLocation=Me;exports.setRaycastMesh=ue;exports.useNeedleProgressive=Pe;exports.useRaycastMeshes=we;
|
|
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 b=S;c(b,"registerTexture",(e,t,r,i,o)=>{if(M&&console.log("> Progressive: register texture",i,t.name,t.uuid,t,o),!t){M&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[re]=o);const s=o.guid;S.assignLODInformation(e,t,s,r,i,void 0),S.lodInfos.set(s,o),S.lowresCache.set(s,t)}),c(b,"registerMesh",(e,t,r,i,o,s)=>{var d;M&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const n=r.geometry;if(!n){M&&console.warn("gltf-progressive: Register mesh without geometry");return}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),i>0&&!j(r)&&he(r,n);for(const f of $)(d=f.onRegisteredNewMesh)==null||d.call(f,r,s)}),c(b,"lodInfos",new Map),c(b,"previouslyLoaded",new Map),c(b,"lowresCache",new Map);class Ae{constructor(e,t,r,i,o){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),o!=null&&(this.density=o)}}const U=Z("debugprogressive"),Pe=Z("noprogressive"),fe=Symbol("Needle:LODSManager"),se=Symbol("Needle:LODState"),W=Symbol("Needle:CurrentLOD"),R={mesh_lod:-1,texture_lod:-1},P=class{constructor(e){c(this,"renderer");c(this,"projectionScreenMatrix",new h.Matrix4);c(this,"cameraFrustrum",new h.Frustum);c(this,"targetTriangleDensity",2e5);c(this,"updateInterval",0);c(this,"pause",!1);c(this,"_frame",0);c(this,"_originalRender");c(this,"_sphere",new h.Sphere);c(this,"_tempBox",new h.Box3);c(this,"_tempBox2",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){return e[se]}static addPlugin(e){$.push(e)}static removePlugin(e){const t=$.indexOf(e);t>=0&&$.splice(t,1)}static get(e){return e[fe]?e[fe]:new P(e)}get plugins(){return $}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;le(this.renderer),this.renderer.render=function(r,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,n=e++;t.onBeforeRender(r,i,n,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,n,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var a,d;if(this.pause)return;const o=this.renderer.renderLists.get(e,0),s=o.opaque;let n=!0;if(s.length===1){const f=s[0].material;(f.name==="EffectMaterial"||f.name==="CopyShader")&&(n=!1)}if(t.parent&&t.parent.type==="CubeCamera"&&(n=!1),n){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=this.targetTriangleDensity;for(const p of s){if(p.material&&(((a=p.geometry)==null?void 0:a.type)==="BoxGeometry"||((d=p.geometry)==null?void 0:d.type)==="BufferGeometry")&&(p.material.name==="SphericalGaussianBlur"||p.material.name=="BackgroundCubeMaterial"||p.material.name==="CubemapFromEquirect"||p.material.name==="EquirectangularToCubeUV")){U&&(p.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(p.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",p,p.material.name,p.material.type)));continue}switch(p.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const w=p.object;(w instanceof h.Mesh||w.isMesh)&&this.updateLODs(e,t,w,f,i)}const y=o.transparent;for(const p of y){const w=p.object;(w instanceof h.Mesh||w.isMesh)&&this.updateLODs(e,t,w,f,i)}}}updateLODs(e,t,r,i,o){var a,d;r.userData||(r.userData={});let s=r[se];if(s||(s=new Be,r[se]=s),s.frames++<2)return;for(const f of $)(a=f.onBeforeUpdateLOD)==null||a.call(f,this.renderer,e,t,r);this.calculateLodLevel(t,r,s,i,R),R.mesh_lod=Math.round(R.mesh_lod),R.texture_lod=Math.round(R.texture_lod),R.mesh_lod>=0&&this.loadProgressiveMeshes(r,R.mesh_lod);let n=R.texture_lod;if(r.material&&n>=0){const f=r["DEBUG:LOD"];f!=null&&(n=f),this.loadProgressiveTextures(r.material,n)}for(const f of $)(d=f.onAfterUpdatedLOD)==null||d.call(f,this.renderer,e,t,r,R);s.lastLodLevel_Mesh=R.mesh_lod,s.lastLodLevel_Texture=R.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const i of e)this.loadProgressiveTextures(i,t);return}let r=!1;(e[W]==null||t<e[W])&&(r=!0),r&&(e[W]=t,b.assignTextureLOD(e,t))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e[W]!==t){e[W]=t;const r=e.geometry;return b.assignMeshLOD(e,t).then(i=>(i&&e[W]==t&&r!=e.geometry,i))}return Promise.resolve(null)}static isInside(e,t){const r=e.min,i=e.max,o=(r.x+i.x)*.5,s=(r.y+i.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,r,i,o){var D;if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}let n=10+1;if(U&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=b.getMeshLODInformation(t.geometry),d=a==null?void 0:a.lods,f=d&&d.length>0,y=b.getMaterialMinMaxLODsCount(t.material),p=(y==null?void 0:y.min_count)!=1/0&&y.min_count>0&&y.max_count>0;if(!f&&!p){o.mesh_lod=0,o.texture_lod=0;return}if(f||(n=0),!((D=this.cameraFrustrum)!=null&&D.intersectsObject(t))){o.mesh_lod=99,o.texture_lod=99;return}let w=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const x=t;x.boundingBox||x.computeBoundingBox(),w=x.boundingBox}if(w&&e.isPerspectiveCamera){const x=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)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(w),t.type==="SkinnedMesh"?t.parent&&this._tempBox.applyMatrix4(t.parent.matrixWorld):this._tempBox.applyMatrix4(t.matrixWorld),P.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&x.fov>70){const m=this._tempBox.min,O=this._tempBox.max;let v=m.x,L=m.y,u=O.x,T=O.y;const E=2,F=1.5,N=(m.x+O.x)*.5,z=(m.y+O.y)*.5;v=(v-N)*E+N,L=(L-z)*E+z,u=(u-N)*E+N,T=(T-z)*E+z;const pe=v<0&&u>0?0:Math.min(Math.abs(m.x),Math.abs(O.x)),ye=L<0&&T>0?0:Math.min(Math.abs(m.y),Math.abs(O.y)),te=Math.max(pe,ye);r.lastCentrality=(F-te)*(F-te)*(F-te)}else r.lastCentrality=1;const g=this._tempBox.getSize(this._tempBoxSize);g.multiplyScalar(.5),screen.availHeight>0&&g.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),g.x*=x.aspect;const _=e.matrixWorldInverse,B=this._tempBox2;B.copy(w),B.applyMatrix4(t.matrixWorld),B.applyMatrix4(_);const k=B.getSize(this._tempBox2Size),A=Math.max(k.x,k.y);if(Math.max(g.x,g.y)!=0&&A!=0&&(g.z=k.z/Math.max(k.x,k.y)*Math.max(g.x,g.y)),r.lastScreenCoverage=Math.max(g.x,g.y,g.z),r.lastScreenspaceVolume.copy(g),r.lastScreenCoverage*=r.lastCentrality,U&&P.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const O=P.corner0,v=P.corner1,L=P.corner2,u=P.corner3;O.copy(this._tempBox.min),v.copy(this._tempBox.max),v.x=O.x,L.copy(this._tempBox.max),L.y=O.y,u.copy(this._tempBox.max);const T=(O.z+u.z)*.5;O.z=v.z=L.z=u.z=T,O.applyMatrix4(m),v.applyMatrix4(m),L.applyMatrix4(m),u.applyMatrix4(m),P.debugDrawLine(O,v,255),P.debugDrawLine(O,L,255),P.debugDrawLine(v,u,255),P.debugDrawLine(L,u,255)}let G=999;if(d&&r.lastScreenCoverage>0){for(let m=0;m<d.length;m++)if(d[m].density/r.lastScreenCoverage<i){G=m;break}}G<n&&(n=G)}if(o.mesh_lod=n,p)if(r.lastLodLevel_Texture<0){if(o.texture_lod=y.max_count-1,U){const x=y.lods[y.max_count-1];U&&console.log(`First Texture LOD ${o.texture_lod} (${x.max_height}px) - ${t.name}`)}}else{const x=r.lastScreenCoverage*1.5,_=this.renderer.domElement.clientHeight/window.devicePixelRatio*x;for(let B=y.lods.length-1;B>=0;B--){const k=y.lods[B];if(!(Se()&&k.max_height>4096)&&k.max_height>_){o.texture_lod=B,o.texture_lod<r.lastLodLevel_Texture&&U&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} → ${o.texture_lod} (${k.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${_.toFixed(0)}px) - ${t.name}`);break}}}else o.texture_lod=0}};let C=P;c(C,"debugDrawLine"),c(C,"corner0",new h.Vector3),c(C,"corner1",new h.Vector3),c(C,"corner2",new h.Vector3),c(C,"corner3",new h.Vector3),c(C,"_tempPtInside",new h.Vector3);class Be{constructor(){c(this,"frames",0);c(this,"lastLodLevel_Mesh",-1);c(this,"lastLodLevel_Texture",-1);c(this,"lastScreenCoverage",0);c(this,"lastScreenspaceVolume",new h.Vector3);c(this,"lastCentrality",0)}}const de=Symbol("NEEDLE_mesh_lod"),J=Symbol("NEEDLE_texture_lod");function ge(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=C.get(e);if(C.addPlugin(new Ce(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 Ce{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[J]==!0)return;t[J]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let o=function(n){var d,f,y;if(n[J]==!0)return;n[J]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let p=0;p<a.length;p++){const w=a[p],D=n[w];if((D==null?void 0:D.isTexture)===!0){const x=(f=(d=D.userData)==null?void 0:d.associations)==null?void 0:f.textures,g=r.parser.json.textures[x];if(!g){console.warn("Texture data not found for texture index "+x);continue}if((y=g==null?void 0:g.extensions)!=null&&y[I]){const _=g.extensions[I];_&&i&&b.registerTexture(i,D,_.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[de]==!0)return;t[de]=!0;const r=this.getUrl();if(!r)return;const i=(s=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:s[I];if(i&&r){const n=t.uuid;b.registerMesh(r,n,t,0,i.lods.length,i)}}}function Re(l,e,t,r){le(e),ce(t),t.register(o=>new b(o,l));const i=C.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{ge(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=I;exports.LODsManager=C;exports.NEEDLE_progressive=b;exports.addDracoAndKTX2Loaders=ce;exports.createLoaders=le;exports.getRaycastMesh=j;exports.patchModelViewer=ge;exports.setDracoDecoderLocation=_e;exports.setKTX2TranscoderLocation=Oe;exports.setRaycastMesh=he;exports.useNeedleProgressive=Re;exports.useRaycastMeshes=Te;
|
package/lib/extension.js
CHANGED
|
@@ -208,7 +208,7 @@ export class NEEDLE_progressive {
|
|
|
208
208
|
}
|
|
209
209
|
if (lodObject) {
|
|
210
210
|
if (lodObject?.userData?.LODS) {
|
|
211
|
-
const lods = lodObject.userData.LODS;
|
|
211
|
+
const lods = lodObject.userData.LODS();
|
|
212
212
|
lodInformation = this.lodInfos.get(lods.key);
|
|
213
213
|
if (level === undefined)
|
|
214
214
|
return lodInformation != undefined;
|
|
@@ -537,7 +537,7 @@ export class NEEDLE_progressive {
|
|
|
537
537
|
static async getOrLoadLOD(current, level) {
|
|
538
538
|
const debugverbose = debug == "verbose";
|
|
539
539
|
/** this key is used to lookup the LOD information */
|
|
540
|
-
const LOD = current.userData.LODS;
|
|
540
|
+
const LOD = current.userData.LODS?.();
|
|
541
541
|
if (!LOD) {
|
|
542
542
|
return null;
|
|
543
543
|
}
|
|
@@ -762,11 +762,10 @@ export class NEEDLE_progressive {
|
|
|
762
762
|
if (!res.userData)
|
|
763
763
|
res.userData = {};
|
|
764
764
|
const info = new LODInformation(url, key, level, index, density);
|
|
765
|
-
res.userData.LODS = info;
|
|
766
|
-
res.userData.LOD = level;
|
|
765
|
+
res.userData.LODS = () => info;
|
|
767
766
|
}
|
|
768
767
|
static getAssignedLODInformation(res) {
|
|
769
|
-
return res?.userData?.LODS || null;
|
|
768
|
+
return res?.userData?.LODS?.() || null;
|
|
770
769
|
}
|
|
771
770
|
// private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
|
|
772
771
|
static copySettings(source, target) {
|
package/lib/lods_manager.js
CHANGED
|
@@ -6,6 +6,8 @@ import { plugins } from "./plugins/plugin.js";
|
|
|
6
6
|
const debugProgressiveLoading = getParam("debugprogressive");
|
|
7
7
|
const suppressProgressiveLoading = getParam("noprogressive");
|
|
8
8
|
const $lodsManager = Symbol("Needle:LODSManager");
|
|
9
|
+
const $lodstate = Symbol("Needle:LODState");
|
|
10
|
+
const $currentLOD = Symbol("Needle:CurrentLOD");
|
|
9
11
|
const levels = { mesh_lod: -1, texture_lod: -1 };
|
|
10
12
|
/**
|
|
11
13
|
* 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.
|
|
@@ -42,7 +44,7 @@ export class LODsManager {
|
|
|
42
44
|
static debugDrawLine;
|
|
43
45
|
/** @internal */
|
|
44
46
|
static getObjectLODState(object) {
|
|
45
|
-
return object
|
|
47
|
+
return object[$lodstate];
|
|
46
48
|
}
|
|
47
49
|
static addPlugin(plugin) {
|
|
48
50
|
plugins.push(plugin);
|
|
@@ -204,10 +206,10 @@ export class LODsManager {
|
|
|
204
206
|
if (!object.userData) {
|
|
205
207
|
object.userData = {};
|
|
206
208
|
}
|
|
207
|
-
let state = object
|
|
209
|
+
let state = object[$lodstate];
|
|
208
210
|
if (!state) {
|
|
209
211
|
state = new LOD_state();
|
|
210
|
-
object
|
|
212
|
+
object[$lodstate] = state;
|
|
211
213
|
}
|
|
212
214
|
// Wait a few frames before updating the LODs to make sure the object is loaded, matrices are updated, etc.
|
|
213
215
|
if (state.frames++ < 2) {
|
|
@@ -251,18 +253,17 @@ export class LODsManager {
|
|
|
251
253
|
}
|
|
252
254
|
return;
|
|
253
255
|
}
|
|
254
|
-
const LOD_material = material;
|
|
255
256
|
// Check if the material LOD was already updated to a certain level
|
|
256
257
|
// We don't use the userData here because we want to re-run assigning textures if the material has been cloned
|
|
257
258
|
let update = false;
|
|
258
|
-
if (
|
|
259
|
+
if (material[$currentLOD] == undefined) {
|
|
259
260
|
update = true;
|
|
260
261
|
}
|
|
261
|
-
else if (level <
|
|
262
|
+
else if (level < material[$currentLOD]) {
|
|
262
263
|
update = true;
|
|
263
264
|
}
|
|
264
265
|
if (update) {
|
|
265
|
-
|
|
266
|
+
material[$currentLOD] = level;
|
|
266
267
|
NEEDLE_progressive.assignTextureLOD(material, level);
|
|
267
268
|
}
|
|
268
269
|
}
|
|
@@ -275,13 +276,11 @@ export class LODsManager {
|
|
|
275
276
|
loadProgressiveMeshes(mesh, level) {
|
|
276
277
|
if (!mesh)
|
|
277
278
|
return Promise.resolve(null);
|
|
278
|
-
if (
|
|
279
|
-
mesh
|
|
280
|
-
if (mesh.userData.LOD !== level) {
|
|
281
|
-
mesh.userData.LOD = level;
|
|
279
|
+
if (mesh[$currentLOD] !== level) {
|
|
280
|
+
mesh[$currentLOD] = level;
|
|
282
281
|
const originalGeometry = mesh.geometry;
|
|
283
282
|
return NEEDLE_progressive.assignMeshLOD(mesh, level).then(res => {
|
|
284
|
-
if (res && mesh
|
|
283
|
+
if (res && mesh[$currentLOD] == level && originalGeometry != mesh.geometry) {
|
|
285
284
|
// if (this.handles) {
|
|
286
285
|
// for (const inst of this.handles) {
|
|
287
286
|
// // if (inst["LOD"] < level) continue;
|
package/lib/utils.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { BufferGeometry, Mesh } from "three";
|
|
2
|
+
const $raycastmesh = Symbol("needle:raycast-mesh");
|
|
2
3
|
/**
|
|
3
4
|
* 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
|
|
4
5
|
* @param obj the object to get the raycast mesh from
|
|
5
6
|
* @returns the raycast mesh or null if not set
|
|
6
7
|
*/
|
|
7
8
|
export function getRaycastMesh(obj) {
|
|
8
|
-
if (obj?.
|
|
9
|
-
return obj
|
|
9
|
+
if (obj?.[$raycastmesh] instanceof BufferGeometry) {
|
|
10
|
+
return obj[$raycastmesh];
|
|
10
11
|
}
|
|
11
12
|
return null;
|
|
12
13
|
}
|
|
@@ -23,9 +24,7 @@ export function setRaycastMesh(obj, geom) {
|
|
|
23
24
|
const clone = shallowCloneGeometry(geom);
|
|
24
25
|
// remove LODs userdata to not update the geometry if the raycast mesh is rendered in the scene
|
|
25
26
|
clone.userData = { isRaycastMesh: true };
|
|
26
|
-
|
|
27
|
-
obj.userData = {};
|
|
28
|
-
obj.userData["needle:raycast-mesh"] = clone;
|
|
27
|
+
obj[$raycastmesh] = clone;
|
|
29
28
|
}
|
|
30
29
|
}
|
|
31
30
|
}
|
package/package.json
CHANGED