Multiple render loops and animation ratio

I have implemented a version of the animated gif example from Animated Gifs in Babylon. In his example, @sebavan creates a render loop by calling this._engine.createRenderLoop. Recently we were using particle effects in our application and noticed that the particle effects were very slow. We traced the problem to the fact that we called scene.render() in our own loop, rather than using runRenderLoop. so BJS thought the frame time was the minimum (1ms) and made the animation ratio .06. We fixed the problem by calling scene.getEngine()._measureFps() after calling scene.render(). Today I noticed that if I have an animated gif in my scene, my particle effects are very slow and once again animation ratio was .06, but if I remove the animated gif, animation ratio is 1. I changed our main scene to render in a run render loop and I got animation ratios that are closer to 1. This brings me to ask some questions:

  1. Why is the animation ratio the minimum .06 when I have an animated gif and I am not calling scene.render() in a render loop? I’m guessing that most frames the render function for the gif is a noop because it isn’t time to update the frame yet, so the average time is less than 1ms?
  2. Given the above, why does calling _measureFPS manually on an average of every 16ms not impact the delta time and thus animation ratio when we are rendering a gif?
  3. How is the delta time and thus animation ratio determined when there are multiple render loops and the frame times are different? I’m guessing it is just an average of all the data points sampled.
  4. Does this mean that we shouldn’t use render loops for things that don’t take much time such as animating a gif and if so, what is a better alternative?

Investigating further I find that this seems to have noting to do with animated gifs and the existence of any render loop in the scene will cause the animation ratio to be .06 if we render the scene outside of a render loop, even if we call _measureFps. So my updated questions would be

  1. Why is the animation ratio the minimum .06 when scene.render() is called outside of a render loop, even if _meaureFps is called.
  2. How is the delta time and thus animation ratio determined when there are multiple render loops and the frame times are different? I’m guessing it is just an average of all the data points sampled.
  3. What is the recommended procedure for calling scene.render() outside of a render loop (i.e if we want to sync with some other activity happening outside of the BJS canvas or otherwise want direct control of when the scene is rendered)?

cc @sebavan

@ericwood73 I am not too sure what you are calling animation ratio here ? can you point at the variable ?

Scene | Babylon.js Documentation. It is equal to the delta time * 60/1000. I’ve been saying animationRatio because that is what is used to adjust the animation speed based on frame rate, but really the problem is delta time (Engine | Babylon.js Documentation) is being measured as 0 (which is then clamped to Scene.MinDelta which is 1) when scene.render() is called outside of a render loop.

yup in this case you would need to call engine.beginFrame and engine.endFrame on your own to ensure the deltatime computation for animation.

Gotcha. In the case where I have multiple render loops, how is the delta time determined? Is it just the average of the frame time for each of the loops?

It is computed as the delta since last time you call beginFrame on engine.

I do not think it works with several scenes at different render rates indeed.

In this case you would need a way to have several _performanceMonitor in engine and switch before rendering each scenes.

Can you explain the use case for this ? as I do not see how this would be used in practice ?

1 Like

We have a couple of Texture subclasses that use a render loop to render frames like your animated gif example and then our main scene render. Everything is rendering to the same scene. Should we be using onBeforeSceneRender instead of a new render loop in our texture subclasses?

you can also call engine.runRenderLoop several times, it should behave the same.

A repro of your actual exact issue would help us find the best possible solution :slight_smile:

Possible terminology issue here. The two Texture subclasses do use engine.runRenderLoop. Our main application loop, just calls scene.render(). Based on the information you provided, we should call beginFrame and endFrame before and after the call to scene.render in our application loop. My remaining question is, if the two engine.runRenderLoops take 16ms per frame, but the time between beginFrame and endFrame is say 32ms, is the delta time going to be the average, i.e. (16ms + 16ms + 32ms)/3 = 21ms or around 50 FPS? That small difference probably wouldn’t make a noticeable difference in animation speed, but it would be good to know that is the case.

If you use engine.runRenderLoop you do not need to call beginFrame and endFrame. This is only usefull if you manage your “render loop” outside of the engine provided functions as they would be called respectively before all the registered callbacks and after.

I think it is too much confusing by chat and code would greatly help ?

I don’t really know how to create a PG for this since there are multiple render loops and I’m not sure how I could control the render time for a scene.render(), but in any case I don’t think it is important for the simple question I am trying to ask.

Sorry, beginFrame and endFrame are really irrelevant to my question. If I have three engine.runRenderLoop’s, and two render loops take 16ms per frame, and the third takes 32ms, is the delta time going to be the average, i.e. (16ms + 16ms + 32ms)/3 = 21ms or around 50 FPS? That small difference probably wouldn’t make a noticeable difference in animation speed, but it would be good to know that is the case.

They are not (at least beginFrame) as this is where deltaTime on engine is actually measured in each frames.

Every function called back during runRenderLoop would be called at the exact same frequency. I think the part I do not understand is (two render loops take 16 and the third 32) as here they will all either be 16 or 32. They can not be different ???

Ah okay. Because all of the render loops ultimately call requestAnimationFrame they will all take the same time regardless of how long the actual code called in the render loop takes? If one render loop is slow it will delay the processing of the others? That makes sense and I think all of my questions have been answered.

This is almost that but for perf purpose engine calls requestAnimationFrame and runs the list of callback registered via runRenderLoop in order. So if one is slow it could delay a bit the second as they are all running fully synchronously within the same “animation frame”.