Best practice for instances and culling

I understand that instancing allows a single draw call but when you are dealing with a lot of instances some of those not even being on the screen or occluded by other objects, it feels like you are still undergoing some cost for drawing of items that don’t need to be drawn.

Is this a fair statement or is instancing really that low cost that it does not matter.
If it does matter does babylon take care of the frustrum culling of instances or is that something you should do on your own.

What would you say is the performance best practice around instancing and occlusions.

1 Like

Hi,

AFAIK Babylon.js is smart enough to have normal instances still culled – frustum culled, at least. Thininstances which are not. So, if you want culling, use normal instances.

3 Likes

Am I correct in assuming that normal instances are basically cloned objects and not a performance optimization?

They are a ‘lighter’ version of a clone. As opposed to a clone, they will not render in full. Instead they will keep with the parameters of the master. The parameters you can change on an Instance are less than clones. Basically, you can treat a clone just like a master mesh. It’s a true copy. To change more parameters on an instanced object however, you have to run some code before the buffer. Note that BJS is smart enough to actually transform instances into clones (at least, for the handling of the geometry). If you change the geometry, applying scaling for example, the instance will render like a clone. However, it will keep with its limitation for setting other parameters.
Let’s just say that, in essence, instances are great for static objects. They cannot be merged (as opposed to clones) so they are less useable for a moving object part (like a part of a vehicle) but they are great for limiting the draw calls and overall performance impact on static objects.

2 Likes

Well, from my experience, it depends on the system. On fairly recent rigs with an average GPU, instances render faster than clones in all situations (even though of what you are pointing above, which is I believe correct). However, I also test my scenes with much lower and older systems (a decade old with just a 1Gb GPU). In this case, clones (when occluded) provide equal and sometimes even better performance results.
I’d say if you’re targeting any system that is less than 7 years old, with average GPU (2GB+) today, instances will still perform better than clones.

The draw calls reduction by using instances is still quite important for performance.

The GPU itself has its own culling mechanism and matrix transforms are fast, so you gain a lot of performance by using instances, even if not culled at all.

Depending on what you want to do, though, it may be worth to have an additional pre-culling algorithm. Octrees come to my mind, for example:

Optimizing With Octrees | Babylon.js Documentation (babylonjs.com)

3 Likes

Does it make sense to use something like entity component system combined with octrees for this.

  1. Check the visibility of octree cells.
    1.1 How would I check the visibility of the octree cells
  2. Get entities for those cells.
  3. Update instances for the entities to be drawn.

That does bring up some questions though.

  1. Can you update the quantity of instances on the fly based on your requirements.
  2. What is the recommended way to filter drawable items on your scene.
    2.1 Render loop event to hook into before the scene is processed.
    2.2 How to mark the items so that the engine most optimally knows how to ignore items.

Would be nice if you could register the octree with the scene and have the engine deal with that for you … :grin:

Well, the engine already deals with octrees in the case of static instances (as per the octree docs), having dynamic updates would be a great contribution to add to the engine :smiley:

1 Like