Model Transmission Starts As Solid Color Then Pops In

Playground: https://playground.babylonjs.com/#TCLP3X#1
It’s more obvious in this video with no lighting, background, environment map, etc:
https://share.mikeorozco.dev/FW7cC1668184031L2SYl.mp4

I’m not sure what’s going on here and haven’t been able to find a solution. Any ideas on how to fix this or if this is intended?

Its not a bug, that is an artifact of the render running already before the model loads because of doing it in async.

Basically as the models are being added to the scene from the container you are seeing frames render at a rate faster then the model (and texture blobs) propagating which causes that slight flicker. You could hold the load screen till its ready or load it non async to prevent this.

3 Likes

Wow good catch Pryme8. I wondered why I hadn’t seen this issue before, but you are right, the refraction has a texture map. Thank you for the insight. Usually, we setup the refraction by assigning GLTF transmission as a value in the material so this shouldn’t be hard to fix @notmike101.

Bad news. I did double check the model again and there aren’t any textures assigned to it.
image

This texture is one assigned by the engine. And there are no envmap or other textures at all. So, we shouldn’t be seeing the transmission flash black suddenly. Unless the delay we’re seeing is the time it takes to create a GPU texture or something like that.

It has the wrong appearance for many frames in a row. And this can’t be related to Async loading since the model is not still decoding any textures.

According to QA test reports, the material shows for 0.5 - 1 seconds with the wrong color before finally showing correctly. @sebavan you have transmission knowledge, do you have any ideas aside from delaying rendering for a full second?

It’s definitely the RefractionTexture, probaby texture creation/shader compiling.
The light color “flash” before texture is applied is the base color of the plastic tubes

I’m not sure how the engine works, but what’s showing before the shader has been compiled when it’s the dark color? It shows up correctly once it gets that refection texture for sure, but if the shader hasn’t compiled then it must be falling back to another material shader in the meantime during the frames where the color is wrong??

The length of time the wrong color is visible is browser-dependent too. Firefox it is substantially more noticeable than chrome. Since the video driver is doing shader compilation, I presume the browser shouldn’t matter as much as it does…

Regardless of the reason for the flickering, I’m wondering if there’s an observable that I can monitor to know when scene is ready to display.

@bghgary I am wondering if the loader is waiting properly for the transmission plugin before drawing ?

The transmission helper is using a render target texture internally and you should wait for this RTT to be ready.

There’s a parameter (new in 5.0) to scene.executeWhenReady that will make the engine wait for RTTs to be ready (this flag is false by default for back compatibility).

Here’s a PG that does not flicker for me when hitting several times the play button:

If you change true by false in the executeWhenReady call you will see it flickers when clicking on the play button.

[EDIT] For some reasons it does not work in Firefox and as you said it’s substantially more noticeable than in chrome (and Edge - I have tested and it also works there). The true or false value for the parameter does not seem to change anything, I don’t understand how we get this behavior in Firefox…

3 Likes

The only issue I can see with this approach is if we load a model after the scene is considered “ready”, which is something we do in our code to the point where it would be unavoidable.

For example:

Any ideas for that one?

Can I suggest a change that would simplify this issue:
If an API was exposed to initialize the helpers before they are needed then we can easily have this happen concurrently to the 3D model download and that would hide the delay.

@notmike101 In the meantime we can create a cube with a refraction material property enabled and just let the engine create the helper in the background before the downloaded model needs to be loaded.

Presumably, as long as the download / decoding takes a second, it should hide the issue regardless of the browser.

1 Like

That’s a snazzy idea. You could even hold the loading of the external model to the OnReady observable of the texture.

In case anybody wants to initialize it looks like you’ll have to do what is being done here: Babylon.js/KHR_materials_transmission.ts at d75fa0bf30fd2a8bde8d0c17da3932b679df4989 · BabylonJS/Babylon.js · GitHub

[EDIT]
Upon inspection it looks like merely using refractionFactor may not actually create the Transmission Helper… It seems like something that’s being instantiated specifically to handle GLTF KHR_materials_transmission extension.

Maybe the solution then would be to add an observable to this async process to know when it’s complete then fire the model loading wrapped in that timing.

That would not work because the initialization of the helper depends on the meshes that are part of the transmission helper (all the opaque objects of the scene): the initialization consists in creating the effect for each mesh (material) that is to be rendered in the transmission RTT and waiting for all these effects to be ready.

So, you need to load the object(s) first before being able to wait for the initialization of the helper, but at this point the object(s) will be rendered whereas the helper is not initialized yet.

One way to make it work is to disable the meshes that you add to the scene, wait for the scene to be ready then reenable the meshes. That way, the meshes added to the scene are not rendered (so you don’t see that some textures / the transmission helper are not ready yet). Even if meshes are disabled, scene.executeWhenReady is still able to perform the checks and wait for all the resources to be ready.

Here’s how to do it:

1 Like

Here’s our delima… We have more than one model that we need to load and they may not all load right at the beginning or all have transmission. Will executeWhenReady be called if I add the a model with transmission after the scene has already been loaded with another model that doesn’t have transmission.

Because I think we will still encounter the issue in that situation unless executeWhenReady is fired every time something new is added to the scene?

TLDR: will executeWhenReady or equivalent be called if we add something later and it is the first model containing transmission?

Also, huge :heartpulse: for the example. We owe you one!

The callback you pass to scene.executeWhenReady is called as soon as the scene is ready. If it’s already ready when you call scene.executeWhenReady then your callback is called right away else it will be called when the scene is ready (internally we check for readiness every 100ms).

So scene.executeWhenReady will always work as expected. If you add new meshes, the callback will be fired only when the meshes and the resources associated to them are ready.

Note however that it is a one shot: when the scene is ready, your callback is called a single time and that’s it. If you add meshes (or other resources) later on, you should call scene.executeWhenReady again to know when everything is ready.

2 Likes

This is perfect. Is there a way I can make contributions to the documentation? It would help to clarify this in the API description for scene.executeWhenReady.
https://doc.babylonjs.com/typedoc/classes/BABYLON.Scene#executeWhenReady