Need help with fps optimization

Hello
I’m trying to build a strategy game with Babylon JS, it looks like this :

As you can see on the inspector I have very low fps.
Terrain is generated by assembling pieces made in Blender (you can see selected and mouse over terrain cells on highlight layers), all share the same material now but I want to be able to switch material for different biomes in the future.
I’ve tried many small things to improve it, sometimes with little improvements, sometimes leading to other issues :

  • I use .checkCollisions = false, .material.freeze(), .freezeWorldMatrix() on every terrain cell
  • shadow.getShadowMap().refreshRate = -1 to avoid recomputing the shadow map, I only refresh it when camera moves, zoom or rotate enough
  • I’ve tried merging all terrain cells with the same material (ie for now all of them) to lower the draw calls, raising up to 15 fps, wich was way better but still quite bad. Problem is that select and mouse over highlight layers don’t work anymore
  • same issue with instances (+ instanced meshes didn’t cast shadows but maybe I did it wrong)
  • after that screenshot i’ve reworked on the tree and rocks models to reduce vertices count by about 30%, improved to 6-8 fps but still not good enough

Do I have too many vertices/faces ? How much can Babylon JS handle with a good framerate ?

I use alpha from texture for the trees, is that part of the problem ? Should I use sprites for the leafs instead of planes with alpha texture ? Or just give up on that graphic style and use the ugly lego trees style ?

Any other idea or advice ?

Thanks

1 Like

Related question : I store my materials in a javascript object to re-use them, same material should point to that same object, so why do I get 101 total materials when it should be only 7 ?

Did you try also to configure LODs? Levels of Detail (LOD) | Babylon.js Documentation It can surely lower the number of active faces (2 millions seems very high for a webGL app).
Maybe something can be done with the shadowmap, like use a low-res when the camera is high?

Are your maps generated randomly for each different player party? I think it is, but if not you may better have to generate the maps in Blender, allowing to directly get a static terrain mesh at launch.

2 Likes

3718 draw calls doesn’t look good. Have you tried progressively disabling features on the debug tab to see if something makes a difference.
Are you able to merge any meshes or control the materials to try and get the draw calls down?

A good read in any case: Optimizing Your Scene | Babylon.js Documentation

@Vinc3r
I didn’t configure LODs, most of my meshes are already quite low poly, but I’ll keep that in mind if I make more detailed buildings and for the trees.
I’ve tried reducing the shadowmap from 2048 to 1024, but no change. As I mentioned I disabled the shadow refresh and only do it manually when the camera moves, so it shouldn’t impact the framerate when I’m not moving the camera.
And yes the terrain is generated randomly by assembling terrain cells (184 different types at this point and I still miss configurations with water, coasts, rivers, swamps and stuff like that so it will most likelly reach 400-500 cells types in the end), the world map is divided in sectors of 20x20 terrain cells and I display 3x3 sectors, so 60x60 terrain cells, wich can each have either resources (forest, rocks …) or a building, so potentially 60x60x2 = 7200 meshes.
For testing and development purpose my 0,0 sector is manually configured so I can test my buildings and terrain configuration like I want, the rest is all generated when players explore it. For now I only focus on the terrain generator and the rendering engine, so no gameplay yet.

@MarkM
I’ve tried disabling everything on the debug tab and it didn’t increase the FPS.
I already merge trees or rocks in the same cell, for the terrain as I said I can’t merge if I want to use the highlight layer, but I’ll back on that later.

@Deltakosh
I already did, that’s where I got the .material.freeze(), .freezeWorldMatrix() and others tips.

So at this point I started working on my terrain meshes to reduce the number of faces, from 40-60 vertices 30-40 faces to ~30 vertices ~20 faces (can vary depending on terrain shapes), saw some improvement but still not enough and it takes a lot of time.
I then disabled my resources generating function to remove the trees and rocks and also disabled the shadow generator to check the numbers :


Down to 50k active faces (it was almost 2M on the first screenshot) and no shadow but still only 6 fps :sob:
Even zooming in to reduce active meshes and active faces :

Down to 155 draw calls, raising to 14 fps but that’s still far from satisfying.

I even tried to replace the material by a standard material with only white color :


Back to 4fps, to using textures didn’t change anything, at least for the terrain, alpha texture may still be another problem but not in this case.
That’s when I noticed the draw calls don’t match the active meshes. At first I thought I had a duplicate call to my terrain render function or something like that, checked that, found nothing, and realized I had generally 2x active meshes + 5 draw calls but 3x active meshes + 10 with the green selection highlight on.
Ok maybe try to disable the highlight layers :sparkles:

Almost doubles the FPS and reduce active faces and draw calls by half.

Now if I don’t use highlight layers I can merge the terrain cells (at least the ones in the same sector) :


60 fps, perfect, now I can try to bring back my trees and rocks :

35 fps with a much higher faces count, I still can optimize some of the terrain meshes and use LOD for the trees, not perfect but playable.
And on my 0,0 test sector with the buildings :

Less trees and draw calls, back to 60 FPS, looks pretty good :slight_smile:

Now I need to find another way to highlight the selection, but at least I know I don’t have to scrap the whole project.

2 Likes

Have you used thin instances for trees? It should also help for other static models such as the smaller houses.

If you don’t add/remove trees frequently in the scene, thinInstance will help to boot FPS. You should be able to have more trees and still better performance.

And yes the terrain is generated randomly by assembling terrain cells

And your terrain (without tree or other buildings) already uses quite a lot of GPU resources. E.g. 232 meshes, 8 draw calls, high mesh selection time and frame total. I think you need a better way to build the terrain instead of assembling different terrain cells. Can you try to build the terrain as a single mesh?