UNPKG

@animech-public/playcanvas

Version:
2 lines (1 loc) 7.86 kB
import{CoreExporter as t}from"./core-exporter.js";import{zipSync as e,strToU8 as n}from"../../../modules/fflate/esm/browser.js";import{SEMANTIC_POSITION as s,SEMANTIC_NORMAL as r,SEMANTIC_TEXCOORD0 as i,SEMANTIC_TEXCOORD1 as a}from"../../platform/graphics/constants.js";import{Color as o}from"../../core/math/color.js";const l="root",u=(t,e,n)=>` ${t} inputs:${e} = ${n}`;class f extends t{constructor(...t){super(...t),this.meshMap=void 0,this.materialMap=void 0,this.materials=void 0,this.textureMap=void 0,this.nodeNames=void 0,this.files=void 0}init(){this.meshMap=new Map,this.textureMap=new Map,this.materialMap=new Map,this.materials=[],this.files={},this.nodeNames=new Set}done(){this.meshMap=null,this.textureMap=null,this.materialMap=null,this.materials=null,this.files=null,this.nodeNames=null}build(t,n={}){this.init(),this.addFile(null,l);const s=[];if(t){t.findComponents("render").forEach((t=>{s.push(...t.meshInstances)}))}let r="";s.forEach((t=>{r+=this.buildMeshInstance(t)})),r+=`\ndef "Materials"\n{\n\t\t${this.materials.join("\n")}\n}\n`,this.addFile(null,l,"",r);const i={maxTextureSize:n.maxTextureSize},a=Array.from(this.textureMap.keys()),o=[];for(let t=0;t<a.length;t++){const e="image/png",n=a[t],s=this.textureToCanvas(n,i).then((t=>t?new Promise((n=>t.toBlob(n,e,1))).then((t=>t.arrayBuffer())):(console.warn(`Export of texture ${n.name} is not currently supported.`),new Promise((t=>t(null))))));o.push(s)}return Promise.all(o).then((t=>{t.forEach(((t,e)=>{const n=a[e],s=this.getTextureFileIds(n);this.files[s.fileName]=new Uint8Array(t)})),this.alignFiles();const n=e(this.files,{level:0});return this.done(),n}))}alignFiles(){let t=0;for(const e in this.files){const n=this.files[e];t+=34+e.length;const s=63&t;if(4!==s){const t=new Uint8Array(64-s);this.files[e]=[n,{extra:{12345:t}}]}t=n.length}}getFileIds(t,e,n,s="usda"){const r=`${t?`${t}/`:""}${e}.${s}`;return{name:e,fileName:r,refName:`@./${r}@</${n}>`}}getTextureFileIds(t){return this.getFileIds("texture",`Texture_${t.id}`,"Texture","png")}addFile(t,e,s="",r=""){let i=null;r&&(i=n(r=`#usda 1.0\n(\n\t\tcustomLayerData = {\n\t\t\t\tstring creator = "PlayCanvas UsdzExporter"\n\t\t}\n\t\tmetersPerUnit = 1\n\t\tupAxis = "Y"\n)\n\n${r}`));const a=this.getFileIds(t,e,s);return this.files[a.fileName]=i,a.refName}getMaterialRef(t){let e=this.materialMap.get(t);return e||(e=this.buildMaterial(t),this.materialMap.set(t,e)),e}getMeshRef(t){let e=this.meshMap.get(t);return e||(e=this.buildMesh(t),this.meshMap.set(t,e)),e}buildArray2(t){const e=[],n=t.length;for(let s=0;s<n;s+=2)e.push(`(${t[s]}, ${1-t[s+1]})`);return e.join(", ")}buildArray3(t){const e=[],n=t.length;for(let s=0;s<n;s+=3)e.push(`(${t[s]}, ${t[s+1]}, ${t[s+2]})`);return e.join(", ")}buildMat4(t){const e=t.data,n=[];for(let t=0;t<16;t+=4)n.push(`(${e[t]}, ${e[t+1]}, ${e[t+2]}, ${e[t+3]})`);return`( ${n.join(", ")} )`}buildMaterial(t){const e=`Material_${t.id}`,n=`/Materials/${e}`,s=t=>`<${n}${t}>`,r=[],i=[],a=(e,n,a,l,f,h=!1,d=!1)=>{const p=t[e];if(p){const m=this.getTextureFileIds(p);this.textureMap.set(p,m.refName);const c=t[`${e}Channel`]||"rgb",$=s(`/${m.name}_${f}.outputs:${c}`);r.push(u(a,`${l}.connect`,$)),h&&t.alphaTest;const g=t[`${e}Tiling`],M=t[`${e}Offset`],x=t[`${e}Rotation`],v=1===t[`${e}Uv`]?"st1":"st",b=d&&n?n:o.WHITE;i.push(((t,e,n,r,i,a,o,l)=>`\n\t\t\t\t\t\t\t\tdef Shader "Transform2d_${n}" (\n\t\t\t\t\t\t\t\t\t\tsdrMetadata = {\n\t\t\t\t\t\t\t\t\t\t\t\tstring role = "math"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tuniform token info:id = "UsdTransform2d"\n\t\t\t\t\t\t\t\t\t\tfloat2 inputs:in.connect = ${s(`/uvReader_${r}.outputs:result`)}\n\t\t\t\t\t\t\t\t\t\tfloat inputs:rotation = ${o}\n\t\t\t\t\t\t\t\t\t\tfloat2 inputs:scale = (${i.x}, ${i.y})\n\t\t\t\t\t\t\t\t\t\tfloat2 inputs:translation = (${a.x}, ${a.y})\n\t\t\t\t\t\t\t\t\t\tfloat2 outputs:result\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tdef Shader "Texture_${t.id}_${n}"\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tuniform token info:id = "UsdUVTexture"\n\t\t\t\t\t\t\t\t\t\tasset inputs:file = @${e.fileName}@\n\t\t\t\t\t\t\t\t\t\tfloat2 inputs:st.connect = ${s(`/Transform2d_${n}.outputs:result`)}\n\t\t\t\t\t\t\t\t\t\ttoken inputs:wrapS = "repeat"\n\t\t\t\t\t\t\t\t\t\ttoken inputs:wrapT = "repeat"\n\t\t\t\t\t\t\t\t\t\tfloat4 inputs:scale = (${l.r}, ${l.g}, ${l.b}, ${l.a})\n\t\t\t\t\t\t\t\t\t\tfloat outputs:r\n\t\t\t\t\t\t\t\t\t\tfloat outputs:g\n\t\t\t\t\t\t\t\t\t\tfloat outputs:b\n\t\t\t\t\t\t\t\t\t\tfloat3 outputs:rgb\n\t\t\t\t\t\t\t\t\t\tfloat outputs:a\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t`)(p,m,f,v,g,M,x,b))}else if(n){const t="float"===a?`${n}`:`(${n.r}, ${n.g}, ${n.b})`;r.push(u(a,l,t))}};a("diffuseMap",t.diffuse,"color3f","diffuseColor","diffuse",!1,!0),(t.transparent||t.alphaTest>0)&&a("opacityMap",t.opacity,"float","opacity","opacity",!0),a("normalMap",null,"normal3f","normal","normal"),a("emissiveMap",t.emissive,"color3f","emissiveColor","emissive",!1,!0),a("aoMap",null,"float","occlusion","occlusion"),a("metalnessMap",t.metalness,"float","metallic","metallic"),a("glossMap",t.gloss,"float","roughness","roughness");const l=`\n\t\t\t\t\t\tdef Material "${e}"\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdef Shader "PreviewSurface"\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tuniform token info:id = "UsdPreviewSurface"\n${r.join("\n")}\n\t\t\t\t\t\t\t\t\t\tint inputs:useSpecularWorkflow = 0\n\t\t\t\t\t\t\t\t\t\ttoken outputs:surface\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\ttoken outputs:surface.connect = ${s("/PreviewSurface.outputs:surface")}\n\n\t\t\t\t\t\t\t\tdef Shader "uvReader_st"\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tuniform token info:id = "UsdPrimvarReader_float2"\n\t\t\t\t\t\t\t\t\t\ttoken inputs:varname = "st"\n\t\t\t\t\t\t\t\t\t\tfloat2 inputs:fallback = (0.0, 0.0)\n\t\t\t\t\t\t\t\t\t\tfloat2 outputs:result\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tdef Shader "uvReader_st1"\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tuniform token info:id = "UsdPrimvarReader_float2"\n\t\t\t\t\t\t\t\t\t\ttoken inputs:varname = "st1"\n\t\t\t\t\t\t\t\t\t\tfloat2 inputs:fallback = (0.0, 0.0)\n\t\t\t\t\t\t\t\t\t\tfloat2 outputs:result\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t${i.join("\n")}\n\t\t\t\t\t\t}\n\t\t\t\t`;return this.materials.push(l),s("")}buildMesh(t){let e=[];const n=[];let o=[],l=[],u=[];t.getVertexStream(s,e),t.getVertexStream(r,o),t.getVertexStream(i,l),t.getVertexStream(a,u),t.getIndices(n);const f=n.length||e.length,h=Array(f/3).fill(3).join(", ");if(!n.length)for(let t=0;t<f;t++)n[t]=t;const d=e.length/3;o=o.length?o:Array(3*d).fill(0),l=l.length?l:Array(2*d).fill(0),u=u.length?u:Array(2*d).fill(0),e=this.buildArray3(e),o=this.buildArray3(o),l=this.buildArray2(l),u=this.buildArray2(u);const p=((t,e,n,s,r,i)=>`\ndef "Mesh"\n{\n\t\tdef Mesh "Mesh"\n\t\t{\n\t\t\t\tint[] faceVertexCounts = [${t}]\n\t\t\t\tint[] faceVertexIndices = [${e}]\n\t\t\t\tnormal3f[] normals = [${n}] (\n\t\t\t\t\t\tinterpolation = "vertex"\n\t\t\t\t)\n\t\t\t\tpoint3f[] points = [${s}]\n\t\t\t\ttexCoord2f[] primvars:st = [${r}] (\n\t\t\t\t\t\tinterpolation = "vertex"\n\t\t\t\t)\n\t\t\t\ttexCoord2f[] primvars:st1 = [${i}] (\n\t\t\t\t\t\tinterpolation = "vertex"\n\t\t\t\t)\n\t\t\t\tuniform token subdivisionScheme = "none"\n\t\t}\n}\n`)(h,n,o,e,l,u);return this.addFile("mesh",`Mesh_${t.id}`,"Mesh",p)}buildMeshInstance(t){const e=this.getMeshRef(t.mesh),n=this.getMaterialRef(t.material),s=this.buildMat4(t.node.getWorldTransform()),r=t.node.name.replace(/[^a-z0-9]/gi,"_");let i=r;for(;this.nodeNames.has(i);)i=`${r}_${Math.random().toString(36).slice(2,7)}`;return this.nodeNames.add(i),((t,e,n,s)=>`\ndef Xform "${t}" (\n\t\tprepend references = ${e}\n)\n{\n\t\tmatrix4d xformOp:transform = ${n}\n\t\tuniform token[] xformOpOrder = ["xformOp:transform"]\n\n\t\trel material:binding = ${s}\n}\n`)(i,e,s,n)}}export{f as UsdzExporter};