From 264c8d94f93c97e3c9fc21998e8565035130db5a Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 25 Jan 2008 11:23:36 +0000 Subject: [PATCH] == Limit Distance Constraint == Added a new constraint, "Limit Distance". This constraint defines a 'virtual sphere' around the target which the owner can be made to stay inside, outside, or on the surface of it. This constraint is best used when applied using the Ctrl-Alt-C hotkey, as the radius is set correctly that way. One usage, is to prevent the target of an IK-chain from straying away from the chain. Care should be taken to not use a member of the IK-chain as the target though. Description of Variables: * 'Dist' - Radius of virtual sphere * 'R' - Click on this to recalculate the 'Dist' value (note: like the 'R' button in the StretchTo constraint, this is currently buggy) ' Mode' - This menu gives different options for how the limiting sphere should act. The mode names are self explanatory. * 'Soft' and 'SoftDistance' - currently not functional (so settings are hidden). These are used to define a smaller radius around the sphere of influence where a non-linear relationship between input and resulting locations occurs to prevent the owner 'crashing' into the sphere. --- source/blender/blenkernel/intern/constraint.c | 116 +++++++++++++++++- source/blender/blenloader/intern/readfile.c | 14 +++ source/blender/include/butspace.h | 2 +- .../blender/makesdna/DNA_constraint_types.h | 25 +++- source/blender/src/buttons_object.c | 57 +++++++++ source/blender/src/editconstraint.c | 15 +-- source/blender/src/editipo.c | 2 +- 7 files changed, 219 insertions(+), 12 deletions(-) diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 7d7180da271..38f25b54fd8 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -2382,6 +2382,118 @@ static bConstraintTypeInfo CTI_LOCKTRACK = { locktrack_evaluate /* evaluate */ }; +/* ---------- Limit Distance Constraint ----------- */ + +static void distlimit_new_data (void *cdata) +{ + bDistLimitConstraint *data= (bDistLimitConstraint *)cdata; + + data->dist= 0.0; +} + +static void distlimit_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bDistLimitConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + } +} + +static void distlimit_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bDistLimitConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + +static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bDistLimitConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float dvec[3], dist=0.0f, sfac=1.0f; + short clamp_surf= 0; + + /* calculate our current distance from the target */ + dist= VecLenf(cob->matrix[3], ct->matrix[3]); + + /* set distance (flag is only set when user demands it) */ + if (data->dist == 0) + data->dist= dist; + + /* check if we're which way to clamp from, and calculate interpolation factor (if needed) */ + if (data->mode == LIMITDIST_OUTSIDE) { + /* if inside, then move to surface */ + if (dist <= data->dist) { + clamp_surf= 1; + sfac= data->dist / dist; + } + /* if soft-distance is enabled, start fading once owner is dist+softdist from the target */ + else if (data->flag & LIMITDIST_USESOFT) { + if (dist <= (data->dist + data->soft)) { + + } + } + } + else if (data->mode == LIMITDIST_INSIDE) { + /* if outside, then move to surface */ + if (dist >= data->dist) { + clamp_surf= 1; + sfac= data->dist / dist; + } + /* if soft-distance is enabled, start fading once owner is dist-soft from the target */ + else if (data->flag & LIMITDIST_USESOFT) { + // FIXME: there's a problem with "jumping" when this kicks in + if (dist >= (data->dist - data->soft)) { + sfac = data->soft*(1.0 - exp(-(dist - data->dist)/data->soft)) + data->dist; + sfac /= dist; + + clamp_surf= 1; + } + } + } + else { + if (IS_EQ(dist, data->dist)==0) { + clamp_surf= 1; + sfac= data->dist / dist; + } + } + + /* clamp to 'surface' (i.e. move owner so that dist == data->dist) */ + if (clamp_surf) { + /* simply interpolate along line formed by target -> owner */ + VecLerpf(dvec, ct->matrix[3], cob->matrix[3], sfac); + + /* copy new vector onto owner */ + VECCOPY(cob->matrix[3], dvec); + } + } +} + +static bConstraintTypeInfo CTI_DISTLIMIT = { + CONSTRAINT_TYPE_DISTLIMIT, /* type */ + sizeof(bDistLimitConstraint), /* size */ + "Limit Distance", /* name */ + "bDistLimitConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + distlimit_new_data, /* new data */ + distlimit_get_tars, /* get constraint targets */ + distlimit_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get a target matrix */ + distlimit_evaluate /* evaluate */ +}; + /* ---------- Stretch To ------------ */ static void stretchto_new_data (void *cdata) @@ -3067,12 +3179,12 @@ static void constraints_init_typeinfo () { constraintsTypeInfo[11]= &CTI_PYTHON; /* Python/Script Constraint */ constraintsTypeInfo[12]= &CTI_ACTION; /* Action Constraint */ constraintsTypeInfo[13]= &CTI_LOCKTRACK; /* Locked-Track Constraint */ - constraintsTypeInfo[14]= NULL; /* 'Distance Limit' Constraint */ + constraintsTypeInfo[14]= &CTI_DISTLIMIT; /* Limit Distance Constraint */ constraintsTypeInfo[15]= &CTI_STRETCHTO; /* StretchTo Constaint */ constraintsTypeInfo[16]= &CTI_MINMAX; /* Floor Constraint */ constraintsTypeInfo[17]= &CTI_RIGIDBODYJOINT; /* RigidBody Constraint */ constraintsTypeInfo[18]= &CTI_CLAMPTO; /* ClampTo Constraint */ - constraintsTypeInfo[19]= &CTI_TRANSFORM; /* Transformation Constraint */ + constraintsTypeInfo[19]= &CTI_TRANSFORM; /* Transformation Constraint */ } /* This function should be used for getting the appropriate type-info when only diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 8481e7c0a3a..f3a3a3478ac 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1752,6 +1752,13 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist) data->tar = newlibadr(fd, id->lib, data->tar); } break; + case CONSTRAINT_TYPE_DISTLIMIT: + { + bDistLimitConstraint *data; + data= ((bDistLimitConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; case CONSTRAINT_TYPE_NULL: break; } @@ -1765,6 +1772,7 @@ static void direct_link_constraints(FileData *fd, ListBase *lb) link_list(fd, lb); for (cons=lb->first; cons; cons=cons->next) { cons->data = newdataadr(fd, cons->data); + if (cons->type == CONSTRAINT_TYPE_PYTHON) { bPythonConstraint *data= cons->data; link_list(fd, &data->targets); @@ -7807,6 +7815,12 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb) expand_doit(fd, mainvar, data->tar); } break; + case CONSTRAINT_TYPE_DISTLIMIT: + { + bDistLimitConstraint *data = (bDistLimitConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; default: break; } diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index 6d7a73eec54..a067b3e1489 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -694,7 +694,7 @@ enum { B_CONSTRAINT_ADD_ACTION, B_CONSTRAINT_ADD_LOCKTRACK, B_CONSTRAINT_ADD_FOLLOWPATH, - B_CONSTRAINT_ADD_DISTANCELIMIT, + B_CONSTRAINT_ADD_DISTLIMIT, B_CONSTRAINT_ADD_STRETCHTO, B_CONSTRAINT_ADD_LOCLIMIT, B_CONSTRAINT_ADD_ROTLIMIT, diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 4ae8d6b39e6..2bcf2412588 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -307,6 +307,19 @@ typedef struct bSizeLimitConstraint { short flag2; } bSizeLimitConstraint; +/* Limit Distance Constraint */ +typedef struct bDistLimitConstraint { + Object *tar; + char subtarget[32]; + + float dist; /* distance (radius of clamping sphere) from target */ + float soft; /* distance from clamping-sphere to start applying 'fade' */ + + short flag; /* settings */ + short mode; /* how to limit in relation to clamping sphere */ + int pad; +} bDistLimitConstraint; + /* ------------------------------------------ */ /* bConstraint->type @@ -328,13 +341,14 @@ typedef enum B_CONSTAINT_TYPES { CONSTRAINT_TYPE_PYTHON, /* Unimplemented no longer :) - Aligorith. Scripts */ CONSTRAINT_TYPE_ACTION, CONSTRAINT_TYPE_LOCKTRACK, /* New Tracking constraint that locks an axis in place - theeth */ - CONSTRAINT_TYPE_DISTANCELIMIT, /* was never properly coded - removed! */ + CONSTRAINT_TYPE_DISTLIMIT, /* limit distance */ CONSTRAINT_TYPE_STRETCHTO, /* claiming this to be mine :) is in tuhopuu bjornmose */ CONSTRAINT_TYPE_MINMAX, /* floor constraint */ CONSTRAINT_TYPE_RIGIDBODYJOINT, /* rigidbody constraint */ CONSTRAINT_TYPE_CLAMPTO, /* clampto constraint */ CONSTRAINT_TYPE_TRANSFORM, /* transformation (loc/rot/size -> loc/rot/size) constraint */ + /* NOTE: everytime a new constraint is added, update this */ NUM_CONSTRAINT_TYPES= CONSTRAINT_TYPE_TRANSFORM } B_CONSTRAINT_TYPES; @@ -478,6 +492,15 @@ typedef enum B_CONSTRAINTCHANNEL_FLAG { #define LIMIT_NOPARENT 0x01 /* for all Limit constraints - allow to be used during transform? */ #define LIMIT_TRANSFORM 0x02 + +/* distance limit constraint */ + /* bDistLimitConstraint->flag */ +#define LIMITDIST_USESOFT (1<<0) + + /* bDistLimitConstraint->mode */ +#define LIMITDIST_INSIDE 0 +#define LIMITDIST_OUTSIDE 1 +#define LIMITDIST_ONSURFACE 2 /* python constraint -> flag */ #define PYCON_USETARGETS 0x01 diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 1a415b461cb..32218c27ace 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -1439,6 +1439,54 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s draw_constraint_spaceselect(block, con, *xco, *yco-130, is_armature_owner(ob), -1); } break; + case CONSTRAINT_TYPE_DISTLIMIT: + { + bDistLimitConstraint *data = con->data; + + height = 105; + 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, ""); + + /* Draw target parameters */ + uiBlockBeginAlign(block); + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); + + if (is_armature_target(data->tar)) { + but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else if (is_geom_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + if (is_armature_target(data->tar)) { + uiDefButF(block, BUT, B_CONSTRAINT_TEST, "R", *xco, *yco-60, 20, 18, &data->dist, 0, 0, 0, 0, "Recalculate distance"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Distance:", *xco+18, *yco-60,139,18, &data->dist, 0.0, 100, 0.5, 0.5, "Radius of limiting sphere"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Head/Tail:", *xco+155, *yco-60,100,18, &con->headtail, 0.0, 1, 0.1, 0.1, "Target along length of bone: Head=0, Tail=1"); + } + else { + uiDefButF(block, BUT, B_CONSTRAINT_TEST, "R", *xco, *yco-60, 20, 18, &data->dist, 0, 0, 0, 0, "Recalculate distance"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Distance:", *xco+18, *yco-60, 237, 18, &data->dist, 0.0, 100, 0.5, 0.5, "Radius of limiting sphere"); + } + + /* disabled soft-distance controls... currently it doesn't work yet. It was intended to be used for soft-ik (see xsi-blog for details) */ +#if 0 + uiDefButBitS(block, TOG, LIMITDIST_USESOFT, B_CONSTRAINT_TEST, "Soft", *xco, *yco-82, 50, 18, &data->flag, 0, 24, 0, 0, "Enables soft-distance"); + if (data->flag & LIMITDIST_USESOFT) + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Soft-Distance:", *xco+50, *yco-82, 187, 18, &data->soft, 0.0, 100, 0.5, 0.5, "Distance surrounding radius when transforms should get 'delayed'"); +#endif + uiBlockEndAlign(block); + + uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Limit Mode%t|Inside %x0|Outside %x1|Surface %x2", *xco+((width/2)-50), *yco-104, 100, 18, &data->mode, 0, 24, 0, 0, "Distances in relation to sphere of influence to allow"); + } + break; case CONSTRAINT_TYPE_RIGIDBODYJOINT: { bRigidBodyJointConstraint *data = con->data; @@ -1748,6 +1796,7 @@ static uiBlock *add_constraintmenu(void *arg_unused) uiDefBut(block, BUTM, B_CONSTRAINT_ADD_LOCLIMIT, "Limit Location", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, BUTM, B_CONSTRAINT_ADD_ROTLIMIT, "Limit Rotation", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, BUTM, B_CONSTRAINT_ADD_SIZELIMIT, "Limit Scale", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); + uiDefBut(block, BUTM, B_CONSTRAINT_ADD_DISTLIMIT, "Limit Distance", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, ""); @@ -1980,6 +2029,14 @@ void do_constraintbuts(unsigned short event) BIF_undo_push("Add constraint"); } break; + case B_CONSTRAINT_ADD_DISTLIMIT: + { + con = add_new_constraint(CONSTRAINT_TYPE_DISTLIMIT); + add_constraint_to_active(ob, con); + + BIF_undo_push("Add constraint"); + } + break; default: break; diff --git a/source/blender/src/editconstraint.c b/source/blender/src/editconstraint.c index ac5129dd021..ba73767387e 100644 --- a/source/blender/src/editconstraint.c +++ b/source/blender/src/editconstraint.c @@ -364,21 +364,21 @@ void add_constraint (short only_IK) else { if (pchanact) { if (pchansel) - nr= pupmenu("Add Constraint to Active Bone%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to Active Bone%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); else if ((obsel) && (obsel->type==OB_CURVE)) - nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|Stretch To%x7|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|Stretch To%x7|%l|Action%x16|Script%x18"); else if (obsel) - nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); else - nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); } else { if ((obsel) && (obsel->type==OB_CURVE)) - nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|%l|Action%x16|Script%x18"); else if (obsel) - nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18"); else - nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18"); } } @@ -475,6 +475,7 @@ void add_constraint (short only_IK) } } else if (nr==20) con = add_new_constraint(CONSTRAINT_TYPE_TRANSFORM); + else if (nr==21) con = add_new_constraint(CONSTRAINT_TYPE_DISTLIMIT); if (con==NULL) return; /* paranoia */ diff --git a/source/blender/src/editipo.c b/source/blender/src/editipo.c index 6fe2e032eed..b3ea3e1931c 100644 --- a/source/blender/src/editipo.c +++ b/source/blender/src/editipo.c @@ -2515,7 +2515,7 @@ static int match_adr_constraint(ID * id, int blocktype, char *actname, int adrco case CONSTRAINT_TYPE_LOCKTRACK: if (searchtype==2) foundmatch=1; break; - case CONSTRAINT_TYPE_DISTANCELIMIT: + case CONSTRAINT_TYPE_DISTLIMIT: if (searchtype==1) foundmatch=1; break; case CONSTRAINT_TYPE_MINMAX: