@needle-tools/gltf-progressive 1.2.1-alpha → 1.2.1-alpha.2
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 +6 -0
- package/gltf-progressive.js +432 -423
- package/gltf-progressive.min.js +4 -4
- package/gltf-progressive.umd.cjs +4 -4
- package/lib/extension.js +17 -10
- package/lib/index.d.ts +3 -3
- package/lib/index.js +8 -8
- package/lib/lods_manager.js +26 -6
- package/lib/plugins/modelviewer.js +0 -7
- package/package.json +1 -1
package/gltf-progressive.min.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
var
|
|
2
|
-
`,
|
|
3
|
-
`,
|
|
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{BufferGeometry as K,Mesh as $,Material as Me,Texture as W,TextureLoader as De,Matrix4 as ce,Frustum as _e,Sphere as we,Box3 as de,Vector3 as R}from"three";import{GLTFLoader as Oe}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as be}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Se}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Te}from"three/examples/jsm/loaders/KTX2Loader.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 U,se,z;function ne(t){U||(U=new Se,U.setDecoderPath(Y),U.setDecoderConfig({type:"js"})),z||(z=new Te,z.setTranscoderPath(re)),se||(se=be),t?z.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function oe(t){t.dracoLoader||t.setDRACOLoader(U),t.ktx2Loader||t.setKTX2Loader(z),t.meshoptDecoder||t.setMeshoptDecoder(se)}function J(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 Q;function Ie(){return Q!==void 0||(Q=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),J("debugprogressive")&&console.log("isMobileDevice",Q)),Q}const ie=Symbol("needle:raycast-mesh");function Z(t){return t?.[ie]instanceof K?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(q)return;const e=q=$.prototype.raycast;$.prototype.raycast=function(r,o){const s=this,n=Z(s);let i;n&&s.isMesh&&(i=s.geometry,s.geometry=n),e.call(this,r,o),i&&(s.geometry=i)}}else{if(!q)return;$.prototype.raycast=q,q=null}}let q=null;function Ce(t){const e=new K;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",p=J("debugprogressive"),ae=Symbol("needle-progressive-texture"),V=new Map,le=new Set;if(p){let t=function(){e+=1,console.log("Toggle LOD level",e,V),V.forEach((s,n)=>{for(const i of s.keys){const a=n[i];if(a!=null){if(a.isBufferGeometry===!0){const u=O.getMeshLODInformation(a),l=u?Math.min(e,u.lods.length):0;n["DEBUG:LOD"]=e,O.assignMeshLOD(n,l),u&&(r=Math.max(r,u.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,O.assignTextureLOD(n,e);break}}}}),e>=r&&(e=-1)},e=-1,r=2,o=!1;window.addEventListener("keyup",s=>{s.key==="p"&&t(),s.key==="w"&&(o=!o,le&&le.forEach(n=>{n.name!="BackgroundCubeMaterial"&&n.glyphMap==null&&"wireframe"in n&&(n.wireframe=o)}))})}function fe(t,e,r){var o;if(!p)return;V.has(t)||V.set(t,{keys:[],sourceId:r});const s=V.get(t);((o=s?.keys)==null?void 0:o.includes(e))==!1&&s.keys.push(e)}const _=class{constructor(t,e){d(this,"parser"),d(this,"url"),d(this,"_isLoadingMesh"),d(this,"loadMesh",r=>{var o,s;if(this._isLoadingMesh)return null;const n=(s=(o=this.parser.json.meshes[r])==null?void 0:o.extensions)==null?void 0:s[I];return n?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",r).then(i=>{var a;return this._isLoadingMesh=!1,i&&_.registerMesh(this.url,n.guid,i,(a=n.lods)==null?void 0:a.length,void 0,n),i})):null}),p&&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",s=t[o];if(s!=null)return s;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const i of t)this.getMaterialMinMaxLODsCount(i,e);return t[o]=e,e}if(p==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const a of Object.keys(i.uniforms)){const u=i.uniforms[a].value;u?.isTexture===!0&&n(u,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const a=t[i];a?.isTexture===!0&&n(a,e)}return t[o]=e,e;function n(i,a){const u=r.getAssignedLODInformation(i);if(u){const l=r.lodInfos.get(u.key);if(l&&l.lods){a.min_count=Math.min(a.min_count,l.lods.length),a.max_count=Math.max(a.max_count,l.lods.length);for(let x=0;x<l.lods.length;x++){const c=l.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(t,e){var r;if(Array.isArray(t)){for(const n of t)if(this.hasLODLevelAvailable(n,e))return!0;return!1}if(t.isMaterial===!0){for(const n of Object.keys(t)){const i=t[n];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const n of t.children)if(n.isMesh===!0&&this.hasLODLevelAvailable(n,e))return!0}let o,s;if(t.isMesh?o=t.geometry:(t.isBufferGeometry||t.isTexture)&&(o=t),o&&(r=o?.userData)!=null&&r.LODS){const n=o.userData.LODS;if(s=this.lodInfos.get(n.key),e===void 0)return s!=null;if(s)return Array.isArray(s.lods)?e<s.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof $||t.isMesh===!0){const o=t.geometry,s=this.getAssignedLODInformation(o);if(!s)return Promise.resolve(null);for(const n of k)(r=n.onBeforeGetLODMesh)==null||r.call(n,t,e);return t["LOD:requested level"]=e,_.getOrLoadLOD(o,e).then(n=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(n)){const i=s.index||0;n=n[i]}n&&o!=n&&(n?.isBufferGeometry?(t.geometry=n,p&&fe(t,"geometry",s.url)):p&&console.error("Invalid LOD geometry",n))}return n}).catch(n=>(console.error("Error loading mesh LOD",t,n),null))}else p&&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 Me||t.isMaterial===!0){const r=t,o=[],s=new Array;if(p&&le.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const n=r;for(const i of Object.keys(n.uniforms)){const a=n.uniforms[i].value;if(a?.isTexture===!0){const u=this.assignTextureLODForSlot(a,e,r,i);o.push(u),s.push(i)}}}else for(const n of Object.keys(r)){const i=r[n];if(i?.isTexture===!0){const a=this.assignTextureLODForSlot(i,e,r,n);o.push(a),s.push(n)}}return Promise.all(o).then(n=>{const i=new Array;for(let a=0;a<n.length;a++){const u=n[a],l=s[a];u&&u.isTexture===!0?i.push({material:r,slot:l,texture:u,level:e}):i.push({material:r,slot:l,texture:null,level:e})}return i})}if(t instanceof W||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(s=>{if(Array.isArray(s))return null;if(s?.isTexture===!0){if(s!=t){if(r&&o){const n=r[o];if(n){const i=this.getAssignedLODInformation(n);if(i&&i?.level<e)return p==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,r,n,s),null}r[o]=s}if(p&&o&&r){const n=this.getAssignedLODInformation(t);n&&fe(r,o,n.url)}}return s}else p=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(s=>(console.error("Error loading LOD",t,s),null))}afterRoot(t){var e,r;return p&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,s)=>{var n;if(o!=null&&o.extensions){const i=o?.extensions[I];if(i){if(!i.lods){p&&console.warn("Texture has no LODs",i);return}let a=!1;for(const u of this.parser.associations.keys())u.isTexture===!0&&this.parser.associations.get(u).textures===s&&(a=!0,_.registerTexture(this.url,u,(n=i.lods)==null?void 0:n.length,s,i));a||this.parser.getDependency("texture",s).then(u=>{var l;u&&_.registerTexture(this.url,u,(l=i.lods)==null?void 0:l.length,s,i)})}}}),(r=this.parser.json.meshes)==null||r.forEach((o,s)=>{if(o!=null&&o.extensions){const n=o?.extensions[I];if(n&&n.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const a=this.parser.associations.get(i);a.meshes===s&&_.registerMesh(this.url,n.guid,i,n.lods.length,a.primitives,n)}}}}),null}static async getOrLoadLOD(t,e){var r,o,s,n;const i=p=="verbose",a=t.userData.LODS;if(!a)return null;const u=a?.key;let l;if(t.isTexture===!0){const x=t;x.source&&x.source[ae]&&(l=x.source[ae])}if(l||(l=_.lodInfos.get(u)),l){if(e>0){let f=!1;const b=Array.isArray(l.lods);if(b&&e>=l.lods.length?f=!0:b||(f=!0),f)return this.lowresCache.get(u)}const x=Array.isArray(l.lods)?(r=l.lods[e])==null?void 0:r.path:l.lods;if(!x)return p&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const c=Pe(a.url,x);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const f=c+"_"+l.guid,b=this.previouslyLoaded.get(f);if(b!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${f}`);let m=await b.catch(P=>(console.error(`Error loading LOD ${e} from ${c}
|
|
2
|
+
`,P),null)),w=!1;if(m==null||(m instanceof W&&t instanceof W?(o=m.image)!=null&&o.data||(s=m.source)!=null&&s.data?m=this.copySettings(t,m):(w=!0,this.previouslyLoaded.delete(f)):m instanceof K&&t instanceof K&&((n=m.attributes.position)!=null&&n.array||(w=!0,this.previouslyLoaded.delete(f)))),!w)return m}const g=l,L=new Promise(async(m,w)=>{const P=new Oe;oe(P),p&&(await new Promise(v=>setTimeout(v,1e3)),i&&console.warn("Start loading (delayed) "+c,g.guid));let X=c;if(g&&Array.isArray(g.lods)){const v=g.lods[e];v.hash&&(X+="?v="+v.hash)}const S=await P.loadAsync(X).catch(v=>(console.error(`Error loading LOD ${e} from ${c}
|
|
3
|
+
`,v),null));if(!S)return null;const M=S.parser;i&&console.log("Loading finished "+c,g.guid);let y=0;if(S.parser.json.textures){let v=!1;for(const h of S.parser.json.textures){if(h!=null&&h.extensions){const D=h?.extensions[I];if(D!=null&&D.guid&&D.guid===g.guid){v=!0;break}}y++}if(v){let h=await M.getDependency("texture",y);return h&&_.assignLODInformation(a.url,h,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',c,y,h,f),t instanceof W&&(h=this.copySettings(t,h)),h&&(h.guid=g.guid),m(h)}else p&&console.warn("Could not find texture with guid",g.guid,S.parser.json)}if(y=0,S.parser.json.meshes){let v=!1;for(const h of S.parser.json.meshes){if(h!=null&&h.extensions){const D=h?.extensions[I];if(D!=null&&D.guid&&D.guid===g.guid){v=!0;break}}y++}if(v){const h=await M.getDependency("mesh",y),D=g;if(i&&console.log(`Loaded Mesh "${h.name}"`,c,y,h,f),h.isMesh===!0){const A=h.geometry;return _.assignLODInformation(a.url,A,u,e,void 0,D.density),m(A)}else{const A=new Array;for(let C=0;C<h.children.length;C++){const F=h.children[C];if(F.isMesh===!0){const j=F.geometry;_.assignLODInformation(a.url,j,u,e,C,D.density),A.push(j)}}return m(A)}}else p&&console.warn("Could not find mesh with guid",g.guid,S.parser.json)}return m(null)});return this.previouslyLoaded.set(f,L),await L}else if(t instanceof W){i&&console.log("Load texture from uri: "+c);const f=await new De().loadAsync(c);return f?(f.guid=l.guid,f.flipY=!1,f.needsUpdate=!0,f.colorSpace=t.colorSpace,i&&console.log(l,f)):p&&console.warn("failed loading",c),f}}else p&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,o,s,n){if(!e)return;e.userData||(e.userData={});const i=new Re(t,r,o,s,n);e.userData.LODS=i}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),p&&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 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};
|
|
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 O=_;d(O,"registerTexture",(t,e,r,o,s)=>{if(p&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,s),!e){p&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[ae]=s);const n=s.guid;_.assignLODInformation(t,e,n,r,o,void 0),_.lodInfos.set(n,s),_.lowresCache.set(n,e)}),d(O,"registerMesh",(t,e,r,o,s,n)=>{var i;p&&console.log("> Progressive: register mesh",s,r.name,n,r.uuid,r);const a=r.geometry;if(!a){p&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),_.assignLODInformation(t,a,e,o,s,n.density),_.lodInfos.set(e,n);let u=_.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],_.lowresCache.set(e,u),o>0&&!Z(r)&&he(r,a);for(const l of k)(i=l.onRegisteredNewMesh)==null||i.call(l,r,n)}),d(O,"lodInfos",new Map),d(O,"previouslyLoaded",new Map),d(O,"lowresCache",new Map);class Re{constructor(e,r,o,s,n){d(this,"url"),d(this,"key"),d(this,"level"),d(this,"index"),d(this,"density"),this.url=e,this.key=r,this.level=o,s!=null&&(this.index=s),n!=null&&(this.density=n)}}const G=J("debugprogressive"),ke=J("noprogressive"),ge=Symbol("Needle:LODSManager"),ue=Symbol("Needle:LODState"),N=Symbol("Needle:CurrentLOD"),E={mesh_lod:-1,texture_lod:-1},T=class{constructor(t){d(this,"renderer"),d(this,"projectionScreenMatrix",new ce),d(this,"cameraFrustrum",new _e),d(this,"targetTriangleDensity",2e5),d(this,"updateInterval",0),d(this,"pause",!1),d(this,"_frame",0),d(this,"_originalRender"),d(this,"_sphere",new we),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[ge]?t[ge]:new T(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 s=e._frame,n=t++;e.onBeforeRender(r,o,n,s),e._originalRender.call(this,r,o),e.onAfterRender(r,o,n,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,o){}onAfterRender(t,e,r,o){var s,n;if(this.pause)return;const i=this.renderer.renderLists.get(t,0),a=i.opaque;let u=!0;if(a.length===1){const l=a[0].material;(l.name==="EffectMaterial"||l.name==="CopyShader")&&(u=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(u=!1),u){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 c of a){if(c.material&&(((s=c.geometry)==null?void 0:s.type)==="BoxGeometry"||((n=c.geometry)==null?void 0:n.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){G&&(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 f=c.object;(f instanceof $||f.isMesh)&&this.updateLODs(t,e,f,l,o)}const x=i.transparent;for(const c of x){const f=c.object;(f instanceof $||f.isMesh)&&this.updateLODs(t,e,f,l,o)}}}updateLODs(t,e,r,o,s){var n,i;r.userData||(r.userData={});let a=r[ue];if(a||(a=new je,r[ue]=a),a.frames++<2)return;for(const l of k)(n=l.onBeforeUpdateLOD)==null||n.call(l,this.renderer,t,e,r);this.calculateLodLevel(e,r,a,o,E),E.mesh_lod=Math.round(E.mesh_lod),E.texture_lod=Math.round(E.texture_lod),E.mesh_lod>=0&&this.loadProgressiveMeshes(r,E.mesh_lod);let u=E.texture_lod;if(r.material&&u>=0){const l=r["DEBUG:LOD"];l!=null&&(u=l),this.loadProgressiveTextures(r.material,u)}for(const l of k)(i=l.onAfterUpdatedLOD)==null||i.call(l,this.renderer,t,e,r,E);a.lastLodLevel_Mesh=E.mesh_lod,a.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}let r=!1;(t[N]===void 0||e<t[N])&&(r=!0),r&&(t[N]=e,O.assignTextureLOD(t,e))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[N]!==e){t[N]=e;const r=t.geometry;return O.assignMeshLOD(t,e).then(o=>(o&&t[N]==e&&r!=t.geometry,o))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,o=t.max,s=(r.x+o.x)*.5,n=(r.y+o.y)*.5;return this._tempPtInside.set(s,n,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,o,s){var n;if(!e){s.mesh_lod=-1,s.texture_lod=-1;return}if(!t){s.mesh_lod=-1,s.texture_lod=-1;return}let i=10+1,a=!1;if(G&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=O.getMeshLODInformation(e.geometry),l=u?.lods,x=l&&l.length>0,c=O.getMaterialMinMaxLODsCount(e.material),f=c?.min_count!=1/0&&c.min_count>0&&c.max_count>0;if(!x&&!f){s.mesh_lod=0,s.texture_lod=0;return}if(x||(a=!0,i=0),!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e))){s.mesh_lod=99,s.texture_lod=99;return}let b=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const g=e;g.boundingBox||g.computeBoundingBox(),b=g.boundingBox}if(b&&t.isPerspectiveCamera){const g=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 M=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(M)){s.mesh_lod=0,s.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),T.isInside(this._tempBox,this.projectionScreenMatrix)){s.mesh_lod=0,s.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&g.fov>70){const M=this._tempBox.min,y=this._tempBox.max;let v=M.x,h=M.y,D=y.x,A=y.y;const C=2,F=1.5,j=(M.x+y.x)*.5,H=(M.y+y.y)*.5;v=(v-j)*C+j,h=(h-H)*C+H,D=(D-j)*C+j,A=(A-H)*C+H;const xe=v<0&&D>0?0:Math.min(Math.abs(M.x),Math.abs(y.x)),ye=h<0&&A>0?0:Math.min(Math.abs(M.y),Math.abs(y.y)),te=Math.max(xe,ye);r.lastCentrality=(F-te)*(F-te)*(F-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*=g.aspect;const m=t.matrixWorldInverse,w=this._tempBox2;w.copy(b),w.applyMatrix4(e.matrixWorld),w.applyMatrix4(m);const P=w.getSize(this._tempBox2Size),X=Math.max(P.x,P.y);if(Math.max(L.x,L.y)!=0&&X!=0&&(L.z=P.z/Math.max(P.x,P.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,G&&T.debugDrawLine){const M=this.tempMatrix.copy(this.projectionScreenMatrix);M.invert();const y=T.corner0,v=T.corner1,h=T.corner2,D=T.corner3;y.copy(this._tempBox.min),v.copy(this._tempBox.max),v.x=y.x,h.copy(this._tempBox.max),h.y=y.y,D.copy(this._tempBox.max);const A=(y.z+D.z)*.5;y.z=v.z=h.z=D.z=A,y.applyMatrix4(M),v.applyMatrix4(M),h.applyMatrix4(M),D.applyMatrix4(M),T.debugDrawLine(y,v,255),T.debugDrawLine(y,h,255),T.debugDrawLine(v,D,255),T.debugDrawLine(h,D,255)}let S=999;if(l&&r.lastScreenCoverage>0){for(let M=0;M<l.length;M++)if(l[M].density/r.lastScreenCoverage<o){S=M;break}}S<i&&(i=S,a=!0)}if(a?s.mesh_lod=i:s.mesh_lod=r.lastLodLevel_Mesh,G&&s.mesh_lod!=r.lastLodLevel_Mesh){const g=l?.[s.mesh_lod];g&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${s.mesh_lod} (${g.density.toFixed(0)}) - ${e.name}`)}if(f)if(r.lastLodLevel_Texture<0){if(s.texture_lod=c.max_count-1,G){const g=c.lods[c.max_count-1];G&&console.log(`First Texture LOD ${s.texture_lod} (${g.max_height}px) - ${e.name}`)}}else{const g=r.lastScreenCoverage*1.5,L=this.renderer.domElement.clientHeight/window.devicePixelRatio*g;for(let m=c.lods.length-1;m>=0;m--){const w=c.lods[m];if(!(Ie()&&w.max_height>4096)&&w.max_height>L){s.texture_lod=m,s.texture_lod<r.lastLodLevel_Texture&&G&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${s.texture_lod} (${w.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${L.toFixed(0)}px) - ${e.name}`);break}}}else s.texture_lod=0}};let B=T;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 s=Object.getOwnPropertySymbols(o),n=s.find(a=>a.toString()=="Symbol(renderer)"),i=s.find(a=>a.toString()=="Symbol(scene)");!e&&n!=null&&(e=t[n].threeRenderer),!r&&i!=null&&(r=t[i])}if(e){const o=B.get(e);if(B.addPlugin(new Ge(t)),o.enable(),r){const s=r.camera||r.traverse(n=>n.type=="PerspectiveCamera")[0];s&&e.render(r,s)}return()=>{o.disable()}}return null}class Ge{constructor(e){d(this,"modelviewer"),d(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,r,o,s){this.tryParseMeshLOD(r,s),this.tryParseTextureLOD(r,s)}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),s=this.getUrl();if(s&&o&&r.material){let n=function(a){var u,l,x;if(a[ee]==!0)return;a[ee]=!0,a.userData&&(a.userData.LOD=-1);const c=Object.keys(a);for(let f=0;f<c.length;f++){const b=c[f],g=a[b];if(g?.isTexture===!0){const L=(l=(u=g.userData)==null?void 0:u.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((x=m?.extensions)!=null&&x[I]){const w=m.extensions[I];w&&s&&O.registerTexture(s,g,w.lods.length,L,w)}}}};const i=r.material;if(Array.isArray(i))for(const a of i)n(a);else n(i)}}tryParseMeshLOD(e,r){var o,s;if(r[me]==!0)return;r[me]=!0;const n=this.getUrl();if(!n)return;const i=(s=(o=r.userData)==null?void 0:o.gltfExtensions)==null?void 0:s[I];if(i&&n){const a=r.uuid;O.registerMesh(n,a,r,0,i.lods.length,i)}}}document.addEventListener("DOMContentLoaded",()=>{pe(document.querySelector("model-viewer"))});function Fe(t,e,r,o){ne(e),oe(r),r.register(n=>new O(n,t));const s=B.get(e);return o?.enableLODsManager!==!1&&s.enable(),s}export{I as EXTENSION_NAME,B as LODsManager,O as NEEDLE_progressive,oe as addDracoAndKTX2Loaders,ne as createLoaders,Z as getRaycastMesh,pe as patchModelViewer,Ae as setDracoDecoderLocation,Ee as setKTX2TranscoderLocation,he as setRaycastMesh,Fe 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 Le=Object.defineProperty;var me=(l,e,t)=>e in l?Le(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var d=(l,e,t)=>(me(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("three"),Me=require("three/examples/jsm/loaders/GLTFLoader.js"),De=require("three/examples/jsm/libs/meshopt_decoder.module.js"),_e=require("three/examples/jsm/loaders/DRACOLoader.js"),we=require("three/examples/jsm/loaders/KTX2Loader.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 _e.DRACOLoader,q.setDecoderPath(Z),q.setDecoderConfig({type:"js"})),K||(K=new we.KTX2Loader,K.setTranscoderPath(le)),oe||(oe=De.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 p.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=p.Mesh.prototype.raycast;p.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;p.Mesh.prototype.raycast=V,V=null}}let V=null;function Ae(l){const e=new p.BufferGeometry;for(const t in l.attributes)e.setAttribute(t,l.getAttribute(t));return e.setIndex(l.getIndex()),e}const F=new Array,E="NEEDLE_progressive",x=j("debugprogressive"),se=Symbol("needle-progressive-texture"),X=new Map,ae=new Set;if(x){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(!x)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 v=class{constructor(e,t){d(this,"parser");d(this,"url");d(this,"_isLoadingMesh");d(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=>{var s;return this._isLoadingMesh=!1,o&&v.registerMesh(this.url,t.guid,o,(s=t.lods)==null?void 0:s.length,void 0,t),o})):null});x&&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(x==="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 c=r.lodInfos.get(h.key);if(c&&c.lods){a.min_count=Math.min(a.min_count,c.lods.length),a.max_count=Math.max(a.max_count,c.lods.length);for(let L=0;L<c.lods.length;L++){const u=c.lods[L];u.width&&(a.lods[L]=a.lods[L]||{min_height:1/0,max_height:0},a.lods[L].min_height=Math.min(a.lods[L].min_height,u.height),a.lods[L].max_height=Math.max(a.lods[L].max_height,u.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 p.Mesh||e.isMesh===!0){const i=e.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of F)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,v.getOrLoadLOD(i,t).then(s=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(s)){const n=o.index||0;s=s[n]}s&&i!=s&&((s==null?void 0:s.isBufferGeometry)?(e.geometry=s,x&&fe(e,"geometry",o.url)):x&&console.error("Invalid LOD geometry",s))}return s}).catch(s=>(console.error("Error loading mesh LOD",e,s),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e instanceof p.Material||e.isMaterial===!0){const r=e,i=[],o=new Array;if(x&&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],c=o[a];h&&h.isTexture===!0?n.push({material:r,slot:c,texture:h,level:t}):n.push({material:r,slot:c,texture:null,level:t})}return n})}if(e instanceof p.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,i){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):i==="glyphMap"?Promise.resolve(e):v.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 x==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,t,r,s,o),null}r[i]=o}if(x&&i&&r){const s=this.getAssignedLODInformation(e);s&&fe(r,i,s.url)}}return o}else x=="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 x&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((i,o)=>{var s;if(i!=null&&i.extensions){const n=i==null?void 0:i.extensions[E];if(n){if(!n.lods){x&&console.warn("Texture has no LODs",n);return}let a=!1;for(const h of this.parser.associations.keys())h.isTexture===!0&&this.parser.associations.get(h).textures===o&&(a=!0,v.registerTexture(this.url,h,(s=n.lods)==null?void 0:s.length,o,n));a||this.parser.getDependency("texture",o).then(h=>{var c;h&&v.registerTexture(this.url,h,(c=n.lods)==null?void 0:c.length,o,n)})}}}),(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&&v.registerMesh(this.url,s.guid,n,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var n,a,h,c;const r=x=="verbose",i=e.userData.LODS;if(!i)return null;const o=i==null?void 0:i.key;let s;if(e.isTexture===!0){const L=e;L.source&&L.source[se]&&(s=L.source[se])}if(s||(s=v.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 L=Array.isArray(s.lods)?(n=s.lods[t])==null?void 0:n.path:s.lods;if(!L)return x&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const u=Se(i.url,L);if(u.endsWith(".glb")||u.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const y=u+"_"+s.guid,m=this.previouslyLoaded.get(y);if(m!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${y}`);let O=await m.catch(P=>(console.error(`Error loading LOD ${t} from ${u}
|
|
2
|
+
`,P),null)),A=!1;if(O==null||(O instanceof p.Texture&&e instanceof p.Texture?(a=O.image)!=null&&a.data||(h=O.source)!=null&&h.data?O=this.copySettings(e,O):(A=!0,this.previouslyLoaded.delete(y)):O instanceof p.BufferGeometry&&e instanceof p.BufferGeometry&&((c=O.attributes.position)!=null&&c.array||(A=!0,this.previouslyLoaded.delete(y)))),!A)return O}const w=s,_=new Promise(async(O,A)=>{const P=new Me.GLTFLoader;ue(P),x&&(await new Promise(g=>setTimeout(g,1e3)),r&&console.warn("Start loading (delayed) "+u,w.guid));let Y=u;if(w&&Array.isArray(w.lods)){const g=w.lods[t];g.hash&&(Y+="?v="+g.hash)}const k=await P.loadAsync(Y).catch(g=>(console.error(`Error loading LOD ${t} from ${u}
|
|
3
|
+
`,g),null));if(!k)return null;const z=k.parser;r&&console.log("Loading finished "+u,w.guid);let I=0;if(k.parser.json.textures){let g=!1;for(const f of k.parser.json.textures){if(f!=null&&f.extensions){const M=f==null?void 0:f.extensions[E];if(M!=null&&M.guid&&M.guid===w.guid){g=!0;break}}I++}if(g){let f=await z.getDependency("texture",I);return f&&v.assignLODInformation(i.url,f,o,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+f.name+'"',u,I,f,y),e instanceof p.Texture&&(f=this.copySettings(e,f)),f&&(f.guid=w.guid),O(f)}else x&&console.warn("Could not find texture with guid",w.guid,k.parser.json)}if(I=0,k.parser.json.meshes){let g=!1;for(const f of k.parser.json.meshes){if(f!=null&&f.extensions){const M=f==null?void 0:f.extensions[E];if(M!=null&&M.guid&&M.guid===w.guid){g=!0;break}}I++}if(g){const f=await z.getDependency("mesh",I),M=w;if(r&&console.log(`Loaded Mesh "${f.name}"`,u,I,f,y),f.isMesh===!0){const T=f.geometry;return v.assignLODInformation(i.url,T,o,t,void 0,M.density),O(T)}else{const T=new Array;for(let b=0;b<f.children.length;b++){const G=f.children[b];if(G.isMesh===!0){const $=G.geometry;v.assignLODInformation(i.url,$,o,t,b,M.density),T.push($)}}return O(T)}}else x&&console.warn("Could not find mesh with guid",w.guid,k.parser.json)}return O(null)});return this.previouslyLoaded.set(y,_),await _}else if(e instanceof p.Texture){r&&console.log("Load texture from uri: "+u);const m=await new p.TextureLoader().loadAsync(u);return m?(m.guid=s.guid,m.flipY=!1,m.needsUpdate=!0,m.colorSpace=e.colorSpace,r&&console.log(s,m)):x&&console.warn("failed loading",u),m}}else x&&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(),x&&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 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;
|
|
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;d(S,"registerTexture",(e,t,r,i,o)=>{if(x&&console.log("> Progressive: register texture",i,t.name,t.uuid,t,o),!t){x&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[se]=o);const s=o.guid;v.assignLODInformation(e,t,s,r,i,void 0),v.lodInfos.set(s,o),v.lowresCache.set(s,t)}),d(S,"registerMesh",(e,t,r,i,o,s)=>{var h;x&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const n=r.geometry;if(!n){x&&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&&!ee(r)&&ge(r,n);for(const c of F)(h=c.onRegisteredNewMesh)==null||h.call(c,r,s)}),d(S,"lodInfos",new Map),d(S,"previouslyLoaded",new Map),d(S,"lowresCache",new Map);class Pe{constructor(e,t,r,i,o){d(this,"url");d(this,"key");d(this,"level");d(this,"index");d(this,"density");this.url=e,this.key=t,this.level=r,i!=null&&(this.index=i),o!=null&&(this.density=o)}}const N=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){d(this,"renderer");d(this,"projectionScreenMatrix",new p.Matrix4);d(this,"cameraFrustrum",new p.Frustum);d(this,"targetTriangleDensity",2e5);d(this,"updateInterval",0);d(this,"pause",!1);d(this,"_frame",0);d(this,"_originalRender");d(this,"_sphere",new p.Sphere);d(this,"_tempBox",new p.Box3);d(this,"_tempBox2",new p.Box3);d(this,"tempMatrix",new p.Matrix4);d(this,"_tempWorldPosition",new p.Vector3);d(this,"_tempBoxSize",new p.Vector3);d(this,"_tempBox2Size",new p.Vector3);this.renderer=e}static getObjectLODState(e){return e[ie]}static addPlugin(e){F.push(e)}static removePlugin(e){const t=F.indexOf(e);t>=0&&F.splice(t,1)}static get(e){return e[de]?e[de]:new B(e)}get plugins(){return F}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 c=s[0].material;(c.name==="EffectMaterial"||c.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 c=this.targetTriangleDensity;for(const u of s){if(u.material&&(((a=u.geometry)==null?void 0:a.type)==="BoxGeometry"||((h=u.geometry)==null?void 0:h.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){N&&(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 p.Mesh||y.isMesh)&&this.updateLODs(e,t,y,c,i)}const L=o.transparent;for(const u of L){const y=u.object;(y instanceof p.Mesh||y.isMesh)&&this.updateLODs(e,t,y,c,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 c of F)(a=c.onBeforeUpdateLOD)==null||a.call(c,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 c=r["DEBUG:LOD"];c!=null&&(n=c),this.loadProgressiveTextures(r.material,n)}for(const c of F)(h=c.onAfterUpdatedLOD)==null||h.call(c,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 w;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(N&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const h=S.getMeshLODInformation(t.geometry),c=h==null?void 0:h.lods,L=c&&c.length>0,u=S.getMaterialMinMaxLODsCount(t.material),y=(u==null?void 0:u.min_count)!=1/0&&u.min_count>0&&u.max_count>0;if(!L&&!y){o.mesh_lod=0,o.texture_lod=0;return}if(L||(a=!0,n=0),!((w=this.cameraFrustrum)!=null&&w.intersectsObject(t))){o.mesh_lod=99,o.texture_lod=99;return}let m=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const _=t;_.boundingBox||_.computeBoundingBox(),m=_.boundingBox}if(m&&e.isPerspectiveCamera){const _=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 g=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g)){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&&_.fov>70){const g=this._tempBox.min,f=this._tempBox.max;let M=g.x,T=g.y,b=f.x,G=f.y;const $=2,te=1.5,H=(g.x+f.x)*.5,J=(g.y+f.y)*.5;M=(M-H)*$+H,T=(T-J)*$+J,b=(b-H)*$+H,G=(G-J)*$+J;const ye=M<0&&b>0?0:Math.min(Math.abs(g.x),Math.abs(f.x)),xe=T<0&&G>0?0:Math.min(Math.abs(g.y),Math.abs(f.y)),re=Math.max(ye,xe);r.lastCentrality=(te-re)*(te-re)*(te-re)}else r.lastCentrality=1;const D=this._tempBox.getSize(this._tempBoxSize);D.multiplyScalar(.5),screen.availHeight>0&&D.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),D.x*=_.aspect;const O=e.matrixWorldInverse,A=this._tempBox2;A.copy(m),A.applyMatrix4(t.matrixWorld),A.applyMatrix4(O);const P=A.getSize(this._tempBox2Size),Y=Math.max(P.x,P.y);if(Math.max(D.x,D.y)!=0&&Y!=0&&(D.z=P.z/Math.max(P.x,P.y)*Math.max(D.x,D.y)),r.lastScreenCoverage=Math.max(D.x,D.y,D.z),r.lastScreenspaceVolume.copy(D),r.lastScreenCoverage*=r.lastCentrality,N&&B.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const f=B.corner0,M=B.corner1,T=B.corner2,b=B.corner3;f.copy(this._tempBox.min),M.copy(this._tempBox.max),M.x=f.x,T.copy(this._tempBox.max),T.y=f.y,b.copy(this._tempBox.max);const G=(f.z+b.z)*.5;f.z=M.z=T.z=b.z=G,f.applyMatrix4(g),M.applyMatrix4(g),T.applyMatrix4(g),b.applyMatrix4(g),B.debugDrawLine(f,M,255),B.debugDrawLine(f,T,255),B.debugDrawLine(M,b,255),B.debugDrawLine(T,b,255)}let z=999;if(c&&r.lastScreenCoverage>0){for(let g=0;g<c.length;g++)if(c[g].density/r.lastScreenCoverage<i){z=g;break}}z<n&&(n=z,a=!0)}if(a?o.mesh_lod=n:o.mesh_lod=r.lastLodLevel_Mesh,N&&o.mesh_lod!=r.lastLodLevel_Mesh){const D=c==null?void 0:c[o.mesh_lod];D&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${o.mesh_lod} (${D.density.toFixed(0)}) - ${t.name}`)}if(y)if(r.lastLodLevel_Texture<0){if(o.texture_lod=u.max_count-1,N){const _=u.lods[u.max_count-1];N&&console.log(`First Texture LOD ${o.texture_lod} (${_.max_height}px) - ${t.name}`)}}else{const _=r.lastScreenCoverage*1.5,O=this.renderer.domElement.clientHeight/window.devicePixelRatio*_;for(let A=u.lods.length-1;A>=0;A--){const P=u.lods[A];if(!(Te()&&P.max_height>4096)&&P.max_height>O){o.texture_lod=A,o.texture_lod<r.lastLodLevel_Texture&&N&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${o.texture_lod} (${P.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${O.toFixed(0)}px) - ${t.name}`);break}}}else o.texture_lod=0}};let C=B;d(C,"debugDrawLine"),d(C,"corner0",new p.Vector3),d(C,"corner1",new p.Vector3),d(C,"corner2",new p.Vector3),d(C,"corner3",new p.Vector3),d(C,"_tempPtInside",new p.Vector3);class Ce{constructor(){d(this,"frames",0);d(this,"lastLodLevel_Mesh",-1);d(this,"lastLodLevel_Texture",-1);d(this,"lastScreenCoverage",0);d(this,"lastScreenspaceVolume",new p.Vector3);d(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){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){d(this,"modelviewer");d(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,c,L;if(n[Q]==!0)return;n[Q]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let u=0;u<a.length;u++){const y=a[u],m=n[y];if((m==null?void 0:m.isTexture)===!0){const w=(c=(h=m.userData)==null?void 0:h.associations)==null?void 0:c.textures,_=r.parser.json.textures[w];if(!_){console.warn("Texture data not found for texture index "+w);continue}if((L=_==null?void 0:_.extensions)!=null&&L[E]){const D=_.extensions[E];D&&i&&S.registerTexture(i,m,D.lods.length,w,D)}}}};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)}}}document.addEventListener("DOMContentLoaded",()=>{pe(document.querySelector("model-viewer"))});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}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
|
@@ -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;
|
|
@@ -258,12 +258,16 @@ export class NEEDLE_progressive {
|
|
|
258
258
|
geo = geo[index];
|
|
259
259
|
}
|
|
260
260
|
if (geo && currentGeometry != geo) {
|
|
261
|
+
const isGeometry = geo?.isBufferGeometry;
|
|
261
262
|
// if (debug == "verbose") console.log("Progressive Mesh " + mesh.name + " loaded", currentGeometry, "→", geo, "\n", mesh)
|
|
262
|
-
if (
|
|
263
|
+
if (isGeometry) {
|
|
263
264
|
mesh.geometry = geo;
|
|
264
265
|
if (debug)
|
|
265
266
|
registerDebug(mesh, "geometry", lodinfo.url);
|
|
266
267
|
}
|
|
268
|
+
else if (debug) {
|
|
269
|
+
console.error("Invalid LOD geometry", geo);
|
|
270
|
+
}
|
|
267
271
|
}
|
|
268
272
|
}
|
|
269
273
|
// this.onProgressiveLoadEnd(info);
|
|
@@ -413,7 +417,7 @@ export class NEEDLE_progressive {
|
|
|
413
417
|
return this.parser.getDependency("mesh", meshIndex).then(mesh => {
|
|
414
418
|
this._isLoadingMesh = false;
|
|
415
419
|
if (mesh) {
|
|
416
|
-
NEEDLE_progressive.registerMesh(this.url, ext.guid, mesh, ext.lods
|
|
420
|
+
NEEDLE_progressive.registerMesh(this.url, ext.guid, mesh, ext.lods?.length, undefined, ext);
|
|
417
421
|
}
|
|
418
422
|
return mesh;
|
|
419
423
|
});
|
|
@@ -436,7 +440,7 @@ export class NEEDLE_progressive {
|
|
|
436
440
|
const val = this.parser.associations.get(key);
|
|
437
441
|
if (val.textures === index) {
|
|
438
442
|
found = true;
|
|
439
|
-
NEEDLE_progressive.registerTexture(this.url, key, ext.lods
|
|
443
|
+
NEEDLE_progressive.registerTexture(this.url, key, ext.lods?.length, index, ext);
|
|
440
444
|
}
|
|
441
445
|
}
|
|
442
446
|
}
|
|
@@ -444,7 +448,7 @@ export class NEEDLE_progressive {
|
|
|
444
448
|
if (!found) {
|
|
445
449
|
this.parser.getDependency("texture", index).then(tex => {
|
|
446
450
|
if (tex) {
|
|
447
|
-
NEEDLE_progressive.registerTexture(this.url, tex, ext.lods
|
|
451
|
+
NEEDLE_progressive.registerTexture(this.url, tex, ext.lods?.length, index, ext);
|
|
448
452
|
}
|
|
449
453
|
});
|
|
450
454
|
}
|
|
@@ -537,7 +541,7 @@ export class NEEDLE_progressive {
|
|
|
537
541
|
static async getOrLoadLOD(current, level) {
|
|
538
542
|
const debugverbose = debug == "verbose";
|
|
539
543
|
/** this key is used to lookup the LOD information */
|
|
540
|
-
const LOD = current.userData.LODS
|
|
544
|
+
const LOD = current.userData.LODS;
|
|
541
545
|
if (!LOD) {
|
|
542
546
|
return null;
|
|
543
547
|
}
|
|
@@ -680,7 +684,7 @@ export class NEEDLE_progressive {
|
|
|
680
684
|
return resolve(tex);
|
|
681
685
|
}
|
|
682
686
|
else if (debug) {
|
|
683
|
-
console.warn("Could not find texture with guid", ext.guid);
|
|
687
|
+
console.warn("Could not find texture with guid", ext.guid, gltf.parser.json);
|
|
684
688
|
}
|
|
685
689
|
}
|
|
686
690
|
index = 0;
|
|
@@ -713,7 +717,7 @@ export class NEEDLE_progressive {
|
|
|
713
717
|
const geometries = new Array();
|
|
714
718
|
for (let i = 0; i < mesh.children.length; i++) {
|
|
715
719
|
const child = mesh.children[i];
|
|
716
|
-
if (child
|
|
720
|
+
if (child.isMesh === true) {
|
|
717
721
|
const geo = child.geometry;
|
|
718
722
|
NEEDLE_progressive.assignLODInformation(LOD.url, geo, LODKEY, level, i, meshExt.density);
|
|
719
723
|
geometries.push(geo);
|
|
@@ -722,6 +726,9 @@ export class NEEDLE_progressive {
|
|
|
722
726
|
return resolve(geometries);
|
|
723
727
|
}
|
|
724
728
|
}
|
|
729
|
+
else if (debug) {
|
|
730
|
+
console.warn("Could not find mesh with guid", ext.guid, gltf.parser.json);
|
|
731
|
+
}
|
|
725
732
|
}
|
|
726
733
|
// we could not find a texture or mesh with the given guid
|
|
727
734
|
return resolve(null);
|
|
@@ -762,10 +769,10 @@ export class NEEDLE_progressive {
|
|
|
762
769
|
if (!res.userData)
|
|
763
770
|
res.userData = {};
|
|
764
771
|
const info = new LODInformation(url, key, level, index, density);
|
|
765
|
-
res.userData.LODS =
|
|
772
|
+
res.userData.LODS = info;
|
|
766
773
|
}
|
|
767
774
|
static getAssignedLODInformation(res) {
|
|
768
|
-
return res?.userData?.LODS
|
|
775
|
+
return res?.userData?.LODS || null;
|
|
769
776
|
}
|
|
770
777
|
// private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
|
|
771
778
|
static copySettings(source, target) {
|
package/lib/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { WebGLRenderer } from "three";
|
|
2
|
-
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
3
|
-
import { LODsManager } from "./lods_manager.js";
|
|
4
1
|
export * from "./extension.js";
|
|
5
2
|
export * from "./plugins/index.js";
|
|
6
3
|
export { LODsManager } from "./lods_manager.js";
|
|
7
4
|
export { setDracoDecoderLocation, setKTX2TranscoderLocation, createLoaders, addDracoAndKTX2Loaders } from "./loaders.js";
|
|
8
5
|
export * from "./utils.js";
|
|
6
|
+
import { WebGLRenderer } from "three";
|
|
7
|
+
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
8
|
+
import { LODsManager } from "./lods_manager.js";
|
|
9
9
|
declare class UseNeedleGLTFProgressive {
|
|
10
10
|
enableLODsManager?: boolean;
|
|
11
11
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import { addDracoAndKTX2Loaders, createLoaders } from "./loaders.js";
|
|
2
|
-
import { NEEDLE_progressive } from "./extension.js";
|
|
3
|
-
import { LODsManager } from "./lods_manager.js";
|
|
4
1
|
export * from "./extension.js";
|
|
5
2
|
export * from "./plugins/index.js";
|
|
6
3
|
export { LODsManager } from "./lods_manager.js";
|
|
7
4
|
export { setDracoDecoderLocation, setKTX2TranscoderLocation, createLoaders, addDracoAndKTX2Loaders } from "./loaders.js";
|
|
8
5
|
export * from "./utils.js";
|
|
6
|
+
import { patchModelViewer } from "./plugins/modelviewer.js";
|
|
7
|
+
// Query once for model viewer. If a user does not have model-viewer in their page, this will return null.
|
|
8
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
9
|
+
patchModelViewer(document.querySelector("model-viewer"));
|
|
10
|
+
});
|
|
11
|
+
import { addDracoAndKTX2Loaders, createLoaders } from "./loaders.js";
|
|
12
|
+
import { NEEDLE_progressive } from "./extension.js";
|
|
13
|
+
import { LODsManager } from "./lods_manager.js";
|
|
9
14
|
;
|
|
10
15
|
/** Use this function to enable progressive loading of gltf models.
|
|
11
16
|
* @param url The url of the gltf model.
|
|
@@ -32,8 +37,3 @@ export function useNeedleProgressive(url, renderer, loader, opts) {
|
|
|
32
37
|
}
|
|
33
38
|
return lod;
|
|
34
39
|
}
|
|
35
|
-
import { patchModelViewer } from "./plugins/modelviewer.js";
|
|
36
|
-
// Query once for model viewer. If a user does not have model-viewer in their page, this will return null.
|
|
37
|
-
document.addEventListener("DOMContentLoaded", () => {
|
|
38
|
-
patchModelViewer(document.querySelector("model-viewer"));
|
|
39
|
-
});
|
package/lib/lods_manager.js
CHANGED
|
@@ -147,6 +147,12 @@ export class LODsManager {
|
|
|
147
147
|
if (camera.parent && camera.parent.type === "CubeCamera") {
|
|
148
148
|
updateLODs = false;
|
|
149
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
|
+
}
|
|
150
156
|
if (updateLODs) {
|
|
151
157
|
if (suppressProgressiveLoading)
|
|
152
158
|
return;
|
|
@@ -256,7 +262,7 @@ export class LODsManager {
|
|
|
256
262
|
// Check if the material LOD was already updated to a certain level
|
|
257
263
|
// We don't use the userData here because we want to re-run assigning textures if the material has been cloned
|
|
258
264
|
let update = false;
|
|
259
|
-
if (material[$currentLOD]
|
|
265
|
+
if (material[$currentLOD] === undefined) {
|
|
260
266
|
update = true;
|
|
261
267
|
}
|
|
262
268
|
else if (level < material[$currentLOD]) {
|
|
@@ -332,6 +338,7 @@ export class LODsManager {
|
|
|
332
338
|
/** highest LOD level we'd ever expect to be generated */
|
|
333
339
|
const maxLevel = 10;
|
|
334
340
|
let mesh_level = maxLevel + 1;
|
|
341
|
+
let mesh_level_calculated = false;
|
|
335
342
|
if (debugProgressiveLoading && mesh["DEBUG:LOD"] != undefined) {
|
|
336
343
|
return mesh["DEBUG:LOD"];
|
|
337
344
|
}
|
|
@@ -348,6 +355,7 @@ export class LODsManager {
|
|
|
348
355
|
return;
|
|
349
356
|
}
|
|
350
357
|
if (!has_mesh_lods) {
|
|
358
|
+
mesh_level_calculated = true;
|
|
351
359
|
mesh_level = 0;
|
|
352
360
|
}
|
|
353
361
|
if (!this.cameraFrustrum?.intersectsObject(mesh)) {
|
|
@@ -491,9 +499,24 @@ export class LODsManager {
|
|
|
491
499
|
const isLowerLod = expectedLevel < mesh_level;
|
|
492
500
|
if (isLowerLod) {
|
|
493
501
|
mesh_level = expectedLevel;
|
|
502
|
+
mesh_level_calculated = true;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
if (mesh_level_calculated) {
|
|
506
|
+
result.mesh_lod = mesh_level;
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
result.mesh_lod = state.lastLodLevel_Mesh;
|
|
510
|
+
}
|
|
511
|
+
if (debugProgressiveLoading) {
|
|
512
|
+
const changed = result.mesh_lod != state.lastLodLevel_Mesh;
|
|
513
|
+
if (changed) {
|
|
514
|
+
const level = mesh_lods?.[result.mesh_lod];
|
|
515
|
+
if (level) {
|
|
516
|
+
console.log(`Mesh LOD changed: ${state.lastLodLevel_Mesh} → ${result.mesh_lod} (${level.density.toFixed(0)}) - ${mesh.name}`);
|
|
517
|
+
}
|
|
494
518
|
}
|
|
495
519
|
}
|
|
496
|
-
result.mesh_lod = mesh_level;
|
|
497
520
|
if (has_texture_lods) {
|
|
498
521
|
// 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
|
|
499
522
|
if (state.lastLodLevel_Texture < 0) {
|
|
@@ -516,7 +539,7 @@ export class LODsManager {
|
|
|
516
539
|
result.texture_lod = i;
|
|
517
540
|
if (result.texture_lod < state.lastLodLevel_Texture) {
|
|
518
541
|
if (debugProgressiveLoading)
|
|
519
|
-
console.log(`Texture LOD changed ${state.lastLodLevel_Texture} → ${result.texture_lod} (${lod.max_height}px: ${(100 * state.lastScreenCoverage).toFixed(2)} % = ${pixelSizeOnScreen.toFixed(0)}px) - ${mesh.name}`);
|
|
542
|
+
console.log(`Texture LOD changed: ${state.lastLodLevel_Texture} → ${result.texture_lod} (${lod.max_height}px: ${(100 * state.lastScreenCoverage).toFixed(2)} % = ${pixelSizeOnScreen.toFixed(0)}px) - ${mesh.name}`);
|
|
520
543
|
}
|
|
521
544
|
break;
|
|
522
545
|
}
|
|
@@ -530,9 +553,6 @@ export class LODsManager {
|
|
|
530
553
|
}
|
|
531
554
|
}
|
|
532
555
|
}
|
|
533
|
-
function lerp(a, b, t) {
|
|
534
|
-
return a + (b - a) * t;
|
|
535
|
-
}
|
|
536
556
|
class LOD_state {
|
|
537
557
|
frames = 0;
|
|
538
558
|
lastLodLevel_Mesh = -1;
|
|
@@ -22,7 +22,6 @@ export function patchModelViewer(modelviewer) {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
if (renderer) {
|
|
25
|
-
console.log("Adding Needle LODs to modelviewer");
|
|
26
25
|
const lod = LODsManager.get(renderer);
|
|
27
26
|
LODsManager.addPlugin(new RegisterModelviewerDataPlugin(modelviewer));
|
|
28
27
|
lod.enable();
|
|
@@ -30,12 +29,6 @@ export function patchModelViewer(modelviewer) {
|
|
|
30
29
|
const camera = scene["camera"] || scene.traverse((o) => o.type == "PerspectiveCamera")[0];
|
|
31
30
|
if (camera) {
|
|
32
31
|
renderer.render(scene, camera);
|
|
33
|
-
// setTimeout(() => {
|
|
34
|
-
// renderer.render(scene, camera);
|
|
35
|
-
// }, 100)
|
|
36
|
-
// setTimeout(() => {
|
|
37
|
-
// renderer.render(scene, camera);
|
|
38
|
-
// }, 1200)
|
|
39
32
|
}
|
|
40
33
|
}
|
|
41
34
|
return () => {
|
package/package.json
CHANGED