Geometry Nodes: Expose sharp edge status with builtin nodes #112029

Merged
Hans Goudey merged 5 commits from HooglyBoogly/blender:geometry-nodes-face-edge-smooth into main 2023-09-06 17:12:34 +02:00
11 changed files with 116 additions and 22 deletions

View File

@ -360,6 +360,7 @@ class NODE_MT_geometry_node_GEO_MESH_READ(Menu):
node_add_menu.add_node_type(layout, "GeometryNodeToolFaceSet")
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshFaceIsPlanar")
node_add_menu.add_node_type(layout, "GeometryNodeInputShadeSmooth")
node_add_menu.add_node_type(layout, "GeometryNodeInputEdgeSmooth")
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshIsland")
node_add_menu.add_node_type(layout, "GeometryNodeInputShortestEdgePaths")
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshVertexNeighbors")

View File

@ -29,7 +29,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 22
#define BLENDER_FILE_SUBVERSION 23
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@ -1205,7 +1205,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define GEO_NODE_INPUT_RADIUS 1105
#define GEO_NODE_INPUT_CURVE_TILT 1106
#define GEO_NODE_INPUT_CURVE_HANDLES 1107
#define GEO_NODE_INPUT_SHADE_SMOOTH 1108
#define GEO_NODE_INPUT_FACE_SMOOTH 1108
#define GEO_NODE_INPUT_SPLINE_RESOLUTION 1109
#define GEO_NODE_INPUT_SPLINE_CYCLIC 1110
#define GEO_NODE_SET_CURVE_RADIUS 1111
@ -1312,6 +1312,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define GEO_NODE_TOOL_FACE_SET 2112
#define GEO_NODE_TOOL_SET_FACE_SET 2113
#define GEO_NODE_POINTS_TO_CURVES 2114
#define GEO_NODE_INPUT_EDGE_SMOOTH 2115
/** \} */

View File

