diff options
author | Campbell Barton <ideasman42@gmail.com> | 2010-02-19 18:34:26 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2010-02-19 18:34:26 +0300 |
commit | 3bf2715039eecee409d3b6c3639e853b6750e77c (patch) | |
tree | 55c5f083013ba9d8eee6ecff9be93d037ab4cf63 /source/blender | |
parent | 3b9fdfa9e1905a01230be7b15174c711c2b0f974 (diff) |
apply visual transform to pose
So constrainted bones can have their transform applied to their loc/scale/rot, then remove the constraints
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_armature.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 97 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 1 | ||||
-rw-r--r-- | source/blender/collada/DocumentExporter.cpp | 2 | ||||
-rw-r--r-- | source/blender/editors/armature/armature_intern.h | 3 | ||||
-rw-r--r-- | source/blender/editors/armature/armature_ops.c | 9 | ||||
-rw-r--r-- | source/blender/editors/armature/editarmature.c | 62 | ||||
-rw-r--r-- | source/blender/ikplugin/intern/iksolver_plugin.c | 2 | ||||
-rw-r--r-- | source/blender/ikplugin/intern/itasc_plugin.cpp | 2 |
9 files changed, 139 insertions, 43 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 30bed6bb335..e142fceebda 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -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); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index b568991742e..9c1e15b0f77 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -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 */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index cb4c97f7eb7..88aaf054aec 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -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]; diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index 700444cb088..4b35499fb62 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -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) { diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 04c113db3be..9d0db52d007 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -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); diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index 9c1812fb61b..ba2c6597e43 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -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); diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index 1db6a4b4112..4a3ef38daa6 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -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 */ diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c index 84e1ba7354f..9c0f151aa8b 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.c +++ b/source/blender/ikplugin/intern/iksolver_plugin.c @@ -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; } diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index 0cff13c70b7..af69cb9a996 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -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; |