[Bf-blender-cvs] [7484f274dcd] master: Curves: Port curve to mesh node to the new data-block

Hans Goudey noreply at git.blender.org
Fri Apr 15 17:16:55 CEST 2022


Commit: 7484f274dcdc9092dd5d85059e8d110572fe3b3c
Author: Hans Goudey
Date:   Fri Apr 15 10:14:54 2022 -0500
Branches: master
https://developer.blender.org/rB7484f274dcdc9092dd5d85059e8d110572fe3b3c

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

This commit changes the Curve to Mesh node to work with `Curves`
instead of `CurveEval`. The change ends up basically completely
rewriting the node, since the different attribute storage means that
the decisions made previously don't make much sense anymore.

The main loops are now "for each attribute: for each curve combination"
rather than the other way around, with the goal of taking advantage
of the locality of curve attributes. This improvement is quite
noticeable with many small curves; I measured a 4-5x improvement
(around 4-5s to <1s) when converting millions of curves to tens of
millions of faces. I didn't obverse any change in performance compared
to 3.1 with fewer curves though.

The changes also solve an algorithmic flaw where any interpolated
attributes would be evaluated for every curve combination instead
of just once per curve. This can be a large improvement when there
are many profile curves.

The code relies heavily on a function `foreach_curve_combination`
which calculates some basic information about each combination and
calls a templated function. I made assumptions about unnecessary reads
being removed by compiler optimizations. For further performance
improvements in the future that might be an area to investigate.
Another might be using a "for a group of curves: for each attribute:
for each curve" pattern to increase the locality of memory access.

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

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

M	source/blender/blenkernel/BKE_curve_to_mesh.hh
M	source/blender/blenkernel/BKE_curves.hh
M	source/blender/blenkernel/intern/curve_to_mesh_convert.cc
M	source/blender/blenkernel/intern/curves_geometry.cc
M	source/blender/blenkernel/intern/mesh_convert.cc
M	source/blender/blenlib/BLI_vector.hh
M	source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc

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

diff --git a/source/blender/blenkernel/BKE_curve_to_mesh.hh b/source/blender/blenkernel/BKE_curve_to_mesh.hh
index a49cb6eb7f5..6e657542e0f 100644
--- a/source/blender/blenkernel/BKE_curve_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_curve_to_mesh.hh
@@ -2,7 +2,7 @@
 
 #pragma once
 
-struct CurveEval;
+struct CurvesGeometry;
 struct Mesh;
 
 /** \file
@@ -21,11 +21,13 @@ namespace blender::bke {
  * changed anyway in a way that affects the normals. So currently this code uses the safer /
  * simpler solution of deferring normal calculation to the rest of Blender.
  */
-Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, bool fill_caps);
+Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
+                          const CurvesGeometry &profile,
+                          bool fill_caps);
 /**
  * Create a loose-edge mesh based on the evaluated path of the curve's splines.
  * Transfer curve attributes to the mesh.
  */
-Mesh *curve_to_wire_mesh(const CurveEval &curve);
+Mesh *curve_to_wire_mesh(const CurvesGeometry &curve);
 
 }  // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 3d912e10fb2..282e2a40bd0 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -328,6 +328,10 @@ class CurvesGeometry : public ::CurvesGeometry {
    * calculated. That can be ensured with #ensure_evaluated_offsets.
    */
   void interpolate_to_evaluated(int curve_index, GSpan src, GMutableSpan dst) const;
+  /**
+   * Evaluate generic data for curve control points to the standard evaluated points of the curves.
+   */
+  void interpolate_to_evaluated(GSpan src, GMutableSpan dst) const;
 
  private:
   /**
@@ -445,6 +449,13 @@ bool segment_is_vector(Span<int8_t> handle_types_left,
  */
 bool last_cylic_segment_is_vector(Span<int8_t> handle_types_left, Span<int8_t> handle_types_right);
 
