[Bf-blender-cvs] [901a03725ed] master: Curves: Port mesh to curve node to new data-block

Hans Goudey noreply at git.blender.org
Tue Mar 8 02:06:57 CET 2022


Commit: 901a03725ed58166e5b2401dfadd7c1cb7e490a2
Author: Hans Goudey
Date:   Mon Mar 7 19:06:40 2022 -0600
Branches: master
https://developer.blender.org/rB901a03725ed58166e5b2401dfadd7c1cb7e490a2

Curves: Port mesh to curve node to new data-block

The main improvement is a code simplification, because attributes don't
have to be transferred separately for each curve, and all attributes can
be handled generically. Performance improves significantly when the
output contains many curves. Basic testing with a 2 million curve output
shows an approximate 10x performance improvement.

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

M	source/blender/geometry/GEO_mesh_to_curve.hh
M	source/blender/geometry/intern/mesh_to_curve_convert.cc
M	source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc

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

diff --git a/source/blender/geometry/GEO_mesh_to_curve.hh b/source/blender/geometry/GEO_mesh_to_curve.hh
index a99ee9c7fee..c480e4178cf 100644
--- a/source/blender/geometry/GEO_mesh_to_curve.hh
+++ b/source/blender/geometry/GEO_mesh_to_curve.hh
@@ -2,11 +2,10 @@
 
 #include "BLI_index_mask.hh"
 
-#include "BKE_spline.hh"
-
 #pragma once
 
 struct Mesh;
+struct Curves;
 class MeshComponent;
 
 /** \file
@@ -20,7 +19,6 @@ namespace blender::geometry {
  * intersections of more than three edges will become breaks in splines. Attributes that
  * are not built-in on meshes and not curves are transferred to the result curve.
  */
-std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_component,
-                                                 const IndexMask selection);
+Curves *mesh_to_curve_convert(const MeshComponent &mesh_component, const IndexMask selection);
 
 }  // namespace blender::geometry
diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc
index 121a1b5de39..0c2377fde6d 100644
--- a/source/blender/geometry/intern/mesh_to_curve_convert.cc
+++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc
@@ -2,7 +2,6 @@
 
 #include "BLI_array.hh"
 #include "BLI_set.hh"
-#include "BLI_string_ref.hh"
 #include "BLI_task.hh"
 
 #include "DNA_mesh_types.h"
@@ -10,85 +9,48 @@
 
 #include "BKE_attribute_access.hh"
 #include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
 #include "BKE_geometry_set.hh"
-#include "BKE_spline.hh"
 
 #include "GEO_mesh_to_curve.hh"
 
 namespace blender::geometry {
 
 template<typename T>
-static void copy_attribute_to_points(const VArray<T> &source_data,
-                                     Span<int> map,
-                                     MutableSpan<T> dest_data)
+static void copy_with_map(const VArray<T> &src, Span<int> map, MutableSpan<T> dst)
 {
-  for (const int point_index : map.index_range()) {
-    const int vert_index = map[point_index];
-    dest_data[point_index] = source_data[vert_index];
-  }
+  devirtualize_varray(src, [&](const auto &src) {
+    threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) {
+      for (const int i : range) {
+        const int vert_index = map[i];
+        dst[i] = src[vert_index];
+      }
+    });
+  });
 }
 
