PageSourceSearch

https://www.hylab.cn/_nuxt/DBFrqV68.js

js hylab.cn collected 2026-10-06 17:48:02 UTC 36,531 bytes, 1 lines download raw bytes

1import{_ as je}from"./D-MUCNxV.js";import{_ as $e}from"./DwcSeOE_.js";import{a as ie,c as ce,j as ke}from"./W1TgRJYa.js";import{_ as ue}from"./DmsNOQ8W.js";import{_ as Ce}from"./DDS9BHTO.js";import{_ as Me}from"./DZ-VdPQV.js";import{_ as Se}from"./B3Se1-Cm.js";import{A as Ie}from"./DGnCCaWY.js";import{C as Te}from"./BEgrC1e7.js";import{C as Ne}from"./CpO-xpUX.js";import{_ as Ue}from"./BCyQu7cd.js";import{l as de,W as T,A as R,a3 as y,Y as B,ae as e,a1 as D,u as r,a4 as P,a2 as L,$ as J,J as he,ac as be,X as re,a9 as Fe,j as N,r as ve,n as xe,C as _e,q as Be}from"./Dqo3qaBd.js";import"./BG6OCo_E.js";import"./BdJn1KuN.js";import"./bP-9rpc3.js";import"./Bc1m-ga_.js";import"./CZASFq4B.js";import"./-pdA1fqS.js";import"./BGJ5elDp.js";import"./BhtNSMY5.js";import"./BAYYwzxh.js";import"./CR4N7Y8R.js";import"./9mAZmDNa.js";import"./_cWlG-EH.js";import"./BWju5z7f.js";import"./BfdHIRBl.js";import"./CD1NNBjR.js";import"./DqhbohBS.js";const De=["/js/three-bin/three.min.js","/js/three-bin/BinaryLoader.js","/js/three-bin/GLTFExporter.js","/js/three-bin/GLTFLoader.js","/js/three-bin/OrbitControls.js"],fe=new Map;let we=!1;function Ae(I){if(fe.has(I))return fe.get(I);const p=new Promise((b,g)=>{const o=document.createElement("script");o.src=I,o.async=!1,o.onload=()=>b(),o.onerror=()=>g(new Error(`加载脚本失败: ${I}`)),document.head.appendChild(o)});return fe.set(I,p),p}async function ye(){if(!we){we=!0;for(const I of De)await Ae(I)}return window.THREE}function Ge(I,p,b){const g=new I.BufferGeometry;p.vertices.length;const o=p.faces.length,v=b?b.length:1,f=v>1,c={};for(let _=0;_<v;_++)c[_]=[];for(let _=0;_<o;_++){const U=p.faces[_],H=f&&U.materialIndex||0;c[H]||(c[H]=[]),c[H].push(_)}const j=[],u=[],h=[],a=[],m=[];let w=0,x=0;for(let _=0;_<v;_++){const U=c[_]||[];if(U.length===0)continue;const H=w,Q=new Map;for(const Z of U){const q=p.faces[Z],X=[];for(let K=0;K<3;K++){const Y=K===0?q.a:K===1?q.b:q.c,d=q.vertexNormals&&q.vertexNormals.length===3?q.vertexNormals[K]:q.normal,l=p.faceVertexUvs[0]&&p.faceVertexUvs[0][Z],s=l?p.faceVertexUvs[0][Z][K]:null,i=`${Y}_${d.x.toFixed(4)}_${d.y.toFixed(4)}_${d.z.toFixed(4)}_${l?`${s.x.toFixed(4)}_${s.y.toFixed(4)}`:"noUV"}`;let C;if(Q.has(i))C=Q.get(i);else{C=w,Q.set(i,C);const $=p.vertices[Y];j.push($.x,$.y,$.z),u.push(d.x,d.y,d.z),l&&h.push(s.x,1-s.y),w++}X.push(C)}a.push(X[0],X[1],X[2])}if(w-H>0){const Z=U.length*3;m.push({start:x,count:Z,materialIndex:_}),x+=Z}}return g.addAttribute("position",new I.Float32BufferAttribute(j,3)),g.addAttribute("normal",new I.Float32BufferAttribute(u,3)),h.length>0&&g.addAttribute("uv",new I.Float32BufferAttribute(h,2)),g.setIndex(a),m.forEach(_=>{g.addGroup(_.start,_.count,_.materialIndex)}),g}function Le(I,p){return new Promise(async(b,g)=>{try{const o=await p.jsonFile.text(),v=JSON.parse(o),f=URL.createObjectURL(p.binFile);v.buffers=f;const c={};if(p.textureFiles&&p.textureFiles.length>0){for(const a of p.textureFiles)c[a.name]=URL.createObjectURL(a);v.materials&&v.materials.length>0&&v.materials.forEach(a=>{a.mapDiffuse&&c[a.mapDiffuse]&&(a.mapDiffuse=c[a.mapDiffuse]),a.mapAlpha&&c[a.mapAlpha]&&(a.mapAlpha=c[a.mapAlpha]),a.mapNormal&&c[a.mapNormal]&&(a.mapNormal=c[a.mapNormal]),a.mapSpecular&&c[a.mapSpecular]&&(a.mapSpecular=c[a.mapSpecular]),a.mapBump&&c[a.mapBump]&&(a.mapBump=c[a.mapBump])})}const j=new Blob([JSON.stringify(v)],{type:"application/json"}),u=URL.createObjectURL(j),h=new I.BinaryLoader;h.binaryPath="",h.texturePath="",h.load(u,(a,m)=>{URL.revokeObjectURL(u),URL.revokeObjectURL(f),Object.values(c).forEach(w=>URL.revokeObjectURL(w)),b({geometry:a,materials:Array.isArray(m)?m:[m],jsonData:JSON.parse(o)})},void 0,a=>{URL.revokeObjectURL(u),URL.revokeObjectURL(f),Object.values(c).forEach(m=>URL.revokeObjectURL(m)),g(new Error("模型加载失败: "+(a?.message||a)))})}catch(o){g(o)}})}function Re(I,p,b){const g=[];return p&&p.length>0&&p.forEach((o,v)=>{const f=new I.MeshStandardMaterial({color:new I.Color(1,1,1),metalness:0,roughness:.9,flatShading:!1,side:I.DoubleSide});if(o.color&&f.color.copy(o.color),o.map&&o.map.image&&o.map.image.width&&(f.map=o.map,f.needsUpdate=!0),o.opacity!==void 0&&o.opacity<1&&(f.transparent=!0,f.opacity=o.opacity),b&&b.materials&&b.materials[v]){const c=b.materials[v];c.alphaTest&&(f.alphaTest=c.alphaTest,f.transparent=!0),c.mapAlpha&&(f.transparent=!0,f.alphaTest=c.alphaTest||.5)}f.name=o.name||`material_${v}`,g.push(f)}),g.length===0&&g.push(new I.MeshStandardMaterial({color:13421772,metalness:0,roughness:.9,flatShading:!1,side:I.DoubleSide})),g}function Ee(I,p,b,g){b&&b.dispose(),g&&g.length>0&&g.forEach(o=>{o.map&&o.map.dispose(),o.dispose()}),p&&(p.geometry=null,p.material=null)}const Ve={class:"space-y-6"},Oe={class:"space-y-4"},ze={class:"text-sm text-gray-600"},Pe={key:0,class:"text-xs text-gray-500 mt-1"},We={class:"text-sm text-gray-600"},Je={key:0,class:"text-xs text-gray-500 mt-1"},He={class:"text-sm text-gray-600"},qe={key:0,class:"mt-2 flex flex-wrap gap-2"},Ke=["onClick"],Ze={class:"flex gap-3"},Xe={class:"space-y-4"},Ye={class:"p-4 bg-primary-50 rounded-lg"},Qe={class:"grid grid-cols-2 md:grid-cols-4 gap-4 text-sm"},et={class:"text-xl font-bold text-primary-600"},tt={class:"text-xl font-bold text-primary-600"},nt={class:"text-xl font-bold text-primary-600"},ot={class:"text-xl font-bold text-primary-600"},st={class:"bg-gray-900 text-gray-100 p-4 rounded-lg max-h-64 overflow-y-auto text-xs font-mono"},rt=de({__name:"BinToGlbConverter",setup(I){const p=N(null),b=N(null),g=N(null),o=N(null),v=N(null),f=N([]),c=N(!1),j=N(null),u=N([]),h=ve({vertices:0,triangles:0,materials:0,textures:0}),a=xe(()=>o.value&&v.value);function m(d,l="info"){const s=new Date;u.value.push({message:d,type:l,time:s.toLocaleTimeString()})}function w(d){return{"text-blue-400":d==="info","text-green-400":d==="success","text-red-400":d==="error"}}function x(d){return d<1024?d+" B":d<1024*1024?(d/1024).toFixed(2)+" KB":(d/(1024*1024)).toFixed(2)+" MB"}function _(d){const l=d.target;l.files?.[0]&&(o.value=l.files[0])}function U(d){const l=d.target;l.files?.[0]&&(v.value=l.files[0])}function H(d){const l=d.target;l.files&&f.value.push(...Array.from(l.files))}function Q(d){d.dataTransfer?.files?.[0]&&(o.value=d.dataTransfer.files[0])}function ae(d){d.dataTransfer?.files?.[0]&&(v.value=d.dataTransfer.files[0])}function Z(d){d.dataTransfer?.files&&f.value.push(...Array.from(d.dataTransfer.files))}function q(d){f.value.splice(d,1)}function X(){o.value=null,v.value=null,f.value=[],j.value=null,u.value=[],p.value&&(p.value.value=""),b.value&&(b.value.value=""),g.value&&(g.value.value="")}async function K(){if(!(!o.value||!v.value)){c.value=!0,u.value=[],j.value=null;try{m("正在加载旧版 three.js...","info");const d=await ye();m("正在加载 BIN 模型...","info");const l={jsonFile:o.value,binFile:v.value,textureFiles:f.value.length>0?f.value:void 0},s=await Le(d,l);m(`模型加载成功: ${s.geometry.vertices?.length||0} 顶点, ${s.geometry.faces?.length||0} 面`,"success");let i=0,C=0;for(let S=0;S<s.geometry.faces.length;S++){const V=s.geometry.faces[S];if(V.vertexNormals&&V.vertexNormals.length===3){const z=V.vertexNormals[0];z&&z.lengthSq&&z.lengthSq()>.001?i++:C++}else C++}i===0&&C>0&&s.geometry.computeVertexNormals(),m("正在转换几何体...","info");const $=Ge(d,s.geometry,s.materials);s.geometry.dispose();const n=$.getAttribute("normal");if(n){for(let S=0;S<n.count;S++){const V=n.getX(S),k=n.getY(S),z=n.getZ(S),ee=Math.sqrt(V*V+k*k+z*z);ee>.001&&n.setXYZ(S,V/ee,k/ee,z/ee)}n.needsUpdate=!0}const t=Re(d,s.materials,s.jsonData),F=new d.Mesh($,t.length===1?t[0]:t);F.name=o.value.name.replace(/\.json$/i,""),h.vertices=$.getAttribute("position")?.count||0,h.triangles=$.index?Math.floor($.index.count/3):Math.floor(h.vertices/3),h.materials=t.length,h.textures=t.filter(S=>S.map).length,m("正在导出 GLB...","info");const M=new d.GLTFExporter,E=await new Promise((S,V)=>{M.parse(F,k=>{k instanceof ArrayBuffer?S(k):k instanceof Uint8Array?S(k.buffer):typeof k=="object"?S(new TextEncoder().encode(JSON.stringify(k)).buffer):V(new Error("不支持的导出格式"))},k=>V(k),{binary:!0,embedImages:!0,truncateDrawRange:!0,onlyVisible:!0,forceIndices:!1})});j.value=E,m(`GLB 转换成功!文件大小: ${x(E.byteLength)}`,"success"),Ee(d,F,$,t)}catch(d){m(`转换失败: ${d.message}`,"error"),console.error(d)}finally{c.value=!1}}}function Y(){if(!j.value)return;const d=new Blob([j.value],{type:"model/gltf-binary"}),l=URL.createObjectURL(d),s=document.createElement("a");s.href=l,s.download=o.value?.name.replace(/\.json$/i,".glb")||"model.glb",s.click(),URL.revokeObjectURL(l)}return(d,l)=>{const s=ie,i=Ue,C=ce,$=ue;return T(),R("div",Ve,[y($,null,{header:B(()=>[...l[6]||(l[6]=[e("h3",{class:"text-lg font-semibold text-gray-900"},"上传 BIN 模型文件",-1)])]),default:B(()=>[e("div",Oe,[e("div",null,[l[7]||(l[7]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},[D(" JSON 元数据文件 "),e("span",{class:"text-red-500"},"*")],-1)),e("div",{class:"border-2 border-dashed border-gray-300 rounded-lg p-6 text-center hover:border-primary-400 transition-colors cursor-pointer",onDragover:l[0]||(l[0]=P(()=>{},["prevent"])),onDrop:P(Q,["prevent"]),onClick:l[1]||(l[1]=n=>r(p)?.click())},[y(s,{name:"i-heroicons-document",class:"w-8 h-8 mx-auto text-gray-400 mb-2"}),e("p",ze,L(r(o)?r(o).name:"点击或拖拽 .json 文件到此处"),1),r(o)?(T(),R("p",Pe,L(x(r(o).size)),1)):J("",!0),e("input",{ref_key:"jsonInput",ref:p,type:"file",accept:".json",class:"hidden",onChange:_},null,544)],32)]),e("div",null,[l[8]||(l[8]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},[D(" BIN 二进制文件 "),e("span",{class:"text-red-500"},"*")],-1)),e("div",{class:"border-2 border-dashed border-gray-300 rounded-lg p-6 text-center hover:border-primary-400 transition-colors cursor-pointer",onDragover:l[2]||(l[2]=P(()=>{},["prevent"])),onDrop:P(ae,["prevent"]),onClick:l[3]||(l[3]=n=>r(b)?.click())},[y(s,{name:"i-heroicons-cube",class:"w-8 h-8 mx-auto text-gray-400 mb-2"}),e("p",We,L(r(v)?r(v).name:"点击或拖拽 .bin 文件到此处"),1),r(v)?(T(),R("p",Je,L(x(r(v).size)),1)):J("",!0),e("input",{ref_key:"binInput",ref:b,type:"file",accept:".bin",class:"hidden",onChange:U},null,544)],32)]),e("div",null,[l[10]||(l[10]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},[D(" 纹理文件 "),e("span",{class:"text-gray-400 text-xs"},"(可选)")],-1)),e("div",{class:"border-2 border-dashed border-gray-300 rounded-lg p-6 text-center hover:border-primary-400 transition-colors cursor-pointer",onDragover:l[4]||(l[4]=P(()=>{},["prevent"])),onDrop:P(Z,["prevent"]),onClick:l[5]||(l[5]=n=>r(g)?.click())},[y(s,{name:"i-heroicons-photo",class:"w-8 h-8 mx-auto text-gray-400 mb-2"}),e("p",He,L(r(f).length>0?`${r(f).length} 个纹理文件`:"点击或拖拽纹理文件到此处"),1),l[9]||(l[9]=e("p",{class:"text-xs text-gray-500"},"支持 .jpg, .png 格式",-1)),e("input",{ref_key:"textureInput",ref:g,type:"file",accept:".jpg,.jpeg,.png",multiple:"",class:"hidden",onChange:H},null,544)],32),r(f).length>0?(T(),R("div",qe,[(T(!0),R(he,null,be(r(f),(n,t)=>(T(),re(i,{key:t,color:"neutral",variant:"subtle",size:"sm"},{default:B(()=>[D(L(n.name)+" ",1),e("button",{class:"ml-1 text-gray-400 hover:text-red-500",onClick:F=>q(t)},"×",8,Ke)]),_:2},1024))),128))])):J("",!0)]),e("div",Ze,[y(C,{color:"primary",disabled:!r(a)||r(c),loading:r(c),onClick:K},{default:B(()=>[D(L(r(c)?"转换中...":"转换为 GLB"),1)]),_:1},8,["disabled","loading"]),y(C,{color:"neutral",variant:"outline",onClick:X},{default:B(()=>[...l[11]||(l[11]=[D("清空",-1)])]),_:1})])])]),_:1}),r(j)?(T(),re($,{key:0},{header:B(()=>[...l[12]||(l[12]=[e("h3",{class:"text-lg font-semibold text-gray-900"},"转换结果",-1)])]),default:B(()=>[e("div",Xe,[e("div",Ye,[e("div",Qe,[e("div",null,[l[13]||(l[13]=e("p",{class:"text-gray-600"}
1,"顶点数",-1)),e("p",et,L(r(h).vertices.toLocaleString()),1)]),e("div",null,[l[14]||(l[14]=e("p",{class:"text-gray-600"},"三角形数",-1)),e("p",tt,L(r(h).triangles.toLocaleString()),1)]),e("div",null,[l[15]||(l[15]=e("p",{class:"text-gray-600"},"材质数",-1)),e("p",nt,L(r(h).materials),1)]),e("div",null,[l[16]||(l[16]=e("p",{class:"text-gray-600"},"纹理数",-1)),e("p",ot,L(r(h).textures),1)])])]),y(C,{color:"primary",onClick:Y},{default:B(()=>[y(s,{name:"i-heroicons-arrow-down-tray",class:"w-4 h-4 mr-2"}),l[17]||(l[17]=D(" 下载 GLB 文件 ",-1))]),_:1})])]),_:1})):J("",!0),r(u).length>0?(T(),re($,{key:1},{header:B(()=>[...l[18]||(l[18]=[e("h3",{class:"text-lg font-semibold text-gray-900"},"转换日志",-1)])]),default:B(()=>[e("div",st,[(T(!0),R(he,null,be(r(u),(n,t)=>(T(),R("div",{key:t,class:Fe(w(n.type))}," ["+L(n.time)+"] "+L(n.message),3))),128))])]),_:1})):J("",!0)])}}}),at=Object.assign(rt,{__name:"BinToGlbConverter"}),lt={class:"space-y-4"},it={class:"space-y-4"},ct={class:"grid grid-cols-1 md:grid-cols-2 gap-4"},ut={class:"text-sm text-gray-600"},dt={class:"text-sm text-gray-600"},pt={class:"text-sm text-gray-600"},ft={class:"flex gap-3"},mt={class:"flex items-center justify-between"},gt={class:"flex items-center gap-3 text-sm"},vt={key:0,class:"text-gray-600"},xt={class:"relative",style:{height:"600px"}},yt={key:0,class:"absolute top-3 right-3 bg-gray-900/90 text-gray-100 rounded-lg p-3 text-xs space-y-1"},ht={class:"flex justify-between gap-4"},bt={class:"font-mono text-primary-400"},wt={class:"flex justify-between gap-4"},_t={class:"font-mono text-primary-400"},Bt={class:"flex justify-between gap-4"},Lt={class:"font-mono text-primary-400"},jt={class:"flex justify-between gap-4"},$t={class:"font-mono text-primary-400"},kt={key:1,class:"absolute inset-0 flex items-center justify-center bg-gray-900/80"},Ct={key:2,class:"absolute inset-0 flex items-center justify-center"},Mt={class:"text-center text-gray-400"},St=de({__name:"BinModelViewer",setup(I){const p=N(null),b=N(null),g=N(null),o=N(null),v=N(null),f=N([]),c=N(!1),j=N(null),u=ve({name:"",loaded:!1,vertices:0,triangles:0,materials:0,textures:""}),h=xe(()=>o.value&&v.value);let a=null,m=null,w=null,x=null,_=null,U=null,H=null;function Q(n){const t=n.target;t.files?.[0]&&(o.value=t.files[0])}function ae(n){const t=n.target;t.files?.[0]&&(v.value=t.files[0])}function Z(n){const t=n.target;t.files&&f.value.push(...Array.from(t.files))}function q(n){n.dataTransfer?.files?.[0]&&(o.value=n.dataTransfer.files[0])}function X(n){n.dataTransfer?.files?.[0]&&(v.value=n.dataTransfer.files[0])}function K(n){n.dataTransfer?.files&&f.value.push(...Array.from(n.dataTransfer.files))}function Y(){o.value=null,v.value=null,f.value=[],p.value&&(p.value.value=""),b.value&&(b.value.value=""),g.value&&(g.value.value=""),i(),u.loaded=!1,u.name=""}function d(){if(!j.value||!a)return;m=new a.Scene,m.background=new a.Color(1710638);const n=j.value.clientWidth,t=j.value.clientHeight;w=new a.PerspectiveCamera(60,n/t,.1,1e3),w.position.set(5,5,5),x=new a.WebGLRenderer({antialias:!0}),x.setSize(n,t),x.shadowMap.enabled=!0,j.value.appendChild(x.domElement),_=new a.OrbitControls(w,x.domElement),_.enableDamping=!0,_.dampingFactor=.05,_.enableKeys=!1;const F=new a.AmbientLight(16777215,.6);m.add(F);const M=new a.DirectionalLight(16777215,.8);M.position.set(10,10,5),M.castShadow=!0,m.add(M);const E=new a.DirectionalLight(16777215,.3);E.position.set(-10,5,-5),m.add(E);const S=new a.PlaneGeometry(50,50),V=new a.MeshStandardMaterial({color:2763326,roughness:.8}),k=new a.Mesh(S,V);k.rotation.x=-Math.PI/2,k.receiveShadow=!0,m.add(k);const z=new a.GridHelper(50,50,4473958,3355477);m.add(z),window.addEventListener("resize",l),s()}function l(){!j.value||!w||!x||(w.aspect=j.value.clientWidth/j.value.clientHeight,w.updateProjectionMatrix(),x.setSize(j.value.clientWidth,j.value.clientHeight))}function s(){H=requestAnimationFrame(s),_&&_.update(),x&&m&&w&&x.render(m,w)}function i(){U&&m&&(m.remove(U),U.traverse(n=>{n.geometry&&n.geometry.dispose(),n.material&&(Array.isArray(n.material)?n.material.forEach(t=>t.dispose()):n.material.dispose())}),U=null)}
1function C(n){n.transparency!==void 0&&(n.opacity=1-n.transparency,delete n.transparency),delete n.colorAmbient,delete n.opticalDensity,delete n.alphaTest,!n.map&&!n.alphaMap?(n.opacity=1,n.transparent=!1):((n.opacity===void 0||n.opacity===null||isNaN(n.opacity)||n.opacity<=0)&&(n.opacity=1),n.transparent=!0),n.side=a.DoubleSide,n.map&&(n.map.encoding=a.sRGBEncoding),n.visible=!0,n.needsUpdate=!0}async function $(){if(!(!o.value||!v.value)){c.value=!0,u.loaded=!1;try{a||(a=await ye()),m||(await Be(),d()),i();const n={jsonFile:o.value,binFile:v.value,textureFiles:f.value.length>0?f.value:void 0},t=await Le(a,n);let F=0,M=0;for(let A=0;A<t.geometry.faces.length;A++){const oe=t.geometry.faces[A];if(oe.vertexNormals&&oe.vertexNormals.length===3){const pe=oe.vertexNormals[0];pe&&pe.lengthSq&&pe.lengthSq()>.001?F++:M++}else M++}F===0&&M>0&&t.geometry.computeVertexNormals(),U=new a.Mesh(t.geometry,t.materials),u.name=o.value.name.replace(/\.json$/i,""),t.geometry.computeBoundingBox();const E=t.geometry.boundingBox,S=E.getCenter(new a.Vector3);U.position.x=-S.x,U.position.y=-E.min.y,U.position.z=-S.z,U.traverse(A=>{if(A.isMesh&&(A.castShadow=!0,A.receiveShadow=!0,A.material)){const oe=A.material;Array.isArray(oe)?oe.forEach(se=>C(se)):C(oe),Array.isArray(A.material)?A.material.forEach(se=>{se.opacity=1,se.transparent=!1,se.visible=!0,se.needsUpdate=!0}):(A.material.opacity=1,A.material.transparent=!1,A.material.visible=!0,A.material.needsUpdate=!0)}}),U.visible||(U.visible=!0),m.add(U);const V=new a.Box3().setFromObject(U),k=V.getCenter(new a.Vector3),z=V.getSize(new a.Vector3),ee=Math.max(z.x,z.y,z.z),te=w.fov*(Math.PI/180);let ne=Math.abs(ee/2/Math.tan(te/2));ne*=2.5,w.position.set(ne,ne*.7,ne),w.lookAt(k.x,k.y,k.z),_.target.set(k.x,k.y,k.z),_.update();let G=0,O=0;const W=[];t.geometry.attributes?.position?G=t.geometry.attributes.position.count:t.geometry.vertices&&(G=t.geometry.vertices.length),t.geometry.index?O=t.geometry.index.count/3:t.geometry.faces&&(O=t.geometry.faces.length);const le=t.materials;Array.isArray(le)?le.forEach(A=>{A.map&&W.push("漫反射"),A.normalMap&&W.push("法线"),A.alphaMap&&W.push("透明")}):le&&le.map&&W.push("漫反射"),u.vertices=G,u.triangles=Math.floor(O),u.materials=Array.isArray(le)?le.length:1,u.textures=W.length>0?[...new Set(W)].join(", "):"",u.loaded=!0}catch(n){console.error("模型加载失败:",n),alert("模型加载失败: "+n.message)}finally{c.value=!1}}}return _e(()=>{H&&cancelAnimationFrame(H),window.removeEventListener("resize",l),i(),x&&(x.dispose(),x.domElement&&x.domElement.parentNode&&x.domElement.parentNode.removeChild(x.domElement))}),(n,t)=>{const F=ie,M=ce,E=ue;return T(),R("div",lt,[y(E,null,{header:B(()=>[...t[6]||(t[6]=[e("h3",{class:"text-lg font-semibold text-gray-900"},"上传 BIN 模型文件",-1)])]),default:B(()=>[e("div",it,[e("div",ct,[e("div",{class:"border-2 border-dashed border-gray-300 rounded-lg p-4 text-center hover:border-primary-400 transition-colors cursor-pointer",onDragover:t[0]||(t[0]=P(()=>{},["prevent"])),onDrop:P(q,["prevent"]),onClick:t[1]||(t[1]=S=>r(p)?.click())},[y(F,{name:"i-heroicons-document",class:"w-6 h-6 mx-auto text-gray-400 mb-1"}),e("p",ut,L(r(o)?r(o).name:"JSON 文件"),1),e("input",{ref_key:"jsonInput",ref:p,type:"file",accept:".json",class:"hidden",onChange:Q},null,544)],32),e("div",{class:"border-2 border-dashed border-gray-300 rounded-lg p-4 text-center hover:border-primary-400 transition-colors cursor-pointer",onDragover:t[2]||(t[2]=P(()=>{},["prevent"])),onDrop:P(X,["prevent"]),onClick:t[3]||(t[3]=S=>r(b)?.click())},[y(F,{name:"i-heroicons-cube",class:"w-6 h-6 mx-auto text-gray-400 mb-1"}),e("p",dt,L(r(v)?r(v).name:"BIN 文件"),1),e("input",{ref_key:"binInput",ref:b,type:"file",accept:".bin",class:"hidden",onChange:ae},null,544)],32)]),e("div",{class:"border-2 border-dashed border-gray-300 rounded-lg p-4 text-center hover:border-primary-400 transition-colors cursor-pointer",onDragover:t[4]||(t[4]=P(()=>{},["prevent"])),onDrop:P(K,["prevent"]),onClick:t[5]||(t[5]=S=>r(g)?.click())},[y(F,{name:"i-heroicons-photo",class:"w-6 h-6 mx-auto text-gray-400 mb-1"}),e("p",pt,L(r(f).length>0?`${r(f).length} 个纹理文件`:"纹理文件(可选)"),1),e("input",{ref_key:"textureInput",ref:g,type:"file",accept:".jpg,.jpeg,.png",multiple:"",class:"hidden",onChange:Z},null,544)],32),e("div",ft,[y(M,{color:"primary",disabled:!r(h)||r(c),loading:r(c),onClick:$},{default:B(()=>[D(L(r(c)?"加载中...":"加载模型"),1)]),_:1},8,["disabled","loading"]),y(M,{color:"neutral",variant:"outline",onClick:Y},{default:B(()=>[...t[7]||(t[7]=[D("清空",-1)])]),_:1})])])]),_:1}),y(E,null,{header:B(()=>[e("div",mt,[t[9]||(t[9]=e("h3",{class:"text-lg font-semibold text-gray-900"},"3D 查看器",-1)),e("div",gt,[r(u).name?(T(),R("div",vt,[t[8]||(t[8]=e("span",{class:"text-gray-400"},"模型:",-1)),D(" "+L(r(u).name),1)])):J("",!0)])])]),default:B(()=>[e("div",xt,[e("div",{ref_key:"containerRef",ref:j,class:"w-full h-full rounded-lg overflow-hidden bg-gray-900"},null,512),r(u).loaded?(T(),R("div",yt,[e("div",ht,[t[10]||(t[10]=e("span",{class:"text-gray-400"}
1,"顶点数",-1)),e("span",bt,L(r(u).vertices.toLocaleString()),1)]),e("div",wt,[t[11]||(t[11]=e("span",{class:"text-gray-400"},"三角形",-1)),e("span",_t,L(r(u).triangles.toLocaleString()),1)]),e("div",Bt,[t[12]||(t[12]=e("span",{class:"text-gray-400"},"材质数",-1)),e("span",Lt,L(r(u).materials),1)]),e("div",jt,[t[13]||(t[13]=e("span",{class:"text-gray-400"},"纹理",-1)),e("span",$t,L(r(u).textures||"无"),1)])])):J("",!0),t[16]||(t[16]=e("div",{class:"absolute bottom-3 left-1/2 -translate-x-1/2 bg-gray-900/80 text-gray-400 text-xs px-3 py-1 rounded-full"}," 左键旋转 | 滚轮缩放 | 右键平移 ",-1)),r(c)?(T(),R("div",kt,[...t[14]||(t[14]=[e("div",{class:"text-center"},[e("div",{class:"w-10 h-10 border-4 border-primary-400 border-t-transparent rounded-full animate-spin mx-auto mb-2"}),e("p",{class:"text-gray-300 text-sm"},"加载中...")],-1)])])):J("",!0),!r(c)&&!r(u).loaded?(T(),R("div",Ct,[e("div",Mt,[y(F,{name:"i-heroicons-cube-transparent",class:"w-16 h-16 mx-auto mb-3 opacity-50"}),t[15]||(t[15]=e("p",null,"上传模型文件后查看 3D 预览",-1))])])):J("",!0)])]),_:1})])}}}),It=Object.assign(St,{__name:"BinModelViewer"}),Tt={class:"space-y-4"},Nt={class:"space-y-4"},Ut={class:"text-gray-600 mb-1"},Ft={key:0},Dt={class:"text-sm text-gray-600"},At={class:"flex gap-3"},Gt={class:"flex items-center justify-between"},Rt={key:0,class:"text-sm text-gray-600"},Et={class:"relative",style:{height:"600px"}},Vt={key:0,class:"absolute top-3 right-3 bg-gray-900/90 text-gray-100 rounded-lg p-3 text-xs space-y-1"},Ot={class:"flex justify-between gap-4"},zt={class:"font-mono text-primary-400"},Pt={class:"flex justify-between gap-4"},Wt={class:"font-mono text-primary-400"},Jt={class:"flex justify-between gap-4"},Ht={class:"font-mono text-primary-400"},qt={class:"flex justify-between gap-4"},Kt={class:"font-mono text-primary-400"},Zt={key:1,class:"absolute inset-0 flex items-center justify-center bg-gray-900/80"},Xt={key:2,class:"absolute inset-0 flex items-center justify-center"},Yt={class:"text-center text-gray-400"},Qt=de({__name:"GltfModelViewer",setup(I){const p=N(null),b=N(null),g=N(null),o=N([]),v=N(!1),f=N(null),c=ve({name:"",loaded:!1,vertices:0,triangles:0,materials:0,textures:""}),j=xe(()=>g.value?.name.toLowerCase().endsWith(".gltf"));let u=null,h=null,a=null,m=null,w=null,x=null,_=null;function U(s){const i=s.target;i.files?.[0]&&(g.value=i.files[0])}function H(s){s.dataTransfer?.files?.[0]&&(g.value=s.dataTransfer.files[0])}function Q(s){const i=s.target;i.files&&o.value.push(...Array.from(i.files))}function ae(s){s.dataTransfer?.files&&o.value.push(...Array.from(s.dataTransfer.files))}function Z(){g.value=null,o.value=[],p.value&&(p.value.value=""),b.value&&(b.value.value=""),Y(),c.loaded=!1,c.name=""}function q(){if(!f.value||!u)return;h=new u.Scene,h.background=new u.Color(1710638);const s=f.value.clientWidth,i=f.value.clientHeight;a=new u.PerspectiveCamera(60,s/i,.1,1e3),a.position.set(5,5,5),m=new u.WebGLRenderer({antialias:!0}),m.setSize(s,i),m.shadowMap.enabled=!0,m.shadowMap.type=u.PCFSoftShadowMap,f.value.appendChild(m.domElement),w=new u.OrbitControls(a,m.domElement),w.enableDamping=!0,w.dampingFactor=.05,w.enableKeys=!1;const C=new u.AmbientLight(16777215,.6);h.add(C);const $=new u.DirectionalLight(16777215,.8);$.position.set(10,10,5),$.castShadow=!0,h.add($);const n=new u.DirectionalLight(16777215,.3);n.position.set(-10,5,-5),h.add(n);const t=new u.PlaneGeometry(50,50),F=new u.MeshStandardMaterial({color:2763326,roughness:.8}),M=new u.Mesh(t,F);M.rotation.x=-Math.PI/2,M.receiveShadow=!0,h.add(M);const E=new u.GridHelper(50,50,4473958,3355477);h.add(E),window.addEventListener("resize",X),K()}function X(){!f.value||!a||!m||(a.aspect=f.value.clientWidth/f.value.clientHeight,a.updateProjectionMatrix(),m.setSize(f.value.clientWidth,f.value.clientHeight))}function K(){_=requestAnimationFrame(K),w&&w.update(),m&&h&&a&&m.render(h,a)}function Y(){x&&h&&(h.remove(x),x.traverse(s=>{s.geometry&&s.geometry.dispose(),s.material&&(Array.isArray(s.material)?s.material.forEach(i=>i.dispose()):s.material.dispose())}),x=null)}
1function d(s){s.transparency!==void 0&&(s.opacity=1-s.transparency,delete s.transparency),delete s.colorAmbient,delete s.opticalDensity,delete s.alphaTest,!s.map&&!s.alphaMap?(s.opacity=1,s.transparent=!1):((s.opacity===void 0||s.opacity===null||isNaN(s.opacity)||s.opacity<=0)&&(s.opacity=1),s.transparent=!0),s.side=u.DoubleSide,s.map&&(s.map.encoding=u.sRGBEncoding),s.visible=!0,s.needsUpdate=!0}async function l(){if(g.value){v.value=!0,c.loaded=!1;try{u||(u=await ye()),h||(await Be(),q()),Y();const s=URL.createObjectURL(g.value);let i=null;const C={};if(j.value&&o.value.length>0){for(const n of o.value)C[n.name]=URL.createObjectURL(n);i=window.fetch;const $=(n,t)=>{const F=typeof n=="string"?n:n?.url;if(F){const M=F.split("/").pop()?.split("?")[0]||"";if(C[M])return i(C[M],t)}return i(n,t)};window.fetch=$}try{const $=new u.GLTFLoader;x=(await new Promise((G,O)=>{$.load(s,W=>G(W),void 0,W=>O(W))})).scene,x.rotation.x=-Math.PI/2,x.updateMatrixWorld(!0);const t=new u.Box3().setFromObject(x);x.position.x=-t.min.x,x.position.y=-t.min.y,x.position.z=-t.min.z,x.traverse(G=>{if(G.isMesh&&(G.castShadow=!0,G.receiveShadow=!1,G.material)){const O=G.material;Array.isArray(O)?O.forEach(W=>d(W)):d(O)}}),h.add(x);const F=new u.Box3().setFromObject(x),M=F.getCenter(new u.Vector3),E=F.getSize(new u.Vector3),S=Math.max(E.x,E.y,E.z),V=a.fov*(Math.PI/180);let k=Math.abs(S/2/Math.tan(V/2));k*=2.5,a.position.set(k,k*.7,k),a.lookAt(M.x,M.y,M.z),w.target.set(M.x,M.y,M.z),w.update();let z=0,ee=0;const te=[];let ne=0;x.traverse(G=>{if(G.isMesh){if(G.geometry){const O=G.geometry.attributes?.position;O&&(z+=O.count);const W=G.geometry.index;W&&(ee+=W.count/3)}if(G.material){ne++;const O=G.material;O.map&&te.push("漫反射"),O.normalMap&&te.push("法线"),O.roughnessMap&&te.push("粗糙度"),O.metalnessMap&&te.push("金属度")}}}),c.name=g.value.name,c.vertices=z,c.triangles=Math.floor(ee),c.materials=ne,c.textures=te.length>0?[...new Set(te)].join(", "):"",c.loaded=!0}finally{i&&(window.fetch=i),URL.revokeObjectURL(s),Object.values(C).forEach($=>URL.revokeObjectURL($))}}catch(s){console.error("模型加载失败:",s),alert("模型加载失败: "+s.message)}finally{v.value=!1}}}return _e(()=>{_&&cancelAnimationFrame(_),window.removeEventListener("resize",X),Y(),m&&(m.dispose(),m.domElement&&m.domElement.parentNode&&m.domElement.parentNode.removeChild(m.domElement))}),(s,i)=>{const C=ie,$=ce,n=ue;return T(),R("div",Tt,[y(n,null,{header:B(()=>[...i[4]||(i[4]=[e("h3",{class:"text-lg font-semibold text-gray-900"},"上传 glTF/GLB 模型文件",-1)])]),default:B(()=>[e("div",Nt,[e("div",{class:"border-2 border-dashed border-gray-300 rounded-lg p-6 text-center hover:border-primary-400 transition-colors cursor-pointer",onDragover:i[0]||(i[0]=P(()=>{},["prevent"])),onDrop:P(H,["prevent"]),onClick:i[1]||(i[1]=t=>r(p)?.click())},[y(C,{name:"i-heroicons-cube",class:"w-10 h-10 mx-auto text-gray-400 mb-2"}),e("p",Ut,L(r(g)?r(g).name:"点击或拖拽文件到此处上传"),1),i[5]||(i[5]=e("p",{class:"text-sm text-gray-500"},"支持 .gltf 和 .glb 格式",-1)),e("input",{ref_key:"fileInput",ref:p,type:"file",accept:".gltf,.glb",class:"hidden",onChange:U},null,544)],32),r(j)?(T(),R("div",Ft,[e("div",{class:"border-2 border-dashed border-gray-300 rounded-lg p-4 text-center hover:border-primary-400 transition-colors cursor-pointer",onDragover:i[2]||(i[2]=P(()=>{},["prevent"])),onDrop:P(ae,["prevent"]),onClick:i[3]||(i[3]=t=>r(b)?.click())},[y(C,{name:"i-heroicons-photo",class:"w-6 h-6 mx-auto text-gray-400 mb-1"}),e("p",Dt,L(r(o).length>0?`${r(o).length} 个纹理文件`:"纹理文件(.gltf 外部引用)"),1),e("input",{ref_key:"textureInput",ref:b,type:"file",accept:".jpg,.jpeg,.png,.bin",multiple:"",class:"hidden",onChange:Q},null,544)],32)])):J("",!0),e("div",At,[y($,{color:"primary",disabled:!r(g)||r(v),loading:r(v),onClick:l},{default:B(()=>[D(L(r(v)?"加载中...":"加载模型"),1)]),_:1},8,["disabled","loading"]),y($,{color:"neutral",variant:"outline",onClick:Z},{default:B(()=>[...i[6]||(i[6]=[D("清空",-1)])]),_:1})])])]),_:1}),y(n,null,{header:B(()=>[e("div",Gt,[i[8]||(i[8]=e("h3",{class:"text-lg font-semibold text-gray-900"},"3D 查看器",-1)),r(c).loaded?(T(),R("div",Rt,[i[7]||(i[7]=e("span",{class:"text-gray-400"},"模型:",-1)),D(" "+L(r(c).name),1)])):J("",!0)])]),default:B(()=>[e("div",Et,[e("div",{ref_key:"containerRef",ref:f,class:"w-full h-full rounded-lg overflow-hidden bg-gray-900"},null,512),r(c).loaded?(T(),R("div",Vt,[e("div",Ot,[i[9]||(i[9]=e("span",{class:"text-gray-400"}
1,"顶点数",-1)),e("span",zt,L(r(c).vertices.toLocaleString()),1)]),e("div",Pt,[i[10]||(i[10]=e("span",{class:"text-gray-400"},"三角形",-1)),e("span",Wt,L(r(c).triangles.toLocaleString()),1)]),e("div",Jt,[i[11]||(i[11]=e("span",{class:"text-gray-400"},"材质数",-1)),e("span",Ht,L(r(c).materials),1)]),e("div",qt,[i[12]||(i[12]=e("span",{class:"text-gray-400"},"纹理",-1)),e("span",Kt,L(r(c).textures||"无"),1)])])):J("",!0),i[15]||(i[15]=e("div",{class:"absolute bottom-3 left-1/2 -translate-x-1/2 bg-gray-900/80 text-gray-400 text-xs px-3 py-1 rounded-full"}," 左键旋转 | 滚轮缩放 | 右键平移 ",-1)),r(v)?(T(),R("div",Zt,[...i[13]||(i[13]=[e("div",{class:"text-center"},[e("div",{class:"w-10 h-10 border-4 border-primary-400 border-t-transparent rounded-full animate-spin mx-auto mb-2"}),e("p",{class:"text-gray-300 text-sm"},"加载中...")],-1)])])):J("",!0),!r(v)&&!r(c).loaded?(T(),R("div",Xt,[e("div",Yt,[y(C,{name:"i-heroicons-cube-transparent",class:"w-16 h-16 mx-auto mb-3 opacity-50"}),i[14]||(i[14]=e("p",null,"上传模型文件后查看 3D 预览",-1))])])):J("",!0)])]),_:1})])}}}),en=Object.assign(Qt,{__name:"GltfModelViewer"}),tn={class:"px-2 py-12"},nn={class:"mb-6"},on={class:"flex gap-2 w-full md:w-auto flex-wrap"},me="BIN模型转GLB工具 - 在线Three.js模型转换与查看器 | 超腾开源",ge="免费在线BIN模型转GLB工具,将Three.js的BIN模型(.json元数据与.bin二进制几何数据)转换为标准GLB格式,可附加纹理贴图,内置BIN模型与glTF/GLB在线3D查看器,所有转换与渲染均在浏览器本地完成、数据不上传服务器,操作简单,适合Web3D与Three.js开发使用,即开即用、上手简单",Nn=de({__name:"index",setup(I){const p=N("convert");function b(g){p.value=g}return ke({title:me,meta:[{name:"description",content:ge},{name:"keywords",content:"BIN转GLB,Three.js模型转换,BinaryLoader,GLTFExporter,GLTFLoader,3D模型查看器,模型格式转换,在线3D工具"},{name:"author",content:"超腾开源"},{property:"og:type",content:"website"},{property:"og:title",content:me},{property:"og:description",content:ge},{name:"twitter:card",content:"summary"},{name:"twitter:title",content:me},{name:"twitter:description",content:ge}]}),(g,o)=>{const v=je,f=$e,c=ie,j=ce,u=ue,h=Ce,a=Me,m=Se;return T(),re(m,{ui:{root:"mx-0 sm:mx-4",left:"hidden lg:hidden xl:block",center:"lg:col-span-10 xl:col-span-6",right:"hidden lg:hidden xl:block"}},{left:B(()=>[...o[3]||(o[3]=[e("div",null,null,-1)])]),right:B(()=>[y(a,{ui:{root:"py-2"}},{default:B(()=>[y(Ie)]),_:1})]),default:B(()=>[e("div",tn,[y(v,{class:"mb-6"}),o[9]||(o[9]=e("h1",{class:"sr-only"},"BIN模型转GLB工具 - 在线Three.js模型转换与查看器",-1)),o[10]||(o[10]=e("div",{class:"mb-4"},[e("h2",{class:"text-3xl font-bold text-gray-900 mb-4"},"BIN 模型转换与查看器"),e("p",{class:"text-gray-600 text-lg"}," 在线转换 Three.js Binary 模型为 GLB 格式,支持 BIN 模型和 glTF/GLB 模型的在线 3D 查看 ")],-1)),y(f,{color:"info",variant:"subtle",icon:"i-heroicons-information-circle",title:"使用说明",description:"BIN 模型由 .json 元数据文件和 .bin 二进制几何数据文件组成,可附加纹理文件。工具支持将 BIN 模型转换为标准 GLB 格式,以及在线预览 BIN 和 glTF/GLB 模型。所有转换和渲染均在浏览器本地完成,不上传服务器。",class:"mb-8"}),e("div",nn,[e("div",on,[y(j,{color:r(p)==="convert"?"primary":"neutral",variant:r(p)==="convert"?"solid":"outline",onClick:o[0]||(o[0]=w=>b("convert"))},{default:B(()=>[y(c,{name:"i-heroicons-arrow-path",class:"w-4 h-4 mr-2"}),o[4]||(o[4]=D(" BIN 转 GLB ",-1))]),_:1},8,["color","variant"]),y(j,{color:r(p)==="bin-viewer"?"primary":"neutral",variant:r(p)==="bin-viewer"?"solid":"outline",onClick:o[1]||(o[1]=w=>b("bin-viewer"))},{default:B(()=>[y(c,{name:"i-heroicons-cube",class:"w-4 h-4 mr-2"}),o[5]||(o[5]=D(" BIN 模型查看器 ",-1))]),_:1},8,["color","variant"]),y(j,{color:r(p)==="gltf-viewer"?"primary":"neutral",variant:r(p)==="gltf-viewer"?"solid":"outline",onClick:o[2]||(o[2]=w=>b("gltf-viewer"))},{default:B(()=>[y(c,{name:"i-heroicons-cube-transparent",class:"w-4 h-4 mr-2"}),o[6]||(o[6]=D(" glTF 模型查看器 ",-1))]),_:1},8,["color","variant"])])]),r(p)==="convert"?(T(),re(at,{key:0,class:"mb-8"})):r(p)==="bin-viewer"?(T(),re(It,{key:1,class:"mb-8"})):r(p)==="gltf-viewer"?(T(),re(en,{key:2,class:"mb-8"})):J("",!0),y(u,{class:"mb-8"},{header:B(()=>[...o[7]||(o[7]=[e("h2",{class:"text-xl font-semibold text-gray-900"},"格式说明",-1)])]),default:B(()=>[o[8]||(o[8]=e("div",{class:"prose prose-sm max-w-none text-gray-600"},[e("p",null,[e("strong",null,"BIN 模型"),D("是旧版 Three.js(r90 及更早版本)的 BinaryLoader 格式,由两个文件组成: ")]),e("ul",null,[e("li",null,[e("strong",null,".json 文件"),D(":模型元数据,包含材质、ç
1º¹ç†ã€æ‹“扑信息")]),e("li",null,[e("strong",null,".bin 文件"),D(":二进制几何数据,包含顶点、法线、UV 坐标")])]),e("p",null,[e("strong",null,"GLB"),D("(GL Transmission Format Binary)是 Khronos Group 制定的 3D 模型标准格式, 将几何数据、材质、纹理打包在单个二进制文件中,是现代 Web 3D 的标准格式。 ")]),e("h4",{class:"text-gray-900 mt-4"},"转换特性"),e("ul",null,[e("li",null,"支持将旧版 BIN 模型转换为现代 GLB 格式"),e("li",null,"正确处理多材质几何体,保留顶点索引"),e("li",null,"支持纹理文件(漫反射贴图、Alpha 贴图)"),e("li",null,"自动合并 Alpha 贴图到漫反射贴图的透明通道"),e("li",null,"归一化法线向量,修复 GLTFExporter 警告"),e("li",null,"使用旧版 Three.js(r90)加载 BIN 模型,兼容新旧版本")]),e("h4",{class:"text-gray-900 mt-4"},"查看器功能"),e("ul",null,[e("li",null,"支持 BIN 模型和 glTF/GLB 模型的在线 3D 查看"),e("li",null,"轨道控制器:左键旋转、滚轮缩放、右键平移"),e("li",null,"显示模型统计信息(顶点数、三角形数、材质数、纹理信息)"),e("li",null,"自动居中模型并调整相机位置"),e("li",null,"支持阴影渲染和双面材质")]),e("div",{class:"mt-4 p-3 bg-amber-50 rounded-lg border border-amber-200"},[e("p",{class:"text-amber-800 text-xs"},[e("strong",null,"注意:"),D("新版 Three.js(r125+)已移除 BinaryLoader 和旧版 Geometry API。 本工具使用旧版 Three.js(r90)加载 BIN 模型,确保兼容性。 ")])])],-1))]),_:1}),y(Te,{"source-type":"tool","source-id":"7482760568634478592","button-text":"工具"}),y(Ne,{type:"tool",id:"7482760568634478592"}),y(h)])]),_:1})}}});
1export{Nn as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.