[Bf-blender-cvs] [81ec3dce654] master: Geometry Nodes: Add "Connected" mode to Merge by Distance node

Aleksi Juvani noreply at git.blender.org
Thu Apr 7 00:31:13 CEST 2022


Commit: 81ec3dce6542f996e5d61017fab83bd721b61822
Author: Aleksi Juvani
Date:   Wed Apr 6 17:30:56 2022 -0500
Branches: master
https://developer.blender.org/rB81ec3dce6542f996e5d61017fab83bd721b61822

Geometry Nodes: Add "Connected" mode to Merge by Distance node

Expose the "Connected" mode from the weld modifier in the
"Merge by Distance" geometry node. This method only merges
vertices along existing edges, but it can be much faster
because it doesn't have to build a KD Tree of all selected
points.

Differential Revision: https://developer.blender.org/D14321

===================================================================

M	source/blender/blenloader/intern/versioning_300.c
M	source/blender/makesdna/DNA_node_types.h
M	source/blender/makesrna/intern/rna_nodetree.c
M	source/blender/nodes/NOD_static_types.h
M	source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc

===================================================================

diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 5ba7dc74e3d..dd3412d6c83 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -2648,5 +2648,22 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
    */
   {
     /* Keep this block, even when empty. */
+
+    /* Add node storage for the merge by distance node. */
+    FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+      if (ntree->type == NTREE_GEOMETRY) {
+        LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+          if (node->type == GEO_NODE_MERGE_BY_DISTANCE) {
+            if (node->storage == NULL) {
+              NodeGeometryMergeByDistance *data = MEM_callocN(sizeof(NodeGeometryMergeByDistance),
+                                                              __func__);
+              data->mode = GEO_NODE_MERGE_BY_DISTANCE_MODE_ALL;
+              node->storage = data;
+            }
+          }
+        }
+      }
+    }
+    FOREACH_NODETREE_END;
   }
 }
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 73539bea8ee..ff7686d87af 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1296,6 +1296,11 @@ typedef struct NodeGeometryMeshCone {
   uint8_t fill_type;
 } NodeGeometryMeshCone;
 
+typedef struct NodeGeometryMergeByDistance {
+  /* GeometryNodeMergeByDistanceMode. */
+  uint8_t mode;
+} NodeGeometryMergeByDistance;
+
 typedef struct NodeGeometryMeshLine {
   /* GeometryNodeMeshLineMode. */
   uint8_t mode;
@@ -2007,6 +2012,11 @@ typedef enum GeometryNodeMeshCircleFillType {
   GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN = 2,
 } GeometryNodeMeshCircleFillType;
 
+typedef enum GeometryNodeMergeByDistanceMode {
+  GEO_NODE_MERGE_BY_DISTANCE_MODE_ALL = 0,
+  GEO_NODE_MERGE_BY_DISTANCE_MODE_CONNECTED = 1,
+} GeometryNodeMergeByDistanceMode;
+
 typedef enum GeometryNodeMeshLineMode {
   GEO_NODE_MESH_LINE_MODE_END_POINTS = 0,
   GEO_NODE_MESH_LINE_MODE_OFFSET = 1,
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index cbac6aefc10..31b2d36dcfd 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -9846,6 +9846,32 @@ static void def_geo_mesh_cone(StructRNA *srna)
   RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
 }
 
+static void def_geo_merge_by_distance(StructRNA *srna)
+{
+  PropertyRNA *prop;
+
+  static EnumPropertyItem mode_items[] = {
+      {GEO_NODE_MERGE_BY_DISTANCE_MODE_ALL,
+       "ALL",
+       0,
+       "All",
+       "Merge all close selected points, whether or not they are connected"},
+      {GEO_NODE_MERGE_BY_DISTANCE_MODE_CONNECTED,
+       "CONNECTED",
+       0,
+       "Connected",
+       "Only merge mesh vertices along existing edges. This method can be much faster"},
+      {0, NULL, 0, NULL, NULL},
+  };
+
+  RNA_def_struct_sdna_from(srna, "NodeGeometryMergeByDistance", "storage");
+
+  prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+  RNA_def_property_enum_items(prop, mode_items);
+  RNA_def_property_ui_text(prop, "Mode", "");
+  RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
 static void def_geo_mesh_line(StructRNA *srna)
 {
   PropertyRNA *prop;
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 0cc5b2d541d..b45097a4ed1 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -334,7 +334,7 @@ DefNode(GeometryNode, GEO_NODE_INSTANCES_TO_POINTS, 0, "INSTANCES_TO_POINTS", In
 DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "")
 DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")
 DefNode(GeometryNode, GEO_NODE_MATERIAL_SELECTION, 0, "MATERIAL_SELECTION", MaterialSelection, "Material Selection", "")
-DefNode(GeometryNode, GEO_NODE_MERGE_BY_DISTANCE, 0, "MERGE_BY_DISTANCE", MergeByDistance, "Merge by Distance", "")
+DefNode(GeometryNode, GEO_NODE_MERGE_BY_DISTANCE, def_geo_merge_by_distance, "MERGE_BY_DISTANCE", MergeByDistance, "Merge by Distance", "")
 DefNode(GeometryNode, GEO_NODE_MESH_BOOLEAN, def_geo_boolean, "MESH_BOOLEAN", MeshBoolean, "Mesh Boolean", "")
 DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Mesh Circle", "")
 DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "")
diff --git a/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
index 4b9b2064915..1ec97858d4d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
@@ -3,10 +3,15 @@
 #include "GEO_mesh_merge_by_distance.hh"
 #include "GEO_point_merge_by_distance.hh"
 
+#include "UI_interface.h"
+#include "UI_resources.h"
+
 #include "node_geometry_util.hh"
 
 namespace blender::nodes::node_geo_merge_by_distance_cc {
 
+NODE_STORAGE_FUNCS(NodeGeometryMergeByDistance)
+
 static void node_declare(NodeDeclarationBuilder &b)
 {
   b.add_input<decl::Geometry>(N_("Geometry"))
@@ -16,6 +21,20 @@ static void node_declare(NodeDeclarationBuilder &b)
   b.add_output<decl::Geometry>(N_("Geometry"));
 }
 
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+  uiLayoutSetPropSep(layout, true);
+  uiLayoutSetPropDecorate(layout, false);
+  uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+  NodeGeometryMergeByDistance *data = MEM_cnew<NodeGeometryMergeByDistance>(__func__);
+  data->mode = GEO_NODE_MERGE_BY_DISTANCE_MODE_ALL;
+  node->storage = data;
+}
+
 static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_points,
                                                 const float merge_distance,
                                                 const Field<bool> &selection_field)
@@ -34,9 +53,24 @@ static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_p
   return geometry::point_merge_by_distance(src_points, merge_distance, selection);
 }
 
