[Bf-blender-cvs] [f4f89a76a8f] master: Curves: Port parameter node to the new data-block

Hans Goudey noreply at git.blender.org
Wed Mar 30 03:12:07 CEST 2022


Commit: f4f89a76a8f4ca77bc59c9572cd2aab6da1e9023
Author: Hans Goudey
Date:   Tue Mar 29 20:11:38 2022 -0500
Branches: master
https://developer.blender.org/rBf4f89a76a8f4ca77bc59c9572cd2aab6da1e9023

Curves: Port parameter node to the new data-block

Using the evaluated lengths cache from 72d25fa41d8c575, re-implement
the curve parameter node with the new data structure. Conceptually
it works the same way, but the code is restructured and cleaned up
a bit as well. This also adds support for Catmull Rom curves.

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

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

M	source/blender/blenkernel/BKE_curves.hh
M	source/blender/blenkernel/intern/curves_geometry.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc

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

diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 13b3d280bc7..29cf38421d1 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -273,6 +273,12 @@ class CurvesGeometry : public ::CurvesGeometry {
   /** Makes sure the data described by #evaluated_offsets if necessary. */
   void ensure_evaluated_offsets() const;
 
+  /**
+   * Retrieve offsets into a Bezier curve's avaluated points for each control point.
+   * Call #ensure_evaluated_offsets() first to ensure that the evaluated offsets cache is current.
+   */
+  Span<int> bezier_evaluated_offsets_for_curve(int curve_index) const;
+
   Span<float3> evaluated_positions() const;
 
   /**
@@ -285,6 +291,7 @@ class CurvesGeometry : public ::CurvesGeometry {
    * but is passed for performance reasons to avoid looking up the attribute.
    */
   Span<float> evaluated_lengths_for_curve(int curve_index, bool cyclic) const;
+  float evaluated_length_total_for_curve(int curve_index, bool cyclic) const;
 
   /** Calculates the data described by #evaluated_lengths_for_curve if necessary. */
   void ensure_evaluated_lengths() const;
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index c4e9a06aad0..94402f0e548 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -548,6 +548,12 @@ Span<int> CurvesGeometry::evaluated_offsets() const
   return this->runtime->evaluated_offsets_cache;
 }
 
+Span<int> CurvesGeometry::bezier_evaluated_offsets_for_curve(const int curve_index) const
+{
+  const IndexRange points = this->points_for_curve(curve_index);
+  return this->runtime->bezier_evaluated_offsets.as_span().slice(points);
+}
+
 IndexMask CurvesGeometry::indices_for_curve_type(const CurveType type,
                                                  Vector<int64_t> &r_indices) const
 {
@@ -779,6 +785,12 @@ Span<float> CurvesGeometry::evaluated_lengths_for_curve(const int curve_index,
   return this->runtime->evaluated_length_cache.as_span().slice(range);
 }
 
+float CurvesGeometry::evaluated_length_total_for_curve(const int curve_index,
+                                                       const bool cyclic) const
+{
+  return this->evaluated_lengths_for_curve(curve_index, cyclic).last();
+}
+
 /** \} */
 
 /* -------------------------------------------------------------------- */
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
index 3edaccba506..02aaa86c072 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
@@ -2,7 +2,7 @@
 
 #include "BLI_task.hh"
 
-#include "BKE_spline.hh"
+#include "BKE_curves.hh"
 
 #include "node_geometry_util.hh"
 
@@ -26,168 +26,160 @@ static void node_declare(NodeDeclarationBuilder &b)
 }
 
 /**
- * A basic interpolation from the point domain to the spline domain would be useless, since the
- * average parameter for each spline would just be 0.5, or close to it. Instead, the parameter for
- * each spline is the portion of the total length at the start of the spline.
+ * For lengths on the curve domain, a basic interpolation from the point domain would be useless,
+ * since the average parameter for each curve would just be 0.5, or close to it. Instead, the
+ * value for each curve is defined as the portion of the total length of all curves at its start.
  */
