[Bf-blender-cvs] [0264d8390fa] master: Apply Pose as Rest Pose: implement an Only Selected bones option.

Alexander Gavrilov noreply at git.blender.org
Mon May 13 18:53:11 CEST 2019


Commit: 0264d8390fa28153e8a122ed419faba936944bd9
Author: Alexander Gavrilov
Date:   Sun Jul 8 17:10:15 2018 +0300
Branches: master
https://developer.blender.org/rB0264d8390fa28153e8a122ed419faba936944bd9

Apply Pose as Rest Pose: implement an Only Selected bones option.

The most difficult part is handling parent-child relations correctly:
when a parent is applied, the children should be moved accordingly,
and when applying a child, it should not include transformation from
unapplied parents. All this requires walking bones as a tree, instead
of a flat list.

Limitation: Applying bones with non-uniform scaling without also applying
children will distort non-rest posing on said children for reasons related
to T54159 (basically, non-uniform scale plus rotation creates shear, and
Blender matrix decomposition utilities don't have tools to deal with it).

Reviewers: campbellbarton, brecht, mont29

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

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

M	release/scripts/startup/bl_ui/space_view3d.py
M	source/blender/editors/armature/pose_transform.c

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

diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 8510f8c1dd0..23cd2c36e76 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -3143,7 +3143,8 @@ class VIEW3D_MT_pose_apply(Menu):
     def draw(self, _context):
         layout = self.layout
 
-        layout.operator("pose.armature_apply")
+        layout.operator("pose.armature_apply").selected = False
+        layout.operator("pose.armature_apply", text="Apply Selected as Rest Pose").selected = True
         layout.operator("pose.visual_transform_apply")
 
         layout.separator()
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 6207d5412cf..49b66429515 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -59,6 +59,9 @@
 #include "ED_screen.h"
 #include "ED_util.h"
 
+#include "UI_interface.h"
+#include "UI_resources.h"
+
 #include "armature_intern.h"
 
 /* ********************************************** */
@@ -87,6 +90,229 @@ static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Objec
   }
 }
 
