Commit: 60a6fbf5b59911cba54d30bd1105626fcc577875
Author: Hans Goudey
Date:   Wed Mar 30 10:37:39 2022 -0500
Branches: master
https://developer.blender.org/rB60a6fbf5b59911cba54d30bd1105626fcc577875

Curves: Port resample node to the new data-block

This commit re-implements the resample curve node to use the new curves
type instead of CurveEval. The largest changes come from the need to
keep track of offsets into the point attribute arrays, and the fact
that the attributes for all curves are stored in a flat array.

Another difference is that a bit more of the logic is handled by
building of the field network inputs. The idea is to let the field
evaluator handle potential optimizations while making the rest of the
code simpler.

When resampling 1 million small poly curves,the node is about 6
times faster compared to 3.1 on my hardware (500ms to 80ms).

This also adds support for Catmull Rom curve inputs.

Differential Revision: https://developer.blender.org/D14435

===================================================================

M       source/blender/blenlib/BLI_generic_span.hh
M       source/blender/nodes/geometry/node_geometry_util.hh
M       source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
M       source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc

===================================================================

diff --git a/source/blender/blenlib/BLI_generic_span.hh 
b/source/blender/blenlib/BLI_generic_span.hh
index f4f93735e06..4c0bfc83ba8 100644
--- a/source/blender/blenlib/BLI_generic_span.hh
+++ b/source/blender/blenlib/BLI_generic_span.hh
@@ -164,6 +164,18 @@ class GMutableSpan {
   {
     return this->slice(range.start(), range.size());
   }
+
+  /**
+   * Copy all values from another span into this span. This invokes undefined 
behavior when the
+   * destination contains uninitialized data and T is not trivially copy 
constructible.
+   * The size of both spans is expected to be the same.
+   */
+  void copy_from(GSpan values)
+  {
+    BLI_assert(type_ == &values.type());
+    BLI_assert(size_ == values.size());
+    type_->copy_assign_n(values.data(), data_, size_);
+  }
 };
 
 }  // namespace blender
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh 
b/source/blender/nodes/geometry/node_geometry_util.hh
index 5b7211e44b4..7af3159bbf8 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -81,4 +81,14 @@ void separate_geometry(GeometrySet &geometry_set,
 std::optional<CustomDataType> 
node_data_type_to_custom_data_type(eNodeSocketDatatype type);
 std::optional<CustomDataType> node_socket_to_custom_data_type(const 
bNodeSocket &socket);
 
+class SplineLengthFieldInput final : public GeometryFieldInput {
+ public:
+  SplineLengthFieldInput();
+  GVArray get_varray_for_context(const GeometryComponent &component,
+                                 AttributeDomain domain,
+                                 IndexMask mask) const final;
+  uint64_t hash() const override;
+  bool is_equal_to(const fn::FieldNode &other) const override;
+};
+
 }  // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc 
b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index 5a4c2ad1660..54fa56f7419 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -1,11 +1,13 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 
 #include "BLI_array.hh"
+#include "BLI_index_mask_ops.hh"
+#include "BLI_length_parameterize.hh"
 #include "BLI_task.hh"
 #include "BLI_timeit.hh"
 
 #include "BKE_attribute_math.hh"
-#include "BKE_spline.hh"
+#include "BKE_curves.hh"
 
 #include "UI_interface.h"
 #include "UI_resources.h"
@@ -23,7 +25,7 @@ static void node_declare(NodeDeclarationBuilder &b)
   
b.add_input<decl::Int>(N_("Count")).default_value(10).min(1).max(100000).supports_field();
   b.add_input<decl::Float>(N_("Length"))
       .default_value(0.1f)
-      .min(0.001f)
+      .min(0.01f)
       .supports_field()
       .subtype(PROP_DISTANCE);
   b.add_output<decl::Geometry>(N_("Curve"));
