From 89317afbdfe19da951aeb2fa7764cc2f60b39f4d Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 12 Nov 2007 04:17:03 +0000 Subject: Patch #7767: Constraint Subtargets can now target anywhere on a bone, not just the head or tail Patch by: Roland Hess (harkyman) For example, a constraint can be sub-targeted at the 50% (or 31.2% or 85% etc.) point of its target bone, giving you enormous rigging flexibility and removing the need for complex contraptions to do such things as: - A bone whose base slides only between to points on a rig (CopyLoc with a variable, animated subtarget point) - Bones that attach to multiple points along another bone (CopyLocs, each with a different head/tail percentage) - Bones that need to stretch to a point midway between specific spots on two other bones (old way: too crazy to mention; new way: stretch bone between points on end bones, then another stretch to the midpoint of the first stretch) It is only used for the constraint types for which it is relevant: CopyLoc, TrackTo, StretchTo and MinMax, TrackTo, and Floor. Notes: - This is accessed by the Head/Tail number-slider. - This value can be animated per constraint - The old "Copy Bone Tail" option for the CopyLoc constraint has been automatically converted to 1.0 Head/Bone values for the affected constraints - In the code, this value is in the bConstraint struct, so it is available for all constraints, even though only a few implement it. --- source/blender/blenkernel/intern/action.c | 4 +- source/blender/blenkernel/intern/constraint.c | 74 +++++++++++--------------- source/blender/blenkernel/intern/ipo.c | 2 +- source/blender/blenloader/intern/readfile.c | 28 +++++++--- source/blender/makesdna/DNA_constraint_types.h | 7 ++- source/blender/makesdna/DNA_ipo_types.h | 7 ++- source/blender/src/buttons_object.c | 47 ++++++++++++---- source/blender/src/editipo_lib.c | 5 +- 8 files changed, 107 insertions(+), 67 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index d202178fc0a..bd5e5d612c6 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -305,8 +305,10 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan pchan->flag= chan->flag; con= chan->constraints.first; - for(pcon= pchan->constraints.first; pcon; pcon= pcon->next) + for(pcon= pchan->constraints.first; pcon; pcon= pcon->next) { pcon->enforce= con->enforce; + pcon->headtail= con->headtail; + } } /* checks for IK constraint, can do more constraints flags later */ diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index f50cb2c6be0..558c90b37db 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -194,6 +194,11 @@ void do_constraint_channels (ListBase *conbase, ListBase *chanbase, float ctime, con->enforce = CLAMPIS(icu->curval, 0.0f, 1.0f); } break; + case CO_HEADTAIL: + { + con->headtail = icu->curval; + } + break; } } } @@ -224,6 +229,9 @@ void unique_constraint_name (bConstraint *con, ListBase *list) } /* See if we even need to do this */ + if (list == NULL) + return; + for (curcon = list->first; curcon; curcon=curcon->next) { if (curcon != con) { if (!strcmp(curcon->name, con->name)) { @@ -710,7 +718,7 @@ static void contarget_get_lattice_mat (Object *ob, char *substring, float mat[][ /* generic function to get the appropriate matrix for most target cases */ /* The cases where the target can be object data have not been implemented */ -static void constraint_target_to_mat4 (Object *ob, char *substring, float mat[][4], short from, short to) +static void constraint_target_to_mat4 (Object *ob, char *substring, float mat[][4], short from, short to, float headtail) { /* Case OBJECT */ if (!strlen(substring)) { @@ -744,7 +752,22 @@ static void constraint_target_to_mat4 (Object *ob, char *substring, float mat[][ * PoseChannel by the Armature Object's Matrix to get a worldspace * matrix. */ - Mat4MulMat4(mat, pchan->pose_mat, ob->obmat); + if (headtail < 0.000001) { + /* skip length interpolation if set to head */ + Mat4MulMat4(mat, pchan->pose_mat, ob->obmat); + } + else { + float tempmat[4][4], loc[3]; + + /* interpolate along length of bone */ + VecLerpf(loc, pchan->pose_head, pchan->pose_tail, headtail); + + /* use interpolated distance for subtarget */ + Mat4CpyMat4(tempmat, pchan->pose_mat); + VecCopyf(tempmat[3], loc); + + Mat4MulMat4(mat, tempmat, ob->obmat); + } } else Mat4CpyMat4(mat, ob->obmat); @@ -794,7 +817,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = { static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) { if (VALID_CONS_TARGET(ct)) - constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); else if (ct) Mat4One(ct->matrix); } @@ -1192,7 +1215,7 @@ static void kinematic_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstra bKinematicConstraint *data= con->data; if (VALID_CONS_TARGET(ct)) - constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); else if (ct) { if (data->flag & CONSTRAINT_IK_AUTO) { Object *ob= cob->ob; @@ -1564,43 +1587,6 @@ static void loclike_flush_tars (bConstraint *con, ListBase *list, short nocopy) } } -static void loclike_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) -{ - bLocateLikeConstraint *data = con->data; - - if (VALID_CONS_TARGET(ct)) { - if (ct->tar->type==OB_ARMATURE && strlen(ct->subtarget)) { - /* Pose-Channels for the CopyLoc target are handled specially, so that - * we can support using the bone-tip as an option. - */ - bPoseChannel *pchan; - float tmat[4][4]; - - pchan = get_pose_channel(ct->tar->pose, ct->subtarget); - if (pchan) { - Mat4CpyMat4(tmat, pchan->pose_mat); - - if (data->flag & LOCLIKE_TIP) { - VECCOPY(tmat[3], pchan->pose_tail); - } - - Mat4MulMat4(ct->matrix, tmat, ct->tar->obmat); - } - else - Mat4CpyMat4(ct->matrix, ct->tar->obmat); - - /* convert matrix space as required */ - constraint_mat_convertspace(ct->tar, pchan, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); - } - else { - /* get target matrix as is done normally for other constraints */ - constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); - } - } - else if (ct) - Mat4One(ct->matrix); -} - static void loclike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) { bLocateLikeConstraint *data= con->data; @@ -1644,7 +1630,7 @@ static bConstraintTypeInfo CTI_LOCLIKE = { loclike_new_data, /* new data */ loclike_get_tars, /* get constraint targets */ loclike_flush_tars, /* flush constraint targets */ - loclike_get_tarmat, /* get target matrix */ + default_get_tarmat, /* get target matrix */ loclike_evaluate /* evaluate */ }; @@ -1896,7 +1882,7 @@ static void pycon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintT /* firstly calculate the matrix the normal way, then let the py-function override * this matrix if it needs to do so */ - constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); BPY_pyconstraint_target(data, ct); } else if (ct) @@ -1987,7 +1973,7 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint Mat4One(ct->matrix); /* get the transform matrix of the target */ - constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space); + constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); /* determine where in transform range target is */ /* data->type is mapped as follows for backwards compatability: diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 107633eda64..83b845a0064 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -85,7 +85,7 @@ */ int co_ar[CO_TOTIPO]= { - CO_ENFORCE + CO_ENFORCE, CO_HEADTAIL }; int ob_ar[OB_TOTIPO]= { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 615d1759f66..2e4c56dbc9c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -6827,11 +6827,11 @@ static void do_versions(FileData *fd, Library *lib, Main *main) bConstraint *con; bConstraintTarget *ct; - for(ob = main->object.first; ob; ob= ob->id.next) { - if(ob->pose) { - for(pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) { - for(con=pchan->constraints.first; con; con=con->next) { - if(con->type==CONSTRAINT_TYPE_PYTHON) { + for (ob = main->object.first; ob; ob= ob->id.next) { + if (ob->pose) { + for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) { + for (con=pchan->constraints.first; con; con=con->next) { + if (con->type == CONSTRAINT_TYPE_PYTHON) { bPythonConstraint *data= (bPythonConstraint *)con->data; if (data->tar) { /* version patching needs to be done */ @@ -6849,12 +6849,19 @@ static void do_versions(FileData *fd, Library *lib, Main *main) strcpy(data->subtarget, ""); } } + else if (con->type == CONSTRAINT_TYPE_LOCLIKE) { + bLocateLikeConstraint *data= (bLocateLikeConstraint *)con->data; + + /* new headtail functionality makes Bone-Tip function obsolete */ + if (data->flag & LOCLIKE_TIP) + con->headtail = 1.0f; + } } } } - for(con=ob->constraints.first; con; con=con->next) { - if(con->type==CONSTRAINT_TYPE_PYTHON) { + for (con=ob->constraints.first; con; con=con->next) { + if (con->type==CONSTRAINT_TYPE_PYTHON) { bPythonConstraint *data= (bPythonConstraint *)con->data; if (data->tar) { /* version patching needs to be done */ @@ -6872,6 +6879,13 @@ static void do_versions(FileData *fd, Library *lib, Main *main) strcpy(data->subtarget, ""); } } + else if (con->type == CONSTRAINT_TYPE_LOCLIKE) { + bLocateLikeConstraint *data= (bLocateLikeConstraint *)con->data; + + /* new headtail functionality makes Bone-Tip function obsolete */ + if (data->flag & LOCLIKE_TIP) + con->headtail = 1.0f; + } } } } diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 431ef56e1c4..bf512c3faf8 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -64,6 +64,8 @@ typedef struct bConstraint { char name[30]; /* Constraint name */ float enforce; /* Amount of influence exherted by constraint (0.0-1.0) */ + float headtail; /* Point along subtarget bone where the actual target is. 0=head (default for all), 1=tail*/ + int pad; } bConstraint; @@ -116,7 +118,7 @@ typedef struct bPythonConstraint { char subtarget[32]; /* subtarger from previous implentation (version-patch sets this to "" on file-load) */ } bPythonConstraint; -/* Single-target subobject constraints --------------------- */ + /* Inverse-Kinematics (IK) constraint */ typedef struct bKinematicConstraint { Object *tar; @@ -134,6 +136,8 @@ typedef struct bKinematicConstraint { float grabtarget[3]; /* for target-less IK */ } bKinematicConstraint; + +/* Single-target subobject constraints --------------------- */ /* Track To Constraint */ typedef struct bTrackToConstraint { Object *tar; @@ -386,6 +390,7 @@ typedef enum B_CONSTRAINTCHANNEL_FLAG { #define LOCLIKE_X 0x01 #define LOCLIKE_Y 0x02 #define LOCLIKE_Z 0x04 + /* LOCLIKE_TIP is a depreceated option... use headtail=1.0f instead */ #define LOCLIKE_TIP 0x08 #define LOCLIKE_X_INVERT 0x10 #define LOCLIKE_Y_INVERT 0x20 diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h index 1fca73b576c..2b943c2c23e 100644 --- a/source/blender/makesdna/DNA_ipo_types.h +++ b/source/blender/makesdna/DNA_ipo_types.h @@ -319,10 +319,11 @@ typedef short IPO_Channel; #define AC_QUAT_Z 28 /* ******************** */ -#define CO_TOTIPO 1 /* Constraint Ipos */ -#define CO_TOTNAM 1 +#define CO_TOTIPO 2 /* Constraint Ipos */ +#define CO_TOTNAM 2 #define CO_ENFORCE 1 +#define CO_HEADTAIL 2 /* #define CO_TIME 2 #define CO_OFFSET_X 3 @@ -399,3 +400,5 @@ typedef short IPO_Channel; #endif + + diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 98c2914cee4..3a2c7bda497 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -494,7 +494,7 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s Object *ob= OBACT; bConstraintTypeInfo *cti; uiBut *but; - char typestr[64]; + char typestr[32]; short height, width = 265; int rb_col; @@ -807,7 +807,7 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s /* Draw options */ uiDefButBitI(block, TOG, LOCLIKE_OFFSET, B_CONSTRAINT_TEST, "Offset", *xco, *yco-89, (width/2), 18, &data->flag, 0, 24, 0, 0, "Add original location onto copied location"); if (is_armature_target(data->tar)) { - uiDefButBitI(block, TOG, LOCLIKE_TIP, B_CONSTRAINT_TEST, "Target Bone Tail", *xco+(width/2), *yco-89, (width/2), 18, &data->flag, 0, 24, 0, 0, "Copy Location of Target Bone's Tail"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Head/Tail:", *xco+(width/2), *yco-89, (width/2), 18, &con->headtail, 0.0, 1, 0.1, 0.1, "Target along length of bone: Head=0, Tail=1"); } /* constraint space settings */ @@ -978,7 +978,11 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s { bTrackToConstraint *data = con->data; - height = 96; + if (is_armature_target(data->tar)) + height = 118; + else + height = 96; + uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); @@ -1025,15 +1029,27 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+238, *yco-64,17,18, &data->reserved2, 13.0, 2.0, 0, 0, "Z axis points upward"); uiBlockEndAlign(block); - /* constraint space settings */ - draw_constraint_spaceselect(block, con, *xco, *yco-94, is_armature_owner(ob), is_armature_target(data->tar)); + if (is_armature_target(data->tar)) { + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Head/Tail:", *xco, *yco-94, 241, 18, &con->headtail, 0.0, 1, 0.1, 0.1, "Target along length of bone: Head=0, Tail=1"); + + /* constraint space settings */ + draw_constraint_spaceselect(block, con, *xco, *yco-116, is_armature_owner(ob), is_armature_target(data->tar)); + } + else { + /* constraint space settings */ + draw_constraint_spaceselect(block, con, *xco, *yco-94, is_armature_owner(ob), is_armature_target(data->tar)); + } } break; case CONSTRAINT_TYPE_MINMAX: { bMinMaxConstraint *data = con->data; - height = 66; + if (is_armature_target(data->tar)) + height = 88; + else + height = 66; + uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); @@ -1070,6 +1086,11 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Y", *xco+126, *yco-64,24,18, &data->minmaxflag, 12.0, 4.0, 0, 0, "Will not pass above Y of target"); uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Z", *xco+150, *yco-64,24,18, &data->minmaxflag, 12.0, 5.0, 0, 0, "Will not pass above Z of target"); uiBlockEndAlign(block); + + if (is_armature_target(data->tar)) { + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Head/Tail:", *xco, *yco-86, 241, 18, &con->headtail, 0.0, 1, 0.1, 0.1, "Target along length of bone: Head=0, Tail=1"); + } + } break; case CONSTRAINT_TYPE_LOCKTRACK: @@ -1181,13 +1202,19 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s } uiBlockEndAlign(block); - uiBlockBeginAlign(block); - uiDefButF(block,BUTM,B_CONSTRAINT_TEST,"R",*xco, *yco-60,20,18,&(data->orglength),0.0,0,0,0,"Recalculate RLength"); - uiDefButF(block,NUM,B_CONSTRAINT_TEST,"Rest Length:",*xco+18, *yco-60,237,18,&(data->orglength),0.0,100,0.5,0.5,"Length at Rest Position"); + if (is_armature_target(data->tar)) { + uiDefButF(block, BUTM, B_CONSTRAINT_TEST, "R", *xco, *yco-60, 20, 18, &data->orglength, 0.0, 0, 0, 0, "Recalculate RLength"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Rest Length:", *xco+18, *yco-60,139,18, &data->orglength, 0.0, 100, 0.5, 0.5, "Length at Rest Position"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Head/Tail:", *xco+155, *yco-60,97,18, &con->headtail, 0.0, 1, 0.1, 0.1, "Target along length of bone: Head=0, Tail=1"); + } + else { + uiDefButF(block, BUTM, B_CONSTRAINT_TEST, "R", *xco, *yco-60, 20, 18, &data->orglength, 0.0, 0, 0, 0, "Recalculate RLength"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Rest Length:", *xco+18, *yco-60, 237, 18, &data->orglength, 0.0, 100, 0.5, 0.5, "Length at Rest Position"); + } uiBlockEndAlign(block); - uiDefButF(block,NUM,B_CONSTRAINT_TEST,"Volume Variation:",*xco+18, *yco-82,237,18,&(data->bulge),0.0,100,0.5,0.5,"Factor between volume variation and stretching"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Volume Variation:", *xco+18, *yco-82, 237, 18, &data->bulge, 0.0, 100, 0.5, 0.5, "Factor between volume variation and stretching"); uiBlockBeginAlign(block); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Vol:",*xco+14, *yco-104,30,18, NULL, 0.0, 0.0, 0.0, 0.0, ""); diff --git a/source/blender/src/editipo_lib.c b/source/blender/src/editipo_lib.c index f10e100df7d..6ef45f32620 100644 --- a/source/blender/src/editipo_lib.c +++ b/source/blender/src/editipo_lib.c @@ -61,7 +61,7 @@ char *ob_ic_names[OB_TOTNAM] = { "LocX", "LocY", "LocZ", "dLocX", "dLocY", "dLoc "Layer", "Time", "ColR", "ColG", "ColB", "ColA", "FStreng", "FFall", "RDamp", "Damping", "Perm" }; -char *co_ic_names[CO_TOTNAM] = { "Inf" }; +char *co_ic_names[CO_TOTNAM] = { "Inf", "HeadTail" }; char *mtex_ic_names[TEX_TOTNAM] = { "OfsX", "OfsY", "OfsZ", "SizeX", "SizeY", "SizeZ", "texR", "texG", "texB", "DefVar", "Col", "Nor", "Var", "Disp" }; @@ -191,6 +191,7 @@ char *getname_co_ei(int nr) { switch(nr){ case CO_ENFORCE: + case CO_HEADTAIL: return co_ic_names[nr-1]; } return ic_name_empty[0]; @@ -388,3 +389,5 @@ int texchannel_to_adrcode(int channel) } + + -- cgit v1.2.3