Patch #17500: fixes: multiple IK's on bone + targetless IK

Submitted by: Teppo Kansala (teppoka)

See patch report for details of fixes.
https://projects.blender.org/tracker/index.php?func=detail&aid=17500&group_id=9&atid=127

Note: the patch submitter's test files were quite nice, and would be good to have in our regression suite.
This commit is contained in:
Joshua Leung 2008-09-29 04:00:42 +00:00
parent 0b622fc07f
commit 32b733dafb
5 changed files with 52 additions and 33 deletions

@ -1573,21 +1573,16 @@ static void initialize_posetree(struct Object *ob, bPoseChannel *pchan_tip)
/* find IK constraint, and validate it */
for(con= pchan_tip->constraints.first; con; con= con->next) {
if(con->type==CONSTRAINT_TYPE_KINEMATIC) break;
if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
data=(bKinematicConstraint*)con->data;
if (data->flag & CONSTRAINT_IK_AUTO) break;
if (data->tar==NULL) continue;
if (data->tar->type==OB_ARMATURE && data->subtarget[0]==0) continue;
if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0)) break;
}
}
if(con==NULL) return;
data=(bKinematicConstraint*)con->data;
/* two types of targets */
if(data->flag & CONSTRAINT_IK_AUTO);
else {
if(con->flag & CONSTRAINT_DISABLE) return; /* checked in editconstraint.c */
if(con->enforce == 0.0f) return;
if(data->tar==NULL) return;
if(data->tar->type==OB_ARMATURE && data->subtarget[0]==0) return;
}
/* exclude tip from chain? */
if(!(data->flag & CONSTRAINT_IK_TIP))
pchan_tip= pchan_tip->parent;

@ -463,7 +463,9 @@ typedef enum B_CONSTRAINTCHANNEL_FLAG {
/* bKinematicConstraint->flag */
#define CONSTRAINT_IK_TIP 1
#define CONSTRAINT_IK_ROT 2
/* targetless */
#define CONSTRAINT_IK_AUTO 4
/* autoik */
#define CONSTRAINT_IK_TEMP 8
#define CONSTRAINT_IK_STRETCH 16
#define CONSTRAINT_IK_POS 32

@ -1301,7 +1301,7 @@ static void pchan_draw_IK_root_lines(bPoseChannel *pchan, short only_temp)
bPoseChannel *parchan;
for (con= pchan->constraints.first; con; con= con->next) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce!=0.0)) {
bKinematicConstraint *data = (bKinematicConstraint*)con->data;
int segcount= 0;
@ -2573,3 +2573,4 @@ int draw_armature(Base *base, int dt, int flag)
/* *************** END Armature drawing ******************* */

@ -213,6 +213,8 @@ int pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
bConstraint *con;
Bone *bone;
/* No need to check if constraint is active (has influence),
* since all constraints with CONSTRAINT_IK_AUTO are active */
for(con= pchan->constraints.first; con; con= con->next) {
if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
bKinematicConstraint *data= con->data;
@ -1733,3 +1735,4 @@ void pose_flipquats(void)
autokeyframe_pose_cb_func(ob, TFM_ROTATION, 0);
}

@ -397,7 +397,7 @@ static bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
bConstraint *con= pchan->constraints.first;
for(;con; con= con->next) {
if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
if(con->type==CONSTRAINT_TYPE_KINEMATIC && (con->enforce!=0.0)) {
bKinematicConstraint *data= con->data;
if(data->tar==NULL)
@ -505,12 +505,17 @@ static short apply_targetless_ik(Object *ob)
Mat3ToQuat(rmat3, parchan->quat);
/* for size, remove rotation */
QuatToMat3(parchan->quat, qmat);
Mat3Inv(imat, qmat);
Mat3MulMat3(smat, rmat3, imat);
Mat3ToSize(smat, parchan->size);
/* causes problems with some constraints (so apply only if needed) */
if (data->flag & CONSTRAINT_IK_STRETCH) {
QuatToMat3(parchan->quat, qmat);
Mat3Inv(imat, qmat);
Mat3MulMat3(smat, rmat3, imat);
Mat3ToSize(smat, parchan->size);
}
VECCOPY(parchan->loc, rmat[3]);
/* causes problems with some constraints (e.g. childof), so disable this */
/* as it is IK shouldn't affect location directly */
/* VECCOPY(parchan->loc, rmat[3]); */
}
}
@ -711,7 +716,7 @@ static void pchan_autoik_adjust (bPoseChannel *pchan, short chainlen)
/* check if pchan has ik-constraint */
for (con= pchan->constraints.first; con; con= con->next) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce!=0.0)) {
bKinematicConstraint *data= con->data;
/* only accept if a temporary one (for auto-ik) */
@ -763,6 +768,7 @@ static void pose_grab_with_ik_clear(Object *ob)
/* clear all temporary lock flags */
pchan->ikflag &= ~(BONE_IK_NO_XDOF_TEMP|BONE_IK_NO_YDOF_TEMP|BONE_IK_NO_ZDOF_TEMP);
pchan->constflag &= ~(PCHAN_HAS_IK|PCHAN_HAS_TARGET);
/* remove all temporary IK-constraints added */
for (con= pchan->constraints.first; con; con= con->next) {
if (con->type==CONSTRAINT_TYPE_KINEMATIC) {
@ -771,9 +777,11 @@ static void pose_grab_with_ik_clear(Object *ob)
BLI_remlink(&pchan->constraints, con);
MEM_freeN(con->data);
MEM_freeN(con);
pchan->constflag &= ~(PCHAN_HAS_IK|PCHAN_HAS_TARGET);
break;
continue;
}
pchan->constflag |= PCHAN_HAS_IK;
if(data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]==0))
pchan->constflag |= PCHAN_HAS_TARGET;
}
}
}
@ -784,6 +792,7 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
{
bKinematicConstraint *data;
bConstraint *con;
bConstraint *targetless = 0;
/* Sanity check */
if (pchan == NULL)
@ -791,23 +800,31 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
/* 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)
break;
}
if (con) {
/* but, if this is a targetless IK, we make it auto anyway (for the children loop) */
data= has_targetless_ik(pchan);
if (data)
data->flag |= CONSTRAINT_IK_AUTO;
return 0;
if (con->type==CONSTRAINT_TYPE_KINEMATIC) {
bKinematicConstraint *data= con->data;
if(data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]==0)) {
targetless = con;
/* but, if this is a targetless IK, we make it auto anyway (for the children loop) */
if (con->enforce!=0.0) {
targetless->flag |= CONSTRAINT_IK_AUTO;
return 0;
}
}
if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0))
return 0;
}
}
con = add_new_constraint(CONSTRAINT_TYPE_KINEMATIC);
BLI_addtail(&pchan->constraints, con);
pchan->constflag |= (PCHAN_HAS_IK|PCHAN_HAS_TARGET); /* for draw, but also for detecting while pose solving */
data= con->data;
data->flag= CONSTRAINT_IK_TIP|CONSTRAINT_IK_TEMP|CONSTRAINT_IK_AUTO;
if (targetless) { /* if exists use values from last targetless IK-constraint as base */
*data = *((bKinematicConstraint*)targetless->data);
}
else
data->flag= CONSTRAINT_IK_TIP;
data->flag |= CONSTRAINT_IK_TEMP|CONSTRAINT_IK_AUTO;
VECCOPY(data->grabtarget, pchan->pose_tail);
data->rootbone= 1;
@ -4279,3 +4296,4 @@ void createTransData(TransInfo *t)