Commit: 6bcda04d1f1cc396dcc188678997105b09231bde Author: Hans Goudey Date: Fri Jul 22 09:59:28 2022 -0500 Branches: master https://developer.blender.org/rB6bcda04d1f1cc396dcc188678997105b09231bde
Geometry Nodes: Port sample curves node to new data-block Use the newer more generic sampling and interpolation functions developed recently (ab444a80a280) instead of the `CurveEval` type. Functions are split up a bit more internally, to allow a separate mode for supplying the curve index directly in the future (T92474). In one basic test, the performance seems mostly unchanged from 3.1. Differential Revision: https://developer.blender.org/D14621 =================================================================== M source/blender/blenlib/BLI_length_parameterize.hh M source/blender/functions/FN_field.hh M source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc =================================================================== diff --git a/source/blender/blenlib/BLI_length_parameterize.hh b/source/blender/blenlib/BLI_length_parameterize.hh index 1b494c021a3..d81bcbe1e7a 100644 --- a/source/blender/blenlib/BLI_length_parameterize.hh +++ b/source/blender/blenlib/BLI_length_parameterize.hh @@ -6,6 +6,7 @@ * \ingroup bli */ +#include "BLI_index_mask.hh" #include "BLI_math_base.hh" #include "BLI_math_color.hh" #include "BLI_math_vector.hh" @@ -41,26 +42,38 @@ void accumulate_lengths(const Span<T> values, const bool cyclic, MutableSpan<flo } template<typename T> -inline void interpolate(const Span<T> src, - const Span<int> indices, - const Span<float> factors, - MutableSpan<T> dst) +inline void interpolate_to_masked(const Span<T> src, + const Span<int> indices, + const Span<float> factors, + const IndexMask dst_mask, + MutableSpan<T> dst) { BLI_assert(indices.size() == factors.size()); - BLI_assert(indices.size() == dst.size()); + BLI_assert(indices.size() == dst_mask.size()); const int last_src_index = src.size() - 1; - for (const int i : dst.index_range()) { - const int prev_index = indices[i]; - const float factor = factors[i]; - const bool is_cyclic_case = prev_index == last_src_index; - if (is_cyclic_case) { - dst[i] = math::interpolate(src.last(), src.first(), factor); + dst_mask.to_best_mask_type([&](auto dst_mask) { + for (const int i : IndexRange(dst_mask.size())) { + const int prev_index = indices[i]; + const float factor = factors[i]; + const bool is_cyclic_case = prev_index == last_src_index; + if (is_cyclic_case) { + dst[dst_mask[i]] = math::interpolate(src.last(), src.first(), factor); + } + else { + dst[dst_mask[i]] = math::interpolate(src[prev_index], src[prev_index + 1], factor); + } } - else { - dst[i] = math::interpolate(src[prev_index], src[prev_index + 1], factor); - } - } + }); +} + +template<typename T> +inline void interpolate(const Span<T> src, + const Span<int> indices, + const Span<float> factors, + MutableSpan<T> dst) +{ + interpolate_to_masked(src, indices, factors, dst.index_range(), dst); } /** diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh index a8136d06c5f..bc42cab8db5 100644 --- a/source/blender/functions/FN_field.hh +++ b/source/blender/functions/FN_field.hh @@ -221,6 +221,17 @@ class FieldOperation : public FieldNode { const MultiFunction &multi_function() const; const CPPType &output_cpp_type(int output_index) const override; + + static std::shared_ptr<FieldOperation> Create(std::shared_ptr<const MultiFunction> function, + Vector<GField> inputs = {}) + { + return std::make_shared<FieldOperation>(FieldOperation(std::move(function), inputs)); + } + static std::shared_ptr<FieldOperation> Create(const MultiFunction &function, + Vector<GField> inputs = {}) + { + return std::make_shared<FieldOperation>(FieldOperation(function, inputs)); + } }; class FieldContext; diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc index 01cf1d8db52..e80b600a740 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc @@ -1,8 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BLI_task.hh" +#include "BLI_devirtualize_parameters.hh" +#include "BLI_length_parameterize.hh" -#include "BKE_spline.hh" +#include "BKE_curves.hh" #include "UI_interface.h" #include "UI_resources.h" @@ -58,34 +59,103 @@ static void node_update(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, length, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); } -template<typename T> static T sample_with_lookup(const Spline::LookupResult lookup, Span<T> data) +static void sample_indices_and_lengths(const Span<float> accumulated_lengths, + const Span<float> sample_lengths, + const IndexMask mask, + MutableSpan<int> r_segment_indices, + MutableSpan<float> r_length_in_segment) { - return attribute_math::mix2( - lookup.factor, data[lookup.evaluated_index], data[lookup.next_evaluated_index]); + const float total_length = accumulated_lengths.last(); + length_parameterize::SampleSegmentHint hint; + + mask.to_best_mask_type([&](const auto mask) { + for (const int64_t i : mask) { + int segment_i; + float factor_in_segment; + length_parameterize::sample_at_length(accumulated_lengths, + std::clamp(sample_lengths[i], 0.0f, total_length), + segment_i, + factor_in_segment, + &hint); + const float segment_start = segment_i == 0 ? 0.0f : accumulated_lengths[segment_i - 1]; + const float segment_end = accumulated_lengths[segment_i]; + const float segment_length = segment_end - segment_start; + + r_segment_indices[i] = segment_i; + r_length_in_segment[i] = factor_in_segment * segment_length; + } + }); +} + +static void sample_indices_and_factors_to_compressed(const Span<float> accumulated_lengths, + const Span<float> sample_lengths, + const IndexMask mask, + MutableSpan<int> r_segment_indices, + MutableSpan<float> r_factor_in_segment) +{ + const float total_length = accumulated_lengths.last(); + length_parameterize::SampleSegmentHint hint; + + mask.to_best_mask_type([&](const auto mask) { + for (const int64_t i : IndexRange(mask.size())) { + const float length = sample_lengths[mask[i]]; + length_parameterize::sample_at_length(accumulated_lengths, + std::clamp(length, 0.0f, total_length), + r_segment_indices[i], + r_factor_in_segment[i], + &hint); + } + }); } +/** + * Given an array of accumulated lengths, find the segment indices that + * sample lengths lie on, and how far along the segment they are. + */ +class SampleFloatSegmentsFunction : public fn::MultiFunction { + private: + Array<float> accumulated_lengths_; + + public: + SampleFloatSegmentsFunction(Array<float> accumulated_lengths) + : accumulated_lengths_(std::move(accumulated_lengths)) + { + static fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static fn::MFSignature create_signature() + { + fn::MFSignatureBuilder signature{"Sample Curve Index"}; + signature.single_input<float>("Length"); + + signature.single_output<int>("Curve Index"); + signature.single_output<float>("Length in Curve"); + return signature.build(); + } + + void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override + { + const VArraySpan<float> lengths = params.readonly_single_input<float>(0, "Length"); + MutableSpan<int> indices = params.uninitialized_single_output<int>(1, "Curve Index"); + MutableSpan<float> lengths_in_segments = params.uninitialized_single_output<float>( + 2, "Length in Curve"); + + sample_indices_and_lengths(accumulated_lengths_, lengths, mask, indices, lengths_in_segments); + } +}; + class SampleCurveFunction : public fn::MultiFunction { private: /** - * The function holds a geometry set instead of a curve or a curve component in order to - * maintain a reference to the geometry while the field tree is being built, so that the - * curve is not freed before the function can execute. + * The function holds a geometry set instead of curves or a curve component reference in order + * to maintain a ownership of the geometry while the field tree is being built and used, so + * that the curve is not freed before the function can execute. */ GeometrySet geometry_set_; - /** - * To support factor inputs, the node adds another field operation before this one to multiply by - * the curve's total length. Since that must calculate the spline lengths anyway, store them to - * reuse the calculation. - */ - Array<float> spline_lengths_; - /** The last member of #spline_lengths_, extracted for convenience. */ - const float total_length_; public: - SampleCurveFunction(GeometrySet geometry_set, Array<float> spline_lengths) - : geometry_set_(std::move(geometry_set)), - spline_lengths_(std::move(spline_lengths)), - total_length_(spline_lengths_.last()) + SampleCurveFunction(GeometrySet geometry_set) : geometry_set_(std::move(geometry_set)) { static fn::MFSignature signature = create_signature(); this->set_signature(&signature); @@ -93,7 +163,8 @@ class SampleCurveFunction : public fn::MultiFunction { static fn::MFSignature create_signature() { - blender::fn::MFSignatureBuilder signature{"Curve Sample"}; + blender::fn::MFSignatureBuilder signature{"Sample Curve"}; + signature.single_input<int>("Curve Index"); signature.single_input<float>("Length"); signature.single_output<float3>("Position"); signature.single_output<float3>("Tangent"); @@ -104,11 +175,11 @@ class SampleCurveFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { MutableSpan<float3> sampled_positions = params.uninitialized_single_output_if_required<float3>( - 1, "Position"); + 2, "Po @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
