Armature: add automatic B-Bone Scale toggles.

Currently B-Bone scaling can only be controlled via their
properties, thus requiring up to 8 drivers per joint between
B-Bones to transfer scaling factors from the handle bone.

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

In addition, four toggles are added for each handle, which
multiply each of the X, Y, Z 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.

Differential Revision: https://developer.blender.org/D9870
This commit is contained in:
Alexander Gavrilov 2021-06-15 13:51:19 +03:00
parent 638c16f410
commit b6030711a2
Notes: blender-bot 2023-02-14 06:42:53 +01:00
Referenced by issue #89621, Bendy bones saved in 3.0 break in older versions
Referenced by issue #89361, Bendy bones fail to version in this one file
Referenced by issue #83908, Streamlining advanced rigging of B-Bone chains.
5 changed files with 166 additions and 7 deletions

View File

@ -176,20 +176,47 @@ class BONE_PT_curved(BoneButtonsPanel, Panel):
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")
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")
split2 = split.split(factor=0.7)
row2 = split2.row(align=True)
row2.prop(bone, "bbone_handle_use_scale_start", index=0, text="X", toggle=True)
row2.prop(bone, "bbone_handle_use_scale_start", index=1, text="Y", toggle=True)
row2.prop(bone, "bbone_handle_use_scale_start", index=2, text="Z", toggle=True)
split2.prop(bone, "bbone_handle_use_ease_start", 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")
split2 = split.split(factor=0.7)
row2 = split2.row(align=True)
row2.prop(bone, "bbone_handle_use_scale_end", index=0, text="X", toggle=True)
row2.prop(bone, "bbone_handle_use_scale_end", index=1, text="Y", toggle=True)
row2.prop(bone, "bbone_handle_use_scale_end", index=2, text="Z", toggle=True)
split2.prop(bone, "bbone_handle_use_ease_end", text="Ease", toggle=True)
row.label(icon="BLANK1")
class BONE_PT_relations(BoneButtonsPanel, Panel):

View File

@ -959,7 +959,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));
@ -996,6 +996,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;
@ -1041,6 +1046,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);
}
}
}
@ -1088,6 +1099,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
@ -1137,6 +1154,47 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
param->curve_out_x = bone->curve_out_x + (!rest ? pchan->curve_out_x : 0.0f);
param->curve_out_z = bone->curve_out_z + (!rest ? pchan->curve_out_z : 0.0f);
if (bone->bbone_flag & BBONE_SCALE_EASING) {
param->ease1 *= param->scale_in[1];
param->curve_in_x *= param->scale_in[1];
param->curve_in_z *= param->scale_in[1];
param->ease2 *= param->scale_out[1];
param->curve_out_x *= param->scale_out[1];
param->curve_out_z *= param->scale_out[1];
}
/* Custom handle scale. */
if (bone->bbone_prev_flag & BBONE_HANDLE_SCALE_X) {
param->scale_in[0] *= prev_scale[0];
}
if (bone->bbone_prev_flag & BBONE_HANDLE_SCALE_Y) {
param->scale_in[1] *= prev_scale[1];
}
if (bone->bbone_prev_flag & BBONE_HANDLE_SCALE_Z) {
param->scale_in[2] *= prev_scale[2];
}
if (bone->bbone_prev_flag & BBONE_HANDLE_SCALE_EASE) {
param->ease1 *= prev_scale[1];
param->curve_in_x *= prev_scale[1];
param->curve_in_z *= prev_scale[1];
}
if (bone->bbone_next_flag & BBONE_HANDLE_SCALE_X) {
param->scale_out[0] *= next_scale[0];
}
if (bone->bbone_next_flag & BBONE_HANDLE_SCALE_Y) {
param->scale_out[1] *= next_scale[1];
}
if (bone->bbone_next_flag & BBONE_HANDLE_SCALE_Z) {
param->scale_out[2] *= next_scale[2];
}
if (bone->bbone_next_flag & BBONE_HANDLE_SCALE_EASE) {
param->ease2 *= next_scale[1];
param->curve_out_x *= next_scale[1];
param->curve_out_z *= next_scale[1];
}
}
}

View File

