Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Strip PB scripts in Editor code? Or extract mesh from ProBuilderMesh?

Discussion in 'World Building' started by dgoyette, Jan 12, 2020.

  1. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    TLDR: Can't I can StripProBuilderObjects from within some other Editor script?

    I'm using a now-deprecated Asset Store offering to fracture objects into pieces. I've found that in many cases, the resulting object is kind of a mess, with way too many verts, and a lot of overlapping verts. This results into terrible UV maps. I've found that if I ProBuilderize it, and Weld Vertices, the result is very good. However, doing that manually is a pain, as sometimes there are hundreds of small pieces.

    In the Editor code that generates these pieces, I can add a ProBuilderMesh, and I can call WeldVertices on it, and that works great. But I haven't found a way to strip off the PB objects after doing that, so that the object just has its plain mesh. It seems that all of the code to Strip PB Objects is in private/protected classes, not accessible from other Editor code.

    Another approach would be if I could somehow get the underlying mesh from a ProBuilderMesh, and assign that to the objects's Mesh Filter. But I don't see a way to do that, as the mesh of a ProBuilderMesh is internal.

    Note that I'm only doing this stuff in an Editor script, not a build/runtime script, so I'm hoping that makes it more likely that this can be done.

    In short, I'm starting with a plain old mesh + Mesh Renderer, and I want to run this through PB's Weld Vertices, but end up with a plain old mesh + Mesh Renderer when I'm done. Is it possible to script that?
     
  2. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    dgoyette likes this.
  3. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    That worked great. Thanks.

    My use-case is probably kind of weird, but the following code uses PB to basically clean up a messy, generated mesh (generated via some 3rd party code I'm using that, unfortunately, isn't great...). This looks a little silly, and I'm probably calling some things redundantly here, but the end result is that it cleans up mesh nicely, even for prefabs whose mesh data is stored as an asset.

    Code (CSharp):
    1. private static void Probuilderize2(GameObject objectToProbuilderize, bool destroyAfter)
    2. {
    3.     var filter = objectToProbuilderize.GetComponent<MeshFilter>();
    4.     var renderer = objectToProbuilderize.GetComponent<Renderer>();
    5.     Mesh originalMesh = filter.sharedMesh;
    6.  
    7.     var settings = new MeshImportSettings()
    8.     {
    9.         quads = true,
    10.         smoothing = true,
    11.         smoothingAngle = 1
    12.     };
    13.  
    14.     ProBuilderMesh pb = Undo.AddComponent<ProBuilderMesh>(objectToProbuilderize);
    15.  
    16.     MeshImporter meshImporter = new MeshImporter(pb);
    17.     meshImporter.Import(filter.sharedMesh, materials: renderer.sharedMaterials, importSettings: settings);
    18.  
    19.     // if this was previously a pb_Object, or similarly any other instance asset, destroy it.
    20.     // if it is backed by saved asset, leave the mesh asset alone but assign a new mesh to the
    21.     // renderer so that we don't modify the asset.
    22.     if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(originalMesh)))
    23.     {
    24.         GameObject.DestroyImmediate(originalMesh);
    25.     }
    26.     else
    27.     {
    28.         objectToProbuilderize.GetComponent<MeshFilter>().sharedMesh = new Mesh();
    29.     }
    30.  
    31.     pb.ToMesh();
    32.     pb.Refresh();
    33.     pb.Optimize();
    34.  
    35.     // Clean up the objects by welding. This is probably overkill, but we seem to need to call this a
    36.     // couple of times depending on how messy the original object was.
    37.     pb.WeldVertices(Enumerable.Range(0, pb.vertexCount - 1).ToArray(), 0.01f);
    38.     pb.WeldVertices(Enumerable.Range(0, pb.vertexCount - 1).ToArray(), 0.01f);
    39.     pb.WeldVertices(Enumerable.Range(0, pb.vertexCount - 1).ToArray(), 0.01f);
    40.     pb.WeldVertices(Enumerable.Range(0, pb.vertexCount - 1).ToArray(), 0.01f);
    41.     pb.WeldVertices(Enumerable.Range(0, pb.vertexCount - 1).ToArray(), 0.01f);
    42.  
    43.     pb.Refresh();
    44.     pb.Optimize();
    45.  
    46.  
    47.  
    48.     if (destroyAfter)
    49.     {
    50.         // preserveMeshAssetOnDestroy must be true in order to keep the PB mesh on the object
    51.         // and assign it to the prefab.
    52.         pb.preserveMeshAssetOnDestroy = true;
    53.         GameObject.DestroyImmediate(pb);
    54.     }
    55. }