Pose Brush: Option to disable the IK anchor point
authorPablo Dobarro <pablodp606@gmail.com>
Tue, 11 Feb 2020 18:43:36 +0000 (19:43 +0100)
committerPablo Dobarro <pablodp606@gmail.com>
Tue, 11 Feb 2020 18:44:14 +0000 (19:44 +0100)
The IK chain was using an anchor point by default as it makes sense for
posing, but for creating curved shapes it is useful to be able to
disable it.

Reviewed By: jbakker

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

release/scripts/startup/bl_ui/properties_paint_common.py
source/blender/blenkernel/intern/brush.c
source/blender/blenloader/intern/versioning_280.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/makesdna/DNA_brush_types.h
source/blender/makesrna/intern/rna_brush.c

index ec3dec6c54d066bce1cfa5fc32e0de166f36a427..7d2846acb72aed3353778b6b3cdd87f988bea359 100644 (file)
@@ -620,6 +620,7 @@ def brush_settings(layout, context, brush, popover=False):
             layout.prop(brush, "pose_offset")
             layout.prop(brush, "pose_smooth_iterations")
             layout.prop(brush, "pose_ik_segments")
+            layout.prop(brush, "use_pose_ik_anchored")
             layout.separator()
         
         if brush.sculpt_tool == 'SCRAPE':
index a2e3a9974088552346433c7c19488d62f74eadb0..effb3002630ba2fb8703cbf440f86b04348753ff 100644 (file)
@@ -1000,6 +1000,7 @@ void BKE_brush_sculpt_reset(Brush *br)
     case SCULPT_TOOL_POSE:
       br->pose_smooth_iterations = 4;
       br->pose_ik_segments = 1;
+      br->flag2 |= BRUSH_POSE_IK_ANCHORED;
       br->flag &= ~BRUSH_ALPHA_PRESSURE;
       br->flag &= ~BRUSH_SPACE;
       br->flag &= ~BRUSH_SPACE_ATTEN;
index cb12efd0ec2ce79bf30694552a44170f5d3365e7..b570947739a2e65dc183cb4f1ef10cff45b6e016 100644 (file)
@@ -4440,5 +4440,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
         br->pose_ik_segments = 1;
       }
     }
+
+    /* Pose brush keep anchor point. */
+    for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+      if (br->sculpt_tool == SCULPT_TOOL_POSE) {
+        br->flag2 |= BRUSH_POSE_IK_ANCHORED;
+      }
+    }
   }
 }
index f4c94b6e5de63da61e53c8ed35c8d01d75be67bd..e0c75e1e64f389f8ca8c412331ea445764e610a5 100644 (file)
@@ -3576,7 +3576,9 @@ static void sculpt_flip_quat_by_symm_area(float quat[3],
   }
 }
 
-static void pose_solve_ik_chain(SculptPoseIKChain *ik_chain, const float initial_target[3])
+static void pose_solve_ik_chain(SculptPoseIKChain *ik_chain,
+                                const float initial_target[3],
+                                const bool use_anchor)
 {
   SculptPoseIKChainSegment *segments = ik_chain->segments;
   int tot_segments = ik_chain->tot_segments;
@@ -3615,13 +3617,15 @@ static void pose_solve_ik_chain(SculptPoseIKChain *ik_chain, const float initial
   }
 
   /* Move back the whole chain to preserve the anchor point. */
-  float anchor_diff[3];
-  sub_v3_v3v3(
-      anchor_diff, segments[tot_segments - 1].initial_orig, segments[tot_segments - 1].orig);
+  if (use_anchor) {
+    float anchor_diff[3];
+    sub_v3_v3v3(
+        anchor_diff, segments[tot_segments - 1].initial_orig, segments[tot_segments - 1].orig);
 
-  for (int i = 0; i < tot_segments; i++) {
-    add_v3_v3(segments[i].orig, anchor_diff);
-    add_v3_v3(segments[i].head, anchor_diff);
+    for (int i = 0; i < tot_segments; i++) {
+      add_v3_v3(segments[i].orig, anchor_diff);
+      add_v3_v3(segments[i].head, anchor_diff);
+    }
   }
 }
 
@@ -3742,8 +3746,8 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
     copy_v3_v3(ik_target, ss->cache->true_location);
     add_v3_v3(ik_target, ss->cache->grab_delta);
 
-    /* Solve the IK positions */
-    pose_solve_ik_chain(ik_chain, ik_target);
+    /* Solve the IK positions. */
+    pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED);
   }
 
   /* Flip the segment chain in all symmetry axis and calculate the transform matrices for each
index 278256f39c85220eb6d5c1062c365353155309fb..c5bf026983b4de41aa4d5e232a5834ad4e667c18 100644 (file)
@@ -458,6 +458,7 @@ typedef enum eBrushSamplingFlags {
 typedef enum eBrushFlags2 {
   BRUSH_MULTIPLANE_SCRAPE_DYNAMIC = (1 << 0),
   BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW = (1 << 1),
+  BRUSH_POSE_IK_ANCHORED = (1 << 2),
 } eBrushFlags2;
 
 typedef enum {
index 42f475dda94518d24e54bbb01ea7b0ccd299a4dd..0096aa3f29f178e12eaf07fe86c479cf86c39b71 100644 (file)
@@ -2099,6 +2099,12 @@ static void rna_def_brush(BlenderRNA *brna)
       prop, "Show Cursor Preview", "Preview the scrape planes in the cursor during the stroke");
   RNA_def_property_update(prop, 0, "rna_Brush_update");
 
+  prop = RNA_def_property(srna, "use_pose_ik_anchored", PROP_BOOLEAN, PROP_NONE);
+  RNA_def_property_boolean_sdna(prop, NULL, "flag2", BRUSH_POSE_IK_ANCHORED);
+  RNA_def_property_ui_text(
+      prop, "Keep Anchor Point", "Keep the position of the last segmend in the IK chain fixed");
+  RNA_def_property_update(prop, 0, "rna_Brush_update");
+
   prop = RNA_def_property(srna, "invert_to_scrape_fill", PROP_BOOLEAN, PROP_NONE);
   RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_INVERT_TO_SCRAPE_FILL);
   RNA_def_property_ui_text(prop,