Unity3D draw call optimization : static batching VS manually draw mesh with MaterialPropertyBlock
- by Heisenbug
I've read Unity3D draw call batching documentation.
I understood it, and I want to use it (or something similar) in order to optimize my application.
My situation is the following:
I'm drawing hundreds of 3d buildings. Each building can be represented using a Mesh (or a SubMesh for each building, but I don't thing this will affect performances)
Each building can be textured with several combinations of texture patterns(walls, windows,..). Textures are stored into an Atlas for optimizaztion (see Texture2d.PackTextures)
Texture mapping and facade pattern generation is done in fragment shader. The shader can be the same (except for few values) for all buildings, so I'd like to use a sharedMaterial in order to optimize parameters passed to the GPU.
The main problem is that, even if I use an Atlas, share the material, and declare the objects as static to use static batching, there are few parameters(very fews, it could be just even a float I guess) that should be different for every draw call.
I don't know exactly how to manage this situation using Unity3D.
I'm trying 2 different solutions, none of them completely implemented.
Solution 1
Build a GameObject for each building building (I don't like very much the overhead of a GameObject, anyway..)
Prepare each GameObject to be static batched with StaticBatchingUtility.Combine.
Pack all texture into an atlas
Assign the parent game object of combined batched objects the Material (basically the shader and the atlas)
Change some properties in the material before drawing an Object
The problem is the point 5. Let's say I have to assign a different id to an object before drawing it, how can I do this?
If I use a different material for each object I can't benefit of
static batching.
If I use a sharedMaterial and I modify a material property, all GameObjects will reference the same modified variable
Solution 2
Build a Mesh for every building (sounds better, no GameObject overhead)
Pack all textures into an Atlas
Draw each mesh manually using Graphics.DrawMesh
Customize each DrawMesh call using a MaterialPropertyBlock
This would solve the issue related to slightly modify material properties for each draw call, but the documentation isn't clear on the following point:
Does several consecutive calls to Graphic.DrawMesh with a different MaterialPropertyBlock would cause a new material to be instanced?
Or Unity can understand that I'm modifying just few parameters while using the same material and is able to optimize that (in such a way that the big atlas is passed just once to the GPU)?