Unloading and Reloading materials

I have been doing some investigations into scene management (inspired by the same reasons in the discussion linked at the end )

There might be a bug in the following use case:
If the same textures are used on different materials
and one of the materials is unloaded and then one of the shared textures is loaded
then the bound _onTextureLoad() method is called for the unloaded material causing an error.
eg “TypeError: Cannot set property ‘emissiveMap’ of undefined”

Here is a project that displays the issue, and in assetHelper.js there is a potential workaround.

https://playcanvas.com/editor/scene/1109860
https://playcanvas.com/editor/code/774292?tabs=44122974,44122980

5 Likes

Here are some more details on the issue. I think this is what is happening.

When the material’s asset references are created these callbacks are set:

When the material is unloaded the callbacks for the assetReferences aren’t removed:

So when a texture from the assetReference is subsequently loaded the callback is called for the now unloaded material asset:

and this causes the error as the material asset is undefined.

So you probably want to either remove the callbacks, which is what I did in my hack workaround ( but then they need to be recreated later when the material is reloaded) or check that the material is not undefined in these callbacks.

There is another related engine bug.

3 Likes

I got around the issue by patching the MaterialHandler. I also made an AssetHelper class that will download all the scene’s json files and parse to get all the asset dependencies per scene. It’s work in progress ( Javascript is not my first language )

https://playcanvas.com/editor/code/779957?tabs=45050271,45050274
https://playcanvas.com/editor/scene/1120670

this._materialHandler._onTextureLoad = function(parameterName, materialAsset, textureAsset) {

    // Fixes bug where materialAsset is not loaded.
    if (materialAsset.loaded) {
        _this._originalOnTextureLoad(parameterName, materialAsset, textureAsset);
    }
};
1 Like

Thanks for investigating into this and glad that you had found a workaround, I will add this to our internal tracker and try to schedule an engine level fix

1 Like

Just ran into this issue and found this thread. Will this be tracked on the engine issue log? I don’t want to pester in the thread if not necessary.


:slight_smile:

3 Likes

Oh cool, nice job tracking this down. In my project I unload models and textures, but don’t unload materials because of this. Wasn’t a blocker, but cool to see someone was able to figure this one out.

1 Like

Good morning,

So it looks like with the latest engine release, the app no longer crashes when unloading assets on scene destroy and then reloading them on reload, but I am getting a bit of strange behavior.

Now when returning to the scene, it seems that none of my textures actually get applied to the material. The runtime lightmaps still appear to work, but none of the other maps appear to load. Looking at the console, I’m getting a warning of:

Ignoring unsupported input property to standard material: validated

for each material with a texture that gets loaded.

I made a repro of the behavior, but strangely, the warning doesn’t appear in the repro, so I could be doing something wrong in general.

Here is the repro:

and the project:

https://playcanvas.com/project/781274/overview/unload-reload-material-repro

To see the behavior, just click to go to scene 2 then scene 1 then scene 2 once more. You will see that the material unloaded from the Earth Sphere, does not get applied on reload. The moon’s textures get unloaded, but the material does not.

Also, one more observation. It appears that the same unloading and reloading material issue also applies to cubemaps that get unloaded. The app crashes and presents the error:

facetextures[0] undefined

Simply not unloading the cubemap prevents crashing even when textures are unloaded.

@ray is this something you can have a look over please?

this error only displays when using the debug version of the engine … so maybe in the repro you have not ticked “debug” or similar?

My test project has similar issues. Go to scene 2 and back to scene1 and see the console errors.

https://playcanvas.com/project/779957/overview/asset-helper

That was right! Checking debug also reproduced the warning. Thank you!

I will look into this and update when I have more info.

6 Likes

On line 235 when reloading the material, data[name] is a Texture (from the previous load I think) and so the IF test fails and the code to assign textures doesn’t get executed. In a previous test when I forced data[name] to be the id of the texture asset it did force the texture to load. Could be something related to this.

1 Like

Here is an example that might assist in finding the proper solution. When a material is unloaded, I reset the material asset’s data texture references back to the texture assets ID.
https://playcanvas.com/project/779957/overview/asset-helper
https://playcanvas.com/editor/code/779957?tabs=45050271

2 Likes

@Kulodo133 - thanks for the additional information - I have submitted a engine fix PR here: https://github.com/playcanvas/engine/pull/3074

2 Likes

@ray is it possible for me to test the branch using this mechanism?

https://developer.playcanvas.com/en/user-manual/scripting/custom_engine/

You would have to build the engine locally, host it (using something like python http server) and use the link above to run with it in the launch tab.

1 Like

I built the engine locally and checked out Ray’s branch and it does fix the issue :grinning:https://playcanvas.com/project/779957/overview/asset-helper

2 Likes