[Bf-blender-cvs] [cc617d69299] temp-angavrilov-constraints: Armature: add B-Bone lengthwise scaling and custom handle scaling options.

Alexander Gavrilov noreply at git.blender.org
Wed Jan 13 15:36:14 CET 2021


Commit: cc617d6929960b246956dec956debb4009bcb481
Author: Alexander Gavrilov
Date:   Fri Dec 11 19:17:39 2020 +0300
Branches: temp-angavrilov-constraints
https://developer.blender.org/rBcc617d6929960b246956dec956debb4009bcb481

Armature: add B-Bone lengthwise scaling and custom handle scaling options.

In addition to the base bone transformation itself, B-Bones have
controls that affect transformation of its segments. For rotation
the features are quite complete, allowing to both reorient the
Bezier handles via properties, and to control them using custom
handle bones. However for scaling there are two deficiencies.

First, there are only X and Y scale factors (actually X and Z,
but this is the legacy naming), while lengthwise all segments
have the same scaling. The ease option merely affects the shape
of the curve, and does not cause actual scaling.

Second, scaling can only be controlled via properties, thus
requiring up to 6 drivers per joint between B-Bones to transfer
scaling factors from the handle bone. This is very inefficient.

This patch addresses these deficiencies by adding Length scale
inputs, and providing toggles to apply custom handle local scale
channels to the now four scale-related properties. The 'Length'
name is used to avoid confusion due to the X/Y vs X/Z naming.

The two Length scale inputs control the ratio between the lengths
of the start and end segments of the bone: although for convenience
two inputs are provided, the whole chain is still uniformly scaled
to fit the curve.

A Scale Easing option is provided to multiply the easing value
by the Length scale factors to synchronize them - this produces
a natural scaling effect where both the shape of the curve and
the scale is affected.

The second issue is addressed by providing toggles for each handle
that multiply each of the X, Z, Length and Ease values by the matching
Local Scale channel of the handle bone, thus replacing trivial drivers.
The Scale Easing option has no effect on this process since it's easy
to just enable both Length and Ease buttons.

Finally, this fixes a strange behavior where the segments were not
actually scaled in the Y direction to match their actual length, thus
producing gaps or overlap depending on the shape of the curve. For
transformation the change should be very small if enough segments
are used, but this will affect the results of the Copy Transforms
and Armature constraints, so a backwards compatibility option is
provided. Newly created bones default to the new behavior.

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

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

M	release/scripts/startup/bl_ui/properties_data_bone.py
M	source/blender/blenkernel/BKE_armature.h
M	source/blender/blenkernel/intern/action.c
M	source/blender/blenkernel/intern/armature.c
M	source/blender/blenloader/intern/versioning_290.c
M	source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
M	source/blender/draw/engines/overlay/overlay_armature.c
M	source/blender/editors/armature/armature_add.c
M	source/blender/editors/armature/armature_intern.h
M	source/blender/editors/armature/armature_utils.c
M	source/blender/editors/armature/pose_transform.c
M	source/blender/editors/armature/pose_utils.c
M	source/blender/makesdna/DNA_action_types.h
M	source/blender/makesdna/DNA_armature_types.h
M	source/blender/makesrna/intern/rna_armature.c

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

diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py
index 170d7910339..5911994bcb9 100644
--- a/release/scripts/startup/bl_ui/properties_data_bone.py
+++ b/release/scripts/startup/bl_ui/properties_data_bone.py
@@ -170,28 +170,57 @@ class BONE_PT_curved(BoneButtonsPanel, Panel):
         col = topcol.column(align=True)
         col.prop(bbone, "bbone_scaleinx", text="Scale In X")
         col.prop(bbone, "bbone_scaleiny", text="In Y")
+        col.prop(bbone, "bbone_scalein_len", text="In Len")
 
         col = topcol.column(align=True)
         col.prop(bbone, "bbone_scaleoutx", text="Scale Out X")
         col.prop(bbone, "bbone_scaleouty", text="Out Y")
+        col.prop(bbone, "bbone_scaleout_len", text="Out Len")
 
         col = topcol.column(align=True)
         col.prop(bbone, "bbone_easein", text="Ease In")
         col.prop(bbone, "bbone_easeout", text="Out")
+        col.prop(bone, "use_scale_easing")
+
+        topcol.prop(bone, "use_unscaled_segments")
 
         col = topcol.column(align=True)
         col.prop(bone, "bbone_handle_type_start", text="Start Handle")
 
