Question (or a lot of questions) about performance and optimisations

Hey! Me again :x

This time with a real “bother”, sort of…

I have been working on my game - in which the world is split into rooms - for the good of the last 7 months, but I’ve only recently added more than 2 rooms, and realised that I can barely get 30 fps. It was a mess, I had 700 meshes, barely any optimisation, .createBox everywhere etc.

Since then I’ve been working my head and ears off, sweating blood, just to get that sweet drip of 60 fps… And I did, but there are still parts where the fps drop, also - draw calls (more below).

So far my optimizations included:

  • MERGE EVERYTHING, well sort of, I only merge meshes in each room. Why not merge everything? Read next point.

  • mesh.visilbility actually affects performance, so while you’re in one room, I add a ceiling and set mesh.visibility = 0 to all other rooms. Big performance boost, but rayCasts still detect these meshes (in case you shoot a bullet to next room).

  • Okay, but setting mesh.visibilityon a massive mesh made from 200+ other meshes, every time you switch to next room, has to have an impact… It did, until I applied - scene.blockMaterialDirtyMechanism = true;.

  • mesh.checkCollisions = false on previous room meshes when you leave the room

  • scene.freezeActiveMeshes()

  • mesh.freezeWorldMatrix() on inactive meshes

  • mesh.material.freeze()

  • mesh.cullingStrategy = BOUNDINGSPHERE_ONLY

  • mesh.convertToUnIndexedMesh()

  • camera.maxZ = 200 huge boost this one

So after all this, I am down to 150 meshes with 5 rooms. Character meshes are not merged because most of them animate somehow, same for doors.

Even though, the performance is great, I feel in my guts that there’s still something missing.

By my guts I mean I ran instrumentation.drawCallsCounter and after a bit of walking and 10minutes of standing still the count property was at 40000 and the current was at 440.

How can I further reduce the draw calls?

  • I read about material sharing, does that simply mean saving new Material and assign it to materials, instead of always calling new Material or is there a deeper meaning?

-I know about anitalias and hardware scaling, those are more of a high level settings.

I should note that the machine I am testing this on is a AMD8320, 8GB RAM and 660GTX (1440p resolution) so pretty old, but should be sufficient for what I am making.

ANY input or point into a direction is highly appreciated and I thank you in advance!

Ta!

Hey!
so first, you must not set visibility but just call mesh.setEnabled(false). You will see a major perf improvement

Instances also help a lot in your case as meshes could be duplicated a lot. This is even more powerful than merging at some points

1 Like

Hey Delta,

What about picking disabled meshes with ray, does it work? Because you can shoot through an open door and the bullet needs to hit the mesh, just like it was there (hence why I used visibility).

What about the materials question? Is that how to reuse materials properly, or does it not matter when merging meshes?

Thanks!

You can change the predicate for the scene.pick so it will consider disabled objects

Reusing materials is extremely important to save perf thanks to cache. So avoid creating new one if you don;t need too. Meshes love to share materials :wink:

1 Like

Great to know thank you.

Any idea about the 40000 total draw calls after 10 minutes of not doing much? :smiley:

I am needy I know I know :x.

Thanks!

draw calls happen on every frame so this is not surprising as you may have let your renderloop running

Regarding materials, is material.clone() and then changing matterial.diffuseColor enough, or is it better to just store for example a material with diffuseColor = '#fff' and then assing the stored material to multiple meshes?

Damn ok, I just made the inspector work with my setup and there was 2066 materials.

I used the latter option where I store materials with the same parameters in a hash and reuse them = 29 materials…

:open_mouth:

Cloning materials duplicates. I have also chosen the same option as you. Storing materials in a hashmap and then assign them to meshes manually on load. As far as I am aware, the only usecase when materials are not duplicated is instances. You should also have a huge performance boost. Draw calls kill performance.

1 Like

Funnily enough, there was really no difference in draw calls when I made the materials fix.

I still get around 300-400 when looking towards other rooms, 100 when looking out

There was no difference between having 2066 materials an 29 ? Are you sure? It might be that BJS does some optimizations and actually matches materials together before issuing the draw call. Are you using shadows? Those also eat draw calls. What about GUI? As far as I am aware, one material should be one draw call.

1 Like

No shadows, one hemispheric light, no glows, no highlights. GUI is 100% in React.

Here are the before and after material fix, looking at the exactly same spot.

This feels so wrong. Perhaps someone else might be able to help. I can not see anything wrong with your values. The draw calls for 49 materials should not be over 500 imho.

1 Like

Well, when I remove all the walls for example, I have 200 less draw calls.

All the walls are a merged big mesh, merged from 1577 meshes. So, perhaps, while merging definitely helps, it looks like all the 1577 meshes are still being checked for something? Material, collisions, bounding boxes? No idea.

Ohh I think I know what is going on. When merging meshes all their materials are joined together into a MultiMaterial. A MultiMaterial is basically a collection of materials. It shows as 1 material but it does not render in 1 draw call but at n draw calls where n = the number of materials composing it ( Someone correct me if I am wrong ). Why don’t you run your materials optimization thing before merging? That should help.

1 Like

I do exactly so. When any shape is built, it is assigned a material (either new or existing) automatically.

When all the rooms are built, I merge their meshes together and all the walls together to a separate mesh.

Without merging how many materials do you see in the inspector?

1 Like

49, same as with merging

Well, now that I recall from reading it somewhere, merging meshes does issue one draw call. Right now I am clueless. Hopefully someone else might be able to help. Just wondering though, have you tried instances?

1 Like

I do use instances for bullets, but for what else?

Each of my room is made from various objects (bench, flower, table, wall, column). I take these and merge them all to one.

I do that for every room, so in the end I have for example, 7 rooms with 7 big meshes.

Would it help, when creating for example the bench, I would check if a bench was already created and instead of creating a new bench again, I would instantiate / clone an existing bench?

I thought that wouldn’t matter, since I am essentially merging everything to a big mesh.

Pinging @Deltakosh