bugfix [#24907] bone roll z up broken and python script showing correct method to...
authorCampbell Barton <ideasman42@gmail.com>
Thu, 25 Nov 2010 19:49:07 +0000 (19:49 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 25 Nov 2010 19:49:07 +0000 (19:49 +0000)
from Josh Wedlake (joshwedlake), who provided a reference script used to apply changes in ED_rollBoneToVector().

- Obvious bug fixed where Z-Up didnt work right.
- More align axis options to Recalculate Roll operator: X/Y/Z/View Axis & Negate.
- Axis Only option, ignore the axis direction, use shortest rotation to align bones.

ED_rollBoneToVector() changes:
- would give bad roll when the axis wasn't normalized or perpendicular to the bone.
  some callers accounted for this but not all.
- option to align to the axis but not the direction.

source/blender/blenlib/BLI_math_vector.h
source/blender/blenlib/intern/math_vector_inline.c
source/blender/editors/armature/editarmature.c
source/blender/editors/armature/editarmature_generate.c
source/blender/editors/armature/editarmature_retarget.c
source/blender/editors/include/ED_armature.h
source/blender/editors/transform/transform_generics.c
source/blender/makesrna/intern/rna_armature_api.c

index 2e59695..ec62954 100644 (file)
@@ -121,15 +121,15 @@ void mid_v3_v3v3(float r[3], const float a[3], const float b[3]);
 
 /********************************* Comparison ********************************/
 
-MINLINE int is_zero_v3(float a[3]);
-MINLINE int is_one_v3(float a[3]);
+MINLINE int is_zero_v3(const float a[3]);
+MINLINE int is_one_v3(const float a[3]);
 
-MINLINE int equals_v3v3(float a[3], float b[3]);
-MINLINE int compare_v3v3(float a[3], float b[3], float limit);
-MINLINE int compare_len_v3v3(float a[3], float b[3], float limit);
+MINLINE int equals_v3v3(const float a[3], const float b[3]);
+MINLINE int compare_v3v3(const float a[3], const float b[3], const float limit);
+MINLINE int compare_len_v3v3(const float a[3], const float b[3], const float limit);
 
-MINLINE int compare_v4v4(float a[4], float b[4], float limit);
-MINLINE int equals_v4v4(float a[4], float b[4]);
+MINLINE int compare_v4v4(const float a[4], const float b[4], const float limit);
+MINLINE int equals_v4v4(const float a[4], const float b[4]);
 
 MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2]);
 
index 6bccb00..9718b37 100644 (file)
@@ -419,27 +419,27 @@ MINLINE void normal_float_to_short_v3(short *out, const float *in)
 
 /********************************* Comparison ********************************/
 
-MINLINE int is_zero_v3(float *v)
+MINLINE int is_zero_v3(const float *v)
 {
        return (v[0] == 0 && v[1] == 0 && v[2] == 0);
 }
 
-MINLINE int is_one_v3(float *v)
+MINLINE int is_one_v3(const float *v)
 {
        return (v[0] == 1 && v[1] == 1 && v[2] == 1);
 }
 
-MINLINE int equals_v3v3(float *v1, float *v2)
+MINLINE int equals_v3v3(const float *v1, const float *v2)
 {
        return ((v1[0]==v2[0]) && (v1[1]==v2[1]) && (v1[2]==v2[2]));
 }
 
-MINLINE int equals_v4v4(float *v1, float *v2)
+MINLINE int equals_v4v4(const float *v1, const float *v2)
 {
        return ((v1[0]==v2[0]) && (v1[1]==v2[1]) && (v1[2]==v2[2]) && (v1[3]==v2[3]));
 }
 
-MINLINE int compare_v3v3(float *v1, float *v2, float limit)
+MINLINE int compare_v3v3(const float *v1, const float *v2, const float limit)
 {
        if(fabs(v1[0]-v2[0])<limit)
                if(fabs(v1[1]-v2[1])<limit)
@@ -449,7 +449,7 @@ MINLINE int compare_v3v3(float *v1, float *v2, float limit)
        return 0;
 }
 
-MINLINE int compare_len_v3v3(float *v1, float *v2, float limit)
+MINLINE int compare_len_v3v3(const float *v1, const float *v2, const float limit)
 {
        float x,y,z;
 
@@ -460,7 +460,7 @@ MINLINE int compare_len_v3v3(float *v1, float *v2, float limit)
        return ((x*x + y*y + z*z) < (limit*limit));
 }
 
