Armature: add Inherit Scale options to remove shear or average the scale.

As an inherent property of matrix-based transformation math, non-
uniform scaling of a parent bone induces shear into the transform
matrix of any rotated child. Such matrices cannot be cleanly
decomposed into a combination of location/rotation/scale, which
causes issues for rigging and animation tools.

Blender bones have options to exclude rotation and/or scale from the
inherited transformation, but don't have any support for removing the
often undesired shear component. That goal requires replacing simple
parenting with a combination of multiple bones and constraints. The
same is true about the goal of inheriting some scale, but completely
avoiding shear.

This patch replaces the old Inherit Scale checkbox with a enum that
supports multiple options:

* Full: inherit all effects of scale, like with enabled Inherit Scale.

* Fix Shear: removes shear from the final inherited transformation.

  The cleanup math is specifically designed to preserve the main
  axis of the bone, its length and total volume, and minimally
  affect roll on average. It however will not prevent reappearance
  of shear due to local rotation of the child or its children.

* Average: inherit uniform scale that represents the parent volume.

  This is the simplest foolproof solution that will inherit some
  scale without ever causing shear.

* None: completely remove scale and shear.

* None (Legacy): old disabled Inherit Scale checkbox.

  This mode does not handle parent shear in any way, so the child
  is likely to end up having both scale and shear. It is retained
  for backward compatibility.

Since many rigging-related addons access the use_inherit_scale
property from Python, it is retained as a backward compatibility
stub that provides the old functionality.

As a side effect of reworking the code, this also fixes a matrix
multiplication order bug in the Inherit Rotation code, which caused
the parent local scale to be applied in world space. In rigger
opinion this option is useless in production rigs, so this fix
should not be a problem.

Reviewers: brecht

Differential Revision: https://developer.blender.org/D5588
This commit is contained in:
Alexander Gavrilov 2019-09-04 10:10:27 +03:00
parent 64f8f7db7c
commit fcf2a712ec
Notes: blender-bot 2023-02-14 02:22:13 +01:00
Referenced by issue #69697, Toggle Bone Options: Can't toggle inherit scale
14 changed files with 368 additions and 45 deletions

View File

@ -232,11 +232,13 @@ class BONE_PT_relations(BoneButtonsPanel, Panel):
sub = col.column()
sub.active = (bone.parent is not None)
sub.prop(bone, "use_connect")
sub.prop(bone, "use_inherit_rotation")
sub.prop(bone, "use_inherit_scale")
sub = col.column()
sub.active = (not bone.parent or not bone.use_connect)
sub.prop(bone, "use_local_location")
sub = col.column()
sub.active = (bone.parent is not None)
sub.prop(bone, "use_inherit_rotation")
sub.prop(bone, "inherit_scale")
class BONE_PT_display(BoneButtonsPanel, Panel):

View File

@ -3193,7 +3193,7 @@ class BoneOptions:
"use_deform",
"use_envelope_multiply",
"use_inherit_rotation",
"use_inherit_scale",
"inherit_scale",
]
if context.mode == 'EDIT_ARMATURE':

View File

