Search Unity

Mesh Combine/Welding optimization for mobile

Discussion in 'General Graphics' started by WorldWideGlide, Apr 13, 2021.

  1. WorldWideGlide

    WorldWideGlide

    Joined:
    Nov 3, 2013
    Posts:
    26
    I recently added a feature to my game that will "weld" separate meshes into single seamless objects. I am welding individual blocks into groups, and the groups progressively get larger.

    Before:
    upload_2021-4-12_13-34-11.png
    After:
    upload_2021-4-12_13-34-23.png

    So far it works reasonably well but performance is a big concern of mine, especially on mobile. My desktop has little issue but I'm seeing some lag on my Galaxy S20+ when the shapes are merged. This is concerning because I want this game to run OK on 3rd or even 4th generation devices. I'd like to know if anyone has some advice on ways to do this efficiently!

    I'm using CombineMeshes(CombineInstance) to join individual meshes into a single mesh (very little overhead), then the following function to 'weld' the vertices of the combined mesh:

    Code (CSharp):
    1. public void WeldMeshes2(GameObject combinedMeshObj)
    2.     {
    3.        
    4.         var combinedMesh = combinedMeshObj.GetComponent<MeshFilter>().mesh;
    5.  
    6.         Vector3[] verts = combinedMesh.vertices;
    7.  
    8.         // Build new vertex buffer and remove "duplicate" vertices
    9.         // that are within the given threshold.
    10.         List<Vector3> newVerts = new List<Vector3>();
    11.        
    12.         foreach (Vector3 vert in verts)
    13.         {
    14.             // Has vertex already been added to newVerts list?
    15.             foreach (Vector3 newVert in newVerts)
    16.                 if (Vector3.Distance(newVert, vert) <= weldThreshold)
    17.                     goto skipToNext;
    18.  
    19.             // Accept new vertex!
    20.             newVerts.Add(vert);
    21.  
    22.         skipToNext:;
    23.  
    24.         }
    25.        
    26.         // Rebuild triangles using new vertices
    27.         int[] tris = combinedMesh.triangles;
    28.      
    29.         for (int i = 0; i < tris.Length; ++i)
    30.         {
    31.             // Find new vertex point from buffer
    32.             for (int j = 0; j < newVerts.Count; ++j)
    33.             {
    34.                 if (Vector3.Distance(newVerts[j], verts[tris[i]]) <= weldThreshold)
    35.                 {
    36.                     tris[i] = j;
    37.                     break;
    38.                 }
    39.             }
    40.         }
    41.         //print("Weld: Recalculate triangle Time " + (Time.realtimeSinceStartup - t2));
    42.  
    43.         // Update mesh!
    44.         combinedMesh.Clear();
    45.         combinedMesh.vertices = newVerts.ToArray();
    46.         combinedMesh.triangles = tris;
    47.         RecalculateNormalsSeamless(combinedMesh);
    48.  
    49.     }
    75% of the lag is being caused by the triangle recalculation //Rebuild triangles using new vertices. This is because the final shape that is being welded can have thousands of triangles. The rest is from the vertice calculation //Build new vertex buffer and remove "duplicate" vertices. For reference the blocks I'm using have only 136 verts and 108 triangles. The lag gets worse the larger the group is...

    Is there anyway to do this with less overhead aside from using cheaper meshes???

     
  2. Thygrrr

    Thygrrr

    Joined:
    Sep 23, 2013
    Posts:
    700
    You could offload the work into multiple frames (e.g. in a coroutine), basically processing as many as you have time for each frame, playing a visual effect on top of where it happens if you need to cover it up, and then combine.