I remember way back in 4.22 there was supposed to be some automatic draw call batching going on… now in 5.3 ive been doing tests. One row of objects all same material… anotehr row with different materials… Tried deleting one and then deleting the other to check the draw call number and they both have the exact same draw call number. I thought things with the same material were supposed to be batched at this point? Whats going on?
Its called instancing and it only happens if you use instances.
There is really nothing that’s automatic in the engine.
Hey there @kurylo3d! As MH mentioned, you’re going to want to use instanced static meshes and instanced materials when you can to reduce overhead when used appropriately. I can’t speak to the engine doing this automatically before, but there is some things in place to help with saving a bit on shaders, but it’s minimal and usually developer managed.
And as a bonus, here’s a good post with some more resources:
Anotehr question is also for nanite. What about instanced materials. Right now nanite does basically 1 draw call per material as far as ive been told. What if you use material instances from the same base material? Are they treated as seperate materials or batched into the same draw call?
Aside from that is their any commands for checking nanites stats and any documentation to understand them?
I haven’t looked into FMesh drawing mechanics too deeply myself, definitely not deeply enough to point to where it operates. It doesn’t help that I began working in earnest in UE4.24. This overhaul seemed baked in and reduces draws for primarily mesh draw calls that can be merged based on the batching rules. I’ll have to dig a bit deeper on the source changes at that time to answer it more thoroughly.
The nanite bit I can answer with a bit more certainty, and you’re correct, from my original tests even with material instances, they will each still be a draw call, there doesn’t seem to be any (obvious) batching for them, though I haven’t tested outside of editor so calls are inflated due to PIE. The reduction in overhead comes from having less shader permutations.
Disclaimer: One or more of these links are unaffiliated with Epic Games. Epic Games is not liable for anything that may occur outside of this Unreal Engine domain. Please exercise your best judgment when following links outside of the forums.
Command wise, there’s a handful that are useful though less geared to draws and more internal nanite mechanisms like the bins and cluster data:
Supplementary deep dive into Nanite that lightly touches on the material portion:
I see no dynmaic batching happening for sure with all my tests when it comes to traditional draw calls… I do have another question though.
I am experimenting with a city that i am building that is using Custom Primitive Data on a per object basis for variety on every thing. So far it looks like it keeps everything together by keeping everything on the same material.
So after some testing (and the beneifit is only with nanite… not non nanite) … instead of looking at draw calls im looking at “stat rhi” → draw primitive calls…
Seperate materials with nanite obviously keeps everything seperate…
Same material with instances with same base material with nanite has the same effect… everythign is seperate draw calls.
Same material with nanite has less draw calls. (some sort of batching)
Same material with Custom Primitive Data for variety per object has the same batching as 1 material…(obviously its also 1 material but its accesing floats from the custom primitive data on the objects to chance their color and stuff.)
In non nanite there is no batching for any case… not even if they are all the same material.
Stat scene rendering → draw calls… tehre is no effect for any case on this number either… (though nanite meshes obviously do not register here at all.)
So my question now is … is there a problem with using CPD on 10,000 objects… Could this hurt performance in anyway?
You are at the mercy of what the engine does (unless you re-write it), so your best and only bet is to keep on bench testing as you progress.
Here are a couple examples for you.
Case 1.
A building is made up of wall/window meshes all with a span of 2m x 2m x 10cm.
Will it cost less as individual meshes or as instanced meshes?
Case 2.
The area you are looking at is made up of hexagonal meshes measuring some 2m x 2m x 2m
They are arranged so that some stack upwards, some are beehived forming a floor. There are some very large objects in the way for this scene.
What costs less? Instancing or individual meshes?
As a general answer to both 1 and 2 you can assume that instancing cost less.
However, in practice, 2 will have 0 to a negative pefromance impact with instancing modtly due to scene composition.
That’s because in scene 2 the parts aren’t members of a whole.
As such, it is possible that you hamper the engine’s ability to cull and HLOD by instancing the objects.
A good example for this is Foliage.
Used to be, that foliage would partition and split for batching calls based on how it was painted. This feature was only part of the foliage actor.
The process would make enough of a performance difference that the same amount of instances placed on a grid - where the batching was not possible - would drop by 40 to 60% vompared to the same amount of instances placed in clumps.
Now, I have no idea if the foliage is still doing this (probably isn’t because they messed with it for nanite). But it actually illustrates the issue for scene 2 quite nicely.
If you could choose which instances belong to a batch, and instance only the meshes that make sense (for example fhe ones forming tall structure stacks) - then youd get less of a cost.
Remeber though that drawcall count is still impacted (on everything that isnt batched).
1 instance = 1 call. The engine is in charge of using or not using that call (due to culling or whatever else) but the primitive of the instance is still an individual call.
So for the stacks of hex to make 1 call, you cant simply toss them in an instanced syste… you have to actor merge them into a single object, or set up a batch system like the foliage used to have…
Does instancing benefit nanite? Thought the whole point of instancing was to reduce drawcalls, but i thought nanite was rendering everything in the scene with the same material in 1 draw call per material…
Also instancing doesnt support custom primitive data (unless im wrong)… which is something im using heavily…
I doubt it.
Well, you know what they say about assumptions…
Onestly i would expect or figure the same, but the system is also still just beta…
MH covered most everything else, but CPD is actually great for performance in comparison to alternatives, but I’m not certain it will work correctly with instancing due to the nature of instances. If you stress test it and everything works fine, I’d love to hear your feedback!