Geometry Nodes: Add "Set Curve Order" node

Adds a dedicated node to set the order of NURBS curves.
Design at #154612

Pull Request: https://projects.blender.org/blender/blender/pulls/154648
This commit is contained in:
Romain Guimbal 2026-02-23 18:01:16 +01:00 • committed by Hans Goudey
parent 5b3393c252
commit 52062edb6f
4 changed files with 113 additions and 0 deletions

View file

@ -97,6 +97,7 @@ class NODE_MT_gn_curve_write_base(node_add_menu.NodeMenu):
def draw(self, _context):
layout = self.layout
self.node_operator(layout, "GeometryNodeSetCurveNormal")
self.node_operator(layout, "GeometryNodeSetCurveOrder")
self.node_operator(layout, "GeometryNodeSetCurveRadius")
self.node_operator(layout, "GeometryNodeSetCurveTilt")
self.node_operator(layout, "GeometryNodeSetCurveHandlePositions")

View file

@ -10385,6 +10385,7 @@ static void rna_def_nodes(BlenderRNA *brna)
define("GeometryNode", "GeometryNodeSeparateGeometry");
define("GeometryNode", "GeometryNodeSetCurveHandlePositions");
define("GeometryNode", "GeometryNodeSetCurveNormal");
define("GeometryNode", "GeometryNodeSetCurveOrder");
define("GeometryNode", "GeometryNodeSetCurveRadius");
define("GeometryNode", "GeometryNodeSetCurveTilt");
define("GeometryNode", "GeometryNodeSetGeometryBundle");

View file

@ -233,6 +233,7 @@ set(SRC
nodes/node_geo_separate_geometry.cc
nodes/node_geo_set_curve_handles.cc
nodes/node_geo_set_curve_normal.cc
nodes/node_geo_set_curve_order.cc
nodes/node_geo_set_curve_radius.cc
nodes/node_geo_set_curve_tilt.cc
nodes/node_geo_set_geometry_bundle.cc

View file

@ -0,0 +1,110 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_curves.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_type_conversions.hh"
#include "FN_multi_function_builder.hh"
#include "GEO_foreach_geometry.hh"
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_set_curve_order_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.use_custom_socket_order();
b.allow_any_socket_order();
b.add_input<decl::Geometry>("Curves")
.supported_type({GeometryComponent::Type::Curve, GeometryComponent::Type::GreasePencil})
.description("Curves to change the order of");
b.add_output<decl::Geometry>("Curves").propagate_all().align_with_previous();
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().field_on_all();
b.add_input<decl::Int>("Order").default_value(4).min(2).max(127).field_on_all();
}
static void set_grease_pencil_order(GreasePencil &grease_pencil,
const Field<bool> &selection,
const Field<int8_t> &order,
std::atomic<bool> &has_nurbs)
{
using namespace blender::bke::greasepencil;
for (const int layer_index : grease_pencil.layers().index_range()) {
Drawing *drawing = grease_pencil.get_eval_drawing(grease_pencil.layer(layer_index));
if (drawing == nullptr) {
continue;
}
bke::CurvesGeometry &curves = drawing->strokes_for_write();
if (curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
bke::try_capture_field_on_geometry(
curves.attributes_for_write(),
bke::GreasePencilLayerFieldContext(grease_pencil, AttrDomain::Curve, layer_index),
"nurbs_order",
bke::AttrDomain::Curve,
selection,
order);
has_nurbs = true;
}
else {
continue;
}
}
}
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curves");
const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
const Field<int> order = params.extract_input<Field<int>>("Order");
const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
const Field<int8_t> order_int8 = conversions.try_convert(order, CPPType::get<int8_t>());
std::atomic<bool> has_nurbs = false;
geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
if (curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
const bke::CurvesFieldContext field_context{*curves_id, AttrDomain::Curve};
bke::try_capture_field_on_geometry(curves.attributes_for_write(),
field_context,
"nurbs_order",
bke::AttrDomain::Curve,
selection,
order_int8);
has_nurbs = true;
}
}
if (GreasePencil *grease_pencil = geometry_set.get_grease_pencil_for_write()) {
set_grease_pencil_order(*grease_pencil, selection, order_int8, has_nurbs);
}
});
if (!has_nurbs) {
params.error_message_add(NodeWarningType::Info, TIP_("Input curves do not have NURBS type"));
}
params.set_output("Curves", std::move(geometry_set));
}
static void node_register()
{
static bke::bNodeType ntype;
geo_node_type_base(&ntype, "GeometryNodeSetCurveOrder");
ntype.ui_name = "Set Curve Order";
ntype.ui_description =
"Control how many control points influence each evaluated point by changing the "
"\"nurbs_order\" attribute";
ntype.nclass = NODE_CLASS_GEOMETRY;
ntype.geometry_node_execute = node_geo_exec;
ntype.declare = node_declare;
bke::node_register_type(ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_geo_set_curve_order_cc