Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice
  2. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  3. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Adding a MeshCollider much slower in b10 than in b9

Discussion in '2017.3 Beta' started by Indral, Nov 22, 2017.

  1. Indral

    Indral

    Joined:
    Aug 18, 2017
    Posts:
    4
    In a project I generate a grid mesh in code. This mesh is then added to a MeshFilter and a MeshCollider on a new GameObject. Below is a simplified form of the code I use in this project. The time it takes to add the MeshCollider and assign the mesh is logged in the console.

    On my PC, in Unity 2017.3.0b9 the time it takes to add the MeshCollider and assign the mesh is 17ms. In Unity 2017.3.0b10 it takes 159ms, which is over 9 times slower. For larger or more complex meshes the difference increases even further; in my actual project the difference is 62ms vs 840ms, or 13.5 times slower.

    The default CookingOptions appear to be the same between b9 and b10 (
    CookForFasterSimulation, EnableMeshCleaning, WeldColocatedVertices). Enabling mesh cleaning by removing line 23 in the script below has little or no effect in b9, while it dramatically improves the performance in b10 (though still much slower than in b9, from 159ms to 44ms in my case).

    In addition to the speed difference, there is an issue with the geometry when generating more than 65.000 vertices (visible by looking at the generated mesh in wireframe view). I haven't read up on those changes yet though, I may have to perform some extra steps to get this to work properly.

    Steps to reproduce:
    1. Create an empty project
    2. Add an empty GameObject to the scene
    3. Add the script below to the empty GameObject
    4. Run the project
    5. Compare the output between Unity 2017.3.0b9 and 2017.3.0b10
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class MeshGenerator : MonoBehaviour
    4. {
    5.     public int Columns = 200;
    6.     public int Rows = 200;
    7.  
    8.     void Start()
    9.     {
    10.         Mesh gridMesh = GenerateGridMesh();
    11.  
    12.         GameObject meshObject = new GameObject("Generated Grid");
    13.  
    14.         MeshRenderer meshRenderer = meshObject.AddComponent<MeshRenderer>();
    15.         meshRenderer.sharedMaterial = new Material(Shader.Find("Diffuse"));
    16.  
    17.         MeshFilter meshFilter = meshObject.AddComponent<MeshFilter>();
    18.         meshFilter.sharedMesh = gridMesh;
    19.  
    20.         System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
    21.         stopwatch.Start();
    22.         MeshCollider meshCollider = meshObject.AddComponent<MeshCollider>();
    23.         meshCollider.cookingOptions -= MeshColliderCookingOptions.EnableMeshCleaning;
    24.         meshCollider.sharedMesh = gridMesh;
    25.         Debug.LogFormat("Adding the MeshCollider took {0}ms.", stopwatch.ElapsedMilliseconds);
    26.     }
    27.  
    28.     private Mesh GenerateGridMesh()
    29.     {
    30.         int numberOfTiles = Columns * Rows;
    31.         Vector3[] vertices = new Vector3[numberOfTiles * 4];
    32.         int[] triangles = new int[numberOfTiles * 6];
    33.  
    34.         for (int col = 0; col < Columns; col++)
    35.         {
    36.             for (int row = 0; row < Rows; row++)
    37.             {
    38.                 GenerateTile(vertices, triangles, col, row);
    39.             }
    40.         }
    41.  
    42.         return new Mesh()
    43.         {
    44.             vertices = vertices,
    45.             triangles = triangles
    46.         };
    47.     }
    48.  
    49.     private void GenerateTile(Vector3[] vertices, int[] triangles, int col, int row)
    50.     {
    51.         int tileVertexIndex = (col * Columns + row) * 4;
    52.         int tileTriangleIndex = (col * Columns + row) * 6;
    53.  
    54.         Vector3 tileCenter = new Vector3(col, 0, row);
    55.         vertices[tileVertexIndex + 0] = new Vector3(-0.5f, 0, -0.5f) + tileCenter;
    56.         vertices[tileVertexIndex + 1] = new Vector3(-0.5f, 0, 0.5f) + tileCenter;
    57.         vertices[tileVertexIndex + 2] = new Vector3(0.5f, 0, 0.5f) + tileCenter;
    58.         vertices[tileVertexIndex + 3] = new Vector3(0.5f, 0, -0.5f) + tileCenter;
    59.  
    60.         triangles[tileTriangleIndex + 0] = tileVertexIndex + 0;
    61.         triangles[tileTriangleIndex + 1] = tileVertexIndex + 1;
    62.         triangles[tileTriangleIndex + 2] = tileVertexIndex + 2;
    63.  
    64.         triangles[tileTriangleIndex + 3] = tileVertexIndex + 2;
    65.         triangles[tileTriangleIndex + 4] = tileVertexIndex + 3;
    66.         triangles[tileTriangleIndex + 5] = tileVertexIndex + 0;
    67.     }
    68. }
     
  2. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,589
    Great find, seems you found a regression! In this case, I recommend to submit a bug-report following the advice given in this document.

    Using the bug-reporter seems to be an important step, because it makes sure the report is in Unity Technologies bug-tracking pipeline and has to be processed at some point. Using the forum is often used to add to a little more attention to a bug-report, but does not replace submitting the bug-report.

    It's from advantage to attach a project to the bug-report that UT can use to reproduce the issue and test their fix against. Providing a project to reproduce the issue is even more important if it's a crash bug. The easier an issue can be reproduced by QA, the more likely it is to get forwarded to a developer, who might or might not work on a bug-fix for that at some point.

    After you submitted the bug-report, you receive a confirmation email with a Case number. UT often asks us to post the Case number in the forum thread, which allows them to find that bug-report if they look at your post.

    Following these steps will increase the chance that UT is looking at your issue tremendously.
     
    LeonhardP likes this.
  3. Indral

    Indral

    Joined:
    Aug 18, 2017
    Posts:
    4
    Thank you, makes sense! I've submitted a case with case number 971836. QA asked me to submit an additional ticket for the geometry issue, which has case number 971847.
     
    Last edited: Nov 23, 2017
  4. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,589
  5. Tallek

    Tallek

    Joined:
    Apr 21, 2014
    Posts:
    34
    The public issue tracker item is marked as "By Design". Is there any more info as to why it is by design or what is going on here?
     
  6. Indral

    Indral

    Joined:
    Aug 18, 2017
    Posts:
    4
    This is the feedback I received:

    I did some quick tests based on this feedback, and still noticed a (much smaller) performance difference between b9 and b10. However, this may very well be due to me not fully understanding how to add a MeshCollider and setting the cooking options before applying the mesh.

    Specifically, according to the reply from Unity this section of code was incorrect:
    Code (CSharp):
    1.  
    2.         MeshFilter meshFilter = meshObject.AddComponent<MeshFilter>();
    3.         meshFilter.sharedMesh = gridMesh;
    4.  
    5.         System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
    6.         stopwatch.Start();
    7.         MeshCollider meshCollider = meshObject.AddComponent<MeshCollider>();
    8.         meshCollider.cookingOptions -= MeshColliderCookingOptions.EnableMeshCleaning;
    9.         meshCollider.sharedMesh = gridMesh;
    10.         Debug.LogFormat("Adding the MeshCollider took {0}ms.", stopwatch.ElapsedMilliseconds);
    If I understand it correctly: Since the sharedMesh property was already set on the MeshFilter, adding the MeshCollider means it will use this sharedMesh right away, and setting the sharedMesh on the MeshCollider doesn't do anything. This means that I was only profiling the line which changed the cooking options, and this is what wasn't working correctly in b9.

    What I'm still trying to figure out is how to organize this code. I guess it will have to work something like this:
    1. Add the MeshFilter
    2. Add the MeshCollider
    3. Set the cooking options on the MeshCollider
    4. Assign the mesh to the sharedMesh on the MeshFilter
    5. Assign the mesh to the sharedMesh on the MeshCollider
    Because adding a MeshCollider will use an existing sharedMesh on the MeshFilter, the MeshCollider can't be added after assigning the sharedMesh to the MeshFilter, since I don't think there's a way to supply cooking options during the AddComponent call. Does anyone have a better idea?