Unity3D draw call optimization : static batching VS manually draw mesh with MaterialPropertyBlock

Posted by Heisenbug on Game Development See other posts from Game Development or by Heisenbug
Published on 2012-12-12T14:37:32Z Indexed on 2012/12/12 17:20 UTC
Read the original article Hit count: 3062

Filed under:
|
|

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

  1. Build a GameObject for each building building (I don't like very much the overhead of a GameObject, anyway..)
  2. Prepare each GameObject to be static batched with StaticBatchingUtility.Combine.
  3. Pack all texture into an atlas
  4. Assign the parent game object of combined batched objects the Material (basically the shader and the atlas)
  5. 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

  1. Build a Mesh for every building (sounds better, no GameObject overhead)
  2. Pack all textures into an Atlas
  3. Draw each mesh manually using Graphics.DrawMesh
  4. 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)?

© Game Development or respective owner

Related posts about unity

Related posts about shaders