[Bf-blender-cvs] [8852191b779] master: Curves: Interpolate point count in add brush

Hans Goudey noreply at git.blender.org
Tue May 10 18:28:09 CEST 2022


Commit: 8852191b779e880fe4d5116f2bee3fcddb8aced4
Author: Hans Goudey
Date:   Tue May 10 18:27:24 2022 +0200
Branches: master
https://developer.blender.org/rB8852191b779e880fe4d5116f2bee3fcddb8aced4

Curves: Interpolate point count in add brush

This commit adds an option to interpolate the number of control points
in new curves based on the count in neighboring existing curves. The
idea is to provide a more automatic default than manually controlling
the number of points in a curve, so users don't have to think about
the resolution quite as much.

Internally, some utilities for creating new curves are extracted to a
new header file. These can be used for the various nodes and operators
that create new curves.

The top-bar UI will be adjusted in a separate patch, probably moving
all of the settings that affect the size and shape of the new curves
into a popover.

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

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

M	release/scripts/startup/bl_ui/space_view3d.py
A	source/blender/blenkernel/BKE_curves_utils.hh
M	source/blender/blenkernel/CMakeLists.txt
A	source/blender/blenkernel/intern/curves_utils.cc
M	source/blender/editors/sculpt_paint/curves_sculpt_add.cc
M	source/blender/geometry/intern/resample_curves.cc
M	source/blender/makesdna/DNA_brush_enums.h
M	source/blender/makesrna/intern/rna_brush.c

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

diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 122c7078c04..7bac7343bca 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -523,6 +523,7 @@ class _draw_tool_settings_context_mode:
             layout.prop(brush.curves_sculpt_settings, "curve_length")
             layout.prop(brush.curves_sculpt_settings, "interpolate_length")
             layout.prop(brush.curves_sculpt_settings, "interpolate_shape")
+            layout.prop(brush.curves_sculpt_settings, "interpolate_point_count")
 
         if brush.curves_sculpt_tool == 'GROW_SHRINK':
             layout.prop(brush, "direction", expand=True, text="")
diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh
new file mode 100644
index 00000000000..62b060093e9
--- /dev/null
+++ b/source/blender/blenkernel/BKE_curves_utils.hh
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BKE_curves.hh"
+
+/** \file
+ * \ingroup bke
+ * \brief Low-level operations for curves.
+ */
+
+namespace blender::bke::curves {
+
+/**
+ * Copy the size of every curve in #curve_ranges to the corresponding index in #counts.
+ */
+void fill_curve_counts(const bke::CurvesGeometry &curves,
+                       Span<IndexRange> curve_ranges,
+                       MutableSpan<int> counts);
+
+/**
+ * Turn an array of sizes into the offset at each index including all previous sizes.
+ */
+void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, int start_offset = 0);
+
+}  // namespace blender::bke::curves
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index c9e88362b80..0b4f81df452 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -117,6 +117,7 @@ set(SRC
   intern/curveprofile.cc
   intern/curves.cc
   intern/curves_geometry.cc
+  intern/curves_utils.cc
   intern/customdata.cc
   intern/customdata_file.c
   intern/data_transfer.c
@@ -356,6 +357,7 @@ set(SRC
   BKE_curveprofile.h
   BKE_curves.h
   BKE_curves.hh
+  BKE_curves_utils.hh
   BKE_customdata.h
   BKE_customdata_file.h
   BKE_data_transfer.h
diff --git a/source/blender/blenkernel/intern/curves_utils.cc b/source/blender/blenkernel/intern/curves_utils.cc
new file mode 100644
index 00000000000..78c2382b62f
--- /dev/null
+++ b/source/blender/blenkernel/intern/curves_utils.cc
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_curves_utils.hh"
+
+namespace blender::bke::curves {
+
+void fill_curve_counts(const bke::CurvesGeometry &curves,
+                       const Span<IndexRange> curve_ranges,
+                       MutableSpan<int> counts)
+{
+  threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange ranges_range) {
+    for (const IndexRange curves_range : curve_ranges.slice(ranges_range)) {
+      threading::parallel_for(curves_range, 4096, [&](IndexRange range) {
+        for (const int i : range) {
+          counts[i] = curves.points_for_curve(i).size();
+        }
+      });
+    }
+  });
+}
+
+void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, const int start_offset)
+{
+  int offset = start_offset;
+  for (const int i : counts_to_offsets.index_range().drop_back(1)) {
+    const int count = counts_to_offsets[i];
+    BLI_assert(count > 0);
+    counts_to_offsets[i] = offset;
+    offset += count;
+  }
+  counts_to_offsets.last() = offset;
+}
+
+}  // namespace blender::bke::curves
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index 6edc9194319..18bdbb88d8f 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -18,6 +18,7 @@
 #include "BKE_bvhutils.h"
 #include "BKE_context.h"
 #include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
 #include "BKE_mesh.h"
 #include "BKE_mesh_runtime.h"
 #include "BKE_paint.h"
