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