Graphics.DrawMeshInstanced uses 3-5 Batches.

Hello everyone.

I am trying to create a building game, where you can place tiles and build areas using drag and drop.
When you hold and drag your mouse, it will preview this area using blue boxes.
7508417--925625--upload_2021-9-20_16-16-54.png

For this i am using Graphics.DrawMeshInstanced, to save performance on huge areas.
But here i noticed, that unity seems to draw the mesh 3-5 times.

Here is the statistic, when i have one instance of the mesh in my scene.
7508417--925640--upload_2021-9-20_16-27-27.png
My mesh has exactly 12 tris and 14 vertices.
The statistic is showing 60 tris, 70 verts and 5 batches, so the mesh is definitely drawn 5x.

When i draw more meshes, the numbers rise linear. (60 tris, 120, 180 etc…)

I checked my code, and put in a counter, to check how many times Graphics.DrawMeshInstanced is called, and it is only executed once.
Also the matrix array only shows one entry.
I have exactly one game object with my script in the scene.

So to my knowledge it is definitely not the script calling DrawMeshInstanced multiple times.

Here is my code.
I am calling the DrawMeshInstanced once every frame in the update function.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RoomManager : MonoBehaviour
{
    public Mesh mesh;
    public Material material;

    public Vector3 selectionStartPosition;
    public Vector3 selectionCurrentPosition;

    Transform instanceTransform;

    public List<Matrix4x4> matrices;

    public int counter;

    private void Start()
    {
        instanceTransform = new GameObject().transform;
        instanceTransform.rotation = Quaternion.Euler(-90, 0, 0);
        instanceTransform.localScale = new Vector3(0.2f, 0.2f, 0.2f);
    }

    void Update()
    {
        //Drag area start position
        if (Input.GetMouseButtonDown(0))
            selectionStartPosition = GetMousePositionInWorld();

        //Drag area current position
        if (Input.GetMouseButton(0) || Input.GetMouseButtonUp(0))
        {
            selectionCurrentPosition = GetMousePositionInWorld();

            //Convert world position to integers
            Vector2Int preFromPos = new Vector2Int(Mathf.RoundToInt(selectionStartPosition.x), Mathf.RoundToInt(selectionStartPosition.z));
            Vector2Int preToPos = new Vector2Int(Mathf.RoundToInt(selectionCurrentPosition.x), Mathf.RoundToInt(selectionCurrentPosition.z));

            //Sort positions, so we can iterate with for loop
            Vector2Int fromPos = new Vector2Int(Mathf.Min(preFromPos.x, preToPos.x), Mathf.Min(preFromPos.y, preToPos.y));
            Vector2Int toPos = new Vector2Int(Mathf.Max(preFromPos.x, preToPos.x), Mathf.Max(preFromPos.y, preToPos.y));

            matrices = new List<Matrix4x4>();

            if (Input.GetMouseButton(0))
            {
                //Add positions to matrix array
                for (int x = fromPos.x; x <= toPos.x; x++)
                    for (int z = fromPos.y; z <= toPos.y; z++)
                    {
                        instanceTransform.position = new Vector3(x, 0, z);
                        matrices.Add(instanceTransform.localToWorldMatrix);
                    }

                //Draws the mesh instanced.
                //Unity only supports 1023 Instances per call, so this needs to be accounted for
                counter = 0;
                for (int x = 0; x < matrices.Count / 1023f; x++)
                {
                    int instanceCountToEnd = Mathf.Min(1023, matrices.Count - 1023 * x);
                    Graphics.DrawMeshInstanced(mesh, 0, material, matrices.GetRange(1023 * x, instanceCountToEnd));
                    counter++;
                }
            }

            if (Input.GetMouseButtonUp(0))
            {

            }
        }
    }

    public Vector3 GetMousePositionInWorld()
    {
        Plane plane = new Plane(Vector3.up, 0);
        Vector3 targetPosition = new Vector3();
        float distance;
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (plane.Raycast(ray, out distance))
        {
            targetPosition = ray.GetPoint(distance);
            targetPosition.Scale(new Vector3(1, 0, 1));
        }
        return targetPosition;
    }
}

So, why is this the case? Is this normal behaviour? If not, how can i get around this?
Thank you very much for your help!

5 batches does not indicate that your mesh is being drawn 5 times. Theres a skybox and lighting as well.
Use the frame debugger and you’ll see what is spent on the batches.

When using forward rendering, each light affects an object. Try adding 3 point lights above them and check the triangle count again.

1 Like