ImportMeshAsync blocks other operations

I am trying to download and load an asset from our server on runtime, and it is done based on user requests so I can’t simply batch all the assets at once with AssetsManager. I am trying to load each asset one by one, and I have a separate Loading Screen (rendered with React, so it’s separate from the babylon canvas itself) that should display the progress in percentage as the asset loads.

However, I found out that the ImportMesh and ImportMeshAsync operations are both blocking, meaning any of my other functions (setTimeout, setInterval, or React setState) would not be executed while ImportMesh/ImportMeshAsync are being executed, and thus I have no way to simulate a smooth loading screen.

I have tried using the progress event callback, but that only gives progressive reports from around 0 to 50 to 100 (2 or 3 reports for the entire 5 seconds of loading). Is there a better way to smoothly display a loading percentage?

(Sorry for not providing a PG for this, but I don’t really know how to get React onto PG. I suppose an example could be as simple as trying to execute a setInterval operation while the asset is loading, but whatever callback passed to setInterval will not be called until LoadMesh/LoadMeshAsync finished downloading and importing the asset)

I was also looking at Web Worker, which seems to be able to run resource-intensive code on a separate thread, thought I’m not sure if it will be usable for passing around an entire Babylon.js Mesh object

Hi Madaoism,

I don’t think ImportMeshAsync is supposed to be blocking. It should return a Promise, which will allow you to continue running other things until the promise is resolved. Check out this Playground, which I modified slightly from a preexisting one. Open up a the browser’s console (F12), un-comment line 25, then press Play. You should see the “Doing something!” message begin immediately, even though the SceneLoader is still working on the assets asynchronously. If an approach like that works for you, will it enable you to do the loading screen you described?

That’s quite interesting, I have no clue why it is working on PG but not on my application.

This is what is logged on my app when I tried to use ImportMeshAsync to load an asset in a async/await function:
image

I’ll try dig into it a bit more, but maybe React just doesn’t get to update while the mesh is being loaded…? Seems like the update is being called (but not as often as before, from about 50ms interval gap to 200+ ms gaps).

Also, the final ‘file reading’ stage of the operation seems to be really blocking, and not the ‘downloading’ part of it.

Paging Dr. @bghgary, who knows all things about asset loading. :smiley:

If you can capture a profile of it, that will help. There are parts of glTF loading that are synchronous, like parsing JSON and decoding images.

Something like this? I’m trying to load 3 different OBJ files during the period shown below.

Actually this is my first time using the profiler, but now it got me wondering if it was because I was trying to merge all the meshes into one single mesh after loading the file…

Yes, that’s the profiler. You should be able to analyze what is taking long frames and, like you say, the MergeMeshes one is rather large taking 8 seconds.

I think @Deltakosh has been working on this recently. Maybe this will be ready soon?

1 Like

I will keep waiting for it then :smiley:
Probably not worth getting the codebase too complicated to improve the loading screen a little bit. It can stuck at 80% for a few seconds, I’m sure no one will mind :eyes:

Thanks for the advices!

1 Like

Hi, I have a very similar problem, but I think this one is due to certain sub-processes in BabylonJS.

I have a really large mesh (over 100 MB) that I’m trying to load into BabylonJS using the built-in BABYLON.SceneLoader.ImportMeshAsync function. For some reason the function runs without blocking for half a second or so, and then the webpage freezes for another couple seconds and then the model appears.

I think this is because the function makes a request to the server for the file, lets other functions continue, and then gets bogged down with heavy computation once the file arrives. I want this to run without blocking if possible because I’m trying to make up for the large file size by loading the file in the background. Is that possible?

I’ve attached a screenshot from my profiler, and it looks to me like the frame rate drops to 0 at exactly the same time as the meshloader is running (but I could be wrong, I’ve also never used the profiler before now).

If non-blocking loading is not possible, what would you suggest I do instead?

I’m having the same problem with the loading of a gltf with alot of meshes. It takes around 3s to request the gltf file, and after that is freezes the main thread while it reads/loads the meshes for like 7-10s.
@Deltakosh any ideas on this issue?

After the file is downloaded, there are some javascript running to process the file that will block the current thread, there’s no way around that.

To avoid blocking the main thread, you would need to run the import process in a worker thread, but I don’t think it is currently supported. One possible workaround is to use Babylonjs with an offscreen canvas (but it has some caveats too):

[EDIT]
Well, thinking about it, I don’t think the offscreen canvas will help in your case as you want to have your Babylon scene (and not the main thread) running during the mesh loading…
[/EDIT]

@Evgeni_Popov This might be a shot in the dark, but if I’m using a javascript backend like node is there potentially a way that I could somehow “precompile” the object file and then post it once completed? it looks like Babylon only blocks while running computations after receiving the model. If I could somehow run the heavy computation in a javascript worker thread instead of client-side, I could potentially remove the blocking entirely.

babylon doesn’t block, Javascript does :slight_smile:
At one point or another, javascript’s main thread needs to read and deal with the information you load,
It’s impossible to avoid, except pre-loading all files.

@aWeirdo Sorry, what I meant was that Babylon blocks because it’s using javascript (which can’t really be avoided). I was hoping I could get around this with posting a pre-computer mesh from a node server (which does allow threading), but idk if that’s feasible.

That’s not really possible, the JS code running creates the underlying structures Babylon.js needs to create a mesh… The solution would be a worker thread, but you can’t pass arbitrary objects from a worker thread to the main thread (nor the other way around).

Ok, thank you for the help. I guess I’ll try to rethink my approach to avoid loading such large meshes, but if I figure anything out I’ll try to post it here so other people can use it.
Thanks again @Evgeni_Popov and @aWeirdo!

hello, @bghgary @Evgeni_Popov
I used assetsManager to download the file, and then used importMeshAsync to load the file, through the performance tool analysis, there is a slow operation after loading, why is this?

Is the first slow task importMeshAsync happening, while the second slow task is the first render after loading the model? Why is the first render slow after loading the model? Is there any way to alleviate this slowness.

If importMeshAsync is used again, the slow tasks that occurred the first time importMeshAsync was used will not occur.

It seems it’s the compilation of the shaders, but we don’t see the whole trace in the screenshot.

Are you using WebGL1? In WebGL2, we normally use parallel shader compilation, so you should not see some large time spent in shader compilation in a performance snapshot…