[Bf-blender-cvs] [7dc94155f62] master: Curves: support symmetry in curves sculpting brushes

Jacques Lucke noreply at git.blender.org
Wed May 4 09:52:46 CEST 2022


Commit: 7dc94155f62025248e8c111efa8bf0561b3bb492
Author: Jacques Lucke
Date:   Wed May 4 09:51:32 2022 +0200
Branches: master
https://developer.blender.org/rB7dc94155f62025248e8c111efa8bf0561b3bb492

Curves: support symmetry in curves sculpting brushes

This adds support for X/Y/Z symmetry for all brushes in curves
sculpt mode. In theory this can be extended to support radial
symmetry, but that's not part of this patch.

It works by essentially applying a brush stroke multiple with
different transforms. This is similiar to how symmetry works in
mesh sculpt mode, but is quite different from how it worked in
the old hair system (there it tried to find matching hair strands
on both sides of the surface; if none was found, symmetry did
not work).

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

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

M	release/scripts/startup/bl_ui/space_view3d.py
M	release/scripts/startup/bl_ui/space_view3d_toolbar.py
M	source/blender/editors/sculpt_paint/CMakeLists.txt
M	source/blender/editors/sculpt_paint/curves_sculpt_add.cc
R091	source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc	source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
M	source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
M	source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
M	source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
M	source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
M	source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
M	source/blender/makesdna/DNA_curves_types.h
M	source/blender/makesrna/intern/rna_curves.c

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

diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 2f2c146b8cf..9756d9ab3a1 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -151,6 +151,11 @@ class VIEW3D_HT_tool_header(Header):
                 row.popover(panel="VIEW3D_PT_sculpt_symmetry_for_topbar", text="")
             elif mode_string == 'PAINT_VERTEX':
                 row.popover(panel="VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar", text="")
+        elif mode_string == 'SCULPT_CURVES':
+            _row, sub = row_for_mirror()
+            sub.prop(context.object.data, "use_mirror_x", text="X", toggle=True)
+            sub.prop(context.object.data, "use_mirror_y", text="Y", toggle=True)
+            sub.prop(context.object.data, "use_mirror_z", text="Z", toggle=True)
 
         # Expand panels from the side-bar as popovers.
         popover_kw = {"space_type": 'VIEW_3D', "region_type": 'UI', "category": "Tool"}
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 8c3215abc36..ba02bfb4082 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -1048,6 +1048,35 @@ class VIEW3D_PT_sculpt_symmetry_for_topbar(Panel):
 
     draw = VIEW3D_PT_sculpt_symmetry.draw
 
+class VIEW3D_PT_curves_sculpt_symmetry(Panel, View3DPaintPanel):
+    bl_context = ".curves_sculpt"  # dot on purpose (access from topbar)
+    bl_label = "Symmetry"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        return context.object and context.object.type == 'CURVES'
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False
+
+        curves = context.object.data
+
+        row = layout.row(align=True, heading="Mirror")
+        row.prop(curves, "use_mirror_x", text="X", toggle=True)
+        row.prop(curves, "use_mirror_y", text="Y", toggle=True)
+        row.prop(curves, "use_mirror_z", text="Z", toggle=True)
+
+class VIEW3D_PT_curves_sculpt_symmetry_for_topbar(Panel):
+    bl_space_type = 'TOPBAR'
+    bl_region_type = 'HEADER'
+    bl_label = "Symmetry"
+
+    draw = VIEW3D_PT_curves_sculpt_symmetry.draw
+
+
 
 # ********** default tools for weight-paint ****************
 
