Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2019-09-04 10:10:27 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2019-09-04 10:34:21 +0300
commitfcf2a712eca278f198e8d61845f2078088af1f9a (patch)
tree77c6c3e0f60cba4f1fb3669029487e922514d7dd /source
parent64f8f7db7cce0c8923afcabb523f7400f744387e (diff)
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
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_armature.h1
-rw-r--r--source/blender/blenkernel/intern/armature.c104
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h6
-rw-r--r--source/blender/blenlib/intern/math_matrix.c126
-rw-r--r--source/blender/blenloader/intern/versioning_280.c19
-rw-r--r--source/blender/editors/armature/armature_edit.c6
-rw-r--r--source/blender/editors/armature/armature_utils.c2
-rw-r--r--source/blender/editors/armature/pose_transform.c32
-rw-r--r--source/blender/editors/include/ED_armature.h1
-rw-r--r--source/blender/makesdna/DNA_armature_types.h19
-rw-r--r--source/blender/makesrna/intern/rna_armature.c76
-rw-r--r--source/blender/makesrna/intern/rna_armature_api.c5
12 files changed, 359 insertions, 38 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 3beae7a1f9d..b255500272a 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -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],
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 168422a4454..c31d1a77404 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -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);
+ if (full_transform) {
+ /* Parent pose rotation and scale. */
+ mul_m4_m4m4(r_bpt->rotscale_mat, parent_pose_mat, offs_bone);
}
- else if (bone_flag & BONE_HINGE) {
- /* Parent rest rotation and pose scale. */
+ else {
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);
+ /* 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);
+ }
+ }
- /* Applies the parent pose scale to the rest matrix. */
- mul_m4_m4m4(tmat, tmat, parent_arm_mat);
+ /* 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);
- }
- 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);
- }
- else {
- mul_m4_m4m4(r_bpt->rotscale_mat, parent_pose_mat, 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),
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index f5d87667b73..00c301a01bc 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -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]);
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 2568d42566c..7c1b44978e2 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -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.
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 454f1921586..45276181102 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -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);
+ }
+ }
}
}
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index c4c10549da3..64857dd1874 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -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.
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index cd299906b4c..2b18fc15f63 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -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
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 854fb237929..52a3f7711c4 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -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);
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 48d0a5fe8be..173ba65fc47 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -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;
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index 088fd96a5ae..68241df3f93 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -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. */
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 7949db9055f..cfcc37adf6c 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -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);
diff --git a/source/blender/makesrna/intern/rna_armature_api.c b/source/blender/makesrna/intern/rna_armature_api.c
index f3bdef75c9c..2b60dbde39f 100644
--- a/source/blender/makesrna/intern/rna_armature_api.c
+++ b/source/blender/makesrna/intern/rna_armature_api.c
@@ -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) {