+/**
+ * Return true if the handle types at the index are free (#BEZIER_HANDLE_FREE) or vector
+ * (#BEZIER_HANDLE_VECTOR). In these cases, directional continuitity from the previous and next
+ * evaluated segments is assumed not to be desired.
+ */
+bool point_is_sharp(Span<int8_t> handle_types_left, Span<int8_t> handle_types_right, int index);
+
 /**
  * Calculate offsets into the curve's evaluated points for each control point. While most control
  * point edges generate the number of edges specified by the resolution, vector segments only
@@ -715,4 +726,22 @@ inline float CurvesGeometry::evaluated_length_total_for_curve(const int curve_in
 
 /** \} */
 
+/* -------------------------------------------------------------------- */
+/** \name Bezier Inline Methods
+ * \{ */
+
+namespace curves::bezier {
+
+inline bool point_is_sharp(const Span<int8_t> handle_types_left,
+                           const Span<int8_t> handle_types_right,
+                           const int index)
+{
+  return ELEM(handle_types_left[index], BEZIER_HANDLE_VECTOR, BEZIER_HANDLE_FREE) ||
+         ELEM(handle_types_right[index], BEZIER_HANDLE_VECTOR, BEZIER_HANDLE_FREE);
+}
+
+}  // namespace curves::bezier
+
+/** \} */
+
 }  // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index 9b22a4c9726..c48d155f5ce 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -9,65 +9,15 @@
 
 #include "BKE_attribute_access.hh"
 #include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
 #include "BKE_geometry_set.hh"
 #include "BKE_material.h"
 #include "BKE_mesh.h"