@@ -2351,6 +2380,9 @@ classes = (
     VIEW3D_PT_sculpt_options,
     VIEW3D_PT_sculpt_options_gravity,
 
+    VIEW3D_PT_curves_sculpt_symmetry,
+    VIEW3D_PT_curves_sculpt_symmetry_for_topbar,
+
     VIEW3D_PT_tools_weightpaint_symmetry,
     VIEW3D_PT_tools_weightpaint_symmetry_for_topbar,
     VIEW3D_PT_tools_weightpaint_options,
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 08eed52f440..d3bf28798c4 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -27,8 +27,8 @@ set(INC
 )
 
 set(SRC
-  curves_sculpt_3d_brush.cc
   curves_sculpt_add.cc
+  curves_sculpt_brush.cc
   curves_sculpt_comb.cc
   curves_sculpt_delete.cc
   curves_sculpt_grow_shrink.cc
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index 0d399419ad8..99d725fb4cb 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -194,13 +194,13 @@ struct AddOperationExecutor {
     /* Sample points on the surface using one of multiple strategies. */
     AddedPoints added_points;
     if (add_amount_ == 1) {
-      this->sample_in_center(added_points);
+      this->sample_in_center_with_symmetry(added_points);
     }
     else if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
-      this->sample_projected(rng, added_points);
+      this->sample_projected_with_symmetry(rng, added_points);
     }
     else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
-      this->sample_spherical(rng, added_points);
+      this->sample_spherical_with_symmetry(rng, added_points);
     }
     else {
       BLI_assert_unreachable();
@@ -241,13 +241,27 @@ struct AddOperationExecutor {
   /**
    * Sample a single point exactly at the mouse position.
    */
-  void sample_in_center(AddedPoints &r_added_points)
+  void sample_in_center_with_symmetry(AddedPoints &r_added_points)
   {
     float3 ray_start_wo, ray_end_wo;
     ED_view3d_win_to_segment_clipped(
         depsgraph_, region_, v3d_, brush_pos_re_, ray_start_wo, ray_end_wo, true);
     const float3 ray_start_su = world_to_surface_mat_ * ray_start_wo;
     const float3 ray_end_su = world_to_surface_mat_ * ray_end_wo;
+
+    const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+        eCurvesSymmetryType(curves_id_->symmetry));
+
+    for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+      this->sample_in_center(
+          r_added_points, brush_transform * ray_start_su, brush_transform * ray_end_su);
+    }
+  }
+
+  void sample_in_center(AddedPoints &r_added_points,
+                        const float3 &ray_start_su,
+                        const float3 &ray_end_su)
+  {
     const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
 
     BVHTreeRayHit ray_hit;
@@ -280,11 +294,23 @@ struct AddOperationExecutor {
   /**
    * Sample points by shooting rays within the brush radius in the 3D view.
    */
-  void sample_projected(RandomNumberGenerator &rng, AddedPoints &r_added_points)
+  void sample_projected_with_symmetry(RandomNumberGenerator &rng, AddedPoints &r_added_points)
   {
+    const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+        eCurvesSymmetryType(curves_id_->symmetry));
+    for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+      this->sample_projected(rng, r_added_points, brush_transform);
+    }
+  }
+
+  void sample_projected(RandomNumberGenerator &rng,
+                        AddedPoints &r_added_points,
+                        const float4x4 &brush_transform)
+  {
+    const int old_amount = r_added_points.bary_coords.size();
     const int max_iterations = std::max(100'000, add_amount_ * 10);
     int current_iteration = 0;
-    while (r_added_points.bary_coords.size() < add_amount_) {
+    while (r_added_points.bary_coords.size() < old_amount + add_amount_) {
       if (current_iteration++ >= max_iterations) {
         break;
       }
@@ -296,8 +322,8 @@ struct AddOperationExecutor {
       float3 ray_start_wo, ray_end_wo;
       ED_view3d_win_to_segment_clipped(
           depsgraph_, region_, v3d_, pos_re, ray_start_wo, ray_end_wo, true);
-      const float3 ray_start_su = world_to_surface_mat_ * ray_start_wo;
-      const float3 ray_end_su = world_to_surface_mat_ * ray_end_wo;
+      const float3 ray_start_su = brush_transform * (world_to_surface_mat_ * ray_start_wo);
+      const float3 ray_end_su = brush_transform * (world_to_surface_mat_ * ray_end_wo);
       const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
 
       BVHTreeRayHit ray_hit;
@@ -339,7 +365,7 @@ struct AddOperationExecutor {
   /**
    * Sample points in a 3D sphere around the surface position that the mouse hovers over.
    */
-  void sample_spherical(RandomNumberGenerator &rng, AddedPoints &r_added_points)
+  void sample_spherical_with_symmetry(RandomNumberGenerator &rng, AddedPoints &r_added_points)
   {
     /* Find ray that starts in the center of the brush. */
     float3 brush_ray_start_wo, brush_ray_end_wo;
@@ -347,7 +373,6 @@ struct AddOperationExecutor {
         depsgraph_, region_, v3d_, brush_pos_re_, brush_ray_start_wo, brush_ray_end_wo, true);
     const float3 brush_ray_start_su = world_to_surface_mat_ * brush_ray_start_wo;
     const float3 brush_ray_end_su = world_to_surface_mat_ * brush_ray_end_wo;
-    const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su);
 
     /* Find ray that starts on the boundary of the brush. That is used to compute the brush radius
      * in 3D. */
@@ -362,6 +387,27 @@ struct AddOperationExecutor {
     const float3 brush_radius_ray_start_su = world_to_surface_mat_ * brush_radius_ray_start_wo;
     const float3 brush_radius_ray_end_su = world_to_surface_mat_ * brush_radius_ray_end_wo;
 
+    const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+        eCurvesSymmetryType(curves_id_->symmetry));
+    for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+      this->sample_spherical(rng,
+                             r_added_points,
+                             brush_transform * brush_ray_start_su,
+                             brush_transform * brush_ray_end_su,
+                             brush_transform * brush_radius_ray_start_su,
+                             brush_transform * brush_radius_ray_end_su);
+    }
+  }
+
+  void sample_spherical(RandomNumberGenerator &rng,
+                        AddedPoints &r_added_points,
+                        const float3 &brush_ray_start_su,
+                        const float3 &brush_ray_end_su,
+                        const float3 &brush_radius_ray_start_su,
+                        const float3 &brush_radius_ray_end_su)
+  {
+    const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su);
+
     BVHTreeRayHit ray_hit;
     ray_hit.dist = FLT_MAX;
     ray_hit.index = -1;
@@ -426,7 +472,8 @@ struct AddOperationExecutor {
     const int max_iterations = 5;
     int current_iteration = 0;
 
-    while (r_added_points.bary_coords.size() < add_amount_) {
+    const int old_amount = r_added_points.bary_coords.size();
+    while (r_added_points.bary_coords.size() < old_amount + add_amount_) {
       if (current_iteration++ >= max_iterations) {
         break;
       }
@@ -506,8 +553,8 @@ struct AddOperationExecutor {
     }
 
     /* Remove samples when there are too many. */
-    while (r_added_points.bary_coords.size() > add_amount_) {
-      const int index_to_remove = rng.get_int32(r_added_points.

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list