[Bf-blender-cvs] [eaf416693dc] master: Geometry Nodes: Port the trim curve node to the new data-block

Mattias Fredriksson noreply at git.blender.org
Tue Sep 13 18:36:59 CEST 2022


Commit: eaf416693dcb431ec122fc559788e6c930038c23
Author: Mattias Fredriksson
Date:   Tue Sep 13 11:36:14 2022 -0500
Branches: master
https://developer.blender.org/rBeaf416693dcb431ec122fc559788e6c930038c23

Geometry Nodes: Port the trim curve node to the new data-block

The trim functionality is implemented in the geometry module, and
generalized a bit to be potentially useful for bisecting in the future.
The implementation is based on a helper type called `IndexRangeCyclic`
which allows iteration over all control points between two points on a
curve.

Catmull Rom curves are now supported-- trimmed without resampling first.
However, maintaining the exact shape is not possible. NURBS splines are
still converted to polylines using the evaluated curve concept.

Performance is equivalent or faster then a 3.1 build with regards to
node timings. Compared to 3.3 and 3.2, it's easy to observe test cases
where the node is at least 3 or 4 times faster.

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

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

M	source/blender/blenkernel/BKE_attribute.hh
M	source/blender/blenkernel/BKE_curves.hh
M	source/blender/blenkernel/BKE_curves_utils.hh
M	source/blender/blenkernel/intern/attribute_access.cc
M	source/blender/blenkernel/intern/curve_catmull_rom.cc
A	source/blender/blenlib/BLI_array_utils.hh
M	source/blender/blenlib/CMakeLists.txt
A	source/blender/blenlib/intern/array_utils.cc
M	source/blender/geometry/CMakeLists.txt
A	source/blender/geometry/GEO_trim_curves.hh
A	source/blender/geometry/intern/trim_curves.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc

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

diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh
index 21d91af55d5..fbdacee139c 100644
--- a/source/blender/blenkernel/BKE_attribute.hh
+++ b/source/blender/blenkernel/BKE_attribute.hh
@@ -710,6 +710,19 @@ Vector<AttributeTransferData> retrieve_attributes_for_transfer(
     eAttrDomainMask domain_mask,
     const Set<std::string> &skip = {});
 
+/**
+ * Copy attributes for the domain based on the elementwise mask.
+ *
+ * \param mask_indices: Indexed elements to copy from the source data-block.
+ * \param domain: Attribute domain to transfer.
+ * \param skip: Named attributes to ignore/skip.
+ */
+void copy_attribute_domain(AttributeAccessor src_attributes,
+                           MutableAttributeAccessor dst_attributes,
+                           IndexMask selection,
+                           eAttrDomain domain,
+                           const Set<std::string> &skip = {});
+
 bool allow_procedural_attribute_access(StringRef attribute_name);
 extern const char *no_procedural_access_message;
 
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 4b0fc293b54..9f150c13d6e 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -22,6 +22,7 @@
 #include "BLI_virtual_array.hh"
 
 #include "BKE_attribute.hh"
