==Armature==
authorMartin Poirier <theeth@yahoo.com>
Thu, 13 Nov 2008 22:35:40 +0000 (22:35 +0000)
committerMartin Poirier <theeth@yahoo.com>
Thu, 13 Nov 2008 22:35:40 +0000 (22:35 +0000)
Fix the roll mess in transform. Since roll is based on an automatically calculated up axis, transforming bones would mess up bone orientation. This code automatically adjusts the roll value to keep bone orientation as consistant as possible. That works all around in transform for all transformations.

Doesn't work with x-axis mirror though as that doesn't use transform elements (fixing it would be nice for later)

Most interesting is that it works with the mirror tool (obviously), so you don't have to fix all the rolls after mirroring one side of an armature.

It could be made an option if someone presents a good enough point for that, but I can't see why you'd want the previous mess instead.

NB: this also ports a utility fonction from etch-a-ton to set bone roll from an up axis.

source/blender/include/BIF_editarmature.h
source/blender/include/transform.h
source/blender/src/editarmature.c
source/blender/src/transform_conversions.c
source/blender/src/transform_generics.c

index 02d736808188b2826ca2103519b3df37126f8ffe..ce275563a873a6eb46713e9f7b0b47ba259d32a1 100644 (file)
@@ -68,6 +68,8 @@ typedef struct EditBone
 
 } EditBone;
 
+float  rollBoneToVector(EditBone *bone, float new_up_axis[3]);
+
 void   make_boneList(struct ListBase *list, struct ListBase *bones, EditBone *parent);
 void   editbones_to_armature (struct ListBase *list, struct Object *ob);
 
index bd91bf8100ad9d74c54982fce0556381c55d68f8..fa7b8fc0a193dfd162af01da0b22b8516841b534 100644 (file)
@@ -160,7 +160,7 @@ typedef struct TransData {
        TransDataExtension *ext;        /* for objects, poses. 1 single malloc per TransInfo! */
        TransDataIpokey *tdi;           /* for objects, ipo keys. per transdata a malloc */
        TransDataCurveHandleFlags *hdata; /* for curves, stores handle flags for modification/cancel */
-       void *tdmir;             /* mirrored element pointer, in editmode mesh to EditVert */
+       void  *extra;            /* extra data (mirrored element pointer, in editmode mesh to EditVert) (editbone for roll fixing) (...) */
     short  flag;         /* Various flags */
        short  protectflag;      /* If set, copy of Object or PoseChannel protection */
 /*#ifdef WITH_VERSE*/
index 5ddf522e4a86aa86e043c2857f0a736ca9ac3b26..ee5d56eaf43f527284944573823484cd44e5a141 100644 (file)
@@ -1817,6 +1817,31 @@ void deselectall_armature(int toggle, int doundo)
        }
 }
 
+/* adjust bone roll to align Z axis with vector
+ * vec is in local space and is normalized
+ */
+float rollBoneToVector(EditBone *bone, float new_up_axis[3])
+{
+       float mat[3][3], nor[3], up_axis[3], vec[3];
+       float roll;
+
+       VecSubf(nor, bone->tail, bone->head);
+       
+       vec_roll_to_mat3(nor, 0, mat);
+       VECCOPY(up_axis, mat[2]);
+       
+       roll = NormalizedVecAngle2(new_up_axis, up_axis);
+       
+       Crossf(vec, up_axis, new_up_axis);
+       
+       if (Inpf(vec, nor) < 0)
+       {
+               roll = -roll;
+       }
+       
+       return roll;
+}
+
 /* Sets the roll value of selected bones, depending on the mode
  *     mode == 0: their z-axes point upwards 
  *     mode == 1: their z-axes point towards 3d-cursor
index 496d5120bb9c989f2c48ce69d04a6da2e06ec6d4..f58eaefc62853e9808c3f4ab0585bd7c163003e4 100644 (file)
@@ -1133,6 +1133,14 @@ static void createTransArmatureVerts(TransInfo *t)
                                        Mat3CpyMat3(td->smtx, smtx);
                                        Mat3CpyMat3(td->mtx, mtx);
 
+                                       VecSubf(delta, ebo->tail, ebo->head);   
+                                       vec_roll_to_mat3(delta, ebo->roll, td->axismtx);
+
+                                       if ((ebo->flag & BONE_ROOTSEL) == 0)
+                                       {
+                                               td->extra = ebo;
+                                       }
+
                                        td->ext = NULL;
                                        td->tdi = NULL;
                                        td->val = NULL;
@@ -1150,6 +1158,11 @@ static void createTransArmatureVerts(TransInfo *t)
                                        Mat3CpyMat3(td->smtx, smtx);
                                        Mat3CpyMat3(td->mtx, mtx);
 
+                                       VecSubf(delta, ebo->tail, ebo->head);   
+                                       vec_roll_to_mat3(delta, ebo->roll, td->axismtx);
+
+                                       td->extra = ebo; /* to fix roll */
+
                                        td->ext = NULL;
                                        td->tdi = NULL;
                                        td->val = NULL;
