donmccurdy / glTF-Transform

glTF 2.0 SDK for JavaScript and TypeScript, on Web and Node.js.
https://gltf-transform.dev
MIT License
1.3k stars 145 forks source link

feat(core): Add io.jsonToBinary() #1280

Closed donmccurdy closed 4 months ago

donmccurdy commented 4 months ago

Example:

const { json, resources } = await io.writeJSON(document);
const glb = await io.jsonToBinary({ json, resources });

Related:

Remaining:

donmccurdy commented 4 months ago

Current dependencies on/for this PR:

This stack of pull requests is managed by Graphite.

donmccurdy commented 4 months ago

Testing on meshopt-compressed inputs with the script below:

import { NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
import { MeshoptDecoder } from 'meshoptimizer';
import fs from 'fs/promises';

await MeshoptDecoder.ready;

const io = new NodeIO()
  .registerExtensions(ALL_EXTENSIONS)
  .registerDependencies({ 'meshopt.decoder': MeshoptDecoder });

const jsonDoc = await io.readAsJSON('scene-meshopt.gltf');

console.log(JSON.stringify(jsonDoc.json.bufferViews, null, 2));
console.log('-------------');

const glb = await io.jsonToBinary(jsonDoc);

const jsonDoc2 = await io.binaryToJSON(glb);

console.log(JSON.stringify(jsonDoc2.json.bufferViews, null, 2));

await fs.writeFile('scene-packed.glb', glb);
donmccurdy commented 4 months ago

I've spent a while trying to provide this API...

const glb = await io.jsonToBinary(jsonDoc);

... but a fundamental problem with this approach seems to be, that if we don't parse the JSON into a Document, which I'd expect a method of that name to avoid, then extensions are never initialized and we have no way to understand extensions' references to buffers. And the buffers need to be repacked when writing a multi-buffer input to GLB. This shows up with Meshopt compression, but other extensions could theoretically do the same thing.

For now the best option remains to read the document, unpartition its buffers, and then write to GLB:

import { unpartition } from '@gltf-transform/functions';
const document = io.readJSON(jsonDoc);
await document.transform(unpartition());
const glb = await io.writeBinary(document);