@@ -54,195 +56,549 @@ static void node_update(bNodeTree *ntree, bNode *node)
   nodeSetSocketAvailability(ntree, length_socket, mode == 
GEO_NODE_CURVE_RESAMPLE_LENGTH);
 }
 
-struct SampleModeParam {
-  GeometryNodeCurveResampleMode mode;
-  std::optional<Field<float>> length;
-  std::optional<Field<int>> count;
-  Field<bool> selection;
+/** Returns the number of evaluated points in each curve. Used to deselect 
curves with none. */
+class EvaluatedCountFieldInput final : public GeometryFieldInput {
+ public:
+  EvaluatedCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), 
"Evaluated Point Count")
+  {
+    category_ = Category::Generated;
+  }
+
+  GVArray get_varray_for_context(const GeometryComponent &component,
+                                 const AttributeDomain domain,
+                                 IndexMask UNUSED(mask)) const final
+  {
+    if (component.type() == GEO_COMPONENT_TYPE_CURVE && domain == 
ATTR_DOMAIN_CURVE &&
+        !component.is_empty()) {
+      const CurveComponent &curve_component = static_cast<const CurveComponent 
&>(component);
+      const Curves &curves_id = *curve_component.get_for_read();
+      const bke::CurvesGeometry &curves = 
bke::CurvesGeometry::wrap(curves_id.geometry);
+      curves.ensure_evaluated_offsets();
+      return VArray<int>::ForFunc(curves.curves_num(), [&](const int64_t 
index) -> int {
+        return curves.evaluated_points_for_curve(index).size();
+      });
+    }
+    return {};
+  }
+
+  uint64_t hash() const override
+  {
+    /* Some random constant hash. */
+    return 234905872379865;
+  }
+
+  bool is_equal_to(const fn::FieldNode &other) const override
+  {
+    return dynamic_cast<const EvaluatedCountFieldInput *>(&other) != nullptr;
+  }
 };
 