@@ -1863,7 +1876,7 @@ static void VertsToTransData(TransData *td, EditVert *eve)
        td->ext = NULL;
        td->tdi = NULL;
        td->val = NULL;
-       td->tdmir = NULL;
+       td->extra = NULL;
        if (BIF_GetTransInfo()->mode == TFM_BWEIGHT) {
                td->val = &(eve->bweight);
                td->ival = eve->bweight;
@@ -2216,7 +2229,7 @@ static void createTransEditVerts(TransInfo *t)
                                /* Mirror? */
                                if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) {
                                        EditVert *vmir= editmesh_get_x_mirror_vert(G.obedit, tob->iloc);        /* initializes octree on first call */
-                                       if(vmir != eve) tob->tdmir = vmir;
+                                       if(vmir != eve) tob->extra = vmir;
                                }
                                tob++;
                        }
index 2a91b66ad8ecb29d73af2ffb240c65a6440cea3e..d8bc2158faa5261eb99b94d23d2fdb12ade495db 100644 (file)
@@ -254,7 +254,7 @@ static void editmesh_apply_to_mirror(TransInfo *t)
                if (td->flag & TD_SKIP)
                        continue;
                
-               eve = td->tdmir;
+               eve = td->extra;
                if(eve) {
                        eve->co[0]= -td->loc[0];
                        eve->co[1]= td->loc[1];
@@ -470,6 +470,8 @@ void recalcData(TransInfo *t)
                else if(G.obedit->type==OB_ARMATURE){   /* no recalc flag, does pose */
                        bArmature *arm= G.obedit->data;
                        EditBone *ebo;
+                       TransData *td = t->data;
+                       int i;
                        
                        /* Ensure all bones are correctly adjusted */
                        for (ebo=G.edbo.first; ebo; ebo=ebo->next){
@@ -506,6 +508,28 @@ void recalcData(TransInfo *t)
                                        ebo->oldlength= ebo->length;
                                }
                        }
+                       
+                       /* fix roll */
+                       for(i = 0; i < t->total; i++, td++)
+                       {
+                               if (td->extra)
+                               {
+                                       float vec[3], up_axis[3];
+                                       float qrot[4];
+                                       
+                                       ebo = td->extra;
+                                       
+                                       VecSubf(vec, ebo->tail, ebo->head);
+                                       Normalize(vec);
+                                       RotationBetweenVectorsToQuat(qrot, td->axismtx[1], vec);
+                                       
+                                       VECCOPY(up_axis, td->axismtx[2]);
+                                       QuatMulVecf(qrot, up_axis);
+                                       
+                                       ebo->roll = rollBoneToVector(ebo, up_axis);
+                               }
+                       }
+                       
                        if(arm->flag & ARM_MIRROR_EDIT) 
                                transform_armature_mirror_update();