@ -182,6 +182,7 @@ void BKE_bone_parent_transform_apply(const struct BoneParentTransform *bpt,
void BKE_bone_parent_transform_calc_from_pchan(const struct bPoseChannel *pchan,
struct BoneParentTransform *r_bpt);
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
int inherit_scale_mode,
const float offs_bone[4][4],
const float parent_arm_mat[4][4],
const float parent_pose_mat[4][4],

View File

@ -1867,11 +1867,16 @@ void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
/* yoffs(b-1) + root(b) + bonemat(b). */
BKE_bone_offset_matrix_get(bone, offs_bone);
BKE_bone_parent_transform_calc_from_matrices(
bone->flag, offs_bone, parbone->arm_mat, parchan->pose_mat, r_bpt);
BKE_bone_parent_transform_calc_from_matrices(bone->flag,
bone->inherit_scale_mode,
offs_bone,
parbone->arm_mat,
parchan->pose_mat,
r_bpt);
}
else {
BKE_bone_parent_transform_calc_from_matrices(bone->flag, bone->arm_mat, NULL, NULL, r_bpt);
BKE_bone_parent_transform_calc_from_matrices(
bone->flag, bone->inherit_scale_mode, bone->arm_mat, NULL, NULL, r_bpt);
}
}
@ -1882,39 +1887,90 @@ void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
* parent_arm_mat, parent_pose_mat: arm_mat and pose_mat of parent, or NULL
* r_bpt: OUTPUT parent transform */
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
int inherit_scale_mode,
const float offs_bone[4][4],
const float parent_arm_mat[4][4],
const float parent_pose_mat[4][4],
BoneParentTransform *r_bpt)
{
if (parent_pose_mat) {
const bool use_rotation = (bone_flag & BONE_HINGE) == 0;
const bool full_transform = use_rotation && inherit_scale_mode == BONE_INHERIT_SCALE_FULL;
/* Compose the rotscale matrix for this bone. */
if ((bone_flag & BONE_HINGE) && (bone_flag & BONE_NO_SCALE)) {
/* Parent rest rotation and scale. */
mul_m4_m4m4(r_bpt->rotscale_mat, parent_arm_mat, offs_bone);
}
else if (bone_flag & BONE_HINGE) {
/* Parent rest rotation and pose scale. */
float tmat[4][4], tscale[3];
/* Extract the scale of the parent pose matrix. */
mat4_to_size(tscale, parent_pose_mat);
size_to_mat4(tmat, tscale);
/* Applies the parent pose scale to the rest matrix. */
mul_m4_m4m4(tmat, tmat, parent_arm_mat);
mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone);
}
else if (bone_flag & BONE_NO_SCALE) {
/* Parent pose rotation and rest scale (i.e. no scaling). */
float tmat[4][4];
copy_m4_m4(tmat, parent_pose_mat);
normalize_m4(tmat);
mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone);
if (full_transform) {
/* Parent pose rotation and scale. */
mul_m4_m4m4(r_bpt->rotscale_mat, parent_pose_mat, offs_bone);
}
else {
mul_m4_m4m4(r_bpt->rotscale_mat, parent_pose_mat, offs_bone);
float tmat[4][4], tscale[3];
/* If using parent pose rotation: */
if (use_rotation) {
copy_m4_m4(tmat, parent_pose_mat);
/* Normalize the matrix when needed. */
switch (inherit_scale_mode) {
case BONE_INHERIT_SCALE_FULL:
case BONE_INHERIT_SCALE_FIX_SHEAR:
/* Keep scale and shear. */
break;
case BONE_INHERIT_SCALE_NONE:
case BONE_INHERIT_SCALE_AVERAGE:
/* Remove scale and shear from parent. */
orthogonalize_m4_stable(tmat, 1, true);
break;
case BONE_INHERIT_SCALE_NONE_LEGACY:
/* Remove only scale - bad legacy way. */
normalize_m4(tmat);
break;
default:
BLI_assert(false);
}
}
/* If removing parent pose rotation: */
else {
copy_m4_m4(tmat, parent_arm_mat);
/* Copy the parent scale when needed. */
switch (inherit_scale_mode) {
case BONE_INHERIT_SCALE_FULL:
/* Ignore effects of shear. */
mat4_to_size(tscale, parent_pose_mat);
rescale_m4(tmat, tscale);
break;
case BONE_INHERIT_SCALE_FIX_SHEAR:
/* Take the effects of parent shear into account to get exact volume. */
mat4_to_size_fix_shear(tscale, parent_pose_mat);
rescale_m4(tmat, tscale);
break;
case BONE_INHERIT_SCALE_NONE:
case BONE_INHERIT_SCALE_AVERAGE:
case BONE_INHERIT_SCALE_NONE_LEGACY:
/* Keep unscaled. */
break;
default:
BLI_assert(false);
}
}
/* Apply the average parent scale when needed. */
if (inherit_scale_mode == BONE_INHERIT_SCALE_AVERAGE) {
mul_mat3_m4_fl(tmat, cbrtf(fabsf(mat4_to_volume_scale(parent_pose_mat))));
}
mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone);
/* Remove remaining shear when needed, preserving volume. */
if (inherit_scale_mode == BONE_INHERIT_SCALE_FIX_SHEAR) {
orthogonalize_m4_stable(r_bpt->rotscale_mat, 1, false);
}
}
/* Compose the loc matrix for this bone. */
@ -1938,7 +1994,7 @@ void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
mul_m4_m4m4(r_bpt->loc_mat, bone_loc, tmat4);
}
/* Those flags do not affect position, use plain parent transform space! */
else if (bone_flag & (BONE_HINGE | BONE_NO_SCALE)) {
else if (!full_transform) {
mul_m4_m4m4(r_bpt->loc_mat, parent_pose_mat, offs_bone);
}
/* Else (i.e. default, usual case),

View File

@ -252,6 +252,9 @@ void normalize_m4_m4(float R[4][4], const float A[4][4]) ATTR_NONNULL();
void orthogonalize_m3(float R[3][3], int axis);
void orthogonalize_m4(float R[4][4], int axis);
void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize);
void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize);
bool is_orthogonal_m3(const float mat[3][3]);
bool is_orthogonal_m4(const float mat[4][4]);
bool is_orthonormal_m3(const float mat[3][3]);
@ -303,8 +306,11 @@ void size_to_mat4(float R[4][4], const float size[3]);
void mat3_to_size(float r[3], const float M[3][3]);
void mat4_to_size(float r[3], const float M[4][4]);
void mat4_to_size_fix_shear(float r[3], const float M[4][4]);
void translate_m4(float mat[4][4], float tx, float ty, float tz);
void rotate_m4(float mat[4][4], const char axis, const float angle);
void rescale_m4(float mat[4][4], float scale[3]);
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]);

View File

@ -1516,6 +1516,111 @@ void orthogonalize_m4(float mat[4][4], int axis)
mul_v3_fl(mat[2], size[2]);
}
/** Make an orthonormal basis around v1 in a way that is stable and symmetric. */
static void orthogonalize_stable(float v1[3], float v2[3], float v3[3], bool normalize)
{
/* Make secondary axis vectors orthogonal to the primary via
* plane projection, which preserves the determinant. */
float len_sq_v1 = len_squared_v3(v1);
if (len_sq_v1 > 0.0f) {
madd_v3_v3fl(v2, v1, -dot_v3v3(v2, v1) / len_sq_v1);
madd_v3_v3fl(v3, v1, -dot_v3v3(v3, v1) / len_sq_v1);
if (normalize) {
mul_v3_fl(v1, 1.0f / sqrtf(len_sq_v1));
}
}
/* Make secondary axis vectors orthogonal relative to each other. */
float norm_v2[3], norm_v3[3], tmp[3];
float length_v2 = normalize_v3_v3(norm_v2, v2);
float length_v3 = normalize_v3_v3(norm_v3, v3);
float cos_angle = dot_v3v3(norm_v2, norm_v3);
float abs_cos_angle = fabsf(cos_angle);
/* Apply correction if the shear angle is significant, and not degenerate. */
if (abs_cos_angle > 1e-4f && abs_cos_angle < 1.0f - FLT_EPSILON) {
/* Adjust v2 by half of the necessary angle correction.
* Thus the angle change is the same for both axis directions. */
float angle = acosf(cos_angle);
float target_angle = angle + ((float)M_PI_2 - angle) / 2;
madd_v3_v3fl(norm_v2, norm_v3, -cos_angle);
mul_v3_fl(norm_v2, sinf(target_angle) / len_v3(norm_v2));
madd_v3_v3fl(norm_v2, norm_v3, cosf(target_angle));
/* Make v3 orthogonal. */
cross_v3_v3v3(tmp, norm_v2, norm_v3);
cross_v3_v3v3(norm_v3, tmp, norm_v2);
normalize_v3(norm_v3);
/* Re-apply scale, preserving area and proportion. */
if (!normalize) {
float scale_fac = sqrtf(sinf(angle));
mul_v3_v3fl(v2, norm_v2, length_v2 * scale_fac);
mul_v3_v3fl(v3, norm_v3, length_v3 * scale_fac);
}
}
if (normalize) {
copy_v3_v3(v2, norm_v2);
copy_v3_v3(v3, norm_v3);
}
}
/**
* Make an orthonormal matrix around the selected axis of the given matrix,
* in a way that is symmetric and stable to variations in the input, and
* preserving the value of the determinant, i.e. the overall volume change.
*
* \param axis: Axis to build the orthonormal basis around.
* \param normalize: Normalize the matrix instead of preserving volume.
*/
void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize)
{
switch (axis) {
case 0:
orthogonalize_stable(R[0], R[1], R[2], normalize);
break;
case 1:
orthogonalize_stable(R[1], R[0], R[2], normalize);
break;
case 2:
orthogonalize_stable(R[2], R[0], R[1], normalize);
break;
default:
BLI_assert(0);
break;
}
}
/**
* Make an orthonormal matrix around the selected axis of the given matrix,
* in a way that is symmetric and stable to variations in the input, and
* preserving the value of the determinant, i.e. the overall volume change.
*
* \param axis: Axis to build the orthonormal basis around.
* \param normalize: Normalize the matrix instead of preserving volume.
*/
void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize)
{
switch (axis) {
case 0:
orthogonalize_stable(R[0], R[1], R[2], normalize);
break;
case 1:
orthogonalize_stable(R[1], R[0], R[2], normalize);
break;
case 2:
orthogonalize_stable(R[2], R[0], R[1], normalize);
break;
default:
BLI_assert(0);
break;
}
}
bool is_orthogonal_m3(const float m[3][3])
{
int i, j;
@ -1851,6 +1956,19 @@ void mat4_to_size(float size[3], const float mat[4][4])
size[2] = len_v3(mat[2]);
}
/** Extract scale factors from the matrix, with correction to ensure
* exact volume in case of a sheared matrix. */
void mat4_to_size_fix_shear(float size[3], const float mat[4][4])
{
mat4_to_size(size, mat);
float volume = size[0] * size[1] * size[2];
if (volume != 0.0f) {
mul_v3_fl(size, cbrtf(fabsf(mat4_to_volume_scale(mat) / volume)));
}
}
/**
* This computes the overall volume scale factor of a transformation matrix.
* For an orthogonal matrix, it is the product of all three scale values.
@ -2045,6 +2163,14 @@ void rotate_m4(float mat[4][4], const char axis, const float angle)
}
}
/** Scale a matrix in-place. */
void rescale_m4(float mat[4][4], float scale[3])
{
mul_v3_fl(mat[0], scale[0]);
mul_v3_fl(mat[1], scale[1]);
mul_v3_fl(mat[2], scale[2]);
}
/**
* Scale or rotate around a pivot point,
* a convenience function to avoid having to do inline.

View File

@ -637,6 +637,18 @@ static void do_version_bones_split_bbone_scale(ListBase *lb)
}
}
static void do_version_bones_inherit_scale(ListBase *lb)
{
for (Bone *bone = lb->first; bone; bone = bone->next) {
if (bone->flag & BONE_NO_SCALE) {
bone->inherit_scale_mode = BONE_INHERIT_SCALE_NONE_LEGACY;
bone->flag &= ~BONE_NO_SCALE;
}
do_version_bones_inherit_scale(&bone->childbase);
}
}
static bool replace_bbone_scale_rnapath(char **p_old_path)
{
char *old_path = *p_old_path;
@ -3756,5 +3768,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
/* Convert the BONE_NO_SCALE flag to inherit_scale_mode enum. */
if (!DNA_struct_elem_find(fd->filesdna, "Bone", "char", "inherit_scale_mode")) {
LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
do_version_bones_inherit_scale(&arm->bonebase);
}
}
}
}

