Proper way to update an assigned (PBR) material

Good morning:

In my scene, I need to update a specific material, that comes within a GLTF I’ve just imported.

The case is that, if I traverse the different channels, updating each one at a time, a visible artifact (blink-like) happens in the 3d model. Under this strategy, maybe the atomicMaterialsUpdate API can help here, but sadly I can’t find any example of use of PG about.

This said, I thought a complementary (better) approach would be to have a fully-updated backup material, and swap it with the active one by means of a unique assignation, but sadly scene.getMaterialByName("myMateriaNameHerel")=baclupMaterial throw an “invalid assignment left-hand side” exception.

I’ve reviewed de Scene and Material APIs, but none of them seems to fit my needs, so any help on would be really very appreciated.

Thanks in advance for your time.

There should be no blinking if you are using WebGL2, because we are using parallel shader compilation and don’t update the current material (effect) until the new effect is compiled when you change some properties of the material that lead to the creation of a new effect.

Would you be able to setup a repro in the Playground so that we can better help?

Regarding atomicMaterialsUpdate, here’s the doc:

However, I don’t think it will help with your problem at hand.

What you want to do is update the mesh.material property of all the meshes for which you want to change the material.

1 Like

Hi @Evgeni_Popov:

I see, it’s then a misunderstanding here. I supposed it would exist a way to update the material and automatically have it propagated along all meshes using it.

Thanks for your time.

If you update an existing material, then yes it will be propagated to all meshes that use this material as you don’t change the material property. But if you create a new material, then you will have to loop over all the meshes to change it.

Hi there, @Evgeni_Popov:

Ok, taking this PG as example, the central point here is that, in the aim to go the more efficient way (I mean with a whole-material-update API callI), I was hoping to be able to use the offendingMaterialUpdate method (lines 49 to 58), but instead it’s necessary the workingMaterialUpdate one.

BTW, as you can see, in order to “dispose” the PBR channels attached to a texture, I’ve assigned them straightforward to “null”, but maybe that is not the more convenient way, isn’t it?

Thanks for your time.

You can implement the offendingUpdateMaterial function like this:

This is the right way to do it!

Thanks again, @Evgeni_Popov, for the immediate response:

As a final request, regarding both your brand-new version of offendigUpdateMaterial and my workingUpdateMaterial, what would you recommend to use?

I’ve carried out a very simplistic (and maybe misleading) test with the help of console.time (of course, very rough tool) and obtaining an average (throught 10 executions) of:

  • workingUpdateMaterial: ~1ms
  • (no longer) offendingUpdateMaterial: ~3ms

Despite the much more speed in the workingUpdateMaterial, are there any others considerations you can foresee that discourage its use?

Thanks for your time.

Updating an existing material is probably better as it will save a little bit of memory. But I would not worry about the timings, as I don’t think you will be using those functions so many times in the course of your program?

Thanks, @Evgeni_Popov:

Bringing the things just a little further, trying to update the PBR channels by means of their attached textures, something is not working here, as I get an exception raised from uniformBuffers.updateColor4ForUniform:

What is happening here?

Again, thank you very much for your time and advices.

P.S: Please note that it fails with both methods: updatetextredMaterialFromAux and updateTexturedMaterial.

You forgot the new keyword on line 99:

    mat.albedoColor = BABYLON.Color3(1.0, 1.0, 1.0);
1 Like

Hi there, @Evgeni_Popov:

I’ve opted for re-living this thread, as my question is indeed closely related to the subject.

You said that no blinking should happen when updating channel textures of a PBR material, isn’t it? But the case is that, I’m experimenting such a behavior, as you can see in this PG.

So, I wonder is there any “swap” technique more appropriate to implement this. In order to avoid or soften that not very aesthetic behavior, I mean.

Thanks for your time.

You should wait for both the textures to be loaded and the effect to be ready. Scene.executeWhenReady will help you for the effect part:

You should use texture.onLoadedObservable instead of using a timeout to detect that a texture is loaded, but the timeout way is easier for a PG!

1 Like

Hi, @Evgeni_Popov; and as always, thanks for your immediate response.

The case with the suggested texture.onLoadedObservable is that it seems to not being defined, as you can see in this new version of the PG.

What am I doing wrong there?

Sorry, it is named onLoadObservable.

Thanks, @Evgeni_Popov:

It worked like a charm.

Anyway, I see now in the docs that the Texture class constructor let as also provide, as its sixth parameter, an onLoad callback.

So I think it could be a more appropriate (compact) way to implement all this, avoiding the use of observables.

In such a case, what are the “recommended” values I must have here for the parameters: noMipmapOrOptions and samplingMode?

Thanks for your time.

You generally want mipmaps as it improves the rendering and performances, so noMipmap=false and samplingMode = BABYLON.Constants.TEXTURE_TRILINEAR_SAMPLINGMODE (those are the default values for these parameters).

1 Like