| 123456789101112131415161718192021 |
- import { readFileSync } from 'node:fs'
- import draco3d from '../../../../../node_modules/draco3d/draco3d.js'
- const d = await draco3d.createDecoderModule({})
- for (const path of process.argv.slice(2)) {
- const raw=readFileSync(path), size=raw.readUInt32LE(12), j=JSON.parse(raw.toString('utf8',20,20+size)), bin=raw.subarray(size+28)
- const report={path,triangles:0,bad:[]}
- for(const p of j.meshes[0].primitives){
- const e=p.extensions.KHR_draco_mesh_compression,v=j.bufferViews[e.bufferView],data=bin.subarray(v.byteOffset||0,(v.byteOffset||0)+v.byteLength)
- const decoder=new d.Decoder(), buffer=new d.DecoderBuffer(), mesh=new d.Mesh();buffer.Init(new Int8Array(data),data.length)
- const status=decoder.DecodeBufferToMesh(buffer,mesh);if(!status.ok())throw Error(status.error_msg())
- function attr(s){const a=decoder.GetAttributeByUniqueId(mesh,e.attributes[s]),ptr=d._malloc(mesh.num_points()*12);decoder.GetAttributeDataArrayForAllPoints(mesh,a,d.DT_FLOAT32,mesh.num_points()*12,ptr);const result=new Float32Array(d.HEAPF32.buffer,ptr,mesh.num_points()*3).slice();d._free(ptr);return result}
- const positions=attr('POSITION'),normals=attr('NORMAL'),ptr=d._malloc(mesh.num_faces()*12);decoder.GetTrianglesUInt32Array(mesh,mesh.num_faces()*12,ptr);const indices=new Uint32Array(d.HEAPU32.buffer,ptr,mesh.num_faces()*3).slice();d._free(ptr)
- for(let f=0;f<mesh.num_faces();f++){
- const ids=indices.subarray(f*3,f*3+3),[a,b,c]=Array.from(ids,id=>Array.from(positions.subarray(id*3,id*3+3))),u=b.map((x,i)=>x-a[i]),w=c.map((x,i)=>x-a[i]),cross=[u[1]*w[2]-u[2]*w[1],u[2]*w[0]-u[0]*w[2],u[0]*w[1]-u[1]*w[0]],area2=Math.hypot(...cross)
- report.triangles++;const dot=cross.reduce((sum,x,i)=>sum+x*normals[ids[0]*3+i],0)/area2
- if(dot<0.9||area2<1e-10)report.bad.push({material:j.materials[p.material].name,face:f,dot,area:area2/2,positions:[a,b,c]})
- }
- for(const obj of [status,mesh,buffer,decoder])d.destroy(obj)
- }
- console.log(JSON.stringify(report))
- }
|