| 1234567891011121314151617181920212223242526272829303132333435 |
- import assert from 'node:assert/strict'
- import {MeshoptEncoder,MeshoptDecoder} from 'meshoptimizer'
- import {parseGlb,packGlb} from './instance-repeated-meshes.mjs'
- await Promise.all([MeshoptEncoder.ready,MeshoptDecoder.ready])
- export function compressInstanceBuffers(bytes){
- const {json,bin}=parseGlb(bytes),dracoViews=new Set(json.meshes.flatMap(m=>m.primitives.map(p=>p.extensions?.KHR_draco_mesh_compression?.bufferView)).filter(i=>i!==undefined))
- const chunks=[];let size=0,fallback=0
- for(let i=0;i<json.bufferViews.length;i++){
- const view=json.bufferViews[i],data=bin.subarray(view.byteOffset||0,(view.byteOffset||0)+view.byteLength),a=json.accessors.find(a=>a.bufferView===i)
- const pad=(-size)&3;if(pad){chunks.push(Buffer.alloc(pad));size+=pad}
- if(dracoViews.has(i)||!a){view.byteOffset=size;view.buffer=0;chunks.push(data);size+=data.length;continue}
- assert.equal(a.componentType===5125||a.componentType===5126,true);assert.equal(a.byteOffset||0,0)
- const stride={SCALAR:4,VEC2:8,VEC3:12,VEC4:16}[a.type],count=data.length/stride,mode=a.componentType===5125?'INDICES':'ATTRIBUTES'
- assert.equal(count,a.count)
- const encoded=Buffer.from(MeshoptEncoder.encodeGltfBuffer(data,count,stride,mode))
- view.extensions={EXT_meshopt_compression:{buffer:0,byteOffset:size,byteLength:encoded.length,byteStride:stride,count,mode,filter:'NONE'}}
- view.buffer=1;view.byteOffset=fallback;fallback+=data.length
- chunks.push(encoded);size+=encoded.length
- }
- json.extensionsUsed=[...new Set([...(json.extensionsUsed||[]),'EXT_meshopt_compression'])]
- json.extensionsRequired=[...new Set([...(json.extensionsRequired||[]),'EXT_meshopt_compression'])]
- json.buffers=[{byteLength:size},{byteLength:fallback,extensions:{EXT_meshopt_compression:{fallback:true}}}]
- return packGlb(json,Buffer.concat(chunks))
- }
- export function unpackInstanceBuffers(bytes){
- const {json,bin}=parseGlb(bytes),chunks=[];let size=0
- for(const view of json.bufferViews){const pad=(-size)&3;if(pad){chunks.push(Buffer.alloc(pad));size+=pad}
- const ext=view.extensions?.EXT_meshopt_compression;let data
- if(ext){data=Buffer.alloc(ext.count*ext.byteStride);MeshoptDecoder.decodeGltfBuffer(data,ext.count,ext.byteStride,bin.subarray(ext.byteOffset,ext.byteOffset+ext.byteLength),ext.mode,ext.filter);delete view.extensions}
- else data=bin.subarray(view.byteOffset||0,(view.byteOffset||0)+view.byteLength)
- view.byteOffset=size;view.buffer=0;chunks.push(data);size+=data.length
- }
- json.buffers=[{byteLength:size}];json.extensionsUsed=(json.extensionsUsed||[]).filter(e=>e!=='EXT_meshopt_compression');json.extensionsRequired=(json.extensionsRequired||[]).filter(e=>e!=='EXT_meshopt_compression')
- return {json,bin:Buffer.concat(chunks)}
- }
|