@ -1180,6 +1180,16 @@ static void ebone_spline_preview(EditBone *ebone, const float result_array[MAX_B
param.curve_out_x = ebone->curve_out_x;
param.curve_out_z = ebone->curve_out_z;
if (ebone->bbone_flag & BBONE_SCALE_EASING) {
param.ease1 *= param.scale_in[1];
param.curve_in_x *= param.scale_in[1];
param.curve_in_z *= param.scale_in[1];
param.ease2 *= param.scale_out[1];
param.curve_out_x *= param.scale_out[1];
param.curve_out_z *= param.scale_out[1];
}
ebone->segments = BKE_pchan_bbone_spline_compute(&param, false, (Mat4 *)result_array);
}

View File

@ -302,8 +302,25 @@ typedef enum eBone_BBoneHandleType {
typedef enum eBone_BBoneFlag {
/** Add the parent Out roll to the In roll. */
BBONE_ADD_PARENT_END_ROLL = (1 << 0),
/** Multiply B-Bone easing values with Scale Length. */
BBONE_SCALE_EASING = (1 << 1),
} eBone_BBoneFlag;
/* bone->bbone_prev/next_flag */
typedef enum eBone_BBoneHandleFlag {
/** Use handle bone scaling for scale X. */
BBONE_HANDLE_SCALE_X = (1 << 0),
/** Use handle bone scaling for scale Y (length). */
BBONE_HANDLE_SCALE_Y = (1 << 1),
/** Use handle bone scaling for scale Z. */
BBONE_HANDLE_SCALE_Z = (1 << 2),
/** Use handle bone scaling for easing. */
BBONE_HANDLE_SCALE_EASE = (1 << 3),
/** Is handle scale required? */
BBONE_HANDLE_SCALE_ANY = BBONE_HANDLE_SCALE_X | BBONE_HANDLE_SCALE_Y | BBONE_HANDLE_SCALE_Z |
BBONE_HANDLE_SCALE_EASE,
} eBone_BBoneHandleFlag;
#define MAXBONENAME 64
#ifdef __cplusplus

View File

@ -769,6 +769,13 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editb
RNA_def_property_ui_text(prop, "Ease Out", "Length of second Bezier Handle (for B-Bones only)");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
if (is_posebone == false) {
prop = RNA_def_property(srna, "use_scale_easing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
prop, "Scale Easing", "Multiply the final easing values by the Scale In/Out Y factors");
RNA_def_property_boolean_sdna(prop, NULL, "bbone_flag", BBONE_SCALE_EASING);
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
}
/* Scale In/Out */
prop = RNA_def_property(srna, "bbone_scalein", PROP_FLOAT, PROP_XYZ);
@ -1053,6 +1060,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(prop, "B-Bone Display Z Width", "B-Bone Z size");
/* B-Bone Start Handle settings. */
prop = RNA_def_property(srna, "bbone_handle_type_start", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "bbone_prev_type");
RNA_def_property_enum_items(prop, prop_bbone_handle_type);
@ -1077,6 +1085,26 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_ui_text(
prop, "B-Bone Start Handle", "Bone that serves as the start handle for the B-Bone curve");
prop = RNA_def_property(srna, "bbone_handle_use_scale_start", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
prop,
"Start Handle Scale",
"Multiply B-Bone Scale In channels by the local scale values of the start handle. "
"This is done after the Scale Easing option and isn't affected by it");
RNA_def_property_boolean_sdna(prop, NULL, "bbone_prev_flag", BBONE_HANDLE_SCALE_X);
RNA_def_property_array(prop, 3);
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
prop = RNA_def_property(srna, "bbone_handle_use_ease_start", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
prop,
"Start Handle Ease",
"Multiply the B-Bone Ease In channel by the local Y scale value of the start handle. "
"This is done after the Scale Easing option and isn't affected by it");
RNA_def_property_boolean_sdna(prop, NULL, "bbone_prev_flag", BBONE_HANDLE_SCALE_EASE);
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
/* B-Bone End Handle settings. */
prop = RNA_def_property(srna, "bbone_handle_type_end", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "bbone_next_type");
RNA_def_property_enum_items(prop, prop_bbone_handle_type);
@ -1101,6 +1129,25 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_ui_text(
prop, "B-Bone End Handle", "Bone that serves as the end handle for the B-Bone curve");
prop = RNA_def_property(srna, "bbone_handle_use_scale_end", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
prop,
"End Handle Scale",
"Multiply B-Bone Scale Out channels by the local scale values of the end handle. "
"This is done after the Scale Easing option and isn't affected by it");
RNA_def_property_boolean_sdna(prop, NULL, "bbone_next_flag", BBONE_HANDLE_SCALE_X);
RNA_def_property_array(prop, 3);
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
prop = RNA_def_property(srna, "bbone_handle_use_ease_end", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
prop,
"End Handle Ease",
"Multiply the B-Bone Ease Out channel by the local Y scale value of the end handle. "
"This is done after the Scale Easing option and isn't affected by it");
RNA_def_property_boolean_sdna(prop, NULL, "bbone_next_flag", BBONE_HANDLE_SCALE_EASE);
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
RNA_define_lib_overridable(false);
}