Loading a multi-file glTF in Node

Is it possible to use GLTFLoader to load a multi-file gltf (.gltf + .bin + textures) in a Node.js environment?

I have it working in a web browser with FilesInputStore with code that looks like this:

const input = document.getElementById('modelInput') as HTMLInputElement;
const files = Array.from(input.files);
let gltfFile = null as unknown as File;
files.forEach(file => {
  FilesInputStore.FilesToLoad[file.name] = file;
  if (file.name.endsWith('gltf')) {
    gltfFile = file;
  }
});
if (gltfFile) {
  const engine = new NullEngine();
  const scene = new Scene(engine);
  await SceneLoader.AppendAsync('file:', gltfFile, scene);
}

I am able to load a single .glb file in node with code that looks like this:

import { EncodeArrayBufferToBase64 } from '@babylonjs/core/Misc/stringTools.js';
const fileDataBuffer = await fs.promises.readFile(filepath);
const dataString = 'data:;base64,' + EncodeArrayBufferToBase64(fileDataBuffer);
const engine = new NullEngine();
const scene = new Scene(engine);
await SceneLoader.AppendAsync('', dataString, scene);

I can read the json data from the .gltf using GLTFFileLoader

// data is 'data:;base64,' + EncodeArrayBufferToBase64(fileDataBuffer), from above
private async extractJsonFromGltf(scene: Scene, data: string | File): Promise<GltfJsonInterface> {
  return await new Promise((resolve, reject) => {
    const fileLoader = new GLTFFileLoader();
    fileLoader.loadFile(
      scene,
      data,
      data => {
        resolve(data.json);
      },
      ev => {
        // this does not seem to be called
      },
      false, // array buffer, false because we're using data: with a base64 string
      err => {
        reject();
      },
    );
  });
}

I can also run the glTF-Validator using the .json extracted above and can load the files using the External Resources Function glTF-Validator/module.mjs at main · KhronosGroup/glTF-Validator · GitHub. Is there a way to do something similar with SceneLoader?

private async loadGltfWithGltfValidator(jsonString: string, filepaths: string[]) {
  return new Promise<void>((resolve, reject) => {
    validateString(jsonString, {
      externalResourceFunction: (uri: string) => {
        return new Promise(async (resolve, reject) => {
          for (let i = 0; i < filepaths.length; i++) {
            const filepath = filepaths[i];
            const filename = filepath.substring(filepath.lastIndexOf(path.sep) + 1, filepath.length);
            if (filename == uri) {
              const fileDataBuffer = await fs.promises.readFile(filepath);
              resolve(new Uint8Array(fileDataBuffer));
            }
          }
          reject('file ' + uri + ' not found');
        });
      },
    })
    .then((report: GltfValidatorReportInterface) => {
      this.loadReportFromGltfValidator(report);
      resolve();
    })
    .catch((error: any) => {
      console.error('Validation failed: ', error);
      reject();
    });
  });
}

If there isn’t a native way to load multi-file glTFs, my alternative approach will be to recreate the .glb data like the makeglb tool: GitHub - sbtron/makeglb: Convert glTF to glb, since I can successfully load the .glb data as a base64 string.

Hello! @RaananW @sebavan any ideas?

About validation, we have a onValidatedObservable on the GLTF file loader: GLTFFileLoader | Babylon.js Documentation (babylonjs.com), which itself calls the GLTFValidation methods: GLTFValidation | Babylon.js Documentation (babylonjs.com)

The short answer is - there is no way to load multiple files in a single call with the current loader API. The long one would be the same, but with a lot more words :wink:

1 Like

Thanks for confirming! I’ll just merge the files into the glb format and load it as a base64 string.

1 Like

Hold my beer, ChatGPT