apply visual transform to pose
authorCampbell Barton <ideasman42@gmail.com>
Fri, 19 Feb 2010 15:34:26 +0000 (15:34 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 19 Feb 2010 15:34:26 +0000 (15:34 +0000)
So constrainted bones can have their transform applied to their loc/scale/rot, then remove the constraints

release/scripts/ui/space_view3d.py
source/blender/blenkernel/BKE_armature.h
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/object.c
source/blender/collada/DocumentExporter.cpp
source/blender/editors/armature/armature_intern.h
source/blender/editors/armature/armature_ops.c
source/blender/editors/armature/editarmature.c
source/blender/ikplugin/intern/iksolver_plugin.c
source/blender/ikplugin/intern/itasc_plugin.cpp

index 93cb29bb93b77c2e20be2eab5636c7b43768456d..1fc2447bcfcb2b62152e8eac7c1f8e543b9f2c0c 100644 (file)
@@ -990,8 +990,7 @@ class VIEW3D_MT_pose(bpy.types.Menu):
 
         layout.separator()
 
-        layout.operator("pose.apply")
-        layout.operator("pose.relax")
+        layout.menu("VIEW3D_MT_pose_apply")
 
         layout.separator()
 
@@ -1110,6 +1109,17 @@ class VIEW3D_MT_pose_constraints(bpy.types.Menu):
 class VIEW3D_MT_pose_showhide(VIEW3D_MT_showhide):
     _operator_name = "pose"
 
+
+class VIEW3D_MT_pose_apply(bpy.types.Menu):
+    bl_label = "Apply"
+
+    def draw(self, context):
+        layout = self.layout
+
+        layout.operator("pose.armature_apply")
+        layout.operator("pose.visual_transform_apply")
+
+
 # ********** Edit Menus, suffix from ob.type **********
 
 
@@ -2160,6 +2170,7 @@ classes = [
     VIEW3D_MT_pose_ik,
     VIEW3D_MT_pose_constraints,
     VIEW3D_MT_pose_showhide,
+    VIEW3D_MT_pose_apply,
 
     VIEW3D_MT_edit_mesh,
     VIEW3D_MT_edit_mesh_specials, # Only as a menu for keybindings
index 30bed6bb3352804aec6df044effd158ef0f9c53e..e142fceebda0c053e3b0eaf763cdde2bc1f69453 100644 (file)
@@ -91,7 +91,7 @@ void where_is_armature (struct bArmature *arm);
 void where_is_armature_bone(struct Bone *bone, struct Bone *prevbone);
 void armature_rebuild_pose(struct Object *ob, struct bArmature *arm);
 void where_is_pose (struct Scene *scene, struct Object *ob);
-void where_is_pose_bone(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime);
+void where_is_pose_bone(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, int do_extra);
 
 /* get_objectspace_bone_matrix has to be removed still */
 void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int root, int posed);
@@ -105,6 +105,8 @@ void armature_mat_pose_to_bone(struct bPoseChannel *pchan, float inmat[][4], flo
 void armature_loc_pose_to_bone(struct bPoseChannel *pchan, float *inloc, float *outloc);
 void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4]);
 
+void pchan_apply_mat4(struct bPoseChannel *pchan, float mat[][4]);
+
 /* Rotation Mode Conversions - Used for PoseChannels + Objects... */
 void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode);
 
index b568991742ef307a0bc5065e24606ddc26a40bb1..9c1e15b0f7734d802e6169434d0f97b52b57566e 100644 (file)
@@ -1266,8 +1266,36 @@ void armature_loc_pose_to_bone(bPoseChannel *pchan, float *inloc, float *outloc)
        VECCOPY(outloc, nLocMat[3]);
 }
 
