Search Unity

ProBuilder API - using ProBuilder from script

Discussion in 'World Building' started by jariwake, Jul 8, 2018.

  1. jariwake

    jariwake

    Joined:
    Jun 2, 2017
    Posts:
    100
    I am thinking of using ProBuilder for procedural level generation. But it seems there is no API documentation available anywhere. The documentation does not contain any information about the API and FAQ just says "The ProBuilder API is currently considered to be in beta. It will change before the final release."

    There is this ProBuilder API example repository, but it just contains a couple of examples which are not really documented/explained.

    So is it really true that there is no any kind of documentation for the ProBuilder API available yet? If so, is there a roadmap for the ProBuilder that would indicate when the API would be officially released and supported?
     
  2. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    It's true that currently there is not any official documentation for the API. However, preparing the code and documentation for public use is what I've been doing for the last few months. The 4.0.0 update introduces a public API along with a scripting reference.

    There is not a set release date yet, but I anticipate it within the next few weeks.
     
    shikhrr and MilenaRocha like this.
  3. jariwake

    jariwake

    Joined:
    Jun 2, 2017
    Posts:
    100
    Thanks for the answer, @kaarrrllll. I have been toying with the API examples and it seems it is quite straight forward in terms of creating geometry. But will the API support all the geometry editing methods as well? In other words, will everything that is possible from the ProBuilder editor GUI be also possible via scripting? What I am especially interested are the boolean operations (which are now marked as experimental).
     
  4. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    Yes, everything you can do from the editor is accessible in script (except generating lightmap uvs).

    If you're looking for just the CSG, here's the library that ProBuilder is using under the hood: https://github.com/karl-/pb_CSG
     
  5. tarahugger

    tarahugger

    Joined:
    Jul 18, 2014
    Posts:
    129
    I've been playing with CSG and while it does work, it creates a real dogs-breakfast of the mesh after a couple of operations. The tris count skyrockets to the point where it would be unusable on mobile and eventually the mesh breaks catastrophically. It might be fine if we had a solid and efficient way of optimizing/simplifying the mesh between operations, but for my purposes right now it seems unworkable.

    Other issues include:
    • Not working with complicated or merged pb_objects, or pb_objects where extrude was used.
    • Losing nice quad face selection ability and can only select triangles.


    Code (CSharp):
    1.     public static pb_Object ExtractIntersection(GameObject source, GameObject stamp)
    2.     {
    3.         var sourcePb = source.GetComponent<pb_Object>();
    4.         var sourceMeshFilter = source.GetComponent<MeshFilter>();
    5.         var originalCenter = sourceMeshFilter.sharedMesh.bounds.center;
    6.  
    7.         // Create a mesh comprising only parts of the original mesh that overlap with the stamp.
    8.         var intersectionMesh = CSG.Intersect(source, stamp);
    9.  
    10.         // Create a game object and pb_object from mesh
    11.         var intersectionPb = ProBuilderize(intersectionMesh);
    12.  
    13.         // Cut out the intersection from the original, so that the original object remains the same visually but is now split into two objects.
    14.         var newMesh = CSG.Subtract(source, intersectionPb.gameObject);
    15.  
    16.         sourceMeshFilter.sharedMesh = newMesh;
    17.  
    18.         //// Update the pb_object to reflect changes to the underlying mesh.
    19.         ResetPbObjectWithMeshFilter(sourcePb, true);
    20.  
    21.         // The modified mesh coming out of CSG probably needs to be repositioned relative to previous pivot.
    22.         var newCenter = sourceMeshFilter.sharedMesh.bounds.center;
    23.         var offset = originalCenter - newCenter;
    24.         var indices = sourceMeshFilter.sharedMesh.GetIndices(0);
    25.  
    26.         sourcePb.TranslateVertices(indices, offset);
    27.         CenterPivot(sourcePb, indices);
    28.  
    29.         sourcePb.ToMesh();
    30.         sourcePb.Refresh();
    31.  
    32.         //pb_Smoothing.ApplySmoothingGroups(sourcePb, sourcePb.faces, 1, pb_Vertex.GetVertices(newMesh).Select(x => x.normal).ToArray());
    33.         //CollapseCoincidentVertices(sourcePb, sourcePb.faces);
    34.  
    35.         return intersectionPb;
    36.     }
    I think we need two things, a mesh simplification function and an easy way to clean a mesh, for example, if i create a rectangle box platform and a circular platform to place on the end of it, drag them over each other, then click a button and it strips all the overlapping parts.

    Currently unless i'm missing something, if i use 'merge objects' it keeps them intact and if i want to properly merge them i have to go in and edit out all the internal parts manually.
     
    Last edited: Jul 10, 2018
  6. tarahugger

    tarahugger

    Joined:
    Jul 18, 2014
    Posts:
    129
    Another related and frustrating thing is that it doesn't sub-divide faces 'properly' when the faces next to them have already been sub-divided and extruded. This is pretty limiting for progressive modifications, we'll end up having to know in advance and sub-divide everything up front.



    In the video there, it knows already that it is a single big square face so it could re-do its layout to 2x2/2 tri
     
  7. jariwake

    jariwake

    Joined:
    Jun 2, 2017
    Posts:
    100
    I see. I take that currently ProBuilder API does not expose CSG in any way, but it will be in the future. So right now my only option is to use CSG "in parallel" with ProBuilder?
     
  8. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    Yes, that's correct.
     
  9. Aranda

    Aranda

    Joined:
    Jan 23, 2015
    Posts:
    16
    Hi @kaarrrllll, still looking forward to 4.0.0 and the docs!. In particular I'd like to clear smoothing groups and triangulate objects from the API, but I can't seem to find it. Is this already available in 3.X or do I need to wait for 4.0?
     
  10. ibyte

    ibyte

    Joined:
    Aug 14, 2009
    Posts:
    1,047
    TheGabelle likes this.
  11. jariwake

    jariwake

    Joined:
    Jun 2, 2017
    Posts:
    100
    Well..it has been more than 5 months since you posted this, @kaarrrllll =)

    Could you maybe post an update on when the next version of ProBuilder with the API is out?
     
    HoldTheLine and Flavelius like this.
  12. gabrielw_unity

    gabrielw_unity

    Unity Technologies

    Joined:
    Feb 19, 2018
    Posts:
    963
    ibyte likes this.
  13. BBigG

    BBigG

    Joined:
    Aug 7, 2019
    Posts:
    4
    Hey hey, is there any news about this? The CSG tools is still experimental and therefore not accessible via the PB API?
     
  14. thomass16

    thomass16

    Joined:
    Feb 4, 2018
    Posts:
    1
    Would also love access to the CSG API. Will that be available soon?
     
    Xriuk and MilenaRocha like this.
  15. Nyanpas

    Nyanpas

    Joined:
    Dec 29, 2016
    Posts:
    406
    I would also like access to booleans like subtract, and also if it does not destroy the mesh like in the example mentioned above...
     
  16. Tarrag

    Tarrag

    Joined:
    Nov 7, 2016
    Posts:
    215
    I can't see API model export capability via script but if someone knew how to work around it , would much appreciate a share please, cheers!
     
  17. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    @Tarrag I don't think the model export is publicly exposed at the moment, but I will see about making it public in the next update.

    The best way to access CSG operations is still via the repository I linked above.
     
  18. Tarrag

    Tarrag

    Joined:
    Nov 7, 2016
    Posts:
    215
    kaarrrllll likes this.
  19. peterfiveeight

    peterfiveeight

    Joined:
    Jun 24, 2013
    Posts:
    9
    Any 2020 news on the API docs?

    Thanks
     
  20. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
  21. Radiangames2

    Radiangames2

    Joined:
    Aug 22, 2012
    Posts:
    45
    Sorry to bring back an old-ish thread, but I'm trying to create a custom button in the ProBuilder editor (to do some custom selection), and I can't even get a basic script to compile. It says "Pref<t> is inaccessible". I just copied the SelectByVertexColor script and I'm trying to use that as a basis. I can't find any real examples of the API being used, so it's possible I'm completely off here in how I'm using it. I expected to be able to just do a custom button without trouble.

    I'll try doing a normal popup window and see if any of the ProBuilder stuff works there.

    In either case, it'd be awesome to have some examples of custom scripts/buttons using the PB API. The two examples I found in the docs (create a custom quad and move it up) are minimal at best.

    Thanks,
    Luke
     
  22. Radiangames2

    Radiangames2

    Joined:
    Aug 22, 2012
    Posts:
    45
    Replying to this post directly to make sure Karl sees the question above :)

    EDIT: I was able to get the selection function to work as intended if I call it from a standard editor script. So that makes me happy enough. Fine having my own custom window for non-standard PB functions.
     
    Last edited: Feb 27, 2020
  23. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
  24. alex_znder

    alex_znder

    Joined:
    May 14, 2019
    Posts:
    3
    @kaarrrllll Hey Karl. Im wondering if i am able to access the Extrusion variable in the Polyshape component, I have an extrusion that i wish to get bigger / smaller by 1 when the user presses a button. For instance pseudo:

    if Button is pressed{
    extrusionnumber + 1 // float variable for label + extrusion size
    polyshape.extrusion = extrusionnumber
    }

    however i am not able to get component for the polyshape component, is there another way to change the length of the extrusion?
     
  25. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    The PolyShape component is currently private, but if you were to install source and make it public the property you're looking for is "extrude". Then make sure to call `polyShape.CreateShapeFromPolygon` after.
     
  26. alex_znder

    alex_znder

    Joined:
    May 14, 2019
    Posts:
    3
    Am i overthinking the method? is there a better way of doing this?
     
  27. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    Last edited: Mar 3, 2020
    PassivePicasso likes this.
  28. hridpath

    hridpath

    Joined:
    Jan 28, 2017
    Posts:
    16
    @kaarrrllll I have a collection of meshes that I want to programatically convert to a ProBuilderMesh object. Can you explain the best way to do that in C# script?
     
  29. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    @hridpath There is a code example showing how to do this in the Runtime samples for ProBuilder. Import from the Package Manager page on ProBuilder.
     
  30. hridpath

    hridpath

    Joined:
    Jan 28, 2017
    Posts:
    16
    @kaarrrllll Thank you for the pointer. I have included an Undo so this can be backed out. Does this look correct to you?

    public static bool ConvertToProbuilderGameObject(GameObject obj)
    {
    try
    {
    var mf = obj.GetComponent<MeshFilter>();
    if (mf)
    {
    Mesh originalMesh = mf.sharedMesh;
    ProBuilderMesh pb = Undo.AddComponent<ProBuilderMesh>(obj);

    var mesh = obj.AddComponent<ProBuilderMesh>();
    var importer = new MeshImporter(mesh);

    if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(originalMesh)))
    Undo.DestroyObjectImmediate(originalMesh);
    else
    obj.GetComponent<MeshFilter>().sharedMesh = new Mesh();

    importer.Import(mf.sharedMesh);
    mf.sharedMesh = new Mesh();
    mesh.ToMesh();
    mesh.Refresh();
    }

    }
    catch
    {
    return false;
    }
    return true;
    }
     
    Last edited: Mar 24, 2020
  31. batteryyrettab

    batteryyrettab

    Joined:
    Sep 20, 2013
    Posts:
    7
    Really enjoying using the Probuilder API (it's good that you have the samples now once the Package is installed).

    1. My first question is: Is there a Method for resetting the pivot rotation? I've currently got:
    Code (CSharp):
    1. ProBuilderMesh pb = GetComponent<ProBuilderMesh>();
    2.  
    3. pb.SetPivot(new Vector3(7,2,8));
    What I'd like to do is reset the rotations not just the position. Currently I have to go into the sub-object editing and rotate all faces to do this. [Note: With the bug where the gizmo is not selectable sometimes I can't do this. I do note that one axis is selectable but the other two aren't.]

    2. My second question is: Could we get an overloaded Extrude Method that doesn't have to use an Array or a List of faces? I understand why that's optimal for mass operations but when doing one face at a time it's a little clunky - or is it just my bad code? E.g.
    Code (CSharp):
    1. // Add a new uninitialized pb_Object
    2.             var mesh = gameObject.AddComponent<ProBuilderMesh>();
    3.  
    4. foreach (Face item in mesh.faces)
    5.             {
    6.                 int randomHeight = Random.Range(1, 5);
    7.  
    8.                 if (randomHeight == 1)
    9.                 {
    10.                     List<Face> singleFace = new List<Face>(); //Am I doing this wrong - could I just access an individual face?
    11.                     singleFace.Add(item); //Am I doing this wrong - could I just access an individual face?
    12.                     mesh.Extrude(singleFace, ExtrudeMethod.IndividualFaces, Random.Range(1, 5));
    13.                 }
    14.              
    15.             }
    3. I notice when I use Merge ojects of two poly shapes together and then go into sub-object editing the vertex gizmo is missing, the face and edge gizmo is at Vertor3.zero. (This also happens if I just strip the two poly shape scripts off both objects before using Merge Objects - tried that first to see if would work). I found a workaround by using your Strip all Probuilder Scripts on Selection and then ProBuilderizing it back - then it works. Maybe this could be done automatically?

    4. Again, loving Probuilder and it's developing API!
     
    Last edited: Mar 26, 2020
  32. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    Thanks!

    What you could do is apply your transforms as usual, then use the `FreezeTransform` function to bake the transform to the vertices. Or just apply the rotation directly to the vertex positions.

    You could add an extension method to do this if you wanted, ex.

    Code (CSharp):
    1. static class ExtrudeExtension
    2. {
    3.     static Face[] k_ExtrudeFaces = new Face[1];
    4.  
    5.     public static Face[] Extrude(this ProBuilderMesh mesh, Face face, ExtrudeMethod method, float distance)
    6.     {
    7.         k_ExtrudeFaces[0] = face;
    8.         return mesh.Extrude(k_ExtrudeFaces, method, distance);
    9.     }
    10. }
    This sounds like a bug to me, could you please file a bug report in the editor?
     
    batteryyrettab likes this.
  33. hridpath

    hridpath

    Joined:
    Jan 28, 2017
    Posts:
    16
    I am having an issue with using the Extrude method on a mesh that is imported via the importer.
    [Background info]
    I have created models in Blender that only have x and y values and no z values. (bezier curves converted to mesh). I have an UV unwraped and a single material. I am importing these models into Unity 2019.3.7f1. My intent is to generate game objects that are ProBuilderMeshes and allow the user to move and merge these with existing ProBuilderMeshes.
    One of the things I am trying to do is to take this imported mesh and convert it to a ProbuilderMesh and Extrude to a specific length programatically.

    I can get to this point but the extruded mesh does not extrude properly :
    upload_2020-4-18_17-57-31.png upload_2020-4-18_17-57-46.png upload_2020-4-18_17-58-1.png

    I have hundreds of these "profiles" and I do not want to create prefabs for each one. I want to use the ProBuilder API and do these as needed. BTW...this is for edit time.

    I did try to create a 3d object with minimal depth and use that. But It still would not extrude correctly.
    Here is the code snippet I am trying to use:
    upload_2020-4-18_18-5-14.png

    Any help is always appreciated. TIA
     
  34. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    What do you mean by not extruding properly? I don't understand what the intended result is.
     
  35. hridpath

    hridpath

    Joined:
    Jan 28, 2017
    Posts:
    16
    @kaarrrllll If you look at the images, you can see that some faces are black and the end is UV-reversed. It is not a lighiting issue as I can rotate the object and light has no effect on the black area.
     
  36. hridpath

    hridpath

    Joined:
    Jan 28, 2017
    Posts:
    16
    @kaarrrllll Is this the only forum where these questions can be addressed?
     
  37. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    Ok, so I think in this case you'd want to extrude the perimeter edges backwards, not the faces. Once the perimeter edges have been extruded you can take that same perimeter edge list and use the Fill Hole method to create a backing face if necessary.
     
  38. hridpath

    hridpath

    Joined:
    Jan 28, 2017
    Posts:
    16
    Thanks. I will try that.
     
  39. hridpath

    hridpath

    Joined:
    Jan 28, 2017
    Posts:
    16
    @kaarrrllll FillHole is a MenuAction and appears not exposed to the API. Reviewing the FillHole class, most of the functions and propeties used appear to be internal only.

    Am I missing something?
     
  40. hridpath

    hridpath

    Joined:
    Jan 28, 2017
    Posts:
    16

    Attached Files:

  41. hridpath

    hridpath

    Joined:
    Jan 28, 2017
    Posts:
    16
    @kaarrrllll Ref: extrude issue; I found that the ProBuilderMesh Importing process actually doubles the vertex counts. The vetex count for the gameobject I am importing is 30. But after the import the vertex count goes to 68.

    It appears that ProBuilderMesh Probuilderize is not handling a 2d mesh well. The process is creating split verticies to establish Coincedent Vetexes.(assumed).

    Looks like I am needing to convert the 2d profile to a 3d object and not use ProBuilder API for this.
     
  42. Waz

    Waz

    Joined:
    May 1, 2010
    Posts:
    287
    That's how all meshes work in Unity. A vertex on a sharp edge needs to be duplicated, because it has two different normals, depending on which face is using it.
     
  43. Waz

    Waz

    Joined:
    May 1, 2010
    Posts:
    287
    I'm really struggling to get anywhere with the ProBuilder API.

    For example, given a list of Vector3 that define a polygon, how do I create a (triangulated) ProBuilder Face? I've tried:

    Code (CSharp):
    1. List<Vector3> v = ...;
    2. myProBuilder.positions = v;
    3. var newFace = myProBuilder.CreatePolygon(Enumerable.Range(0, v.Count-1).ToArray(), false);
    4.  
    But it fails in shared vertex code which appears to be trying to use unvalidated members.
     
  44. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    That looks correct to me, what is the error you're getting?
     
  45. Waz

    Waz

    Joined:
    May 1, 2010
    Posts:
    287
    Code (csharp):
    1. : The given key was not present in the dictionary.
    2. System.Collections.Generic.Dictionary`2[TKey,TValue].get_Item (TKey key) (at <fb001e01371b4adca20013e0ac763896>:0)
    3. UnityEngine.ProBuilder.ProBuilderMesh.GetSharedVertexHandles (System.Collections.Generic.IEnumerable`1[T] vertices) (at Library/PackageCache/com.unity.probuilder@4.2.3/Runtime/Core/ProBuilderMeshFunction.cs:535)
    4. UnityEngine.ProBuilder.MeshOperations.AppendElements.CreatePolygon (UnityEngine.ProBuilder.ProBuilderMesh mesh, System.Collections.Generic.IList`1[T] indexes, System.Boolean unordered) (at Library/PackageCache/com.unity.probuilder@4.2.3/Runtime/MeshOperations/AppendElements.cs:181)
    5.  
    The ProBuilderMesh has just been Clear()ed too, so nothing prior to the above code.

    Basically, it's trying to find the vertices in the sharedVertexLookup, which is presumably empty.

    Also note that the only reason I'm trying CreatePolygon() is that CreateShapeFromPolygon(), which I can get to work, doesn't return any indication of which faces are the sides and which the extrusion rim.
     
    Last edited: Jul 27, 2020
  46. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    I see. It looks like the problem is that CreatePolygon assumes that the indices passed are already part of the SharedVertex cache, which when you're constructing a new face from scratch will not be the case.

    As a workaround, you could instead use AppendElements.AppendFace, using the Triangulation class as necessary.
     
  47. Waz

    Waz

    Joined:
    May 1, 2010
    Posts:
    287
    That class is private. I think I've come to realize this is a complete waste of time. ProBuilder API is just a pile of half-thought-out internals, half published into a non-cohesive blob of random functionality.

    Tell me how I'm wrong, I'd love to be.

    Edit: it gets worse. I was trying to programmatically Bevel the edges of a face. Finally got it to work by kludges, only to find that Bevel doesn't even work properly in the editor with anything but the most trivially concave edge lists.

    Edit: oh, wow. And CreateShapeFromPolygon() sometimes gets the shape backwards, depending on different values of thickness. Is this tested at all? It's not a preview package.
     
    Last edited: Jul 31, 2020
  48. andybak

    andybak

    Joined:
    Jan 14, 2017
    Posts:
    569
    This is rather the conclusion I reached. It didn't feel like an API where any design and usability thinking had been applied. Things that were possible required some counterintuitive steps and some things just seemed impossible.

    If I was working on ProBuilder I think I would have found the API intolerable for my own use, let alone exposing it as a public API. Being charitable maybe some of the design decisions were made for performance reasons. This is about the only excuse that I would concede as valid for sub-optimal APIs but even so I'm sure some of that could be mitigated with a bit of effort.
     
  49. Rickmc3280

    Rickmc3280

    Joined:
    Jun 28, 2014
    Posts:
    189
    I am trying to create shapes and have found the shape generator. I am able to create any of these shapes and when I modified the Probuilder Mesh to require mesh colliders on build... I was also able to manipulate them.

    However, I cannot place them anywhere, or access the transform. I see the SetPivot, but this seems counter intuitive. Is there a way for me to move the object? Better yet specifically locate it at init (seeing as it is a probuildermesh and not a GameObject) as the same rules do not seem to apply when scripting Transform etc.

    Edited to Add:

    I was able to change the position by getting the transform.position, but using the transform as a whole will not work.
     
    Last edited: Aug 3, 2020
  50. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    You would move the object through the transform. You can think of a ProBuilderMesh as functionally the same as a MeshFilter.