@ -34,6 +34,7 @@
#include "BLI_string_ref.hh"
#include "BKE_armature.h"
#include "BKE_attribute.h"
#include "BKE_effect.h"
#include "BKE_grease_pencil.hh"
#include "BKE_idprop.hh"
@ -1031,6 +1032,18 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 23)) {
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
if (ntree->type == NTREE_GEOMETRY) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == GEO_NODE_SET_SHADE_SMOOTH) {
HooglyBoogly marked this conversation as resolved Outdated

It's ok to compare with the node type int here. Don't think we will ever change that we have this int. We might just not have to create them manually anymore in the future.

It's ok to compare with the node type int here. Don't think we will ever change that we have this int. We might just not have to create them manually anymore in the future.
node->custom1 = ATTR_DOMAIN_FACE;
}
}
}
}
}
/**
* Versioning code until next subversion bump goes here.
*

View File

@ -223,6 +223,7 @@ DEF_ENUM(rna_enum_attribute_type_items)
DEF_ENUM(rna_enum_color_attribute_type_items)
DEF_ENUM(rna_enum_attribute_type_with_auto_items)
DEF_ENUM(rna_enum_attribute_domain_items)
DEF_ENUM(rna_enum_attribute_domain_edge_face_items)
DEF_ENUM(rna_enum_attribute_domain_only_mesh_items)
DEF_ENUM(rna_enum_attribute_domain_point_face_curve_items)
DEF_ENUM(rna_enum_attribute_curves_domain_items)

View File

@ -106,6 +106,12 @@ const EnumPropertyItem rna_enum_attribute_domain_point_face_curve_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
const EnumPropertyItem rna_enum_attribute_domain_edge_face_items[] = {
{ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", "Attribute on mesh edge"},
{ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"},
{0, nullptr, 0, nullptr, nullptr},
};
const EnumPropertyItem rna_enum_attribute_domain_without_corner_items[] = {
{ATTR_DOMAIN_POINT, "POINT", 0, "Point", "Attribute on point"},
{ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", "Attribute on mesh edge"},

View File

@ -357,7 +357,7 @@ DefNode(GeometryNode, GEO_NODE_INPUT_NORMAL, 0, "INPUT_NORMAL", InputNormal, "No
DefNode(GeometryNode, GEO_NODE_INPUT_POSITION, 0, "POSITION", InputPosition, "Position", "Retrieve a vector indicating the location of each element")
DefNode(GeometryNode, GEO_NODE_INPUT_RADIUS, 0, "INPUT_RADIUS", InputRadius, "Radius", "Retrieve the radius at each point on curve or point cloud geometry")
DefNode(GeometryNode, GEO_NODE_INPUT_SCENE_TIME, 0, "INPUT_SCENE_TIME", InputSceneTime, "Scene Time", "Retrieve the current time in the scene's animation in units of seconds or frames")
DefNode(GeometryNode, GEO_NODE_INPUT_SHADE_SMOOTH, 0, "INPUT_SHADE_SMOOTH", InputShadeSmooth, "Is Shade Smooth", "Retrieve whether each face is marked for smooth shading")
DefNode(GeometryNode, GEO_NODE_INPUT_FACE_SMOOTH, 0, "INPUT_SHADE_SMOOTH", InputShadeSmooth, "Is Face Smooth", "Retrieve whether each face is marked for smooth or sharp normals")
DefNode(GeometryNode, GEO_NODE_INPUT_SHORTEST_EDGE_PATHS, 0, "SHORTEST_EDGE_PATHS", InputShortestEdgePaths, "Shortest Edge Paths", "")
DefNode(GeometryNode, GEO_NODE_INPUT_SIGNED_DISTANCE, 0, "SIGNED_DISTANCE", InputSignedDistance, "Signed Distance", "Retrieve the signed distance field grid called 'distance' from a volume")
DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_CYCLIC, 0, "INPUT_SPLINE_CYCLIC",InputSplineCyclic, "Is Spline Cyclic", "Retrieve whether each spline endpoint connects to the beginning")
@ -461,6 +461,7 @@ DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, 0, "VOLUME_TO_MESH", VolumeToMesh
DefNode(GeometryNode, GEO_NODE_INTERPOLATE_CURVES, 0, "INTERPOLATE_CURVES", InterpolateCurves, "Interpolate Curves", "Generate new curves on points by interpolating between existing curves")
DefNode(GeometryNode, GEO_NODE_POINTS_TO_CURVES, 0, "POINTS_TO_CURVES", PointsToCurves, "Points to Curves", "Split all points to curve by its group ID and reorder by weight")
DefNode(GeometryNode, GEO_NODE_INPUT_EDGE_SMOOTH, 0, "INPUT_EDGE_SMOOTH", InputEdgeSmooth, "Is Edge Smooth", "Retrieve whether each edge is marked for smooth or split normals")
/* undefine macros */
#undef DefNode

View File

