diagnose-normal-winding.mjs 1.9 KB

123456789101112131415161718192021
  1. import { readFileSync } from 'node:fs'
  2. import draco3d from '../../../../../node_modules/draco3d/draco3d.js'
  3. const d = await draco3d.createDecoderModule({})
  4. for (const path of process.argv.slice(2)) {
  5. const raw=readFileSync(path), size=raw.readUInt32LE(12), j=JSON.parse(raw.toString('utf8',20,20+size)), bin=raw.subarray(size+28)
  6. const report={path,triangles:0,bad:[]}
  7. for(const p of j.meshes[0].primitives){
  8. const e=p.extensions.KHR_draco_mesh_compression,v=j.bufferViews[e.bufferView],data=bin.subarray(v.byteOffset||0,(v.byteOffset||0)+v.byteLength)
  9. const decoder=new d.Decoder(), buffer=new d.DecoderBuffer(), mesh=new d.Mesh();buffer.Init(new Int8Array(data),data.length)
  10. const status=decoder.DecodeBufferToMesh(buffer,mesh);if(!status.ok())throw Error(status.error_msg())
  11. 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}
  12. 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)
  13. for(let f=0;f<mesh.num_faces();f++){
  14. 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)
  15. report.triangles++;const dot=cross.reduce((sum,x,i)=>sum+x*normals[ids[0]*3+i],0)/area2
  16. 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]})
  17. }
  18. for(const obj of [status,mesh,buffer,decoder])d.destroy(obj)
  19. }
  20. console.log(JSON.stringify(report))
  21. }