Only preload assets which are part of exported scene

I have a project which has 2 scenes. If I download 1 scene and host it on our server, it will also preload assets which are only part of the other scene.
Is there an option when exporting, to only add the needed assets for the scene which is exported? Or do I need to create 2 projects for this or use some custom loading script?

Thereā€™s no option for that as itā€™s assumed that all scenes in a project is for the same project/build.

You can fork the project or make a branch.

Thanks for clarifying. But then what is the porpuse of selecting scenes when downloading the build? Only the scene file gets excluded?

Some scenes may be used for internal testing during development or perhaps they are still in development and do not need to be in the build yet

Also worth noting that the assets are separate to the scene so the preload setting on the assets are irrelevant to which scene is loaded in the sense that no matter which scene is loaded, it will preload whichever assets that are set to preload.

Another possible method you can do (which you may be hinting to before), is to have custom in game asset loader using tags.

An example can be seen here where it will load the assets needed for the scene you select via tags: Loading Scenes | Learn PlayCanvas

Yeah we do load by tag in another project, but it is kind of a hassle to assign tags to all those assets. I was hoping I can prevent that.
Thanks!

Actually is there some option to monitor asset loading?
What I have in mind is removing all assets from preloading. Then when the scene is loaded, this should trigger the loading of all assets. Is there a way to check if this has finished?

I made a system like that. I can share later when Iā€™m home.

Hmm, I canā€™t think of one through the public API but the asset registry does fire an event when an asset starts loading and when it finishes loading so it might be possible to listen to how many have been fired and then tracked the loaded assets events to know when it is ā€˜finishedā€™.

1 Like

Here is an example project in case it might be useful.

  • the app starts in the loading screen script where it can disable the default preloading of assets
  • a Coordinator is created to handle the startup and setup
  • the scenes are parsed to determine which asset each scene needs.
  • the first sceneā€™s assets are loaded and then the scene is loaded.
  • you can switch between scene 1 and scene 2 using 1 and 2 keys.
  • when switching scenes the old sceneā€™s assets are unloaded and the new scenes assets are loaded.
  • the trick that is used when parsing the scene is that if value is found that is a number and also is an asset id in the asset registry then that asset is set as required by the scene.
  • launch the app from the ā€œ_startupā€ scene.
1 Like

Thanks for sharing you system! I will have a look at it. Parsing the scene file sounds promising to remove the need for tags.

EDIT: You still have assets set to preload in the editor. Shouldnā€™t the materials be set to not preload?

They could be - I updated it, but I also disable that in the code.

Ah I see. What staggeres me tho:
When I open the chrome network profiler no files are fetched when switching from scene 1 to scene 2.

Maybe later I can add some textures to those materials in scene1 and scene2 to make it slightly more complex.

I tested with a texture, which does work correctly. Seems like materials arenā€™t standalone asset files

1 Like

Iā€™ve tried implementing this in my project and the reference parsing from scene seems to work. But I do have the problem, that the asset ready/loaded event is called instantly.

LoadScene.prototype.loadAssets = function (cb) {
    let loadedAssets = 0;

    for (let i = 0; i < this.requiredAssets.length; i++) {
        let asset = this.app.assets.get(this.requiredAssets[i]);
        asset.ready(function () {
            loadedAssets++;
            console.log(`${asset.name} | ${asset.loading} | ${asset.loaded}`);
            if (loadedAssets === this.requiredAssets.length) {
                // setTimeout(cb.bind(this), 5000);
                cb();
            }
        }, this);
        // asset.on('load', function () {
        //     loadedAssets++;
        //     console.log(`${asset.name} | ${asset.loading} | ${asset.loaded}`);
        //     if (loadedAssets === this.requiredAssets.length) {
        //         cb();
        //     }
        // }, this);
        this.app.assets.load(asset);
        console.log(`${asset.name} | ${asset.loading} | ${asset.loaded}`);
    }
};

asset.loading is always logged out as false and asset.loaded always true. Which means the ready/loaded callback is executed immediately.
Only for 2 text files ,which I use for a debug menu (html, css), the callback seems to work correctly.

In my example project there is a dummy first scene _startup that needs no assets. Then the assets for the real first scene are loaded and then the real first scene is displayed. This setup is important because if I had just displayed the real first scene, then the engine would start loading the assets that werenā€™t already preloaded, so that it could render the scene I wonder if this is what is happening in your case? i.e the assets are already loaded, before you call your loadAssets functions?

Ah I guess I should have mentioned. I also have an empty first scene, which does the asset loading and after that it will switch to the desired scene.

LoadScene.prototype.loadScene = function (id) {
    let scene = this.app.scenes.find(id);
    if (!scene) {
        console.error('Could not find scene with id "' + id + '"!');
        return;
    }
    this.app.scenes.loadSceneData(scene, function (err, sceneItem) {
        if (err) {
            console.log(err);
            return;
        }
        this.processItem(sceneItem.data.entities);
        this.loadAssets(function () {
            console.log("All assets loaded!");
            this.app.scenes.loadSceneHierarchy(scene, function (err, parent) {
                if (err) {
                    console.error(err);
                } else {
                    this.app.scenes.loadSceneSettings(scene, function (err, parent) {
                        if (err) {
                            console.error(err);
                        } else {
                            this.onLoadingComplete();
                        }
                    }.bind(this));
                }
            }.bind(this));
        }.bind(this));
    }.bind(this));
};
1 Like

I think your asset.ready callback should take a parameter called asset. That might be it.

Also in my original code you will notice that I also process the asset registry as well as the scene registry when building the list of asset references. I donā€™t know if you are too. It is important because an asset might reference other assets eg material and textures.

Hmm yes I only process the scene data. I donā€™t quite get why to process the asset registry if Iā€™m honest. Still my loading problem persists regardless of this.

In javascript function parameters can be omitted. I did add it though but same behaviour.

After further investigation it seems you are right. I need to do the asset registry processing.
Why is this needed? Shouldnā€™t the scene processing be enough?