I feel like I'm close but still missing something. Here's what I have so far
var files = window.files;
console.log(files) // => (3) [File, File, File]
// File objects:
// 0: File {correctName: 'test.bin', name: 'test.bin' …}
// 1: File {correctName: 'test.gltf', name: 'test.gltf', …}
// 2: File {correctName: 'test.png', name: 'teest.png', …}
var fi = new BABYLON.FilesInput(engine, scene, (s) => {
console.log('here in scene loaded callback');
})
fi.loadFiles({ dataTransfer: { files: asheFiles } });
The scene loaded callback never gets called however. I also don't see anything being rendered on the canvas element in the page.
I know there's clearly a way to do it based on the example they have here: https://sandbox.babylonjs.com/
I'm just trying to figure out how to recreate that.
Okay folks, I do have a solution.
After searching through many of their documentation pages, forums online and similar questions here on Stackoverflow, I've realized that Babylon js doesn't really sport a direct file load API. They have functions that can take file objects as arguments, but ultimately that does not meet the needs of digesting a gltf file that's split up into various parts, namely .gltf, .png, and .bin. As using a provided method such as BABYLON.SceneLoader.Append on the gltf file will fail once BABYLON parses it and immediately starts requesting the accompanying files (.png and .bin) over the web. Here you could theoretically use a .glb file, but that's not the file format I'm using in my project.
You need to hack the library into allowing you to do what you need. I started looking at the example code used in the linked sandbox above. They use this FileInput class to somehow load all the accompanying files together after a drag and drop event. I emulated the drag and drop functionality via:
function sceneLoadedCB(newScene) { window.scene = newSene; initCamera(newScene, canvas); }
const fi = new BABYLON.FilesInput(engine, scene, sceneLoadedCB)
fi.loadFiles({
dataTransfer: { files: [gltfFileObject, pngFileObject, binFileObject] }
})
This would've been good enough for my purposes except that it will always create another scene object in place of the current one, stopping me from loading up a scene with multiple gltf objects. Asset containers will not work to solve this as they are always bound to the scene they are created with; you cannot transfer assets from one scene to another.
I didn't reverse engineer the logic that parses and groups the files as all being part of the same gltf object. But I did find this static property of the FilesInputStore class being used as a place to store actual javascript File objects. If you populate this store with your gltf file accompanying file assets you will be able to load them together as all being part of your gltf file.
Demo:
var theScene // your babylon scene instance
const renderLoop = (sceneToRender) => {
sceneToRender = sceneToRender || window.scene
sceneToRender.render();
sceneToRender.getEngine().runRenderLoop(renderLoop);
};
yourGLTFFiles.forEach((file) => {
window.BABYLON.FilesInputStore.FilesToLoad[file.name] = file
})
const gltfFile = yourGLTFFiles.find((file) => file.name.includes('gltf'))
BABYLON.SceneLoader.Append('file:', gltfFile, theScene, function (loadedScene) {
console.log('here in scene loaded callback, scene: ', loadedScene)
// below will be true since append adds to the scene instance you passed it
console.log(loadedScene === theScene)
renderLoop(theScene)
});
This took me forever to solve. I hope this solution saves you time in building your awesome project!