diff options
author | Jacques Lucke <jacques@blender.org> | 2021-08-18 15:53:34 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-08-18 15:53:34 +0300 |
commit | 62d485e470290d0f93c6edd9d87c4e23549c5b8a (patch) | |
tree | 083ddc5926d855d25f0b72372cb10f3b08a1ae95 /source/blender | |
parent | cd6eb6548244e4d741ce04b7adfb8902ebd75507 (diff) |
initial evaluate curve node
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_node.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.cc | 1 | ||||
-rw-r--r-- | source/blender/nodes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/nodes/NOD_geometry.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/NOD_static_types.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_evaluate_curve.cc | 178 |
6 files changed, 183 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 7b3321bf70f..1f7aa4dd26f 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1488,6 +1488,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_POSITION 1083 #define GEO_NODE_SET_POSITION 1084 #define GEO_NODE_SAMPLE_MESH_SURFACE 1085 +#define GEO_NODE_EVALUATE_CURVE 1086 /** \} */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 33b227ae73d..b2d485b5720 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -5161,6 +5161,7 @@ static void registerGeometryNodes() register_node_type_geo_curve_trim(); register_node_type_geo_delete_geometry(); register_node_type_geo_edge_split(); + register_node_type_geo_evaluate_curve(); register_node_type_geo_extrude_and_move(); register_node_type_geo_index(); register_node_type_geo_input_material(); diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 9ac8dff68ab..aff21e9d906 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -188,6 +188,7 @@ set(SRC geometry/nodes/node_geo_curve_trim.cc geometry/nodes/node_geo_delete_geometry.cc geometry/nodes/node_geo_edge_split.cc + geometry/nodes/node_geo_evaluate_curve.cc geometry/nodes/node_geo_extrude.cc geometry/nodes/node_geo_extrude_and_move.cc geometry/nodes/node_geo_index.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index b6390825625..1f648789981 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -75,6 +75,7 @@ void register_node_type_geo_curve_to_points(void); void register_node_type_geo_curve_trim(void); void register_node_type_geo_delete_geometry(void); void register_node_type_geo_edge_split(void); +void register_node_type_geo_evaluate_curve(void); void register_node_type_geo_index(void); void register_node_type_geo_input_material(void); void register_node_type_geo_is_viewport(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index b29cb1389e0..8266e22eb81 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -317,6 +317,7 @@ DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, " DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "") DefNode(GeometryNode, GEO_NODE_CURVE_TRIM, def_geo_curve_trim, "CURVE_TRIM", CurveTrim, "Curve Trim", "") DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "") +DefNode(GeometryNode, GEO_NODE_EVALUATE_CURVE, 0, "EVALUATE_CURVE", EvaluateCurve, "Evaluate Curve", "") DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "") DefNode(GeometryNode, GEO_NODE_INDEX, 0, "INDEX", Index, "Index", "") DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "") diff --git a/source/blender/nodes/geometry/nodes/node_geo_evaluate_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_evaluate_curve.cc new file mode 100644 index 00000000000..b8b79e2e609 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_evaluate_curve.cc @@ -0,0 +1,178 @@ +/* + * 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 "UI_interface.h" +#include "UI_resources.h" + +#include "BKE_attribute_math.hh" +#include "BKE_customdata.h" +#include "BKE_spline.hh" + +#include "node_geometry_util.hh" + +static bNodeSocketTemplate geo_node_evaluate_curve_in[] = { + {SOCK_GEOMETRY, N_("Curve")}, + {SOCK_FLOAT, + N_("Length"), + 0.0f, + 0.0f, + 0.0f, + 0.0f, + -FLT_MAX, + FLT_MAX, + PROP_TRANSLATION, + SOCK_FIELD}, + {SOCK_RGBA, N_("Custom"), 1, 1, 1, 1, 0, 1, PROP_NONE, SOCK_FIELD}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_evaluate_curve_out[] = { + {SOCK_VECTOR, N_("Position")}, + {SOCK_VECTOR, N_("Tangent")}, + {SOCK_VECTOR, N_("Normal")}, + {SOCK_RGBA, N_("Custom")}, + {-1, ""}, +}; + +namespace blender::nodes { + +class EvaluateCurveFunction : public fn::MultiFunction { + private: + GeometrySet geometry_set_; + AnonymousCustomDataLayerID *attribute_id_; + + public: + EvaluateCurveFunction(GeometrySet geometry_set, AnonymousCustomDataLayerID *attribute_id) + : geometry_set_(std::move(geometry_set)), attribute_id_(attribute_id) + { + static fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + CustomData_anonymous_id_strong_increment(attribute_id_); + } + + ~EvaluateCurveFunction() override + { + CustomData_anonymous_id_strong_decrement(attribute_id_); + } + + static fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"Evaluate Curve"}; + signature.single_input<float>("Length"); + signature.single_output<float3>("Position"); + signature.single_output<float3>("Tangent"); + signature.single_output<float3>("Normal"); + signature.single_output<ColorGeometry4f>("Custom"); + return signature.build(); + } + + void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override + { + const VArray<float> &src_lengths = params.readonly_single_input<float>(0, "Length"); + MutableSpan<float3> sampled_positions = params.uninitialized_single_output<float3>(1, + "Position"); + MutableSpan<float3> sampled_tangents = params.uninitialized_single_output<float3>(2, + "Tangent"); + MutableSpan<float3> sampled_normals = params.uninitialized_single_output<float3>(3, "Normal"); + MutableSpan<ColorGeometry4f> sampled_custom = + params.uninitialized_single_output<ColorGeometry4f>(4, "Custom"); + + auto return_default = [&]() { + sampled_positions.fill_indices(mask, {0, 0, 0}); + sampled_tangents.fill_indices(mask, {0, 0, 0}); + sampled_normals.fill_indices(mask, {0, 0, 0}); + sampled_custom.fill_indices(mask, {0, 0, 0, 1}); + }; + + if (!geometry_set_.has_curve()) { + return return_default(); + } + + const CurveComponent *curve_component = geometry_set_.get_component_for_read<CurveComponent>(); + const CurveEval *curve = curve_component->get_for_read(); + if (curve->splines().is_empty()) { + return return_default(); + } + const Spline &spline = *curve->splines()[0]; + std::optional<GSpan> custom_generic = spline.attributes.get_anonymous_for_read(*attribute_id_); + if (!custom_generic) { + return return_default(); + } + + Span<ColorGeometry4f> custom = (*custom_generic).typed<ColorGeometry4f>(); + GVArray_Typed<ColorGeometry4f> evaluated_custom = spline.interpolate_to_evaluated(custom); + + const float spline_length = spline.length(); + const Span<float3> evaluated_positions = spline.evaluated_positions(); + const Span<float3> evaluated_tangents = spline.evaluated_tangents(); + const Span<float3> evaluated_normals = spline.evaluated_normals(); + for (const int i : mask) { + const float length = std::clamp(src_lengths[i], 0.0f, spline_length); + Spline::LookupResult lookup = spline.lookup_evaluated_length(length); + const int i1 = lookup.evaluated_index; + const int i2 = lookup.next_evaluated_index; + sampled_positions[i] = attribute_math::mix2( + lookup.factor, evaluated_positions[i1], evaluated_positions[i2]); + sampled_tangents[i] = attribute_math::mix2( + lookup.factor, evaluated_tangents[i1], evaluated_tangents[i2]) + .normalized(); + sampled_normals[i] = attribute_math::mix2( + lookup.factor, evaluated_normals[i1], evaluated_normals[i2]) + .normalized(); + sampled_custom[i] = attribute_math::mix2( + lookup.factor, evaluated_custom[i1], evaluated_custom[i2]); + } + } +}; + +static void geo_node_evaluate_curve_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); + geometry_set = geometry_set_realize_instances(geometry_set); + + FieldPtr curve_field = params.get_input_field<float>("Length").field(); + bke::FieldRef<ColorGeometry4f> attribute_field = params.get_input_field<ColorGeometry4f>( + "Custom"); + + AnonymousCustomDataLayerID *layer_id = CustomData_anonymous_id_new("Evaluate Curve"); + CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>(); + try_freeze_field_on_geometry( + curve_component, *layer_id, ATTR_DOMAIN_POINT, *attribute_field.field()); + + auto make_output_field = [&](int out_param_index) -> FieldPtr { + auto fn = std::make_unique<EvaluateCurveFunction>(geometry_set, layer_id); + return new bke::MultiFunctionField(Vector<FieldPtr>{curve_field}, + optional_ptr<const fn::MultiFunction>{std::move(fn)}, + out_param_index); + }; + + params.set_output("Position", bke::FieldRef<float3>(make_output_field(1))); + params.set_output("Tangent", bke::FieldRef<float3>(make_output_field(2))); + params.set_output("Normal", bke::FieldRef<float3>(make_output_field(3))); + params.set_output("Custom", bke::FieldRef<ColorGeometry4f>(make_output_field(4))); +} + +} // namespace blender::nodes + +void register_node_type_geo_evaluate_curve() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_EVALUATE_CURVE, "Evaluate Curve", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates(&ntype, geo_node_evaluate_curve_in, geo_node_evaluate_curve_out); + ntype.geometry_node_execute = blender::nodes::geo_node_evaluate_curve_exec; + nodeRegisterType(&ntype); +} |