-static std::unique_ptr<CurveEval> create_curve_from_vert_indices(
-    const MeshComponent &mesh_component, Span<Vector<int>> vert_indices, IndexRange cyclic_splines)
+static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_component,
+                                              const Span<int> vert_indices,
+                                              const Span<int> curve_offsets,
+                                              const IndexRange cyclic_splines)
 {
-  std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
-  curve->resize(vert_indices.size());
-
-  MutableSpan<SplinePtr> splines = curve->splines();
+  Curves *curves_id = bke::curves_new_nomain(vert_indices.size(), curve_offsets.size());
+  bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+  curves.offsets().drop_back(1).copy_from(curve_offsets);
+  curves.offsets().last() = vert_indices.size();
+  curves.curve_types().fill(CURVE_TYPE_POLY);
 
-  for (const int i : vert_indices.index_range()) {
-    splines[i] = std::make_unique<PolySpline>();
-    splines[i]->resize(vert_indices[i].size());
-  }
-  for (const int i : cyclic_splines) {
-    splines[i]->set_cyclic(true);
-  }
+  curves.cyclic().fill(false);
+  curves.cyclic().slice(cyclic_splines).fill(true);
 
   Set<bke::AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids();
 
-  /* Copy builtin control point attributes. */
-  if (source_attribute_ids.contains("tilt")) {
-    const VArray<float> tilt_attribute = mesh_component.attribute_get_for_read<float>(
-        "tilt", ATTR_DOMAIN_POINT, 0.0f);
-    threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
-      for (const int i : range) {
-        copy_attribute_to_points<float>(tilt_attribute, vert_indices[i], splines[i]->tilts());
-      }
-    });
-    source_attribute_ids.remove_contained("tilt");
-  }
-  else {
-    for (SplinePtr &spline : splines) {
-      spline->tilts().fill(0.0f);
-    }
-  }
-
-  if (source_attribute_ids.contains("radius")) {
-    const VArray<float> radius_attribute = mesh_component.attribute_get_for_read<float>(
-        "radius", ATTR_DOMAIN_POINT, 1.0f);
-    threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
-      for (const int i : range) {
-        copy_attribute_to_points<float>(radius_attribute, vert_indices[i], splines[i]->radii());
-      }
-    });
-    source_attribute_ids.remove_contained("radius");
-  }
-  else {
-    for (SplinePtr &spline : splines) {
-      spline->radii().fill(1.0f);
-    }
-  }
-
-  VArray<float3> mesh_positions = mesh_component.attribute_get_for_read(
-      "position", ATTR_DOMAIN_POINT, float3(0));
-  threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
-    for (const int i : range) {
-      copy_attribute_to_points(mesh_positions, vert_indices[i], splines[i]->positions());
-    }
-  });
+  CurveComponent curves_component;
+  curves_component.replace(curves_id, GeometryOwnershipType::Editable);
 
   for (const bke::AttributeIDRef &attribute_id : source_attribute_ids) {
-    if (mesh_component.attribute_is_builtin(attribute_id)) {
+    if (mesh_component.attribute_is_builtin(attribute_id) &&
+        !curves_component.attribute_is_builtin(attribute_id)) {
       /* Don't copy attributes that are built-in on meshes but not on curves. */
       continue;
     }
@@ -105,33 +67,24 @@ static std::unique_ptr<CurveEval> create_curve_from_vert_indices(
       continue;
     }
 
-    const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute.type());
-
-    threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
-      for (const int i : range) {
-        /* Create attribute on the spline points. */
-        splines[i]->attributes.create(attribute_id, data_type);
-        std::optional<fn::GMutableSpan> spline_attribute = splines[i]->attributes.get_for_write(
-            attribute_id);
-        BLI_assert(spline_attribute);
-
-        /* Copy attribute based on the map for this spline. */
-        attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
-          using T = decltype(dummy);
-          copy_attribute_to_points<T>(
-              mesh_attribute.typed<T>(), vert_indices[i], spline_attribute->typed<T>());
-        });
-      }
+    /* Copy attribute based on the map for this spline. */
+    attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
+      using T = decltype(dummy);
+      bke::OutputAttribute_Typed<T> attribute =
+          curves_component.attribute_try_get_for_output_only<T>(attribute_id, ATTR_DOMAIN_POINT);
+      copy_with_map<T>(mesh_attribute.typed<T>(), vert_indices, attribute.as_span());
+      attribute.save();
     });
   }
 
-  curve->assert_valid_point_attributes();
-  return curve;
+  return curves_id;
 }
 
 struct CurveFromEdgesOutput {
   /** The indices in the mesh for each control point of each result splines. */
-  Vector<Vector<int>> vert_indices;
+  Vector<int> vert_indices;
+  /** The first index of each curve in the result. */
+  Vector<int> curve_offsets;
   /** A subset of splines that should be set cyclic. */
   IndexRange cyclic_splines;
 };
@@ -139,7 +92,9 @@ struct CurveFromEdgesOutput {
 static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
                                                          Span<std::pair<int, int>> edges)
 {
-  Vector<Vector<int>> vert_indices;
+  Vector<int> vert_indices;
+  vert_indices.reserve(edges.size());
+  Vector<int> curve_offsets;
 
   /* Compute the number of edges connecting to each vertex. */
   Array<int> neighbor_count(verts.size(), 0);
@@ -191,15 +146,16 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
         continue;
       }
 
-      Vector<int> spline_indices;
-      spline_indices.append(current_vert);
+      /* Start a new curve in the output. */
+      curve_offsets.append(vert_indices.size());
+      vert_indices.append(current_vert);
 
       /* Follow connected edges until we read a vertex with more than two connected edges. */
       while (true) {
         int last_vert = current_vert;
         current_vert = next_vert;
 
-        spline_indices.append(current_vert);
+        vert_indices.append(current_vert);
         unused_edges[current_vert]--;
         unused_edges[last_vert]--;
 
@@ -212,13 +168,11 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
         const int next_b = neighbors[offset + 1];
         next_vert = (last_vert == next_a) ? next_b : next_a;
       }
-
-      vert_indices.append(std::move(spline_indices));
     }
   }
 
   /* All splines added after this are cyclic. */
-  const int cyclic_start = vert_indices.size();
+  const int cyclic_start = curve_offsets.size();
 
   /* All remaining edges are part of cyclic splines (we skipped vertices with two edges before). */
   for (const int start_vert : verts.index_range()) {
@@ -229,16 +183,15 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
     int current_vert = start_vert;
     int next_vert = neighbors[neighbor_offsets[current_vert]];
 
-    Vector<int> spline_indices;
-
-    spline_indices.append(current_vert);
+    curve_offsets.append(vert_indices.size());
+    vert_indices.append(current_vert);
 
     /* Follow connected edges until we loop back to the start vertex. */
     while (next_vert != start_vert) {
       const int last_vert = current_vert;
       current_vert = next_vert;
 
-      spline_indices.append(current_vert);
+      vert_indices.append(current_vert);
       unused_edges[current_vert]--;
       unused_edges[last_vert]--;
 
@@ -247,13 +200,11 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
       const int next_b = neighbors[offset + 1];
       n

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list