-#include "BKE_spline.hh"
 
 #include "BKE_curve_to_mesh.hh"
 
 namespace blender::bke {
 
-/** Information about the creation of one curve spline and profile spline combination. */
-struct ResultInfo {
-  const Spline &spline;
-  const Spline &profile;
-  int vert_offset;
-  int edge_offset;
-  int loop_offset;
-  int poly_offset;
-  int spline_vert_len;
-  int spline_edge_len;
-  int profile_vert_len;
-  int profile_edge_len;
-};
-
-static void vert_extrude_to_mesh_data(const Spline &spline,
-                                      const float3 profile_vert,
-                                      MutableSpan<MVert> r_verts,
-                                      MutableSpan<MEdge> r_edges,
-                                      const int vert_offset,
-                                      const int edge_offset)
-{
-  const int eval_size = spline.evaluated_points_size();
-  for (const int i : IndexRange(eval_size - 1)) {
-    MEdge &edge = r_edges[edge_offset + i];
-    edge.v1 = vert_offset + i;
-    edge.v2 = vert_offset + i + 1;
-    edge.flag = ME_LOOSEEDGE;
-  }
-
-  if (spline.is_cyclic() && spline.evaluated_edges_size() > 1) {
-    MEdge &edge = r_edges[edge_offset + spline.evaluated_edges_size() - 1];
-    edge.v1 = vert_offset + eval_size - 1;
-    edge.v2 = vert_offset;
-    edge.flag = ME_LOOSEEDGE;
-  }
-
-  Span<float3> positions = spline.evaluated_positions();
-  Span<float3> tangents = spline.evaluated_tangents();
-  Span<float3> normals = spline.evaluated_normals();
-  VArray<float> radii = spline.interpolate_to_evaluated(spline.radii());
-  for (const int i : IndexRange(eval_size)) {
-    float4x4 point_matrix = float4x4::from_normalized_axis_data(
-        positions[i], normals[i], tangents[i]);
-    point_matrix.apply_scale(radii[i]);
-
-    MVert &vert = r_verts[vert_offset + i];
-    copy_v3_v3(vert.co, point_matrix * profile_vert);
-  }
-}
-
 static void mark_edges_sharp(MutableSpan<MEdge> edges)
 {
   for (MEdge &edge : edges) {
@@ -75,36 +25,50 @@ static void mark_edges_sharp(MutableSpan<MEdge> edges)
   }
 }
 
-static void spline_extrude_to_mesh_data(const ResultInfo &info,
-                                        const bool fill_caps,
-                                        MutableSpan<MVert> r_verts,
-                                        MutableSpan<MEdge> r_edges,
-                                        MutableSpan<MLoop> r_loops,
-                                        MutableSpan<MPoly> r_polys)
+static void fill_mesh_topology(const int vert_offset,
+                               const int edge_offset,
+                               const int poly_offset,
+                               const int loop_offset,
+                               const int main_point_num,
+                               const int profile_point_num,
+                               const bool main_cyclic,
+                               const bool profile_cyclic,
+                               const bool fill_caps,
+                               MutableSpan<MEdge> edges,
+                               MutableSpan<MLoop> loops,
+                               MutableSpan<MPoly> polys)
 {
-  const Spline &spline = info.spline;
-  const Spline &profile = info.profile;
-  if (info.profile_vert_len == 1) {
-    vert_extrude_to_mesh_data(spline,
-                              profile.evaluated_positions()[0],
-                              r_verts,
-                              r_edges,
-                              info.vert_offset,
-                              info.edge_offset);
+  const int main_segment_num = curves::curve_segment_size(main_point_num, main_cyclic);
+  const int profile_segment_num = curves::curve_segment_size(profile_point_num, profile_cyclic);
+
+  if (profile_point_num == 1) {
+    for (const int i : IndexRange(main_point_num - 1)) {
+      MEdge &edge = edges[edge_offset + i];
+      edge.v1 = vert_offset + i;
+      edge.v2 = vert_offset + i + 1;
+      edge.flag = ME_LOOSEEDGE;
+    }
+
+    if (main_cyclic && main_segment_num > 1) {
+      MEdge &edge = edges[edge_offset + main_segment_num - 1];
+      edge.v1 = vert_offset + main_point_num - 1;
+      edge.v2 = vert_offset;
+      edge.flag = ME_LOOSEEDGE;
+    }
     return;
   }
 
   /* Add the edges running along the length of the curve, starting at each profile vertex. */
-  const int spline_edges_start = info.edge_offset;
-  for (const int i_profile : IndexRange(info.profile_vert_len)) {
-    const int profile_edge_offset = spline_edges_start + i_profile * info.spline_edge_len;
-    for (const int i_ring : IndexRange(info.spline_edge_len)) {
-      const int i_next_ring = (i_ring == info.spline_vert_len - 1) ? 0 : i_ring + 1;
+  const int main_edges_start = edge_offset;
+  for (const int i_profile : IndexRange(profile_point_num)) {
+    const int profile_edge_offset = main_edges_start + i_profile * main_segment_num;
+    for (const int i_ring : IndexRange(main_segment_num)) {
+      const int i_next_ring = (i_ring == main_point_num - 1) ? 0 : i_ring + 1;
 
-      const int ring_vert_offset = info.vert_offset + info.profile_vert_len * i_ring;
-      const int next_ring_vert_offset = info.vert_offset + info.profile_vert_len * i_next_ring;
+      const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
+      const int next_ring_vert_offset = vert_offset + profile_point_num * i_next_ring;
 
-      MEdge &edge = r_edges[profile_edge_offset + i_ring];
+      MEdge &edge = edges[profile_edge_offset + i_ring];
       edge.v1 = ring_vert_offset + i_profile;
       edge.v2 = next_ring_vert_offset + i_profile;
       edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
@@ -112,16 +76,15 @@ static void spline_extrude_to_mesh_data(const ResultInfo &info,
   }
 
   /* Add the edges running along each profile ring. */
-  const int profile_edges_start = spline_edges_start +
-                                  info.profile_vert_len * info.spline_edge_len;
-  for (const int i_ring : IndexRange(info.spline_vert_len)) {
-    const int ring_vert_offset = info.vert_offset + info.profile_vert_len * i_ring;
+  const int profile_edges_start = main_edges_start + profile_point_num * main_segment_num;
+  for (const int i_ring : IndexRange(main_point_num)) {
+    const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
 
-    const int ring_edge_offset = profile_edges_start + i_ring * info.profile_edge_len;
-    for (const int i_profile : IndexRange(info.profile_edge_len)) {
-      const int i_next_profile = (i_profile == info.profile_vert_l

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list