Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/armature.c')
-rw-r--r--source/blender/blenkernel/intern/armature.c244
1 files changed, 191 insertions, 53 deletions
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 4d50c268397..8bb694f45e8 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -30,6 +30,8 @@
#include <math.h>
#include <string.h>
#include <stdio.h>
+#include <float.h>
+
#include "MEM_guardedalloc.h"
//XXX #include "nla.h"
@@ -354,6 +356,117 @@ void bone_flip_name (char *name, int strip_number)
sprintf (name, "%s%s%s%s", prefix, replace, suffix, number);
}
+/* Finds the best possible extension to the name on a particular axis. (For renaming, check for unique names afterwards)
+ * This assumes that bone names are at most 32 chars long!
+ * strip_number: removes number extensions (TODO: not used)
+ * axis: the axis to name on
+ * head/tail: the head/tail co-ordinate of the bone on the specified axis
+ */
+void bone_autoside_name (char *name, int strip_number, short axis, float head, float tail)
+{
+ int len;
+ char basename[32]={""};
+ char extension[5]={""};
+
+ len= strlen(name);
+ if (len == 0) return;
+ strcpy(basename, name);
+
+ /* Figure out extension to append:
+ * - The extension to append is based upon the axis that we are working on.
+ * - If head happens to be on 0, then we must consider the tail position as well to decide
+ * which side the bone is on
+ * -> If tail is 0, then it's bone is considered to be on axis, so no extension should be added
+ * -> Otherwise, extension is added from perspective of object based on which side tail goes to
+ * - If head is non-zero, extension is added from perspective of object based on side head is on
+ */
+ if (axis == 2) {
+ /* z-axis - vertical (top/bottom) */
+ if (IS_EQ(head, 0)) {
+ if (tail < 0)
+ strcpy(extension, "Bot");
+ else if (tail > 0)
+ strcpy(extension, "Top");
+ }
+ else {
+ if (head < 0)
+ strcpy(extension, "Bot");
+ else
+ strcpy(extension, "Top");
+ }
+ }
+ else if (axis == 1) {
+ /* y-axis - depth (front/back) */
+ if (IS_EQ(head, 0)) {
+ if (tail < 0)
+ strcpy(extension, "Fr");
+ else if (tail > 0)
+ strcpy(extension, "Bk");
+ }
+ else {
+ if (head < 0)
+ strcpy(extension, "Fr");
+ else
+ strcpy(extension, "Bk");
+ }
+ }
+ else {
+ /* x-axis - horizontal (left/right) */
+ if (IS_EQ(head, 0)) {
+ if (tail < 0)
+ strcpy(extension, "R");
+ else if (tail > 0)
+ strcpy(extension, "L");
+ }
+ else {
+ if (head < 0)
+ strcpy(extension, "R");
+ else if (head > 0)
+ strcpy(extension, "L");
+ }
+ }
+
+ /* Simple name truncation
+ * - truncate if there is an extension and it wouldn't be able to fit
+ * - otherwise, just append to end
+ */
+ if (extension[0]) {
+ int change = 1;
+
+ while (change) { /* remove extensions */
+ change = 0;
+ if (len > 2 && basename[len-2]=='.') {
+ if (basename[len-1]=='L' || basename[len-1] == 'R' ) { /* L R */
+ basename[len-2] = '\0';
+ len-=2;
+ change= 1;
+ }
+ } else if (len > 3 && basename[len-3]=='.') {
+ if ( (basename[len-2]=='F' && basename[len-1] == 'r') || /* Fr */
+ (basename[len-2]=='B' && basename[len-1] == 'k') /* Bk */
+ ) {
+ basename[len-3] = '\0';
+ len-=3;
+ change= 1;
+ }
+ } else if (len > 4 && basename[len-4]=='.') {
+ if ( (basename[len-3]=='T' && basename[len-2]=='o' && basename[len-1] == 'p') || /* Top */
+ (basename[len-3]=='B' && basename[len-2]=='o' && basename[len-1] == 't') /* Bot */
+ ) {
+ basename[len-4] = '\0';
+ len-=4;
+ change= 1;
+ }
+ }
+ }
+
+ if ((32 - len) < strlen(extension) + 1) { /* add 1 for the '.' */
+ strncpy(name, basename, len-strlen(extension));
+ }
+ }
+
+ sprintf(name, "%s.%s", basename, extension);
+}
/* ************* B-Bone support ******************* */
@@ -1305,18 +1418,27 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
bPoseChannel *pchan, *pchanp, pchanw;
bConstraint *con;
- if(frompose==NULL) return;
+ if (frompose==NULL) return;
/* exception, armature local layer should be proxied too */
- if(pose->proxy_layer)
+ if (pose->proxy_layer)
((bArmature *)ob->data)->layer= pose->proxy_layer;
/* clear all transformation values from library */
rest_pose(frompose);
- pchan= pose->chanbase.first;
- for(; pchan; pchan= pchan->next) {
- if(pchan->bone->layer & layer_protected) {
+ /* copy over all of the proxy's bone groups */
+ /* TODO for later - implement 'local' bone groups as for constraints
+ * Note: this isn't trivial, as bones reference groups by index not by pointer,
+ * so syncing things correctly needs careful attention
+ */
+ BLI_freelistN(&pose->agroups);
+ BLI_duplicatelist(&pose->agroups, &frompose->agroups);
+ pose->active_group= frompose->active_group;
+
+ for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
+ if (pchan->bone->layer & layer_protected) {
+ ListBase proxylocal_constraints = {NULL, NULL};
pchanp= get_pose_channel(frompose, pchan->name);
/* copy posechannel to temp, but restore important pointers */
@@ -1327,9 +1449,16 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
pchanw.child= pchan->child;
pchanw.path= NULL;
- /* constraints, set target ob pointer to own object */
+ /* constraints - proxy constraints are flushed... local ones are added after
+ * 1. extract constraints not from proxy (CONSTRAINT_PROXY_LOCAL) from pchan's constraints
+ * 2. copy proxy-pchan's constraints on-to new
+ * 3. add extracted local constraints back on top
+ */
+ extract_proxylocal_constraints(&proxylocal_constraints, &pchan->constraints);
copy_constraints(&pchanw.constraints, &pchanp->constraints);
+ addlisttolist(&pchanw.constraints, &proxylocal_constraints);
+ /* constraints - set target ob pointer to own object */
for (con= pchanw.constraints.first; con; con= con->next) {
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
@@ -1444,21 +1573,16 @@ static void initialize_posetree(struct Object *ob, bPoseChannel *pchan_tip)
/* find IK constraint, and validate it */
for(con= pchan_tip->constraints.first; con; con= con->next) {
- if(con->type==CONSTRAINT_TYPE_KINEMATIC) break;
+ if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
+ data=(bKinematicConstraint*)con->data;
+ if (data->flag & CONSTRAINT_IK_AUTO) break;
+ if (data->tar==NULL) continue;
+ if (data->tar->type==OB_ARMATURE && data->subtarget[0]==0) continue;
+ if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0)) break;
+ }
}
if(con==NULL) return;
- data=(bKinematicConstraint*)con->data;
-
- /* two types of targets */
- if(data->flag & CONSTRAINT_IK_AUTO);
- else {
- if(con->flag & CONSTRAINT_DISABLE) return; /* checked in editconstraint.c */
- if(con->enforce == 0.0f) return;
- if(data->tar==NULL) return;
- if(data->tar->type==OB_ARMATURE && data->subtarget[0]==0) return;
- }
-
/* exclude tip from chain? */
if(!(data->flag & CONSTRAINT_IK_TIP))
pchan_tip= pchan_tip->parent;
@@ -1561,7 +1685,7 @@ static void initialize_posetree(struct Object *ob, bPoseChannel *pchan_tip)
were executed & assigned. Now as last we do an IK pass */
static void execute_posetree(Object *ob, PoseTree *tree)
{
- float R_parmat[3][3];
+ float R_parmat[3][3], identity[3][3];
float iR_parmat[3][3];
float R_bonemat[3][3];
float goalrot[3][3], goalpos[3];
@@ -1570,7 +1694,8 @@ static void execute_posetree(Object *ob, PoseTree *tree)
float irest_basis[3][3], full_basis[3][3];
float end_pose[4][4], world_pose[4][4];
float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch=NULL;
- int a, flag, hasstretch=0;
+ float resultinf=0.0f;
+ int a, flag, hasstretch=0, resultblend=0;
bPoseChannel *pchan;
IK_Segment *seg, *parent, **iktree, *iktarget;
IK_Solver *solver;
@@ -1580,13 +1705,13 @@ static void execute_posetree(Object *ob, PoseTree *tree)
if (tree->totchannel == 0)
return;
-
+
iktree= MEM_mallocN(sizeof(void*)*tree->totchannel, "ik tree");
for(a=0; a<tree->totchannel; a++) {
pchan= tree->pchan[a];
bone= pchan->bone;
-
+
/* set DoF flag */
flag= 0;
if(!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP))
@@ -1595,32 +1720,32 @@ static void execute_posetree(Object *ob, PoseTree *tree)
flag |= IK_YDOF;
if(!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP))
flag |= IK_ZDOF;
-
+
if(tree->stretch && (pchan->ikstretch > 0.0)) {
flag |= IK_TRANS_YDOF;
hasstretch = 1;
}
-
+
seg= iktree[a]= IK_CreateSegment(flag);
-
+
/* find parent */
if(a == 0)
parent= NULL;
else
parent= iktree[tree->parent[a]];
-
+
IK_SetParent(seg, parent);
-
+
/* get the matrix that transforms from prevbone into this bone */
Mat3CpyMat4(R_bonemat, pchan->pose_mat);
-
+
/* gather transformations for this IK segment */
-
+
if (pchan->parent)
Mat3CpyMat4(R_parmat, pchan->parent->pose_mat);
else
Mat3One(R_parmat);
-
+
/* bone offset */
if (pchan->parent && (a > 0))
VecSubf(start, pchan->pose_head, pchan->parent->pose_tail);
@@ -1630,40 +1755,40 @@ static void execute_posetree(Object *ob, PoseTree *tree)
/* change length based on bone size */
length= bone->length*VecLength(R_bonemat[1]);
-
+
/* compute rest basis and its inverse */
Mat3CpyMat3(rest_basis, bone->bone_mat);
Mat3CpyMat3(irest_basis, bone->bone_mat);
Mat3Transp(irest_basis);
-
+
/* compute basis with rest_basis removed */
Mat3Inv(iR_parmat, R_parmat);
Mat3MulMat3(full_basis, iR_parmat, R_bonemat);
Mat3MulMat3(basis, irest_basis, full_basis);
-
+
/* basis must be pure rotation */
Mat3Ortho(basis);
-
+
/* transform offset into local bone space */
Mat3Ortho(iR_parmat);
Mat3MulVecfl(iR_parmat, start);
-
+
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]);
-
+
if(tree->stretch && (pchan->ikstretch > 0.0)) {
float ikstretch = pchan->ikstretch*pchan->ikstretch;
- IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0-ikstretch, 0.999));
+ IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0-ikstretch, 0.99));
IK_SetLimit(seg, IK_TRANS_Y, 0.001, 1e10);
}
}
@@ -1689,7 +1814,7 @@ static void execute_posetree(Object *ob, PoseTree *tree)
for (target=tree->targets.first; target; target=target->next) {
float polepos[3];
int poleconstrain= 0;
-
+
data= (bKinematicConstraint*)target->con->data;
/* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though
@@ -1706,7 +1831,7 @@ static void execute_posetree(Object *ob, PoseTree *tree)
/* same for pole vector target */
if(data->poletar) {
get_constraint_target_matrix(target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
-
+
if(data->flag & CONSTRAINT_IK_SETANGLE) {
/* don't solve IK when we are setting the pole angle */
break;
@@ -1716,6 +1841,12 @@ static void execute_posetree(Object *ob, PoseTree *tree)
VECCOPY(polepos, goal[3]);
poleconstrain= 1;
+ /* for pole targets, we blend the result of the ik solver
+ * instead of the target position, otherwise we can't get
+ * a smooth transition */
+ resultblend= 1;
+ resultinf= target->con->enforce;
+
if(data->flag & CONSTRAINT_IK_GETANGLE) {
poleangledata= data;
data->flag &= ~CONSTRAINT_IK_GETANGLE;
@@ -1724,7 +1855,7 @@ static void execute_posetree(Object *ob, PoseTree *tree)
}
/* do we need blending? */
- if (target->con->enforce!=1.0) {
+ if (!resultblend && target->con->enforce!=1.0) {
float q1[4], q2[4], q[4];
float fac= target->con->enforce;
float mfac= 1.0-fac;
@@ -1774,36 +1905,41 @@ static void execute_posetree(Object *ob, PoseTree *tree)
tree->basis_change= MEM_mallocN(sizeof(float[3][3])*tree->totchannel, "ik basis change");
if(hasstretch)
ikstretch= MEM_mallocN(sizeof(float)*tree->totchannel, "ik stretch");
-
+
for(a=0; a<tree->totchannel; a++) {
IK_GetBasisChange(iktree[a], tree->basis_change[a]);
-
+
if(hasstretch) {
/* have to compensate for scaling received from parent */
float parentstretch, stretch;
-
+
pchan= tree->pchan[a];
parentstretch= (tree->parent[a] >= 0)? ikstretch[tree->parent[a]]: 1.0;
-
+
if(tree->stretch && (pchan->ikstretch > 0.0)) {
float trans[3], length;
-
+
IK_GetTranslationChange(iktree[a], trans);
length= pchan->bone->length*VecLength(pchan->pose_mat[1]);
-
+
ikstretch[a]= (length == 0.0)? 1.0: (trans[1]+length)/length;
}
else
ikstretch[a] = 1.0;
-
+
stretch= (parentstretch == 0.0)? 1.0: ikstretch[a]/parentstretch;
-
+
VecMulf(tree->basis_change[a][0], stretch);
VecMulf(tree->basis_change[a][1], stretch);
VecMulf(tree->basis_change[a][2], stretch);
-
}
+ if(resultblend && resultinf!=1.0f) {
+ Mat3One(identity);
+ Mat3BlendMat3(tree->basis_change[a], identity,
+ tree->basis_change[a], resultinf);
+ }
+
IK_FreeSegment(iktree[a]);
}
@@ -2072,8 +2208,10 @@ static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime)
}
else {
Mat4MulMat4(pchan->pose_mat, pchan->chan_mat, bone->arm_mat);
- /* only rootbones get the cyclic offset */
- VecAddf(pchan->pose_mat[3], pchan->pose_mat[3], ob->pose->cyclic_offset);
+
+ /* only rootbones get the cyclic offset (unless user doesn't want that) */
+ if ((bone->flag & BONE_NO_CYCLICOFFSET) == 0)
+ VecAddf(pchan->pose_mat[3], pchan->pose_mat[3], ob->pose->cyclic_offset);
}
/* do NLA strip modifiers - i.e. curve follow */