diff options
author | Ton Roosendaal <ton@blender.org> | 2005-07-24 15:36:05 +0400 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2005-07-24 15:36:05 +0400 |
commit | 4d273d8d5b9eb471f82ee49819905eedb68d6a4f (patch) | |
tree | c27fb4ba1f2dff92f75e998d8c03dd9ad627053a /source | |
parent | 1d27a7676b261cd5eecde5828a396398376f6af1 (diff) |
Armature-Pose IK goodies!
- Added option to the IK buttons, to have it use the 'tip' as end of the
IK chain. I never really understood this old convention (IK didn't work
on the Bone itself).
Old files still will read OK though. But I made the "To Tip" a default
when adding new IK constraints.
- Hotkey CTRL+I: add IK, with option to have it adding an Empty target,
or use a selected Bone as target. With the new non-modal PoseMode, it
gives instant access to playing with the IK chain.
- Hotkey ALT+I: clears IK, on all selected Bones
- Hotkey ALT+C: clears Constraints on all selected Bones (incl IK)
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_constraint.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 12 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 17 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 4 | ||||
-rw-r--r-- | source/blender/include/BIF_poseobject.h | 4 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_constraint_types.h | 9 | ||||
-rw-r--r-- | source/blender/src/buttons_object.c | 9 | ||||
-rw-r--r-- | source/blender/src/editarmature.c | 3 | ||||
-rw-r--r-- | source/blender/src/poseobject.c | 176 | ||||
-rw-r--r-- | source/blender/src/space.c | 17 |
10 files changed, 218 insertions, 35 deletions
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 8fdc63bef60..1dd5beed9fa 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -60,7 +60,7 @@ void free_constraint_channels (ListBase *chanbase); char constraint_has_target (struct bConstraint *con); struct Object *get_constraint_target(struct bConstraint *con, char **subtarget); -void set_constraint_target(struct bConstraint *con, struct Object *ob); +void set_constraint_target(struct bConstraint *con, struct Object *ob, char *subtarget); /* Constraint target/owner types */ diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 845cb618638..64b3c9f7ca6 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -791,11 +791,15 @@ static void initialize_posechain(struct Object *ob, bPoseChannel *pchan_tip) /* Find the chain's root & count the segments needed */ for (curchan = pchan_tip; curchan; curchan=curchan->parent){ pchan_root = curchan; - /* tip is not in the chain */ - if (curchan!=pchan_tip){ - chanlist[segcount]=curchan; - segcount++; + + chanlist[segcount]=curchan; + segcount++; + + /* exclude tip from chain? */ + if(curchan==pchan_tip) { + if(!(data->flag & CONSTRAINT_IK_TIP)) segcount--; } + if(segcount>255) break; // also weak if (!(curchan->bone->flag & BONE_IK_TOPARENT)) diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 13e1114078c..e3b0263de51 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -92,10 +92,9 @@ void free_constraints (ListBase *conlist) bConstraint *con; /* Do any specific freeing */ - for (con=conlist->first; con; con=con->next) - { + for (con=conlist->first; con; con=con->next) { free_constraint_data (con); - }; + } /* Free the whole list */ BLI_freelistN(conlist); @@ -374,7 +373,7 @@ Object *get_constraint_target(bConstraint *con, char **subtarget) return NULL; } -void set_constraint_target(bConstraint *con, Object *ob) +void set_constraint_target(bConstraint *con, Object *ob, char *subtarget) { /* * Set the target for this constraint @@ -384,36 +383,42 @@ void set_constraint_target(bConstraint *con, Object *ob) { bActionConstraint *data = con->data; data->tar= ob; + if(subtarget) BLI_strncpy(data->subtarget, subtarget, 32); } break; case CONSTRAINT_TYPE_LOCLIKE: { bLocateLikeConstraint *data = con->data; data->tar= ob; + if(subtarget) BLI_strncpy(data->subtarget, subtarget, 32); } break; case CONSTRAINT_TYPE_ROTLIKE: { bRotateLikeConstraint *data = con->data; data->tar= ob; + if(subtarget) BLI_strncpy(data->subtarget, subtarget, 32); } break; case CONSTRAINT_TYPE_KINEMATIC: { bKinematicConstraint *data = con->data; data->tar= ob; + if(subtarget) BLI_strncpy(data->subtarget, subtarget, 32); } break; case CONSTRAINT_TYPE_TRACKTO: { bTrackToConstraint *data = con->data; data->tar= ob; + if(subtarget) BLI_strncpy(data->subtarget, subtarget, 32); } break; case CONSTRAINT_TYPE_LOCKTRACK: { bLockTrackConstraint *data = con->data; data->tar= ob; + if(subtarget) BLI_strncpy(data->subtarget, subtarget, 32); } break; case CONSTRAINT_TYPE_FOLLOWPATH: @@ -426,6 +431,7 @@ void set_constraint_target(bConstraint *con, Object *ob) { bStretchToConstraint *data = con->data; data->tar= ob; + if(subtarget) BLI_strncpy(data->subtarget, subtarget, 32); } break; } @@ -488,7 +494,8 @@ void *new_constraint_data (short type) data->tolerance = (float)0.001; data->iterations = 500; - + data->flag= CONSTRAINT_IK_TIP; + result = data; } break; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 87e0a0c95c4..c2a3ab49c32 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -322,7 +322,7 @@ void unlink_object(Object *ob) for(pchan= obt->pose->chanbase.first; pchan; pchan= pchan->next) { for (con = pchan->constraints.first; con; con=con->next) { if(ob==get_constraint_target(con, &str)) { - set_constraint_target(con, NULL); + set_constraint_target(con, NULL, NULL); obt->recalc |= OB_RECALC_DATA; } } @@ -333,7 +333,7 @@ void unlink_object(Object *ob) for (con = obt->constraints.first; con; con=con->next) { if(ob==get_constraint_target(con, &str)) { - set_constraint_target(con, NULL); + set_constraint_target(con, NULL, NULL); obt->recalc |= OB_RECALC_OB; } } diff --git a/source/blender/include/BIF_poseobject.h b/source/blender/include/BIF_poseobject.h index ac0c66ff0d1..6c065ace0d8 100644 --- a/source/blender/include/BIF_poseobject.h +++ b/source/blender/include/BIF_poseobject.h @@ -49,7 +49,11 @@ void set_pose_keys(struct Object *ob); */ void exit_posemode(void); +/* tools */ void pose_special_editmenu(void); +void pose_add_IK(void); +void pose_clear_IK(void); +void pose_clear_constraints(void); #endif diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 2646f803bf9..cfb180cf33d 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -67,13 +67,11 @@ typedef struct bConstraint{ typedef struct bKinematicConstraint{ Object *tar; float tolerance; /* Acceptable distance from target */ - int iterations; /* Maximum number of iterations to try */ + short iterations; /* Maximum number of iterations to try */ + short flag; /* Like IK to Tip */ char subtarget[32]; /* String to specify sub-object target */ - float cacheeff[3]; /* Target location cache */ - int reserved1; - float cachemat[4][4]; /* Result cache */ } bKinematicConstraint; typedef struct bTrackToConstraint{ @@ -219,5 +217,8 @@ typedef struct bStretchToConstraint{ #define PLANE_Y 0x00000001 #define PLANE_Z 0x00000002 +/* bKinematicConstraint->flag */ +#define CONSTRAINT_IK_TIP 1 + #endif diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index a73d333a797..077e973a2a8 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -529,15 +529,18 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiDefIDPoinBut(block, test_obpoin_but, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); arm = get_armature(data->tar); - if (arm){ + if (arm) but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); - } else strcpy (data->subtarget, ""); uiBlockEndAlign(block); + uiDefButBitS(block, TOG, CONSTRAINT_IK_TIP, B_CONSTRAINT_REDRAW, "Use Tip", *xco+((width/2)-117), *yco-42, 80, 18, &data->flag, 0, 0, 0, 0, "Include Bone's tip als last element in Chain"); + + uiBlockBeginAlign(block); uiDefButF(block, NUM, B_CONSTRAINT_REDRAW, "Tolerance:", *xco+((width/2)-117), *yco-64, 120, 18, &data->tolerance, 0.0001f, 1.0, 0.0, 0.0, "Maximum distance to target after solving"); - uiDefButI(block, NUM, B_CONSTRAINT_REDRAW, "Iterations:", *xco+((width/2)+3), *yco-64, 120, 18, &data->iterations, 1, 10000, 0.0, 0.0, "Maximum number of solving iterations"); + uiDefButS(block, NUM, B_CONSTRAINT_REDRAW, "Iterations:", *xco+((width/2)+3), *yco-64, 120, 18, &data->iterations, 1, 10000, 0.0, 0.0, "Maximum number of solving iterations"); + uiBlockEndAlign(block); } break; diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index 9976e2180d7..ec2c1364c3c 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -1155,7 +1155,7 @@ static EditBone *add_editbone(void) strcpy (bone->name,"Bone"); unique_editbone_name (bone->name); - bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL; + bone->flag |= BONE_TIPSEL; bone->weight= 1.0F; bone->dist= 1.0F; bone->xwidth= 0.1; @@ -1188,7 +1188,6 @@ static void add_primitive_bone(Object *ob) /* Create a bone */ bone= add_editbone(); - bone->flag |= BONE_ACTIVE; VECCOPY(bone->head, curs); VecAddf(bone->tail, bone->head, imat[1]); // bone with unit length 1 diff --git a/source/blender/src/poseobject.c b/source/blender/src/poseobject.c index 741b38754c8..2aea0ecfb26 100644 --- a/source/blender/src/poseobject.c +++ b/source/blender/src/poseobject.c @@ -6,10 +6,7 @@ * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,20 +20,16 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. + * Contributor(s): Ton Roosendaal, Blender Foundation '05, full recode. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** * support for animation modes - Reevan McKay */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #include <stdlib.h> +#include "MEM_guardedalloc.h" + #include "BLI_arithb.h" #include "BLI_blenlib.h" @@ -51,16 +44,19 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_constraint.h" -#include "BKE_global.h" +#include "BKE_depsgraph.h" #include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_object.h" +#include "BIF_editconstraint.h" #include "BIF_gl.h" #include "BIF_graphics.h" #include "BIF_interface.h" +#include "BIF_poseobject.h" #include "BIF_space.h" #include "BIF_toolbox.h" #include "BIF_screen.h" -#include "BIF_poseobject.h" #include "BDR_editobject.h" @@ -144,13 +140,16 @@ void exit_posemode(void) scrarea_queue_headredraw(curarea); } +/* context: active channel */ void pose_special_editmenu(void) { Object *ob= OBACT; bPoseChannel *pchan; short nr; + /* paranoia checks */ if(!ob && !ob->pose) return; + if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return; for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) if(pchan->bone->flag & BONE_ACTIVE) break; @@ -175,4 +174,155 @@ void pose_special_editmenu(void) } } +/* context: active channel, optional selected channel */ +void pose_add_IK(void) +{ + Object *ob= OBACT; + bPoseChannel *pchanact, *pchansel; + bConstraint *con; + short nr; + + /* paranoia checks */ + if(!ob && !ob->pose) return; + if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return; + + /* find active */ + for(pchanact= ob->pose->chanbase.first; pchanact; pchanact= pchanact->next) + if(pchanact->bone->flag & BONE_ACTIVE) break; + if(pchanact==NULL) return; + + /* find selected */ + for(pchansel= ob->pose->chanbase.first; pchansel; pchansel= pchansel->next) { + if(pchansel!=pchanact) + if(pchansel->bone->flag & BONE_SELECTED) break; + } + + for(con= pchanact->constraints.first; con; con= con->next) { + if(con->type==CONSTRAINT_TYPE_KINEMATIC) break; + } + if(con) { + error("Pose Channel already has IK"); + return; + } + + if(pchansel) + nr= pupmenu("Add IK Constraint%t|To new Empty Object%x1|To selected Bone%x2"); + else + nr= pupmenu("Add IK Constraint%t|To new Empty Object%x1"); + + if(nr<1) return; + + /* prevent weird chains... */ + if(nr==2) { + bPoseChannel *pchan= pchanact; + while(pchan) { + if(pchan==pchansel) break; + if(pchan->bone->flag & BONE_IK_TOPARENT) + pchan= pchan->parent; + else pchan= NULL; + } + if(pchan) { + error("IK target should not be in the IK chain itself"); + return; + } + } + + con = add_new_constraint(CONSTRAINT_TYPE_KINEMATIC); + BLI_addtail(&pchanact->constraints, con); + pchanact->constflag |= PCHAN_HAS_IK; // for draw, but also for detecting while pose solving + + /* add new empty as target */ + if(nr==1) { + Base *base= BASACT; + Object *obt; + + obt= add_object(OB_EMPTY); + /* transform cent to global coords for loc */ + VecMat4MulVecfl(obt->loc, ob->obmat, pchanact->pose_tail); + + set_constraint_target(con, obt, NULL); + + /* restore, add_object sets active */ + BASACT= base; + base->flag |= SELECT; + } + else if(nr==2) { + set_constraint_target(con, ob, pchansel->name); + } + + ob->pose->flag |= POSE_RECALC; // sort pose channels + DAG_scene_sort(G.scene); // sort order of objects + + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); // and all its relations + + allqueue (REDRAWVIEW3D, 0); + allqueue (REDRAWBUTSOBJECT, 0); + + BIF_undo_push("Add IK constraint"); +} + +/* context: all selected channels */ +void pose_clear_IK(void) +{ + Object *ob= OBACT; + bPoseChannel *pchan; + bConstraint *con; + bConstraint *next; + + /* paranoia checks */ + if(!ob && !ob->pose) return; + if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return; + + if(okee("Remove IK constraint(s)")==0) return; + + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) { + + for(con= pchan->constraints.first; con; con= next) { + next= con->next; + if(con->type==CONSTRAINT_TYPE_KINEMATIC) { + BLI_remlink(&pchan->constraints, con); + free_constraint_data(con); + MEM_freeN(con); + } + } + pchan->constflag &= ~PCHAN_HAS_IK; + } + } + + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); // and all its relations + + allqueue (REDRAWVIEW3D, 0); + allqueue (REDRAWBUTSOBJECT, 0); + + BIF_undo_push("Remove IK constraint(s)"); +} + +void pose_clear_constraints(void) +{ + Object *ob= OBACT; + bPoseChannel *pchan; + + /* paranoia checks */ + if(!ob && !ob->pose) return; + if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return; + + if(okee("Remove Constraints")==0) return; + + /* find active */ + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) { + free_constraints(&pchan->constraints); + pchan->constflag= 0; + } + } + + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); // and all its relations + + allqueue (REDRAWVIEW3D, 0); + allqueue (REDRAWBUTSOBJECT, 0); + + BIF_undo_push("Remove Constraint(s)"); + +} diff --git a/source/blender/src/space.c b/source/blender/src/space.c index 895a292bffa..c112fd059fc 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -103,6 +103,7 @@ #include "BIF_meshtools.h" #include "BIF_mywindow.h" #include "BIF_oops.h" +#include "BIF_poseobject.h" #include "BIF_outliner.h" #include "BIF_resources.h" #include "BIF_screen.h" @@ -1122,7 +1123,10 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) copy_attr_menu(); } else if(G.qual==LR_ALTKEY) { - convertmenu(); /* editobject.c */ + if(ob && (ob->flag & OB_POSEMODE)) + pose_clear_constraints(); /* poseobject.c */ + else + convertmenu(); /* editobject.c */ } else if((G.qual==LR_SHIFTKEY)) { view3d_home(1); @@ -1295,6 +1299,17 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) } break; case IKEY: + if(G.obedit); + else if(G.qual==LR_CTRLKEY) { + if(ob && ob->type==OB_ARMATURE) + if(ob->flag & OB_POSEMODE) + pose_add_IK(); + } + else if(G.qual==LR_ALTKEY) { + if(ob && ob->type==OB_ARMATURE) + if(ob->flag & OB_POSEMODE) + pose_clear_IK(); + } break; case JKEY: |