We are currently starting to work on a new project, which will feature a lot of levels and a lot of different assets. We already ran into some problems in the past with having too many assets being loaded in the VRAM. So this time we wanted to tackle this issue before it becomes a problem at all. This is the project where I’m currently testing stuff out: Test Project: Asset Loading
I noticed when setting preload on assets to false, the app will automatically load the asset, if it is needed in a scene. So I added an event listener to listen to pc.app.assets.on('load'), so i can remember which assets were loaded dynamically. The next step I figured would be to unload all of these assets, when you change the scene. When I inspect the VRAM via the PC Profiler, it looks good, the memory seems to be freed when i go back to the empty scene, except for Textures Other.
>>
But I got problems when I returned to the scene with the dynamically loaded model, as it stayed black, with no texture whatsoever. When I tried unloading only materials and models, but kept the textures, it kinda works, but texture assets in the VRAM are not freed. Also in both cases, I got this warning, which I don’t quite understand:
This is quite a study you did, thanks for sharing. Optimal loading/unloading of assets is quite mandatory to get right if you have a huge assets bank and/or trying to optimise for low RAM usage (mobile).
To my knowledge:
I think not, this will happen only once when the asset is requested for the first time and you haven’t manually unloaded. As soon as you use the asset.unload() method you will have to manually reload the asset using:
this.app.load(asset);
Not sure, but to my experience I never had an issue with the order I am manually loading my assets (model, material vs texture). Only when I reference resources in custom shaders the order is important, otherwise the shader may fail to compile/run.
It depends on how you plan to showcase your transition. The scene hierarchy is a collection of entities, that load and are made available independently of any asset loading.
From the moment that you have the new hierarchy available and you parent it to the Root entity, it will be available much like any regular entity added as child.
Good question, I wasn’t able to find any relevant property in the engine source code with a quick look.
I am not sure about it, most likely one of the engine devs here or on the repo can answer about it.
I suspect the “Textures Other” would be the framebuffer / depth buffer / shadow maps - so render targets used by the engine. Try changing the shadaw map resolution / rendering window resolution and see if the size changes.
Thanks guys for the reply, you already helped me quite a bit. I got a bit further in my journey to fully releasing the memory today:
I split the process of reloading the assets into 2 parts. First, when starting to load a new scene, I unload all the assets that I remembered from when I entered the scene. Then after the new scene hierarchy was successfully loaded, I manually load all the assets which I already knew that need to be loaded. If I don’t know anything about this scene yet, I will keep listening for the pc.app.assets.on('load') event and add those assets to a reference object. This object is created dynamically at the moment, and gets expanded whenever you enter a new Scene. It looks something like this:
Not relying on the auto loading and instead manually loading assets, which I already knew will be needed, made this work when transitioning between 2 scenes. The catch though: It only works without any problems, when those 2 scenes do not share any assets. If the scenes share a material or a model, both the model and the material get auto reloaded, but the texture (E.g. a diffuse map on the material) doesn’t. The model stays black, as if it didn’t have a diffuse map.
My guess is, that the auto loading triggers for the model and the material, since they are both referenced in the scene graph, but not for assets referenced by other assets. It could also be related to the warning mentioned above. Materials seems to be validated only once and then a flag gets added to prevent redundant validations. Maybe the auto loading would be triggered there? @yaustar can you maybe provide some insight on that?
If that is the case, I would need to know somehow which assets reference each other. If I unload a material and a texture, once I load this material again, I need to manually load the texture as well. Where would I find these references?
Once this issue is resolved, the next step will be finding reoccurring assets and unload only the ones that are necessary.
It’s possible it only handles this at the time the assets are created and not later. May have to dig a bit deeper on that one and perhaps get a reproducible / check if it’s expected behaviour.
My experience with handling assets is to use tags on the assets themselves for each scene that they are needed.
That way, I can find the assets by tag for the scene that they are needed for and load them ahead of time.
I was struggling with this the other day, trying to get a reference to texture assets as referenced by a material.
Though it seems impossible to do this since the material diffuse/emissive etc slots reference the texture resource, not the asset. So there is no way to get the asset IDs.
In my case I solved this in a not so clean way: grab the texture name and find the asset by its name (this breaks if asset names aren’t unique, which they can be).
I’d say this is a valid feature request to be able to get referenced assets by another asset.
Doing a quick test with a StandardMaterial and Texture asset, it seems like it only does the asset dependency load on the very first load. This could be a bug or some sort of intentional optimisation.
I add it to repo tomorrow morning as it doesn’t feel right.
We will have multiple world maps with 10+ levels each, similar to games like Candy Crush. So adding a tag to each asset for every level that it appears in doesn’t seem feasible. Especially since we plan to continuously release new content.
We did this a lot during our console days, even duplicating assets to make the loads easier to manage in game. We had a common folder, a folder for each world and one for each zoom. There was also some special folders for things like faces, bodies etc that didn’t really fit the above structure.
(Side note: you can group select the assets and add/remove tags so if you have them in a folder structure, you can select all and add a tag in one go)
We don’t know yet, how we will organize our level assets. But it is more than likely, that we will have some assets, that are specific to a world at first, but later on we will reuse them in another world. So in the long run, most assets might end up in the Common pool. At that point we could just preload them all.
Manually setting those tags sounds like a pretty tedious task, which is likely very prone to human errors, especially since in the beginning we will iterate a lot, when it comes to building levels. So we would like to avoid it.
If we could write an editor-script (like in unity) or something similiar, to automatically set those tags, this approach would be more viable I think.
@AliMoe I’ve tried doing something similar in the past:
Given an entity hierarchy, find all assets used by various components
What I did was traverse the hierarchy and do checks for model/element/animation components for any used assets. It wasn’t an easy task since there are a lot of cases but at the end it worked.
We had a list of all used assets in a level, which we could load and signal at the end that the level is ready.
What was hard to fully nail was the model->materials->textures references, so we added a constraint that all asset names should be unique. From there we could easily find the relations.
@Leonidas Your approach could be a good backup plan. I think it is a lot easier to put restraints on the naming of assets, and you could also put console warnings in place, in case some assets have the same name.
@yaustar Cool, that’s a nice lead to follow on. Thanks for creating the issue. I didn’t get to work on this yesterday, but I will keep you updated on my progress once I get back to it.
I used _assetReferences to load linked assets like you proposed. A problem I faced was, that after loading all assets in _assetReferences, this property was emptied. So I can’t continuously rely on it to load all needed asset. Instead I stored all references in the previously mentioned data structure and check there, if any additional assets need to be loaded. It now looks a bit like this:
The key 12345678 is the id of the asset, so it’s unique and I don’t really need the additional material object inside references. But I thought especially for debugging purposes this might be helpful. I also don’t know if there are other asset types which have the _assetReferences property, so I built it as if, just in case.
The only thing that kind of bothers me is that I rely on this “private” property, so it might break in the future. It would be nice to find a solution without it to always be sure it works. But now I can go on to the next step of “intelligently” reloading only assets which are needed.
Ohh, and please take a look at the code if you want to, I will keep this project public and updated.