@@ -105,10 +106,11 @@ struct AddOperationExecutor {
   bool use_front_face_;
   bool interpolate_length_;
   bool interpolate_shape_;
+  bool interpolate_point_count_;
   bool use_interpolation_;
   float new_curve_length_;
   int add_amount_;
-  int points_per_curve_;
+  int constant_points_per_curve_;
 
   /** Various matrices to convert between coordinate spaces. */
   float4x4 curves_to_world_mat_;
@@ -129,6 +131,15 @@ struct AddOperationExecutor {
     Vector<int> looptri_indices;
   };
 
+  struct NeighborInfo {
+    /* Curve index of the neighbor. */
+    int index;
+    /* The weights of all neighbors of a new curve add up to 1. */
+    float weight;
+  };
+  static constexpr int max_neighbors = 5;
+  using NeighborsVector = Vector<NeighborInfo, max_neighbors>;
+
   void execute(AddOperation &self, bContext *C, const StrokeExtension &stroke_extension)
   {
     self_ = &self;
@@ -172,10 +183,12 @@ struct AddOperationExecutor {
     const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
         brush_->falloff_shape);
     add_amount_ = std::max(0, brush_settings_->add_amount);
-    points_per_curve_ = std::max(2, brush_settings_->points_per_curve);
+    constant_points_per_curve_ = std::max(2, brush_settings_->points_per_curve);
     interpolate_length_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
     interpolate_shape_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
-    use_interpolation_ = interpolate_length_ || interpolate_shape_;
+    interpolate_point_count_ = brush_settings_->flag &
+                               BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
+    use_interpolation_ = interpolate_length_ || interpolate_shape_ || interpolate_point_count_;
     new_curve_length_ = brush_settings_->curve_length;
 
     tot_old_curves_ = curves_->curves_num();
@@ -215,18 +228,26 @@ struct AddOperationExecutor {
       return;
     }
 
+    Array<NeighborsVector> neighbors_per_curve;
     if (use_interpolation_) {
       this->ensure_curve_roots_kdtree();
+      neighbors_per_curve = this->find_curve_neighbors(added_points);
     }
 
+    /* Resize to add the new curves, building the offests in the array owned by thge curves. */
     const int tot_added_curves = added_points.bary_coords.size();
-    const int tot_added_points = tot_added_curves * points_per_curve_;
+    curves_->resize(curves_->points_num(), curves_->curves_num() + tot_added_curves);
+    if (interpolate_point_count_) {
+      this->initialize_curve_offsets_with_interpolation(neighbors_per_curve);
+    }
+    else {
+      this->initialize_curve_offsets_without_interpolation(constant_points_per_curve_);
+    }
 
-    curves_->resize(curves_->points_num() + tot_added_points,
-                    curves_->curves_num() + tot_added_curves);
+    /* Resize to add the correct point count calculated as part of building the offsets. */
+    curves_->resize(curves_->offsets().last(), curves_->curves_num());
 
-    threading::parallel_invoke([&]() { this->initialize_curve_offsets(tot_added_curves); },
-                               [&]() { this->initialize_attributes(added_points); });
+    this->initialize_attributes(added_points, neighbors_per_curve);
 
     curves_->update_curve_types();
 
@@ -580,33 +601,37 @@ struct AddOperationExecutor {
     }
   }
 
-  void initialize_curve_offsets(const int tot_added_curves)
+  void initialize_curve_offsets_with_interpolation(const Span<NeighborsVector> neighbors_per_curve)
   {
-    MutableSpan<int> offsets = curves_->offsets_for_write();
-    threading::parallel_for(IndexRange(tot_added_curves), 1024, [&](const IndexRange range) {
-      for (const int i : range) {
-        const int curve_i = tot_old_curves_ + i;
-        offsets[curve_i + 1] = tot_old_points_ + (i + 1) * points_per_curve_;
+    MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_);
+
+    attribute_math::DefaultMixer<int> mixer{new_offsets};
+    threading::parallel_for(neighbors_per_curve.index_range(), 1024, [&](IndexRange curves_range) {
+      for (const int i : curves_range) {
+        for (const NeighborInfo &neighbor : neighbors_per_curve[i]) {
+          const int neighbor_points_num = curves_->points_for_curve(neighbor.index).size();
+          mixer.mix_in(i, neighbor_points_num, neighbor.weight);
+        }
       }
     });
-  }
+    mixer.finalize();
 
-  struct NeighborInfo {
-    /* Curve index of the neighbor. */
-    int index;
-    /* The weights of all neighbors of a new curve add up to 1. */
-    float weight;
-  };
-  static constexpr int max_neighbors = 5;
-  using NeighborsVector = Vector<NeighborInfo, max_neighbors>;
+    bke::curves::accumulate_counts_to_offsets(new_offsets, tot_old_points_);
+  }
 
-  void initialize_attributes(const AddedPoints &added_points)
+  void initialize_curve_offsets_without_interpolation(const int points_per_curve)
   {
-    Array<NeighborsVector> neighbors_per_curve;
-    if (use_interpolation_) {
-      neighbors_per_curve = this->find_curve_neighbors(added_points);
+    MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_);
+    int offset = tot_old_points_;
+    for (const int i : new_offsets.index_range()) {
+      new_offsets[i] = offset;
+      offset += points_per_curve;
     }
+  }
 
+  void initialize_attributes(const AddedPoints &added_points,
+                             const Span<NeighborsVector> neighbors_per_curve)
+  {
     Array<float> new_lengths_cu(added_points.bary_coords.size());
     if (interpolate_length_) {
       this->interpolate_lengths(neighbors_per_curve, new_lengths_cu);
@@ -735,15 +760,14 @@ struct AddOperationExecutor {
     threading::parallel_for(
         added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
           for (const int i : range) {
-            const int first_point_i = tot_old_points_ + i * points_per_curve_;
+            const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i);
             con

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list