== Auto-IK ==
-- Peach request (from wiki feature request list) -- When translating a bone using Auto-IK, you can now use the ScrollWheel on the Mouse or the Page Up/Down keys to adjust the chain length. Notes: * Up decreases the length, while Down increases it. * The previously used chain-length is stored per scene * Currently, it might be too sensitive. Also, it would help to have some kind of indication of the current chain-length somewhere... * The chain length specified this way determines the MAXIMUM chain length possible for all chains (if 0, then the default chain-length is used). Chains are clamped to have a chain length which does not exceed the default chain length. This restriction may be removed following further feedback...
This commit is contained in:
parent
b71d55b055
commit
faf638238d
|
@ -230,7 +230,7 @@ typedef struct TransInfo {
|
|||
// for manipulator exceptions, like scaling using center point, drawing help lines
|
||||
#define T_USES_MANIPULATOR (1 << 7)
|
||||
|
||||
/* restrictions flags */
|
||||
/* restrictions flags */
|
||||
#define T_ALL_RESTRICTIONS ((1 << 8)|(1 << 9)|(1 << 10))
|
||||
#define T_NO_CONSTRAINT (1 << 8)
|
||||
#define T_NULL_ONE (1 << 9)
|
||||
|
@ -239,14 +239,17 @@ typedef struct TransInfo {
|
|||
#define T_PROP_EDIT (1 << 11)
|
||||
#define T_PROP_CONNECTED (1 << 12)
|
||||
|
||||
/* if MMB is pressed or not */
|
||||
/* if MMB is pressed or not */
|
||||
#define T_MMB_PRESSED (1 << 13)
|
||||
|
||||
#define T_V3D_ALIGN (1 << 14)
|
||||
#define T_2D_EDIT (1 << 15) /* for 2d views like uv or ipo */
|
||||
/* for 2d views like uv or ipo */
|
||||
#define T_2D_EDIT (1 << 15)
|
||||
#define T_CLIP_UV (1 << 16)
|
||||
|
||||
#define T_FREE_CUSTOMDATA (1 << 17)
|
||||
/* auto-ik is on */
|
||||
#define T_AUTOIK (1 << 18)
|
||||
|
||||
/* ******************************************************************************** */
|
||||
|
||||
|
@ -375,6 +378,8 @@ void sort_trans_data_dist(TransInfo *t);
|
|||
void add_tdi_poin(float *poin, float *old, float delta);
|
||||
void special_aftertrans_update(TransInfo *t);
|
||||
|
||||
void transform_autoik_update(TransInfo *t, short mode);
|
||||
|
||||
/* auto-keying stuff used by special_aftertrans_update */
|
||||
void autokeyframe_ob_cb_func(struct Object *ob, int tmode);
|
||||
void autokeyframe_pose_cb_func(struct Object *ob, int tmode, short targetless_ik);
|
||||
|
@ -458,3 +463,4 @@ char handleNumInput(NumInput *n, unsigned short event);
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -126,7 +126,8 @@ typedef struct bKinematicConstraint {
|
|||
Object *tar;
|
||||
short iterations; /* Maximum number of iterations to try */
|
||||
short flag; /* Like CONSTRAINT_IK_TIP */
|
||||
int rootbone; /* index to rootbone, if zero go all the way to mother bone */
|
||||
short rootbone; /* index to rootbone, if zero go all the way to mother bone */
|
||||
short max_rootbone; /* for auto-ik, maximum length of chain */
|
||||
char subtarget[32]; /* String to specify sub-object target */
|
||||
|
||||
Object *poletar; /* Pole vector target */
|
||||
|
|
|
@ -363,7 +363,8 @@ typedef struct ToolSettings {
|
|||
short uvcalc_mapalign;
|
||||
short uvcalc_flag;
|
||||
|
||||
short pad2;
|
||||
/* Auto-IK */
|
||||
short autoik_chainlen;
|
||||
|
||||
/* Image Paint (8 byte aligned please!) */
|
||||
struct ImagePaintSettings imapaint;
|
||||
|
|
|
@ -815,7 +815,10 @@ static void transformEvent(unsigned short event, short val) {
|
|||
break;
|
||||
case PAGEUPKEY:
|
||||
case WHEELDOWNMOUSE:
|
||||
if(Trans.flag & T_PROP_EDIT) {
|
||||
if (Trans.flag & T_AUTOIK) {
|
||||
transform_autoik_update(&Trans, 1);
|
||||
}
|
||||
else if(Trans.flag & T_PROP_EDIT) {
|
||||
Trans.propsize*= 1.1f;
|
||||
calculatePropRatio(&Trans);
|
||||
}
|
||||
|
@ -831,7 +834,10 @@ static void transformEvent(unsigned short event, short val) {
|
|||
break;
|
||||
case PAGEDOWNKEY:
|
||||
case WHEELUPMOUSE:
|
||||
if(Trans.flag & T_PROP_EDIT) {
|
||||
if (Trans.flag & T_AUTOIK) {
|
||||
transform_autoik_update(&Trans, -1);
|
||||
}
|
||||
else if (Trans.flag & T_PROP_EDIT) {
|
||||
Trans.propsize*= 0.90909090f;
|
||||
calculatePropRatio(&Trans);
|
||||
}
|
||||
|
@ -4094,3 +4100,4 @@ void BIF_TransformSetUndo(char *str)
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -695,6 +695,62 @@ static void set_pose_transflags(TransInfo *t, Object *ob)
|
|||
t->mode= TFM_ROTATION;
|
||||
}
|
||||
|
||||
|
||||
/* -------- Auto-IK ---------- */
|
||||
|
||||
/* adjust pose-channel's auto-ik chainlen */
|
||||
static void pchan_autoik_adjust (bPoseChannel *pchan, short chainlen)
|
||||
{
|
||||
bConstraint *con;
|
||||
|
||||
/* don't bother to search if no valid constraints */
|
||||
if ((pchan->constflag & (PCHAN_HAS_IK|PCHAN_HAS_TARGET))==0)
|
||||
return;
|
||||
|
||||
/* check if pchan has ik-constraint */
|
||||
for (con= pchan->constraints.first; con; con= con->next) {
|
||||
if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
|
||||
bKinematicConstraint *data= con->data;
|
||||
|
||||
/* only accept if a temporary one (for auto-ik) */
|
||||
if (data->flag & CONSTRAINT_IK_TEMP) {
|
||||
/* chainlen is new chainlen, but is limited by maximum chainlen */
|
||||
if ((chainlen==0) || (chainlen > data->max_rootbone))
|
||||
data->rootbone= data->max_rootbone;
|
||||
else
|
||||
data->rootbone= chainlen;
|
||||
printf("chainlen = %d, max = %d, new = %d\n", chainlen, data->max_rootbone, data->rootbone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* change the chain-length of auto-ik */
|
||||
void transform_autoik_update (TransInfo *t, short mode)
|
||||
{
|
||||
short *chainlen= &G.scene->toolsettings->autoik_chainlen;
|
||||
bPoseChannel *pchan;
|
||||
|
||||
/* mode determines what change to apply to chainlen */
|
||||
if (mode == 1) {
|
||||
/* mode=1 is from WHEELMOUSEDOWN... increases len */
|
||||
(*chainlen)++;
|
||||
}
|
||||
else if (mode == -1) {
|
||||
/* mode==-1 is from WHEELMOUSEUP... decreases len */
|
||||
if (*chainlen > 0) (*chainlen)--;
|
||||
}
|
||||
|
||||
/* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
|
||||
if (ELEM(NULL, t->poseobj, t->poseobj->pose))
|
||||
return;
|
||||
|
||||
/* apply to all pose-channels */
|
||||
for (pchan=t->poseobj->pose->chanbase.first; pchan; pchan=pchan->next) {
|
||||
pchan_autoik_adjust(pchan, *chainlen);
|
||||
}
|
||||
}
|
||||
|
||||
/* frees temporal IKs */
|
||||
static void pose_grab_with_ik_clear(Object *ob)
|
||||
{
|
||||
|
@ -722,19 +778,19 @@ static void pose_grab_with_ik_clear(Object *ob)
|
|||
}
|
||||
}
|
||||
|
||||
/* adds the IK to pchan */
|
||||
static void pose_grab_with_ik_add(bPoseChannel *pchan)
|
||||
/* adds the IK to pchan - returns if added */
|
||||
static short pose_grab_with_ik_add(bPoseChannel *pchan)
|
||||
{
|
||||
bKinematicConstraint *data;
|
||||
bConstraint *con;
|
||||
|
||||
if (pchan == NULL) { // Sanity check
|
||||
return;
|
||||
}
|
||||
/* Sanity check */
|
||||
if (pchan == NULL)
|
||||
return 0;
|
||||
|
||||
/* rule: not if there's already an IK on this channel */
|
||||
for (con= pchan->constraints.first; con; con= con->next)
|
||||
if(con->type==CONSTRAINT_TYPE_KINEMATIC)
|
||||
if (con->type==CONSTRAINT_TYPE_KINEMATIC)
|
||||
break;
|
||||
|
||||
if (con) {
|
||||
|
@ -742,7 +798,7 @@ static void pose_grab_with_ik_add(bPoseChannel *pchan)
|
|||
data= has_targetless_ik(pchan);
|
||||
if (data)
|
||||
data->flag |= CONSTRAINT_IK_AUTO;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
con = add_new_constraint(CONSTRAINT_TYPE_KINEMATIC);
|
||||
|
@ -764,73 +820,79 @@ static void pose_grab_with_ik_add(bPoseChannel *pchan)
|
|||
data->rootbone++;
|
||||
pchan= pchan->parent;
|
||||
}
|
||||
|
||||
/* make a copy of maximum chain-length */
|
||||
data->max_rootbone= data->rootbone;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* bone is a canditate to get IK, but we don't do it if it has children connected */
|
||||
static void pose_grab_with_ik_children(bPose *pose, Bone *bone)
|
||||
static short pose_grab_with_ik_children(bPose *pose, Bone *bone)
|
||||
{
|
||||
Bone *bonec;
|
||||
int wentdeeper= 0;
|
||||
short wentdeeper=0, added=0;
|
||||
|
||||
/* go deeper if children & children are connected */
|
||||
for(bonec= bone->childbase.first; bonec; bonec= bonec->next) {
|
||||
if(bonec->flag & BONE_CONNECTED) {
|
||||
for (bonec= bone->childbase.first; bonec; bonec= bonec->next) {
|
||||
if (bonec->flag & BONE_CONNECTED) {
|
||||
wentdeeper= 1;
|
||||
pose_grab_with_ik_children(pose, bonec);
|
||||
added+= pose_grab_with_ik_children(pose, bonec);
|
||||
}
|
||||
}
|
||||
if(wentdeeper==0) {
|
||||
if (wentdeeper==0) {
|
||||
bPoseChannel *pchan= get_pose_channel(pose, bone->name);
|
||||
if(pchan)
|
||||
pose_grab_with_ik_add(pchan);
|
||||
if (pchan)
|
||||
added+= pose_grab_with_ik_add(pchan);
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
/* main call which adds temporal IK chains */
|
||||
static void pose_grab_with_ik(Object *ob)
|
||||
static short pose_grab_with_ik(Object *ob)
|
||||
{
|
||||
bArmature *arm;
|
||||
bPoseChannel *pchan, *pchansel= NULL;
|
||||
Bone *bonec;
|
||||
|
||||
if(ob==NULL || ob->pose==NULL || (ob->flag & OB_POSEMODE)==0)
|
||||
return;
|
||||
if (ob==NULL || ob->pose==NULL || (ob->flag & OB_POSEMODE)==0)
|
||||
return 0;
|
||||
|
||||
arm = ob->data;
|
||||
|
||||
/* rule: only one Bone */
|
||||
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||
if(pchan->bone->layer & arm->layer) {
|
||||
if(pchan->bone->flag & BONE_SELECTED) {
|
||||
if(pchansel)
|
||||
for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||
if (pchan->bone->layer & arm->layer) {
|
||||
if (pchan->bone->flag & BONE_SELECTED) {
|
||||
if (pchansel)
|
||||
break;
|
||||
pchansel= pchan;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(pchan || pchansel==NULL) return;
|
||||
if (pchan || pchansel==NULL) return 0;
|
||||
|
||||
/* rule: no IK for solitary (unconnected) bone */
|
||||
for(bonec=pchansel->bone->childbase.first; bonec; bonec=bonec->next) {
|
||||
if(bonec->flag & BONE_CONNECTED) {
|
||||
for (bonec=pchansel->bone->childbase.first; bonec; bonec=bonec->next) {
|
||||
if (bonec->flag & BONE_CONNECTED) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((pchansel->bone->flag & BONE_CONNECTED)==0 && (bonec == NULL)) return;
|
||||
if ((pchansel->bone->flag & BONE_CONNECTED)==0 && (bonec == NULL)) return 0;
|
||||
|
||||
/* rule: if selected Bone is not a root bone, it gets a temporal IK */
|
||||
if(pchansel->parent) {
|
||||
if (pchansel->parent) {
|
||||
/* only adds if there's no IK yet */
|
||||
pose_grab_with_ik_add(pchansel);
|
||||
return pose_grab_with_ik_add(pchansel);
|
||||
}
|
||||
else {
|
||||
/* rule: go over the children and add IK to the tips */
|
||||
pose_grab_with_ik_children(ob->pose, pchansel->bone);
|
||||
return pose_grab_with_ik_children(ob->pose, pchansel->bone);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* only called with pose mode active object now */
|
||||
static void createTransPose(TransInfo *t, Object *ob)
|
||||
{
|
||||
|
@ -838,6 +900,7 @@ static void createTransPose(TransInfo *t, Object *ob)
|
|||
bPoseChannel *pchan;
|
||||
TransData *td;
|
||||
TransDataExtension *tdx;
|
||||
short ik_on= 0;
|
||||
int i;
|
||||
|
||||
t->total= 0;
|
||||
|
@ -855,8 +918,10 @@ static void createTransPose(TransInfo *t, Object *ob)
|
|||
if (!(ob->lay & G.vd->lay)) return;
|
||||
|
||||
/* do we need to add temporal IK chains? */
|
||||
if((arm->flag & ARM_AUTO_IK) && t->mode==TFM_TRANSLATION)
|
||||
pose_grab_with_ik(ob);
|
||||
if ((arm->flag & ARM_AUTO_IK) && t->mode==TFM_TRANSLATION) {
|
||||
ik_on= pose_grab_with_ik(ob);
|
||||
if (ik_on) t->flag |= T_AUTOIK;
|
||||
}
|
||||
|
||||
/* set flags and count total (warning, can change transform to rotate) */
|
||||
set_pose_transflags(t, ob);
|
||||
|
@ -890,6 +955,8 @@ static void createTransPose(TransInfo *t, Object *ob)
|
|||
|
||||
if(td != (t->data+t->total)) printf("Bone selection count error\n");
|
||||
|
||||
/* initialise initial auto=ik chainlen's? */
|
||||
if (ik_on) transform_autoik_update(t, 0);
|
||||
}
|
||||
|
||||
/* ********************* armature ************** */
|
||||
|
@ -3539,3 +3606,4 @@ void createTransData(TransInfo *t)
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue