forked from bartvdbraak/blender
Patch #17346: Align bones in edit mode
Submitted by: Lorenzo Pierfederici (lento) This patch adds the CTRL-ALT-A hotkey to align bones in armature edit mode. It works the same way as parenting: selected bones will be aligned with active bone, if only one bone is selected it will be aligned with its parent (if any) Thanks!
This commit is contained in:
parent
06a5e9b58a
commit
1206061ed4
@ -264,6 +264,7 @@ hotkeys={
|
||||
['Alt-A', 'Play animation in current window'],
|
||||
['Ctrl-A', 'Apply objects size/rotation to object data'],
|
||||
['Ctrl-A', 'Text Editor: Select all'],
|
||||
['Ctrl-ALT-A', '3D-View: Armature Edit mode, align selected bones to active bone'],
|
||||
['Shift-A', 'Sequencer: Add menu'],
|
||||
['Shift-A', '3D-View: Add menu'],
|
||||
['Shift-ALT-A', 'Play animation in all windows'],
|
||||
|
@ -139,6 +139,8 @@ void hide_selected_armature_bones(void);
|
||||
void hide_unselected_armature_bones(void);
|
||||
void show_all_armature_bones(void);
|
||||
|
||||
void align_selected_bones(void);
|
||||
|
||||
#define BONESEL_ROOT 0x10000000
|
||||
#define BONESEL_TIP 0x20000000
|
||||
#define BONESEL_BONE 0x40000000
|
||||
@ -157,3 +159,4 @@ void show_all_armature_bones(void);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
@ -3310,6 +3310,143 @@ void switch_direction_armature (void)
|
||||
BIF_undo_push("Switch Direction");
|
||||
}
|
||||
|
||||
/* editbone alignment */
|
||||
|
||||
/* helper to fix a ebone position if its parent has moved due to alignment*/
|
||||
static void fix_connected_bone(EditBone *ebone)
|
||||
{
|
||||
float diff[3];
|
||||
|
||||
if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || VecEqual(ebone->parent->tail, ebone->head))
|
||||
return;
|
||||
|
||||
/* if the parent has moved we translate child's head and tail accordingly*/
|
||||
VecSubf(diff, ebone->parent->tail, ebone->head);
|
||||
VecAddf(ebone->head, ebone->head, diff);
|
||||
VecAddf(ebone->tail, ebone->tail, diff);
|
||||
return;
|
||||
}
|
||||
|
||||
/* helper to recursively find chains of connected bones starting at ebone and fix their position */
|
||||
static void fix_editbone_connected_children(EditBone *ebone)
|
||||
{
|
||||
EditBone *selbone;
|
||||
|
||||
for (selbone = G.edbo.first; selbone; selbone=selbone->next) {
|
||||
if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
|
||||
fix_connected_bone(selbone);
|
||||
fix_editbone_connected_children(selbone);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void bone_align_to_bone(EditBone *selbone, EditBone *actbone)
|
||||
{
|
||||
float selboneaxis[3], actboneaxis[3], length;
|
||||
|
||||
VecSubf(actboneaxis, actbone->tail, actbone->head);
|
||||
Normalize(actboneaxis);
|
||||
|
||||
VecSubf(selboneaxis, selbone->tail, selbone->head);
|
||||
length = VecLength(selboneaxis);
|
||||
|
||||
VecMulf(actboneaxis, length);
|
||||
VecAddf(selbone->tail, selbone->head, actboneaxis);
|
||||
selbone->roll = actbone->roll;
|
||||
|
||||
/* if the bone being aligned has connected descendants they must be moved
|
||||
according to their parent new position, otherwise they would be left
|
||||
in an unconsistent state: connected but away from the parent*/
|
||||
fix_editbone_connected_children(selbone);
|
||||
return;
|
||||
}
|
||||
|
||||
void align_selected_bones(void)
|
||||
{
|
||||
bArmature *arm= G.obedit->data;
|
||||
EditBone *actbone, *ebone, *selbone;
|
||||
EditBone *flipbone, *flippar;
|
||||
short allchildbones= 0, foundselbone= 0;
|
||||
|
||||
/* find active bone to align to */
|
||||
for (actbone = G.edbo.first; actbone; actbone=actbone->next) {
|
||||
if (arm->layer & actbone->layer) {
|
||||
if (actbone->flag & BONE_ACTIVE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (actbone == NULL) {
|
||||
error("Needs an active bone");
|
||||
return;
|
||||
}
|
||||
|
||||
/* find selected bones */
|
||||
for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
|
||||
if (arm->layer & ebone->layer) {
|
||||
if ((ebone->flag & BONE_SELECTED) && (ebone != actbone)) {
|
||||
foundselbone++;
|
||||
if (ebone->parent != actbone) allchildbones= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* abort if no selected bones, and active bone doesn't have a parent to work with instead */
|
||||
if (foundselbone==0 && actbone->parent==NULL) {
|
||||
error("Need selected bone(s)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (foundselbone==0 && actbone->parent) {
|
||||
/* When only the active bone is selected, and it has a parent,
|
||||
* align it to the parent, as that is the only possible outcome.
|
||||
*/
|
||||
bone_align_to_bone(actbone, actbone->parent);
|
||||
|
||||
if (arm->flag & ARM_MIRROR_EDIT) {
|
||||
flipbone = armature_bone_get_mirrored(actbone);
|
||||
if (flipbone)
|
||||
bone_align_to_bone(flipbone, flipbone->parent);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* loop through all editbones, aligning all selected bones to the active bone */
|
||||
for (selbone = G.edbo.first; selbone; selbone=selbone->next) {
|
||||
if (arm->layer & selbone->layer) {
|
||||
if ((selbone->flag & BONE_SELECTED) && (selbone!=actbone)) {
|
||||
/* align selbone to actbone */
|
||||
bone_align_to_bone(selbone, actbone);
|
||||
|
||||
if (arm->flag & ARM_MIRROR_EDIT) {
|
||||
/* - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
|
||||
* (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
|
||||
* This is useful for arm-chains, for example parenting lower arm to upper arm
|
||||
* - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
|
||||
* then just use actbone. Useful when doing upper arm to spine.
|
||||
*/
|
||||
flipbone = armature_bone_get_mirrored(selbone);
|
||||
flippar = armature_bone_get_mirrored(actbone);
|
||||
|
||||
if (flipbone) {
|
||||
if (flippar)
|
||||
bone_align_to_bone(flipbone, flippar);
|
||||
else
|
||||
bone_align_to_bone(flipbone, actbone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
countall(); /* checks selection */
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
allqueue(REDRAWOOPS, 0);
|
||||
BIF_undo_push("Align bones");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ***************** Pose tools ********************* */
|
||||
|
||||
void clear_armature(Object *ob, char mode)
|
||||
|
@ -1864,8 +1864,11 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
break;
|
||||
|
||||
case AKEY:
|
||||
if (G.obedit == 0 && G.qual == (LR_CTRLKEY|LR_ALTKEY)) {
|
||||
if(G.qual == (LR_CTRLKEY|LR_ALTKEY)) {
|
||||
if(G.obedit == 0)
|
||||
alignmenu();
|
||||
else if(G.obedit->type==OB_ARMATURE)
|
||||
align_selected_bones();
|
||||
}
|
||||
else if(G.qual & LR_CTRLKEY) { /* also with shift! */
|
||||
apply_object();
|
||||
|
Loading…
Reference in New Issue
Block a user