Patch #7767: Constraint Subtargets can now target anywhere on a bone, not just the...
authorJoshua Leung <aligorith@gmail.com>
Mon, 12 Nov 2007 04:17:03 +0000 (04:17 +0000)
committerJoshua Leung <aligorith@gmail.com>
Mon, 12 Nov 2007 04:17:03 +0000 (04:17 +0000)
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
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/ipo.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_constraint_types.h
source/blender/makesdna/DNA_ipo_types.h
source/blender/src/buttons_object.c
source/blender/src/editipo_lib.c

index d202178fc0a4002d883f17cd093c7fc58e64ff8b..bd5e5d612c6c7a6a37cf3cc1538edbeb3804197c 100644 (file)
@@ -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 */
index f50cb2c6be058a6f50afe2f721af8a5e5add7b50..558c90b37dbcafb9f084f027bdb1d638248c5fda 100644 (file)
@@ -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:
index 107633eda64a1ce1883418af49a483970b4618fd..83b845a0064a9064fe0d5ad41297e972fce1626c 100644 (file)
@@ -85,7 +85,7 @@
 */
 
 int co_ar[CO_TOTIPO]= {
-       CO_ENFORCE
+       CO_ENFORCE, CO_HEADTAIL
 };
 
 int ob_ar[OB_TOTIPO]= {
index 615d1759f668b5d1b8875ab1aa571dca62c41604..2e4c56dbc9cd63eb419cfcc00d6ffd7bc6d22234 100644 (file)
@@ -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;
+                               }
                        }
                }
        }
index 431ef56e1c4e05ed78314a2da64577f14ff2de11..bf512c3faf81e6bf7f2409eed85fca68a92e9dc2 100644 (file)
@@ -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
index 1fca73b576cba4ae66515f1c90cba21a642d0c58..2b943c2c23ee479ef7d79fbba5a7e9a6b8b07c75 100644 (file)
@@ -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
 
+
+
index 98c2914cee437e6d3cd161cec166a4f9da45758b..3a2c7bda49762ff5dbdd18ccea9b94dd94782434 100644 (file)
@@ -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, ""); 
index f10e100df7d0bc81a080e9f8cf17bd34444a43cf..6ef45f3262037077e702fe2f004942cc3edce072 100644 (file)
@@ -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)
 }
 
 
+
+