godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.07k stars 69 forks source link

Convex Merge/Convex Hull for Mesh libraries/CSG (Like TrenchBroom) #8688

Open Roosader opened 6 months ago

Roosader commented 6 months ago

Describe the project you are working on

A mix of a 3D modeling application and 2D drawing application. Like Doom Builder mixed with a sketchbook. Presently, I am taking a 2D polygon and using the points from that to make a CSGPolygon3D and then extracting the mesh generated from that. I am doing this at runtime

Describe the problem or limitation you are having in your project

I really want to implement a convex merge for 3D shapes, but the only ways to do that are to either use a convex hull library in C# or C++, or write one myself. Both of these options are feasible, but it's something that I feel would be useful to have in the engine as well.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

I would like to have a Convex Merge function added to the CSG shapes. Maybe having this as a property on a CSGCombiner node so all of the children of a CSGCombiner node that has the operation set to "Convex Hull" would be combined into one convex shape. From there, I could then use get_meshes() to grab the mesh that is generated.

Maybe also mesh classes like SurfaceTool and ImmediateMesh could benefit from having this functionality. It could be very helpful for procedural generation.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

I am able to take any array of points and create a ConvexPolygonShape3D from that array and it can automatically remove the points, but the only mesh it can be used for is the line mesh (the shape's debug mesh). That is enough information realistically that I can then take that debug mesh and make a triangulated mesh with surfaces, but it seems like something that should be relatively straightforward to have added to other parts of the engine that deal with meshes rather than having to create something that adds an extra step.

What's already in Godot (in some form):

Taking a set of points (be it either from a single shape or multiple shapes) and keeping only the ones that make up the convex hull of the points. This part is possible with the Mesh class's create_convex_shape() method and setting clean to true so that all points not on the hull are dropped and are used to make a ConvexPolygonShape3D.

The part that isn't possible is the triangulation of those points to create a convex shape with surfaces. There is already the debug shape that is made that is used to represent the ConvexPolygonShape3D , but that only has defined lines rather than surfaces.

I think that this feature could be implemented in the following specific ways:

CSGCombiner - add a new Convex Merge operation in addition to the existing Subtraction, Intersection, and Union operations so that all CSG shapes that are children of this node can be used to create a convex hull

SurfaceTool/ImmediateMesh - take any arbitrary PackedVector3Array (not indexed or triangulated) and create a Convex Hull, retaining only the points that are on the hull and discarding the excess. This resulting Convex Hull can then either be used outright as a mesh, or one could use commit_to_arrays() to get an array of points that could then be used in some other fashion. In SurfaceTool, there is currently an add_triangle_fan() method, so perhaps a create_convex_hull() method would be appropriate?

If this enhancement will not be used often, can it be worked around with a few lines of script?

The only way that I've seen that would be at all feasible presently is either by implementing a Convex Hull and triangulation algorithm by hand, using a C++/C# library, or by taking the debug mesh of a ConvexPolygonShape3D and using the lines to attempt to triangulate faces.

Is there a reason why this should be core and not an add-on in the asset library?

I think that having this, even aside from my personal main use case, would be that level prototyping would be greatly enhanced. There are many shapes that can't really be made without taking a large shape and using subtraction operations to cut into it. With convex merging, you could create a CSGCombiner node, then place a set of any CSG shapes as children, and then set the CSGCombiner node to "Convex Merge" and it would create a composite shape based on the vertices of its children. I just think that this is a much quicker way of building complex shapes than what is currently available, and most of the work is already done in a sense considering the debug mesh that is created from a ConvexPolygonShape3D, but that is an extra layer of abstraction that I think can potentially be skipped and rather implemented as a core feature of CSGShapes.

Thank you for reading!

Calinou commented 6 months ago

The part that isn't possible is the triangulation of those points to create a convex shape with surfaces. There is already the debug shape that is made that is used to represent the ConvexPolygonShape3D , but that only has defined lines rather than surfaces.

Would https://github.com/godotengine/godot/pull/83353 be helpful here?

Roosader commented 6 months ago

The part that isn't possible is the triangulation of those points to create a convex shape with surfaces. There is already the debug shape that is made that is used to represent the ConvexPolygonShape3D , but that only has defined lines rather than surfaces.

Would godotengine/godot#83353 be helpful here?

Hmm... I can definitely give that a try. I should have specified that I didn't THINK it was possible lol. Not that it WASN'T possible. I will see if that aspect will work for me. Does this create faces through the mesh however? From that other issue, it looks like is might go through the center, but I very well could be mistaken! I'm not super keen on having to convert it back and forth between different classes, but the performance impact shouldn't be too terrible I don't think.

As for my proposal, I think at least the CSG convex hull idea could be very helpful. I know you've seen Cyclops (as you've replied to me on Reddit about it a couple times) and have also recommended TrenchBroom and Qodot to people, and I really think that having the ability to convex merge CSG shapes would really speed up complex shape creation and bring the workflow much closer to a dedicated level editing tool like TrenchBroom without much trouble. At least with the way I use TrenchBroom.

Sorry if I kinda have tunnel vision here haha. If this isn't feasible or worth implementing, that's okay! I just figured that most of the parts were seemingly already there, but like, kinda spread out in a sense? So I figured that consolidating it all into a couple of methods or into an operation for CSG could be useful.

Thank you for your response, Calinou!

Roosader commented 6 months ago

@Calinou Another thing that might make this easier is if it would be possible to get the mesh of a Shape3D as an array of faces rather than an array of lines? I wrote (most) of a script that takes the lines and finds each pair of lines attached to that line that themselves share a common point (ab finds ac and bc), but I'm just thinking that it might be easier to have this as an option on the Shape3D get_debug_mesh() method? Maybe something like Shape3D.get_debug_mesh(faces = false) returns lines so the default behavior would be the same?

My script just uses a bunch of nested for loops and is pretty messy and has a lot of duplicate values.