-static std::optional<Mesh *> mesh_merge_by_distance(const MeshComponent &mesh_component,
-                                                    const float merge_distance,
-                                                    const Field<bool> &selection_field)
+static std::optional<Mesh *> mesh_merge_by_distance_connected(const MeshComponent &mesh_component,
+                                                              const float merge_distance,
+                                                              const Field<bool> &selection_field)
+{
+  const int src_size = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+  Array<bool> selection(src_size);
+  GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
+  FieldEvaluator evaluator{context, src_size};
+  evaluator.add_with_destination(selection_field, selection.as_mutable_span());
+  evaluator.evaluate();
+
+  const Mesh &mesh = *mesh_component.get_for_read();
+  return geometry::mesh_merge_by_distance_connected(mesh, selection, merge_distance, false);
+}
+
+static std::optional<Mesh *> mesh_merge_by_distance_all(const MeshComponent &mesh_component,
+                                                        const float merge_distance,
+                                                        const Field<bool> &selection_field)
 {
   const int src_size = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
   GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
@@ -55,6 +89,9 @@ static std::optional<Mesh *> mesh_merge_by_distance(const MeshComponent &mesh_co
 
 static void node_geo_exec(GeoNodeExecParams params)
 {
+  const NodeGeometryMergeByDistance &storage = node_storage(params.node());
+  const GeometryNodeMergeByDistanceMode mode = (GeometryNodeMergeByDistanceMode)storage.mode;
+
   GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
 
   const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
@@ -69,8 +106,18 @@ static void node_geo_exec(GeoNodeExecParams params)
       }
     }
     if (geometry_set.has_mesh()) {
-      std::optional<Mesh *> result = mesh_merge_by_distance(
-          *geometry_set.get_component_for_read<MeshComponent>(), merge_distance, selection);
+      const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
+      std::optional<Mesh *> result;
+      switch (mode) {
+        case GEO_NODE_MERGE_BY_DISTANCE_MODE_ALL:
+          result = mesh_merge_by_distance_all(component, merge_distance, selection);
+          break;
+        case GEO_NODE_MERGE_BY_DISTANCE_MODE_CONNECTED:
+          result = mesh_merge_by_distance_connected(component, merge_distance, selection);
+          break;
+        default:
+          BLI_assert_unreachable();
+      }
       if (result) {
         geometry_set.replace_mesh(*result);
       }
@@ -89,8 +136,13 @@ void register_node_type_geo_merge_by_distance()
   static bNodeType ntype;
 
   geo_node_type_base(&ntype, GEO_NODE_MERGE_BY_DISTANCE, "Merge by Distance", NODE_CLASS_GEOMETRY);
-
+  node_type_init(&ntype, file_ns::node_init);
+  node_type_storage(&ntype,
+                    "NodeGeometryMergeByDistance",
+                    node_free_standard_storage,
+                    node_copy_standard_storage);
   ntype.declare = file_ns::node_declare;
   ntype.geometry_node_execute = file_ns::node_geo_exec;
+  ntype.draw_buttons = file_ns::node_layout;
   nodeRegisterType(&ntype);
 }



More information about the Bf-blender-cvs mailing list