== Bone Roll - Align to Cursor ==
In this commit, a new way to set the bone roll is introduced. It aligns the z-axis of the selected bone(s) to the 3D-Cursor, so that the cursor intersects with the YZ plane. This makes it easier to align bone rolls to a target, for use in rigs where arms/legs are not horizontal/vertical. To use this, just press Ctrl N, and choose the "Align Z-Axis to 3D-Cursor" option. Credits go to Robert Christian (wavez) for providing the method as a working BPy script, that demonstrated this in action.
This commit is contained in:
@@ -108,7 +108,7 @@ void selectconnected_posearmature(void);
|
|||||||
void select_bone_parent(void);
|
void select_bone_parent(void);
|
||||||
void unique_editbone_name (struct ListBase *ebones, char *name);
|
void unique_editbone_name (struct ListBase *ebones, char *name);
|
||||||
|
|
||||||
void auto_align_armature(void);
|
void auto_align_armature(short mode);
|
||||||
void create_vgroups_from_armature(Object *ob, Object *par);
|
void create_vgroups_from_armature(Object *ob, Object *par);
|
||||||
|
|
||||||
void hide_selected_pose_bones(void);
|
void hide_selected_pose_bones(void);
|
||||||
|
|||||||
@@ -1866,7 +1866,6 @@ static void validate_bonebutton_cb(void *bonev, void *namev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void v3d_posearmature_buts(uiBlock *block, Object *ob, float lim)
|
static void v3d_posearmature_buts(uiBlock *block, Object *ob, float lim)
|
||||||
{
|
{
|
||||||
uiBut *but;
|
uiBut *but;
|
||||||
@@ -1954,10 +1953,10 @@ static void v3d_editarmature_buts(uiBlock *block, Object *ob, float lim)
|
|||||||
uiDefButF(block, NUM, B_ARMATUREPANEL1, "TipY:", 160, 50, 140, 19, ebone->tail+1, -lim, lim, 10, 3, "");
|
uiDefButF(block, NUM, B_ARMATUREPANEL1, "TipY:", 160, 50, 140, 19, ebone->tail+1, -lim, lim, 10, 3, "");
|
||||||
uiDefButF(block, NUM, B_ARMATUREPANEL1, "TipZ:", 160, 30, 140, 19, ebone->tail+2, -lim, lim, 10, 3, "");
|
uiDefButF(block, NUM, B_ARMATUREPANEL1, "TipZ:", 160, 30, 140, 19, ebone->tail+2, -lim, lim, 10, 3, "");
|
||||||
uiBlockEndAlign(block);
|
uiBlockEndAlign(block);
|
||||||
|
|
||||||
tfp->ob_eul[0]= 180.0*ebone->roll/M_PI;
|
tfp->ob_eul[0]= 180.0*ebone->roll/M_PI;
|
||||||
uiDefButF(block, NUM, B_ARMATUREPANEL1, "Roll:", 10, 100, 140, 19, tfp->ob_eul, -lim, lim, 1000, 3, "");
|
uiDefButF(block, NUM, B_ARMATUREPANEL1, "Roll:", 10, 100, 140, 19, tfp->ob_eul, -lim, lim, 1000, 3, "");
|
||||||
|
|
||||||
|
|
||||||
uiBlockBeginAlign(block);
|
uiBlockBeginAlign(block);
|
||||||
uiDefButF(block, NUM, B_ARMATUREPANEL1, "TipRadius:", 10, 150, 140, 19, &ebone->rad_tail, 0, lim, 10, 3, "");
|
uiDefButF(block, NUM, B_ARMATUREPANEL1, "TipRadius:", 10, 150, 140, 19, &ebone->rad_tail, 0, lim, 10, 3, "");
|
||||||
if (ebone->parent && ebone->flag & BONE_CONNECTED )
|
if (ebone->parent && ebone->flag & BONE_CONNECTED )
|
||||||
|
|||||||
@@ -1269,19 +1269,61 @@ void deselectall_armature(int toggle, int doundo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void auto_align_armature(void)
|
/* Sets the roll value of selected bones, depending on the mode
|
||||||
/* Sets the roll value of selected bones so that their zaxes point upwards */
|
* mode == 0: their z-axes point upwards
|
||||||
|
* mode == 1: their z-axes point towards 3d-cursor
|
||||||
|
*/
|
||||||
|
void auto_align_armature(short mode)
|
||||||
{
|
{
|
||||||
bArmature *arm= G.obedit->data;
|
bArmature *arm= G.obedit->data;
|
||||||
EditBone *ebone;
|
EditBone *ebone;
|
||||||
float xaxis[3]={1.0, 0.0, 0.0}, yaxis[3], zaxis[3]={0.0, 0.0, 1.0};
|
|
||||||
float targetmat[3][3], imat[3][3];
|
|
||||||
float curmat[3][3], diffmat[3][3];
|
|
||||||
float delta[3];
|
float delta[3];
|
||||||
|
float curmat[3][3];
|
||||||
|
float *cursor= give_cursor();
|
||||||
|
|
||||||
for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
|
for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
|
||||||
if(arm->layer & ebone->layer) {
|
if(arm->layer & ebone->layer) {
|
||||||
if (ebone->flag & BONE_SELECTED) {
|
if (ebone->flag & BONE_SELECTED) {
|
||||||
|
/* specific method used to calculate roll depends on mode */
|
||||||
|
if (mode == 1) {
|
||||||
|
/* Z-Axis point towards cursor */
|
||||||
|
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) */
|
||||||
|
VecSubf(delta, ebone->tail, ebone->head);
|
||||||
|
vec_roll_to_mat3(delta, ebone->roll, curmat);
|
||||||
|
Mat4CpyMat3(mat, curmat);
|
||||||
|
VECCOPY(mat[3], ebone->head);
|
||||||
|
|
||||||
|
/* multiply bone-matrix by object matrix (so that bone-matrix is in WorldSpace) */
|
||||||
|
Mat4MulMat4(tmat, mat, G.obedit->obmat);
|
||||||
|
Mat4Invert(imat, tmat);
|
||||||
|
|
||||||
|
/* find position of cursor relative to bone */
|
||||||
|
VecMat4MulVecfl(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] = atan2(vec[0], vec[2]);
|
||||||
|
rot[0] = rot[2] = 0.0f;
|
||||||
|
EulToMat4(rot, rmat);
|
||||||
|
|
||||||
|
/* Multiply the bone matrix by rotation matrix. This should be new bone-matrix */
|
||||||
|
Mat4MulMat4(tmat, rmat, mat);
|
||||||
|
Mat3CpyMat4(curmat, tmat);
|
||||||
|
|
||||||
|
/* Now convert from new bone-matrix, back to a roll value (in radians) */
|
||||||
|
mat3_to_vec_roll(curmat, delta, &ebone->roll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Z-Axis Point Up */
|
||||||
|
float xaxis[3]={1.0, 0.0, 0.0}, yaxis[3], zaxis[3]={0.0, 0.0, 1.0};
|
||||||
|
float targetmat[3][3], imat[3][3], diffmat[3][3];
|
||||||
|
|
||||||
/* Find the current bone matrix */
|
/* Find the current bone matrix */
|
||||||
VecSubf(delta, ebone->tail, ebone->head);
|
VecSubf(delta, ebone->tail, ebone->head);
|
||||||
vec_roll_to_mat3(delta, 0.0, curmat);
|
vec_roll_to_mat3(delta, 0.0, curmat);
|
||||||
@@ -1304,6 +1346,7 @@ void auto_align_armature(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* **************** undo for armatures ************** */
|
/* **************** undo for armatures ************** */
|
||||||
|
|
||||||
|
|||||||
@@ -3633,6 +3633,39 @@ static uiBlock *view3d_edit_armature_parentmenu(void *arg_unused)
|
|||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void do_view3d_edit_armature_rollmenu(void *arg, int event)
|
||||||
|
{
|
||||||
|
if (event == 1 || event == 2)
|
||||||
|
/* set roll based on aligning z-axis */
|
||||||
|
auto_align_armature(event);
|
||||||
|
else if (event == 3) {
|
||||||
|
/* interactively set bone roll */
|
||||||
|
initTransform(TFM_BONE_ROLL, CTX_NONE);
|
||||||
|
Transform();
|
||||||
|
}
|
||||||
|
allqueue(REDRAWVIEW3D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uiBlock *view3d_edit_armature_rollmenu(void *arg_unused)
|
||||||
|
{
|
||||||
|
uiBlock *block;
|
||||||
|
short yco = 20, menuwidth = 120;
|
||||||
|
|
||||||
|
block= uiNewBlock(&curarea->uiblocks, "view3d_edit_armature_rollmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
|
||||||
|
uiBlockSetButmFunc(block, do_view3d_edit_armature_rollmenu, NULL);
|
||||||
|
|
||||||
|
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Roll (Z-Axis Up)|Ctrl N, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
|
||||||
|
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Roll to Cursor|Ctrl N, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
|
||||||
|
|
||||||
|
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||||
|
|
||||||
|
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Roll|Ctrl R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
|
||||||
|
|
||||||
|
uiBlockSetDirection(block, UI_RIGHT);
|
||||||
|
uiTextBoundsBlock(block, 60);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
static void do_view3d_edit_armaturemenu(void *arg, int event)
|
static void do_view3d_edit_armaturemenu(void *arg, int event)
|
||||||
{
|
{
|
||||||
switch(event) {
|
switch(event) {
|
||||||
@@ -3662,18 +3695,12 @@ static void do_view3d_edit_armaturemenu(void *arg, int event)
|
|||||||
case 10: /* forked! */
|
case 10: /* forked! */
|
||||||
extrude_armature(1);
|
extrude_armature(1);
|
||||||
break;
|
break;
|
||||||
case 11: /* clear roll */
|
|
||||||
auto_align_armature();
|
|
||||||
break;
|
|
||||||
case 12: /* subdivide */
|
case 12: /* subdivide */
|
||||||
subdivide_armature();
|
subdivide_armature();
|
||||||
break;
|
break;
|
||||||
case 13: /* flip left and right names */
|
case 13: /* flip left and right names */
|
||||||
armature_flip_names();
|
armature_flip_names();
|
||||||
break;
|
break;
|
||||||
case 14: /* interactively set bone roll */
|
|
||||||
initTransform(TFM_BONE_ROLL, CTX_NONE);
|
|
||||||
Transform();
|
|
||||||
}
|
}
|
||||||
allqueue(REDRAWVIEW3D, 0);
|
allqueue(REDRAWVIEW3D, 0);
|
||||||
}
|
}
|
||||||
@@ -3729,8 +3756,7 @@ static uiBlock *view3d_edit_armaturemenu(void *arg_unused)
|
|||||||
uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
|
uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
|
||||||
uiDefIconTextBlockBut(block, view3d_edit_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, menuwidth, 19, "");
|
uiDefIconTextBlockBut(block, view3d_edit_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, menuwidth, 19, "");
|
||||||
uiDefIconTextBlockBut(block, view3d_edit_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 19, "");
|
uiDefIconTextBlockBut(block, view3d_edit_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 19, "");
|
||||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Bone Roll Angle|Ctrl R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, "");
|
uiDefIconTextBlockBut(block, view3d_edit_armature_rollmenu, NULL, ICON_RIGHTARROW_THIN, "Bone Roll", 0, yco-=20, 120, 19, "");
|
||||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Bone Roll Angle|Ctrl N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
|
|
||||||
|
|
||||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||||
|
|
||||||
|
|||||||
@@ -2081,8 +2081,9 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
|||||||
switch (G.obedit->type){
|
switch (G.obedit->type){
|
||||||
case OB_ARMATURE:
|
case OB_ARMATURE:
|
||||||
if(G.qual==LR_CTRLKEY) {
|
if(G.qual==LR_CTRLKEY) {
|
||||||
if (okee("Recalculate bone roll angles")) {
|
pupval= pupmenu("Recalculate Bone Roll Angles%t|Clear Roll (Z-Axis Up) %x1|Align Z-Axis to 3D-Cursor %x2");
|
||||||
auto_align_armature();
|
if (pupval > 0) {
|
||||||
|
auto_align_armature(pupval - 1);
|
||||||
allqueue(REDRAWVIEW3D, 0);
|
allqueue(REDRAWVIEW3D, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user