@hology/core 0.0.260 → 0.0.262
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/dist/gameplay/actors/actor.d.ts +4 -0
- package/dist/gameplay/actors/actor.js +1 -1
- package/dist/gameplay/actors/builtin/components/actor-transform-persistence.d.ts +29 -0
- package/dist/gameplay/actors/builtin/components/actor-transform-persistence.js +4 -0
- package/dist/gameplay/ai/navigation.js +1 -1
- package/dist/gameplay/index.d.ts +3 -0
- package/dist/gameplay/index.js +1 -1
- package/dist/gameplay/initiate.d.ts +4 -0
- package/dist/gameplay/initiate.js +1 -1
- package/dist/gameplay/inject.d.ts +8 -0
- package/dist/gameplay/inject.js +1 -1
- package/dist/gameplay/net/service/net-decorator.d.ts +9 -5
- package/dist/gameplay/net/service/net-decorator.js +1 -1
- package/dist/gameplay/net/service/net-service.js +1 -1
- package/dist/gameplay/services/actor-persistence.d.ts +69 -0
- package/dist/gameplay/services/actor-persistence.js +4 -0
- package/dist/gameplay/services/asset-loader.d.ts +3 -0
- package/dist/gameplay/services/asset-loader.js +1 -1
- package/dist/gameplay/services/render.d.ts +1 -1
- package/dist/gameplay/services/scene-transition.js +1 -1
- package/dist/gameplay/services/world.d.ts +10 -1
- package/dist/gameplay/services/world.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/rendering/graphics-runtime.d.ts +1 -1
- package/dist/rendering/graphics-runtime.js +1 -1
- package/dist/rendering/node-material-webgpu-resolver.js +1 -1
- package/dist/rendering/webgpu-experimental-backend.js +1 -1
- package/dist/rendering.d.ts +6 -1
- package/dist/rendering.js +1 -1
- package/dist/scene/asset-resource-loader.d.ts +3 -0
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/bootstrap.d.ts +2 -0
- package/dist/scene/bootstrap.js +1 -1
- package/dist/scene/custom-param-deserialize.js +1 -1
- package/dist/scene/custom-param-runtime-types.js +1 -1
- package/dist/scene/lattice-deformation.d.ts +28 -0
- package/dist/scene/lattice-deformation.js +4 -0
- package/dist/scene/materializer.d.ts +22 -3
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/model-ref.d.ts +7 -0
- package/dist/scene/model-ref.js +4 -0
- package/dist/scene/model.d.ts +2 -1
- package/dist/scene/model.js +1 -1
- package/dist/shader/parameter.d.ts +2 -1
- package/dist/shader-nodes/pom.js +1 -1
- package/dist/test/actor-persistence-runtime.test.d.ts +2 -0
- package/dist/test/actor-persistence-runtime.test.js +4 -0
- package/dist/test/actor-persistence.test.d.ts +2 -0
- package/dist/test/actor-persistence.test.js +4 -0
- package/dist/test/actor-transform-persistence.test.d.ts +2 -0
- package/dist/test/actor-transform-persistence.test.js +4 -0
- package/dist/test/graphics-runtime.test.js +1 -1
- package/dist/test/lattice-deformation.test.d.ts +2 -0
- package/dist/test/lattice-deformation.test.js +4 -0
- package/dist/test/materializer-prefetch.test.js +1 -1
- package/dist/test/prefab-instance-params.test.js +1 -1
- package/dist/test/world-lifecycle.test.js +1 -1
- package/dist/test/world-prefab-spawn.test.js +1 -1
- package/docs/actor-persistence.md +87 -0
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{AudioLoader as e,BufferGeometry as t,Euler as r,Group as a,LoadingManager as s,Mesh as i,Object3D as n,Texture as o,TextureLoader as l,Vector3 as c}from"three";import{MTLLoader as h,OBJLoader as u,LUTCubeLoader as m}from"three-stdlib";import{cloneMesh as d,mergeCompatibleSkinnedMeshes as f}from"../utils/mesh.js";import{pathJoin as p}from"../utils/files.js";import{Subject as g,firstValueFrom as y}from"rxjs";import{BoxCollisionShape as w,CapsuleCollisionShape as x,CollisionShapeSource as M,CylinderCollisionShape as b,SphereCollisionShape as A}from"./collision/collision-shape.js";import{importCollisionShapes as L,isCollisionMesh as S}from"./collision/collision-shape-import.js";import*as _ from"three";import{iterateMaterials as v}from"../utils/materials.js";import{applyMaterial as T,getConvertedFbxToGlbAssignedMaterialTextureFlipY as R}from"./materializer.js";import{BufferGeometryUtils as C,DRACOLoader as P,EXRLoader as F,FBXLoader as K,GLTFLoader as k,KTX2Loader as I,TGALoader as B,UltraHDRLoader as j}from"three/examples/jsm/Addons.js";import{disposeScene as D}from"../utils/three/cleanup.js";import{resolveAnimationRigBasisRotation as W,setAnimationClipRigId as U}from"../gameplay/animation/retarget.js";(()=>{const e=new Uint8Array([255,0,0,255]),t=new _.DataTexture(e,1,1,_.RGBAFormat);t.needsUpdate=!0})();const z=new P;z.setDecoderConfig({type:"js"}),z.setDecoderPath("/assets/draco/");const G=["glb","gltf","fbx","obj"];export class AssetResourceLoader{onError(e){console.error(e)}constructor(){this.cache=new Map,this.textureCache=new Map,this.loadingManager=new s,this.glbLoader=new k(this.loadingManager).setDRACOLoader(z),this.fbxLoader=new K(this.loadingManager),this.objLoader=new u(this.loadingManager),this.textureLoader=new l(this.loadingManager),this.tgaLoader=new B(this.loadingManager),this.exrLoader=new F(this.loadingManager),this.cubeLoader=new m(this.loadingManager),this.hdrLoader=new j(this.loadingManager),this.ktx2Loader=new I(this.loadingManager),this.ktx2Ready=Promise.resolve(),this._textureLoader=new _.ImageBitmapLoader(this.loadingManager),this.audioLoader=new e(this.loadingManager),this.initialisedKtx2=!1,this._retrievedMeshes=[],this._retrievedTextures=[],this.makeReady=new g,this.ready=y(this.makeReady),this.directFileLoading=!1,this._texturePromises=new Map,this._arrayTexturesByFileKey=new Map,this._arrayTexturePromisesByFileKey=new Map,this._arrayTextureSettingsByFileKey=new Map,this._animationPromises=new Map,this._animationCache=new Map,this.asyncMeshResults=new Map,this.asyncAudioResults=new Map,this.collisionShapeCache=new Map,this.optimizedMeshes=new Set}setDirectFileLoading(e){this.directFileLoading=e}configureKtx2(){this.initialisedKtx2=!0;null!=getElectronArg("windowId")||import.meta.url.includes(".vite")||import.meta.url.includes("hology/packages/core")?this.ktx2Loader.setTranscoderPath("/assets/basis/"):this.ktx2Loader.setTranscoderPath(new URL("../assets/basis/",import.meta.url).href),this.ktx2Loader.setWorkerLimit(6)}initKtx2(e){this.configureKtx2(),this.ktx2Loader.detectSupport(e)}initKtx2ForWebGpu(){this.configureKtx2(),this.ktx2Ready=Promise.resolve(navigator.gpu?.requestAdapter({powerPreference:"high-performance"})??null).then(e=>{this.ktx2Loader.detectSupport({isWebGPURenderer:!0,hasFeature:t=>!0===e?.features.has(t)})})}setDataDir(e){this.basePath=p(e,"asset-resources"),this.makeReady.next(!0)}getUri(e){const t=function(e){return E.get(e)}(e),r=getElectronArg("windowId");return null!=r||import.meta.url.includes(".vite")||import.meta.url.includes("hology/packages/core")?p(this.basePath,e)+(null!=r?`?windowId=${r}${null!=t?`&v=${t}`:""}`:""):new URL(p("..",this.basePath,e),import.meta.url).href}async getTexture(e){if(!e||!e.fileKey)return null;if("png"===e.fileFormat||e.fileFormat,this._texturePromises.has(e.id))return this._texturePromises.get(e.id);const t=this._getTexture(e).finally(()=>{this._texturePromises.delete(e.id)});return this._texturePromises.set(e.id,t),t}async _getTexture(e){if(null==e||null==e.fileKey)return null;if(await this.ready,e.fileKey.toLowerCase().endsWith(".ktx2")&&await this.ktx2Ready,this.textureCache.has(e.id)){const t=this.textureCache.get(e.id);if(null!=e.texture){const r=q(t,e);t.flipY!==r?(t.needsUpdate=!0,t.flipY=r):t.wrapS!==Y(e.texture?.wrapS)?(t.needsUpdate=!0,t.wrapS=Y(e.texture?.wrapS)):t.wrapT!==Y(e.texture?.wrapT)&&(t.wrapT=Y(e.texture?.wrapT),t.needsUpdate=!0)}const r=V(X(e));t.colorSpace!==r&&(t.colorSpace=r,t.needsUpdate=!0)}else try{const t=this._getTextureLoader(e.fileKey),r=this.directFileLoading&&t===this.textureLoader;await(r?this._textureLoader:t).loadAsync(this.getUri(e.fileKey)).then(t=>(r&&((t=new o(t)).needsUpdate=!0),t.texture3D?t=t.texture3D:(t.wrapS=Y(e.texture?.wrapS),t.wrapT=Y(e.texture?.wrapT),t.flipY=q(t,e),t.colorSpace=V(X(e))),this.textureCache.set(e.id,t),this._retrievedTextures.push(t),t))}catch(t){return console.warn("Failed to load texture "+e.name,t),null}const t=this.textureCache.get(e.id);return null!=t&&(t.userData.assetId=e.id),t}async getTextureArray(e){const t=e.texture?.textureArrayFileKey,r=e.texture?.textureArrayLayer;if(!t||null==r)return{texture:null,layerIndex:null};let a=this._arrayTexturesByFileKey.get(t);if(null==a){let e=this._arrayTexturePromisesByFileKey.get(t);null==e&&(e=this.loadTextureArray(t).finally(()=>{this._arrayTexturePromisesByFileKey.delete(t)}),this._arrayTexturePromisesByFileKey.set(t,e)),a=await e}return this.applyTextureArraySettings(t,a,e),{texture:a,layerIndex:r}}async loadTextureArray(e){const t=this._getTextureLoader(e);let r=await t.loadAsync(this.getUri(e));return r instanceof o||(r=r.texture3D),this._arrayTexturesByFileKey.set(e,r),this._retrievedTextures.push(r),r}applyTextureArraySettings(e,t,r){const a=function(e){return{wrapS:Y(e.texture?.wrapS),wrapT:Y(e.texture?.wrapT)}}(r),s=this._arrayTextureSettingsByFileKey.get(e);if(null!=s&&(n=a,(i=s).wrapS!==n.wrapS||i.wrapT!==n.wrapT))return void console.warn(`Texture array ${e} is used with incompatible texture settings. Texture arrays share wrapping; rebuild arrays so incompatible textures are grouped separately.`);var i,n;null==s&&this._arrayTextureSettingsByFileKey.set(e,a);let o=!1;t.wrapS!==a.wrapS&&(t.wrapS=a.wrapS,o=!0),t.wrapT!==a.wrapT&&(t.wrapT=a.wrapT,o=!0),!1!==t.flipY&&(t.flipY=!1,o=!0),o&&(t.needsUpdate=!0)}_getTextureLoader(e){return e?.toLowerCase().endsWith(".tga")?this.tgaLoader:e?.toLowerCase().endsWith(".ktx2")?this.ktx2Loader:e?.toLowerCase().endsWith(".exr")?this.exrLoader:e?.toLowerCase().endsWith(".cube")?this.cubeLoader:this.textureLoader}clearCache(e){this.clearCacheByAsset(e)}clearCacheByAsset(e){null!=e&&(this.clearCacheById(e.id),null!=e.fileKey&&(Array.from(this.cache.keys()).forEach(t=>{t.startsWith(e.fileKey)&&this.cache.delete(t)}),Array.from(this.asyncMeshResults.keys()).forEach(t=>{t.startsWith(e.fileKey)&&this.asyncMeshResults.delete(t)}),Array.from(this._animationCache.keys()).forEach(t=>{t.startsWith(e.fileKey+"|")&&this._animationCache.delete(t)}),Array.from(this._animationPromises.keys()).forEach(t=>{t.startsWith(e.fileKey+"|")&&this._animationPromises.delete(t)}),$(e.fileKey)),null!=e.materialLib&&$(e.materialLib))}clearCacheById(e){const t=Array.from(this.cache.values()).find(t=>t.scene.userData.assetId===e);t&&Array.from(this.cache.keys()).forEach(e=>{this.cache.get(e)===t&&this.cache.delete(e)}),this.textureCache.delete(e),this._texturePromises.delete(e),Array.from(this.collisionShapeCache.keys()).forEach(t=>{t.startsWith(e+"|")&&this.collisionShapeCache.delete(t)})}async getMesh(e,t){if(await this.ready,null==e)return console.error("No asset was provided"),{scene:new a,animations:[]};if(!G.includes(e.fileFormat?.toLowerCase()))return console.error("Unsupported mesh file format "+e.fileFormat,e),{scene:new a,animations:[]};const r=e.fileKey+(!0===t?.mergeGeomtries?"1":"0");if(!this.cache.has(r))try{this.asyncMeshResults.has(r)||this.asyncMeshResults.set(r,this.loadMesh(e).finally(()=>this.asyncMeshResults.delete(r))),this.cache.set(r,await this.asyncMeshResults.get(r))}catch(e){return this.onError(e),{scene:new a,animations:[]}}const s=this.cache.get(r),n=s.scene,o=s.animations;if(!1===t?.clone)return{scene:n,animations:o};const l=this.computeCollisionShapes(e,n),c=(e.mesh?.secondaryMotion?.regions.length??0)>0;!0!==t?.mergeGeomtries||c||this.optimizeDrawGroups(n);const h=d(n);h.traverse(e=>{e instanceof i&&e.material instanceof Array&&(e.material=e.material.slice())});const u=new AssetMeshInstance;u.add(h),u.collisionShapes=l,u.animations=o,u.userData.assetId=e.id,u.userData.secondaryMotion=e.mesh?.secondaryMotion,function(e){const t=e.children.length>0?e.children:[e];for(let e=0;e<t.length;e++)r(t[e],"",e);function r(e,t,a){const s=e instanceof i?"Mesh":"Group",n=`${t}/${e.name?.trim()?.length>0?e.name:s}[${a}]`;e.userData.secondaryMotionMeshPath=n;for(let t=0;t<e.children.length;t++)r(e.children[t],n,t)}}(u);const m=e.mesh?.animationRigId??e.anim?.rigId;if(u.userData.animationRigId=m,h.userData.animationRigId=m,null!=m&&null!=this.animationRigProvider){const e=await this.animationRigProvider(m);u.userData.animationRig=e,h.userData.animationRig=e,null!=e&&!1!==t?.applyRigBasis&&u.quaternion.copy(W(e))}const f=e.receiveShadow??!1,p=e.castShadow??!1;if(h.traverse(e=>{e.castShadow=p,e.receiveShadow=f}),!0===t?.rescale&&"number"==typeof e.mesh?.rescale&&u.scale.setScalar(e.mesh?.rescale),!0===t?.applyMaterials){const r=t?.materialResolver??this.materialProvider;if(null!=r)for(const t of e.materialAssignments??[])await T(u,t,r,void 0,{textureFlipY:R(e)});else console.warn(`applyMaterials was set to true for ${e.name} but no material resolver was provided.`)}return{scene:u,animations:o}}async getAudio(e){await this.ready;const t=e.fileKey;if(this.asyncAudioResults.has(t))return await this.asyncAudioResults.get(t);const r=this.audioLoader.loadAsync(this.getUri(e.fileKey)).finally(()=>{setTimeout(()=>{this.asyncAudioResults.delete(t)},1e3)});return this.asyncAudioResults.set(t,r),r}async getAnimationClip(e){if(null==e||null==e.fileKey||null==e.anim?.clip)return console.warn("Asset or animation clip name is not defined",e),null;const t=e.anim.clip,r=e.fileKey+"|"+t;if(this._animationCache.has(r))return this._animationCache.get(r);if(this._animationPromises.has(r))return this._animationPromises.get(r);const a=(async()=>{try{const a=await this.getMesh(e),s=a.animations.find(e=>e.name===t);return null!=s&&(U(s,e.anim?.rigId),this._animationCache.set(r,s)),s}catch(e){return this.onError(e),null}finally{setTimeout(()=>this._animationPromises.delete(r),1e3)}})();return this._animationPromises.set(r,a),a}computeCollisionShapes(e,t){if(!0!==e.collisionDetection)return[];const r=e.id+"|"+(e.mesh?.collisions?.shapeType??"")+"|"+(e.mesh?.rescale??1)+"|"+JSON.stringify(e.mesh?.colliders??[]);if(!this.collisionShapeCache.has(r)){const a=e.mesh?.colliders??[],s=a.length>0?createAuthoredCollisionShapes(a,e.mesh?.rescale):L(t,e);this.collisionShapeCache.set(r,s)}return this.collisionShapeCache.get(r)}async loadMesh(e){return await this.ready,await this.loadByAsset(e).then(r=>(r.scene.traverse(r=>{if(r instanceof i&&r.geometry instanceof t){const t=removeInvalidFaces(r.geometry);t>0&&console.warn(`Removed ${t} invalid face${1===t?"":"s"} from ${e.name}/${r.name||"unnamed mesh"}`)}r instanceof i&&r.material&&function(e){let t=e.material;if(null==t)return;Array.isArray(t)?e.material=t.map(Q):e.material=Q(t)}(r),S(r)?r.visible=!1:r instanceof i&&r.geometry instanceof t&&(r.geometry.hasAttribute("normal")||r.geometry.computeVertexNormals())}),this._retrievedMeshes.push(r.scene),r.scene=function(e,t){let r=!1;if(t.traverseVisible(e=>{H.test(e.name)&&(r=!0)}),!r)return t;const a=[],s=[t];for(;s.length>0;){const e=s.shift(),t=e.name.match(H);if(null!=t){const r=parseInt(t[1]);if(0!==r){console.warn(`Skipping LOD level ${r} for now as LOD is not fully supported`),a.push(e);continue}}s.push(...e.children)}for(const e of a)e.removeFromParent();return t}(0,r.scene),function(e){const t=Z;Z.length=0,e.traverse(e=>{(e instanceof _.Camera||e instanceof _.Light)&&t.push(e)}),t.forEach(e=>e.removeFromParent())}(r.scene),r.scene.userData.assetId=e.id,r))}optimizeDrawGroups(e){if(this.optimizedMeshes.has(e.uuid))return;this.optimizedMeshes.add(e.uuid),e.updateWorldMatrix(!0,!0);const r=[];e.traverse(e=>{e instanceof i&&!(e instanceof _.SkinnedMesh)&&e.geometry instanceof t&&Array.isArray(e.material)&&!S(e)&&r.push({mesh:e,geometry:e.geometry,materialArray:e.material,parent:e.parent})});for(const{mesh:t,geometry:a,materialArray:s,parent:n}of r){t.removeFromParent();for(let r=0;r<s.length;r++){const o=s[r],l=a.groups.filter(e=>e.materialIndex===r);if(0===l.length)continue;const c=this.extractGeometryGroups(a,l);c.groups.length>1&&C.mergeGroups(c);const h=new i(c,o);h.copy(t,!1),h.geometry=c,h.material=o,n?n.add(h):e.add(h)}a.dispose()}f(e,S);let a=!0,s=0,n=0;if(e.traverse(e=>{if(e instanceof i&&e.geometry instanceof t&&!S(e)){s++;const t=Object.keys(e.geometry.attributes).length;t!==n&&0!==n&&(a=!1),n=t}else(e instanceof _.SkinnedMesh||e instanceof _.Bone)&&(a=!1)}),s>1&&a){const r=new Map;e.traverse(a=>{if(a instanceof i&&a.geometry instanceof t&&!S(a)){if(Array.isArray(a.material))return;a.updateWorldMatrix(!0,!0);const t=a.material?.uuid||"default";r.has(t)||r.set(t,{material:a.material,geometries:[],objects:[]});const s=r.get(t),i=e.matrixWorld.clone().invert().multiply(a.matrixWorld);s.geometries.push(a.geometry.clone().applyMatrix4(i)),s.objects.push(a)}});for(const e of r.values())for(const t of e.objects)t.removeFromParent();for(const t of r.values()){let r,a=t.geometries;if(a.some(e=>null!=e.index)&&(a=a.map(e=>{if(null!=e.index)return e;const t=e.getAttribute("position");if(null==t)return e;const r=t.count>65535?new Uint32Array(t.count):new Uint16Array(t.count);for(let e=0;e<r.length;e++)r[e]=e;return e.setIndex(new _.BufferAttribute(r,1)),e})),r=1===t.geometries.length?a[0]:O(a)?C.mergeGeometries(a,!0):null,null!=r)r.groups.length>1&&C.mergeGroups(r),e.add(new i(r,t.material));else for(const r of a)e.add(new i(r,t.material))}}e.traverse(e=>{if(e instanceof i&&e.geometry instanceof t&&!S(e)){const t=e.geometry;!Array.isArray(e.material)&&t.groups.length>1&&C.mergeGroups(t)}})}extractGeometryGroups(e,r){const a=e.index;if(!a){const a=new t;let s=0;for(const e of r)s+=e.count;if(0===s)return a;for(const t in e.attributes){const i=e.attributes[t],n=i.itemSize,o=i.array,l=new(0,o.constructor)(s*n);let c=0;for(const e of r){const t=e.start*n,r=e.count*n;for(let e=0;e<r;e++)l[c+e]=o[t+e];c+=r}const h=new _.BufferAttribute(l,n,i.normalized);a.setAttribute(t,h)}return a.groups=[{start:0,count:s,materialIndex:0}],a}const s=[];for(const e of r)for(let t=0;t<e.count;t++){const r=a.getX(e.start+t);s.push(r)}if(0===s.length)return new t;const i=new Map,n=[];let o=0;for(const e of s)i.has(e)||(i.set(e,o),o++),n.push(i.get(e));if(0===n.length||0===i.size)return new t;const l=new t;for(const t in e.attributes){const r=e.attributes[t],a=r.itemSize,s=r.array,n=new(0,s.constructor)(i.size*a);for(const[e,t]of i)for(let r=0;r<a;r++)n[t*a+r]=s[e*a+r];const o=new _.BufferAttribute(n,a,r.normalized);l.setAttribute(t,o)}const c=new((n.length>0?Math.max(...n):0)>65535?Uint32Array:Uint16Array)(n.length);for(let e=0;e<n.length;e++)c[e]=n[e];return l.setIndex(new _.BufferAttribute(c,1)),l.groups=[{start:0,count:n.length,materialIndex:0}],l}async loadByAsset(e){this.fbxLoader;const t=this.getUri(e.fileKey);switch(e.fileFormat){case"glb":case"gltf":return this.glbLoader.loadAsync(t).then(t=>{const r=!0===e.originalFileKey?.toLowerCase().endsWith(".fbx")&&1===t.scene.children.length?t.scene.children[0]:t.scene;return r!==t.scene&&t.scene.remove(r),{scene:r,animations:t.animations}});case"fbx":if(this.directFileLoading){const e=await fetch(t);if(!e.ok)throw new Error(`Failed to load FBX ${t}: ${e.status}`);const r=await e.arrayBuffer(),a=this.fbxLoader.parse(r,_.LoaderUtils.extractUrlBase(t));return{scene:a,animations:a.animations}}return this.fbxLoader.loadAsync(t).then(e=>({scene:e,animations:e.animations}));case"obj":if(null!=e.materialLib){const t=new h;t.materialOptions={normalizeRGB:!1};const r=await t.loadAsync(this.getUri(e.materialLib));this.objLoader.setMaterials(r)}return this.objLoader.loadAsync(t).then(e=>(N(e),e)).then(e=>({scene:e,animations:e.animations}))}}disposeAll(){this.cache.clear(),this._retrievedMeshes.forEach(e=>D(e)),this._retrievedTextures.forEach(e=>e.dispose()),this._retrievedMeshes.length=0,this._retrievedTextures.length=0}}const E=new Map;function $(e){E.set(e,(E.get(e)??0)+1)}function O(e){if(e.length<2)return!0;const t=e[0],r=Object.keys(t.attributes).sort(),a=Object.keys(t.morphAttributes).sort();return e.slice(1).every(e=>{if(null==e.index!=(null==t.index))return!1;if(e.morphTargetsRelative!==t.morphTargetsRelative)return!1;const s=Object.keys(e.attributes).sort(),i=Object.keys(e.morphAttributes).sort();if(s.join("|")!==r.join("|"))return!1;if(i.join("|")!==a.join("|"))return!1;for(const a of r){const r=t.getAttribute(a),s=e.getAttribute(a);if(r.itemSize!==s.itemSize||r.normalized!==s.normalized||r.array.constructor!==s.array.constructor)return!1}for(const r of a){const a=t.morphAttributes[r],s=e.morphAttributes[r];if(a.length!==s.length)return!1;for(let e=0;e<a.length;e++)if(a[e].itemSize!==s[e].itemSize||a[e].normalized!==s[e].normalized||a[e].array.constructor!==s[e].array.constructor)return!1}return!0})}function N(e){if(e instanceof i)for(const t of v(e.material))t instanceof _.MeshPhongMaterial&&!t.color.isLinear&&(t.color.isLinear=!0);e.children?.forEach(N)}export class AssetMeshInstance extends n{}export function createAuthoredCollisionShapes(e,t=1){const a=null!=t&&0!==t?1/t:1;return e.map(e=>{let t;switch(e.type){case"box":t=new w((new c).fromArray(e.size).multiplyScalar(a));break;case"sphere":t=new A(e.radius*a);break;case"capsule":t=new x(e.length*a,e.radius*a);break;case"cylinder":t=new b(e.radius*a,e.radius*a,e.height*a,16,new r)}return t.source=M.custom,t.offset.fromArray(e.position??[0,0,0]).multiplyScalar(a),t.rotation.fromArray(e.rotation??[0,0,0,"XYZ"]),t})}export function getElectronArg(e){const t=`--${e}=`,r=window.process?.argv.find(e=>e.startsWith(t));return r?.substring(t.length)}function Y(e){switch(e){case"clamp":return _.ClampToEdgeWrapping;case"repeat":return _.RepeatWrapping;case"mirror":return _.MirroredRepeatWrapping}return _.RepeatWrapping}function q(e,t){const r=e;return!0!==r.isCompressedTexture&&!0!==r.isCompressedArrayTexture&&(t.texture?.flipY??!0)}function X(e){return e.texture?.colorSpace??function(e){if("exr"===e.fileFormat||e.fileKey?.toLowerCase().endsWith(".exr"))return"linear";const t=`${e.name} ${e.fileKey??""}`.toLowerCase();if(J.some(e=>t.includes(e)))return"linear";return"srgb"}(e)}function V(e){return"linear"===e?_.LinearSRGBColorSpace:_.SRGBColorSpace}const J=["_normal","_nrm","_nor","_norm","_roughness","_rough","_metalness","_metallic","_metal","_ao","_ambient","_occlusion","_mask","_height","_disp","_displacement","_bump","_opacity"];new _.Matrix4;const Z=[];const H=/_LOD(\d+)/;export function removeInvalidFaces(e){const t=e.getAttribute("position");if(null==t||t.itemSize<3)return 0;const r=e.index,a=r?.count??t.count,s=Math.floor(a/3),i=[],n=new Uint32Array(s+1),o=new c,l=new c,h=new c;let u=0;for(let e=0;e<s;e++){const a=3*e,s=r?.getX(a)??a,c=r?.getX(a+1)??a+1,m=r?.getX(a+2)??a+2;let d=Number.isInteger(s)&&Number.isInteger(c)&&Number.isInteger(m)&&s>=0&&c>=0&&m>=0&&s<t.count&&c<t.count&&m<t.count;if(d){o.fromBufferAttribute(t,s),l.fromBufferAttribute(t,c).sub(o),h.fromBufferAttribute(t,m).sub(o);const e=Math.max(l.lengthSq(),h.lengthSq(),l.distanceToSquared(h)),r=l.cross(h).lengthSq();d=Number.isFinite(e)&&Number.isFinite(r)&&e>0&&r>Number.EPSILON*e*e}d?i.push(s,c,m):u++,n[e+1]=i.length}if(0===u)return 0;if(e.setIndex(i),e.groups.length>0){const t=e.groups.slice();e.clearGroups();for(const r of t){const t=Math.max(0,Math.ceil(r.start/3)),a=Math.min(s,Math.floor((r.start+r.count)/3));if(a<=t)continue;const i=n[t],o=n[a]-i;o>0&&e.addGroup(i,o,r.materialIndex)}}const m=Math.max(0,Math.ceil(e.drawRange.start/3)),d=Number.isFinite(e.drawRange.count)?Math.min(s,Math.floor((e.drawRange.start+e.drawRange.count)/3)):s,f=Math.min(m,s),p=Math.min(s,Math.max(f,d)),g=n[f];return e.setDrawRange(g,n[p]-g),u}function Q(e){let t=e instanceof _.MeshPhysicalMaterial&&0===e.sheen&&0===e.anisotropy;if("MeshLambertMaterial"===e.type||"MeshPhongMaterial"===e.type||t){let t={};(e instanceof _.MeshLambertMaterial||e instanceof _.MeshPhongMaterial||e instanceof _.MeshPhysicalMaterial)&&(t.color=e.color,t.map=e.map,t.bumpMap=e.bumpMap,t.bumpScale=e.bumpScale,t.lightMap=e.lightMap,t.lightMapIntensity=e.lightMapIntensity,t.aoMap=e.aoMap,t.aoMapIntensity=e.aoMapIntensity,t.emissiveMap=e.emissiveMap,t.alphaMap=e.alphaMap,t.envMap=e.envMap,t.envMapRotation=e.envMapRotation,t.wireframe=e.wireframe,t.wireframeLinewidth=e.wireframeLinewidth,t.fog=e.fog,t.opacity=e.opacity,t.transparent=e.transparent,t.side=e.side,t.depthTest=e.depthTest,t.depthWrite=e.depthWrite,t.alphaTest=e.alphaTest,t.displacementMap=e.displacementMap,t.displacementScale=e.displacementScale,t.displacementBias=e.displacementBias);const r=new _.MeshStandardMaterial(t);return r.userData={...e.userData??{}},r.name=e.name,r}return e}/*
|
|
1
|
+
import{AudioLoader as e,BufferGeometry as t,Euler as r,Group as a,LoadingManager as s,Mesh as i,Object3D as n,Texture as o,TextureLoader as l,Vector3 as c}from"three";import{MTLLoader as h,OBJLoader as u,LUTCubeLoader as m}from"three-stdlib";import{cloneMesh as d,mergeCompatibleSkinnedMeshes as p}from"../utils/mesh.js";import{pathJoin as f}from"../utils/files.js";import{Subject as g,firstValueFrom as y}from"rxjs";import{BoxCollisionShape as w,CapsuleCollisionShape as x,CollisionShapeSource as M,CylinderCollisionShape as b,SphereCollisionShape as A}from"./collision/collision-shape.js";import{importCollisionShapes as L,isCollisionMesh as S}from"./collision/collision-shape-import.js";import*as _ from"three";import{iterateMaterials as v}from"../utils/materials.js";import{applyMaterial as T,getConvertedFbxToGlbAssignedMaterialTextureFlipY as R}from"./materializer.js";import{BufferGeometryUtils as C,DRACOLoader as B,EXRLoader as P,FBXLoader as I,GLTFLoader as k,KTX2Loader as F,TGALoader as K,UltraHDRLoader as D}from"three/examples/jsm/Addons.js";import{disposeScene as j}from"../utils/three/cleanup.js";import{resolveAnimationRigBasisRotation as W,setAnimationClipRigId as U}from"../gameplay/animation/retarget.js";(()=>{const e=new Uint8Array([255,0,0,255]),t=new _.DataTexture(e,1,1,_.RGBAFormat);t.needsUpdate=!0})();const z=new B;z.setDecoderConfig({type:"js"}),z.setDecoderPath("/assets/draco/");const G=["glb","gltf","fbx","obj"];export class AssetResourceLoader{onError(e){console.error(e)}constructor(){this.cache=new Map,this.textureCache=new Map,this.loadingManager=new s,this.glbLoader=new k(this.loadingManager).setDRACOLoader(z),this.fbxLoader=new I(this.loadingManager),this.objLoader=new u(this.loadingManager),this.textureLoader=new l(this.loadingManager),this.tgaLoader=new K(this.loadingManager),this.exrLoader=new P(this.loadingManager),this.cubeLoader=new m(this.loadingManager),this.hdrLoader=new D(this.loadingManager),this.ktx2Loader=new F(this.loadingManager),this.ktx2Ready=Promise.resolve(),this._textureLoader=new _.ImageBitmapLoader(this.loadingManager),this.audioLoader=new e(this.loadingManager),this.initialisedKtx2=!1,this._retrievedMeshes=[],this._retrievedTextures=[],this.makeReady=new g,this.ready=y(this.makeReady),this.directFileLoading=!1,this._texturePromises=new Map,this._arrayTexturesByFileKey=new Map,this._arrayTexturePromisesByFileKey=new Map,this._arrayTextureSettingsByFileKey=new Map,this._animationPromises=new Map,this._animationCache=new Map,this.asyncMeshResults=new Map,this.asyncAudioResults=new Map,this.collisionShapeCache=new Map,this.optimizedMeshes=new Set}setDirectFileLoading(e){this.directFileLoading=e}setImageBitmapDecoder(e){this.imageBitmapDecoder=e}decodeImageBitmap(e){return this.imageBitmapDecoder?.(e)}configureKtx2(){this.initialisedKtx2=!0;null!=getElectronArg("windowId")||import.meta.url.includes(".vite")||import.meta.url.includes("hology/packages/core")?this.ktx2Loader.setTranscoderPath("/assets/basis/"):this.ktx2Loader.setTranscoderPath(new URL("../assets/basis/",import.meta.url).href),this.ktx2Loader.setWorkerLimit(6)}initKtx2(e){this.configureKtx2(),this.ktx2Loader.detectSupport(e)}initKtx2ForWebGpu(){this.configureKtx2(),this.ktx2Ready=Promise.resolve(navigator.gpu?.requestAdapter({powerPreference:"high-performance"})??null).then(e=>{this.ktx2Loader.detectSupport({isWebGPURenderer:!0,hasFeature:t=>!0===e?.features.has(t)})})}setDataDir(e){this.basePath=f(e,"asset-resources"),this.makeReady.next(!0)}getUri(e){if(e.startsWith("asset://"))return e;const t=function(e){return $.get(e)}(e),r=getElectronArg("windowId");return null!=r||import.meta.url.includes(".vite")||import.meta.url.includes("hology/packages/core")?f(this.basePath,e)+(null!=r?`?windowId=${r}${null!=t?`&v=${t}`:""}`:""):new URL(f("..",this.basePath,e),import.meta.url).href}async getTexture(e){if(!e||!e.fileKey)return null;if("png"===e.fileFormat||e.fileFormat,this._texturePromises.has(e.id))return this._texturePromises.get(e.id);const t=this._getTexture(e).finally(()=>{this._texturePromises.delete(e.id)});return this._texturePromises.set(e.id,t),t}async _getTexture(e){if(null==e||null==e.fileKey)return null;if(await this.ready,e.fileKey.toLowerCase().endsWith(".ktx2")&&await this.ktx2Ready,this.textureCache.has(e.id)){const t=this.textureCache.get(e.id);if(null!=e.texture){const r=q(t,e);t.flipY!==r?(t.needsUpdate=!0,t.flipY=r):t.wrapS!==Y(e.texture?.wrapS)?(t.needsUpdate=!0,t.wrapS=Y(e.texture?.wrapS)):t.wrapT!==Y(e.texture?.wrapT)&&(t.wrapT=Y(e.texture?.wrapT),t.needsUpdate=!0)}const r=V(X(e));t.colorSpace!==r&&(t.colorSpace=r,t.needsUpdate=!0)}else try{const t=this._getTextureLoader(e.fileKey),r=null!=this.imageBitmapDecoder&&/\.(png|jpe?g)$/i.test(e.fileKey),a=r||this.directFileLoading&&t===this.textureLoader,s=this.getUri(e.fileKey),i=r?this.imageBitmapDecoder(s).catch(t=>(console.warn(`Worker image decode failed for ${e.name}; falling back to ImageBitmapLoader`,t),this._textureLoader.loadAsync(s))):(a?this._textureLoader:t).loadAsync(s);await i.then(t=>(a&&((t=new o(t)).needsUpdate=!0),t.texture3D?t=t.texture3D:(t.wrapS=Y(e.texture?.wrapS),t.wrapT=Y(e.texture?.wrapT),t.flipY=q(t,e),t.colorSpace=V(X(e))),this.textureCache.set(e.id,t),this._retrievedTextures.push(t),t))}catch(t){return console.warn("Failed to load texture "+e.name,t),null}const t=this.textureCache.get(e.id);return null!=t&&(t.userData.assetId=e.id),t}async getTextureArray(e){const t=e.texture?.textureArrayFileKey,r=e.texture?.textureArrayLayer;if(!t||null==r)return{texture:null,layerIndex:null};let a=this._arrayTexturesByFileKey.get(t);if(null==a){let e=this._arrayTexturePromisesByFileKey.get(t);null==e&&(e=this.loadTextureArray(t).finally(()=>{this._arrayTexturePromisesByFileKey.delete(t)}),this._arrayTexturePromisesByFileKey.set(t,e)),a=await e}return this.applyTextureArraySettings(t,a,e),{texture:a,layerIndex:r}}async loadTextureArray(e){const t=this._getTextureLoader(e);let r=await t.loadAsync(this.getUri(e));return r instanceof o||(r=r.texture3D),this._arrayTexturesByFileKey.set(e,r),this._retrievedTextures.push(r),r}applyTextureArraySettings(e,t,r){const a=function(e){return{wrapS:Y(e.texture?.wrapS),wrapT:Y(e.texture?.wrapT)}}(r),s=this._arrayTextureSettingsByFileKey.get(e);if(null!=s&&(n=a,(i=s).wrapS!==n.wrapS||i.wrapT!==n.wrapT))return void console.warn(`Texture array ${e} is used with incompatible texture settings. Texture arrays share wrapping; rebuild arrays so incompatible textures are grouped separately.`);var i,n;null==s&&this._arrayTextureSettingsByFileKey.set(e,a);let o=!1;t.wrapS!==a.wrapS&&(t.wrapS=a.wrapS,o=!0),t.wrapT!==a.wrapT&&(t.wrapT=a.wrapT,o=!0),!1!==t.flipY&&(t.flipY=!1,o=!0),o&&(t.needsUpdate=!0)}_getTextureLoader(e){return e?.toLowerCase().endsWith(".tga")?this.tgaLoader:e?.toLowerCase().endsWith(".ktx2")?this.ktx2Loader:e?.toLowerCase().endsWith(".exr")?this.exrLoader:e?.toLowerCase().endsWith(".cube")?this.cubeLoader:this.textureLoader}clearCache(e){this.clearCacheByAsset(e)}clearCacheByAsset(e){null!=e&&(this.clearCacheById(e.id),null!=e.fileKey&&(Array.from(this.cache.keys()).forEach(t=>{t.startsWith(e.fileKey)&&this.cache.delete(t)}),Array.from(this.asyncMeshResults.keys()).forEach(t=>{t.startsWith(e.fileKey)&&this.asyncMeshResults.delete(t)}),Array.from(this._animationCache.keys()).forEach(t=>{t.startsWith(e.fileKey+"|")&&this._animationCache.delete(t)}),Array.from(this._animationPromises.keys()).forEach(t=>{t.startsWith(e.fileKey+"|")&&this._animationPromises.delete(t)}),E(e.fileKey)),null!=e.materialLib&&E(e.materialLib))}clearCacheById(e){const t=Array.from(this.cache.values()).find(t=>t.scene.userData.assetId===e);t&&Array.from(this.cache.keys()).forEach(e=>{this.cache.get(e)===t&&this.cache.delete(e)}),this.textureCache.delete(e),this._texturePromises.delete(e),Array.from(this.collisionShapeCache.keys()).forEach(t=>{t.startsWith(e+"|")&&this.collisionShapeCache.delete(t)})}async getMesh(e,t){if(await this.ready,null==e)return console.error("No asset was provided"),{scene:new a,animations:[]};if(!G.includes(e.fileFormat?.toLowerCase()))return console.error("Unsupported mesh file format "+e.fileFormat,e),{scene:new a,animations:[]};const r=e.fileKey+(!0===t?.mergeGeomtries?"1":"0");if(!this.cache.has(r))try{this.asyncMeshResults.has(r)||this.asyncMeshResults.set(r,this.loadMesh(e).finally(()=>this.asyncMeshResults.delete(r))),this.cache.set(r,await this.asyncMeshResults.get(r))}catch(e){return this.onError(e),{scene:new a,animations:[]}}const s=this.cache.get(r),n=s.scene,o=s.animations;if(!1===t?.clone)return{scene:n,animations:o};const l=this.computeCollisionShapes(e,n),c=(e.mesh?.secondaryMotion?.regions.length??0)>0;!0!==t?.mergeGeomtries||c||this.optimizeDrawGroups(n);const h=d(n);h.traverse(e=>{e instanceof i&&e.material instanceof Array&&(e.material=e.material.slice())});const u=new AssetMeshInstance;u.add(h),u.collisionShapes=l,u.animations=o,u.userData.assetId=e.id,u.userData.secondaryMotion=e.mesh?.secondaryMotion,function(e){const t=e.children.length>0?e.children:[e];for(let e=0;e<t.length;e++)r(t[e],"",e);function r(e,t,a){const s=e instanceof i?"Mesh":"Group",n=`${t}/${e.name?.trim()?.length>0?e.name:s}[${a}]`;e.userData.secondaryMotionMeshPath=n;for(let t=0;t<e.children.length;t++)r(e.children[t],n,t)}}(u);const m=e.mesh?.animationRigId??e.anim?.rigId;if(u.userData.animationRigId=m,h.userData.animationRigId=m,null!=m&&null!=this.animationRigProvider){const e=await this.animationRigProvider(m);u.userData.animationRig=e,h.userData.animationRig=e,null!=e&&!1!==t?.applyRigBasis&&u.quaternion.copy(W(e))}const p=e.receiveShadow??!1,f=e.castShadow??!1;if(h.traverse(e=>{e.castShadow=f,e.receiveShadow=p}),!0===t?.rescale&&"number"==typeof e.mesh?.rescale&&u.scale.setScalar(e.mesh?.rescale),!0===t?.applyMaterials){const r=t?.materialResolver??this.materialProvider;if(null!=r)for(const t of e.materialAssignments??[])await T(u,t,r,void 0,{textureFlipY:R(e)});else console.warn(`applyMaterials was set to true for ${e.name} but no material resolver was provided.`)}return{scene:u,animations:o}}async getAudio(e){await this.ready;const t=e.fileKey;if(this.asyncAudioResults.has(t))return await this.asyncAudioResults.get(t);const r=this.audioLoader.loadAsync(this.getUri(e.fileKey)).finally(()=>{setTimeout(()=>{this.asyncAudioResults.delete(t)},1e3)});return this.asyncAudioResults.set(t,r),r}async getAnimationClip(e){if(null==e||null==e.fileKey||null==e.anim?.clip)return console.warn("Asset or animation clip name is not defined",e),null;const t=e.anim.clip,r=e.fileKey+"|"+t;if(this._animationCache.has(r))return this._animationCache.get(r);if(this._animationPromises.has(r))return this._animationPromises.get(r);const a=(async()=>{try{const a=await this.getMesh(e),s=a.animations.find(e=>e.name===t);return null!=s&&(U(s,e.anim?.rigId),this._animationCache.set(r,s)),s}catch(e){return this.onError(e),null}finally{setTimeout(()=>this._animationPromises.delete(r),1e3)}})();return this._animationPromises.set(r,a),a}computeCollisionShapes(e,t){if(!0!==e.collisionDetection)return[];const r=e.id+"|"+(e.mesh?.collisions?.shapeType??"")+"|"+(e.mesh?.rescale??1)+"|"+JSON.stringify(e.mesh?.colliders??[]);if(!this.collisionShapeCache.has(r)){const a=e.mesh?.colliders??[],s=a.length>0?createAuthoredCollisionShapes(a,e.mesh?.rescale):L(t,e);this.collisionShapeCache.set(r,s)}return this.collisionShapeCache.get(r)}async loadMesh(e){return await this.ready,await this.loadByAsset(e).then(r=>(r.scene.traverse(r=>{if(r instanceof i&&r.geometry instanceof t){const t=removeInvalidFaces(r.geometry);t>0&&console.warn(`Removed ${t} invalid face${1===t?"":"s"} from ${e.name}/${r.name||"unnamed mesh"}`)}r instanceof i&&r.material&&function(e){let t=e.material;if(null==t)return;Array.isArray(t)?e.material=t.map(Q):e.material=Q(t)}(r),S(r)?r.visible=!1:r instanceof i&&r.geometry instanceof t&&(r.geometry.hasAttribute("normal")||r.geometry.computeVertexNormals())}),this._retrievedMeshes.push(r.scene),r.scene=function(e,t){let r=!1;if(t.traverseVisible(e=>{H.test(e.name)&&(r=!0)}),!r)return t;const a=[],s=[t];for(;s.length>0;){const e=s.shift(),t=e.name.match(H);if(null!=t){const r=parseInt(t[1]);if(0!==r){console.warn(`Skipping LOD level ${r} for now as LOD is not fully supported`),a.push(e);continue}}s.push(...e.children)}for(const e of a)e.removeFromParent();return t}(0,r.scene),function(e){const t=Z;Z.length=0,e.traverse(e=>{(e instanceof _.Camera||e instanceof _.Light)&&t.push(e)}),t.forEach(e=>e.removeFromParent())}(r.scene),r.scene.userData.assetId=e.id,r))}optimizeDrawGroups(e){if(this.optimizedMeshes.has(e.uuid))return;this.optimizedMeshes.add(e.uuid),e.updateWorldMatrix(!0,!0);const r=[];e.traverse(e=>{e instanceof i&&!(e instanceof _.SkinnedMesh)&&e.geometry instanceof t&&Array.isArray(e.material)&&!S(e)&&r.push({mesh:e,geometry:e.geometry,materialArray:e.material,parent:e.parent})});for(const{mesh:t,geometry:a,materialArray:s,parent:n}of r){t.removeFromParent();for(let r=0;r<s.length;r++){const o=s[r],l=a.groups.filter(e=>e.materialIndex===r);if(0===l.length)continue;const c=this.extractGeometryGroups(a,l);c.groups.length>1&&C.mergeGroups(c);const h=new i(c,o);h.copy(t,!1),h.geometry=c,h.material=o,n?n.add(h):e.add(h)}a.dispose()}p(e,S);let a=!0,s=0,n=0;if(e.traverse(e=>{if(e instanceof i&&e.geometry instanceof t&&!S(e)){s++;const t=Object.keys(e.geometry.attributes).length;t!==n&&0!==n&&(a=!1),n=t}else(e instanceof _.SkinnedMesh||e instanceof _.Bone)&&(a=!1)}),s>1&&a){const r=new Map;e.traverse(a=>{if(a instanceof i&&a.geometry instanceof t&&!S(a)){if(Array.isArray(a.material))return;a.updateWorldMatrix(!0,!0);const t=a.material?.uuid||"default";r.has(t)||r.set(t,{material:a.material,geometries:[],objects:[]});const s=r.get(t),i=e.matrixWorld.clone().invert().multiply(a.matrixWorld);s.geometries.push(a.geometry.clone().applyMatrix4(i)),s.objects.push(a)}});for(const e of r.values())for(const t of e.objects)t.removeFromParent();for(const t of r.values()){let r,a=t.geometries;if(a.some(e=>null!=e.index)&&(a=a.map(e=>{if(null!=e.index)return e;const t=e.getAttribute("position");if(null==t)return e;const r=t.count>65535?new Uint32Array(t.count):new Uint16Array(t.count);for(let e=0;e<r.length;e++)r[e]=e;return e.setIndex(new _.BufferAttribute(r,1)),e})),r=1===t.geometries.length?a[0]:O(a)?C.mergeGeometries(a,!0):null,null!=r)r.groups.length>1&&C.mergeGroups(r),e.add(new i(r,t.material));else for(const r of a)e.add(new i(r,t.material))}}e.traverse(e=>{if(e instanceof i&&e.geometry instanceof t&&!S(e)){const t=e.geometry;!Array.isArray(e.material)&&t.groups.length>1&&C.mergeGroups(t)}})}extractGeometryGroups(e,r){const a=e.index;if(!a){const a=new t;let s=0;for(const e of r)s+=e.count;if(0===s)return a;for(const t in e.attributes){const i=e.attributes[t],n=i.itemSize,o=i.array,l=new(0,o.constructor)(s*n);let c=0;for(const e of r){const t=e.start*n,r=e.count*n;for(let e=0;e<r;e++)l[c+e]=o[t+e];c+=r}const h=new _.BufferAttribute(l,n,i.normalized);a.setAttribute(t,h)}return a.groups=[{start:0,count:s,materialIndex:0}],a}const s=[];for(const e of r)for(let t=0;t<e.count;t++){const r=a.getX(e.start+t);s.push(r)}if(0===s.length)return new t;const i=new Map,n=[];let o=0;for(const e of s)i.has(e)||(i.set(e,o),o++),n.push(i.get(e));if(0===n.length||0===i.size)return new t;const l=new t;for(const t in e.attributes){const r=e.attributes[t],a=r.itemSize,s=r.array,n=new(0,s.constructor)(i.size*a);for(const[e,t]of i)for(let r=0;r<a;r++)n[t*a+r]=s[e*a+r];const o=new _.BufferAttribute(n,a,r.normalized);l.setAttribute(t,o)}const c=new((n.length>0?Math.max(...n):0)>65535?Uint32Array:Uint16Array)(n.length);for(let e=0;e<n.length;e++)c[e]=n[e];return l.setIndex(new _.BufferAttribute(c,1)),l.groups=[{start:0,count:n.length,materialIndex:0}],l}async loadByAsset(e){this.fbxLoader;const t=this.getUri(e.fileKey);switch(e.fileFormat){case"glb":case"gltf":return this.glbLoader.loadAsync(t).then(t=>{const r=!0===e.originalFileKey?.toLowerCase().endsWith(".fbx")&&1===t.scene.children.length?t.scene.children[0]:t.scene;return r!==t.scene&&t.scene.remove(r),{scene:r,animations:t.animations}});case"fbx":if(this.directFileLoading){const e=await fetch(t);if(!e.ok)throw new Error(`Failed to load FBX ${t}: ${e.status}`);const r=await e.arrayBuffer(),a=this.fbxLoader.parse(r,_.LoaderUtils.extractUrlBase(t));return{scene:a,animations:a.animations}}return this.fbxLoader.loadAsync(t).then(e=>({scene:e,animations:e.animations}));case"obj":if(null!=e.materialLib){const t=new h;t.materialOptions={normalizeRGB:!1};const r=await t.loadAsync(this.getUri(e.materialLib));this.objLoader.setMaterials(r)}return this.objLoader.loadAsync(t).then(e=>(N(e),e)).then(e=>({scene:e,animations:e.animations}))}}disposeAll(){this.cache.clear(),this._retrievedMeshes.forEach(e=>j(e)),this._retrievedTextures.forEach(e=>e.dispose()),this._retrievedMeshes.length=0,this._retrievedTextures.length=0}}const $=new Map;function E(e){$.set(e,($.get(e)??0)+1)}function O(e){if(e.length<2)return!0;const t=e[0],r=Object.keys(t.attributes).sort(),a=Object.keys(t.morphAttributes).sort();return e.slice(1).every(e=>{if(null==e.index!=(null==t.index))return!1;if(e.morphTargetsRelative!==t.morphTargetsRelative)return!1;const s=Object.keys(e.attributes).sort(),i=Object.keys(e.morphAttributes).sort();if(s.join("|")!==r.join("|"))return!1;if(i.join("|")!==a.join("|"))return!1;for(const a of r){const r=t.getAttribute(a),s=e.getAttribute(a);if(r.itemSize!==s.itemSize||r.normalized!==s.normalized||r.array.constructor!==s.array.constructor)return!1}for(const r of a){const a=t.morphAttributes[r],s=e.morphAttributes[r];if(a.length!==s.length)return!1;for(let e=0;e<a.length;e++)if(a[e].itemSize!==s[e].itemSize||a[e].normalized!==s[e].normalized||a[e].array.constructor!==s[e].array.constructor)return!1}return!0})}function N(e){if(e instanceof i)for(const t of v(e.material))t instanceof _.MeshPhongMaterial&&!t.color.isLinear&&(t.color.isLinear=!0);e.children?.forEach(N)}export class AssetMeshInstance extends n{}export function createAuthoredCollisionShapes(e,t=1){const a=null!=t&&0!==t?1/t:1;return e.map(e=>{let t;switch(e.type){case"box":t=new w((new c).fromArray(e.size).multiplyScalar(a));break;case"sphere":t=new A(e.radius*a);break;case"capsule":t=new x(e.length*a,e.radius*a);break;case"cylinder":t=new b(e.radius*a,e.radius*a,e.height*a,16,new r)}return t.source=M.custom,t.offset.fromArray(e.position??[0,0,0]).multiplyScalar(a),t.rotation.fromArray(e.rotation??[0,0,0,"XYZ"]),t})}export function getElectronArg(e){const t=`--${e}=`,r=window.process?.argv.find(e=>e.startsWith(t));return r?.substring(t.length)}function Y(e){switch(e){case"clamp":return _.ClampToEdgeWrapping;case"repeat":return _.RepeatWrapping;case"mirror":return _.MirroredRepeatWrapping}return _.RepeatWrapping}function q(e,t){const r=e;return!0!==r.isCompressedTexture&&!0!==r.isCompressedArrayTexture&&(t.texture?.flipY??!0)}function X(e){return e.texture?.colorSpace??function(e){if("exr"===e.fileFormat||e.fileKey?.toLowerCase().endsWith(".exr"))return"linear";const t=`${e.name} ${e.fileKey??""}`.toLowerCase();if(J.some(e=>t.includes(e)))return"linear";return"srgb"}(e)}function V(e){return"linear"===e?_.LinearSRGBColorSpace:_.SRGBColorSpace}const J=["_normal","_nrm","_nor","_norm","_roughness","_rough","_metalness","_metallic","_metal","_ao","_ambient","_occlusion","_mask","_height","_disp","_displacement","_bump","_opacity"];new _.Matrix4;const Z=[];const H=/_LOD(\d+)/;export function removeInvalidFaces(e){const t=e.getAttribute("position");if(null==t||t.itemSize<3)return 0;const r=e.index,a=r?.count??t.count,s=Math.floor(a/3),i=[],n=new Uint32Array(s+1),o=new c,l=new c,h=new c;let u=0;for(let e=0;e<s;e++){const a=3*e,s=r?.getX(a)??a,c=r?.getX(a+1)??a+1,m=r?.getX(a+2)??a+2;let d=Number.isInteger(s)&&Number.isInteger(c)&&Number.isInteger(m)&&s>=0&&c>=0&&m>=0&&s<t.count&&c<t.count&&m<t.count;if(d){o.fromBufferAttribute(t,s),l.fromBufferAttribute(t,c).sub(o),h.fromBufferAttribute(t,m).sub(o);const e=Math.max(l.lengthSq(),h.lengthSq(),l.distanceToSquared(h)),r=l.cross(h).lengthSq();d=Number.isFinite(e)&&Number.isFinite(r)&&e>0&&r>Number.EPSILON*e*e}d?i.push(s,c,m):u++,n[e+1]=i.length}if(0===u)return 0;if(e.setIndex(i),e.groups.length>0){const t=e.groups.slice();e.clearGroups();for(const r of t){const t=Math.max(0,Math.ceil(r.start/3)),a=Math.min(s,Math.floor((r.start+r.count)/3));if(a<=t)continue;const i=n[t],o=n[a]-i;o>0&&e.addGroup(i,o,r.materialIndex)}}const m=Math.max(0,Math.ceil(e.drawRange.start/3)),d=Number.isFinite(e.drawRange.count)?Math.min(s,Math.floor((e.drawRange.start+e.drawRange.count)/3)):s,p=Math.min(m,s),f=Math.min(s,Math.max(p,d)),g=n[p];return e.setDrawRange(g,n[f]-g),u}function Q(e){let t=e instanceof _.MeshPhysicalMaterial&&0===e.sheen&&0===e.anisotropy;if("MeshLambertMaterial"===e.type||"MeshPhongMaterial"===e.type||t){let t={};(e instanceof _.MeshLambertMaterial||e instanceof _.MeshPhongMaterial||e instanceof _.MeshPhysicalMaterial)&&(t.color=e.color,t.map=e.map,t.bumpMap=e.bumpMap,t.bumpScale=e.bumpScale,t.lightMap=e.lightMap,t.lightMapIntensity=e.lightMapIntensity,t.aoMap=e.aoMap,t.aoMapIntensity=e.aoMapIntensity,t.emissiveMap=e.emissiveMap,t.alphaMap=e.alphaMap,t.envMap=e.envMap,t.envMapRotation=e.envMapRotation,t.wireframe=e.wireframe,t.wireframeLinewidth=e.wireframeLinewidth,t.fog=e.fog,t.opacity=e.opacity,t.transparent=e.transparent,t.side=e.side,t.depthTest=e.depthTest,t.depthWrite=e.depthWrite,t.alphaTest=e.alphaTest,t.displacementMap=e.displacementMap,t.displacementScale=e.displacementScale,t.displacementBias=e.displacementBias);const r=new _.MeshStandardMaterial(t);return r.userData={...e.userData??{}},r.name=e.name,r}return e}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -7,6 +7,7 @@ import type { RuntimeAssetsService } from './runtime-asset-service.js';
|
|
|
7
7
|
import type { ShaderType, ActorType, ActorComponentType } from '../shader/shader.js';
|
|
8
8
|
import type { DetailTier } from './model.js';
|
|
9
9
|
import { NetMode } from '../gameplay/net/net-session.js';
|
|
10
|
+
import type { ActorPersistence } from '../gameplay/services/actor-persistence.js';
|
|
10
11
|
export type ShaderDefinitions = {
|
|
11
12
|
[name: string]: ShaderType;
|
|
12
13
|
};
|
|
@@ -17,6 +18,7 @@ export type ComponentDefinitions = {
|
|
|
17
18
|
[name: string]: ActorComponentType;
|
|
18
19
|
};
|
|
19
20
|
export type LoadSceneConfig = {
|
|
21
|
+
persistence?: ActorPersistence;
|
|
20
22
|
detailTier: DetailTier;
|
|
21
23
|
nodeMode?: NetMode;
|
|
22
24
|
};
|
package/dist/scene/bootstrap.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{polyfill as e}from"../utils/polyfill.js";import{SceneDataService as t}from"./scene-data-service.js";import{SceneMaterializer as n}from"./materializer.js";import{basicSceneSetup as i}from"./sky.js";import{NetMode as r}from"../gameplay/net/net-session.js";export async function loadScene(a,s,o,c,m,
|
|
1
|
+
import{polyfill as e}from"../utils/polyfill.js";import{SceneDataService as t}from"./scene-data-service.js";import{SceneMaterializer as n}from"./materializer.js";import{basicSceneSetup as i}from"./sky.js";import{NetMode as r}from"../gameplay/net/net-session.js";export async function loadScene(a,s,o,c,m,p,d,l,f,w,j){e();const{scene:y,renderer:h,camera:u}=a,S=new Set(y.children);i(y);const b=await l.getScene(s);if(null==b)throw Error(`Could not find scene with name ${s}`);const g=await l.getSceneData(b.id),v=new t,O=Object.entries(c).map(([e,t])=>({name:e,type:t})),z=Object.entries(m).map(([e,t])=>({name:e,type:t})),E=Object.entries(p).map(([e,t])=>({name:e,type:t})),I=new n(y,v,f,w,a,O,z,d,E);I.inEditor=!1,I.detailTier=j?.detailTier,I.netMode=j?.nodeMode??r.none;const M=j?.persistence?.enabled?await I.preparePersistence(j.persistence,b.id,g):g;return v.initiate(M),await I.initWithInstancing(),{scene:y,view:a,materializer:I,assetResourceLoader:w,assetsService:f,actors:I.actorInstances,sceneRoots:y.children.filter(e=>!S.has(e))}}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Color as e,Euler as a,Vector2 as r,Vector3 as u,Vector4 as t}from"three";import{getParameterDefinitionType as l,isParameterDefinitionAbstract as n}from"../shader/parameter.js";import{Curve2 as s}from"../utils/curve.js";import{isSequenceData as c,Sequence as o}from"../effects/sequence/sequence-data.js";import{SerializedParamType as v}from"./model.js";export function customParamValueNeedsAsyncResolution(e){if(null==e||null==e.value||""===e.value)return!1;if(
|
|
1
|
+
import{Color as e,Euler as a,Vector2 as r,Vector3 as u,Vector4 as t}from"three";import{getParameterDefinitionType as l,isParameterDefinitionAbstract as n}from"../shader/parameter.js";import{Curve2 as s}from"../utils/curve.js";import{isSequenceData as c,Sequence as o}from"../effects/sequence/sequence-data.js";import{SerializedParamType as v}from"./model.js";import{ModelRef as i}from"./model-ref.js";export function customParamValueNeedsAsyncResolution(e){if(null==e||null==e.value||""===e.value)return!1;if(f(e))return e.value.some(a=>customParamValueNeedsAsyncResolution(m(e,a)));switch(e.type){case v.Texture:case v.Sampler2DNode:case v.Object3D:case v.Material:case v.AudioBuffer:case v.VisualEffect:case v.Prefab:case v.PrefabActor:case v.DataAsset:case v.AnimationClip:return!0;case v.Sequence:return!c(e.value);case v.SequenceData:return!1;case v.Struct:return Object.values(p(e.value)).some(e=>customParamValueNeedsAsyncResolution(e));default:return!1}}export function deserializeCustomParamValueSync(l,n={}){if(null==l||null==l.value||""===l.value)return l?.value??null;switch(l.type){case v.Array:return f(l)&&Array.isArray(l.value)?l.value.map(e=>deserializeCustomParamValueSync(m(l,e),n)):[];case v.Number:case v.FloatNode:return"string"==typeof l.value?parseFloat(l.value):l.value;case v.Boolean:case v.BooleanNode:case v.String:return l.value;case v.Vector2:case v.Vec2Node:return"object"==typeof l.value?Array.isArray(l.value)?(new r).fromArray(l.value):new r(l.value.x,l.value.y):null;case v.Vector3:case v.Vec3Node:return"object"==typeof l.value?Array.isArray(l.value)?(new u).fromArray(l.value):new u(l.value.x,l.value.y,l.value.z):null;case v.Vector4:case v.Vec4Node:return"object"==typeof l.value?Array.isArray(l.value)?(new t).fromArray(l.value):new t(l.value.x,l.value.y,l.value.z,l.value.w):null;case v.Color:case v.RgbNode:return new e(l.value);case v.Euler:return Array.isArray(l.value)?(new a).fromArray(l.value):l.value;case v.BaseActor:return n.actor?.(l.value)??l.value;case v.ModelRef:return"string"==typeof l.value?new i(l.value):null;case v.Sequence:return c(l.value)?new o(l.value):l.value;case v.SequenceData:return c(l.value)?l.value:null;case v.Curve:return s.decode(l.value);case v.Struct:return function(e,a){const r=A(e.value),u=y(r?.struct??e.struct);for(const[t,l]of Object.entries(r?.value??p(e.value)))u[t]=deserializeCustomParamValueSync(l,a);return u}(l,n);default:return l.value}}export async function deserializeCustomParamValue(e,a={}){if(null==e||null==e.value||""===e.value)return e?.value??null;if(!customParamValueNeedsAsyncResolution(e))return deserializeCustomParamValueSync(e,a);switch(e.type){case v.Array:return f(e)&&Array.isArray(e.value)?Promise.all(e.value.map(r=>deserializeCustomParamValue(m(e,r),a))):[];case v.Texture:return a.texture?.(e.value)??null;case v.Sampler2DNode:return a.sampler2DNode?.(e.value)??null;case v.Object3D:return a.object3D?.(e.value)??null;case v.Material:return a.material?.(e.value)??null;case v.AudioBuffer:return a.audioBuffer?.(e.value)??null;case v.VisualEffect:return a.visualEffect?.(e.value)??null;case v.Prefab:return a.prefab?.(e.value)??null;case v.PrefabActor:return a.prefabActor?.(e.value)??null;case v.DataAsset:return a.dataAsset?.(e.value)??null;case v.Sequence:return c(e.value)?new o(e.value):a.sequence?.(e.value)??null;case v.SequenceData:return c(e.value)?e.value:null;case v.AnimationClip:return a.animationClip?.(e.value)??null;case v.Struct:return async function(e,a){const r=A(e.value),u=y(r?.struct??e.struct);for(const[t,l]of Object.entries(r?.value??p(e.value)))u[t]=await deserializeCustomParamValue(l,a);return u}(e,a);default:return deserializeCustomParamValueSync(e,a)}}function f(e){return e.type===v.Array}function m(e,a){const r=A(a);return{type:e.element,...null!=r?.struct||null!=e.elementStruct?{struct:r?.struct??e.elementStruct}:{},value:r?.value??a}}function y(e){const a=null!=e?l(e):void 0;if(null==a||n(e))return{};try{return new a}catch{return{}}}function p(e){const a=A(e);return null!=a?a.value:d(e)?e:null!=e&&"object"==typeof e&&d(e.params)?e.params:{}}function A(e){return null!=e&&"object"==typeof e&&!Array.isArray(e)&&"string"==typeof e.struct&&d(e.value)?e:null}function d(e){return null!=e&&"object"==typeof e&&!Array.isArray(e)&&Object.values(e).every(e=>null!=e&&"object"==typeof e&&"type"in e)}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Color as e,Euler as r,Material as t,Object3D as n,Texture as u,Vector2 as o,Vector3 as a,Vector4 as c,AnimationClip as l}from"three";import{BooleanNode as i,FloatNode as s,RgbNode as f,Sampler2DNode as y,Texture2dLookupNode as p,Vec2Node as m,Vec3Node as d,Vec4Node as b}from"three-shader-graph";import{getParameterDefinitionId as A,getParameterDefinitionType as g,isParameterDefinitionStructAssignableTo as S}from"../shader/parameter.js";import{Curve2 as N}from"../utils/curve.js";import{isSequenceData as V}from"../effects/sequence/sequence-data.js";import{SerializedParamType as v}from"./model.js";export const applyRuntimeParamTypeInference=!0;export function convertConfiguredParamsToRuntimeTypes(e,r={}){const t={},n=[],u=Object.entries(e),o=r.applyRuntimeParamTypeInference??true;if(0===u.length||!o)return o?{params:t,skipped:n}:{params:e,skipped:n};const a=getRuntimeParameterTypeHints(e,r);for(const[e,r]of u){const u=a.get(e),o=P(r,u);if(null==o)continue;if(!1===o.override){t[e]=o;continue}const c=null!=u?convertConfiguredParamValueToRuntimeType(o,u):o;null!=c?t[e]=c:n.push({key:e,sourceType:o.type,targetType:u.type})}return{params:t,skipped:n}}function P(e,r){return function(e){return null!=e&&"object"==typeof e&&!Array.isArray(e)&&"number"==typeof e.type&&"value"in e}(e)?e:r?.type===v.SequenceData&&V(e)?{type:v.SequenceData,value:e}:null}export function getRuntimeParameterTypeHints(e,r={}){const t=new Map,n=Object.keys(e).filter(r=>!1!==e[r]?.override);if(0===n.length)return t;const u=new Set(n),o=r.parameterTarget??function(e){if(null==e)return null;try{return new e}catch{return null}}(r.parameterType),a=function(e,r){if(null!=r.propertyParams)return r.propertyParams;if(null==r.extractPropertyParameters)return[];if(null!=r.parameterType)return R(r.parameterType,r.extractPropertyParameters);if(null!=e)return R(e.constructor,r.extractPropertyParameters);return[]}(o,r);for(const e of a){if(!u.has(e.name))continue;const n=w(e,r.toSerializedParamType);null!=n&&t.set(e.name,n);const a=inferRuntimeSerializedParamTypeHint(j(o,e.name))??inferRuntimeSerializedParamTypeHint(e.options.defaultValue);null!=a&&t.set(e.name,x(a,n))}if(null!=o)for(const e of n){const r=inferRuntimeSerializedParamTypeHint(j(o,e));if(null!=r){const n=t.get(e);t.set(e,x(r,n))}}return t}const T=new WeakMap,h=new WeakMap,C=Symbol("noCachedSerializedParamType");function R(e,r){let t=T.get(r);null==t&&(t=new WeakMap,T.set(r,t));const n=t.get(e);if(null!=n)return n;const u=function(e,r){try{return r(e)}catch{return[]}}(e,r);return t.set(e,u),u}function j(e,r){return null!=e?e[r]:void 0}function w(e,r){const t=function(e,r){if(null==e||null==r)return;const t=function(e,r){const t=h.get(r);if(null==t||!t.has(e))return C;const n=t.get(e);return null===n?void 0:n}(e,r);if(t!==C)return t;try{const t=r(e);return D(e,r,t),t}catch{return void D(e,r,void 0)}}(e.type,r),n=t===v.Struct?A(e.type):void 0;return!0===e.options.array?{type:v.Array,...null!=t?{element:t}:{},...null!=n?{elementStruct:n}:{}}:null!=t?{type:t,...null!=n?{struct:n}:{}}:void 0}function D(e,r,t){let n=h.get(r);null==n&&(n=new WeakMap,h.set(r,n)),n.set(e,t??null)}function x(e,r){return e.type!==v.Array?e:{type:v.Array,element:e.element??r?.element,elementStruct:e.elementStruct??r?.elementStruct}}export function inferRuntimeSerializedParamTypeHint(g){if(null==g)return;if(Array.isArray(g)){const e=g.map(e=>inferRuntimeSerializedParamTypeHint(e)).find(e=>null!=e);return{type:v.Array,...null!=e&&e.type!==v.Array?{element:e.type}:{},...null!=e?.struct?{elementStruct:e.struct}:{}}}switch(typeof g){case"number":return{type:v.Number};case"boolean":return{type:v.Boolean};case"string":return{type:v.String}}const S=function(e){const r=e;if(e instanceof s||"function"==typeof r?.isFloat||!0===r?.isFloat)return v.FloatNode;if(e instanceof i||"function"==typeof r?.isBool||!0===r?.isBool)return v.BooleanNode;if(e instanceof f||"function"==typeof r?.isRgb||!0===r?.isRgb)return v.RgbNode;if(e instanceof m||"function"==typeof r?.isVec2||!0===r?.isVec2)return v.Vec2Node;if(e instanceof d||"function"==typeof r?.isVec3||!0===r?.isVec3)return v.Vec3Node;if(e instanceof b||"function"==typeof r?.isVec4||!0===r?.isVec4)return v.Vec4Node;if(e instanceof y||e instanceof p||"function"==typeof r?.isSampler2D||!0===r?.isSampler2D)return v.Sampler2DNode;return}(g);if(null!=S)return{type:S};if(g instanceof o)return{type:v.Vector2};if(g instanceof a)return{type:v.Vector3};if(g instanceof c)return{type:v.Vector4};if(g instanceof e)return{type:v.Color};if(g instanceof r)return{type:v.Euler};if(g instanceof u)return{type:v.Texture};if(g instanceof t)return{type:v.Material};if(g instanceof n)return{type:v.Object3D};if("undefined"!=typeof AudioBuffer&&g instanceof AudioBuffer)return{type:v.AudioBuffer};if(X(g,"VisualEffect"))return{type:v.VisualEffect};if(X(g,"PrefabOf"))return{type:v.PrefabActor};if(X(g,"Prefab"))return{type:v.Prefab};if(X(g,"DataAssetRef"))return{type:v.DataAsset};if(g instanceof N)return{type:v.Curve};if(X(g,"ColorLayer"))return{type:v.ColorLayer};if(X(g,"MaskLayer"))return{type:v.MaskLayer};if(g instanceof l)return{type:v.AnimationClip};if(X(g,"Sequence"))return{type:v.Sequence};if(V(g))return{type:v.SequenceData};const P=A(g.constructor);return null!=P?{type:v.Struct,struct:P}:void 0}export function convertConfiguredParamValueToRuntimeType(e,r){if(null==e||null==r)return e;if(e.type===v.Array||r.type===v.Array)return function(e,r){if(r.type===v.Array){const t=B(e),n=r.element??(t?e.element:e.type);if(null==n)return t?e:null;const u=t?e.element:e.type,o=(t?Array.isArray(e.value)?e.value:[]:[e.value]).map(e=>M(e,u,n));return o.some(e=>e===q)?null:{...e,type:v.Array,element:n,...F(e,r),value:o}}if(!B(e))return null;const t=Array.isArray(e.value)?e.value[0]:void 0;if(null==t)return null;const n=M(t,e.element,r.type);if(n===q)return null;return{...e,type:r.type,...k(e,r),value:n}}(e,r);const t=M(e.value,e.type,r.type);return t===q?null:{...e,type:r.type,...k(e,r),value:t}}function B(e){return e.type===v.Array}function k(e,r){if(r.type!==v.Struct&&e.type!==v.Struct)return{};const t=function(e,r){if(null==r)return e;if(null==e)return r;if(e===r||S(e,r))return e;const t=g(e),n=g(r);if(null==t||null==n)return e;return r}(e.type===v.Struct?e.struct:void 0,r.struct);return null!=t?{struct:t}:{}}function F(e,r){if(r.type!==v.Array)return{};const t=B(e)?e.elementStruct:void 0,n=r.elementStruct??t;return null!=n?{elementStruct:n}:{}}const q=Symbol("skippedParamValue");function M(e,r,t){if(function(e,r){if(e===r)return!0;const t=L(e);return null!=t&&t===L(r)}(r,t)&&function(e,r){switch(r){case v.Number:return"number"==typeof e||"string"==typeof e&&Number.isFinite(parseFloat(e));case v.FloatNode:return"number"==typeof e||"string"==typeof e&&Number.isFinite(parseFloat(e))||function(e){if(null==e||"object"!=typeof e||Array.isArray(e))return!1;const r=e;return"particle"===r.time&&"string"==typeof r.easing&&null!=H(r.a)&&null!=H(r.b)}(e);case v.Boolean:case v.BooleanNode:return"boolean"==typeof e;case v.Vector2:case v.Vec2Node:return z(e,2);case v.Vector3:case v.Vec3Node:return z(e,3);case v.Vector4:case v.Vec4Node:return z(e,4);case v.Euler:return Array.isArray(e)&&e.length>=3&&null!=O(e,3);case v.Color:case v.RgbNode:return null!=I(e);case v.String:return"string"==typeof e;case v.Scene:return null!=e&&"object"==typeof e&&"string"==typeof e.id;case v.Array:return Array.isArray(e);case v.Texture:case v.Sampler2DNode:case v.BaseActor:case v.Object3D:case v.Material:case v.AudioBuffer:case v.VisualEffect:case v.Prefab:case v.PrefabActor:case v.DataAsset:case v.AnimationClip:case v.Sequence:return null==e||"string"==typeof e||"object"==typeof e;case v.SequenceData:return null==e||V(e);case v.Struct:return null!=e&&"object"==typeof e&&!Array.isArray(e);case v.Curve:case v.ColorLayer:case v.MaskLayer:return null!=e}return!0}(e,t))return e;switch(t){case v.Number:case v.FloatNode:{const r=H(e);return null!=r?r:q}case v.Boolean:case v.BooleanNode:{const r=function(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const r=e.trim().toLowerCase();if(["true","1","yes","on"].includes(r))return!0;if(["false","0","no","off"].includes(r))return!1}return null}(e);return null!=r?r:q}case v.Vector2:case v.Vec2Node:return E(e,2,r)??q;case v.Vector3:case v.Vec3Node:return E(e,3,r)??q;case v.Vector4:case v.Vec4Node:return E(e,4,r)??q;case v.Color:case v.RgbNode:return function(e,r){if(r===v.Color||r===v.RgbNode)return"string"==typeof e||"number"==typeof e?e:W(e);return W(e)}(e,r)??q;case v.Euler:return function(e,r){if(Array.isArray(e)){const r=O(e,3);if(null==r)return null;const t="string"==typeof e[3]?e[3]:"XYZ";return[r[0],r[1],r[2],t]}const t=E(e,3,r);return null!=t?[t[0],t[1],t[2],"XYZ"]:null}(e,r)??q;case v.String:return"string"==typeof e?e:String(e);case v.Scene:return"string"==typeof e?{id:e,name:e}:null!=e&&"object"==typeof e&&"string"==typeof e.id?e:q;case v.Texture:case v.Sampler2DNode:case v.BaseActor:case v.Object3D:case v.Material:case v.AudioBuffer:case v.VisualEffect:case v.Curve:case v.ColorLayer:case v.MaskLayer:case v.Prefab:case v.PrefabActor:case v.DataAsset:case v.AnimationClip:case v.Sequence:case v.SequenceData:case v.Struct:return t===v.SequenceData&&V(e)?e:q}return q}function z(e,r){if(Array.isArray(e))return e.length>=r&&null!=O(e,r);if(null!=e&&"object"==typeof e){const t=e;return["x","y","z","w"].slice(0,r).every(e=>null!=H(t[e]))}return!1}function L(e){switch(e){case v.Number:case v.FloatNode:return"number";case v.Boolean:case v.BooleanNode:return"boolean";case v.Vector2:case v.Vec2Node:return"vector2";case v.Vector3:case v.Vec3Node:return"vector3";case v.Vector4:case v.Vec4Node:return"vector4";case v.Color:case v.RgbNode:return"color";case v.Texture:case v.Sampler2DNode:return"texture";case v.Prefab:case v.PrefabActor:return"prefab";case v.DataAsset:return"dataAsset";case v.Struct:return"struct"}}function H(e){if("number"==typeof e)return Number.isFinite(e)?e:null;if("string"==typeof e){const r=parseFloat(e);return Number.isFinite(r)?r:null}if("boolean"==typeof e)return e?1:0;if(Array.isArray(e))return H(e[0]);if(null!=e&&"object"==typeof e){const r=e;return H(r.x??r.r??r.value)}return null}function E(e,r,t){if(t===v.Color||t===v.RgbNode){const t=I(e);if(null!=t)return O(t.toArray(),r,4===r?1:0)}if(Array.isArray(e))return O(e,r);if("number"==typeof e||"string"==typeof e||"boolean"==typeof e){const t=H(e);return null!=t?new Array(r).fill(t):null}if(null!=e&&"object"==typeof e){const t=e,n=["x","y","z","w"].slice(0,r).map(e=>t[e]);if(n.some(e=>null!=e))return O(n,r);const u=["r","g","b","a"].slice(0,r).map(e=>t[e]);if(u.some(e=>null!=e))return O(u,r,4===r?1:0)}return null}function O(e,r,t=0){const n=[];for(let u=0;u<r;u++){const r=H(e[u]??t);if(null==r)return null;n.push(r)}return n}function W(e){const r=I(e);return null!=r?"#"+r.getHexString():null}function I(r){try{if(r instanceof e)return r.clone();if("string"==typeof r)return function(e){return/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(e.trim())||/^(rgb|hsl)a?\(/i.test(e.trim())}(r)?new e(r):null;if("number"==typeof r)return Number.isInteger(r)&&r>=0?new e(r):null;if(Array.isArray(r)){const t=O(r,3);return null!=t?(new e).fromArray(t):null}if(null!=r&&"object"==typeof r){const t=r;if(null!=t.r||null!=t.g||null!=t.b){const r=O([t.r,t.g,t.b],3);return null!=r?(new e).fromArray(r):null}if(null!=t.x||null!=t.y||null!=t.z){const r=O([t.x,t.y,t.z],3);return null!=r?(new e).fromArray(r):null}}}catch{return null}return null}function X(e,r){return null!=e&&"object"==typeof e&&e.constructor?.name===r}/*
|
|
1
|
+
import{Color as e,Euler as r,Material as t,Object3D as n,Texture as u,Vector2 as o,Vector3 as a,Vector4 as c,AnimationClip as i}from"three";import{BooleanNode as l,FloatNode as s,RgbNode as f,Sampler2DNode as y,Texture2dLookupNode as p,Vec2Node as m,Vec3Node as d,Vec4Node as b}from"three-shader-graph";import{getParameterDefinitionId as A,getParameterDefinitionType as g,isParameterDefinitionStructAssignableTo as S}from"../shader/parameter.js";import{Curve2 as N}from"../utils/curve.js";import{isSequenceData as V}from"../effects/sequence/sequence-data.js";import{SerializedParamType as v}from"./model.js";import{ModelRef as P}from"./model-ref.js";export const applyRuntimeParamTypeInference=!0;export function convertConfiguredParamsToRuntimeTypes(e,r={}){const t={},n=[],u=Object.entries(e),o=r.applyRuntimeParamTypeInference??true;if(0===u.length||!o)return o?{params:t,skipped:n}:{params:e,skipped:n};const a=getRuntimeParameterTypeHints(e,r);for(const[e,r]of u){const u=a.get(e),o=T(r,u);if(null==o)continue;if(!1===o.override){t[e]=o;continue}const c=null!=u?convertConfiguredParamValueToRuntimeType(o,u):o;null!=c?t[e]=c:n.push({key:e,sourceType:o.type,targetType:u.type})}return{params:t,skipped:n}}function T(e,r){return function(e){return null!=e&&"object"==typeof e&&!Array.isArray(e)&&"number"==typeof e.type&&"value"in e}(e)?e:r?.type===v.SequenceData&&V(e)?{type:v.SequenceData,value:e}:null}export function getRuntimeParameterTypeHints(e,r={}){const t=new Map,n=Object.keys(e).filter(r=>!1!==e[r]?.override);if(0===n.length)return t;const u=new Set(n),o=r.parameterTarget??function(e){if(null==e)return null;try{return new e}catch{return null}}(r.parameterType),a=function(e,r){if(null!=r.propertyParams)return r.propertyParams;if(null==r.extractPropertyParameters)return[];if(null!=r.parameterType)return C(r.parameterType,r.extractPropertyParameters);if(null!=e)return C(e.constructor,r.extractPropertyParameters);return[]}(o,r);for(const e of a){if(!u.has(e.name))continue;const n=D(e,r.toSerializedParamType);null!=n&&t.set(e.name,n);const a=inferRuntimeSerializedParamTypeHint(w(o,e.name))??inferRuntimeSerializedParamTypeHint(e.options.defaultValue);null!=a&&t.set(e.name,B(a,n))}if(null!=o)for(const e of n){const r=inferRuntimeSerializedParamTypeHint(w(o,e));if(null!=r){const n=t.get(e);t.set(e,B(r,n))}}return t}const R=new WeakMap,h=new WeakMap,j=Symbol("noCachedSerializedParamType");function C(e,r){let t=R.get(r);null==t&&(t=new WeakMap,R.set(r,t));const n=t.get(e);if(null!=n)return n;const u=function(e,r){try{return r(e)}catch{return[]}}(e,r);return t.set(e,u),u}function w(e,r){return null!=e?e[r]:void 0}function D(e,r){const t=function(e,r){if(null==e||null==r)return;const t=function(e,r){const t=h.get(r);if(null==t||!t.has(e))return j;const n=t.get(e);return null===n?void 0:n}(e,r);if(t!==j)return t;try{const t=r(e);return x(e,r,t),t}catch{return void x(e,r,void 0)}}(e.type,r),n=t===v.Struct?A(e.type):void 0;return!0===e.options.array?{type:v.Array,...null!=t?{element:t}:{},...null!=n?{elementStruct:n}:{}}:null!=t?{type:t,...null!=n?{struct:n}:{}}:void 0}function x(e,r,t){let n=h.get(r);null==n&&(n=new WeakMap,h.set(r,n)),n.set(e,t??null)}function B(e,r){return e.type!==v.Array?e:{type:v.Array,element:e.element??r?.element,elementStruct:e.elementStruct??r?.elementStruct}}export function inferRuntimeSerializedParamTypeHint(g){if(null==g)return;if(Array.isArray(g)){const e=g.map(e=>inferRuntimeSerializedParamTypeHint(e)).find(e=>null!=e);return{type:v.Array,...null!=e&&e.type!==v.Array?{element:e.type}:{},...null!=e?.struct?{elementStruct:e.struct}:{}}}switch(typeof g){case"number":return{type:v.Number};case"boolean":return{type:v.Boolean};case"string":return{type:v.String}}const S=function(e){const r=e;if(e instanceof s||"function"==typeof r?.isFloat||!0===r?.isFloat)return v.FloatNode;if(e instanceof l||"function"==typeof r?.isBool||!0===r?.isBool)return v.BooleanNode;if(e instanceof f||"function"==typeof r?.isRgb||!0===r?.isRgb)return v.RgbNode;if(e instanceof m||"function"==typeof r?.isVec2||!0===r?.isVec2)return v.Vec2Node;if(e instanceof d||"function"==typeof r?.isVec3||!0===r?.isVec3)return v.Vec3Node;if(e instanceof b||"function"==typeof r?.isVec4||!0===r?.isVec4)return v.Vec4Node;if(e instanceof y||e instanceof p||"function"==typeof r?.isSampler2D||!0===r?.isSampler2D)return v.Sampler2DNode;return}(g);if(null!=S)return{type:S};if(g instanceof o)return{type:v.Vector2};if(g instanceof a)return{type:v.Vector3};if(g instanceof c)return{type:v.Vector4};if(g instanceof e)return{type:v.Color};if(g instanceof r)return{type:v.Euler};if(g instanceof u)return{type:v.Texture};if(g instanceof t)return{type:v.Material};if(g instanceof n)return{type:v.Object3D};if(g instanceof P)return{type:v.ModelRef};if("undefined"!=typeof AudioBuffer&&g instanceof AudioBuffer)return{type:v.AudioBuffer};if(Y(g,"VisualEffect"))return{type:v.VisualEffect};if(Y(g,"PrefabOf"))return{type:v.PrefabActor};if(Y(g,"Prefab"))return{type:v.Prefab};if(Y(g,"DataAssetRef"))return{type:v.DataAsset};if(g instanceof N)return{type:v.Curve};if(Y(g,"ColorLayer"))return{type:v.ColorLayer};if(Y(g,"MaskLayer"))return{type:v.MaskLayer};if(g instanceof i)return{type:v.AnimationClip};if(Y(g,"Sequence"))return{type:v.Sequence};if(V(g))return{type:v.SequenceData};const T=A(g.constructor);return null!=T?{type:v.Struct,struct:T}:void 0}export function convertConfiguredParamValueToRuntimeType(e,r){if(null==e||null==r)return e;if(e.type===v.Array||r.type===v.Array)return function(e,r){if(r.type===v.Array){const t=M(e),n=r.element??(t?e.element:e.type);if(null==n)return t?e:null;const u=t?e.element:e.type,o=(t?Array.isArray(e.value)?e.value:[]:[e.value]).map(e=>z(e,u,n));return o.some(e=>e===q)?null:{...e,type:v.Array,element:n,...F(e,r),value:o}}if(!M(e))return null;const t=Array.isArray(e.value)?e.value[0]:void 0;if(null==t)return null;const n=z(t,e.element,r.type);if(n===q)return null;return{...e,type:r.type,...k(e,r),value:n}}(e,r);const t=z(e.value,e.type,r.type);return t===q?null:{...e,type:r.type,...k(e,r),value:t}}function M(e){return e.type===v.Array}function k(e,r){if(r.type!==v.Struct&&e.type!==v.Struct)return{};const t=function(e,r){if(null==r)return e;if(null==e)return r;if(e===r||S(e,r))return e;const t=g(e),n=g(r);if(null==t||null==n)return e;return r}(e.type===v.Struct?e.struct:void 0,r.struct);return null!=t?{struct:t}:{}}function F(e,r){if(r.type!==v.Array)return{};const t=M(e)?e.elementStruct:void 0,n=r.elementStruct??t;return null!=n?{elementStruct:n}:{}}const q=Symbol("skippedParamValue");function z(e,r,t){if(function(e,r){if(e===r)return!0;const t=H(e);return null!=t&&t===H(r)}(r,t)&&function(e,r){switch(r){case v.Number:return"number"==typeof e||"string"==typeof e&&Number.isFinite(parseFloat(e));case v.FloatNode:return"number"==typeof e||"string"==typeof e&&Number.isFinite(parseFloat(e))||function(e){if(null==e||"object"!=typeof e||Array.isArray(e))return!1;const r=e;return"particle"===r.time&&"string"==typeof r.easing&&null!=E(r.a)&&null!=E(r.b)}(e);case v.Boolean:case v.BooleanNode:return"boolean"==typeof e;case v.Vector2:case v.Vec2Node:return L(e,2);case v.Vector3:case v.Vec3Node:return L(e,3);case v.Vector4:case v.Vec4Node:return L(e,4);case v.Euler:return Array.isArray(e)&&e.length>=3&&null!=W(e,3);case v.Color:case v.RgbNode:return null!=X(e);case v.String:return"string"==typeof e;case v.Scene:return null!=e&&"object"==typeof e&&"string"==typeof e.id;case v.ModelRef:return"string"==typeof e;case v.Array:return Array.isArray(e);case v.Texture:case v.Sampler2DNode:case v.BaseActor:case v.Object3D:case v.Material:case v.AudioBuffer:case v.VisualEffect:case v.Prefab:case v.PrefabActor:case v.DataAsset:case v.AnimationClip:case v.Sequence:return null==e||"string"==typeof e||"object"==typeof e;case v.SequenceData:return null==e||V(e);case v.Struct:return null!=e&&"object"==typeof e&&!Array.isArray(e);case v.Curve:case v.ColorLayer:case v.MaskLayer:return null!=e}return!0}(e,t))return e;switch(t){case v.Number:case v.FloatNode:{const r=E(e);return null!=r?r:q}case v.Boolean:case v.BooleanNode:{const r=function(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const r=e.trim().toLowerCase();if(["true","1","yes","on"].includes(r))return!0;if(["false","0","no","off"].includes(r))return!1}return null}(e);return null!=r?r:q}case v.Vector2:case v.Vec2Node:return O(e,2,r)??q;case v.Vector3:case v.Vec3Node:return O(e,3,r)??q;case v.Vector4:case v.Vec4Node:return O(e,4,r)??q;case v.Color:case v.RgbNode:return function(e,r){if(r===v.Color||r===v.RgbNode)return"string"==typeof e||"number"==typeof e?e:I(e);return I(e)}(e,r)??q;case v.Euler:return function(e,r){if(Array.isArray(e)){const r=W(e,3);if(null==r)return null;const t="string"==typeof e[3]?e[3]:"XYZ";return[r[0],r[1],r[2],t]}const t=O(e,3,r);return null!=t?[t[0],t[1],t[2],"XYZ"]:null}(e,r)??q;case v.String:return"string"==typeof e?e:String(e);case v.Scene:return"string"==typeof e?{id:e,name:e}:null!=e&&"object"==typeof e&&"string"==typeof e.id?e:q;case v.ModelRef:return"string"==typeof e?e:q;case v.Texture:case v.Sampler2DNode:case v.BaseActor:case v.Object3D:case v.Material:case v.AudioBuffer:case v.VisualEffect:case v.Curve:case v.ColorLayer:case v.MaskLayer:case v.Prefab:case v.PrefabActor:case v.DataAsset:case v.AnimationClip:case v.Sequence:case v.SequenceData:case v.Struct:return t===v.SequenceData&&V(e)?e:q}return q}function L(e,r){if(Array.isArray(e))return e.length>=r&&null!=W(e,r);if(null!=e&&"object"==typeof e){const t=e;return["x","y","z","w"].slice(0,r).every(e=>null!=E(t[e]))}return!1}function H(e){switch(e){case v.Number:case v.FloatNode:return"number";case v.Boolean:case v.BooleanNode:return"boolean";case v.Vector2:case v.Vec2Node:return"vector2";case v.Vector3:case v.Vec3Node:return"vector3";case v.Vector4:case v.Vec4Node:return"vector4";case v.Color:case v.RgbNode:return"color";case v.Texture:case v.Sampler2DNode:return"texture";case v.Prefab:case v.PrefabActor:return"prefab";case v.DataAsset:return"dataAsset";case v.Struct:return"struct"}}function E(e){if("number"==typeof e)return Number.isFinite(e)?e:null;if("string"==typeof e){const r=parseFloat(e);return Number.isFinite(r)?r:null}if("boolean"==typeof e)return e?1:0;if(Array.isArray(e))return E(e[0]);if(null!=e&&"object"==typeof e){const r=e;return E(r.x??r.r??r.value)}return null}function O(e,r,t){if(t===v.Color||t===v.RgbNode){const t=X(e);if(null!=t)return W(t.toArray(),r,4===r?1:0)}if(Array.isArray(e))return W(e,r);if("number"==typeof e||"string"==typeof e||"boolean"==typeof e){const t=E(e);return null!=t?new Array(r).fill(t):null}if(null!=e&&"object"==typeof e){const t=e,n=["x","y","z","w"].slice(0,r).map(e=>t[e]);if(n.some(e=>null!=e))return W(n,r);const u=["r","g","b","a"].slice(0,r).map(e=>t[e]);if(u.some(e=>null!=e))return W(u,r,4===r?1:0)}return null}function W(e,r,t=0){const n=[];for(let u=0;u<r;u++){const r=E(e[u]??t);if(null==r)return null;n.push(r)}return n}function I(e){const r=X(e);return null!=r?"#"+r.getHexString():null}function X(r){try{if(r instanceof e)return r.clone();if("string"==typeof r)return function(e){return/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(e.trim())||/^(rgb|hsl)a?\(/i.test(e.trim())}(r)?new e(r):null;if("number"==typeof r)return Number.isInteger(r)&&r>=0?new e(r):null;if(Array.isArray(r)){const t=W(r,3);return null!=t?(new e).fromArray(t):null}if(null!=r&&"object"==typeof r){const t=r;if(null!=t.r||null!=t.g||null!=t.b){const r=W([t.r,t.g,t.b],3);return null!=r?(new e).fromArray(r):null}if(null!=t.x||null!=t.y||null!=t.z){const r=W([t.x,t.y,t.z],3);return null!=r?(new e).fromArray(r):null}}}catch{return null}return null}function Y(e,r){return null!=e&&"object"==typeof e&&e.constructor?.name===r}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { BufferGeometry, Matrix4, Object3D, Vector3 } from 'three';
|
|
2
|
+
/** Offsets are in asset-root space, ordered x fastest, then y, then z. */
|
|
3
|
+
export interface LatticeDeformation {
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
segments: [number, number, number];
|
|
6
|
+
min: [number, number, number];
|
|
7
|
+
max: [number, number, number];
|
|
8
|
+
offsets: [number, number, number][];
|
|
9
|
+
}
|
|
10
|
+
export declare function isValidLattice(data: LatticeDeformation): boolean;
|
|
11
|
+
export declare function latticePoint(data: LatticeDeformation, index: number, target: Vector3): Vector3;
|
|
12
|
+
export declare function createLatticeDeformation(root: Object3D, segments?: [number, number, number]): LatticeDeformation;
|
|
13
|
+
/** Piecewise trilinear FFD. Eight control points per vertex, independent of cage resolution. */
|
|
14
|
+
export declare function deformLatticeGeometry(source: BufferGeometry, matrix: Matrix4, data: LatticeDeformation): BufferGeometry;
|
|
15
|
+
/** Internal identity for independently baked copies of the same static skin pose. */
|
|
16
|
+
export declare function setLatticeGeometrySourceIdentity(geometry: BufferGeometry, identity: string): void;
|
|
17
|
+
/** Owns only generated buffers. Live copies share buffers; a small idle cache supports undo. */
|
|
18
|
+
export declare class LatticeGeometryCache {
|
|
19
|
+
private disposed;
|
|
20
|
+
private readonly roots;
|
|
21
|
+
private readonly entries;
|
|
22
|
+
private readonly bindings;
|
|
23
|
+
apply(root: Object3D, data?: LatticeDeformation, variant?: string): void;
|
|
24
|
+
release(root: Object3D): void;
|
|
25
|
+
private prune;
|
|
26
|
+
dispose(): void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=lattice-deformation.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{isCollisionMesh as e}from"./collision/collision-shape-import.js";import{Box3 as t,Matrix3 as r,Matrix4 as s,Mesh as i,Vector3 as n}from"three";export function isValidLattice(e){return Array.isArray(e?.segments)&&3===e.segments.length&&e.segments.every(e=>Number.isInteger(e)&&e>=1&&e<=8)&&(null==e.enabled||"boolean"==typeof e.enabled)&&Array.isArray(e.min)&&3===e.min.length&&Array.isArray(e.max)&&3===e.max.length&&e.min.every((t,r)=>Number.isFinite(t)&&Number.isFinite(e.max[r])&&e.max[r]>t)&&Array.isArray(e.offsets)&&e.offsets.length===e.segments.reduce((e,t)=>e*(t+1),1)&&e.offsets.every(e=>Array.isArray(e)&&3===e.length&&e.every(Number.isFinite))}export function latticePoint(e,t,r){const[s,i,n]=e.segments,o=t%(s+1),a=Math.floor(t/(s+1))%(i+1),m=Math.floor(t/((s+1)*(i+1)));return r.set(e.min[0]+(e.max[0]-e.min[0])*o/s+e.offsets[t][0],e.min[1]+(e.max[1]-e.min[1])*a/i+e.offsets[t][1],e.min[2]+(e.max[2]-e.min[2])*m/n+e.offsets[t][2])}function o(t,r){const s=n=>{if(!n.userData.isEditorVisualization&&(n===t||null==n.userData.src&&null==n.userData._src)){n instanceof i&&!e(n)&&r(n);for(const e of n.children)s(e)}};s(t)}function a(e,t){const r=new s;for(let s=t;s&&s!==e;s=s.parent)s.updateMatrix(),r.premultiply(s.matrix);return r}export function createLatticeDeformation(e,r=[2,2,2]){if(!Array.isArray(r)||3!==r.length||!r.every(e=>Number.isInteger(e)&&e>=1&&e<=8))throw new Error("Lattice segments must be integers from 1 to 8.");const s=new t,i=new n;if(o(e,t=>{const r=t.geometry.getAttribute("position"),n=a(e,t);if(r)for(let e=0;e<r.count;e++)s.expandByPoint(i.fromBufferAttribute(r,e).applyMatrix4(n))}),s.isEmpty())throw new Error("The model has no vertices to deform.");for(const e of["x","y","z"])s.max[e]-s.min[e]<1e-5&&(s.min[e]-=.005,s.max[e]+=.005);const m={enabled:!0,segments:[...r],min:s.min.toArray(),max:s.max.toArray(),offsets:Array.from({length:r.reduce((e,t)=>e*(t+1),1)},()=>[0,0,0])};if(!isValidLattice(m))throw new Error("Lattice segments must be integers from 1 to 8.");return m}export function deformLatticeGeometry(e,t,s){if(!isValidLattice(s))throw new Error("Invalid lattice deformation.");const i=e.clone(),o=i.getAttribute("position");if(!o)return i;const a=i.getAttribute("normal"),m=i.getAttribute("tangent"),f=t.clone().invert(),l=(new r).getNormalMatrix(t),u=(new r).getNormalMatrix(f),c=(new r).setFromMatrix4(t),d=(new r).setFromMatrix4(f),y=new n,p=new n,h=new n,x=new n,g=new r,b=new r,[M,w,A]=s.segments,v=M/(s.max[0]-s.min[0]),z=w/(s.max[1]-s.min[1]),L=A/(s.max[2]-s.min[2]);for(let e=0;e<o.count;e++){y.fromBufferAttribute(o,e).applyMatrix4(t);const r=Math.max(0,Math.min(M,(y.x-s.min[0])*v)),i=Math.max(0,Math.min(w,(y.y-s.min[1])*z)),n=Math.max(0,Math.min(A,(y.z-s.min[2])*L)),k=Math.min(M-1,Math.floor(r)),N=Math.min(w-1,Math.floor(i)),B=Math.min(A-1,Math.floor(n)),S=r-k,V=i-N,E=n-B,F=y.x>=s.min[0]&&y.x<=s.max[0]?v:0,W=y.y>=s.min[1]&&y.y<=s.max[1]?z:0,j=y.z>=s.min[2]&&y.z<=s.max[2]?L:0;p.set(0,0,0),g.identity();const D=g.elements;for(let e=0;e<2;e++)for(let t=0;t<2;t++)for(let r=0;r<2;r++){const i=s.offsets[k+r+(M+1)*(N+t+(w+1)*(B+e))],n=r?S:1-S,o=t?V:1-V,a=e?E:1-E,m=n*o*a,f=(r?F:-F)*o*a,l=n*(t?W:-W)*a,u=n*o*(e?j:-j);p.x+=i[0]*m,p.y+=i[1]*m,p.z+=i[2]*m;for(let e=0;e<3;e++)D[e]+=i[e]*f,D[3+e]+=i[e]*l,D[6+e]+=i[e]*u}y.add(p).applyMatrix4(f),o.setXYZ(e,y.x,y.y,y.z),a&&(b.copy(g).invert().transpose(),h.fromBufferAttribute(a,e).applyMatrix3(l).applyMatrix3(b).applyMatrix3(u).normalize(),a.setXYZ(e,h.x,h.y,h.z)),m&&(x.fromBufferAttribute(m,e).applyMatrix3(c).applyMatrix3(g).applyMatrix3(d),a&&x.addScaledVector(h,-x.dot(h)),x.normalize(),m.setXYZ(e,x.x,x.y,x.z),m.itemSize>3&&g.determinant()<0&&m.setW(e,-m.getW(e)))}return o.needsUpdate=!0,a?a.needsUpdate=!0:i.computeVertexNormals(),m&&(m.needsUpdate=!0),i.computeBoundingBox(),i.computeBoundingSphere(),"boundsTree"in i&&(i.boundsTree=null),i}const m=new WeakMap;export function setLatticeGeometrySourceIdentity(e,t){m.set(e,t)}function f(e){const t=new Set;for(const r of[...Object.values(e.attributes),...Object.values(e.morphAttributes).flat(),e.index]){if(!r)continue;const e="data"in r?r.data.array:r.array;t.add(e.buffer)}let r=0;for(const e of t)r+=e.byteLength;return r}export class LatticeGeometryCache{constructor(){this.disposed=!1,this.roots=new WeakSet,this.entries=new Map,this.bindings=new WeakMap}apply(e,t,r=""){if(this.disposed)return;const s=isValidLattice(t)&&!1!==t.enabled&&t.offsets.some(e=>0!==e[0]||0!==e[1]||0!==e[2]);if(!s&&!this.roots.has(e))return;s?this.roots.add(e):this.roots.delete(e);const i=s?JSON.stringify([t.segments,t.min,t.max,t.offsets]):"";o(e,n=>{let o=this.bindings.get(n);if(!o&&!s)return;o||(o={source:n.geometry},this.bindings.set(n,o));const l=s?a(e,n):null,u=s?`${m.get(o.source)??o.source.uuid}:${l.elements.join(",")}:${i}:${r}`:void 0;if(o.key!==u)if(o.key&&this.entries.get(o.key).users--,o.key=u,u){let e=this.entries.get(u);if(!e){const r=deformLatticeGeometry(o.source,l,t);e={geometry:r,users:0,bytes:f(r)},this.entries.set(u,e)}e.users++,n.geometry=e.geometry}else n.geometry=o.source}),this.prune()}release(e){this.disposed||(this.roots.delete(e),e.traverse(e=>{if(!(e instanceof i))return;const t=this.bindings.get(e);t?.key&&this.entries.get(t.key).users--,this.bindings.delete(e)}),this.prune())}prune(){let e=0,t=0;for(const r of this.entries.values())r.users||(e++,t+=r.bytes);for(const[r,s]of this.entries)!s.users&&(e>8||t>67108864)&&(s.geometry.dispose(),this.entries.delete(r),e--,t-=s.bytes)}dispose(){if(!this.disposed){this.disposed=!0;for(const e of this.entries.values())e.geometry.dispose();this.entries.clear()}}}/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type LatticeDeformation } from './lattice-deformation.js';
|
|
2
|
+
export { createLatticeDeformation, latticePoint, isValidLattice, deformLatticeGeometry, LatticeGeometryCache, type LatticeDeformation } from './lattice-deformation.js';
|
|
1
3
|
import { Subject } from "rxjs";
|
|
2
4
|
import * as THREE from "three";
|
|
3
5
|
import { Euler, Material, Object3D, Scene, Vector3 } from "three";
|
|
@@ -6,6 +8,7 @@ import { VisualEffect } from '../effects/vfx/vfx-param.js';
|
|
|
6
8
|
import { DataAssetRef } from './objects/data-asset.js';
|
|
7
9
|
import { GameComponent } from '../game-component/game-component.js';
|
|
8
10
|
import { BaseActor } from '../gameplay/actors/actor.js';
|
|
11
|
+
import type { ActorPersistence } from '../gameplay/services/actor-persistence.js';
|
|
9
12
|
import { ActorComponent } from '../gameplay/actors/component.js';
|
|
10
13
|
import { PhysicsBodyType } from '../gameplay/services/physics/physics-system.js';
|
|
11
14
|
import { NetMode } from '../gameplay/net/net-session.js';
|
|
@@ -124,9 +127,9 @@ export type SceneObject = {
|
|
|
124
127
|
* Grass settings. Only relevant for object type landscape
|
|
125
128
|
*/
|
|
126
129
|
grass?: GrassSettings;
|
|
127
|
-
/**
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
/** Object-local cage for static mesh assets. Does not deform authored collision shapes. */
|
|
131
|
+
latticeDeformation?: LatticeDeformation;
|
|
132
|
+
/** Surface scatter settings. Only relevant for object type asset_mesh in v1. */
|
|
130
133
|
surfaceScatter?: SurfaceScatterSettings;
|
|
131
134
|
/**
|
|
132
135
|
* Artist-painted scatter settings. Only relevant for object type scatter.
|
|
@@ -363,6 +366,15 @@ export declare class SceneMaterializer {
|
|
|
363
366
|
private paintedScatterManager?;
|
|
364
367
|
private surfaceScatterManager?;
|
|
365
368
|
materializedActors: Map<string, BaseActor>;
|
|
369
|
+
private persistence?;
|
|
370
|
+
private persistenceSceneId?;
|
|
371
|
+
private readonly authoredPersistenceTargets;
|
|
372
|
+
private readonly authoredPersistenceParents;
|
|
373
|
+
/** Index prefab exposure and scene ancestry before filtering removed objects. */
|
|
374
|
+
preparePersistence(persistence: ActorPersistence, sceneId: string, objects: SceneObject[]): Promise<SceneObject[]>;
|
|
375
|
+
private persistenceActorPath;
|
|
376
|
+
private isPersistenceRemoved;
|
|
377
|
+
registerPersistentActors(): BaseActor[];
|
|
366
378
|
idToSceneObject: Map<string, SceneObject>;
|
|
367
379
|
inEditor: boolean;
|
|
368
380
|
netMode: NetMode;
|
|
@@ -406,6 +418,7 @@ export declare class SceneMaterializer {
|
|
|
406
418
|
* when needed to support larger worlds.
|
|
407
419
|
*/
|
|
408
420
|
private initTextures;
|
|
421
|
+
private texturePrefetch?;
|
|
409
422
|
private prefetchAssets;
|
|
410
423
|
private collectAssetMeshIds;
|
|
411
424
|
private collectObjectAssetMeshIds;
|
|
@@ -469,6 +482,9 @@ export declare class SceneMaterializer {
|
|
|
469
482
|
private attachEditorComponents;
|
|
470
483
|
private addVfxChildActors;
|
|
471
484
|
private applyActorComponentParams;
|
|
485
|
+
private readonly latticeGeometries;
|
|
486
|
+
/** Editor preview only; persistence and history remain the editor's responsibility. */
|
|
487
|
+
previewLatticeDeformation(object: Object3D, data?: LatticeDeformation): void;
|
|
472
488
|
private canObjectBeInstanced;
|
|
473
489
|
private _canBeInstancedCache;
|
|
474
490
|
private experimentalStaticDrawSetDisposer?;
|
|
@@ -598,6 +614,8 @@ export declare class SceneMaterializer {
|
|
|
598
614
|
private geometryCache;
|
|
599
615
|
private collisionShapeCache;
|
|
600
616
|
private createMeshByShape;
|
|
617
|
+
private readonly modelImageBitmaps;
|
|
618
|
+
private decodeModelImage;
|
|
601
619
|
private createFromAsset;
|
|
602
620
|
private createFromPrefab;
|
|
603
621
|
/**
|
|
@@ -682,4 +700,5 @@ type MaterializeContext = {
|
|
|
682
700
|
/** Runtime-spawned prefabs are owned directly by World instead. */
|
|
683
701
|
runtimeSpawn?: boolean;
|
|
684
702
|
};
|
|
703
|
+
export declare function freezeSkinnedMeshes(object: Object3D, cacheLatticeIdentity?: boolean): Object3D;
|
|
685
704
|
//# sourceMappingURL=materializer.d.ts.map
|