- Home /
The question is answered, right answer was accepted
Dynamic Batching and Instantiating
I am creating a project where meshes are placed procedurally using a script. However, the draw calls are hurting performance. When instantiated with a script they will not dynamically batch at all.
I notice that when I place the meshes manually, they batch just fine. So the mesh must be within the vertex count limit of 300.
All of the meshes share the same materials and textures.
All the instantiated meshes seem to reference the same material and not separate instances, since when the materials are modified in the editor the changes apply everywhere.
I am not accessing MeshRenderer.material or .materials[] anywhere in my script.
Static batching is not a desirable option in that these meshes are constantly being instantiated in game, and each StaticBatchingUtility.Combine() call is very costly especially since there will be very many meshes.
Combining meshes isn't an ideal solution either for similar reasons. Combining them using a hierarchy is also very complex and could impose limitations on the project in the future (for example, LOD levels).
Static batching causes some meshes to disappear and move to (0,0,0); some of these objects are scaled (mirrored along one axis specifically) although not necessarily all of them.
On a side note, if anyone has any ideas of how to improve rendering performance when instantiating objects (especially on a large scale) then please feel free to mention them.
Thank you.
I remember reading something about this in the documentation. Let me look it up...
EDIT: Nope, must have been imagining it...
You might have to post an example project so we can test locally. Or at least some steps so we could repro this with cubes or something?
I figured out the issue with that particular example - I had a point light present in the scene, so nothing was being batched. Otherwise, it worked as it was supposed to.
Also, I was switching scenes to test if manually placing objects would let them batch - and that new scene had no point light. :)
Answer by Oliver Eberlei · Dec 15, 2013 at 10:03 AM
I know this is a very old post, but I found this question through google and I came up with a solution that works for me, which I want to share. I'm using this to dynamically batch 2d level sprites, so I'm not sure how this applies to you.
After dynamically creating all the sprites with this code
SpriteRenderer CreateSprite( Sprite sprite, float x, float y, float rotation )
{
GameObject newObject = new GameObject( sprite.name );
newObject.transform.parent = transform;
newObject.transform.localPosition = new Vector3( x, y, 0 );
newObject.transform.localRotation = Quaternion.Euler( 0, 0, rotation );
SpriteRenderer renderer = newObject.AddComponent<SpriteRenderer>();
renderer.sprite = sprite;
renderer.sortingLayerName = "LevelRoom";
return renderer;
}
I simply call this function on the parent gameObject. Since the sprites are all parented to the same GO, this will disable and enable all newly created sprites.
void BatchSprites()
{
gameObject.SetActive( false );
gameObject.SetActive( true );
}
This reduces the drawcalls from 143 to 28. I'm afraid I havn't done any more tests with this method, it seems to work for my specific case. Hopefully it points you in a direction to get your own situations working.
Cheers
You sir are a genius. After looking all over the place and seeing nothing but vague solutions, or undocumented reasons why it was impossible, this solution just plain works. I'm creating a detail-object placing tool, and you just saved my literally thousands of draw calls just by parenting them all to one object and quickly de / re-activating it as the game starts. it costs nothing once the game is running, and it solves the problem absolutely.
Hope more people stumble across this answer!
i did stumbled! :D i noticed that manually placed in editor got batched, but not so the instantiated/created by script, this trick saved me to go trough a lot of crap!!
Answer by Zergling103 · Dec 21, 2011 at 08:39 AM
The best approach is a combination of Dynamic Batching, Static Batching and Mesh Combining since each has its own advantages and disadvantages.
Dynamic Batching
Advantages:*
Requires no code work.
Doesn't cause lag spikes when optimizing many objects.
Supports per-object culling.
Objects can move and rotate freely.
Objects can be created and destroyed.
Disadvantages:
Cannot cope with point lights or spot lights.
Items must be of uniform scale.
Static Batching
Advantages:*
Lowers draw calls dramatically when point and spot lights are not present.
Lowers draw calls significantly when point and spot lights are present.
Supports per-object culling.
Objects can be destroyed.
Disadvantages:
Requires significant code work in order to prevent lag spikes when optimizing many objects.
Does not cope with point lights and spot lights as well as Mesh Combining does.
Items must be of uniform scale.
Objects cannot move after being batched.
Newly created objects must be re-batched inorder to be optimized.
Mesh Combining
Advantages:*
Works well in all lighting conditions.
Works well with any scaling.
Disadvantages:
Requires significant code work in order to prevent lag spikes when optimizing many objects.
Does not support per-object culling, resulting in potentially a lot of wasted computing power processing offscreen polygons. (However, this risk is negligable if the resulting combined mesh's bounding box takes up very little screen area.)
Objects cannot move after being combined, unless recombined afterwards.
Objects cannot be created or destroyed after being combined, unless recombined afterwards.
Requires memory to store the resulting combined mesh.
Here's what I think would work best:
1) Use Mesh Combining to combine the objects into chunks. The chunks should be big enough to fit as many objects as possible without being too big, or else it will never be culled.
Try to use a delayed combine, in case objects are being created, changed, or destroyed often. Wait for everything to settle for a few seconds and then combine them, otherwise every change will cause this slow combine operation to happen.
Detect when changes are made to the objects you want to combine. When a change occurs, delete the combined mesh and enable the original mesh renderers. Then after a pause, recombine them again.
Don't do this in one big step with all the objects you want to optimize. Instead, try to perform the merging over multiple frames.
This resolves the issues Dynamic Batching and Static Batching have with using scaled objects.
This also resolves the issue Static Batching has with optimizing many objects. Since many small objects are combined into a few big ones in this step, Static Batching should work much faster.
This also saves a slight amount of time that'd normally be spent on culling calculations.
Lastly, when using Point Lights or Spot Lights, the combined meshes act as a reliable fallback when the other approaches fall short.
2) Combine the resulting larger objects together using StaticBatchingUtility.Combine();
Try to use a delayed combine here as well, for similar reasons.
Detect when changes are made to the objects you want to combine. When a change occurs, all you have to do is call StaticBatchingUtility.Combine() a second time.
If there are too many objects for the static batcher to combine, consider using mulitple batchers. Batch operations should also be spread out over multple frames as they can be slow.
3) Dynamic batching is applied automatically so no work needs to be done here. :)
Have you managed to locate a solution to this yet?
I'm having an almost identical issue, but can't find any solutions as of yet.
(Whilst I appreciate the long answer above, that doesn't answer the question : "Why don't objects instantiated in a script batch dynamically?")
I don't really see how this answers the question. The actual problem as I see it relates to "When instantiated with a script they will not dynamically batch at all.".
Follow this Question
Related Questions
Is there any way I can statically batch procedurally generated objects? 0 Answers
Drawcalls or Batched, which is more important to performace? 1 Answer
,Drawing 100 000+ cubes 1 Answer
Force elements in same batch 1 Answer
Is there a way to use SkinnedMeshRenderer.BakeMesh() in multiple threads? (Mesh Instancing) 0 Answers