-MINLINE int compare_v4v4(float *v1, float *v2, float limit)
+MINLINE int compare_v4v4(const float *v1, const float *v2, const float limit)
 {
        if(fabs(v1[0]-v2[0])<limit)
                if(fabs(v1[1]-v2[1])<limit)
index 3e40ae4..61d16f9 100644 (file)
@@ -31,6 +31,7 @@
 #include <string.h>
 #include <math.h> 
 #include <float.h> 
+#include <assert.h> 
 
 
 #include "DNA_anim_types.h"
@@ -2066,136 +2067,110 @@ void ED_armature_to_edit(Object *ob)
 /* adjust bone roll to align Z axis with vector
  * vec is in local space and is normalized
  */
-float ED_rollBoneToVector(EditBone *bone, float new_up_axis[3])
+
+float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const short axis_only)
 {
-       float mat[3][3], nor[3], up_axis[3], vec[3];
-       float roll;
+       float mat[3][3], nor[3];
 
        sub_v3_v3v3(nor, bone->tail, bone->head);
-       
-       vec_roll_to_mat3(nor, 0, mat);
-       copy_v3_v3(up_axis, mat[2]);
-       
-       roll = angle_normalized_v3v3(new_up_axis, up_axis);
-       
-       cross_v3_v3v3(vec, up_axis, new_up_axis);
-       
-       if (dot_v3v3(vec, nor) < 0)
-       {
-               roll = -roll;
-       }
-       
-       return roll;
-}
+       vec_roll_to_mat3(nor, 0.0f, mat);
 
+       /* check the bone isnt aligned with the axis */
+       if(!is_zero_v3(align_axis) && angle_v3v3(align_axis, mat[2]) > FLT_EPSILON) {
+               float vec[3], align_axis_proj[3], roll;
 
-/* Set roll value for given bone -> Z-Axis Point up (original method) */
-static void auto_align_ebone_zaxisup(Scene *UNUSED(scene), View3D *UNUSED(v3d), EditBone *ebone)
-{
-       float   delta[3], curmat[3][3];
-       float   xaxis[3]={1.0f, 0.0f, 0.0f}, yaxis[3], zaxis[3]={0.0f, 0.0f, 1.0f};
-       float   targetmat[3][3], imat[3][3], diffmat[3][3];
-       
-       /* Find the current bone matrix */
-       sub_v3_v3v3(delta, ebone->tail, ebone->head);
-       vec_roll_to_mat3(delta, 0.0f, curmat);
-       
-       /* Make new matrix based on y axis & z-up */
-       copy_v3_v3(yaxis, curmat[1]);
-       
-       unit_m3(targetmat);
-       copy_v3_v3(targetmat[0], xaxis);
-       copy_v3_v3(targetmat[1], yaxis);
-       copy_v3_v3(targetmat[2], zaxis);
-       normalize_m3(targetmat);
-       
-       /* Find the difference between the two matrices */
-       invert_m3_m3(imat, targetmat);
-       mul_m3_m3m3(diffmat, imat, curmat);
-       
-       // old-method... let's see if using mat3_to_vec_roll is more accurate
-       //ebone->roll = atan2(diffmat[2][0], diffmat[2][2]);  
-       mat3_to_vec_roll(diffmat, delta, &ebone->roll);
-}
-
-void auto_align_ebone_topoint(EditBone *ebone, float *cursor)
-{
-       float   delta[3], curmat[3][3];
-       float   mat[4][4], tmat[4][4], imat[4][4];
-       float   rmat[4][4], rot[3];
-       float   vec[3];
-
-       /* find the current bone matrix as a 4x4 matrix (in Armature Space) */
-       sub_v3_v3v3(delta, ebone->tail, ebone->head);
-       vec_roll_to_mat3(delta, ebone->roll, curmat);
-       copy_m4_m3(mat, curmat);
-       copy_v3_v3(mat[3], ebone->head);
-       
-       /* multiply bone-matrix by object matrix (so that bone-matrix is in WorldSpace) */
-       invert_m4_m4(imat, mat);
-       
-       /* find position of cursor relative to bone */
-       mul_v3_m4v3(vec, imat, cursor);
-       
-       /* check that cursor is in usable position */
-       if ((IS_EQ(vec[0], 0)==0) && (IS_EQ(vec[2], 0)==0)) {
-               /* Compute a rotation matrix around y */
-               rot[1] = (float)atan2(vec[0], vec[2]);
-               rot[0] = rot[2] = 0.0f;
-               eul_to_mat4( rmat,rot);
+               /* project the new_up_axis along the normal */
+               project_v3_v3v3(vec, align_axis, nor);
+               sub_v3_v3v3(align_axis_proj, align_axis, vec);
                
-               /* Multiply the bone matrix by rotation matrix. This should be new bone-matrix */
-               mul_m4_m4m4(tmat, rmat, mat);
-               copy_m3_m4(curmat, tmat);
+               if(axis_only) {
+                       if(angle_v3v3(align_axis_proj, mat[2]) > M_PI/2) {
+                               negate_v3(align_axis_proj);
+                       }
+               }
                
-               /* Now convert from new bone-matrix, back to a roll value (in radians) */
-               mat3_to_vec_roll(curmat, delta, &ebone->roll);
-       }
-}
+               roll = angle_v3v3(align_axis_proj, mat[2]);
+               
+               cross_v3_v3v3(vec, mat[2], align_axis_proj);
+               
+               if (dot_v3v3(vec, nor) < 0) {
+                       roll = -roll;
+               }
 
-static void auto_align_ebone_tocursor(Scene *scene, View3D *v3d, EditBone *ebone)
-{
-       float cursor_local[3];
-       float   *cursor= give_cursor(scene, v3d);
-       float imat[3][3];
+               return roll;
+       }
 
-       copy_m3_m4(imat, scene->obedit->obmat);
-       invert_m3(imat);
-       copy_v3_v3(cursor_local, cursor);
-       mul_m3_v3(imat, cursor_local);
-       auto_align_ebone_topoint(ebone, cursor_local);
+       return 0.0f;
 }
 
