Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/geometry/nodes/node_geo_set_curve_normal.cc
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||||
| #include "BKE_curves.hh" | #include "BKE_curves.hh" | ||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "UI_resources.h" | #include "UI_resources.h" | ||||
| #include "node_geometry_util.hh" | #include "node_geometry_util.hh" | ||||
| namespace blender::nodes::node_geo_set_curve_normal_cc { | namespace blender::nodes::node_geo_set_curve_normal_cc { | ||||
| static void node_declare(NodeDeclarationBuilder &b) | static void node_declare(NodeDeclarationBuilder &b) | ||||
| { | { | ||||
| b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); | b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); | ||||
| b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().field_on_all(); | b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().field_on_all(); | ||||
| b.add_input<decl::Float>(N_("Weight")) | |||||
| .default_value(0.8f) | |||||
| .min(0.0f) | |||||
| .max(1.0f) | |||||
| .description( | |||||
| "With a larger weight, the normals are more aligned with the curvature vector, but " | |||||
| "might be less stable when animated. Cross-sections with smaller aspect ratios should " | |||||
| "have larger weights."); | |||||
| b.add_output<decl::Geometry>(N_("Curve")).propagate_all(); | b.add_output<decl::Geometry>(N_("Curve")).propagate_all(); | ||||
| } | } | ||||
| static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) | static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) | ||||
| { | { | ||||
| uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); | uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); | ||||
| } | } | ||||
| static void node_init(bNodeTree * /*tree*/, bNode *node) | static void node_init(bNodeTree * /*tree*/, bNode *node) | ||||
| { | { | ||||
| node->custom1 = NORMAL_MODE_MINIMUM_TWIST; | node->custom1 = NORMAL_MODE_MINIMUM_TWIST; | ||||
| } | } | ||||
| static void set_normal_mode(bke::CurvesGeometry &curves, | static void node_update(bNodeTree *ntree, bNode *node) | ||||
| { | |||||
| bNodeSocket *weight_socket = static_cast<bNodeSocket *>(node->inputs.first)->next->next; | |||||
| nodeSetSocketAvailability(ntree, weight_socket, node->custom1 == NORMAL_MODE_CURVATURE_VECTOR); | |||||
| } | |||||
| static void set_normal_mode_and_weight(bke::CurvesGeometry &curves, | |||||
| const NormalMode mode, | const NormalMode mode, | ||||
| const Field<bool> &selection_field) | const Field<bool> &selection_field, | ||||
| const Field<float> &weight_field) | |||||
| { | { | ||||
| bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_CURVE}; | bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_CURVE}; | ||||
| fn::FieldEvaluator evaluator{field_context, curves.curves_num()}; | fn::FieldEvaluator evaluator{field_context, curves.curves_num()}; | ||||
| evaluator.set_selection(selection_field); | evaluator.set_selection(selection_field); | ||||
| if (mode == NORMAL_MODE_CURVATURE_VECTOR) { | |||||
| evaluator.add_with_destination(weight_field, curves.curvature_vector_weight_for_write()); | |||||
| } | |||||
| evaluator.evaluate(); | evaluator.evaluate(); | ||||
| const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); | const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); | ||||
| curves.normal_mode_for_write().fill_indices(selection, mode); | curves.normal_mode_for_write().fill_indices(selection, mode); | ||||
| curves.tag_normals_changed(); | curves.tag_normals_changed(); | ||||
| } | } | ||||
| static void node_geo_exec(GeoNodeExecParams params) | static void node_geo_exec(GeoNodeExecParams params) | ||||
| { | { | ||||
| const NormalMode mode = static_cast<NormalMode>(params.node().custom1); | const NormalMode mode = static_cast<NormalMode>(params.node().custom1); | ||||
| GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); | GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); | ||||
| Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); | Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); | ||||
| Field<float> weight_field; | |||||
| if (mode == NORMAL_MODE_CURVATURE_VECTOR) { | |||||
| weight_field = params.extract_input<Field<float>>("Weight"); | |||||
| } | |||||
| geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { | geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { | ||||
| if (Curves *curves_id = geometry_set.get_curves_for_write()) { | if (Curves *curves_id = geometry_set.get_curves_for_write()) { | ||||
| bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry); | bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry); | ||||
| set_normal_mode(curves, mode, selection_field); | set_normal_mode_and_weight(curves, mode, selection_field, weight_field); | ||||
| } | } | ||||
| }); | }); | ||||
| params.set_output("Curve", std::move(geometry_set)); | params.set_output("Curve", std::move(geometry_set)); | ||||
| } | } | ||||
| } // namespace blender::nodes::node_geo_set_curve_normal_cc | } // namespace blender::nodes::node_geo_set_curve_normal_cc | ||||
| void register_node_type_geo_set_curve_normal() | void register_node_type_geo_set_curve_normal() | ||||
| { | { | ||||
| namespace file_ns = blender::nodes::node_geo_set_curve_normal_cc; | namespace file_ns = blender::nodes::node_geo_set_curve_normal_cc; | ||||
| static bNodeType ntype; | static bNodeType ntype; | ||||
| geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_NORMAL, "Set Curve Normal", NODE_CLASS_GEOMETRY); | geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_NORMAL, "Set Curve Normal", NODE_CLASS_GEOMETRY); | ||||
| ntype.declare = file_ns::node_declare; | ntype.declare = file_ns::node_declare; | ||||
| ntype.geometry_node_execute = file_ns::node_geo_exec; | ntype.geometry_node_execute = file_ns::node_geo_exec; | ||||
| ntype.initfunc = file_ns::node_init; | ntype.initfunc = file_ns::node_init; | ||||
| ntype.updatefunc = file_ns::node_update; | |||||
| ntype.draw_buttons = file_ns::node_layout; | ntype.draw_buttons = file_ns::node_layout; | ||||
| nodeRegisterType(&ntype); | nodeRegisterType(&ntype); | ||||
| } | } | ||||