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.