+
+/* Apply a 4x4 matrix to the pose bone,
+ * similar to object_apply_mat4()
+ */
+void pchan_apply_mat4(bPoseChannel *pchan, float mat[][4])
+{
+       /* location */
+       copy_v3_v3(pchan->loc, mat[3]);
+
+       /* scale */
+       mat4_to_size(pchan->size, mat);
+
+       /* rotation */
+       if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+               float tmp_quat[4];
+
+               /* need to convert to quat first (in temp var)... */
+               mat4_to_quat(tmp_quat, mat);
+               quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, tmp_quat);
+       }
+       else if (pchan->rotmode == ROT_MODE_QUAT) {
+               mat4_to_quat(pchan->quat, mat);
+       }
+       else {
+               mat4_to_eulO(pchan->eul, pchan->rotmode, mat);
+       }
+}
+
 /* Remove rest-position effects from pose-transform for obtaining
- * 'visual' transformation of pose-channel. 
+ * 'visual' transformation of pose-channel.
  * (used by the Visual-Keyframing stuff)
  */
 void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4])
@@ -1895,7 +1923,7 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
        float splineVec[3], scaleFac, radius=1.0f;
        
        /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */
-       where_is_pose_bone(scene, ob, pchan, ctime);
+       where_is_pose_bone(scene, ob, pchan, ctime, 1);
        
        VECCOPY(poseHead, pchan->pose_head);
        VECCOPY(poseTail, pchan->pose_tail);
@@ -2263,8 +2291,10 @@ static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseCha
 
 
 /* The main armature solver, does all constraints excluding IK */
-/* pchan is validated, as having bone and parent pointer */
-void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float ctime)
+/* pchan is validated, as having bone and parent pointer
+ * 'do_extra': when zero skips loc/size/rot, constraints and strip modifiers.
+ */
+void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float ctime, int do_extra)
 {
        Bone *bone, *parbone;
        bPoseChannel *parchan;
@@ -2276,8 +2306,9 @@ void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float cti
        parchan= pchan->parent;
        
        /* this gives a chan_mat with actions (ipos) results */
-       chan_calc_mat(pchan);
-       
+       if(do_extra)    chan_calc_mat(pchan);
+       else                    unit_m4(pchan->chan_mat);
+
        /* construct the posemat based on PoseChannels, that we do before applying constraints */
        /* pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b) */
        
@@ -2342,32 +2373,34 @@ void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float cti
                        add_v3_v3v3(pchan->pose_mat[3], pchan->pose_mat[3], ob->pose->cyclic_offset);
        }
        
-       /* do NLA strip modifiers - i.e. curve follow */
-       do_strip_modifiers(scene, ob, bone, pchan);
-       
-       /* Do constraints */
-       if (pchan->constraints.first) {
-               bConstraintOb *cob;
-               
-               /* make a copy of location of PoseChannel for later */
-               VECCOPY(vec, pchan->pose_mat[3]);
-               
-               /* prepare PoseChannel for Constraint solving 
-                * - makes a copy of matrix, and creates temporary struct to use 
-                */
-               cob= constraints_make_evalob(scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
+       if(do_extra) {
+               /* do NLA strip modifiers - i.e. curve follow */
+               do_strip_modifiers(scene, ob, bone, pchan);
                
-               /* Solve PoseChannel's Constraints */
-               solve_constraints(&pchan->constraints, cob, ctime);     // ctime doesnt alter objects
-               
-               /* cleanup after Constraint Solving 
-                * - applies matrix back to pchan, and frees temporary struct used
-                */
-               constraints_clear_evalob(cob);
-               
-               /* prevent constraints breaking a chain */
-               if(pchan->bone->flag & BONE_CONNECTED) {
-                       VECCOPY(pchan->pose_mat[3], vec);
+               /* Do constraints */
+               if (pchan->constraints.first) {
+                       bConstraintOb *cob;
+
+                       /* make a copy of location of PoseChannel for later */
+                       VECCOPY(vec, pchan->pose_mat[3]);
+
+                       /* prepare PoseChannel for Constraint solving
+                        * - makes a copy of matrix, and creates temporary struct to use
+                        */
+                       cob= constraints_make_evalob(scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
+
+                       /* Solve PoseChannel's Constraints */
+                       solve_constraints(&pchan->constraints, cob, ctime);     // ctime doesnt alter objects
+
+                       /* cleanup after Constraint Solving
+                        * - applies matrix back to pchan, and frees temporary struct used
+                        */
+                       constraints_clear_evalob(cob);
+
+                       /* prevent constraints breaking a chain */
+                       if(pchan->bone->flag & BONE_CONNECTED) {
+                               VECCOPY(pchan->pose_mat[3], vec);
+                       }
                }
        }
        
@@ -2439,7 +2472,7 @@ void where_is_pose (Scene *scene, Object *ob)
                        }
                        /* 5. otherwise just call the normal solver */
                        else if(!(pchan->flag & POSE_DONE)) {
-                               where_is_pose_bone(scene, ob, pchan, ctime);
+                               where_is_pose_bone(scene, ob, pchan, ctime, 1);
                        }
                }
                /* 6. release the IK tree */
index cb4c97f7eb75a9c8cb9922e5bbdec3f7ac61b2ad..88aaf054aeca555db5cfe6d0003ea7f6b6a2a6c5 100644 (file)
@@ -1682,6 +1682,7 @@ void object_mat3_to_rot(Object *ob, float mat[][3], int use_compat)
        }
 }
 
