From 49aeee5a3dfa9fc0ae29e99f7c5c0cc0124e560e Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 18 May 2016 03:19:06 +1200 Subject: Bendy Bones: Advanced B-Bones for Easier + Simple Rigging This commit/patch/branch brings a bunch of powerful new options for B-Bones and for working with B-Bones, making it easier for animators to create their own rigs, using fewer bones (which also means hopefully lighter + faster rigs ;) This functionality was first demoed by Daniel at BConf15 Some highlights from this patch include: * You can now directly control the shape of B-Bones using a series of properties instead of being restricted to trying to indirectly control them through the neighbouring bones. See the "Bendy Bones" panel... * B-Bones can be shaped in EditMode to define a "curved rest pose" for the bone. This is useful for things like eyebrows and mouths/eyelids * You can now make B-Bones use custom bones as their reference bone handles, instead of only using the parent/child bones. To do so, enable the "Use Custom Reference Handles" toggle. If none are specified, then the BBone will only use the Bendy Bone properties. * Constraints Head/Tail option can now slide along the B-Bone shape, instead of just linearly interpolating between the endpoints of the bone. For more details, see: * http://aligorith.blogspot.co.nz/2016/05/bendy-bones-dev-update.html * http://aligorith.blogspot.co.nz/2016/05/an-in-depth-look-at-how-b-bones-work.html -- Credits -- Original Idea: Daniel M Lara (pepeland) Original Patch/Research: Jose Molina Additional Development + Polish: Joshua Leung (aligorith) Testing/Feedback: Daniel M Lara (pepeland), Juan Pablo Bouza (jpbouza) --- source/blender/editors/armature/armature_add.c | 19 +++++++++++++++ source/blender/editors/armature/armature_intern.h | 5 ++++ source/blender/editors/armature/armature_utils.c | 23 ++++++++++++++++-- .../editors/armature/editarmature_retarget.c | 9 +++++++ source/blender/editors/armature/pose_slide.c | 23 ++++++++++++------ source/blender/editors/armature/pose_transform.c | 28 ++++++++++++++++++++++ source/blender/editors/armature/pose_utils.c | 25 ++++++++++++++++++- 7 files changed, 122 insertions(+), 10 deletions(-) (limited to 'source/blender/editors/armature') diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 6afc5a357c8..847b45d612c 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -83,6 +83,15 @@ EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name) bone->segments = 1; bone->layer = arm->layer; + bone->roll1 = 0.0f; + bone->roll2 = 0.0f; + bone->curveInX = 0.0f; + bone->curveInY = 0.0f; + bone->curveOutX = 0.0f; + bone->curveOutY = 0.0f; + bone->scaleIn = 1.0f; + bone->scaleOut = 1.0f; + return bone; } @@ -890,6 +899,16 @@ static int armature_extrude_exec(bContext *C, wmOperator *op) newbone->segments = 1; newbone->layer = ebone->layer; + newbone->roll1 = ebone->roll1; + newbone->roll2 = ebone->roll2; + newbone->curveInX = ebone->curveInX; + newbone->curveInY = ebone->curveInY; + newbone->curveOutX = ebone->curveOutX; + newbone->curveOutY = ebone->curveOutY; + newbone->scaleIn = ebone->scaleIn; + newbone->scaleOut = ebone->scaleOut; + + BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name)); if (flipbone && forked) { // only set if mirror edit diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index ac150b9af74..02aefce3464 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -170,6 +170,11 @@ typedef struct tPChanFCurveLink { float oldangle; float oldaxis[3]; + float roll1, roll2; /* old bbone values (to be restored along with the transform properties) */ + float curveInX, curveInY; /* (NOTE: we haven't renamed these this time, as their names are already long enough) */ + float curveOutX, curveOutY; + float scaleIn, scaleOut; + struct IDProperty *oldprops; /* copy of custom properties at start of operator (to be restored before each modal step) */ } tPChanFCurveLink; diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 85c6835a8bb..d73536e5ba7 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -456,7 +456,16 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone eBone->rad_tail = curBone->rad_tail; eBone->segments = curBone->segments; eBone->layer = curBone->layer; - + + eBone->roll1 = curBone->roll1; + eBone->roll2 = curBone->roll2; + eBone->curveInX = curBone->curveInX; + eBone->curveInY = curBone->curveInY; + eBone->curveOutX = curBone->curveOutX; + eBone->curveOutY = curBone->curveOutY; + eBone->scaleIn = curBone->scaleIn; + eBone->scaleOut = curBone->scaleOut; + if (curBone->prop) eBone->prop = IDP_CopyProperty(curBone->prop); @@ -611,7 +620,17 @@ void ED_armature_from_edit(bArmature *arm) newBone->rad_tail = eBone->rad_tail; newBone->segments = eBone->segments; newBone->layer = eBone->layer; - + + newBone->roll1 = eBone->roll1; + newBone->roll2 = eBone->roll2; + newBone->curveInX = eBone->curveInX; + newBone->curveInY = eBone->curveInY; + newBone->curveOutX = eBone->curveOutX; + newBone->curveOutY = eBone->curveOutY; + newBone->scaleIn = eBone->scaleIn; + newBone->scaleOut = eBone->scaleOut; + + if (eBone->prop) newBone->prop = IDP_CopyProperty(eBone->prop); } diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c index 7c09ad49f35..fa7bf6e7ad4 100644 --- a/source/blender/editors/armature/editarmature_retarget.c +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -1451,6 +1451,15 @@ static EditBone *add_editbonetolist(char *name, ListBase *list) bone->segments = 1; bone->layer = 1; //arm->layer; + bone->roll1 = 0.0f; + bone->roll2 = 0.0f; + bone->curveInX = 0.0f; + bone->curveInY = 0.0f; + bone->curveOutX = 0.0f; + bone->curveOutY = 0.0f; + bone->scaleIn = 1.0f; + bone->scaleOut = 1.0f; + return bone; } #endif diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 9ef46c63f0f..cd0ea23e2d3 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -303,8 +303,8 @@ static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, floa MEM_freeN(path); } -/* helper for apply() - perform sliding for custom properties */ -static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl) +/* helper for apply() - perform sliding for custom properties or bbone properties */ +static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl, const char prop_prefix[]) { PointerRNA ptr = {{NULL}}; LinkData *ld; @@ -313,8 +313,10 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl) /* setup pointer RNA for resolving paths */ RNA_pointer_create(NULL, &RNA_PoseBone, pfl->pchan, &ptr); - /* custom properties are just denoted using ["..."][etc.] after the end of the base path, - * so just check for opening pair after the end of the path + /* - custom properties are just denoted using ["..."][etc.] after the end of the base path, + * so just check for opening pair after the end of the path + * - bbone properties are similar, but they always start with a prefix "bbone_*", + * so a similar method should work here for those too */ for (ld = pfl->fcurves.first; ld; ld = ld->next) { FCurve *fcu = (FCurve *)ld->data; @@ -328,7 +330,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl) * - pPtr is the chunk of the path which is left over */ bPtr = strstr(fcu->rna_path, pfl->pchan_path) + len; - pPtr = strstr(bPtr, "[\""); /* dummy " for texteditor bugs */ + pPtr = strstr(bPtr, prop_prefix); if (pPtr) { /* use RNA to try and get a handle on this property, then, assuming that it is just @@ -517,9 +519,16 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso) } } + if (pchan->flag & POSE_BBONE_SHAPE) { + /* bbone properties - they all start a "bbone_" prefix */ + pose_slide_apply_props(pso, pfl, "bbone_"); + } + if (pfl->oldprops) { - /* not strictly a transform, but contributes to the pose produced in many rigs */ - pose_slide_apply_props(pso, pfl); + /* not strictly a transform, but custom properties contribute to the pose produced in many rigs + * (e.g. the facial rigs used in Sintel) + */ + pose_slide_apply_props(pso, pfl, "[\""); /* dummy " for texteditor bugs */ } } diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 01e16df9f08..df906a3638a 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -367,10 +367,26 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle); } + /* B-Bone posing options should also be included... */ + pchan->curveInX = chan->curveInX; + pchan->curveInY = chan->curveInY; + pchan->curveOutX = chan->curveOutX; + pchan->curveOutY = chan->curveOutY; + + pchan->roll1 = chan->roll1; + pchan->roll2 = chan->roll2; + pchan->scaleIn = chan->scaleIn; + pchan->scaleOut = chan->scaleOut; + /* paste flipped pose? */ if (flip) { pchan->loc[0] *= -1; + pchan->curveInX *= -1; + pchan->curveOutX *= -1; + pchan->roll1 *= -1; // XXX? + pchan->roll2 *= -1; // XXX? + /* has to be done as eulers... */ if (pchan->rotmode > 0) { pchan->eul[1] *= -1; @@ -540,6 +556,9 @@ static void pchan_clear_scale(bPoseChannel *pchan) pchan->size[1] = 1.0f; if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0) pchan->size[2] = 1.0f; + + pchan->scaleIn = 1.0f; + pchan->scaleOut = 1.0f; } /* clear location of pose-channel */ @@ -650,6 +669,15 @@ static void pchan_clear_rot(bPoseChannel *pchan) zero_v3(pchan->eul); } } + + /* Clear also Bendy Bone stuff - Roll is obvious, but Curve X/Y stuff is also kindof rotational in nature... */ + pchan->roll1 = 0.0f; + pchan->roll2 = 0.0f; + + pchan->curveInX = 0.0f; + pchan->curveInY = 0.0f; + pchan->curveOutX = 0.0f; + pchan->curveOutY = 0.0f; } /* clear loc/rot/scale of pose-channel */ diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index 2ba1eedd33b..b960bec3603 100644 --- a/source/blender/editors/armature/pose_utils.c +++ b/source/blender/editors/armature/pose_utils.c @@ -71,7 +71,7 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a ListBase curves = {NULL, NULL}; int transFlags = action_get_item_transforms(act, ob, pchan, &curves); - pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE); + pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE); /* check if any transforms found... */ if (transFlags) { @@ -96,6 +96,8 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a pchan->flag |= POSE_ROT; if (transFlags & ACT_TRANS_SCALE) pchan->flag |= POSE_SIZE; + if (transFlags & ACT_TRANS_BBONE) + pchan->flag |= POSE_BBONE_SHAPE; /* store current transforms */ copy_v3_v3(pfl->oldloc, pchan->loc); @@ -105,6 +107,16 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a copy_v3_v3(pfl->oldaxis, pchan->rotAxis); pfl->oldangle = pchan->rotAngle; + /* store current bbone values */ + pfl->roll1 = pchan->roll1; + pfl->roll2 = pchan->roll2; + pfl->curveInX = pchan->curveInX; + pfl->curveInY = pchan->curveInY; + pfl->curveOutX = pchan->curveOutX; + pfl->curveOutY = pchan->curveOutY; + pfl->scaleIn = pchan->scaleIn; + pfl->scaleOut = pchan->scaleOut; + /* make copy of custom properties */ if (pchan->prop && (transFlags & ACT_TRANS_PROP)) pfl->oldprops = IDP_CopyProperty(pchan->prop); @@ -133,6 +145,7 @@ void poseAnim_mapping_get(bContext *C, ListBase *pfLinks, Object *ob, bAction *a fcurves_to_pchan_links_get(pfLinks, ob, act, pchan); } CTX_DATA_END; + } } @@ -199,6 +212,16 @@ void poseAnim_mapping_reset(ListBase *pfLinks) copy_v3_v3(pchan->rotAxis, pfl->oldaxis); pchan->rotAngle = pfl->oldangle; + /* store current bbone values */ + pchan->roll1 = pfl->roll1; + pchan->roll2 = pfl->roll2; + pchan->curveInX = pfl->curveInX; + pchan->curveInY = pfl->curveInY; + pchan->curveOutX = pfl->curveOutX; + pchan->curveOutY = pfl->curveOutY; + pchan->scaleIn = pfl->scaleIn; + pchan->scaleOut = pfl->scaleOut; + /* just overwrite values of properties from the stored copies (there should be some) */ if (pfl->oldprops) IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops); -- cgit v1.2.3