View File

@ -908,8 +908,10 @@ static void bones_merge(
newbone->parent = start->parent;
/* TODO, copy more things to the new bone */
newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_CYCLICOFFSET |
BONE_NO_LOCAL_LOCATION | BONE_DONE);
newbone->inherit_scale_mode = start->inherit_scale_mode;
/* Step 2a: reparent any side chains which may be parented to any bone in the chain
* of bones to merge - potentially several tips for side chains leading to some tree exist.

View File

@ -491,6 +491,7 @@ static EditBone *make_boneList_rec(ListBase *edbo,
eBone->parent = parent;
BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name));
eBone->flag = curBone->flag;
eBone->inherit_scale_mode = curBone->inherit_scale_mode;
/* fix selection flags */
if (eBone->flag & BONE_SELECTED) {
@ -719,6 +720,7 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
newBone->arm_roll = eBone->roll;
newBone->flag = eBone->flag;
newBone->inherit_scale_mode = eBone->inherit_scale_mode;
if (eBone == arm->act_edbone) {
/* don't change active selection, this messes up separate which uses

View File

@ -241,13 +241,21 @@ static void applyarmature_process_selected_rec(bArmature *arm,
/* Parent effects on the bone transform that have to be removed. */
BKE_bone_offset_matrix_get(bone, offs_bone);
BKE_bone_parent_transform_calc_from_matrices(
bone->flag, offs_bone, bone->parent->arm_mat, pchan_eval->parent->pose_mat, &old_bpt);
BKE_bone_parent_transform_calc_from_matrices(bone->flag,
bone->inherit_scale_mode,
offs_bone,
bone->parent->arm_mat,
pchan_eval->parent->pose_mat,
&old_bpt);
/* Applied parent effects that have to be kept, if any. */
float(*new_parent_pose)[4] = pstate ? pstate->new_rest_mat : bone->parent->arm_mat;
BKE_bone_parent_transform_calc_from_matrices(
bone->flag, offs_bone, bone->parent->arm_mat, new_parent_pose, &new_bpt);
BKE_bone_parent_transform_calc_from_matrices(bone->flag,
bone->inherit_scale_mode,
offs_bone,
bone->parent->arm_mat,
new_parent_pose,
&new_bpt);
BKE_bone_parent_transform_invert(&old_bpt);
BKE_bone_parent_transform_combine(&new_bpt, &old_bpt, &invparent);
@ -283,8 +291,12 @@ static void applyarmature_process_selected_rec(bArmature *arm,
/* Include applied parent effects. */
BKE_bone_offset_matrix_get(bone, offs_bone);
BKE_bone_parent_transform_calc_from_matrices(
bone->flag, offs_bone, pstate->bone->arm_mat, pstate->new_rest_mat, &bpt);
BKE_bone_parent_transform_calc_from_matrices(bone->flag,
bone->inherit_scale_mode,
offs_bone,
pstate->bone->arm_mat,
pstate->new_rest_mat,
&bpt);
unit_m4(new_pstate.new_rest_mat);
BKE_bone_parent_transform_apply(&bpt, new_pstate.new_rest_mat, new_pstate.new_rest_mat);
@ -306,8 +318,12 @@ static void applyarmature_process_selected_rec(bArmature *arm,
/* Compute the channel coordinate space matrices for the new rest state. */
invert_m4_m4(inv_parent_arm, pstate->new_arm_mat);
mul_m4_m4m4(offs_bone, inv_parent_arm, new_pstate.new_arm_mat);
BKE_bone_parent_transform_calc_from_matrices(
bone->flag, offs_bone, pstate->new_arm_mat, pstate->new_arm_mat, &bpt);
BKE_bone_parent_transform_calc_from_matrices(bone->flag,
bone->inherit_scale_mode,
offs_bone,
pstate->new_arm_mat,
pstate->new_arm_mat,
&bpt);
/* Re-apply the location to keep the final effect. */
invert_m4(bpt.loc_mat);

View File

@ -73,6 +73,7 @@ typedef struct EditBone {
* animation are automatically relative to the bones' rest positions*/
int flag;
int layer;
char inherit_scale_mode;
/* Envelope distance & weight */
float dist, weight;

View File

@ -60,6 +60,9 @@ typedef struct Bone {
int flag;
char inherit_scale_mode;
char _pad[7];
float arm_head[3];
/** head/tail in Armature Space (rest pos). */
float arm_tail[3];
@ -229,8 +232,10 @@ typedef enum eBone_Flag {
BONE_UNKEYED = (1 << 13),
/** set to prevent hinge child bones from influencing the transform center */
BONE_HINGE_CHILD_TRANSFORM = (1 << 14),
#ifdef DNA_DEPRECATED
/** No parent scale */
BONE_NO_SCALE = (1 << 15),
#endif
/** hidden bone when drawing PoseChannels (for ghost drawing) */
BONE_HIDDEN_PG = (1 << 16),
/** bone should be drawn as OB_WIRE, regardless of draw-types of view+armature */
@ -254,6 +259,20 @@ typedef enum eBone_Flag {
} eBone_Flag;
/* bone->inherit_scale_mode */
typedef enum eBone_InheritScaleMode {
/* Inherit all scale and shear. */
BONE_INHERIT_SCALE_FULL = 0,
/* Inherit scale, but remove final shear. */
BONE_INHERIT_SCALE_FIX_SHEAR,
/* Inherit average scale. */
BONE_INHERIT_SCALE_AVERAGE,
/* Inherit no scale or shear. */
BONE_INHERIT_SCALE_NONE,
/* Inherit effects of shear on parent (same as old disabled Inherit Scale). */
BONE_INHERIT_SCALE_NONE_LEGACY,
} eBone_InheritScaleMode;
/* bone->bbone_prev_type, bbone_next_type */
typedef enum eBone_BBoneHandleType {
BBONE_HANDLE_AUTO = 0, /* Default mode based on parents & children. */

View File

@ -303,6 +303,40 @@ static void rna_Bone_layer_set(PointerRNA *ptr, const bool *values)
BKE_armature_refresh_layer_used(arm);
}
/* TODO: remove the deprecation stubs. */
static bool rna_use_inherit_scale_get(char inherit_scale_mode)
{
return inherit_scale_mode <= BONE_INHERIT_SCALE_FIX_SHEAR;
}
static void rna_use_inherit_scale_set(char *inherit_scale_mode, bool value)
{
bool cur_value = (*inherit_scale_mode <= BONE_INHERIT_SCALE_FIX_SHEAR);
if (value != cur_value) {
*inherit_scale_mode = (value ? BONE_INHERIT_SCALE_FULL : BONE_INHERIT_SCALE_NONE);
}
}
static bool rna_EditBone_use_inherit_scale_get(PointerRNA *ptr)
{
return rna_use_inherit_scale_get(((EditBone *)ptr->data)->inherit_scale_mode);
}
static void rna_EditBone_use_inherit_scale_set(PointerRNA *ptr, bool value)
{
rna_use_inherit_scale_set(&((EditBone *)ptr->data)->inherit_scale_mode, value);
}
static bool rna_Bone_use_inherit_scale_get(PointerRNA *ptr)
{
return rna_use_inherit_scale_get(((Bone *)ptr->data)->inherit_scale_mode);
}
static void rna_Bone_use_inherit_scale_set(PointerRNA *ptr, bool value)
{
rna_use_inherit_scale_set(&((Bone *)ptr->data)->inherit_scale_mode, value);
}
static void rna_Armature_layer_set(PointerRNA *ptr, const bool *values)
{
bArmature *arm = (bArmature *)ptr->data;
@ -773,6 +807,28 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem prop_inherit_scale_mode[] = {
{BONE_INHERIT_SCALE_FULL, "FULL", 0, "Full", "Inherit all effects of parent scaling"},
{BONE_INHERIT_SCALE_FIX_SHEAR,
"FIX_SHEAR",
0,
"Fix Shear",
"Inherit scaling, but remove shearing of the child in the rest orientation"},
{BONE_INHERIT_SCALE_AVERAGE,
"AVERAGE",
0,
"Average",
"Inherit uniform scaling representing the overall change in the volume of the parent"},
{BONE_INHERIT_SCALE_NONE, "NONE", 0, "None", "Completely ignore parent scaling"},
{BONE_INHERIT_SCALE_NONE_LEGACY,
"NONE_LEGACY",
0,
"None (Legacy)",
"Ignore parent scaling without compensating for parent shear. "
"Replicates the effect of disabling the original Inherit Scale checkbox"},
{0, NULL, 0, NULL, NULL},
};
PropertyRNA *prop;
/* strings */
@ -832,9 +888,25 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_ui_text(prop, "Deform", "Enable Bone to deform geometry");
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
prop = RNA_def_property(srna, "inherit_scale", PROP_ENUM, PROP_NONE);
RNA_def_property_ui_text(
prop, "Inherit Scale", "Specifies how the bone inherits scaling from the parent bone");
RNA_def_property_enum_sdna(prop, NULL, "inherit_scale_mode");
RNA_def_property_enum_items(prop, prop_inherit_scale_mode);
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
/* TODO: remove the compatibility stub. */
prop = RNA_def_property(srna, "use_inherit_scale", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Inherit Scale", "Bone inherits scaling from parent bone");
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BONE_NO_SCALE);
RNA_def_property_ui_text(
prop, "Inherit Scale", "DEPRECATED: Bone inherits scaling from parent bone");
if (editbone) {
RNA_def_property_boolean_funcs(
prop, "rna_EditBone_use_inherit_scale_get", "rna_EditBone_use_inherit_scale_set");
}
else {
RNA_def_property_boolean_funcs(
prop, "rna_Bone_use_inherit_scale_get", "rna_Bone_use_inherit_scale_set");
}
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
prop = RNA_def_property(srna, "use_local_location", PROP_BOOLEAN, PROP_NONE);

View File

@ -71,14 +71,15 @@ static void rna_Bone_convert_local_to_pose(Bone *bone,
if (is_zero_m4(parent_pose_mat) || is_zero_m4(parent_arm_mat)) {
/* No parent case. */
BKE_bone_parent_transform_calc_from_matrices(bone->flag, bone_arm_mat, NULL, NULL, &bpt);
BKE_bone_parent_transform_calc_from_matrices(
bone->flag, bone->inherit_scale_mode, bone_arm_mat, NULL, NULL, &bpt);
}
else {
invert_m4_m4(offs_bone, parent_arm_mat);
mul_m4_m4m4(offs_bone, offs_bone, bone_arm_mat);
BKE_bone_parent_transform_calc_from_matrices(
bone->flag, offs_bone, parent_arm_mat, parent_pose_mat, &bpt);
bone->flag, bone->inherit_scale_mode, offs_bone, parent_arm_mat, parent_pose_mat, &bpt);
}
if (invert) {