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
This commit is contained in:
parent
181d577d7d
commit
81ec3dce65
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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", "")
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue