Geometry Nodes: Set Spline Type Node Field Update

This update of the Set Spline Type node allows for a bool field to be
used as the selection of the affected splines.

Differential Revision: https://developer.blender.org/D12522
This commit is contained in:
Johnny Matthews 2021-10-01 11:59:29 -05:00
parent eacdc0ab4a
commit 1fb364491b
8 changed files with 325 additions and 12 deletions

View File

@ -525,6 +525,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeCurveFill"),
NodeItem("GeometryNodeCurveTrim"),
NodeItem("GeometryNodeCurveLength"),
NodeItem("GeometryNodeCurveSplineType"),
NodeItem("GeometryNodeSplineLength"),
NodeItem("GeometryNodeCurveSubdivide"),
NodeItem("GeometryNodeCurveParameter"),

View File

@ -1510,7 +1510,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_PROXIMITY 1096
#define GEO_NODE_CURVE_SUBDIVIDE 1097
#define GEO_NODE_INPUT_SPLINE_LENGTH 1098
#define GEO_NODE_CURVE_SPLINE_TYPE 1099
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -5713,6 +5713,7 @@ static void registerGeometryNodes()
register_node_type_geo_legacy_attribute_randomize();
register_node_type_geo_legacy_material_assign();
register_node_type_geo_legacy_select_by_material();
register_node_type_geo_legacy_curve_spline_type();
register_node_type_geo_legacy_curve_reverse();
register_node_type_geo_legacy_curve_subdivide();

View File

@ -209,6 +209,7 @@ set(SRC
geometry/nodes/node_geo_curve_resample.cc
geometry/nodes/node_geo_curve_reverse.cc
geometry/nodes/node_geo_curve_sample.cc
geometry/nodes/node_geo_curve_spline_type.cc
geometry/nodes/node_geo_curve_subdivide.cc
geometry/nodes/node_geo_curve_to_mesh.cc
geometry/nodes/node_geo_curve_trim.cc

View File

@ -33,6 +33,7 @@ void register_node_type_geo_legacy_attribute_proximity(void);
void register_node_type_geo_legacy_attribute_randomize(void);
void register_node_type_geo_legacy_material_assign(void);
void register_node_type_geo_legacy_select_by_material(void);
void register_node_type_geo_legacy_curve_spline_type(void);
void register_node_type_geo_legacy_curve_reverse(void);
void register_node_type_geo_legacy_curve_subdivide(void);

View File

@ -335,6 +335,7 @@ DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, def_geo_curve_prim
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "")
DefNode(GeometryNode, GEO_NODE_CURVE_RESAMPLE, def_geo_curve_resample, "CURVE_RESAMPLE", CurveResample, "Resample Curve", "")
DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_TYPE, def_geo_curve_spline_type, "CURVE_SPLINE_TYPE", CurveSplineType, "Set Spline Type", "")
DefNode(GeometryNode, GEO_NODE_CURVE_REVERSE, 0, "CURVE_REVERSE", CurveReverse, "Curve Reverse", "")
DefNode(GeometryNode, GEO_NODE_CURVE_SAMPLE, def_geo_curve_sample, "CURVE_SAMPLE", CurveSample, "Curve Sample", "")
DefNode(GeometryNode, GEO_NODE_CURVE_SUBDIVIDE, 0, "CURVE_SUBDIVIDE", CurveSubdivide, "Curve Subdivide", "")

View File

@ -25,21 +25,21 @@
namespace blender::nodes {
static void geo_node_curve_spline_type_declare(NodeDeclarationBuilder &b)
static void geo_node_legacy_curve_spline_type_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
b.add_input<decl::String>("Selection");
b.add_output<decl::Geometry>("Curve");
}
static void geo_node_curve_spline_type_layout(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
static void geo_node_legacy_curve_spline_type_layout(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE);
}
static void geo_node_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node)
static void geo_node_legacy_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
sizeof(NodeGeometryCurveSplineType), __func__);
@ -238,7 +238,7 @@ static SplinePtr convert_to_nurbs(const Spline &input)
return {};
}
static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSplineType *storage =
(const NodeGeometryCurveSplineType *)params.node().storage;
@ -284,19 +284,19 @@ static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
} // namespace blender::nodes
void register_node_type_geo_curve_spline_type()
void register_node_type_geo_legacy_curve_spline_type()
{
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0);
ntype.declare = blender::nodes::geo_node_curve_spline_type_declare;
ntype.geometry_node_execute = blender::nodes::geo_node_curve_spline_type_exec;
node_type_init(&ntype, blender::nodes::geo_node_curve_spline_type_init);
ntype.declare = blender::nodes::geo_node_legacy_curve_spline_type_declare;
ntype.geometry_node_execute = blender::nodes::geo_node_legacy_curve_spline_type_exec;
node_type_init(&ntype, blender::nodes::geo_node_legacy_curve_spline_type_init);
node_type_storage(&ntype,
"NodeGeometryCurveSplineType",
node_free_standard_storage,
node_copy_standard_storage);
ntype.draw_buttons = blender::nodes::geo_node_curve_spline_type_layout;
ntype.draw_buttons = blender::nodes::geo_node_legacy_curve_spline_type_layout;
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,308 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BKE_spline.hh"
#include "BLI_task.hh"
#include "UI_interface.h"
#include "UI_resources.h"
#include "node_geometry_util.hh"
namespace blender::nodes {
static void geo_node_curve_spline_type_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>("Curve");
}
static void geo_node_curve_spline_type_layout(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE);
}
static void geo_node_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
sizeof(NodeGeometryCurveSplineType), __func__);
data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
node->storage = data;
}
template<class T>
static void scale_input_assign(const Span<T> input,
const int scale,
const int offset,
const MutableSpan<T> r_output)
{
for (const int i : IndexRange(r_output.size())) {
r_output[i] = input[i * scale + offset];
}
}
template<class T>
static void scale_output_assign(const Span<T> input,
const int scale,
const int offset,
const MutableSpan<T> &r_output)
{
for (const int i : IndexRange(input.size())) {
r_output[i * scale + offset] = input[i];
}
}
template<typename CopyFn>
static void copy_attributes(const Spline &input_spline, Spline &output_spline, CopyFn copy_fn)
{
input_spline.attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
std::optional<GSpan> src = input_spline.attributes.get_for_read(attribute_id);
BLI_assert(src);
if (!output_spline.attributes.create(attribute_id, meta_data.data_type)) {
BLI_assert_unreachable();
return false;
}
std::optional<GMutableSpan> dst = output_spline.attributes.get_for_write(attribute_id);
if (!dst) {
BLI_assert_unreachable();
return false;
}
copy_fn(*src, *dst);
return true;
},
ATTR_DOMAIN_POINT);
}
static SplinePtr convert_to_poly_spline(const Spline &input)
{
std::unique_ptr<PolySpline> output = std::make_unique<PolySpline>();
output->resize(input.positions().size());
output->positions().copy_from(input.positions());
output->radii().copy_from(input.radii());
output->tilts().copy_from(input.tilts());
Spline::copy_base_settings(input, *output);
output->attributes = input.attributes;
return output;
}
static SplinePtr poly_to_nurbs(const Spline &input)
{
std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
output->resize(input.positions().size());
output->positions().copy_from(input.positions());
output->radii().copy_from(input.radii());
output->tilts().copy_from(input.tilts());
output->weights().fill(1.0f);
output->set_resolution(12);
output->set_order(4);
Spline::copy_base_settings(input, *output);
output->knots_mode = NURBSpline::KnotsMode::Bezier;
output->attributes = input.attributes;
return output;
}
static SplinePtr bezier_to_nurbs(const Spline &input)
{
const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(input);
std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
output->resize(input.size() * 3);
scale_output_assign(bezier_spline.handle_positions_left(), 3, 0, output->positions());
scale_output_assign(input.radii(), 3, 0, output->radii());
scale_output_assign(input.tilts(), 3, 0, output->tilts());
scale_output_assign(bezier_spline.positions(), 3, 1, output->positions());
scale_output_assign(input.radii(), 3, 1, output->radii());
scale_output_assign(input.tilts(), 3, 1, output->tilts());
scale_output_assign(bezier_spline.handle_positions_right(), 3, 2, output->positions());
scale_output_assign(input.radii(), 3, 2, output->radii());
scale_output_assign(input.tilts(), 3, 2, output->tilts());
Spline::copy_base_settings(input, *output);
output->weights().fill(1.0f);
output->set_resolution(12);
output->set_order(4);
output->set_cyclic(input.is_cyclic());
output->knots_mode = NURBSpline::KnotsMode::Bezier;
output->attributes.reallocate(output->size());
copy_attributes(input, *output, [](GSpan src, GMutableSpan dst) {
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
scale_output_assign<T>(src.typed<T>(), 3, 0, dst.typed<T>());
scale_output_assign<T>(src.typed<T>(), 3, 1, dst.typed<T>());
scale_output_assign<T>(src.typed<T>(), 3, 2, dst.typed<T>());
});
});
return output;
}
static SplinePtr poly_to_bezier(const Spline &input)
{
std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
output->resize(input.size());
output->positions().copy_from(input.positions());
output->radii().copy_from(input.radii());
output->tilts().copy_from(input.tilts());
output->handle_types_left().fill(BezierSpline::HandleType::Vector);
output->handle_types_right().fill(BezierSpline::HandleType::Vector);
output->set_resolution(12);
Spline::copy_base_settings(input, *output);
output->attributes = input.attributes;
return output;
}
static SplinePtr nurbs_to_bezier(const Spline &input)
{
const NURBSpline &nurbs_spline = static_cast<const NURBSpline &>(input);
std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
output->resize(input.size() / 3);
scale_input_assign<float3>(input.positions(), 3, 1, output->positions());
scale_input_assign<float3>(input.positions(), 3, 0, output->handle_positions_left());
scale_input_assign<float3>(input.positions(), 3, 2, output->handle_positions_right());
scale_input_assign<float>(input.radii(), 3, 2, output->radii());
scale_input_assign<float>(input.tilts(), 3, 2, output->tilts());
output->handle_types_left().fill(BezierSpline::HandleType::Align);
output->handle_types_right().fill(BezierSpline::HandleType::Align);
output->set_resolution(nurbs_spline.resolution());
Spline::copy_base_settings(input, *output);
output->attributes.reallocate(output->size());
copy_attributes(input, *output, [](GSpan src, GMutableSpan dst) {
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
scale_input_assign<T>(src.typed<T>(), 3, 1, dst.typed<T>());
});
});
return output;
}
static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params)
{
switch (input.type()) {
case Spline::Type::Bezier:
return input.copy();
case Spline::Type::Poly:
return poly_to_bezier(input);
case Spline::Type::NURBS:
if (input.size() < 6) {
params.error_message_add(
NodeWarningType::Info,
TIP_("NURBS must have minimum of 6 points for Bezier Conversion"));
return input.copy();
}
else {
if (input.size() % 3 != 0) {
params.error_message_add(NodeWarningType::Info,
TIP_("NURBS must have multiples of 3 points for full Bezier "
"conversion, curve truncated"));
}
return nurbs_to_bezier(input);
}
}
BLI_assert_unreachable();
return {};
}
static SplinePtr convert_to_nurbs(const Spline &input)
{
switch (input.type()) {
case Spline::Type::NURBS:
return input.copy();
case Spline::Type::Bezier:
return bezier_to_nurbs(input);
case Spline::Type::Poly:
return poly_to_nurbs(input);
}
BLI_assert_unreachable();
return {};
}
static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSplineType *storage =
(const NodeGeometryCurveSplineType *)params.node().storage;
const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage->spline_type;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
if (!geometry_set.has_curve()) {
return;
}
const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
const CurveEval &curve = *curve_component->get_for_read();
GeometryComponentFieldContext field_context{*curve_component, ATTR_DOMAIN_CURVE};
const int domain_size = curve_component->attribute_domain_size(ATTR_DOMAIN_CURVE);
fn::FieldEvaluator selection_evaluator{field_context, domain_size};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
for (const int i : curve.splines().index_range()) {
if (selection[i]) {
switch (output_type) {
case GEO_NODE_SPLINE_TYPE_POLY:
new_curve->add_spline(convert_to_poly_spline(*curve.splines()[i]));
break;
case GEO_NODE_SPLINE_TYPE_BEZIER:
new_curve->add_spline(convert_to_bezier(*curve.splines()[i], params));
break;
case GEO_NODE_SPLINE_TYPE_NURBS:
new_curve->add_spline(convert_to_nurbs(*curve.splines()[i]));
break;
}
}
else {
new_curve->add_spline(curve.splines()[i]->copy());
}
}
new_curve->attributes = curve.attributes;
geometry_set.replace_curve(new_curve.release());
});
params.set_output("Curve", std::move(geometry_set));
}
} // namespace blender::nodes
void register_node_type_geo_curve_spline_type()
{
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0);
ntype.declare = blender::nodes::geo_node_curve_spline_type_declare;
ntype.geometry_node_execute = blender::nodes::geo_node_curve_spline_type_exec;
node_type_init(&ntype, blender::nodes::geo_node_curve_spline_type_init);
node_type_storage(&ntype,
"NodeGeometryCurveSplineType",
node_free_standard_storage,
node_copy_standard_storage);
ntype.draw_buttons = blender::nodes::geo_node_curve_spline_type_layout;
nodeRegisterType(&ntype);
}