+/* see pchan_apply_mat4() for the equivalent 'pchan' function */
 void object_apply_mat4(Object *ob, float mat[][4])
 {
        float mat3[3][3];
index 700444cb0888c9ab1d28dd64a2f24124b9146b80..4b35499fb629abb50af695756a6b44da123ef7fa 100644 (file)
@@ -2003,7 +2003,7 @@ protected:
                        float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
 
                        BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM);
-                       where_is_pose_bone(scene, ob_arm, pchan, ctime);
+                       where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
 
                        // compute bone local mat
                        if (bone->parent) {
index 04c113db3bee97547dd54f4f29917e64128d8f5d..9d0db52d00747b14e6b89e3fdeb0de5b3cd45c90 100644 (file)
@@ -84,7 +84,8 @@ void ARMATURE_OT_bone_layers(struct wmOperatorType *ot);
 void POSE_OT_hide(struct wmOperatorType *ot);
 void POSE_OT_reveal(struct wmOperatorType *ot);
 
-void POSE_OT_apply(struct wmOperatorType *ot);
+void POSE_OT_armature_apply(struct wmOperatorType *ot);
+void POSE_OT_visual_transform_apply(struct wmOperatorType *ot);
 
 void POSE_OT_rot_clear(struct wmOperatorType *ot);
 void POSE_OT_loc_clear(struct wmOperatorType *ot);
index 9c1812fb61be3f326baeddc6ac9331d6ac2bd1e3..ba2c6597e436b64d5b5c033e3d0a166ae7882e31 100644 (file)
@@ -111,7 +111,8 @@ void ED_operatortypes_armature(void)
        WM_operatortype_append(POSE_OT_hide);
        WM_operatortype_append(POSE_OT_reveal);
        
-       WM_operatortype_append(POSE_OT_apply);
+       WM_operatortype_append(POSE_OT_armature_apply);
+       WM_operatortype_append(POSE_OT_visual_transform_apply);
        
        WM_operatortype_append(POSE_OT_rot_clear);
        WM_operatortype_append(POSE_OT_loc_clear);
@@ -285,9 +286,9 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
        kmi= WM_keymap_add_item(keymap, "POSE_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
                RNA_boolean_set(kmi->ptr, "unselected", 1);
        WM_keymap_add_item(keymap, "POSE_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
-       
-       WM_keymap_add_item(keymap, "POSE_OT_apply", AKEY, KM_PRESS, KM_CTRL, 0);
-       
+
+       WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_apply", AKEY, KM_PRESS, KM_CTRL, 0);
+
        // TODO: clear pose
        WM_keymap_add_item(keymap, "POSE_OT_rot_clear", RKEY, KM_PRESS, KM_ALT, 0);
        WM_keymap_add_item(keymap, "POSE_OT_loc_clear", GKEY, KM_PRESS, KM_ALT, 0);
index 1db6a4b4112a060871cb99a4e95143f294e3a28e..4a3ef38daa63aeb6a644434d8d061bb5665ec0a8 100644 (file)
@@ -637,11 +637,11 @@ static int apply_armature_pose2bones_exec (bContext *C, wmOperator *op)
        return OPERATOR_FINISHED;
 }
 
-void POSE_OT_apply (wmOperatorType *ot)
+void POSE_OT_armature_apply (wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Apply Pose as Rest Pose";
-       ot->idname= "POSE_OT_apply";
+       ot->idname= "POSE_OT_armature_apply";
        ot->description= "Apply the current pose as the new rest pose";
        
        /* callbacks */
@@ -652,6 +652,64 @@ void POSE_OT_apply (wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
+
+/* set the current pose as the restpose */
+static int pose_visual_transform_apply_exec (bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C); // must be active object, not edit-object
+
+       /* don't check if editmode (should be done by caller) */
+       if (ob->type!=OB_ARMATURE)
+               return OPERATOR_CANCELLED;
+
+       /* loop over all selected pchans
+        *
+        * TODO, loop over children before parents if multiple bones
+        * at once are to be predictable*/
+       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
+       {
+               float delta_mat[4][4], imat[4][4], mat[4][4];
+
+               where_is_pose_bone(scene, ob, pchan, CFRA, 1);
+
+               copy_m4_m4(mat, pchan->pose_mat);
+
+               /* calculate pchan->pose_mat without loc/size/rot & constraints applied */
+               where_is_pose_bone(scene, ob, pchan, CFRA, 0);
+               invert_m4_m4(imat, pchan->pose_mat);
+               mul_m4_m4m4(delta_mat, mat, imat);
+
+               pchan_apply_mat4(pchan, delta_mat);
+
+               where_is_pose_bone(scene, ob, pchan, CFRA, 1);
+       }
+       CTX_DATA_END;
+
+       // ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
+
+       return OPERATOR_FINISHED;
+}
+
+void POSE_OT_visual_transform_apply (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Apply Visual Transform to Pose";
+       ot->idname= "POSE_OT_visual_transform_apply";
+       ot->description= "Apply final constrained position of pose bones to their transform.";
+       
+       /* callbacks */
+       ot->exec= pose_visual_transform_apply_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
 /* ---------------------- */
 
 /* Helper function for armature joining - link fixing */
index 84e1ba7354f1d029b844e3a0dd30627040419e8d..9c0f151aa8bfcb6888493ca7b3825bfbfe97f872 100644 (file)
@@ -512,7 +512,7 @@ void iksolver_execute_tree(struct Scene *scene, struct Object *ob,  struct bPose
                /* 4. walk over the tree for regular solving */
                for(a=0; a<tree->totchannel; a++) {
                        if(!(tree->pchan[a]->flag & POSE_DONE)) // successive trees can set the flag
-                               where_is_pose_bone(scene, ob, tree->pchan[a], ctime);
+                               where_is_pose_bone(scene, ob, tree->pchan[a], ctime, 1);
                        // tell blender that this channel was controlled by IK, it's cleared on each where_is_pose()
                        tree->pchan[a]->flag |= POSE_CHAIN;
                }
index 0cff13c70b719323b16f8bfdac3633c6e03c6fb4..af69cb9a996c4e80b45ba587be7069c331f01bf6 100644 (file)
@@ -1532,7 +1532,7 @@ static void execute_scene(Scene* blscene, IK_Scene* ikscene, bItasc* ikparam, fl
                // in animation mode, we must get the bone position from action and constraints
                for(i=0, ikchan=ikscene->channels; i<ikscene->numchan; i++, ++ikchan) {
                        if (!(ikchan->pchan->flag & POSE_DONE))
-                               where_is_pose_bone(blscene, ikscene->blArmature, ikchan->pchan, ctime);
+                               where_is_pose_bone(blscene, ikscene->blArmature, ikchan->pchan, ctime, 1);
                        // tell blender that this channel was controlled by IK, it's cleared on each where_is_pose()
                        ikchan->pchan->flag |= (POSE_DONE|POSE_CHAIN);
                        ikchan->jointValid = 0;