+
 static EnumPropertyItem prop_calc_roll_types[] = {
-       {0, "GLOBALUP", 0, "Z-Axis Up", ""},
-       {1, "CURSOR", 0, "Z-Axis to Cursor", ""},
+       {0, "X", 0, "X Axis", ""},
+       {1, "Y", 0, "Y Axis", ""},
+       {2, "Z", 0, "Z Axis", ""},
+       {6, "VIEW", 0, "View Axis", ""},
+       {7, "CURSOR", 0, "Cursor", ""},
        {0, NULL, 0, NULL, NULL}
 };
 
+
 static int armature_calc_roll_exec(bContext *C, wmOperator *op) 
 {
-       Scene *scene= CTX_data_scene(C);
-       View3D *v3d= CTX_wm_view3d(C);
        Object *ob= CTX_data_edit_object(C);
-       void (*roll_func)(Scene *, View3D *, EditBone *) = NULL;
+       const short type= RNA_enum_get(op->ptr, "type");
+       const short axis_only= RNA_boolean_get(op->ptr, "axis_only");
+       const short axis_flip= RNA_boolean_get(op->ptr, "axis_flip");
+
+       float imat[3][3];
+
+       copy_m3_m4(imat, ob->obmat);
+       invert_m3(imat);
+
+       if(type==7) { /* Cursor */
+               Scene *scene= CTX_data_scene(C);
+               View3D *v3d= CTX_wm_view3d(C); /* can be NULL */
+               float cursor_local[3];
+               float   *cursor= give_cursor(scene, v3d);
        
-       /* specific method used to calculate roll depends on mode */
-       switch (RNA_enum_get(op->ptr, "type")) {
-               case 1:  /* Z-Axis point towards cursor */
-                       roll_func= auto_align_ebone_tocursor;
-                       break;
-               default: /* Z-Axis Point Up */
-                       roll_func= auto_align_ebone_zaxisup;
-                       break;
+
+               copy_v3_v3(cursor_local, cursor);
+               mul_m3_v3(imat, cursor_local);
+
+               /* cursor */
+               CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) {
+                       float cursor_rel[3];
+                       sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
+                       if(axis_flip) negate_v3(cursor_rel);
+                       ebone->roll= ED_rollBoneToVector(ebone, cursor_rel, axis_only);
+               }
+               CTX_DATA_END;
        }
-       
-       /* recalculate roll on selected bones */
-       CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) {
-               /* roll func is a callback which assumes that all is well */
-               roll_func(scene, v3d, ebone);
+       else {
+               float vec[3]= {0.0f, 0.0f, 0.0f};
+               if(type==6) { /* View */
+                       RegionView3D *rv3d= CTX_wm_region_view3d(C);
+                       if(rv3d==NULL) {
+                               BKE_report(op->reports, RPT_ERROR, "No region view3d available");
+                               return OPERATOR_CANCELLED;
+                       }
+
+                       copy_v3_v3(vec, rv3d->viewinv[2]);
+               }
+               else { /* Axis */
+                       assert(type >= 0 && type <= 5);
+                       if(type<3)      vec[type]= 1.0f; 
+                       else            vec[type-2]= -1.0f; 
+               }
+
+               mul_m3_v3(imat, vec);
+               if(axis_flip) negate_v3(vec);
+
+               CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) {
+                       /* roll func is a callback which assumes that all is well */
+                       ebone->roll= ED_rollBoneToVector(ebone, vec, axis_only);
+               }
+               CTX_DATA_END;
        }
-       CTX_DATA_END;
-       
 
        /* note, notifier might evolve */
        WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
@@ -2216,9 +2191,11 @@ void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-       
+
        /* properties */
        ot->prop= RNA_def_enum(ot->srna, "type", prop_calc_roll_types, 0, "Type", "");
