apply visual transform to pose
So constrainted bones can have their transform applied to their loc/scale/rot, then remove the constraints
This commit is contained in:
@@ -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
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
if(do_extra) {
|
||||
/* do NLA strip modifiers - i.e. curve follow */
|
||||
do_strip_modifiers(scene, ob, bone, pchan);
|
||||
|
||||
/* 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);
|
||||
/* 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 */
|
||||
|
@@ -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];
|
||||
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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 */
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user