+#include "BKE_attribute_math.hh"
 
 namespace blender::bke {
 
@@ -161,6 +162,11 @@ class CurvesGeometry : public ::CurvesGeometry {
   IndexRange points_range() const;
   IndexRange curves_range() const;
 
+  /**
+   * Number of control points in the indexed curve.
+   */
+  int points_num_for_curve(const int index) const;
+
   /**
    * The index of the first point in every curve. The size of this span is one larger than the
    * number of curves. Consider using #points_for_curve rather than using the offsets directly.
@@ -531,6 +537,16 @@ bool segment_is_vector(Span<int8_t> handle_types_left,
                        Span<int8_t> handle_types_right,
                        int segment_index);
 
+/**
+ * True if the Bezier curve contains polygonal segments of HandleType::BEZIER_HANDLE_VECTOR.
+ *
+ * \param num_curve_points: Number of points in the curve.
+ * \param evaluated_size: Number of evaluated points in the curve.
+ * \param cyclic: If curve is cyclic.
+ * \param resolution: Curve resolution.
+ */
+bool has_vector_handles(int num_curve_points, int64_t evaluated_size, bool cyclic, int resolution);
+
 /**
  * Return true if the curve's last cyclic segment has a vector type.
  * This only makes a difference in the shape of cyclic curves.
@@ -693,6 +709,36 @@ void interpolate_to_evaluated(const GSpan src,
                               const Span<int> evaluated_offsets,
                               GMutableSpan dst);
 
+void calculate_basis(const float parameter, float r_weights[4]);
+
+/**
+ * Interpolate the control point values for the given parameter on the piecewise segment.
+ * \param a: Value associated with the first control point influencing the segment.
+ * \param d: Value associated with the fourth control point.
+ * \param parameter: Parameter in range [0, 1] to compute the interpolation for.
+ */
+template<typename T>
+T interpolate(const T &a, const T &b, const T &c, const T &d, const float parameter)
+{
+  float n[4];
+  calculate_basis(parameter, n);
+  /* TODO: Use DefaultMixer or other generic mixing in the basis evaluation function to simplify
+   * supporting more types. */
+  if constexpr (!is_same_any_v<T, float, float2, float3, float4, int8_t, int, int64_t>) {
+    T return_value;
+    attribute_math::DefaultMixer<T> mixer({&return_value, 1});
+    mixer.mix_in(0, a, n[0] * 0.5f);
+    mixer.mix_in(0, b, n[1] * 0.5f);
+    mixer.mix_in(0, c, n[2] * 0.5f);
+    mixer.mix_in(0, d, n[3] * 0.5f);
+    mixer.finalize();
+    return return_value;
+  }
+  else {
+    return 0.5f * (a * n[0] + b * n[1] + c * n[2] + d * n[3]);
+  }
+}
+
 }  // namespace catmull_rom
 
 /** \} */
@@ -807,6 +853,16 @@ inline IndexRange CurvesGeometry::curves_range() const
   return IndexRange(this->curves_num());
 }
 
