Search Unity

Which should I optimize - Batches or Draw Calls?

Discussion in 'General Graphics' started by tanmaykulkarni, Jan 19, 2022.

  1. tanmaykulkarni

    tanmaykulkarni

    Joined:
    Nov 5, 2019
    Posts:
    104
    Hey dudes, I am trying to optimize my scene which runs on mobile platforms. I am using texture arrays [using one texture and one material for several objects] by setting UVs on start.

    Now the problem I get here is when I use Texture Arrays and one material, the draw calls increase noticeably and batches get reduced.

    But when I don't use Texture Arrays and use several materials, the draw calls decrease and batches get increased.

    What should I focus on to get more optimal results? Draw Calls or Batches?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    First, what do you mean by "draw call"? Are you using the profiler and looking at the Draw Calls there, or are you looking at the Setpass Calls there or in the stats window? Draw Calls are an important number, but not as important for performance as you might think. As long as the SetPass Calls number is low, having a high Draw Calls isn't a big issue, which is why they no longer show the Draw Calls in the stats window as people were optimizing for that to the detriment of performance.

    Reducing SetPass calls is probably the most important stat to focus on.

    Are you using a texture array or a texture atlas. There's a significant difference in performance for using texture arrays on some mobile devices.

    A texture array is a texture object with multiple layers that can be chosen between by the shader. Basically like having multiple 2D textures in a stack. If you were to look at this texture on a single quad, you'd just see one texture at a time.

    A texture atlas is a texture object that just has multiple textures packed into it just by placing them in different parts of the 2D texture. If you were to look at this texture on a single quad, you'd see all of the textures at once in a grid or whatever layout you've chosen to use. Which section is chosen by manipulating the UVs.

    You mention you're "setting UVs on start" which makes me thing you're using an atlas and not an array. But you comment is also odd and concerning to me. What do you mean by "on start"? Are you modifying the UVs of the meshes themselves at runtime? For mobile performance the best performance will be obtained via static batching. To use static batching you cannot be modifying the meshes at runtime. They need to have a single material with no material property blocks and UVs unmodified by runtime scripts. If you're combining the textures and modifying the mesh UVs when the game starts, it's too late. Those will still each be unique draws unless they're exceedingly simple meshes that the dynamic batching system can handle (300 or fewer vertices each).
     
    BeyondMASC likes this.
  3. tanmaykulkarni

    tanmaykulkarni

    Joined:
    Nov 5, 2019
    Posts:
    104
    I mean the void Start()
    Here's the script which I used
    Code (CSharp):
    1.  public int index;
    2.     void Awake()
    3.     {
    4.         List<Vector3> uvs = new List<Vector3>();
    5.         Mesh mesh = GetComponent<MeshFilter>().mesh;
    6.         mesh.GetUVs(0, uvs);
    7.         for(int i = 0; i < uvs.Count; i++)
    8.         {
    9.             uvs[i] = new Vector3(uvs[i].x, uvs[i].y, index);
    10.         }
    11.         mesh.SetUVs(0, uvs);
    12.     }
    13.  
    14.    
    And I am using texture array only, not atlas.
    What should be the optimal set pass call number on mobile platforms?
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Yeah, you can't do that if you want optminal performance on mobile because then it can't use static batching, assuming these meshes are otherwise static (ie: aren't moved or otherwise placed at runtime).

    Static batching requires the mesh data is finalized before you run the game. This lets Unity combine meshes at build time (or when you press play in the editor) into a single large mesh. However it still retains a connection between the individual game objects and that section of the larger mesh meaning you can toggle the visibility of it or they can be culled. This is the most optimal way to render on mobile platforms.

    If your geometry can't be static at build time, I'd suggest looking into manually combining meshes at runtime, or aggressively reducing mesh vertex counts, or using LODs to hide meshes.

    Optimal? 1. But that's an impossible goal unless you're doing a 2D game using a single sprite sheet for everything.

    Otherwise there is no answer to the question as it depends on the game you're making, the hardware you're running on, what kind of performance level you're targeting, etc. The only answer is "as low as possible", but anywhere between several hundred and a few thousand could be totally fine. If you can get to 60fps on your target device, you're doing good.
     
    BeyondMASC likes this.
  5. tanmaykulkarni

    tanmaykulkarni

    Joined:
    Nov 5, 2019
    Posts:
    104
    Oh, I got it! Anyways thank you!