Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Graphics.DrawMeshInstanced uses 3-5 Batches.

Discussion in 'Scripting' started by Saphirah, Sep 20, 2021.

  1. Saphirah

    Saphirah

    Joined:
    May 27, 2020
    Posts:
    4
    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.
    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.
    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.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class RoomManager : MonoBehaviour
    6. {
    7.     public Mesh mesh;
    8.     public Material material;
    9.  
    10.     public Vector3 selectionStartPosition;
    11.     public Vector3 selectionCurrentPosition;
    12.  
    13.     Transform instanceTransform;
    14.  
    15.     public List<Matrix4x4> matrices;
    16.  
    17.     public int counter;
    18.  
    19.     private void Start()
    20.     {
    21.         instanceTransform = new GameObject().transform;
    22.         instanceTransform.rotation = Quaternion.Euler(-90, 0, 0);
    23.         instanceTransform.localScale = new Vector3(0.2f, 0.2f, 0.2f);
    24.     }
    25.  
    26.     void Update()
    27.     {
    28.         //Drag area start position
    29.         if (Input.GetMouseButtonDown(0))
    30.             selectionStartPosition = GetMousePositionInWorld();
    31.  
    32.         //Drag area current position
    33.         if (Input.GetMouseButton(0) || Input.GetMouseButtonUp(0))
    34.         {
    35.             selectionCurrentPosition = GetMousePositionInWorld();
    36.  
    37.             //Convert world position to integers
    38.             Vector2Int preFromPos = new Vector2Int(Mathf.RoundToInt(selectionStartPosition.x), Mathf.RoundToInt(selectionStartPosition.z));
    39.             Vector2Int preToPos = new Vector2Int(Mathf.RoundToInt(selectionCurrentPosition.x), Mathf.RoundToInt(selectionCurrentPosition.z));
    40.  
    41.             //Sort positions, so we can iterate with for loop
    42.             Vector2Int fromPos = new Vector2Int(Mathf.Min(preFromPos.x, preToPos.x), Mathf.Min(preFromPos.y, preToPos.y));
    43.             Vector2Int toPos = new Vector2Int(Mathf.Max(preFromPos.x, preToPos.x), Mathf.Max(preFromPos.y, preToPos.y));
    44.  
    45.             matrices = new List<Matrix4x4>();
    46.  
    47.             if (Input.GetMouseButton(0))
    48.             {
    49.                 //Add positions to matrix array
    50.                 for (int x = fromPos.x; x <= toPos.x; x++)
    51.                     for (int z = fromPos.y; z <= toPos.y; z++)
    52.                     {
    53.                         instanceTransform.position = new Vector3(x, 0, z);
    54.                         matrices.Add(instanceTransform.localToWorldMatrix);
    55.                     }
    56.  
    57.                 //Draws the mesh instanced.
    58.                 //Unity only supports 1023 Instances per call, so this needs to be accounted for
    59.                 counter = 0;
    60.                 for (int x = 0; x < matrices.Count / 1023f; x++)
    61.                 {
    62.                     int instanceCountToEnd = Mathf.Min(1023, matrices.Count - 1023 * x);
    63.                     Graphics.DrawMeshInstanced(mesh, 0, material, matrices.GetRange(1023 * x, instanceCountToEnd));
    64.                     counter++;
    65.                 }
    66.             }
    67.  
    68.             if (Input.GetMouseButtonUp(0))
    69.             {
    70.  
    71.             }
    72.         }
    73.     }
    74.  
    75.     public Vector3 GetMousePositionInWorld()
    76.     {
    77.         Plane plane = new Plane(Vector3.up, 0);
    78.         Vector3 targetPosition = new Vector3();
    79.         float distance;
    80.         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    81.         if (plane.Raycast(ray, out distance))
    82.         {
    83.             targetPosition = ray.GetPoint(distance);
    84.             targetPosition.Scale(new Vector3(1, 0, 1));
    85.         }
    86.         return targetPosition;
    87.     }
    88. }
    89.  
    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!
     
  2. MaskedMouse

    MaskedMouse

    Joined:
    Jul 8, 2014
    Posts:
    1,091
    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.
     
    PraetorBlue likes this.