diff options
-rw-r--r-- | source/blender/blenloader/intern/versioning_300.c | 17 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 10 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree.c | 26 | ||||
-rw-r--r-- | source/blender/nodes/NOD_static_types.h | 2 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc | 64 |
5 files changed, 112 insertions, 7 deletions
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); } |