Search Unity

Probuilder Collapse/Merge mesh vertices

Discussion in 'World Building' started by stychu, Jan 27, 2021.

  1. stychu

    stychu

    Joined:
    May 9, 2016
    Posts:
    62
    Hi everyone,

    I'm pulling my hair out trying to merge/collapse shared vertices on the mesh via API. Could someone for love help me??

    I've tried

    Code (CSharp):
    1. MeshUtility.CollapseSharedVertices(mesh.GetComponent<MeshFilter>().sharedMesh);
    2.  
    3. MeshUtility.CollapseSharedVertices(mesh.GetComponent<MeshFilter>().sharedMesh, mesh.GetVertices());
    4.  
    5. // this one merges all vertices thuis 0 vertices left and no mesh. Dunno what to pass here
    6. mesh.MergeVertices(mesh.faces.SelectMany(face => face.indexes).ToArray());
    7.  
    8. MeshUtility.CollapseSharedVertices(mesh.GetComponent<MeshFilter>().mesh, mesh.GetVertices());

    I really struggle with this...

    I don't need that much excessive vertex data and it hurts my performance that's why I need to merge shared vertices so I have as less as possible and then do calculations on them.
     
    Last edited: Jan 29, 2021
  2. stychu

    stychu

    Joined:
    May 9, 2016
    Posts:
    62
    Here example of the problem


    Code (CSharp):
    1. ProBuilderMesh BuildQuad(Vector3 pos) {
    2.     ProBuilderMesh quad = ProBuilderMesh.Create(
    3.       new Vector3[] {
    4.         new Vector3(0, 0, 0),
    5.         new Vector3(0.5f, 0, 0),
    6.         new Vector3(0, 0, 0.5f),
    7.         new Vector3(0.5f, 0, 0.5f),
    8.         new Vector3(1f, 0, 0),
    9.         new Vector3(1f, 0, 0.5f),
    10.         new Vector3(0, 0, 1f),
    11.         new Vector3(0.5f, 0, 1f),
    12.         new Vector3(1f, 0, 1f),
    13.       },
    14.       new Face[] {
    15.         new Face(new[] {0, 2, 1, 2, 3, 1}),
    16.         new Face(new[] {1, 3, 4, 3, 5, 4}),
    17.         new Face(new[] {2, 6, 3, 6, 7, 3}),
    18.         new Face(new[] {3, 7, 5, 7, 8, 5}),
    19.       }
    20.     );
    21.  
    22.     quad.transform.position = pos;
    23.  
    24.     return quad;
    25.   }
    26.  
    27.   void Start() {
    28.     ProBuilderMesh plane1 = ShapeGenerator.GeneratePlane(PivotLocation.Center, 1, 1, 1, 1, Axis.Up); // this gets quad/plane with 16 vertices
    29.     ProBuilderMesh plane2 = ShapeGenerator.GeneratePlane(PivotLocation.Center, 1, 1, 1, 1, Axis.Up); // this gets quad/plane with 16 vertices
    30.  
    31.     ProBuilderMesh quad1 = BuildQuad(new Vector3(2, 0, 2)); // this gets quad/plane with 9 vertices
    32.     ProBuilderMesh quad2 = BuildQuad(new Vector3(3, 0, 2)); // this gets quad/plane with 9 vertices
    33.  
    34.     List<ProBuilderMesh> planes     = new List<ProBuilderMesh>() {plane1, plane2};
    35.     ProBuilderMesh       planesMesh = CombineMeshes.Combine(planes, planes.First()).First();
    36.  
    37.     Debug.Log(planesMesh.GetVertices().Length);
    38.     MeshUtility.CollapseSharedVertices(planesMesh.GetComponent<MeshFilter>().sharedMesh); // doesnt work
    39.     planesMesh.ToMesh();
    40.     planesMesh.Refresh();
    41.     Debug.Log(planesMesh.GetVertices().Length);
    42.  
    43.     List<ProBuilderMesh> quads     = new List<ProBuilderMesh>() {quad1, quad2};
    44.     ProBuilderMesh       quadsMesh = CombineMeshes.Combine(quads, quads.First()).First();
    45.  
    46.     Debug.Log(quadsMesh.GetVertices().Length);
    47.     MeshUtility.CollapseSharedVertices(quadsMesh.GetComponent<MeshFilter>().sharedMesh);// doesnt work 18 vertices in my understanding there should by 15 as 3 vertices are shared after merging 2 quads at those positions
    48.     quadsMesh.ToMesh();
    49.     quadsMesh.Refresh();
    50.     Debug.Log(quadsMesh.GetVertices().Length);
    51.  
    52.   }
    How I could possibly reduce the sharedvertices after combining the meshes?? For love is there noone who could help me on that? Is Probuilder cappable of doing this via API?? It can do it in editor but how to do it in code??
    @kaarrrllll would you be able to suggest/help with this? Seems you're only the one who knows something
     
  3. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    ProBuilder will only merge coincident vertices that share common vertex data, which means not just position but also normal, tangent, and UV data. So if your intent is to generate a place with a single vertex for each coincident point you need to make sure that all the input vertices to each coincident vertex are equal. With a plane this is fortunately pretty easy, just set all your faces to use the same smoothing and texture group, and ensure that if you're using vertex colors that they are also uniform.
     
  4. stychu

    stychu

    Joined:
    May 9, 2016
    Posts:
    62
    Thank you @kaarrrllll for the input! I really appreciate it!
    So doing as you said

    Code (CSharp):
    1. planesMesh.faces.ToList()
    2.      .ForEach(
    3.         x => {
    4.           x.textureGroup = group;
    5.           x.smoothingGroup = group;
    6.         }
    7.       );
    8.    
    9.     planesMesh.ToMesh();
    10.     planesMesh.Refresh();
    Does indeed give me ALMOST what I look for. When I look for border vertices it gives me 13 out of 12 which I need. So 1 extra in the middle where two planes are connecting after combine.

    Adding this part of code what I managed to put up gives me 12 border wertices as this part does really merge the shared vertices.

    Code (CSharp):
    1. public static void MergeAllVertices(this ProBuilderMesh mesh) {
    2.     SharedVertex.GetSharedVerticesWithPositions(mesh.VerticesInWorldSpace())
    3.      .Where(vert => vert.Count > 1)
    4.      .ToList()
    5.      .ForEach(vertex => mesh.MergeVertices(vertex.ToArray(), true));
    6.  
    7.     MeshUtility.CollapseSharedVertices(mesh.GetComponent<MeshFilter>().sharedMesh);
    8.     // mesh.ToMesh();
    9.     // mesh.Refresh();
    10.   }
    So I'm pretty happy about that.
     
    kaarrrllll likes this.
  5. stychu

    stychu

    Joined:
    May 9, 2016
    Posts:
    62
    Secondly I would like to ask how to properly move the mesh after you create it??
    Should it be done via:

    - setting transform of the mesh to the desired position

    Code (CSharp):
    1. public static void SetMeshPosition(this ProBuilderMesh mesh, Vector3 position) {
    2.     mesh.transform.position = position;
    3.   }
    Unity_0QmIb3ynrt.png

    - moving vertices of the mesh to the desired position

    Code (CSharp):
    1. public static void SetMeshPosition(this ProBuilderMesh mesh, Vector3 position) {
    2.     Vertex[] vertices = mesh.GetVertices();
    3.  
    4.     for (int i = 0; i < mesh.vertexCount; i++)
    5.       vertices[i].position += position;
    6.  
    7.     mesh.SetVertices(vertices);
    8.     mesh.ToMesh();
    9.     mesh.Refresh();
    10.  
    11.     // If at runtime, collapse duplicate vertices with
    12.     MeshUtility.CollapseSharedVertices(mesh.GetComponent<MeshFilter>().sharedMesh);
    13.   }
    Unity_8R2kXs8uNT.png

    Doing it via transform seems much faster and cleaner but It doesn't seem to move vertices under the hood and when i check for them in the scene they are at the 0.0.0 position whereas mesh is at x position.



    Also there seems to be something off when I have set the PivotLocation for the mesh when generating it. When It has PivotLocation.FirstVertex mesh is a little bit off from the vertices

    Unity_im3JjVuNip.png
     
  6. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    It depends what you want to accomplish when moving the mesh. In most cases moving the transform is what you want to do. However if you want the mesh pivot to remain at a certain point while your vertices move, then you'll need to move vertices directly.