@needle-tools/gltf-progressive 1.2.0-alpha.9 → 1.2.1-alpha.1
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 +4 -0
- package/gltf-progressive.js +408 -410
- package/gltf-progressive.min.js +4 -4
- package/gltf-progressive.umd.cjs +4 -4
- package/lib/extension.js +0 -1
- package/lib/lods_manager.js +26 -16
- 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
|
-
`,y),null));if(!
|
|
1
|
+
var ve=Object.defineProperty,Le=(t,e,r)=>e in t?ve(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,d=(t,e,r)=>(Le(t,typeof e!="symbol"?e+"":e,r),r);import{MeshoptDecoder as De}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Me}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as _e}from"three/examples/jsm/loaders/KTX2Loader.js";import{BufferGeometry as W,Mesh as G,Material as Oe,Texture as U,TextureLoader as we,Matrix4 as ce,Frustum as be,Sphere as Se,Box3 as de,Vector3 as R}from"three";import{GLTFLoader as Te}from"three/examples/jsm/loaders/GLTFLoader.js";let Y="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",re="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(Y+"draco_decoder.js",{method:"head"}).catch(t=>{Y="./include/draco/",re="./include/ktx2/"});function Ae(t){Y=t}function Ee(t){re=t}let z,se,q;function ne(t){z||(z=new Me,z.setDecoderPath(Y),z.setDecoderConfig({type:"js"})),q||(q=new _e,q.setTranscoderPath(re)),se||(se=De),t?q.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function oe(t){t.dracoLoader||t.setDRACOLoader(z),t.ktx2Loader||t.setKTX2Loader(q),t.meshoptDecoder||t.setMeshoptDecoder(se)}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 o=t.substring(0,r+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}let J;function Ie(){return J!==void 0||(J=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),Q("debugprogressive")&&console.log("isMobileDevice",J)),J}const ie=Symbol("needle:raycast-mesh");function Z(t){return t?.[ie]instanceof W?t[ie]:null}function he(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!Z(t)){const r=Ce(e);r.userData={isRaycastMesh:!0},t[ie]=r}}function Be(t=!0){if(t){if(V)return;const e=V=G.prototype.raycast;G.prototype.raycast=function(r,o){const n=this,s=Z(n);let a;s&&n.isMesh&&(a=n.geometry,n.geometry=s),e.call(this,r,o),a&&(n.geometry=a)}}else{if(!V)return;G.prototype.raycast=V,V=null}}let V=null;function Ce(t){const e=new W;for(const r in t.attributes)e.setAttribute(r,t.getAttribute(r));return e.setIndex(t.getIndex()),e}const k=new Array,I="NEEDLE_progressive",v=Q("debugprogressive"),ae=Symbol("needle-progressive-texture"),X=new Map,le=new Set;if(v){let t=function(){e+=1,console.log("Toggle LOD level",e,X),X.forEach((n,s)=>{for(const a of n.keys){const i=s[a];if(i!=null){if(i.isBufferGeometry===!0){const c=w.getMeshLODInformation(i),l=c?Math.min(e,c.lods.length):0;s["DEBUG:LOD"]=e,w.assignMeshLOD(s,l),c&&(r=Math.max(r,c.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,w.assignTextureLOD(s,e);break}}}}),e>=r&&(e=-1)},e=-1,r=2,o=!1;window.addEventListener("keyup",n=>{n.key==="p"&&t(),n.key==="w"&&(o=!o,le&&le.forEach(s=>{s.name!="BackgroundCubeMaterial"&&s.glyphMap==null&&"wireframe"in s&&(s.wireframe=o)}))})}function ge(t,e,r){var o;if(!v)return;X.has(t)||X.set(t,{keys:[],sourceId:r});const n=X.get(t);((o=n?.keys)==null?void 0:o.includes(e))==!1&&n.keys.push(e)}const _=class{constructor(t,e){d(this,"parser"),d(this,"url"),d(this,"_isLoadingMesh"),d(this,"loadMesh",r=>{var o,n;if(this._isLoadingMesh)return null;const s=(n=(o=this.parser.json.meshes[r])==null?void 0:o.extensions)==null?void 0:n[I];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 I}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,o="LODS:minmax",n=t[o];if(n!=null)return n;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[o]=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 c=a.uniforms[i].value;c?.isTexture===!0&&s(c,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const i=t[a];i?.isTexture===!0&&s(i,e)}return t[o]=e,e;function s(a,i){const c=r.getAssignedLODInformation(a);if(c){const l=r.lodInfos.get(c.key);if(l&&l.lods){i.min_count=Math.min(i.min_count,l.lods.length),i.max_count=Math.max(i.max_count,l.lods.length);for(let p=0;p<l.lods.length;p++){const u=l.lods[p];u.width&&(i.lods[p]=i.lods[p]||{min_height:1/0,max_height:0},i.lods[p].min_height=Math.min(i.lods[p].min_height,u.height),i.lods[p].max_height=Math.max(i.lods[p].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 o,n;if(t.isMesh?o=t.geometry:(t.isBufferGeometry||t.isTexture)&&(o=t),o&&(r=o?.userData)!=null&&r.LODS){const s=o.userData.LODS;if(n=this.lodInfos.get(s.key),e===void 0)return n!=null;if(n)return Array.isArray(n.lods)?e<n.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof G||t.isMesh===!0){const o=t.geometry,n=this.getAssignedLODInformation(o);if(!n)return Promise.resolve(null);for(const s of k)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,_.getOrLoadLOD(o,e).then(s=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(s)){const a=n.index||0;s=s[a]}s&&o!=s&&s instanceof W&&(t.geometry=s,v&&ge(t,"geometry",n.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",t,s),null))}else v&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof Oe||t.isMaterial===!0){const r=t,o=[],n=new Array;if(v&&le.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 c=this.assignTextureLODForSlot(i,e,r,a);o.push(c),n.push(a)}}}else for(const s of Object.keys(r)){const a=r[s];if(a?.isTexture===!0){const i=this.assignTextureLODForSlot(a,e,r,s);o.push(i),n.push(s)}}return Promise.all(o).then(s=>{const a=new Array;for(let i=0;i<s.length;i++){const c=s[i],l=n[i];c&&c.isTexture===!0?a.push({material:r,slot:l,texture:c,level:e}):a.push({material:r,slot:l,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,o){return t?.isTexture!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):_.getOrLoadLOD(t,e).then(n=>{if(Array.isArray(n))return null;if(n?.isTexture===!0){if(n!=t){if(r&&o){const s=r[o];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,n),null}r[o]=n}if(v&&o&&r){const s=this.getAssignedLODInformation(t);s&&ge(r,o,s.url)}}return n}else v=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(n=>(console.error("Error loading LOD",t,n),null))}afterRoot(t){var e,r;return v&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[I];if(s){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===n&&(a=!0,_.registerTexture(this.url,i,s.lods.length,n,s));a||this.parser.getDependency("texture",n).then(i=>{i&&_.registerTexture(this.url,i,s.lods.length,n,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[I];if(s&&s.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const i=this.parser.associations.get(a);i.meshes===n&&_.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(t,e){var r,o,n,s;const a=v=="verbose",i=t.userData.LODS;if(!i)return null;const c=i?.key;let l;if(t.isTexture===!0){const p=t;p.source&&p.source[ae]&&(l=p.source[ae])}if(l||(l=_.lodInfos.get(c)),l){if(e>0){let g=!1;const b=Array.isArray(l.lods);if(b&&e>=l.lods.length?g=!0:b||(g=!0),g)return this.lowresCache.get(c)}const p=Array.isArray(l.lods)?(r=l.lods[e])==null?void 0:r.path:l.lods;if(!p)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const u=Pe(i.url,p);if(u.endsWith(".glb")||u.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const g=u+"_"+l.guid,b=this.previouslyLoaded.get(g);if(b!==void 0){a&&console.log(`LOD ${e} was already loading/loaded: ${g}`);let m=await b.catch(E=>(console.error(`Error loading LOD ${e} from ${u}
|
|
2
|
+
`,E),null)),O=!1;if(m==null||(m instanceof U&&t instanceof U?(o=m.image)!=null&&o.data||(n=m.source)!=null&&n.data?m=this.copySettings(t,m):(O=!0,this.previouslyLoaded.delete(g)):m instanceof W&&t instanceof W&&((s=m.attributes.position)!=null&&s.array||(O=!0,this.previouslyLoaded.delete(g)))),!O)return m}const f=l,L=new Promise(async(m,O)=>{const E=new Te;oe(E),v&&(await new Promise(y=>setTimeout(y,1e3)),a&&console.warn("Start loading (delayed) "+u,f.guid));let H=u;if(f&&Array.isArray(f.lods)){const y=f.lods[e];y.hash&&(H+="?v="+y.hash)}const P=await E.loadAsync(H).catch(y=>(console.error(`Error loading LOD ${e} from ${u}
|
|
3
|
+
`,y),null));if(!P)return null;const D=P.parser;a&&console.log("Loading finished "+u,f.guid);let x=0;if(P.parser.json.textures){let y=!1;for(const h of P.parser.json.textures){if(h!=null&&h.extensions){const M=h?.extensions[I];if(M!=null&&M.guid&&M.guid===f.guid){y=!0;break}}x++}if(y){let h=await D.getDependency("texture",x);return h&&_.assignLODInformation(i.url,h,c,e,void 0,void 0),a&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',u,x,h,g),t instanceof U&&(h=this.copySettings(t,h)),h&&(h.guid=f.guid),m(h)}else v&&console.warn("Could not find texture with guid",f.guid)}if(x=0,P.parser.json.meshes){let y=!1;for(const h of P.parser.json.meshes){if(h!=null&&h.extensions){const M=h?.extensions[I];if(M!=null&&M.guid&&M.guid===f.guid){y=!0;break}}x++}if(y){const h=await D.getDependency("mesh",x),M=f;if(a&&console.log(`Loaded Mesh "${h.name}"`,u,x,h,g),h.isMesh===!0){const T=h.geometry;return _.assignLODInformation(i.url,T,c,e,void 0,M.density),m(T)}else{const T=new Array;for(let C=0;C<h.children.length;C++){const N=h.children[C];if(N instanceof G){const j=N.geometry;_.assignLODInformation(i.url,j,c,e,C,M.density),T.push(j)}}return m(T)}}}return m(null)});return this.previouslyLoaded.set(g,L),await L}else if(t instanceof U){a&&console.log("Load texture from uri: "+u);const g=await new we().loadAsync(u);return g?(g.guid=l.guid,g.flipY=!1,g.needsUpdate=!0,g.colorSpace=t.colorSpace,a&&console.log(l,g)):v&&console.warn("failed loading",u),g}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${c}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,o,n,s){if(!e)return;e.userData||(e.userData={});const a=new Re(t,r,o,n,s);e.userData.LODS=a}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),v&&console.warn(`Copying texture settings
|
|
4
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 w=_;d(w,"registerTexture",(t,e,r,o,n)=>{if(v&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,n),!e){v&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[ae]=n);const s=n.guid;_.assignLODInformation(t,e,s,r,o,void 0),_.lodInfos.set(s,n),_.lowresCache.set(s,e)}),d(w,"registerMesh",(t,e,r,o,n,s)=>{var a;v&&console.log("> Progressive: register mesh",n,r.name,s,r.uuid,r);const i=r.geometry;if(!i){v&&console.warn("gltf-progressive: Register mesh without geometry");return}i.userData||(i.userData={}),_.assignLODInformation(t,i,e,o,n,s.density),_.lodInfos.set(e,s);let c=_.lowresCache.get(e);c?c.push(r.geometry):c=[r.geometry],_.lowresCache.set(e,c),o>0&&!Z(r)&&he(r,i);for(const l of k)(a=l.onRegisteredNewMesh)==null||a.call(l,r,s)}),d(w,"lodInfos",new Map),d(w,"previouslyLoaded",new Map),d(w,"lowresCache",new Map);class Re{constructor(e,r,o,n,s){d(this,"url"),d(this,"key"),d(this,"level"),d(this,"index"),d(this,"density"),this.url=e,this.key=r,this.level=o,n!=null&&(this.index=n),s!=null&&(this.density=s)}}const F=Q("debugprogressive"),ke=Q("noprogressive"),fe=Symbol("Needle:LODSManager"),ue=Symbol("Needle:LODState"),$=Symbol("Needle:CurrentLOD"),A={mesh_lod:-1,texture_lod:-1},S=class{constructor(t){d(this,"renderer"),d(this,"projectionScreenMatrix",new ce),d(this,"cameraFrustrum",new be),d(this,"targetTriangleDensity",2e5),d(this,"updateInterval",0),d(this,"pause",!1),d(this,"_frame",0),d(this,"_originalRender"),d(this,"_sphere",new Se),d(this,"_tempBox",new de),d(this,"_tempBox2",new de),d(this,"tempMatrix",new ce),d(this,"_tempWorldPosition",new R),d(this,"_tempBoxSize",new R),d(this,"_tempBox2Size",new R),this.renderer=t}static getObjectLODState(t){return t[ue]}static addPlugin(t){k.push(t)}static removePlugin(t){const e=k.indexOf(t);e>=0&&k.splice(e,1)}static get(t){return t[fe]?t[fe]:new S(t)}get plugins(){return k}enable(){if(this._originalRender)return;let t=0;this._originalRender=this.renderer.render;const e=this;ne(this.renderer),this.renderer.render=function(r,o){e.renderer.getRenderTarget()==null&&(t=0,e._frame+=1);const n=e._frame,s=t++;e.onBeforeRender(r,o,s,n),e._originalRender.call(this,r,o),e.onAfterRender(r,o,s,n)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,o){}onAfterRender(t,e,r,o){var n,s;if(this.pause)return;const a=this.renderer.renderLists.get(t,0),i=a.opaque;let c=!0;if(i.length===1){const l=i[0].material;(l.name==="EffectMaterial"||l.name==="CopyShader")&&(c=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(c=!1),c){if(ke||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const l=this.targetTriangleDensity;for(const 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")){F&&(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 g=u.object;(g instanceof G||g.isMesh)&&this.updateLODs(t,e,g,l,o)}const p=a.transparent;for(const u of p){const g=u.object;(g instanceof G||g.isMesh)&&this.updateLODs(t,e,g,l,o)}}}updateLODs(t,e,r,o,n){var s,a;r.userData||(r.userData={});let i=r[ue];if(i||(i=new je,r[ue]=i),i.frames++<2)return;for(const l of k)(s=l.onBeforeUpdateLOD)==null||s.call(l,this.renderer,t,e,r);this.calculateLodLevel(e,r,i,o,A),A.mesh_lod=Math.round(A.mesh_lod),A.texture_lod=Math.round(A.texture_lod),A.mesh_lod>=0&&this.loadProgressiveMeshes(r,A.mesh_lod);let c=A.texture_lod;if(r.material&&c>=0){const l=r["DEBUG:LOD"];l!=null&&(c=l),this.loadProgressiveTextures(r.material,c)}for(const l of k)(a=l.onAfterUpdatedLOD)==null||a.call(l,this.renderer,t,e,r,A);i.lastLodLevel_Mesh=A.mesh_lod,i.lastLodLevel_Texture=A.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}let r=!1;(t[$]===void 0||e<t[$])&&(r=!0),r&&(t[$]=e,w.assignTextureLOD(t,e))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[$]!==e){t[$]=e;const r=t.geometry;return w.assignMeshLOD(t,e).then(o=>(o&&t[$]==e&&r!=t.geometry,o))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,o=t.max,n=(r.x+o.x)*.5,s=(r.y+o.y)*.5;return this._tempPtInside.set(n,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,o,n){var s;if(!e){n.mesh_lod=-1,n.texture_lod=-1;return}if(!t){n.mesh_lod=-1,n.texture_lod=-1;return}let a=10+1,i=!1;if(F&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const c=w.getMeshLODInformation(e.geometry),l=c?.lods,p=l&&l.length>0,u=w.getMaterialMinMaxLODsCount(e.material),g=u?.min_count!=1/0&&u.min_count>0&&u.max_count>0;if(!p&&!g){n.mesh_lod=0,n.texture_lod=0;return}if(p||(i=!0,a=0),!((s=this.cameraFrustrum)!=null&&s.intersectsObject(e))){n.mesh_lod=99,n.texture_lod=99;return}let b=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const f=e;f.boundingBox||f.computeBoundingBox(),b=f.boundingBox}if(b&&t.isPerspectiveCamera){const f=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 D=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(D)){n.mesh_lod=0,n.texture_lod=0;return}}if(this._tempBox.copy(b),e.type==="SkinnedMesh"?e.parent&&this._tempBox.applyMatrix4(e.parent.matrixWorld):this._tempBox.applyMatrix4(e.matrixWorld),S.isInside(this._tempBox,this.projectionScreenMatrix)){n.mesh_lod=0,n.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&f.fov>70){const D=this._tempBox.min,x=this._tempBox.max;let y=D.x,h=D.y,M=x.x,T=x.y;const C=2,N=1.5,j=(D.x+x.x)*.5,K=(D.y+x.y)*.5;y=(y-j)*C+j,h=(h-K)*C+K,M=(M-j)*C+j,T=(T-K)*C+K;const xe=y<0&&M>0?0:Math.min(Math.abs(D.x),Math.abs(x.x)),ye=h<0&&T>0?0:Math.min(Math.abs(D.y),Math.abs(x.y)),te=Math.max(xe,ye);r.lastCentrality=(N-te)*(N-te)*(N-te)}else r.lastCentrality=1;const L=this._tempBox.getSize(this._tempBoxSize);L.multiplyScalar(.5),screen.availHeight>0&&L.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),L.x*=f.aspect;const m=t.matrixWorldInverse,O=this._tempBox2;O.copy(b),O.applyMatrix4(e.matrixWorld),O.applyMatrix4(m);const E=O.getSize(this._tempBox2Size),H=Math.max(E.x,E.y);if(Math.max(L.x,L.y)!=0&&H!=0&&(L.z=E.z/Math.max(E.x,E.y)*Math.max(L.x,L.y)),r.lastScreenCoverage=Math.max(L.x,L.y,L.z),r.lastScreenspaceVolume.copy(L),r.lastScreenCoverage*=r.lastCentrality,F&&S.debugDrawLine){const D=this.tempMatrix.copy(this.projectionScreenMatrix);D.invert();const x=S.corner0,y=S.corner1,h=S.corner2,M=S.corner3;x.copy(this._tempBox.min),y.copy(this._tempBox.max),y.x=x.x,h.copy(this._tempBox.max),h.y=x.y,M.copy(this._tempBox.max);const T=(x.z+M.z)*.5;x.z=y.z=h.z=M.z=T,x.applyMatrix4(D),y.applyMatrix4(D),h.applyMatrix4(D),M.applyMatrix4(D),S.debugDrawLine(x,y,255),S.debugDrawLine(x,h,255),S.debugDrawLine(y,M,255),S.debugDrawLine(h,M,255)}let P=999;if(l&&r.lastScreenCoverage>0){for(let D=0;D<l.length;D++)if(l[D].density/r.lastScreenCoverage<o){P=D;break}}P<a&&(a=P,i=!0)}if(i?n.mesh_lod=a:n.mesh_lod=r.lastLodLevel_Mesh,g)if(r.lastLodLevel_Texture<0){if(n.texture_lod=u.max_count-1,F){const f=u.lods[u.max_count-1];F&&console.log(`First Texture LOD ${n.texture_lod} (${f.max_height}px) - ${e.name}`)}}else{const f=r.lastScreenCoverage*1.5,L=this.renderer.domElement.clientHeight/window.devicePixelRatio*f;for(let m=u.lods.length-1;m>=0;m--){const O=u.lods[m];if(!(Ie()&&O.max_height>4096)&&O.max_height>L){n.texture_lod=m,n.texture_lod<r.lastLodLevel_Texture&&F&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} \u2192 ${n.texture_lod} (${O.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${L.toFixed(0)}px) - ${e.name}`);break}}}else n.texture_lod=0}};let B=S;d(B,"debugDrawLine"),d(B,"corner0",new R),d(B,"corner1",new R),d(B,"corner2",new R),d(B,"corner3",new R),d(B,"_tempPtInside",new R);class je{constructor(){d(this,"frames",0),d(this,"lastLodLevel_Mesh",-1),d(this,"lastLodLevel_Texture",-1),d(this,"lastScreenCoverage",0),d(this,"lastScreenspaceVolume",new R),d(this,"lastCentrality",0)}}const me=Symbol("NEEDLE_mesh_lod"),ee=Symbol("NEEDLE_texture_lod");function pe(t){if(!t)return null;let e=null,r=null;for(let o=t;o!=null;o=Object.getPrototypeOf(o)){const n=Object.getOwnPropertySymbols(o),s=n.find(i=>i.toString()=="Symbol(renderer)"),a=n.find(i=>i.toString()=="Symbol(scene)");!e&&s!=null&&(e=t[s].threeRenderer),!r&&a!=null&&(r=t[a])}if(e){console.log("Adding Needle LODs to modelviewer");const o=B.get(e);if(B.addPlugin(new Ge(t)),o.enable(),r){const n=r.camera||r.traverse(s=>s.type=="PerspectiveCamera")[0];n&&e.render(r,n)}return()=>{o.disable()}}return null}class Ge{constructor(e){d(this,"modelviewer"),d(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,r,o,n){this.tryParseMeshLOD(r,n),this.tryParseTextureLOD(r,n)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,r){if(r[ee]==!0)return;r[ee]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&r.material){let s=function(i){var c,l,p;if(i[ee]==!0)return;i[ee]=!0,i.userData&&(i.userData.LOD=-1);const u=Object.keys(i);for(let g=0;g<u.length;g++){const b=u[g],f=i[b];if(f?.isTexture===!0){const L=(l=(c=f.userData)==null?void 0:c.associations)==null?void 0:l.textures,m=o.parser.json.textures[L];if(!m){console.warn("Texture data not found for texture index "+L);continue}if((p=m?.extensions)!=null&&p[I]){const O=m.extensions[I];O&&n&&w.registerTexture(n,f,O.lods.length,L,O)}}}};const a=r.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,r){var o,n;if(r[me]==!0)return;r[me]=!0;const s=this.getUrl();if(!s)return;const a=(n=(o=r.userData)==null?void 0:o.gltfExtensions)==null?void 0:n[I];if(a&&s){const i=r.uuid;w.registerMesh(s,i,r,0,a.lods.length,a)}}}function Ne(t,e,r,o){ne(e),oe(r),r.register(s=>new w(s,t));const n=B.get(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{pe(document.querySelector("model-viewer"))});export{I as EXTENSION_NAME,B as LODsManager,w as NEEDLE_progressive,oe as addDracoAndKTX2Loaders,ne as createLoaders,Z as getRaycastMesh,pe as patchModelViewer,Ae as setDracoDecoderLocation,Ee as setKTX2TranscoderLocation,he as setRaycastMesh,Ne as useNeedleProgressive,Be as useRaycastMeshes};
|
package/gltf-progressive.umd.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`,
|
|
3
|
-
`,
|
|
1
|
+
"use strict";var me=Object.defineProperty;var Le=(l,e,t)=>e in l?me(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var f=(l,e,t)=>(Le(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Me=require("three/examples/jsm/libs/meshopt_decoder.module.js"),De=require("three/examples/jsm/loaders/DRACOLoader.js"),we=require("three/examples/jsm/loaders/KTX2Loader.js"),g=require("three"),_e=require("three/examples/jsm/loaders/GLTFLoader.js");let Z="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",le="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(Z+"draco_decoder.js",{method:"head"}).catch(l=>{Z="./include/draco/",le="./include/ktx2/"});function Oe(l){Z=l}function ve(l){le=l}let q,oe,K;function ce(l){q||(q=new De.DRACOLoader,q.setDecoderPath(Z),q.setDecoderConfig({type:"js"})),K||(K=new we.KTX2Loader,K.setTranscoderPath(le)),oe||(oe=Me.MeshoptDecoder),l?K.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ue(l){l.dracoLoader||l.setDRACOLoader(q),l.ktx2Loader||l.setKTX2Loader(K),l.meshoptDecoder||l.setMeshoptDecoder(oe)}function j(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function Se(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 W;function Te(){return W!==void 0||(W=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),j("debugprogressive")&&console.log("isMobileDevice",W)),W}const ne=Symbol("needle:raycast-mesh");function ee(l){return(l==null?void 0:l[ne])instanceof g.BufferGeometry?l[ne]:null}function ge(l,e){if((l.type==="Mesh"||l.type==="SkinnedMesh")&&!ee(l)){const r=Ae(e);r.userData={isRaycastMesh:!0},l[ne]=r}}function be(l=!0){if(l){if(V)return;const e=V=g.Mesh.prototype.raycast;g.Mesh.prototype.raycast=function(t,r){const i=this,o=ee(i);let s;o&&i.isMesh&&(s=i.geometry,i.geometry=o),e.call(this,t,r),s&&(i.geometry=s)}}else{if(!V)return;g.Mesh.prototype.raycast=V,V=null}}let V=null;function Ae(l){const e=new g.BufferGeometry;for(const t in l.attributes)e.setAttribute(t,l.getAttribute(t));return e.setIndex(l.getIndex()),e}const G=new Array,E="NEEDLE_progressive",M=j("debugprogressive"),se=Symbol("needle-progressive-texture"),X=new Map,ae=new Set;if(M){let l=function(){e+=1,console.log("Toggle LOD level",e,X),X.forEach((i,o)=>{for(const s of i.keys){const n=o[s];if(n!=null){if(n.isBufferGeometry===!0){const a=S.getMeshLODInformation(n),h=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,S.assignMeshLOD(o,h),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,S.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,ae&&ae.forEach(o=>{o.name!="BackgroundCubeMaterial"&&o.glyphMap==null&&"wireframe"in o&&(o.wireframe=r)}))})}function fe(l,e,t){var i;if(!M)return;X.has(l)||X.set(l,{keys:[],sourceId:t});const r=X.get(l);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const _=class{constructor(e,t){f(this,"parser");f(this,"url");f(this,"_isLoadingMesh");f(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[E];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(o=>(this._isLoadingMesh=!1,o&&_.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 E}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 h=n.uniforms[a].value;(h==null?void 0:h.isTexture)===!0&&s(h,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 h=r.getAssignedLODInformation(n);if(h){const d=r.lodInfos.get(h.key);if(d&&d.lods){a.min_count=Math.min(a.min_count,d.lods.length),a.max_count=Math.max(a.max_count,d.lods.length);for(let x=0;x<d.lods.length;x++){const c=d.lods[x];c.width&&(a.lods[x]=a.lods[x]||{min_height:1/0,max_height:0},a.lods[x].min_height=Math.min(a.lods[x].min_height,c.height),a.lods[x].max_height=Math.max(a.lods[x].max_height,c.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 g.Mesh||e.isMesh===!0){const i=e.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of G)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,_.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 g.BufferGeometry&&(e.geometry=s,M&&fe(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 g.Material||e.isMaterial===!0){const r=e,i=[],o=new Array;if(M&&ae.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const n of Object.keys(s.uniforms)){const a=s.uniforms[n].value;if((a==null?void 0:a.isTexture)===!0){const h=this.assignTextureLODForSlot(a,t,r,n);i.push(h),o.push(n)}}}else for(const s of Object.keys(r)){const n=r[s];if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,t,r,s);i.push(a),o.push(s)}}return Promise.all(i).then(s=>{const n=new Array;for(let a=0;a<s.length;a++){const h=s[a],d=o[a];h&&h.isTexture===!0?n.push({material:r,slot:d,texture:h,level:t}):n.push({material:r,slot:d,texture:null,level:t})}return n})}if(e instanceof g.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,i){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):i==="glyphMap"?Promise.resolve(e):_.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&&fe(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[E];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,_.registerTexture(this.url,a,s.lods.length,o,s));n||this.parser.getDependency("texture",o).then(a=>{a&&_.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[E];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&&_.registerMesh(this.url,s.guid,n,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var n,a,h,d;const r=M=="verbose",i=e.userData.LODS;if(!i)return null;const o=i==null?void 0:i.key;let s;if(e.isTexture===!0){const x=e;x.source&&x.source[se]&&(s=x.source[se])}if(s||(s=_.lodInfos.get(o)),s){if(t>0){let y=!1;const m=Array.isArray(s.lods);if(m&&t>=s.lods.length?y=!0:m||(y=!0),y)return this.lowresCache.get(o)}const x=Array.isArray(s.lods)?(n=s.lods[t])==null?void 0:n.path:s.lods;if(!x)return M&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const c=Se(i.url,x);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const y=c+"_"+s.guid,m=this.previouslyLoaded.get(y);if(m!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${y}`);let w=await m.catch(P=>(console.error(`Error loading LOD ${t} from ${c}
|
|
2
|
+
`,P),null)),A=!1;if(w==null||(w instanceof g.Texture&&e instanceof g.Texture?(a=w.image)!=null&&a.data||(h=w.source)!=null&&h.data?w=this.copySettings(e,w):(A=!0,this.previouslyLoaded.delete(y)):w instanceof g.BufferGeometry&&e instanceof g.BufferGeometry&&((d=w.attributes.position)!=null&&d.array||(A=!0,this.previouslyLoaded.delete(y)))),!A)return w}const O=s,D=new Promise(async(w,A)=>{const P=new _e.GLTFLoader;ue(P),M&&(await new Promise(p=>setTimeout(p,1e3)),r&&console.warn("Start loading (delayed) "+c,O.guid));let Y=c;if(O&&Array.isArray(O.lods)){const p=O.lods[t];p.hash&&(Y+="?v="+p.hash)}const F=await P.loadAsync(Y).catch(p=>(console.error(`Error loading LOD ${t} from ${c}
|
|
3
|
+
`,p),null));if(!F)return null;const N=F.parser;r&&console.log("Loading finished "+c,O.guid);let k=0;if(F.parser.json.textures){let p=!1;for(const u of F.parser.json.textures){if(u!=null&&u.extensions){const L=u==null?void 0:u.extensions[E];if(L!=null&&L.guid&&L.guid===O.guid){p=!0;break}}k++}if(p){let u=await N.getDependency("texture",k);return u&&_.assignLODInformation(i.url,u,o,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+u.name+'"',c,k,u,y),e instanceof g.Texture&&(u=this.copySettings(e,u)),u&&(u.guid=O.guid),w(u)}else M&&console.warn("Could not find texture with guid",O.guid)}if(k=0,F.parser.json.meshes){let p=!1;for(const u of F.parser.json.meshes){if(u!=null&&u.extensions){const L=u==null?void 0:u.extensions[E];if(L!=null&&L.guid&&L.guid===O.guid){p=!0;break}}k++}if(p){const u=await N.getDependency("mesh",k),L=O;if(r&&console.log(`Loaded Mesh "${u.name}"`,c,k,u,y),u.isMesh===!0){const T=u.geometry;return _.assignLODInformation(i.url,T,o,t,void 0,L.density),w(T)}else{const T=new Array;for(let b=0;b<u.children.length;b++){const I=u.children[b];if(I instanceof g.Mesh){const $=I.geometry;_.assignLODInformation(i.url,$,o,t,b,L.density),T.push($)}}return w(T)}}}return w(null)});return this.previouslyLoaded.set(y,D),await D}else if(e instanceof g.Texture){r&&console.log("Load texture from uri: "+c);const m=await new g.TextureLoader().loadAsync(c);return m?(m.guid=s.guid,m.flipY=!1,m.needsUpdate=!0,m.colorSpace=e.colorSpace,r&&console.log(s,m)):M&&console.warn("failed loading",c),m}}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 Pe(e,r,i,o,s);t.userData.LODS=n}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){return t=t.clone(),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 S=_;f(S,"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[se]=o);const s=o.guid;_.assignLODInformation(e,t,s,r,i,void 0),_.lodInfos.set(s,o),_.lowresCache.set(s,t)}),f(S,"registerMesh",(e,t,r,i,o,s)=>{var h;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={}),_.assignLODInformation(e,n,t,i,o,s.density),_.lodInfos.set(t,s);let a=_.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],_.lowresCache.set(t,a),i>0&&!ee(r)&&ge(r,n);for(const d of G)(h=d.onRegisteredNewMesh)==null||h.call(d,r,s)}),f(S,"lodInfos",new Map),f(S,"previouslyLoaded",new Map),f(S,"lowresCache",new Map);class Pe{constructor(e,t,r,i,o){f(this,"url");f(this,"key");f(this,"level");f(this,"index");f(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"),Be=j("noprogressive"),de=Symbol("Needle:LODSManager"),ie=Symbol("Needle:LODState"),U=Symbol("Needle:CurrentLOD"),R={mesh_lod:-1,texture_lod:-1},B=class{constructor(e){f(this,"renderer");f(this,"projectionScreenMatrix",new g.Matrix4);f(this,"cameraFrustrum",new g.Frustum);f(this,"targetTriangleDensity",2e5);f(this,"updateInterval",0);f(this,"pause",!1);f(this,"_frame",0);f(this,"_originalRender");f(this,"_sphere",new g.Sphere);f(this,"_tempBox",new g.Box3);f(this,"_tempBox2",new g.Box3);f(this,"tempMatrix",new g.Matrix4);f(this,"_tempWorldPosition",new g.Vector3);f(this,"_tempBoxSize",new g.Vector3);f(this,"_tempBox2Size",new g.Vector3);this.renderer=e}static getObjectLODState(e){return e[ie]}static addPlugin(e){G.push(e)}static removePlugin(e){const t=G.indexOf(e);t>=0&&G.splice(t,1)}static get(e){return e[de]?e[de]:new B(e)}get plugins(){return G}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;ce(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"||r>=1&&t.type==="OrthographicCamera")&&(n=!1),n){if(Be||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 c of s){if(c.material&&(((a=c.geometry)==null?void 0:a.type)==="BoxGeometry"||((h=c.geometry)==null?void 0:h.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){z&&(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}switch(c.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const y=c.object;(y instanceof g.Mesh||y.isMesh)&&this.updateLODs(e,t,y,d,i)}const x=o.transparent;for(const c of x){const y=c.object;(y instanceof g.Mesh||y.isMesh)&&this.updateLODs(e,t,y,d,i)}}}updateLODs(e,t,r,i,o){var a,h;r.userData||(r.userData={});let s=r[ie];if(s||(s=new Ce,r[ie]=s),s.frames++<2)return;for(const d of G)(a=d.onBeforeUpdateLOD)==null||a.call(d,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 d=r["DEBUG:LOD"];d!=null&&(n=d),this.loadProgressiveTextures(r.material,n)}for(const d of G)(h=d.onAfterUpdatedLOD)==null||h.call(d,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[U]===void 0||t<e[U])&&(r=!0),r&&(e[U]=t,S.assignTextureLOD(e,t))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e[U]!==t){e[U]=t;const r=e.geometry;return S.assignMeshLOD(e,t).then(i=>(i&&e[U]==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,a=!1;if(z&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const h=S.getMeshLODInformation(t.geometry),d=h==null?void 0:h.lods,x=d&&d.length>0,c=S.getMaterialMinMaxLODsCount(t.material),y=(c==null?void 0:c.min_count)!=1/0&&c.min_count>0&&c.max_count>0;if(!x&&!y){o.mesh_lod=0,o.texture_lod=0;return}if(x||(a=!0,n=0),!((O=this.cameraFrustrum)!=null&&O.intersectsObject(t))){o.mesh_lod=99,o.texture_lod=99;return}let m=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const D=t;D.boundingBox||D.computeBoundingBox(),m=D.boundingBox}if(m&&e.isPerspectiveCamera){const D=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const p=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(p)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(m),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&&D.fov>70){const p=this._tempBox.min,u=this._tempBox.max;let L=p.x,T=p.y,b=u.x,I=u.y;const $=2,te=1.5,H=(p.x+u.x)*.5,J=(p.y+u.y)*.5;L=(L-H)*$+H,T=(T-J)*$+J,b=(b-H)*$+H,I=(I-J)*$+J;const ye=L<0&&b>0?0:Math.min(Math.abs(p.x),Math.abs(u.x)),xe=T<0&&I>0?0:Math.min(Math.abs(p.y),Math.abs(u.y)),re=Math.max(ye,xe);r.lastCentrality=(te-re)*(te-re)*(te-re)}else r.lastCentrality=1;const v=this._tempBox.getSize(this._tempBoxSize);v.multiplyScalar(.5),screen.availHeight>0&&v.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),v.x*=D.aspect;const w=e.matrixWorldInverse,A=this._tempBox2;A.copy(m),A.applyMatrix4(t.matrixWorld),A.applyMatrix4(w);const P=A.getSize(this._tempBox2Size),Y=Math.max(P.x,P.y);if(Math.max(v.x,v.y)!=0&&Y!=0&&(v.z=P.z/Math.max(P.x,P.y)*Math.max(v.x,v.y)),r.lastScreenCoverage=Math.max(v.x,v.y,v.z),r.lastScreenspaceVolume.copy(v),r.lastScreenCoverage*=r.lastCentrality,z&&B.debugDrawLine){const p=this.tempMatrix.copy(this.projectionScreenMatrix);p.invert();const u=B.corner0,L=B.corner1,T=B.corner2,b=B.corner3;u.copy(this._tempBox.min),L.copy(this._tempBox.max),L.x=u.x,T.copy(this._tempBox.max),T.y=u.y,b.copy(this._tempBox.max);const I=(u.z+b.z)*.5;u.z=L.z=T.z=b.z=I,u.applyMatrix4(p),L.applyMatrix4(p),T.applyMatrix4(p),b.applyMatrix4(p),B.debugDrawLine(u,L,255),B.debugDrawLine(u,T,255),B.debugDrawLine(L,b,255),B.debugDrawLine(T,b,255)}let N=999;if(d&&r.lastScreenCoverage>0){for(let p=0;p<d.length;p++)if(d[p].density/r.lastScreenCoverage<i){N=p;break}}N<n&&(n=N,a=!0)}if(a?o.mesh_lod=n:o.mesh_lod=r.lastLodLevel_Mesh,y)if(r.lastLodLevel_Texture<0){if(o.texture_lod=c.max_count-1,z){const D=c.lods[c.max_count-1];z&&console.log(`First Texture LOD ${o.texture_lod} (${D.max_height}px) - ${t.name}`)}}else{const D=r.lastScreenCoverage*1.5,w=this.renderer.domElement.clientHeight/window.devicePixelRatio*D;for(let A=c.lods.length-1;A>=0;A--){const P=c.lods[A];if(!(Te()&&P.max_height>4096)&&P.max_height>w){o.texture_lod=A,o.texture_lod<r.lastLodLevel_Texture&&z&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} → ${o.texture_lod} (${P.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${w.toFixed(0)}px) - ${t.name}`);break}}}else o.texture_lod=0}};let C=B;f(C,"debugDrawLine"),f(C,"corner0",new g.Vector3),f(C,"corner1",new g.Vector3),f(C,"corner2",new g.Vector3),f(C,"corner3",new g.Vector3),f(C,"_tempPtInside",new g.Vector3);class Ce{constructor(){f(this,"frames",0);f(this,"lastLodLevel_Mesh",-1);f(this,"lastLodLevel_Texture",-1);f(this,"lastScreenCoverage",0);f(this,"lastScreenspaceVolume",new g.Vector3);f(this,"lastCentrality",0)}}const he=Symbol("NEEDLE_mesh_lod"),Q=Symbol("NEEDLE_texture_lod");function pe(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 Re(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 Re{constructor(e){f(this,"modelviewer");f(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[Q]==!0)return;t[Q]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let o=function(n){var h,d,x;if(n[Q]==!0)return;n[Q]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let c=0;c<a.length;c++){const y=a[c],m=n[y];if((m==null?void 0:m.isTexture)===!0){const O=(d=(h=m.userData)==null?void 0:h.associations)==null?void 0:d.textures,D=r.parser.json.textures[O];if(!D){console.warn("Texture data not found for texture index "+O);continue}if((x=D==null?void 0:D.extensions)!=null&&x[E]){const v=D.extensions[E];v&&i&&S.registerTexture(i,m,v.lods.length,O,v)}}}};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[he]==!0)return;t[he]=!0;const r=this.getUrl();if(!r)return;const i=(s=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:s[E];if(i&&r){const n=t.uuid;S.registerMesh(r,n,t,0,i.lods.length,i)}}}function Ee(l,e,t,r){ce(e),ue(t),t.register(o=>new S(o,l));const i=C.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{pe(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=E;exports.LODsManager=C;exports.NEEDLE_progressive=S;exports.addDracoAndKTX2Loaders=ue;exports.createLoaders=ce;exports.getRaycastMesh=ee;exports.patchModelViewer=pe;exports.setDracoDecoderLocation=Oe;exports.setKTX2TranscoderLocation=ve;exports.setRaycastMesh=ge;exports.useNeedleProgressive=Ee;exports.useRaycastMeshes=be;
|
package/lib/extension.js
CHANGED
|
@@ -763,7 +763,6 @@ export class NEEDLE_progressive {
|
|
|
763
763
|
res.userData = {};
|
|
764
764
|
const info = new LODInformation(url, key, level, index, density);
|
|
765
765
|
res.userData.LODS = info;
|
|
766
|
-
res.userData.LOD = level;
|
|
767
766
|
}
|
|
768
767
|
static getAssignedLODInformation(res) {
|
|
769
768
|
return res?.userData?.LODS || null;
|
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);
|
|
@@ -145,6 +147,12 @@ export class LODsManager {
|
|
|
145
147
|
if (camera.parent && camera.parent.type === "CubeCamera") {
|
|
146
148
|
updateLODs = false;
|
|
147
149
|
}
|
|
150
|
+
else if (_stack >= 1) {
|
|
151
|
+
// don't update LODs if we're e.g. rendering a shadow map
|
|
152
|
+
if (camera.type === "OrthographicCamera") {
|
|
153
|
+
updateLODs = false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
148
156
|
if (updateLODs) {
|
|
149
157
|
if (suppressProgressiveLoading)
|
|
150
158
|
return;
|
|
@@ -204,10 +212,10 @@ export class LODsManager {
|
|
|
204
212
|
if (!object.userData) {
|
|
205
213
|
object.userData = {};
|
|
206
214
|
}
|
|
207
|
-
let state = object
|
|
215
|
+
let state = object[$lodstate];
|
|
208
216
|
if (!state) {
|
|
209
217
|
state = new LOD_state();
|
|
210
|
-
object
|
|
218
|
+
object[$lodstate] = state;
|
|
211
219
|
}
|
|
212
220
|
// Wait a few frames before updating the LODs to make sure the object is loaded, matrices are updated, etc.
|
|
213
221
|
if (state.frames++ < 2) {
|
|
@@ -251,18 +259,17 @@ export class LODsManager {
|
|
|
251
259
|
}
|
|
252
260
|
return;
|
|
253
261
|
}
|
|
254
|
-
const LOD_material = material;
|
|
255
262
|
// Check if the material LOD was already updated to a certain level
|
|
256
263
|
// We don't use the userData here because we want to re-run assigning textures if the material has been cloned
|
|
257
264
|
let update = false;
|
|
258
|
-
if (
|
|
265
|
+
if (material[$currentLOD] === undefined) {
|
|
259
266
|
update = true;
|
|
260
267
|
}
|
|
261
|
-
else if (level <
|
|
268
|
+
else if (level < material[$currentLOD]) {
|
|
262
269
|
update = true;
|
|
263
270
|
}
|
|
264
271
|
if (update) {
|
|
265
|
-
|
|
272
|
+
material[$currentLOD] = level;
|
|
266
273
|
NEEDLE_progressive.assignTextureLOD(material, level);
|
|
267
274
|
}
|
|
268
275
|
}
|
|
@@ -275,13 +282,11 @@ export class LODsManager {
|
|
|
275
282
|
loadProgressiveMeshes(mesh, level) {
|
|
276
283
|
if (!mesh)
|
|
277
284
|
return Promise.resolve(null);
|
|
278
|
-
if (
|
|
279
|
-
mesh
|
|
280
|
-
if (mesh.userData.LOD !== level) {
|
|
281
|
-
mesh.userData.LOD = level;
|
|
285
|
+
if (mesh[$currentLOD] !== level) {
|
|
286
|
+
mesh[$currentLOD] = level;
|
|
282
287
|
const originalGeometry = mesh.geometry;
|
|
283
288
|
return NEEDLE_progressive.assignMeshLOD(mesh, level).then(res => {
|
|
284
|
-
if (res && mesh
|
|
289
|
+
if (res && mesh[$currentLOD] == level && originalGeometry != mesh.geometry) {
|
|
285
290
|
// if (this.handles) {
|
|
286
291
|
// for (const inst of this.handles) {
|
|
287
292
|
// // if (inst["LOD"] < level) continue;
|
|
@@ -333,6 +338,7 @@ export class LODsManager {
|
|
|
333
338
|
/** highest LOD level we'd ever expect to be generated */
|
|
334
339
|
const maxLevel = 10;
|
|
335
340
|
let mesh_level = maxLevel + 1;
|
|
341
|
+
let mesh_level_calculated = false;
|
|
336
342
|
if (debugProgressiveLoading && mesh["DEBUG:LOD"] != undefined) {
|
|
337
343
|
return mesh["DEBUG:LOD"];
|
|
338
344
|
}
|
|
@@ -349,6 +355,7 @@ export class LODsManager {
|
|
|
349
355
|
return;
|
|
350
356
|
}
|
|
351
357
|
if (!has_mesh_lods) {
|
|
358
|
+
mesh_level_calculated = true;
|
|
352
359
|
mesh_level = 0;
|
|
353
360
|
}
|
|
354
361
|
if (!this.cameraFrustrum?.intersectsObject(mesh)) {
|
|
@@ -492,9 +499,15 @@ export class LODsManager {
|
|
|
492
499
|
const isLowerLod = expectedLevel < mesh_level;
|
|
493
500
|
if (isLowerLod) {
|
|
494
501
|
mesh_level = expectedLevel;
|
|
502
|
+
mesh_level_calculated = true;
|
|
495
503
|
}
|
|
496
504
|
}
|
|
497
|
-
|
|
505
|
+
if (mesh_level_calculated) {
|
|
506
|
+
result.mesh_lod = mesh_level;
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
result.mesh_lod = state.lastLodLevel_Mesh;
|
|
510
|
+
}
|
|
498
511
|
if (has_texture_lods) {
|
|
499
512
|
// If this is the first time a texture LOD is requested we want to get the highest LOD to not display the minimal resolution that the root glTF contains as long while we wait for loading of e.g. the 8k LOD 0 texture
|
|
500
513
|
if (state.lastLodLevel_Texture < 0) {
|
|
@@ -531,9 +544,6 @@ export class LODsManager {
|
|
|
531
544
|
}
|
|
532
545
|
}
|
|
533
546
|
}
|
|
534
|
-
function lerp(a, b, t) {
|
|
535
|
-
return a + (b - a) * t;
|
|
536
|
-
}
|
|
537
547
|
class LOD_state {
|
|
538
548
|
frames = 0;
|
|
539
549
|
lastLodLevel_Mesh = -1;
|
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