[Bf-blender-cvs] [6bcda04d1f1] master: Geometry Nodes: Port sample curves node to new data-block

Hans Goudey noreply at git.blender.org
Fri Jul 22 17:04:52 CEST 2022


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. @@



More information about the Bf-blender-cvs mailing list