SceneLoader (and glTF) options

Hey folks - we recently made some fairly big changes to SceneLoader:

  1. Introduced module level loading functions, which improves tree shaking (bundle size)
  2. The new module level functions take an options object, which includes options for the load call, options for the specific loader (e.g. glTF), and in the case of glTF options for individual glTF extensions.

You can now make calls this:

const assetContainer = await loadAssetContainerAsync("path/to/model", scene, {
  rootUrl: "path/to", // load function option
  pluginOptions: { // options for loader plugins
    gltf: { // options specifically for the glTF loader
      skipMaterials: true, // a glTF loader option
      extensionOptions: { // options for glTF extensions
        MSFT_lod: { // options specifically for the MSFT_lod extension
          maxLODsToLoad: 1, // a MSFT_lod option
        },
      }
    },
  },
});

This is intended to make configuring model loading easier and more discoverable. Prior to this, you would have had to do something like:

const pluginActivatedObserver = SceneLoader.OnPluginActivatedObservable.addOnce((loader) => {
  if (loader.name === "gltf") {
    const glTFLoader = loader as GLTFFileLoader;
    glTFLoader.skipMaterials = true;
    glTFLoader.onExtensionLoadedObservable.addOnce((extension) => {
      if (extension.name === "MSFT_Lod") {
        const msftLodExtension = extension as MSFT_lod;
        msftLodExtension.maxLODsToLoad = 1;
      };
   });
  }
});

await SceneLoader.LoadAssetContainerAsync(...);

Demo: Babylon.js Playground (babylonjs-playground.com)

Docs: Loading Any File Type | Babylon.js Documentation (babylonjs.com)

If you find any issues or have feedback, feel free to respond to this thread!

12 Likes

Just to confirm then - does this change how general (GLTF) models should best be loaded? I currently use SceneLoader.ImportMeshAsync, would it now be better to use e.g. appendSceneAsync?

If so, then: When importing meshes I currently make use of the ImportMeshAsync progress callback to have a loading bar, as well as the result.meshes it returns (in a .then((result) => {})), can the same be achieved with the new functions? From a quick look at the appendSceneAsync documentation it doesn’t mention anything about that.

Thanks!

  1. if you’re using es6 imports and want to do treeshaking effectively, it’s better to use appendSceneAsync or loadAssetContainerAsync

    If the cost of making the change is not significant, it’s probably better to switch to the new API.

  2. you can pass the onProgress callback like this

    await appendSceneAsync("path/to/model.glb", scene, {
        onProgress: e => {
            console.log(`Loading: ${e.loaded}/${e.total}`);
        }
    });
    
2 Likes

Ah - thank you, I am indeed using es6 imports. I’d looked at the appendSceneAsync documentation but hadn’t noticed the onLoad in the LoadAssetContainerOptions. Hopefully it shouldn’t be too much work to switch it over as it seems to work in a very similar way - and for my use case any reduction in bundled size is important, so if it helps with that it’s worth it :person_shrugging:

appendSceneAsync doesn’t seem to return the appended meshes into a .then((result) => { result.meshes }) after the promise - do you know if there’s any other way to easily get a reference to the appended meshes?

As far as I know, this is the simplest way to get appended meshes from the new API.

const meshes = await loadAssetContainerAsync("your/model/url.glb", scene, {
    onProgress: e => { /*...*/ }
}).then(result => {
    result.addAllToScene();
    return result.meshes;
})
2 Likes

Yes, pretty much what @noname0310 said on all accounts (better for tree shaking / bundle size, prefer loadAssetContainerAsync, and use the options for getting progress).

There is a typo in the above example in that it is both using await and a then, but you probably get the idea.

If there is some reason that ImportMeshAsync works for your use case, but loadAssetContainerAsync does not, please share details. We had not planned to introduce a module level function equivalent of ImportMeshAsync since I believe all its use cases can be hanlded with loadAssetContainerAsync.

Thanks @noname0310 for helping with answers here!

2 Likes

Perfect, thank you (and thank you @noname0310!) for the confirmation on that. I’ll migrate my project over to the new API tomorrow and hopefully it’ll all work fine. As you say, as long as loadAssetContainerAsync is no less performant than ImportMeshAsync then any possible improvements to tree shaking etc. are of course worth it!
I’m all for improvements even if they do require some refactoring as long as they’re announced etc. as this one has been, progress is great!

3 Likes