Clean leftovers from combineMeshes

I can’t seem to clean up leftovers from my combined mesh. When I try to delete unnecessary meshes and leave only the newly combined mesh it deletes everything. How I should clean up??
Is it possible to generate shapes without actually making game objects? Just raw data for the shapes?

    private ProBuilderMesh CreateMesh(Vector3 position) {
      ProBuilderMesh mesh = ShapeGenerator.GeneratePlane(PivotLocation.FirstVertex, 1, 1, 0, 0, Axis.Up);

      mesh.transform.position = position;

      return mesh;
    }

    private void Rebuild() {
      List<Vector3>        points = waypoints.Select(point => point.transform.position).ToList();
      List<ProBuilderMesh> meshes = new List<ProBuilderMesh>();

      points.Select(CreateMesh).ToList().ForEach(meshes.Add);

      m_Mesh = CombineMeshes.Combine(meshes, meshes.First()).First();

      m_Mesh.GetComponent<MeshRenderer>().sharedMaterial = material;
    
      meshes.ForEach(mesh => Destroy(mesh.gameObject));

    }

So instead of doing

meshes.ForEach(mesh => Destroy(mesh.gameObject));

I did this and it worked

for (int i = 1; i < meshes.Count; i++)
        Destroy(meshes[i].gameObject);

I’m not sure if this is a bug or I’m doing something wrong when combining meshes but my code generates planes for each vector and takes the first one to combine with the others making the first one the root of the combined mesh. Previously I was deleting all meshes thus the root one too.

I think this might be a bug because I was not able to create a new separate plane and use it as a target mesh for combine which I think should work??

Shouldn’t this one work? It gives me null reference

m_Mesh = CombineMeshes.Combine(meshes, CreateMesh(Vector3.zero)).First();
ArgumentNullException: Value cannot be null.
Parameter name: source
System.Linq.Enumerable.TryGetFirst[TSource] (System.Collections.Generic.IEnumerable`1[T] source, System.Boolean& found) (at <351e49e2a5bf4fd6beabb458ce2255f3>:0)
System.Linq.Enumerable.First[TSource] (System.Collections.Generic.IEnumerable`1[T] source) (at <351e49e2a5bf4fd6beabb458ce2255f3>:0)
ProBuilder.Examples.CreatePolyShape.Rebuild () (at Assets/Samples/ProBuilder/4.2.3/Runtime Examples/Misc/CreatePolyShape.cs:53)
ProBuilder.Examples.CreatePolyShape.Start () (at Assets/Samples/ProBuilder/4.2.3/Runtime Examples/Misc/CreatePolyShape.cs:36)

@kaarrrllll could you give me insight if something is wrong here?

meshes.ForEach(mesh => Destroy(mesh.gameObject));

In this example you’re modifying the collection while iterating it, which isn’t allowed.

m_Mesh = CombineMeshes.Combine(meshes, CreateMesh(Vector3.zero)).First();

That won’t work, the function requires the target mesh to be contained in the first collection.

Instead, try:

var target = ProBuilderMesh.Create();
meshes.Add(target);

m_Mesh = CombineMeshes.Combine(meshes, target).First();

Yeah, I figured that out after going through the codebase comments.

Anyway I’m not able to modify combined mesh for example extrude it after combine is done. Any ideas why ?
@kaarrrllll

Can you post your complete code snippet?

@kaarrrllll I noticed that problem was caused in Unity version 2019.4.14f1 and lower. Upgrading to 2019.4.17f1 and also on 2020 works fine. No errors and I’m able to extrude combined mesh successfully.

One question tho. Is it possible to Generate primitive shape without creating the actual object for it?? I just would like to have the data for that object and don’t appear it in the scene at the moment of creation.

Code that I was checking ad was causing errors in 2019.4.14f1 and lower versions of Unity

[SerializeField]
  private ProBuilderMesh CreateMesh(Vector3 position) {
    ProBuilderMesh mesh = ShapeGenerator.GeneratePlane(PivotLocation.Center, 1, 1, 0, 0, Axis.Up);

    mesh.transform.position = position;

    return mesh;
  }

  void Start() {
    List<Vector3>        points = new List<Vector3>() {Vector3.back, Vector3.forward, Vector3.left, Vector3.right};
    List<ProBuilderMesh> meshes = new List<ProBuilderMesh>();
   
 points.Select(CreateMesh).ToList().ForEach(meshes.Add);

    ProBuilderMesh newMesh = CombineMeshes.Combine(meshes, meshes.First()).First();

    newMesh.Extrude(newMesh.faces, ExtrudeMethod.VertexNormal, 1);
    newMesh.ToMesh();
    newMesh.Refresh();
  }

One way you could do this is by disabling the MeshRenderer as soon as the mesh is created. There isn’t however a way to just build a mesh without also instantiating a GameObject.

1 Like

One more question @kaarrrllll
Is there an easy way to remove internal adjacet faces? For example Having 3 cubes close to eachother(adjacet) i would like them to not have the internal faces where they connect. So those 3 cubes would form 1 big rectangular shape with empty area inside. So instead having 18 faces i would have 14

There isn’t a built-in way to do this, but you could implement it yourself by using something like a 3d variation of the even-odd rule.

1 Like