-static SplinePtr resample_spline(const Spline &src, const int count)
+/**
+ * Return true if the attribute should be copied/interpolated to the result 
curves.
+ * Don't output attributes that correspond to curve types that have no curves 
in the result.
+ */
+static bool interpolate_attribute_to_curves(const AttributeIDRef &attribute_id,
+                                            const std::array<int, 
CURVE_TYPES_NUM> &type_counts)
 {
-  std::unique_ptr<PolySpline> dst = std::make_unique<PolySpline>();
-  Spline::copy_base_settings(src, *dst);
-
-  if (src.evaluated_edges_size() < 1 || count == 1) {
-    dst->resize(1);
-    dst->positions().first() = src.positions().first();
-    dst->radii().first() = src.radii().first();
-    dst->tilts().first() = src.tilts().first();
-
-    src.attributes.foreach_attribute(
-        [&](const AttributeIDRef &attribute_id, const AttributeMetaData 
&meta_data) {
-          std::optional<GSpan> src_attribute = 
src.attributes.get_for_read(attribute_id);
-          if (dst->attributes.create(attribute_id, meta_data.data_type)) {
-            std::optional<GMutableSpan> dst_attribute = 
dst->attributes.get_for_write(
-                attribute_id);
-            if (dst_attribute) {
-              src_attribute->type().copy_assign(src_attribute->data(), 
dst_attribute->data());
-              return true;
-            }
-          }
-          BLI_assert_unreachable();
-          return false;
-        },
-        ATTR_DOMAIN_POINT);
-    return dst;
+  if (!attribute_id.is_named()) {
+    return true;
   }
+  if (ELEM(attribute_id.name(),
+           "handle_type_left",
+           "handle_type_right",
+           "handle_left",
+           "handle_right")) {
+    return type_counts[CURVE_TYPE_BEZIER] != 0;
+  }
+  if (ELEM(attribute_id.name(), "nurbs_weight")) {
+    return type_counts[CURVE_TYPE_NURBS] != 0;
+  }
+  return true;
+}
 
-  dst->resize(count);
+/**
+ * Return true if the attribute should be copied to poly curves.
+ */
+static bool interpolate_attribute_to_poly_curve(const AttributeIDRef 
&attribute_id)
+{
+  static const Set<StringRef> no_interpolation{{
+      "handle_type_left",
+      "handle_type_right",
+      "handle_position_right",
+      "handle_position_left",
+      "nurbs_weight",
+  }};
+  return !(attribute_id.is_named() && 
no_interpolation.contains(attribute_id.name()));
+}
 
-  Array<float> uniform_samples = src.sample_uniform_index_factors(count);
+/**
+ * Retrieve spans from source and result attributes.
+ */
+static void retrieve_attribute_spans(const Span<AttributeIDRef> ids,
+                                     const CurveComponent &src_component,
+                                     CurveComponent &dst_component,
+                                     Vector<GSpan> &src,
+                                     Vector<GMutableSpan> &dst,
+                                     Vector<OutputAttribute> &dst_attributes)
+{
+  for (const int i : ids.index_range()) {
+    GVArray src_attribute = src_component.attribute_try_get_for_read(ids[i], 
ATTR_DOMAIN_POINT);
+    BLI_assert(src_attribute);
+    src.append(src_attribute.get_internal_span());
+
+    const CustomDataType data_type = 
bke::cpp_type_to_custom_data_type(src_attribute.type());
+    OutputAttribute dst_attribute = 
dst_component.attribute_try_get_for_output_only(
+        ids[i], ATTR_DOMAIN_POINT, data_type);
+    dst.append(dst_attribute.as_span());
+    dst_attributes.append(std::move(dst_attribute));
+  }
+}
 
-  src.sample_with_index_factors<float3>(
-      src.evaluated_positions(), uniform_samples, dst->positions());
+struct AttributesForInterpolation : NonCopyable, NonMovable {
+  Vector<GSpan> src;
+  Vector<GMutableSpan> dst;
 
-  src.sample_with_index_factors<float>(
-      src.interpolate_to_evaluated(src.radii()), uniform_samples, 
dst->radii());
+  Vector<OutputAttribute> dst_attributes;
 
-  src.sample_with_index_factors<float>(
-      src.interpolate_to_evaluated(src.tilts()), uniform_samples, 
dst->tilts());
+  Vector<GSpan> src_no_interpolation;
+  Vector<GMutableSpan> dst_no_interpolation;
+};
 
-  src.attributes.foreach_attribute(
-      [&](const AttributeIDRef &attribute_id, const AttributeMetaData 
&meta_data) {
-        std::optional<GSpan> input_attribute = 
src.attributes.get_for_read(attribute_id);
-        if (dst->attributes.create(attribute_id, meta_data.data_type)) {
-          std::optional<GMutableSpan> output_attribute = 
dst->attributes.get_for_write(
-              attribute_id);
-          if (output_attribute) {
-            
src.sample_with_index_factors(src.interpolate_to_evaluated(*input_attribute),
-                                          uniform_samples,
-                                          *output_attribute);
-            return true;
-          }
+/**
+ * Gather a set of all generic attribute IDs to copy to the result curves.
+ */
+static void gather_point_attributes_to_interpolate(const CurveComponent 
&src_component,
+                                                   CurveComponent 
&dst_component,
+                                                   AttributesForInterpolation 
&result)
+{
+  const Curves &dst_curves_id = *dst_component.get_for_read();
+  const bke::CurvesGeometry &dst_curves = 
bke::CurvesGeometry::wrap(dst_curves_id.geometry);
+  const std::array<int, CURVE_TYPES_NUM> type_counts = 
dst_curves.count_curve_types();
+
+  VectorSet<AttributeIDRef> ids;
+  VectorSet<AttributeIDRef> ids_no_interpolation;
+  src_component.attribute_foreach(
+      [&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+        if (meta_data.domain != ATTR_DOMAIN_POINT) {
+         

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to