[Bf-blender-cvs] [f0f44fd92f1] master: Curves: support spherical delete brush

Jacques Lucke noreply at git.blender.org
Mon May 2 09:19:05 CEST 2022


Commit: f0f44fd92f1684552ee0275d14bb6dd72405c8fd
Author: Jacques Lucke
Date:   Mon May 2 09:18:57 2022 +0200
Branches: master
https://developer.blender.org/rBf0f44fd92f1684552ee0275d14bb6dd72405c8fd

Curves: support spherical delete brush

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

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

M	release/scripts/startup/bl_ui/space_view3d.py
M	source/blender/editors/sculpt_paint/curves_sculpt_delete.cc

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

diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 4f1d001b2f3..69477c80c07 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -529,6 +529,9 @@ class _draw_tool_settings_context_mode:
             layout.prop(brush, "falloff_shape", expand=True)
             layout.prop(brush, "curve_preset")
 
+        if brush.curves_sculpt_tool == 'DELETE':
+            layout.prop(brush, "falloff_shape", expand=True)
+
 
 class VIEW3D_HT_header(Header):
     bl_space_type = 'VIEW_3D'
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
index 018c8c2a34f..2841a19d677 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
@@ -35,68 +35,202 @@
 #include "ED_screen.h"
 #include "ED_view3d.h"
 