@ -102,7 +102,8 @@ set(SRC
nodes/node_geo_input_position.cc
nodes/node_geo_input_radius.cc
nodes/node_geo_input_scene_time.cc
nodes/node_geo_input_shade_smooth.cc
nodes/node_geo_input_edge_smooth.cc
nodes/node_geo_input_face_smooth.cc
nodes/node_geo_input_shortest_edge_paths.cc
nodes/node_geo_input_signed_distance.cc
nodes/node_geo_input_spline_cyclic.cc

View File

@ -4,7 +4,7 @@
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_input_shade_smooth_cc {
namespace blender::nodes::node_geo_input_edge_smooth_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
@ -13,19 +13,19 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
{
Field<bool> shade_smooth_field = AttributeFieldInput::Create<bool>("sharp_face");
params.set_output("Smooth", fn::invert_boolean_field(shade_smooth_field));
Field<bool> sharp = AttributeFieldInput::Create<bool>("sharp_edge");
params.set_output("Smooth", fn::invert_boolean_field(std::move(sharp)));
}
static void node_register()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT);
geo_node_type_base(&ntype, GEO_NODE_INPUT_EDGE_SMOOTH, "Is Edge Smooth", NODE_CLASS_INPUT);
ntype.geometry_node_execute = node_geo_exec;
ntype.declare = node_declare;
nodeRegisterType(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_geo_input_shade_smooth_cc
} // namespace blender::nodes::node_geo_input_edge_smooth_cc

View File

@ -0,0 +1,31 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_input_face_smooth_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Bool>("Smooth").field_source();
}
static void node_geo_exec(GeoNodeExecParams params)
{
Field<bool> sharp = AttributeFieldInput::Create<bool>("sharp_face");
params.set_output("Smooth", fn::invert_boolean_field(std::move(sharp)));
}
static void node_register()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_FACE_SMOOTH, "Is Face Smooth", NODE_CLASS_INPUT);
ntype.geometry_node_execute = node_geo_exec;
ntype.declare = node_declare;
nodeRegisterType(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_geo_input_face_smooth_cc

View File

@ -4,6 +4,13 @@
#include "DNA_mesh_types.h"
#include "UI_interface.hh"
#include "UI_resources.hh"
#include "NOD_rna_define.hh"
#include "RNA_enum_types.hh"
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_set_shade_smooth_cc {
@ -16,12 +23,23 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Geometry").propagate_all();
}
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "domain", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
static void node_init(bNodeTree * /*tree*/, bNode *node)
{
node->custom1 = ATTR_DOMAIN_FACE;
}
/**
* When the `sharp_face` attribute doesn't exist, all faces are considered smooth. If all faces
* are selected and the sharp value is a constant false value, we can remove the attribute instead
* as an optimization to avoid storing it and propagating it in the future.
*/
static bool try_removing_sharp_attribute(Mesh &mesh,
const StringRef name,
const Field<bool> &selection_field,
const Field<bool> &sharp_field)
{
@ -36,48 +54,65 @@ static bool try_removing_sharp_attribute(Mesh &mesh,
if (sharp) {
return false;
}
mesh.attributes_for_write().remove("sharp_face");
mesh.attributes_for_write().remove(name);
return true;
}
static void set_sharp_faces(Mesh &mesh,
const Field<bool> &selection_field,
const Field<bool> &sharp_field)
static void set_sharp(Mesh &mesh,
const eAttrDomain domain,
const StringRef name,
const Field<bool> &selection_field,
const Field<bool> &sharp_field)
{
if (mesh.faces_num == 0) {
const int domain_size = mesh.attributes().domain_size(domain);
if (mesh.attributes().domain_size(domain) == 0) {
return;
}
if (try_removing_sharp_attribute(mesh, selection_field, sharp_field)) {
if (try_removing_sharp_attribute(mesh, name, selection_field, sharp_field)) {
return;
}
MutableAttributeAccessor attributes = mesh.attributes_for_write();
AttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write<bool>("sharp_face",
ATTR_DOMAIN_FACE);
AttributeWriter<bool> sharp = attributes.lookup_or_add_for_write<bool>(name, domain);
const bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
fn::FieldEvaluator evaluator{field_context, mesh.faces_num};
const bke::MeshFieldContext field_context{mesh, domain};
fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(sharp_field, sharp_faces.varray);
evaluator.add_with_destination(sharp_field, sharp.varray);
evaluator.evaluate();
sharp_faces.finish();
sharp.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const eAttrDomain domain = eAttrDomain(params.node().custom1);
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
Field<bool> smooth_field = params.extract_input<Field<bool>>("Shade Smooth");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
set_sharp_faces(*mesh, selection_field, fn::invert_boolean_field(smooth_field));
set_sharp(*mesh,
domain,
domain == ATTR_DOMAIN_FACE ? "sharp_face" : "sharp_edge",
selection_field,
fn::invert_boolean_field(smooth_field));
}
});
params.set_output("Geometry", std::move(geometry_set));
}
static void node_rna(StructRNA *srna)
{
RNA_def_node_enum(srna,
"domain",
"Domain",
"",
rna_enum_attribute_domain_edge_face_items,
NOD_inline_enum_accessors(custom1));
}
static void node_register()
{
static bNodeType ntype;
@ -85,7 +120,11 @@ static void node_register()
geo_node_type_base(&ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = node_geo_exec;
ntype.declare = node_declare;
ntype.initfunc = node_init;
ntype.draw_buttons = node_layout;
nodeRegisterType(&ntype);
node_rna(ntype.rna_ext.srna);
}
NOD_REGISTER_NODE(node_register)