+       RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis.");
+       RNA_def_boolean(ot->srna, "axis_only", 0, "Shortest Rotation", "Ignore the axis direction, use the shortest rotation to align.");
 }
 
 /* **************** undo for armatures ************** */
index 6eda622..6abdd85 100644 (file)
@@ -50,18 +50,12 @@ void setBoneRollFromNormal(EditBone *bone, float *no, float UNUSED(invmat[][4]),
 {
        if (no != NULL && !is_zero_v3(no))
        {
-               float tangent[3], vec[3], normal[3];
+               float normal[3];
 
-               VECCOPY(normal, no);    
+               copy_v3_v3(normal, no); 
                mul_m3_v3(tmat, normal);
-
-               sub_v3_v3v3(tangent, bone->tail, bone->head);
-               project_v3_v3v3(vec, tangent, normal);
-               sub_v3_v3(normal, vec);
-               
-               normalize_v3(normal);
                
-               bone->roll = ED_rollBoneToVector(bone, normal);
+               bone->roll = ED_rollBoneToVector(bone, normal, FALSE);
        }
 }
 
index d50f2d0..4ddc73d 100644 (file)
@@ -185,12 +185,12 @@ float rollBoneByQuatAligned(EditBone *bone, float old_up_axis[3], float qrot[4],
        if (angle_normalized_v3v3(x_axis, new_up_axis) < angle_normalized_v3v3(z_axis, new_up_axis))
        {
                rotation_between_vecs_to_quat(qroll, new_up_axis, x_axis); /* set roll rotation quat */
-               return ED_rollBoneToVector(bone, x_axis);
+               return ED_rollBoneToVector(bone, x_axis, FALSE);
        }
        else
        {
                rotation_between_vecs_to_quat(qroll, new_up_axis, z_axis); /* set roll rotation quat */
-               return ED_rollBoneToVector(bone, z_axis);
+               return ED_rollBoneToVector(bone, z_axis, FALSE);
        }
 }
 
@@ -240,7 +240,7 @@ float rollBoneByQuatJoint(RigEdge *edge, RigEdge *previous, float qrot[4], float
                /* real qroll between normal and up_axis */
                rotation_between_vecs_to_quat(qroll, new_up_axis, normal);
 
-               return ED_rollBoneToVector(edge->bone, normal);
+               return ED_rollBoneToVector(edge->bone, normal, FALSE);
        }
 }
 
@@ -251,9 +251,7 @@ float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4])
        VECCOPY(new_up_axis, old_up_axis);
        mul_qt_v3(qrot, new_up_axis);
        
-       normalize_v3(new_up_axis);
-       
-       return ED_rollBoneToVector(bone, new_up_axis);
+       return ED_rollBoneToVector(bone, new_up_axis, FALSE);
 }
 
 /************************************ DESTRUCTORS ******************************************************/
index 16091e4..0db8ffd 100644 (file)
@@ -115,7 +115,7 @@ int ED_do_pose_selectbuffer(struct Scene *scene, struct Base *base, unsigned int
 int mouse_armature(struct bContext *C, short mval[2], int extend);
 int join_armature_exec(struct bContext *C, struct wmOperator *op);
 struct Bone *get_indexed_bone (struct Object *ob, int index);
-float ED_rollBoneToVector(EditBone *bone, float new_up_axis[3]);
+float ED_rollBoneToVector(EditBone *bone, const float new_up_axis[3], const short axis_only);
 EditBone *ED_armature_bone_get_mirrored(struct ListBase *edbo, EditBone *ebo); // XXX this is needed for populating the context iterators
 void ED_armature_sync_selection(struct ListBase *edbo);
 void ED_armature_validate_active(struct bArmature *arm);
index 02db25f..8ff852b 100644 (file)
@@ -747,7 +747,7 @@ void recalcData(TransInfo *t)
                                                                mul_m3_v3(t->mat, up_axis);
                                                        }
                                                        
-                                                       ebo->roll = ED_rollBoneToVector(ebo, up_axis);
+                                                       ebo->roll = ED_rollBoneToVector(ebo, up_axis, FALSE);
                                                }
                                        }
                                }
index 4c19e66..a2b765e 100644 (file)
 #include "BLI_blenlib.h"
 #include "BKE_armature.h"
 
-void rna_EditBone_align_roll(EditBone *ebo, float *no)
+void rna_EditBone_align_roll(EditBone *ebo, float no[3])
 {
-       if(!is_zero_v3(no)) {
-               float normal[3];
-               copy_v3_v3(normal, no);
-               normalize_v3(normal);
-               ebo->roll= ED_rollBoneToVector(ebo, normal);
-       }
+       ebo->roll= ED_rollBoneToVector(ebo, no, FALSE);
 }
 
 float rna_Bone_do_envelope(Bone *bone, float *vec)