+/**
+ * The code below uses a suffix naming convention to indicate the coordinate space:
+ * cu: Local space of the curves object that is being edited.
+ * wo: World space.
+ * re: 2D coordinates within the region.
+ */
+
 namespace blender::ed::sculpt_paint {
 
 using blender::bke::CurvesGeometry;
 
 class DeleteOperation : public CurvesSculptStrokeOperation {
  private:
-  float2 last_mouse_position_;
+  float2 brush_pos_prev_re_;
+
+  CurvesBrush3D brush_3d_;
+
+  friend struct DeleteOperationExecutor;
 
  public:
-  void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override
-  {
-    Scene &scene = *CTX_data_scene(C);
-    Object &object = *CTX_data_active_object(C);
-    ARegion *region = CTX_wm_region(C);
-    RegionView3D *rv3d = CTX_wm_region_view3d(C);
+  void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override;
+};
 
-    CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
-    Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
-    const float brush_radius = BKE_brush_size_get(&scene, &brush);
+struct DeleteOperationExecutor {
+  DeleteOperation *self_ = nullptr;
+  bContext *C_ = nullptr;
+  Depsgraph *depsgraph_ = nullptr;
+  Scene *scene_ = nullptr;
+  Object *object_ = nullptr;
+  ARegion *region_ = nullptr;
+  View3D *v3d_ = nullptr;
+  RegionView3D *rv3d_ = nullptr;
 
-    float4x4 projection;
-    ED_view3d_ob_project_mat_get(rv3d, &object, projection.values);
+  Curves *curves_id_ = nullptr;
+  CurvesGeometry *curves_ = nullptr;
+
+  CurvesSculpt *curves_sculpt_ = nullptr;
+  Brush *brush_ = nullptr;
+  float brush_radius_re_;
+
+  float2 brush_pos_re_;
+  float2 brush_pos_prev_re_;
 
-    Curves &curves_id = *static_cast<Curves *>(object.data);
-    CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
-    Span<float3> positions = curves.positions();
+  float4x4 curves_to_world_mat_;
+  float4x4 world_to_curves_mat_;
 
-    const float2 mouse_start = stroke_extension.is_first ? stroke_extension.mouse_position :
-                                                           last_mouse_position_;
-    const float2 mouse_end = stroke_extension.mouse_position;
+  void execute(DeleteOperation &self, bContext *C, const StrokeExtension &stroke_extension)
+  {
+    BLI_SCOPED_DEFER([&]() { self.brush_pos_prev_re_ = stroke_extension.mouse_position; });
+
+    self_ = &self;
+    C_ = C;
+    depsgraph_ = CTX_data_depsgraph_pointer(C);
+    scene_ = CTX_data_scene(C);
+    object_ = CTX_data_active_object(C);
+    region_ = CTX_wm_region(C);
+    v3d_ = CTX_wm_view3d(C);
+    rv3d_ = CTX_wm_region_view3d(C);
+
+    curves_id_ = static_cast<Curves *>(object_->data);
+    curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+
+    curves_sculpt_ = scene_->toolsettings->curves_sculpt;
+    brush_ = BKE_paint_brush(&curves_sculpt_->paint);
+    brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
+
+    brush_pos_re_ = stroke_extension.mouse_position;
+    brush_pos_prev_re_ = stroke_extension.is_first ? stroke_extension.mouse_position :
+                                                     self.brush_pos_prev_re_;
+
+    curves_to_world_mat_ = object_->obmat;
+    world_to_curves_mat_ = curves_to_world_mat_.inverted();
+
+    const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
+        brush_->falloff_shape);
+
+    if (stroke_extension.is_first) {
+      if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+        this->initialize_spherical_brush_reference_point();
+      }
+    }
+
+    if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+      this->delete_projected();
+    }
+    else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+      this->delete_spherical();
+    }
+    else {
+      BLI_assert_unreachable();
+    }
+
+    DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+    ED_region_tag_redraw(region_);
+  }
+
+  void delete_projected()
+  {
+    float4x4 projection;
+    ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+
+    Span<float3> positions_cu = curves_->positions();
 
     /* Find indices of curves that have to be removed. */
     Vector<int64_t> indices;
     const IndexMask curves_to_remove = index_mask_ops::find_indices_based_on_predicate(
-        curves.curves_range(), 512, indices, [&](const int curve_i) {
-          const IndexRange point_range = curves.points_for_curve(curve_i);
+        curves_->curves_range(), 512, indices, [&](const int curve_i) {
+          const IndexRange point_range = curves_->points_for_curve(curve_i);
           for (const int segment_i : IndexRange(point_range.size() - 1)) {
-            const float3 pos1 = positions[point_range[segment_i]];
-            const float3 pos2 = positions[point_range[segment_i + 1]];
+            const float3 pos1_cu = positions_cu[point_range[segment_i]];
+            const float3 pos2_cu = positions_cu[point_range[segment_i + 1]];
 
-            float2 pos1_proj, pos2_proj;
-            ED_view3d_project_float_v2_m4(region, pos1, pos1_proj, projection.values);
-            ED_view3d_project_float_v2_m4(region, pos2, pos2_proj, projection.values);
+            float2 pos1_re, pos2_re;
+            ED_view3d_project_float_v2_m4(region_, pos1_cu, pos1_re, projection.values);
+            ED_view3d_project_float_v2_m4(region_, pos2_cu, pos2_re, projection.values);
 
-            const float dist = dist_seg_seg_v2(pos1_proj, pos2_proj, mouse_start, mouse_end);
-            if (dist <= brush_radius) {
+            const float dist = dist_seg_seg_v2(
+                pos1_re, pos2_re, brush_pos_prev_re_, brush_pos_re_);
+            if (dist <= brush_radius_re_) {
               return true;
             }
           }
           return false;
         });
 
-    curves.remove_curves(curves_to_remove);
+    curves_->remove_curves(curves_to_remove);
+  }
 
-    curves.tag_positions_changed();
-    DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
-    ED_region_tag_redraw(region);
+  void delete_spherical()
+  {
+    Span<float3> positions_cu = curves_->positions();
 
-    last_mouse_position_ = stroke_extension.mouse_position;
+    float4x4 projection;
+    ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+
+    float3 brush_start_wo, brush_end_wo;
+    ED_view3d_win_to_3d(v3d_,
+                        region_,
+                        curves_to_world_mat_ * self_->brush_3d_.position_cu,
+                        brush_pos_prev_re_,
+                        brush_start_wo);
+    ED_view3d_win_to_3d(v3d_,
+                        region_,
+                        curves_to_world_mat_ * self_->brush_3d_.position_cu,
+                        brush_pos_re_,
+                        brush_end_wo);
+    const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
+    const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+
+    const float brush_radius_cu = self_->brush_3d_.radius_cu;
+    const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+    Vector<int64_t> indices;
+    const IndexMask curves_to_remove = index_mask_ops::find_indices_based_on_predicate(
+        curves_->curves_range(), 512, indices, [&](const int curve_i) {
+          const IndexRange points = curves_->points_for_curve(curve_i);
+          for (const int segment_i : IndexRange(points.size() - 1)) {
+            const float3 pos1_cu = positions_cu[points[segment_i]];
+            const float3 pos2_cu = positions_cu[points[segment_i] + 1];
+
+            float3 closest_segment_cu, closest_brush_cu;
+            isect_seg_seg_v3(pos1_cu,
+                             pos2_cu,
+                             brush_start_cu,
+                             brush_end_cu,
+                             closest_segment_cu,
+                             closest_brush_cu);
+            const float distance_to_brush_sq_cu = math::distance_squared(closest_segment_cu,
+                                                                         closest_brush_cu);
+            if (distance_to_brush_sq_cu > brush_radius_sq_cu) {
+              continue;
+            }
+            return true;
+          }
+          return false;
+        });
+
+    curves_->remove_curves(curves_to_remove);
+  }
+
+  void initialize_spherical_brush_reference_point()
+  {
+    std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
+        *C_, *object_, brush_pos_re_, brush_radius_re_);
+    if (brush_3d.has_value()) {
+      self_->brush_3d_ = *brush_3d;
+    }
   }
 };
 
+void DeleteOperation::on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension)
+{
+  DeleteOperationExecutor executor;
+  executor.execute(*this, C, stroke_extension);
+}
+
 std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation()
 {
   return std::make_unique<DeleteOperation>();



More information about the Bf-blender-cvs mailing list