How to preload mesh/materials so that there isn't stutter when a model enters the camera view?

I have parallelShaderCompile disabled in an application, but this results in meshes causing the application to stutter when they first come into the camera view. Is it possible to avoid this, e.g. by manually calling some sort of “preload” function in advance?

Demo here, where the camera animation will stutter when it first brings the model into view.

1 Like

You can use Asset Containers | Babylon.js Documentation (babylonjs.com)

I get the same stutter if I change the ImportMeshAsync line to

  const container = await BABYLON.SceneLoader.LoadAssetContainerAsync('scenes/BoomBox/', 'BoomBox.gltf', scene);
  const meshes = container.instantiateModelsToScene().rootNodes;

or

  const container = await BABYLON.SceneLoader.LoadAssetContainerAsync('scenes/BoomBox/', 'BoomBox.gltf', scene);
  container.addToScene(); const {meshes} = container;

Can you describe how asset containers would be used to solve this?

You could wait for the assets to be loaded first, then start the animation, and add your mesh to the scene when needed

@bghgary should it not be the case with GLTF/GLB already ???

You can set this on the glTF loader and it will wait for the shader compilation to finish before returning.

  BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce(function (loader) {
      loader.compileMaterials = true;
  });

https://playground.babylonjs.com/#XJ7LTU#1

1 Like

This change still seems to have the stutter when the object first enters the view.

It doesn’t for me. Maybe you can capture a performance profile and see what the stutter is?

The stutter is reduced from what it was previously (~5-6 frame loss), but there is still a consistent 1 frame loss right before the object comes on screen. I created a screen capture, and the frame drop can be noticed at frame 151, where the same frame is repeated twice. It’s such a quick drop that the FPS counter and the performance monitor don’t show any major issue.

2022-08-02T21_40_17.788Z-perfdata.csv.zip (7.5 KB)

If I manually call mesh.render on everything at the start, that seems to resolve the remaining 1 frame hiccup, although this feels hacky.

@sebavan Any ideas? I added some logging and it doesn’t appear to be compiling shaders when the stutter happens.

Can you try setting alwaysSelectAsActiveMesh to true on all the loaded meshes ?

This could also be related to Garbage Collection. Is it happening only in the playground ?

Can you try setting alwaysSelectAsActiveMesh to true on all the loaded meshes ?

This is more of a “passive” solution, as assigning alwaysSelectAsActiveMesh doesn’t immediately trigger the lag, it queues it up for later in the rendering process. Contrast this with the mesh.render hack I mentioned above, which occurs instantly. So it does seem to make the lag not happen later on, but I would prefer if it could be invoked immediately.

Additionally, the side effect of disabling frustum clipping test is probably not desirable in the general use case.

Is it happening only in the playground ?

Same thing happens on a local test webpage I set up using the same code.

Ok so the last step is doing a perf capture in Edge or Chrome during the loading so we could spot the delay and see where it is hanging as I can unfortunately not repro locally as well :frowning: would be great if you can try this ?

1 Like

I actually already tried a perf capture and it doesn’t seem to repro if the profiler is running. :frowning: Classic heisenbug.

Here is a capture, the spike seems to be at around 900ms, although it’s still unclear why, since it doesn’t exceed the frame time.

Profile-20220803T130746.zip (2.1 MB)

Are you seeing a stutter when capturing the profile? Looking at the screenshots in your profile, it doesn’t seem to stutter. I also don’t see the stutter when capturing on my machine. I can only repro when not profiling.

I do see the stutter when capturing, although you’re right that the capture doesn’t seem to reflect that there is an issue.

I was able to resolve my loading issues by tracing all calls to ThinEngine._compileRawShader to see what functions were incurring shader compilation, and then preloading materials by manually calling Mesh.isReady. Various mesh and material properties sometimes had to be adjusted to get the desired shader variant to compile.