diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index d177edfce09..84d87b28037 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -46,19 +46,23 @@ struct Mesh; struct PoseChain; struct ListBase; +typedef struct PoseTarget +{ + struct PoseTarget *next, *prev; + struct bConstraint *con; + int tip; +} PoseTarget; + typedef struct PoseChain { struct PoseChain *next, *prev; // hurms struct bPoseChannel **pchanchain; - struct bConstraint *con; - struct Bone *root, *target; - struct bPose *pose; - int totchannel; - float goal[3]; + struct ListBase targets; + int totchannel; + float (*basis_change)[3][3]; + char group[32]; float tolerance; int iterations; - float goalinv[4][4]; - struct IK_Chain_Extern *solver; } PoseChain; /* Core armature functionality */ diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c index 04371fbb0d0..aa5748ceb89 100644 --- a/source/blender/blenkernel/bad_level_call_stubs/stubs.c +++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c @@ -170,33 +170,24 @@ void BPY_do_all_scripts (short int event){} /* IKsolver stubs */ #include "IK_solver.h" -extern int IK_LoadChain(IK_Chain_ExternPtr chain,IK_Segment_ExternPtr segments, int num_segs) -{ - return 0; -} -extern int IK_SolveChain( - IK_Chain_ExternPtr chain, - float goal[3], - float tolerance, - int max_iterations, - float max_angle_change, - IK_Segment_ExternPtr output - ) -{ - return 0; -} +IK_Segment *IK_CreateSegment(int flag) { return 0; } +void IK_FreeSegment(IK_Segment *seg) {} -extern void IK_FreeChain(IK_Chain_ExternPtr chain) -{ - ; -} +void IK_SetParent(IK_Segment *seg, IK_Segment *parent) {} +void IK_SetTransform(IK_Segment *seg, float start[3], float rest_basis[][3], float basis[][3], float length) {} +void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3]) {} +void IK_GetTranslationChange(IK_Segment *seg, float *translation_change) {}; +void IK_SetLimit(IK_Segment *seg, IK_SegmentAxis axis, float lower, float upper) {}; +void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness) {}; +IK_Solver *IK_CreateSolver(IK_Segment *root) { return 0; } +void IK_FreeSolver(IK_Solver *solver) {}; -extern IK_Chain_ExternPtr IK_CreateChain(void) -{ - return 0; -} +void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float weight) {} +void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[][3], float weight) {} +void IK_SolverAddCenterOfMass(IK_Solver *solver, IK_Segment *root, float goal[3], float weight) {} +int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations) { return 0; } /* exotic.c */ int BPY_call_importloader(char *name) diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 5af1cc34860..a3c7060a731 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -207,6 +207,10 @@ bPoseChannel *verify_pose_channel(bPose* pose, const char* name) chan->size[0] = chan->size[1] = chan->size[2] = 1.0F; Mat3One(chan->ik_mat); + chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f; + chan->limitmax[0]= chan->limitmax[1]= chan->limitmax[2]= 180.0f; + chan->stiffness[0]= chan->stiffness[1]= chan->stiffness[2]= 1.0f; + BLI_addtail (&pose->chanbase, chan); return chan; diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index dabc4fcf359..0d516e1036e 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -967,15 +967,17 @@ void armature_rebuild_pose(Object *ob, bArmature *arm) /* ********************** THE IK SOLVER ******************* */ + /* allocates PoseChain, and links that to root bone/channel */ /* note; if we got this working, it can become static too? */ static void initialize_posechain(struct Object *ob, bPoseChannel *pchan_tip) { - bPoseChannel *curchan, *pchan_root=NULL, *chanlist[256]; + bPoseChannel *curchan, *pchan_root=NULL, *chanlist[256], **oldchan; PoseChain *chain; + PoseTarget *target; bConstraint *con; bKinematicConstraint *data; - int a, segcount= 0; + int a, segcount= 0, size, newsize; /* find IK constraint, and validate it */ for(con= pchan_tip->constraints.first; con; con= con->next) { @@ -1006,75 +1008,128 @@ static void initialize_posechain(struct Object *ob, bPoseChannel *pchan_tip) break; } if (!segcount) return; - + /* setup the chain data */ - chain = MEM_callocN(sizeof(PoseChain), "posechain"); - chain->totchannel= segcount; - chain->solver = IK_CreateChain(); - chain->con= con; - - chain->iterations = data->iterations; - chain->tolerance = data->tolerance; - - chain->pchanchain= MEM_callocN(segcount*sizeof(void *), "channel chain"); - for(a=0; apchanchain[a]= chanlist[segcount-a-1]; + chain = NULL; + + /* if part of group, look for existing chain */ + if(strlen(data->group) > 0) + for(chain= pchan_root->chain.first; chain; chain= chain->next) + if(strcmp(data->group, chain->group)==0) break; + + /* create a target */ + target= MEM_callocN(sizeof(PoseTarget), "posetarget"); + target->con= con; + + if(chain==NULL) { + /* make new chain */ + chain= MEM_callocN(sizeof(PoseChain), "posechain"); + + strcpy(chain->group, data->group); + chain->tolerance= data->tolerance; + chain->iterations= data->iterations; + chain->totchannel= segcount; + + chain->pchanchain= MEM_callocN(segcount*sizeof(void *), "channel chain"); + for(a=0; apchanchain[a]= chanlist[segcount-a-1]; + + target->tip= segcount-1; + + /* AND! link the chain to the root */ + BLI_addtail(&pchan_root->chain, chain); } - - /* AND! link the chain to the root */ - BLI_addtail(&pchan_root->chain, chain); + else { + chain->tolerance= MIN2(chain->tolerance, data->tolerance); + chain->iterations= MAX2(data->iterations, chain->iterations); + + /* skip common pose channels and add remaining*/ + size= MIN2(segcount, chain->totchannel); + for(a=0; apchanchain[a]==chanlist[segcount-a-1]; a++); + + segcount= segcount-a; + + target->tip= chain->totchannel + segcount - 1; + + if (segcount > 0) { + /* resize array */ + newsize= chain->totchannel + segcount; + oldchan= chain->pchanchain; + + chain->pchanchain= MEM_callocN(newsize*sizeof(void*), "channel chain"); + memcpy(chain->pchanchain, oldchan, sizeof(void*)*chain->totchannel); + MEM_freeN(oldchan); + + /* add new pose channels at the end, in reverse order */ + for(a=0; apchanchain[chain->totchannel+a]= chanlist[segcount-a-1]; + + chain->totchannel= newsize; + } + + /* move chain to end of list, for correct evaluation order */ + BLI_remlink(&pchan_root->chain, chain); + BLI_addtail(&pchan_root->chain, chain); + } + + /* add target to the chain */ + BLI_addtail(&chain->targets, target); } /* called from within the core where_is_pose loop, all animsystems and constraints were executed & assigned. Now as last we do an IK pass */ static void execute_posechain(Object *ob, PoseChain *chain) { - IK_Segment_Extern *segs; - bPoseChannel *pchan; float R_parmat[3][3]; float iR_parmat[3][3]; float R_bonemat[3][3]; + float goalrot[3][3], goalpos[3]; float rootmat[4][4], imat[4][4]; - float size[3]; - int curseg; + float goal[4][4], goalinv[4][4]; + float size[3], bonesize[3], irest_basis[3][3], full_basis[3][3]; + float length, basis[3][3], rest_basis[3][3], start[3]; + int a, b, flag; + bPoseChannel *pchan; + IK_Segment *seg, *parent, **ikchain, *iktarget; + IK_Solver *solver; + PoseTarget *target; + bKinematicConstraint *data; + Bone *bone; + + if (chain->totchannel == 0) + return; + + ikchain= MEM_mallocN(sizeof(void*)*chain->totchannel, "ik chain"); + + for(a=0; atotchannel; a++) { + pchan= chain->pchanchain[a]; + bone = pchan->bone; + + /* set DoF flag */ + flag= 0; + if((pchan->ikflag & BONE_IK_NO_XDOF) == 0) + flag |= IK_XDOF; + if((pchan->ikflag & BONE_IK_NO_YDOF) == 0) + flag |= IK_YDOF; + if((pchan->ikflag & BONE_IK_NO_ZDOF) == 0) + flag |= IK_ZDOF; + + seg= ikchain[a]= IK_CreateSegment(flag); + + /* find parent */ + if(a == 0) + parent= NULL; + else { + for(b=a-1; chain->pchanchain[b]!=pchan->parent; b--); + parent= ikchain[b]; + } + + IK_SetParent(seg, parent); - /* first set the goal inverse transform, assuming the root of chain was done ok! */ - pchan= chain->pchanchain[0]; - Mat4One(rootmat); - VECCOPY(rootmat[3], pchan->pose_head); - - Mat4MulMat4 (imat, rootmat, ob->obmat); - Mat4Invert (chain->goalinv, imat); - - /* and set and transform goal */ - get_constraint_target_matrix(chain->con, TARGET_BONE, NULL, rootmat, size, 1.0); // 1.0=ctime - VECCOPY (chain->goal, rootmat[3]); - /* do we need blending? */ - if(chain->con->enforce!=1.0) { - float vec[3]; - float fac= chain->con->enforce; - float mfac= 1.0-fac; - - pchan= chain->pchanchain[chain->totchannel-1]; // last bone - VECCOPY(vec, pchan->pose_tail); - Mat4MulVecfl(ob->obmat, vec); // world space - chain->goal[0]= fac*chain->goal[0] + mfac*vec[0]; - chain->goal[1]= fac*chain->goal[1] + mfac*vec[1]; - chain->goal[2]= fac*chain->goal[2] + mfac*vec[2]; - } - Mat4MulVecfl (chain->goalinv, chain->goal); - - /* Now we construct the IK segments */ - segs = MEM_callocN (sizeof(IK_Segment_Extern)*chain->totchannel, "iksegments"); - - for (curseg=0; cursegtotchannel; curseg++){ - - pchan= chain->pchanchain[curseg]; - - /* Get the matrix that transforms from prevbone into this bone */ + /* get the matrix that transforms from prevbone into this bone */ Mat3CpyMat4(R_bonemat, pchan->pose_mat); - if (pchan->parent && (pchan->bone->flag & BONE_IK_TOPARENT)) { + if(pchan->parent && (bone->flag & BONE_IK_TOPARENT)) { Mat3CpyMat4(R_parmat, pchan->parent->pose_mat); } else @@ -1082,33 +1137,116 @@ static void execute_posechain(Object *ob, PoseChain *chain) Mat3Inv(iR_parmat, R_parmat); - /* Mult and Copy the matrix into the basis and transpose (IK lib likes it) */ - Mat3MulMat3((void *)segs[curseg].basis, iR_parmat, R_bonemat); - Mat3Transp((void *)segs[curseg].basis); - - /* Fill out the IK segment */ - segs[curseg].length = pchan->bone->length; + /* gather transformations for this IK segment */ + start[0]= start[1]= start[2]= 0.0; + + /* change length based on bone size */ + Mat3ToSize(R_bonemat, bonesize); + length= bone->length*bonesize[1]; + + Mat3CpyMat3(rest_basis, bone->bone_mat); + + /* compute basis with rest_basis removed */ + Mat3Inv(irest_basis, rest_basis); + Mat3MulMat3(full_basis, iR_parmat, R_bonemat); + Mat3MulMat3(basis, irest_basis, full_basis); + + /* basis must be pure rotation, size was extracted for length already */ + Mat3Ortho(rest_basis); + Mat3Ortho(basis); + + IK_SetTransform(seg, start, rest_basis, basis, length); + + if (pchan->ikflag & BONE_IK_XLIMIT) + IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]); + if (pchan->ikflag & BONE_IK_YLIMIT) + IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]); + if (pchan->ikflag & BONE_IK_ZLIMIT) + IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]); + + IK_SetStiffness(seg, IK_X, pchan->stiffness[0]); + IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]); + IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]); + } + + solver= IK_CreateSolver(ikchain[0]); + + /* set solver goals */ + + /* first set the goal inverse transform, assuming the root of chain was done ok! */ + pchan= chain->pchanchain[0]; + Mat4One(rootmat); + VECCOPY(rootmat[3], pchan->pose_head); + + Mat4MulMat4 (imat, rootmat, ob->obmat); + Mat4Invert (goalinv, imat); + + for(target=chain->targets.first; target; target=target->next) { + data= (bKinematicConstraint*)target->con->data; + + /* 1.0=ctime */ + get_constraint_target_matrix(target->con, TARGET_BONE, NULL, rootmat, size, 1.0); + + /* and set and transform goal */ + Mat4MulMat4(goal, rootmat, goalinv); + + VECCOPY(goalpos, goal[3]); + Mat3CpyMat4(goalrot, goal); + + /* do we need blending? */ + if(target->con->enforce!=1.0) { + float vec[3], q1[4], q2[4], q[4]; + float fac= target->con->enforce; + float mfac= 1.0-fac; + + pchan= chain->pchanchain[target->tip]; + + /* blend position */ + VECCOPY(vec, pchan->pose_tail); + Mat4MulVecfl(ob->obmat, vec); // world space + Mat4MulVecfl(goalinv, vec); + goalpos[0]= fac*goalpos[0] + mfac*vec[0]; + goalpos[1]= fac*goalpos[1] + mfac*vec[1]; + goalpos[2]= fac*goalpos[2] + mfac*vec[2]; + + /* blend rotation */ + Mat3ToQuat(goalrot, q1); + Mat3CpyMat4(R_bonemat, pchan->pose_mat); + Mat3ToQuat(R_bonemat, q2); + QuatInterpol(q, q1, q2, mfac); + QuatToMat3(q, goalrot); + } + + iktarget= ikchain[target->tip]; + + /*IK_SolverAddCenterOfMass(solver, ikchain[0], goalpos, data->weight);*/ + + if(data->weight != 0.0) + IK_SolverAddGoal(solver, iktarget, goalpos, data->weight); + if((data->flag & KINEMATIC_ORIENTATION) && (data->orientweight != 0.0)) + IK_SolverAddGoalOrientation(solver, iktarget, goalrot, data->orientweight); + } + + /* solve */ + IK_Solve(solver, chain->tolerance, chain->iterations); + IK_FreeSolver(solver); + + /* gather basis changes */ + chain->basis_change= MEM_mallocN(sizeof(float[3][3])*chain->totchannel, "ik basis change"); + + for(a=0; atotchannel; a++) { + IK_GetBasisChange(ikchain[a], chain->basis_change[a]); + IK_FreeSegment(ikchain[a]); } - /* Solve the chain */ - - IK_LoadChain(chain->solver, segs, chain->totchannel); - - IK_SolveChain(chain->solver, chain->goal, chain->tolerance, - chain->iterations, 0.1f, chain->solver->segments); - - - /* not yet free! */ + MEM_freeN(ikchain); } void free_posechain (PoseChain *chain) { - if (chain->solver) { - MEM_freeN (chain->solver->segments); - chain->solver->segments = NULL; - IK_FreeChain(chain->solver); - } + BLI_freelistN(&chain->targets); if(chain->pchanchain) MEM_freeN(chain->pchanchain); + if(chain->basis_change) MEM_freeN(chain->basis_change); MEM_freeN(chain); } @@ -1325,16 +1463,19 @@ void where_is_pose (Object *ob) if(!(chain->pchanchain[a]->flag & POSE_DONE)) // successive chains can set the flag where_is_pose_bone(ob, chain->pchanchain[a]); } - /* 5. execute the IK solver */ - execute_posechain(ob, chain); // calculates 3x3 difference matrices + /* 5. execute the IK solver, applying differences to + the channels and setting POSE_DONE */ + execute_posechain(ob, chain); + /* 6. apply the differences to the channels, we calculate the original differences first */ for(a=0; atotchannel; a++) make_dmats(chain->pchanchain[a]); - for(a=0; atotchannel; a++) - where_is_ik_bone(chain->pchanchain[a], (void *)chain->solver->segments[a].basis_change); - // (sets POSE_DONE) - /* 6. and free */ + for(a=0; atotchannel; a++) + /* sets POSE_DONE */ + where_is_ik_bone(chain->pchanchain[a], chain->basis_change[a]); + + /* 7. and free */ BLI_remlink(&pchan->chain, chain); free_posechain(chain); } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 7501957af11..5940c16eccb 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -485,6 +485,7 @@ void *new_constraint_data (short type) data = MEM_callocN(sizeof(bKinematicConstraint), "kinematicConstraint"); data->tolerance = (float)0.001; + data->weight= (float)1.0; data->iterations = 500; data->flag= CONSTRAINT_IK_TIP; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 1ef78b2eb7d..7bf2706956a 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4904,6 +4904,26 @@ static void do_versions(FileData *fd, Library *lib, Main *main) ob->softflag &= ~OB_SB_ENABLE; } + if(ob->pose) { + bPoseChannel *pchan; + bConstraint *con; + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if (pchan->stiffness[0] == 0.0f) { + pchan->stiffness[0]= pchan->stiffness[1]= pchan->stiffness[2]= 1.0; + pchan->limitmin[0]= pchan->limitmin[1]= pchan->limitmin[2]= -180.0f; + pchan->limitmax[0]= pchan->limitmax[1]= pchan->limitmax[2]= 180.0f; + + for(con= pchan->constraints.first; con; con= con->next) { + if(con->type == CONSTRAINT_TYPE_KINEMATIC) { + bKinematicConstraint *data = (bKinematicConstraint*)con->data; + data->weight = 1.0f; + data->orientweight = 0.0f; + data->flag &= ~KINEMATIC_ORIENTATION; + } + } + } + } + } } for(arm=main->armature.first; arm; arm= arm->id.next) { diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 844b1d638fe..edc78a90260 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -47,7 +47,8 @@ typedef struct bPoseChannel { short flag; /* dynamic, for detecting transform changes */ short constflag; /* for quick detecting which constraints affect this channel */ - int pad; + short ikflag; /* settings for IK bones */ + short pad; struct Bone *bone; /* set on read file or rebuild pose */ struct bPoseChannel *parent; /* set on read file or rebuild pose */ @@ -65,7 +66,10 @@ typedef struct bPoseChannel { float pose_head[3]; /* actually pose_mat[3] */ float pose_tail[3]; /* also used for drawing help lines... */ - int pad1; + + float limitmin[3], limitmax[3]; /* DOF constraint */ + float stiffness[3]; /* DOF stiffness */ + } bPoseChannel; @@ -135,11 +139,21 @@ enum { POSE_KEY = 0x1000 }; -/* Pose Channel constflag (constraint detection) */ +/* PoseChannel constflag (constraint detection) */ #define PCHAN_HAS_IK 1 #define PCHAN_HAS_CONST 2 /* only used for drawing Posemode, not stored in channel */ #define PCHAN_HAS_ACTION 4 +/* PoseChannel->ikflag */ +#define BONE_IK_NO_XDOF 1 +#define BONE_IK_NO_YDOF 2 +#define BONE_IK_NO_ZDOF 4 + +#define BONE_IK_XLIMIT 8 +#define BONE_IK_YLIMIT 16 +#define BONE_IK_ZLIMIT 32 + + #endif diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 7a1c899edb5..e8895e942d4 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -67,7 +67,9 @@ typedef struct bKinematicConstraint{ short flag; /* Like IK to Tip */ char subtarget[32]; /* String to specify sub-object target */ - + char group[32]; /* Name of group */ + float weight; /* Weight of goal in IK group */ + float orientweight; } bKinematicConstraint; typedef struct bTrackToConstraint{ @@ -212,7 +214,8 @@ typedef struct bStretchToConstraint{ #define PLANE_Z 0x02 /* bKinematicConstraint->flag */ -#define CONSTRAINT_IK_TIP 1 +#define CONSTRAINT_IK_TIP 1 +#define KINEMATIC_ORIENTATION 2 #endif diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index b8e7cc0738d..adaef66ba64 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -2280,7 +2280,7 @@ static void editing_panel_pose_bones(Object *ob, bArmature *arm) bPoseChannel *pchan; Bone *curBone; int bx=148, by=180; - int index; + int index, zerodof, zerolimit; /* Draw the bone name block */ @@ -2320,7 +2320,53 @@ static void editing_panel_pose_bones(Object *ob, bArmature *arm) uiDefButBitI(block, TOG, BONE_HIDDEN_P, REDRAWVIEW3D, "Hide", bx+245,by-38,88,18, &curBone->flag, 0, 0, 0, 0, "Toggles display of this bone in Pose Mode"); uiBlockEndAlign(block); - by-=60; + zerodof = 1; + zerolimit = 1; + + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, BONE_IK_NO_XDOF, B_ARM_RECALCDATA, "No X DoF", bx-10,by-60,114,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Disable X DoF for IK"); + if ((pchan->ikflag & BONE_IK_NO_XDOF)==0) { + uiDefButF(block, NUM, B_ARM_RECALCDATA, "Stiff X:", bx-10, by-80, 114, 19, &pchan->stiffness[0], 1.0, 100.0, 10.0f, 2.0f, "Resistance to bending for X axis"); + uiDefButBitS(block, TOG, BONE_IK_XLIMIT, B_ARM_RECALCDATA, "Limit X", bx-10,by-100,114,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Limit rotation over X axis"); + if ((pchan->ikflag & BONE_IK_XLIMIT)) { + uiDefButF(block, NUM, B_ARM_RECALCDATA, "Min X:", bx-10, by-120, 114, 19, &pchan->limitmin[0], -180.0f, 180.0f, 10.0f, 0.0f, "Minimum X limit"); + uiDefButF(block, NUM, B_ARM_RECALCDATA, "Max X:", bx-10, by-140, 114, 19, &pchan->limitmax[0], -180.0f, 180.0f, 10.0f, 0.0f, "Maximum X limit"); + zerolimit = 0; + } + zerodof = 0; + } + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, BONE_IK_NO_YDOF, B_ARM_RECALCDATA, "No Y DoF", bx+104,by-60,113,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Disable Y DoF for IK"); + if ((pchan->ikflag & BONE_IK_NO_YDOF)==0) { + uiDefButF(block, NUM, B_ARM_RECALCDATA, "Stiff Y:", bx+104, by-80, 114, 19, &pchan->stiffness[1], 1.0, 100.0, 10.0f, 2.0f, "Resistance to bending for Y axis"); + uiDefButBitS(block, TOG, BONE_IK_YLIMIT, B_ARM_RECALCDATA, "Limit Y", bx+104,by-100,113,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Limit rotation over Y axis"); + if ((pchan->ikflag & BONE_IK_YLIMIT)) { + uiDefButF(block, NUM, B_ARM_RECALCDATA, "Min Y:", bx+104, by-120, 113, 19, &pchan->limitmin[1], -180.0f, 180.0f, 10.0f, 0.0f, "Minimum Y limit"); + uiDefButF(block, NUM, B_ARM_RECALCDATA, "Max Y:", bx+104, by-140, 113, 19, &pchan->limitmax[1], -180.0f, 180.0f, 10.0f, 0.0f, "Maximum Y limit"); + zerolimit = 0; + } + zerodof = 0; + } + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, BONE_IK_NO_ZDOF, B_ARM_RECALCDATA, "No Z DoF", bx+217,by-60,113,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Disable Z DoF for IK"); + if ((pchan->ikflag & BONE_IK_NO_ZDOF)==0) { + uiDefButF(block, NUM, B_ARM_RECALCDATA, "Stiff Z:", bx+217, by-80, 114, 19, &pchan->stiffness[2], 1.0, 100.0, 10.0f, 2.0f, "Resistance to bending for Z axis"); + uiDefButBitS(block, TOG, BONE_IK_ZLIMIT, B_ARM_RECALCDATA, "Limit Z", bx+217,by-100,113,19, &pchan->flag, 0.0, 0.0, 0.0, 0.0, "Limit rotation over Z axis"); + if ((pchan->flag & BONE_IK_ZLIMIT)) { + uiDefButF(block, NUM, B_ARM_RECALCDATA, "Min Z:", bx+217, by-120, 113, 19, &pchan->limitmin[2], -180.0f, 180.0f, 10.0f, 0.0f, "Minimum Z limit"); + uiDefButF(block, NUM, B_ARM_RECALCDATA, "Max Z:", bx+217, by-140, 113, 19, &pchan->limitmax[2], -180.0f, 180.0f, 10.0f, 0.0f, "Maximum Z limit"); + zerolimit = 0; + } + zerodof = 0; + } + uiBlockEndAlign(block); + + by -= (zerodof)? 82: (zerolimit)? 122: 162; + if(by < -200) break; // for time being... extreme long panels are very slow } } diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 834f3d79e9a..7a1ce9463db 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -585,7 +585,7 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s bKinematicConstraint *data = con->data; bArmature *arm; - height = 66; + height = 108; uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+30,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, ""); @@ -608,6 +608,11 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiDefButS(block, NUM, B_CONSTRAINT_TEST, "Iterations:", *xco+((width/2)+3), *yco-64, 120, 18, &data->iterations, 1, 10000, 0.0, 0.0, "Maximum number of solving iterations"); uiBlockEndAlign(block); + uiDefBut(block, TEX, B_CONSTRAINT_TEST, "IK group:", *xco+((width/2)-117), *yco-86,120,18, &data->group, 0, 24, 0, 0, "IK group name"); + uiDefButF(block, NUMSLI, B_CONSTRAINT_TEST, "Weight ", *xco+((width/2)+3), *yco-86, 120, 18, &data->weight, 0.0, 1.0, 0.0, 0.0, "Weight of position control for this target"); + + uiDefButBitS(block, TOG, KINEMATIC_ORIENTATION, B_CONSTRAINT_TEST, "Orientation", *xco+((width/2)-117), *yco-108,120,18, &data->flag, 0, 0, 0, 0, "Follow orientation of target"); + uiDefButF(block, NUMSLI, B_CONSTRAINT_TEST, "Weight ", *xco+((width/2)+3), *yco-108, 120, 18, &data->orientweight, 0.0, 1.0, 0.0, 0.0, "Weight of orientation control for this target"); } break; case CONSTRAINT_TYPE_TRACKTO: