peach request, pose relax - similar to mesh smooth, moves selected pose bones to closer match keyframes on either side.

This commit is contained in:
Campbell Barton
2007-12-04 21:12:23 +00:00
parent 25ea528a29
commit aa2389c539
2 changed files with 157 additions and 2 deletions

View File

@@ -67,6 +67,6 @@ void pose_clear_paths(struct Object *ob);
void pose_flip_names(void);
void pose_activate_flipped_bone(void);
void pose_movetolayer(void);
void pose_relax(void);
#endif

View File

@@ -37,6 +37,7 @@
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
@@ -56,6 +57,7 @@
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_utildefines.h"
#include "BKE_ipo.h"
#include "BIF_editarmature.h"
#include "BIF_editaction.h"
@@ -77,6 +79,9 @@
#include "mydevice.h"
#include "blendef.h"
#include "transform.h"
#include "BIF_transform.h" /* for autokey TFM_TRANSLATION, etc */
void enter_posemode(void)
{
@@ -479,7 +484,7 @@ void pose_special_editmenu(void)
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
nr= pupmenu("Specials%t|Select Constraint Target%x1|Flip Left-Right Names%x2|Calculate Paths%x3|Clear Paths%x4|Clear User Transform %x5");
nr= pupmenu("Specials%t|Select Constraint Target%x1|Flip Left-Right Names%x2|Calculate Paths%x3|Clear Paths%x4|Clear User Transform %x5|Relax Pose %x6");
if(nr==1) {
pose_select_constraint_target();
}
@@ -497,6 +502,9 @@ void pose_special_editmenu(void)
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
BIF_undo_push("Clear User Transform Pose");
}
else if(nr==6) {
pose_relax();
}
}
void pose_add_IK(void)
@@ -1070,3 +1078,150 @@ void pose_movetolayer(void)
allqueue(REDRAWBUTSEDIT, 0);
}
}
/* for use with pose_relax only */
static int pose_relax_icu(struct IpoCurve *icu, float framef, float *val, float *frame_prev, float *frame_next)
{
if (!icu) {
return 0;
} else {
BezTriple *bezt = icu->bezt;
BezTriple *bezt_prev=NULL, *bezt_next=NULL;
float w1, w2, wtot;
int i;
for (i=0; i < icu->totvert; i++, bezt++) {
if (bezt->vec[1][0] < framef - 1.0) {
bezt_prev = bezt;
} else {
break;
}
}
if (bezt_prev==NULL) return 0;
/* advance to the next, dont need to advance i */
bezt = bezt_prev+1;
for (; i < icu->totvert; i++, bezt++) {
if (bezt->vec[1][0] > framef + 1.0) {
bezt_next = bezt;
break;
}
}
if (bezt_next==NULL) return 0;
if (val) {
w1 = framef - bezt_prev->vec[1][0];
w2 = bezt_next->vec[1][0] - framef;
wtot = w1 + w2;
w1=w1/wtot;
w2=w2/wtot;
#if 0
val = (bezt_prev->vec[1][1] * w2) + (bezt_next->vec[1][1] * w1);
#else
/* apply the value with a hard coded 6th */
*val = (((bezt_prev->vec[1][1] * w2) + (bezt_next->vec[1][1] * w1)) + (*val * 5.0f)) / 6.0f;
#endif
}
if (frame_prev) *frame_prev = bezt_prev->vec[1][0];
if (frame_next) *frame_next = bezt_next->vec[1][0];
return 1;
}
}
void pose_relax()
{
Object *ob = OBACT;
bPose *pose;
bAction *act;
bArmature *arm;
IpoCurve *icu_w, *icu_x, *icu_y, *icu_z;
bPoseChannel *pchan;
bActionChannel *achan;
float framef = F_CFRA;
float frame_prev, frame_next;
float quat_prev[4], quat_next[4], quat_interp[4], quat_orig[4];
int do_scale = 0;
int do_loc = 0;
int do_quat = 0;
int flag = 0;
if (!ob) return;
pose = ob->pose;
act = ob->action;
arm = (bArmature *)ob->data;
if (!pose || !act || !arm) return;
for (pchan=pose->chanbase.first; pchan; pchan= pchan->next){
if(pchan->bone->layer & arm->layer) {
if(pchan->bone->flag & BONE_SELECTED) {
/* do we have an ipo curve? */
achan= get_action_channel(act, pchan->name);
if(achan->ipo) {
/*calc_ipo(achan->ipo, ctime);*/
do_loc += pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_X), framef, &pchan->loc[0], NULL, NULL);
do_loc += pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_Y), framef, &pchan->loc[1], NULL, NULL);
do_loc += pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_Z), framef, &pchan->loc[2], NULL, NULL);
do_scale += pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_X), framef, &pchan->size[0], NULL, NULL);
do_scale += pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_Y), framef, &pchan->size[1], NULL, NULL);
do_scale += pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_Z), framef, &pchan->size[2], NULL, NULL);
if( ((icu_w = find_ipocurve(achan->ipo, AC_QUAT_W))) &&
((icu_x = find_ipocurve(achan->ipo, AC_QUAT_X))) &&
((icu_y = find_ipocurve(achan->ipo, AC_QUAT_Y))) &&
((icu_z = find_ipocurve(achan->ipo, AC_QUAT_Z))) )
{
/* use the quatw keyframe as a basis for others */
if (pose_relax_icu(icu_w, framef, NULL, &frame_prev, &frame_next)) {
/* get 2 quats */
quat_prev[0] = eval_icu(icu_w, frame_prev);
quat_prev[1] = eval_icu(icu_x, frame_prev);
quat_prev[2] = eval_icu(icu_y, frame_prev);
quat_prev[3] = eval_icu(icu_z, frame_prev);
quat_next[0] = eval_icu(icu_w, frame_next);
quat_next[1] = eval_icu(icu_x, frame_next);
quat_next[2] = eval_icu(icu_y, frame_next);
quat_next[3] = eval_icu(icu_z, frame_next);
#if 0
/* apply the setting, completely smooth */
QuatInterpol(pchan->quat, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) );
#else
/* tricky interpolation */
QuatInterpol(quat_interp, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) );
QUATCOPY(quat_orig, pchan->quat);
QuatInterpol(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f);
/* done */
#endif
do_quat++;
}
}
}
}
}
}
ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
/* auto-keyframing */
if (do_loc) flag |= TFM_TRANSLATION;
if (do_scale) flag |= TFM_RESIZE;
if (do_quat) flag |= TFM_ROTATION;
autokeyframe_pose_cb_func(ob, flag, 0);
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
BIF_undo_push("Relax Pose");
}