Probuilder Collapse/Merge mesh vertices

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

MeshUtility.CollapseSharedVertices(mesh.GetComponent<MeshFilter>().sharedMesh);

MeshUtility.CollapseSharedVertices(mesh.GetComponent<MeshFilter>().sharedMesh, mesh.GetVertices());

// this one merges all vertices thuis 0 vertices left and no mesh. Dunno what to pass here
mesh.MergeVertices(mesh.faces.SelectMany(face => face.indexes).ToArray());

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.

Here example of the problem

ProBuilderMesh BuildQuad(Vector3 pos) {
    ProBuilderMesh quad = ProBuilderMesh.Create(
      new Vector3[] {
        new Vector3(0, 0, 0),
        new Vector3(0.5f, 0, 0),
        new Vector3(0, 0, 0.5f),
        new Vector3(0.5f, 0, 0.5f),
        new Vector3(1f, 0, 0),
        new Vector3(1f, 0, 0.5f),
        new Vector3(0, 0, 1f),
        new Vector3(0.5f, 0, 1f),
        new Vector3(1f, 0, 1f),
      },
      new Face[] {
        new Face(new[] {0, 2, 1, 2, 3, 1}),
        new Face(new[] {1, 3, 4, 3, 5, 4}),
        new Face(new[] {2, 6, 3, 6, 7, 3}),
        new Face(new[] {3, 7, 5, 7, 8, 5}),
      }
    );

    quad.transform.position = pos;

    return quad;
  }

  void Start() {
    ProBuilderMesh plane1 = ShapeGenerator.GeneratePlane(PivotLocation.Center, 1, 1, 1, 1, Axis.Up); // this gets quad/plane with 16 vertices
    ProBuilderMesh plane2 = ShapeGenerator.GeneratePlane(PivotLocation.Center, 1, 1, 1, 1, Axis.Up); // this gets quad/plane with 16 vertices

    ProBuilderMesh quad1 = BuildQuad(new Vector3(2, 0, 2)); // this gets quad/plane with 9 vertices
    ProBuilderMesh quad2 = BuildQuad(new Vector3(3, 0, 2)); // this gets quad/plane with 9 vertices

    List<ProBuilderMesh> planes     = new List<ProBuilderMesh>() {plane1, plane2};
    ProBuilderMesh       planesMesh = CombineMeshes.Combine(planes, planes.First()).First();

    Debug.Log(planesMesh.GetVertices().Length);
    MeshUtility.CollapseSharedVertices(planesMesh.GetComponent<MeshFilter>().sharedMesh); // doesnt work
    planesMesh.ToMesh();
    planesMesh.Refresh();
    Debug.Log(planesMesh.GetVertices().Length);

    List<ProBuilderMesh> quads     = new List<ProBuilderMesh>() {quad1, quad2};
    ProBuilderMesh       quadsMesh = CombineMeshes.Combine(quads, quads.First()).First();

    Debug.Log(quadsMesh.GetVertices().Length);
    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
    quadsMesh.ToMesh();
    quadsMesh.Refresh();
    Debug.Log(quadsMesh.GetVertices().Length);

  }

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

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.

Thank you @kaarrrllll for the input! I really appreciate it!
So doing as you said

planesMesh.faces.ToList()
     .ForEach(
        x => {
          x.textureGroup = group;
          x.smoothingGroup = group;
        }
      );
   
    planesMesh.ToMesh();
    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.

public static void MergeAllVertices(this ProBuilderMesh mesh) {
    SharedVertex.GetSharedVerticesWithPositions(mesh.VerticesInWorldSpace())
     .Where(vert => vert.Count > 1)
     .ToList()
     .ForEach(vertex => mesh.MergeVertices(vertex.ToArray(), true));

    MeshUtility.CollapseSharedVertices(mesh.GetComponent<MeshFilter>().sharedMesh);
    // mesh.ToMesh();
    // mesh.Refresh();
  }

So I’m pretty happy about that.

1 Like

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
public static void SetMeshPosition(this ProBuilderMesh mesh, Vector3 position) {
    mesh.transform.position = position;
  }

  • moving vertices of the mesh to the desired position
public static void SetMeshPosition(this ProBuilderMesh mesh, Vector3 position) {
    Vertex[] vertices = mesh.GetVertices();

    for (int i = 0; i < mesh.vertexCount; i++)
      vertices[i].position += position;

    mesh.SetVertices(vertices);
    mesh.ToMesh();
    mesh.Refresh();

    // If at runtime, collapse duplicate vertices with
    MeshUtility.CollapseSharedVertices(mesh.GetComponent<MeshFilter>().sharedMesh);
  }

6782582--785189--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

6782582--785195--Unity_im3JjVuNip.png

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.