Rendering performance issues

CPU: i510400
GPU: GTX 1650

Is it reasonable to have a frame rate of 20+ for 1 million faces and 1600 draw Call?

If I use an instanced mesh, the Draw Call is reduced to 800, but the frame rate is still 30+

There are many factors that influence on performance, faces and draw calls are one but they can’t tell the entire story. Are you using what kinds of materials? Post processing? Node materials? Have you checked the performance tab of your browser for the bottlenecks/GPU use time?

1 Like

For having undergone this performance update for about 3 weeks now in my scene, I’d say the following: 1600+ drawcalls is just too high for an average performance rig. I have about 2k meshes in scene, 90%+ of which are instances. Yet they still (partly) generate draw calls. I found that anything of more than about 400 drawcalls starts to have a real negative impact on fluidity (read FPS). With an absoluteFPS of about 80 and 700 drawcalls, my FPS drops to around 25 on an MBP 2019 4GB radeon Pro 5300M. It appears the GPU time is taking the most (despite the fact that it is mostly instances). I couldn’t find an ideal, one-fits-all solution for it. In the end lower-end GPU seem to deal better with clones than instances (up to a certain point). Reducing the number of meshes by merging them (and thus, the number of draw calls) also can help. Free active meshes and freezing meshes and materials also did a little (but not much). In the end, I made a combination (and a balance so to say) of improvements and ended-up gaining 30% to 80% performance depending on the view (what is in the frustrum). I still haven’t finished yet with this task. I need to go through the materials and anything that could affect the inter-frame. It’s a long journey and something which, I have to say, I do not particularly appreciate :wink:
Here’s the link to my recent post:

I will likely give it an update/feedback on my new discoveries (if any) once I will have finished with the process (hopefully soon :sweat_smile:
That’s all a simple student like myself can say about it at this moment. Still, I hope this can help you find some clues. GL and courage for your project. Of course, if you have any finding to report, I’d love to hear about it. Meanwhile, have a great day :sunglasses:

4 Likes

The materials are all PBR materials, no post-processing is used.
Look at performance analysis, mainly render function.

Thank you for sharing your experience, I plan to try to use Thin Intances to try to solve the problem of low frame rate.

If your system also has an integrated graphics chip then make sure that the browser process is latched to the high performance mode (ie the fast GPU). I’ve found that Edge, especially will often choose the power saving option and use low-perf GPU a lot of times.

@mawa made a comment I also noticed - the high number of draw calls. Each call is a context switch so reducing can help.

Another thing I didn’t see mentioned is what sort of resolution you’re rendering at - perhaps your current rendering is at too high a resolution? You could be halve then upscale potentially if this is the case

Hth

1 Like

1920*923

It seems impossible to use thin instances, that would lose the hierarchy of the model

1920x923

I’m not sure if that last number is a typo, but regardless you could try setting the resolution to a power of 2 in each part (wight, height). A non-pow2 resolution can slow down rendering as well

ok let me try,tks

Merging meshes can currently solve the performance problem of the current scene.

@Deltakosh , notice how nobody even talks about scene.performancePriority? The absolutely first thing to do is:

scene.performancePriority = BABYLON.ScenePerformancePriority.Aggressive;

It might have side effects / in-compatibilities, so it is actually best to be the first thing that should be put in every new scene as a default, & keep a look out for any issues. Yes, technically it can’t be the default in the repo itself, but there are ways around that.

1 Like

Can’t agree more!!

Documentation: Optimizing Your Scene | Babylon.js Documentation (babylonjs.com)

1 Like

You could also drive that home by putting the set code right in the new scene template.

Not a magic bullet, but can reduce a number of things in the render loop, some of which are performed per mesh. This directly forces things into being more CPU bound for little reason other than back-compatibility.

1 Like

I’m afraid on the tons of questions about why things do not work :frowning: reading documentation is not natural for humans :smiley:

2 Likes
//scene.performancePriority = BABYLON.ScenePerformancePriority.Aggressive;

This reduces turning it on down to 2 keystrokes instead of that long thing. No one is going to type that.

Scene.performancePriority = ScenePerformancePriority.Intermediate;

     const oldFreez = m.material.isFrozen;
            m.material.unfreeze();
            m.material.emissiveColor = c;
          if (oldFreez) {
           m.material.freeze();
         }

After using ScenePerformancePriority.Intermediate, the material cannot be updated normally

As far as I know (and I know only little :wink:) thin instances need a reference mesh, either a mesh or a clone. The reference mesh should be made not visible (but cannot be disposed).

I am not seeing that in my work. Have a bunch of materials which are frozen at creation without an environment texture even assigned. Some materials are highly reflective like chrome. The same environment texture is also the emmissive on interior of a sphere which surrounds the entire scene. I want to rotate the env texture so that it will mirror correctly. After everything is ready to go, I run a function like this.

function onReady(scene) {
    // probably marks all materials as dirty
    scene.environmentTexture.setReflectionTextureMatrix(BABYLON.Matrix.RotationY(Math.PI));

    // since all materials are frozen, need to trigger an update to get reflection right
    for (const material of scene.materials) {
        material.freeze();
    }
}

It works in all 3 modes. BTW, My reading of Material.ts says unfreeze() is not actually needed when going to refreeze right after changing something, but that it should not hurt to do so. May have something to do with this code being run before the first render, but I might test doing it afterwards to be sure it does not.


performancePriority changes 4 properties of scene, which affects rendering. It is really good for reducing overhead of things which either do not need to be run on every mesh, or every frame. I think some kind of scene.doEverythingOnce(), could greatly help adoption. Otherwise, you cannot do Aggressive for a scene, unless your scene never changes. If it does change, you’ll know it, because your code just did it, so call doEverythingOnce(). Gives you control over doing stuff, because you know it needs to be done, without having to do it always & forever.

Have not looked close at _renderingManager.maintainStateBetweenFrames, but that might actually require 2 frames in the BackwardCompatible mode to take affect.

image
image

Why does the frame rate drop when using instanced meshes? @ JCPalmer