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
This commit is contained in:
Wannes Malfait 2022-09-17 22:18:52 -05:00 committed by Hans Goudey
parent ce54f48556
commit 3ff15a9e23
7 changed files with 95 additions and 0 deletions

View File

@ -128,6 +128,7 @@ def mesh_node_items(context):
yield NodeItem("GeometryNodeInputMeshEdgeVertices")
yield NodeItem("GeometryNodeInputMeshFaceArea")
yield NodeItem("GeometryNodeInputMeshFaceNeighbors")
yield NodeItem("GeometryNodeMeshFaceSetBoundaries")
yield NodeItem("GeometryNodeInputMeshFaceIsPlanar")
yield NodeItem("GeometryNodeInputShadeSmooth")
yield NodeItem("GeometryNodeInputMeshIsland")

View File

@ -1525,6 +1525,7 @@ struct TexResult;
#define GEO_NODE_INPUT_SHORTEST_EDGE_PATHS 1168
#define GEO_NODE_EDGE_PATHS_TO_CURVES 1169
#define GEO_NODE_EDGE_PATHS_TO_SELECTION 1170
#define GEO_NODE_MESH_FACE_SET_BOUNDARIES 1171
/** \} */

View File

@ -4748,6 +4748,7 @@ static void registerGeometryNodes()
register_node_type_geo_material_replace();
register_node_type_geo_material_selection();
register_node_type_geo_merge_by_distance();
register_node_type_geo_mesh_face_set_boundaries();
register_node_type_geo_mesh_primitive_circle();
register_node_type_geo_mesh_primitive_cone();
register_node_type_geo_mesh_primitive_cube();

View File

@ -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);

View File

@ -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")

View File

@ -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

View File

@ -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);
}