convert-instanced-city.mjs 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637
  1. import assert from 'node:assert/strict'
  2. import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'
  3. import { resolve, join, relative } from 'node:path'
  4. import { parseGlb } from './instance-repeated-meshes.mjs'
  5. import { instanceSafePrimitives } from './instance-safe-primitives.mjs'
  6. import { compressInstanceBuffers } from './instance-buffer-codec.mjs'
  7. const source = resolve(process.argv[2]), output = resolve(process.argv[3])
  8. assert.ok(source && output && source !== output)
  9. assert.ok(!existsSync(output), 'use a new immutable output directory')
  10. const manifest = JSON.parse(readFileSync(join(source,'manifest.json'),'utf8'))
  11. const tree = JSON.parse(readFileSync(join(source,'tileset.json'),'utf8'))
  12. mkdirSync(output,{recursive:true})
  13. const results = new Map(), report = { source, count: manifest.count, cells: [], fallbackCells: manifest.fallbackCells,
  14. budget: manifest.budget, totals: {sourceBytes:0,outputBytes:0,sourceNodes:0,outputNodes:0,instancedPlacements:0,instancedBuildings:0}, candidateOnly:true }
  15. for(const cell of manifest.cells){
  16. const path = join(source,cell.lod0.uri), bytes = readFileSync(path)
  17. const result = instanceSafePrimitives(bytes)
  18. if(result.report.instanceGroups) result.bytes=compressInstanceBuffers(result.bytes)
  19. writeFileSync(join(output,cell.lod0.uri),result.bytes)
  20. const {json} = parseGlb(result.bytes)
  21. const drawPrimitives=json.nodes.reduce((sum,n)=>sum+json.meshes[n.mesh].primitives.length,0)
  22. const coarseUri=relative(output,join(source,cell.lod1.uri)).replaceAll('\\','/')
  23. const record={ ...cell, lod1:{...cell.lod1,uri:coarseUri}, lod0:{...cell.lod0, bytes:result.bytes.length, drawPrimitives}, ...result.report,
  24. sourceBytes:bytes.length, instancedBuildings:new Set(result.report.records.flatMap(r=>r.names).filter(n=>!n.endsWith('_buried_foundation'))).size }
  25. report.cells.push(record);results.set(cell.lod0.uri,record)
  26. report.totals.sourceBytes+=bytes.length;report.totals.outputBytes+=result.bytes.length
  27. report.totals.sourceNodes+=result.report.originalNodes;report.totals.outputNodes+=result.report.outputNodes
  28. report.totals.instancedPlacements+=result.report.instancedPlacements;report.totals.instancedBuildings+=record.instancedBuildings
  29. }
  30. for(const tile of tree.root.children){
  31. const uri=tile.content.uri
  32. tile.content.uri=relative(output,join(source,uri)).replaceAll('\\','/')
  33. assert.ok(results.has(tile.children[0].content.uri))
  34. }
  35. writeFileSync(join(output,'tileset.json'),JSON.stringify(tree,null,2))
  36. writeFileSync(join(output,'manifest.json'),JSON.stringify(report,null,2))
  37. console.log(JSON.stringify({output,cells:report.cells.length,fallbackCells:report.fallbackCells.length,...report.totals}))