How to make memory friendly mesh splitting editor tool?

I’m making an editor tool that separates a mesh into smaller meshes based on timestamp data in UV2. The tool is for Open Brush’s Unity SDK. Open Brush is a VR painting game, and the SDK allows a unity developer to take Open Brush paintings into their Unity project. When you export from Open Brush, the exporter will group strokes together. This tool can be used to get the original strokes.

Example use case: https://youtu.be/krXYTtJ8Mk8

The reason for this post: My first approach had several problems in terms of memory usage, and I’m worried that my improved approach has other problems I’m not aware of.

In my first approach, I use a method GetMeshSubset(Mesh originalMesh, int[] Triangles) to create the new meshes. The caller will fill Triangles with only the necessary triangles for this child mesh:

public static Mesh GetMeshSubset(Mesh OriginalMesh, int[] Triangles) {
    Mesh newMesh = new Mesh();
    newMesh.name = OriginalMesh.name;
    newMesh.vertices = OriginalMesh.vertices;
    newMesh.triangles = Triangles;
    newMesh.uv = OriginalMesh.uv;
    newMesh.uv2 = OriginalMesh.uv2;
    newMesh.uv3 = OriginalMesh.uv3;
    newMesh.colors = OriginalMesh.colors;
    newMesh.subMeshCount = OriginalMesh.subMeshCount;
    newMesh.normals = OriginalMesh.normals;
    return newMesh;
}

There are 2 problems with this approach:

  1. The new mesh data is saved into the scene file because the meshes aren’t saved as assets.

  2. The method unnecessarily copies all vertex, UV, and other data from the original mesh, even if only a small subset of the data is needed for the new mesh.

Improved approach:

  public static Mesh GetMeshSubset(Mesh OriginalMesh, int[] Triangles, Vector3[] vertices = null, Vector2[] uv = null, Vector3[] normals = null,
    Color[] colors = null, int index = 0) {
    Mesh newMesh = new Mesh();
    newMesh.name = OriginalMesh.name;
    newMesh.vertices = vertices ?? OriginalMesh.vertices;
    newMesh.triangles = Triangles;
    newMesh.uv = uv ?? OriginalMesh.uv;
    newMesh.uv3 = OriginalMesh.uv3;
    newMesh.colors = colors ?? OriginalMesh.colors;
    newMesh.subMeshCount = OriginalMesh.subMeshCount;
    newMesh.normals = normals ?? OriginalMesh.normals;
    AssetDatabase.CreateAsset(newMesh, "Assets/"+OriginalMesh.name+"_submesh["+index+"].asset");
    return newMesh;
  }

The reason for this post, is because I’m worried that I have again made a mistake somewhere. Those 2 problems explained above, I didn’t know they would be problems before I encountered them.

So my question: in my currently improved approach - where I create a new asset for each mesh - am I making any mistakes memory/storage-wise?

Yes because the copied mesh still contains all vertices of the original mesh, as well as all the vertex UVs and colors and normals.

You’d have to isolate the vertices that you want to keep and make the triangles for these and create a new mesh out of these including the UVs, colors and normals for just the vertices you want to keep.

This does not belong in a method named GetMeshSubset. Duplicating the mesh object, and creating an asset out of it, are two separate tasks and thus should be split in two separate ‘create’ methods (CreateSubsetMesh and CreateAsset). Respectively the AssetDatabase.CreateAsset simply being called after the first method.

I’m doing that though? I realize that I don’t mention it but in the improved approach, where GetMeshSubset() has parameters for vertices,uv,normals,etc. I make sure that the caller creates those arrays with only the necessary data.

1 Like

From what I’ve tried with mesh slicing, it really helps to stick to native arrays, use the Mesh data API, and use Burst/jobs where possible.
It doesn’t reduce the memory size (a lot? Didn’t do a before and after), but allows you to manage it better and more performant.

Maybe some trickery to do it within GPU memory could theoretically work, but that’s gonna be rough