-static Array<float> curve_length_spline_domain(const CurveEval &curve,
-                                               const IndexMask UNUSED(mask))
+static Array<float> accumulated_lengths_curve_domain(const bke::CurvesGeometry &curves)
 {
-  Span<SplinePtr> splines = curve.splines();
+  curves.ensure_evaluated_lengths();
+
+  Array<float> lengths(curves.curves_num());
+  VArray<bool> cyclic = curves.cyclic();
   float length = 0.0f;
-  Array<float> lengths(splines.size());
-  for (const int i : splines.index_range()) {
+  for (const int i : curves.curves_range()) {
     lengths[i] = length;
-    length += splines[i]->length();
-  }
-  return lengths;
-}
-
-/**
- * The parameter at each control point is the factor at the corresponding evaluated point.
- */
-static void calculate_bezier_lengths(const BezierSpline &spline, MutableSpan<float> lengths)
-{
-  Span<int> offsets = spline.control_point_offsets();
-  Span<float> lengths_eval = spline.evaluated_lengths();
-  for (const int i : IndexRange(1, spline.size() - 1)) {
-    lengths[i] = lengths_eval[offsets[i] - 1];
+    length += curves.evaluated_length_total_for_curve(i, cyclic[i]);
   }
-}
 
-/**
- * The parameter for poly splines is simply the evaluated lengths divided by the total length.
- */
-static void calculate_poly_length(const PolySpline &spline, MutableSpan<float> lengths)
-{
-  Span<float> lengths_eval = spline.evaluated_lengths();
-  if (spline.is_cyclic()) {
-    lengths.drop_front(1).copy_from(lengths_eval.drop_back(1));
-  }
-  else {
-    lengths.drop_front(1).copy_from(lengths_eval);
-  }
+  return lengths;
 }
 
 /**
- * Since NURBS control points do not necessarily coincide with the evaluated curve's path, and
- * each control point doesn't correspond well to a specific evaluated point, the parameter at
- * each point is not well defined. So instead, treat the control points as if they were a poly
- * spline.
+ * Return the length of each control point along each curve, starting at zero for the first point.
+ * Importantly, this is different than the length at each evaluated point. The implemenation is
+ * different for every curve type:
+ *  - Catmull Rom Curves: Use the resolution to find the evaluated point for each control point.
+ *  - Poly Curves: Copy the evaluated lengths, but we need to add a zero to the front of the array.
+ *  - Bezier Curves: Use the evaluated offsets to find the evaluated point for each control point.
+ *  - NURBS Curves: Treat the control points as if they were a poly curve, because there
+ *    is no obvious mapping from each control point to a specific evaluated point.
  */
-static void calculate_nurbs_lengths(const NURBSpline &spline, MutableSpan<float> lengths)
-{
-  Span<float3> positions = spline.positions();
-  Array<float> control_point_lengths(spline.size());
-  float length = 0.0f;
-  for (const int i : IndexRange(positions.size() - 1)) {
-    lengths[i] = length;
-    length += math::distance(positions[i], positions[i + 1]);
-  }
-  lengths.last() = length;
-}
-
-static Array<float> curve_length_point_domain(const CurveEval &curve)
+static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves)
 {
-  Span<SplinePtr> splines = curve.splines();
-  Array<int> offsets = curve.control_point_offsets();
-  const int total_size = offsets.last();
-  Array<float> lengths(total_size);
-
-  threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
-    for (const int i : range) {
-      const Spline &spline = *splines[i];
-      MutableSpan spline_factors{lengths.as_mutable_span().slice(offsets[i], spline.size())};
-      spline_factors.first() = 0.0f;
-      switch (splines[i]->type()) {
-        case CURVE_TYPE_BEZIER: {
-          calculate_bezier_lengths(static_cast<const BezierSpline &>(spline), spline_factors);
+  curves.ensure_evaluated_lengths();
+  const VArray<int8_t> types = curves.curve_types();
+  const VArray<int> resolution = curves.resolution();
+  const VArray<bool> cyclic = curves.cyclic();
+
+  Array<float> result(curves.points_num());
+  VArray<int> resolutions = curves.resolution();
+
+  threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) {
+    for (const int i_curve : range) {
+      const IndexRange points = curves.points_for_curve(i_curve);
+      const Span<float> evaluated_lengths = curves.evaluated_lengths_for_curve(i_curve,
+                                                                               cyclic[i_curve]);
+      MutableSpan<float> lengths = result.as_mutable_span().slice(points);
+      lengths.first() = 0.0f;
+      switch (types[i_curve]) {
+        case CURVE_TYPE_CATMULL_ROM: {
+          const int resolution = resolutions[i_curve];
+          for (const int i : IndexRange(points.size()).drop_front(1).drop_back(1)) {
+            lengths[i] = evaluated_lengths[resolution * i - 1];
+          }
           break;
         }
-        case CURVE_TYPE_POLY: {
-          calculate_poly_length(static_cast<const PolySpline &>(spline), spline_factors);
+        case CURVE_TYPE_POLY:
+          lengths.drop_front(1).copy_from(evaluated_lengths.take_front(lengths.size() - 1));
           break;
-        }
-        case CURVE_TYPE_NURBS: {
-          calculate_nurbs_lengths(static_cast<const NURBSpline &>(spline), spline_factors);
+        case CURVE_TYPE_BEZIER: {
+          const Span<int> offsets = curves.bezier_evaluated_offsets_for_curve(i_curve);
+          for (const int i : IndexRange(points.size()).drop_front(1).drop_back(1)) {
+            lengths[i] = evaluated_lengths[offsets[i] - 1];
+          }
           break;
         }
-        case CURVE_TYPE_CATMULL_ROM: {
-          BLI_assert_unreachable();
+        case CURVE_TYPE_NURBS: {
+          const Span<float3> positions = curves.positions().slice(points);
+          float length = 0.0f;
+          for (const int i : positions.index_range().drop_back(1)) {
+            lengths[i] = length;
+            length += math::distance(positions[i], positions[i + 1]);
+          }
+          lengths.last() = length;
           break;
         }
       }
     }
   });
-  return lengths;
+  return result;
 }
 
-static VArray<float> construct_curve_parameter_varray(const CurveEval &curve,
-                                                      const IndexMask mask,
+static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry &curves,
+                                                      const IndexMask UNUSED(mask),
                                                       const AttributeDomain domain)
 {
+  VArray<b

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list