-        col = col.column(align=True)
-        col.active = (bone.bbone_handle_type_start != 'AUTO')
-        col.prop_search(bone, "bbone_custom_handle_start", arm, bone_list, text="Custom")
+        col2 = col.column(align=True)
+        col2.active = (bone.bbone_handle_type_start != 'AUTO')
+        col2.prop_search(bone, "bbone_custom_handle_start", arm, bone_list, text="Custom")
+
+        row = col.row(align=True)
+        row.use_property_split = False
+        split = row.split(factor=0.4)
+        split.alignment = 'RIGHT'
+        split.label(text="Scale")
+        row2 = split.row(align=True)
+        row2.prop(bone, "bbone_handle_scale_start", index=0, text="X", toggle=True)
+        row2.prop(bone, "bbone_handle_scale_start", index=1, text="Y", toggle=True)
+        row2.prop(bone, "bbone_handle_scale_start", index=2, text="Len", toggle=True)
+        row2.prop(bone, "bbone_handle_scale_start", index=3, text="Ease", toggle=True)
+        row.label(icon="BLANK1")
 
         col = topcol.column(align=True)
         col.prop(bone, "bbone_handle_type_end", text="End Handle")
 
-        col = col.column(align=True)
-        col.active = (bone.bbone_handle_type_end != 'AUTO')
-        col.prop_search(bone, "bbone_custom_handle_end", arm, bone_list, text="Custom")
+        col2 = col.column(align=True)
+        col2.active = (bone.bbone_handle_type_end != 'AUTO')
+        col2.prop_search(bone, "bbone_custom_handle_end", arm, bone_list, text="Custom")
+
+        row = col.row(align=True)
+        row.use_property_split = False
+        split = row.split(factor=0.4)
+        split.alignment = 'RIGHT'
+        split.label(text="Scale")
+        row2 = split.row(align=True)
+        row2.prop(bone, "bbone_handle_scale_end", index=0, text="X", toggle=True)
+        row2.prop(bone, "bbone_handle_scale_end", index=1, text="Y", toggle=True)
+        row2.prop(bone, "bbone_handle_scale_end", index=2, text="Len", toggle=True)
+        row2.prop(bone, "bbone_handle_scale_end", index=3, text="Ease", toggle=True)
+        row.label(icon="BLANK1")
 
 
 class BONE_PT_relations(BoneButtonsPanel, Panel):
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index db44a771095..7dd2ef03582 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -81,8 +81,8 @@ typedef struct EditBone {
   float curve_in_x, curve_in_y;
   float curve_out_x, curve_out_y;
   float ease1, ease2;
-  float scale_in_x, scale_in_y;
-  float scale_out_x, scale_out_y;
+  float scale_in_x, scale_in_y, scale_in_len;
+  float scale_out_x, scale_out_y, scale_out_len;
 
   /** for envelope scaling */
   float oldlength;
@@ -90,6 +90,10 @@ typedef struct EditBone {
   /** Type of next/prev bone handles */
   char bbone_prev_type;
   char bbone_next_type;
+  /** B-Bone flags. */
+  int bbone_flag;
+  short bbone_prev_flag;
+  short bbone_next_flag;
   /** Next/prev bones to use as handle references when calculating bbones (optional) */
   struct EditBone *bbone_prev;
   struct EditBone *bbone_next;
@@ -281,7 +285,7 @@ typedef struct BBoneSplineParameters {
   float length;
 
   /* Non-uniform scale correction. */
-  bool do_scale;
+  bool do_scale, do_scale_segments;
   float scale[3];
 
   /* Handle control bone data. */
@@ -294,7 +298,7 @@ typedef struct BBoneSplineParameters {
   /* Control values. */
   float ease1, ease2;
   float roll1, roll2;
-  float scale_in_x, scale_in_y, scale_out_x, scale_out_y;
+  float scale_in_x, scale_in_y, scale_in_len, scale_out_x, scale_out_y, scale_out_len;
   float curve_in_x, curve_in_y, curve_out_x, curve_out_y;
 } BBoneSplineParameters;
 
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 499f81f3669..0aa4abea594 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -648,8 +648,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
   unit_axis_angle(chan->rotAxis, &chan->rotAngle);
   chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
 
-  chan->scale_in_x = chan->scale_in_y = 1.0f;
-  chan->scale_out_x = chan->scale_out_y = 1.0f;
+  chan->scale_in_x = chan->scale_in_y = chan->scale_in_len = 1.0f;
+  chan->scale_out_x = chan->scale_out_y = chan->scale_out_len = 1.0f;
 
   chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -M_PI;
   chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = M_PI;
@@ -1662,8 +1662,8 @@ void BKE_pose_rest(bPose *pose, bool selected_bones_only)
     pchan->curve_in_x = pchan->curve_in_y = 0.0f;
     pchan->curve_out_x = pchan->curve_out_y = 0.0f;
     pchan->ease1 = pchan->ease2 = 0.0f;
-    pchan->scale_in_x = pchan->scale_in_y = 1.0f;
-    pchan->scale_out_x = pchan->scale_out_y = 1.0f;
+    pchan->scale_in_x = pchan->scale_in_y = pchan->scale_in_len = 1.0f;
+    pchan->scale_out_x = pchan->scale_out_y = pchan->scale_in_len = 1.0f;
 
     pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
   }
@@ -1693,8 +1693,10 @@ void BKE_pose_copy_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchan
   pchanto->ease2 = pchanfrom->ease2;
   pchanto->scale_in_x = pchanfrom->scale_in_x;
   pchanto->scale_in_y = pchanfrom->scale_in_y;
+  pchanto->scale_in_len = pchanfrom->scale_in_len;
   pchanto->scale_out_x = pchanfrom->scale_out_x;
   pchanto->scale_out_y = pchanfrom->scale_out_y;
+  pchanto->scale_out_len = pchanfrom->scale_out_len;
 
   pchanto->rotmode = pchanfrom->rotmode;
   pchanto->flag = pchanfrom->flag;
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index c571de1e384..8cd58968e04 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -850,6 +850,7 @@ bool bone_autoside_name(
 static void equalize_cubic_bezier(const float control[4][3],
                                   int temp_segments,
                                   int final_segments,
+                                  const float *segment_scales,
                                   float *r_t_points)
 {
   float(*coords)[3] = BLI_array_alloca(coords, temp_segments + 1);
@@ -874,12 +875,26 @@ static void equalize_cubic_bezier(const float control[4][3],
   }
 
   /* Go over distances and calculate new parameter values. */
-  float dist_step = pdist[temp_segments] / final_segments;
+  float dist_step = pdist[temp_segments];
+  float dist = 0;
 
   r_t_points[0] = 0.0f;
 
+  if (segment_scales) {
+    float sum = 0.0f;
+
+    for (int i = 0; i < final_segments; i++) {
+      sum += segment_scales[i];
+    }
+
+    dist_step /= sum;
+  }
+  else {
+    dist_step /= final_segments;
+  }
+
   for (int i = 1, nr = 1; i <= final_segments; i++) {
-    float dist = i * dist_step;
+    dist += (segment_scales ? segment_scales[i - 1] : 1) * dist_step;
 
     /* We're looking for location (distance) 'dist' in the array. */
     while ((nr < temp_segments) && (dist >= pdist[nr])) {
@@ -948,7 +963,7 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
 {
   bPoseChannel *next, *prev;
   Bone *bone = pchan->bone;
-  float imat[4][4], posemat[4][4];
+  float imat[4][4], posemat[4][4], tmpmat[4][4];
   float delta[3];
 
   memset(param, 0, sizeof(*param));
@@ -956,6 +971,8 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
   param->segments = bone->segments;
   param->length = bone->length;
 
+  param->do_scale_segments = !!(bone->bbone_flag & BBONE_SCALE_SEGMENTS);
+
   if (!rest) {
     float scale[3];
 
@@ -985,6 +1002,11 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
     invert_m4_m4(imat, pchan->pose_mat);
   }
 
+  float prev_scale[3], next_scale[3];
+
+  copy_v3_fl(prev_scale, 1.0f);
+  copy_v3_fl(next_scale, 1.0f);
+
   if (prev) {
     float h1[3];
     bool done = false;
@@ -1030,6 +1052,12 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
     if (!param->prev_bbone) {
       /* Find the previous roll to interpolate. */
       mul_m4_m4m4(param->prev_mat, imat, rest ? prev->bone->arm_mat : prev->pose_mat);
+
+      /* Retrieve the local scale of the bone if necessary. */
+      if ((bone->bbone_prev_flag & BBONE_HANDLE_SCALE_ANY) && !rest) {
+        BKE_armature_mat_pose_to_bone(prev, prev->pose_mat, tmpmat);
+        mat4_to_size(prev_scale, tmpmat);
+      }
     }
   }
 
@@ -1077,6 +1105,12 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
 
     /* Find the next roll to interpolate as well. */
     mul_m4_m4m4(param->next_mat, imat, rest ? next->bone->arm_mat : next->pose_mat);
+
+    /* Retrieve the local scale of the bone if necessary. */
+    if ((bone->bbone_next_flag & BBONE_HANDLE_SCALE_ANY) && !rest) {
+      BKE_armature_mat_pose_to_bone(next, next->pose_mat, tmpmat);
+      mat4_to_size(next_scale, tmpmat);
+    }
   }
 
   /* Add effects from bbone properties over the top
@@ -1100,7 +1134,7 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *p

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list