+/* Sets the bone head, tail and roll to match the supplied parameters. */
+static void applyarmature_set_edit_position(EditBone *curbone,
+                                            const float pose_mat[4][4],
+                                            const float new_tail[3],
+                                            float r_new_arm_mat[4][4])
+{
+  /* Simply copy the head/tail values from pchan over to curbone. */
+  copy_v3_v3(curbone->head, pose_mat[3]);
+  copy_v3_v3(curbone->tail, new_tail);
+
+  /* Fix roll:
+   *	1. find auto-calculated roll value for this bone now
+   *	2. remove this from the 'visual' y-rotation
+   */
+  {
+    float premat[3][3], pmat[3][3];
+    float delta[3];
+
+    /* Obtain new auto y-rotation. */
+    sub_v3_v3v3(delta, curbone->tail, curbone->head);
+
+    copy_m3_m4(pmat, pose_mat);
+    mat3_vec_to_roll(pmat, delta, &curbone->roll);
+
+    /* Compute new rest pose matrix if requested. */
+    if (r_new_arm_mat) {
+      vec_roll_to_mat3(delta, curbone->roll, premat);
+      copy_m4_m3(r_new_arm_mat, premat);
+      copy_v3_v3(r_new_arm_mat[3], pose_mat[3]);
+    }
+  }
+}
+
+/* Copy properties over from pchan to curbone and reset channels. */
+static void applyarmature_transfer_properties(EditBone *curbone,
+                                              bPoseChannel *pchan,
+                                              const bPoseChannel *pchan_eval)
+{
+  /* Combine pose and rest values for bendy bone settings,
+   * then clear the pchan values (so we don't get a double-up).
+   */
+  if (pchan->bone->segments > 1) {
+    /* Combine rest/pose values. */
+    curbone->curve_in_x += pchan_eval->curve_in_x;
+    curbone->curve_in_y += pchan_eval->curve_in_y;
+    curbone->curve_out_x += pchan_eval->curve_out_x;
+    curbone->curve_out_y += pchan_eval->curve_out_y;
+    curbone->roll1 += pchan_eval->roll1;
+    curbone->roll2 += pchan_eval->roll2;
+    curbone->ease1 += pchan_eval->ease1;
+    curbone->ease2 += pchan_eval->ease2;
+
+    curbone->scale_in_x *= pchan_eval->scale_in_x;
+    curbone->scale_in_y *= pchan_eval->scale_in_y;
+    curbone->scale_out_x *= pchan_eval->scale_out_x;
+    curbone->scale_out_y *= pchan_eval->scale_out_y;
+
+    /* Reset pose values. */
+    pchan->curve_in_x = pchan->curve_out_x = 0.0f;
+    pchan->curve_in_y = pchan->curve_out_y = 0.0f;
+    pchan->roll1 = pchan->roll2 = 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;
+  }
+
+  /* Clear transform values for pchan. */
+  zero_v3(pchan->loc);
+  zero_v3(pchan->eul);
+  unit_qt(pchan->quat);
+  unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
+  pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
+
+  /* Set anim lock. */
+  curbone->flag |= BONE_UNKEYED;
+}
+
+/* Adjust the current edit position of the bone using the pose space matrix. */
+static void applyarmature_adjust_edit_position(bArmature *arm,
+                                               bPoseChannel *pchan,
+                                               const float delta_mat[4][4],
+                                               float r_new_arm_mat[4][4])
+{
+  EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
+  float delta[3], new_tail[3], premat[3][3], new_pose[4][4];
+
+  /* Current orientation matrix. */
+  sub_v3_v3v3(delta, curbone->tail, curbone->head);
+  vec_roll_to_mat3(delta, curbone->roll, premat);
+
+  /* New location and orientation. */
+  mul_m4_m4m3(new_pose, delta_mat, premat);
+  mul_v3_m4v3(new_pose[3], delta_mat, curbone->head);
+  mul_v3_m4v3(new_tail, delta_mat, curbone->tail);
+
+  applyarmature_set_edit_position(curbone, new_pose, new_tail, r_new_arm_mat);
+}
+
+/* Data about parent position for Apply To Selected mode. */
+typedef struct ApplyArmature_ParentState {
+  Bone *bone;
+
+  /* New rest position of the bone with scale included. */
+  float new_rest_mat[4][4];
+  /* New arm_mat of the bone == new_rest_mat without scale. */
+  float new_arm_mat[4][4];
+} ApplyArmature_ParentState;
+
+/* Recursive walk for Apply To Selected mode; pstate NULL unless child of an applied bone. */
+static void applyarmature_process_selected_rec(bArmature *arm,
+                                               bPose *pose,
+                                               bPose *pose_eval,
+                                               Bone *bone,
+                                               ListBase *selected,
+                                               ApplyArmature_ParentState *pstate)
+{
+  bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
+  const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(pose_eval, bone->name);
+
+  if (!pchan || !pchan_eval)
+    return;
+
+  ApplyArmature_ParentState new_pstate = {.bone = bone};
+
+  if (BLI_findptr(selected, pchan, offsetof(CollectionPointerLink, ptr.data))) {
+    /* SELECTED BONE: Snap to final pose transform minus unapplied parent effects.
+     *
+     * I.e. bone position with accumulated parent effects but no local
+     * transformation will match the original final pose_mat.
+     *
+     * Pose channels are reset as expected.
+     */
+    EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
+    BoneParentTransform invparent;
+    float new_tail[3];
+
+    if (pchan->parent) {
+      BoneParentTransform old_bpt, new_bpt;
+      float offs_bone[4][4];
+
+      /* 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);
+
+      /* 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_invert(&old_bpt);
+      BKE_bone_parent_transform_combine(&new_bpt, &old_bpt, &invparent);
+    }
+    else {
+      BKE_bone_parent_transform_clear(&invparent);
+    }
+
+    /* Apply change without inherited unapplied parent transformations. */
+    BKE_bone_parent_transform_apply(&invparent, pchan_eval->pose_mat, new_pstate.new_rest_mat);
+
+    copy_v3_fl3(new_tail, 0.0, bone->length, 0.0);
+    mul_m4_v3(new_pstate.new_rest_mat, new_tail);
+
+    applyarmature_set_edit_position(
+        curbone, new_pstate.new_rest_mat, new_tail, new_pstate.new_arm_mat);
+    applyarmature_transfer_properties(curbone, pchan, pchan_eval);
+
+    pstate = &new_pstate;
+  }
+  else if (pstate) {
+    /* UNSELECTED CHILD OF SELECTED: Include applied parent effects.
+     *
+     * The inherited transform of applied (selected) bones is baked
+     * into the rest pose so that the final bone position doesn't
+     * change.
+     *
+     * Pose channels are not changed, with the exception of the inherited
+     * applied parent scale being baked into the location pose channel.
+     */
+    BoneParentTransform bpt;
+    float offs_bone[4][4], delta[4][4], old_chan_loc[3];
+
+    /* 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);
+
+    unit_m4(new_pstate.new_rest_mat);
+    BKE_bone_parent_transform_apply(&bpt, new_pstate.new_rest_mat, new_pstate.new_rest_mat);
+
+    /* Bone location channel in pose space relative to bone head. */
+    mul_v3_mat3_m4v3(old_chan_loc, bpt.loc_mat, pchan_eval->loc);
+
+    /* Apply the change to the rest bone position. */
+    invert_m4_m4(delta, bone->arm_mat);
+    mul_m4_m4m4(delta, new_pstate.new_rest_mat, delta);
+
+    applyarmature_adjust_edit_position(arm, pchan, delta, new_pstate.new_arm_mat);
+
+    /* Location pose channel has to be updated, because it is affected
+     * by parent scaling, and the rest pose has no scale by definition. */
+    if (!(bone->flag & BONE_CONNECTED) && !is_zero_v3(old_chan_loc)) {
+      float inv_parent_arm[4][4];
+
+      /* 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);
+
+      /* Re-apply the location to keep the final effect. */
+      invert_m4(bpt.loc_mat);
+      mul_v3_mat3_m4v3(pchan->loc, bpt.loc_mat, old_chan_loc);
+    }
+
+    pstate = &new_pstate;
+  }
+
+  for (Bone *child = bone->childbase.first; child; child = child->next) {
+    applyarmature_process_selected_rec(arm, pose, pose_eval, child, selected, pstate);
+ 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list