UNPKG

@blooooork/three-optimization

Version:

High-performance optimization tools for Three.js including texture atlas management, asset loading, and memory optimization

2 lines (1 loc) 4.62 kB
(function(n,f){typeof exports=="object"&&typeof module<"u"?f(exports,require("three"),require("three/examples/jsm/loaders/GLTFLoader.js")):typeof define=="function"&&define.amd?define(["exports","three","three/examples/jsm/loaders/GLTFLoader.js"],f):(n=typeof globalThis<"u"?globalThis:n||self,f(n.ThreeOptimization={},n.THREE,n.GLTFLoader_js))})(this,function(n,f,M){"use strict";function y(d){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(d){for(const t in d)if(t!=="default"){const s=Object.getOwnPropertyDescriptor(d,t);Object.defineProperty(e,t,s.get?s:{enumerable:!0,get:()=>d[t]})}}return e.default=d,Object.freeze(e)}const c=y(f);class A{constructor(e={}){this.maxAtlasSize=e.maxAtlasSize||4096,this.padding=e.padding||2,this.textureMap=new Map,this.atlases=new Map}async createAtlas(e,t="diffuse"){const s=[...e].sort((r,o)=>{const m=r.image?r.image.width*r.image.height:0;return(o.image?o.image.width*o.image.height:0)-m}),a=document.createElement("canvas"),l=a.getContext("2d");let i=0,g=0,h=0,u=0,p=0;for(const r of s){if(!r.image)continue;const o=r.image.width+this.padding*2,m=r.image.height+this.padding*2;i+o>this.maxAtlasSize&&(i=0,g+=h,h=0),h=Math.max(h,m),u=Math.max(u,i+o),p=Math.max(p,g+m),i+=o}a.width=c.MathUtils.ceilPowerOfTwo(u),a.height=c.MathUtils.ceilPowerOfTwo(p),i=0,g=0,h=0;for(const r of s){if(!r.image)continue;const o=r.image.width,m=r.image.height;i+o+this.padding*2>this.maxAtlasSize&&(i=0,g+=h,h=0),l.drawImage(r.image,i+this.padding,g+this.padding,o,m);const w={x:(i+this.padding)/a.width,y:(g+this.padding)/a.height,width:o/a.width,height:m/a.height};this.textureMap.set(r.uuid,w),h=Math.max(h,m+this.padding*2),i+=o+this.padding*2}const x=new c.CanvasTexture(a);return x.flipY=!1,this.atlases.set(t,x),x}getTextureUVs(e){return this.textureMap.get(e)}getAtlas(e="diffuse"){return this.atlases.get(e)}dispose(){this.atlases.forEach(e=>e.dispose()),this.atlases.clear(),this.textureMap.clear()}}class T{constructor(){this.loadedAssets=new Map,this.loadingPromises=new Map,this.materialCache=new Map,this.gltfLoader=new M.GLTFLoader,this.textureLoader=new c.TextureLoader}async loadTexture(e){if(this.loadedAssets.has(e))return this.loadedAssets.get(e);if(this.loadingPromises.has(e))return this.loadingPromises.get(e);const t=new Promise((s,a)=>{this.textureLoader.load(e,l=>{this.loadedAssets.set(e,l),this.loadingPromises.delete(e),s(l)},void 0,a)});return this.loadingPromises.set(e,t),t}async loadModel(e){if(this.loadedAssets.has(e))return this.loadedAssets.get(e).scene.clone();if(this.loadingPromises.has(e))return(await this.loadingPromises.get(e)).scene.clone();const t=new Promise((a,l)=>{this.gltfLoader.load(e,i=>{this.loadedAssets.set(e,i),this.loadingPromises.delete(e),a(i)},void 0,l)});return this.loadingPromises.set(e,t),(await t).scene.clone()}getMaterial(e,t){if(!this.materialCache.has(e)){const s=new c.MeshStandardMaterial({map:t.map,color:t.color,transparent:t.transparent,opacity:t.opacity,side:t.side,roughness:t.roughness||1,metalness:t.metalness||0});this.materialCache.set(e,s)}return this.materialCache.get(e).clone()}dispose(){this.loadedAssets.forEach(e=>{e.dispose&&e.dispose(),e.scene&&e.scene.traverse(t=>{t.geometry&&t.geometry.dispose(),t.material&&(Array.isArray(t.material)?t.material.forEach(s=>s.dispose()):t.material.dispose())})}),this.materialCache.forEach(e=>e.dispose()),this.loadedAssets.clear(),this.loadingPromises.clear(),this.materialCache.clear()}}class P{constructor(){this.tracked=new Set,this.stats={geometries:0,textures:0,materials:0,objects:0}}track(e){this.tracked.has(e)||(this.tracked.add(e),this.stats.objects++,e.traverse(t=>{t.geometry&&this.stats.geometries++,t.material&&(Array.isArray(t.material)?(this.stats.materials+=t.material.length,t.material.forEach(s=>{s.map&&this.stats.textures++})):(this.stats.materials++,t.material.map&&this.stats.textures++))}))}untrack(e){this.tracked.has(e)&&(this.tracked.delete(e),this.stats.objects--,e.traverse(t=>{t.geometry&&this.stats.geometries--,t.material&&(Array.isArray(t.material)?(this.stats.materials-=t.material.length,t.material.forEach(s=>{s.map&&this.stats.textures--})):(this.stats.materials--,t.material.map&&this.stats.textures--))}))}getStats(){return{...this.stats}}dispose(e){this.untrack(e),e.traverse(t=>{t.geometry&&t.geometry.dispose(),t.material&&(Array.isArray(t.material)?t.material.forEach(s=>{s.map&&s.map.dispose(),s.dispose()}):(t.material.map&&t.material.map.dispose(),t.material.dispose()))})}}n.AssetManager=T,n.MemoryManager=P,n.TextureAtlasManager=A,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})});