+inline int CurvesGeometry::points_num_for_curve(const int index) const
+{
+  BLI_assert(this->curve_num > 0);
+  BLI_assert(this->curve_num > index);
+  BLI_assert(this->curve_offsets != nullptr);
+  const int offset = this->curve_offsets[index];
+  const int offset_next = this->curve_offsets[index + 1];
+  return offset_next - offset;
+}
+
 inline bool CurvesGeometry::is_single_type(const CurveType type) const
 {
   return this->curve_type_counts()[type] == this->curves_num();
@@ -833,6 +889,7 @@ inline IndexRange CurvesGeometry::points_for_curve(const int index) const
 {
   /* Offsets are not allocated when there are no curves. */
   BLI_assert(this->curve_num > 0);
+  BLI_assert(this->curve_num > index);
   BLI_assert(this->curve_offsets != nullptr);
   const int offset = this->curve_offsets[index];
   const int offset_next = this->curve_offsets[index + 1];
@@ -905,11 +962,13 @@ inline float CurvesGeometry::evaluated_length_total_for_curve(const int curve_in
 
 /** \} */
 
+namespace curves {
+
 /* -------------------------------------------------------------------- */
 /** \name Bezier Inline Methods
  * \{ */
 
-namespace curves::bezier {
+namespace bezier {
 
 inline bool point_is_sharp(const Span<int8_t> handle_types_left,
                            const Span<int8_t> handle_types_right,
@@ -929,14 +988,24 @@ inline bool segment_is_vector(const int8_t left, const int8_t right)
   return segment_is_vector(HandleType(left), HandleType(right));
 }
 
+inline bool has_vector_handles(const int num_curve_points,
+                               const int64_t evaluated_size,
+                               const bool cyclic,
+                               const int resolution)
+{
+  return evaluated_size - !cyclic != (int64_t)segments_num(num_curve_points, cyclic) * resolution;
+}
+
 inline float3 calculate_vector_handle(const float3 &point, const float3 &next_point)
 {
   return math::interpolate(point, next_point, 1.0f / 3.0f);
 }
 
+}  // namespace bezier
+
 /** \} */
 
-}  // namespace curves::bezier
+}  // namespace curves
 
 struct CurvesSurfaceTransforms {
   float4x4 curves_to_world;
diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh
index 0fbd33002e1..5579ab5654a 100644
--- a/source/blender/blenkernel/BKE_curves_utils.hh
+++ b/source/blender/blenkernel/BKE_curves_utils.hh
@@ -11,9 +11,301 @@
 
 #include "BLI_function_ref.hh"
 #include "BLI_generic_pointer.hh"
+#include "BLI_index_range.hh"
 
 namespace blender::bke::curves {
 
+/* --------------------------------------------------------------------
+ * Utility structs.
+ */
+
+/**
+ * Reference to a piecewise segment on a spline curve.
+ */
+struct CurveSegment {
+  /**
+   * Index of the previous control/evaluated point on the curve. First point on the segment.
+   */
+  int index;
+  /**
+   * Index of the next control/evaluated point on the curve. Last point on the curve segment.
+   * Should be 0 for looped segments.
+   */
+  int next_index;
+};
+
+/**
+ * Reference to a point on a piecewise curve (spline).
+ *
+ * Tracks indices of the neighbouring control/evaluated point pair associated with the segment
+ * in which the point resides. Referenced point within the segment is defined by a
+ * normalized parameter in the range [0, 1].
+ */
+struct CurvePoint : public CurveSegment {
+  /**
+   * Normalized parameter in the range [0, 1] defining the point on the piecewise segment.
+   * Note that the curve point representation is not unique at segment endpoints.
+   */
+  float parameter;
+
+  /**
+   * True if the parameter is an integer and references a control/evaluated point.
+   */
+  inline bool is_controlpoint() const;
+
+  /*
+   * Compare if the points are equal.
+   */
+  inline bool operator==(const CurvePoint &other) const;
+  inline bool operator!=(const CurvePoint &other) const;
+
+  /**
+   * Compare if 'this' point comes before 'other'. Loop segment for cyclical curves counts
+   * as the first (least) segment.
+   */
+  inline bool operator<(const CurvePoint &other) const;
+};
+
+/**
+ * Cyclical index range. Iterates the interval [start, end).
+ */
+class IndexRangeCyclic {
+  /* Index to the start and end of the iterated range.
+   */
+  int64_t start_ = 0;
+  int64_t end_ = 0;
+  /* Index for the start and end of the entire iterable range which contains the iterated range
+   * (e.g. the point range for an indiviudal spline/curve within the entire Curves point domain).
+   */
+  int64_t range_start_ = 0;
+  int64_t range_end_ = 0;
+  /* Number of times the range end is passed when the range is iterated.
+   */
+  int64_t cycles_ = 0;
+
+  constexpr IndexRangeCyclic(int64_t begin,
+                             int64_t end,
+                             int64_t iterable_range_start,
+                             int64_t iterable_range_end,
+                             int64_t cycles)
+      : start_(begin),
+        end_(end),
+        range_start_(iterable_range_start),
+        range_end_(iterable_range_end),
+        cycles_(cycles)
+  {
+  }
+
+ public:
+  constexpr IndexRangeCyclic() = default;
+  ~IndexRangeCyclic() = default;
+
+  constexpr IndexRangeCyclic(int64_t start, int64_t end, IndexRange iterable_range, int64_t cycles)
+      : start_(start),
+        end_(end),
+        range_start_(iterable_range.first()),
+        range_end_(iterable_range.one_after_last()),
+        cycles_(cycles)
+  {
+  }
+
+  /**
+   * Create an iterator over the cyclical interval [start_index, end_index).
+   */
+  constexpr IndexRangeCyclic(int64_t start, int64_t end, IndexRange iterable_range)
+      : start_(start),
+        end_(end == iterable_range.one_after_last() ? iterable_range.first() : end),
+        range_start_(iterable_range.first()),
+        range_end_(iterable_range.one_after_last()),
+        cycles_(end < start)
+  {
+  }
+
+  /**
+   * Increment the range by adding the given number of indices to the beginning of the range.
+   */
+  constexpr IndexRangeCyclic push_forward(int n)
+  {
+    BLI_assert(n >= 0);
+    int64_t nstart = sta

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list