diff options
author | Wannes Malfait <Wannes> | 2022-09-18 06:18:52 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-09-18 06:18:52 +0300 |
commit | 3ff15a9e23bd8a20ee514944779a898f1fe5accb (patch) | |
tree | e6ce2986d9e282db1df2d51b6706b3cb56acd4f4 /source/blender/nodes | |
parent | ce54f4855674059ef9124a27bff0741f97c75eec (diff) |
Geometry Nodes: New Face Set Boundaries node
With the recent addition of the UV unwrapping node, there is a need to
be able to create seams easily. This node does that by outputting a
selection of the boundaries between different input face sets. In the
context of UV mapping, one inputs the "patches" you want, and the node
gives you the seams needed to make those patches.
Differential Revision: https://developer.blender.org/D15423
Diffstat (limited to 'source/blender/nodes')
-rw-r--r-- | source/blender/nodes/NOD_geometry.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/NOD_static_types.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/geometry/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc | 89 |
4 files changed, 92 insertions, 0 deletions
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index e16cd7a253f..63af2c71d45 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -95,6 +95,7 @@ void register_node_type_geo_join_geometry(void); void register_node_type_geo_material_replace(void); void register_node_type_geo_material_selection(void); void register_node_type_geo_merge_by_distance(void); +void register_node_type_geo_mesh_face_set_boundaries(void); void register_node_type_geo_mesh_primitive_circle(void); void register_node_type_geo_mesh_primitive_cone(void); void register_node_type_geo_mesh_primitive_cube(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index d587da823f1..73fb2bf32c8 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -352,6 +352,7 @@ DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, DefNode(GeometryNode, GEO_NODE_MATERIAL_SELECTION, 0, "MATERIAL_SELECTION", MaterialSelection, "Material Selection", "Provide a selection of faces that use the specified material") DefNode(GeometryNode, GEO_NODE_MERGE_BY_DISTANCE, def_geo_merge_by_distance,"MERGE_BY_DISTANCE", MergeByDistance, "Merge by Distance", "Merge vertices or points within a given distance") DefNode(GeometryNode, GEO_NODE_MESH_BOOLEAN, def_geo_boolean, "MESH_BOOLEAN", MeshBoolean, "Mesh Boolean", "Cut, subtract, or join multiple mesh inputs") +DefNode(GeometryNode, GEO_NODE_MESH_FACE_SET_BOUNDARIES, 0, "MESH_FACE_SET_BOUNDARIES", MeshFaceSetBoundaries, "Face Set Boundaries", "Find edges on the boundaries between face sets") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Mesh Circle", "Generate a circular ring of edges") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE",MeshCone, "Cone", "Generate a cone mesh") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CUBE, 0, "MESH_PRIMITIVE_CUBE",MeshCube, "Cube", "Generate a cuboid mesh with variable side lengths and subdivisions") diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index 31c00cc6b82..cc3d00ea21f 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -105,6 +105,7 @@ set(SRC nodes/node_geo_material_replace.cc nodes/node_geo_material_selection.cc nodes/node_geo_merge_by_distance.cc + nodes/node_geo_mesh_face_set_boundaries.cc nodes/node_geo_mesh_primitive_circle.cc nodes/node_geo_mesh_primitive_cone.cc nodes/node_geo_mesh_primitive_cube.cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc new file mode 100644 index 00000000000..88cccfb2f94 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_mesh.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_mesh_face_set_boundaries_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Face Set")) + .default_value(0) + .hide_value() + .supports_field() + .description(N_("An identifier for the group of each face. All contiguous faces with the " + "same value are in the same region")); + b.add_output<decl::Bool>(N_("Boundary Edges")) + .field_source() + .description(N_("The edges that lie on the boundaries between the different face sets")); +} + +class BoundaryFieldInput final : public bke::MeshFieldInput { + private: + const Field<int> face_set; + + public: + BoundaryFieldInput(const Field<int> face_set) + : bke::MeshFieldInput(CPPType::get<bool>(), "Boundary Field"), face_set(face_set) + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + const bke::MeshFieldContext face_context{mesh, ATTR_DOMAIN_FACE}; + FieldEvaluator face_evaluator{face_context, mesh.totpoly}; + face_evaluator.add(face_set); + face_evaluator.evaluate(); + const VArray<int> face_set = face_evaluator.get_evaluated<int>(0); + + Array<bool> boundary(mesh.totedge, false); + Array<bool> edge_visited(mesh.totedge, false); + Array<int> edge_face_set(mesh.totedge, 0); + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); + for (const int i : polys.index_range()) { + const MPoly &poly = polys[i]; + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + const int edge = loop.e; + if (edge_visited[edge]) { + if (edge_face_set[edge] != face_set[i]) { + /* This edge is connected to two faces on different face sets. */ + boundary[edge] = true; + } + } + edge_visited[edge] = true; + edge_face_set[edge] = face_set[i]; + } + } + return mesh.attributes().adapt_domain<bool>( + VArray<bool>::ForContainer(std::move(boundary)), ATTR_DOMAIN_EDGE, domain); + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + const Field<int> face_set_field = params.extract_input<Field<int>>("Face Set"); + Field<bool> face_set_boundaries{std::make_shared<BoundaryFieldInput>(face_set_field)}; + params.set_output("Boundary Edges", std::move(face_set_boundaries)); +} + +} // namespace blender::nodes::node_geo_mesh_face_set_boundaries_cc + +void register_node_type_geo_mesh_face_set_boundaries() +{ + namespace file_ns = blender::nodes::node_geo_mesh_face_set_boundaries_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_MESH_FACE_SET_BOUNDARIES, "Face Set Boundaries", NODE_CLASS_INPUT); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + nodeRegisterType(&ntype); +} |