Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2016-05-17 18:19:06 +0300
committerJoshua Leung <aligorith@gmail.com>2016-05-17 18:19:06 +0300
commit49aeee5a3dfa9fc0ae29e99f7c5c0cc0124e560e (patch)
tree49ace019e0509cd188f24d11c8f799ab676f6bbd /source/blender/editors
parent29a17d54da1f4b85a59487e032165bb44dc1b065 (diff)
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)
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/armature/armature_add.c19
-rw-r--r--source/blender/editors/armature/armature_intern.h5
-rw-r--r--source/blender/editors/armature/armature_utils.c23
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c9
-rw-r--r--source/blender/editors/armature/pose_slide.c23
-rw-r--r--source/blender/editors/armature/pose_transform.c28
-rw-r--r--source/blender/editors/armature/pose_utils.c25
-rw-r--r--source/blender/editors/include/ED_armature.h5
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c98
9 files changed, 216 insertions, 19 deletions
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);
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 15c68378b9a..904132b8876 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -74,7 +74,10 @@ typedef struct EditBone {
float xwidth, length, zwidth; /* put them in order! transform uses this as scale */
float ease1, ease2;
float rad_head, rad_tail;
-
+ float roll1, roll2;
+ float curveOutX, curveOutY;
+ float curveInX, curveInY;
+ float scaleIn, scaleOut;
float oldlength; /* for envelope scaling */
short segments;
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index 5cda721be44..f7c1e2ee981 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -53,6 +53,7 @@
#include "BKE_global.h"
#include "BKE_modifier.h"
#include "BKE_nla.h"
+#include "BKE_curve.h"
#include "BIF_gl.h"
@@ -1093,20 +1094,101 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
glPopMatrix();
}
-static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, float xwidth, float length, float zwidth)
+/* A partial copy of b_bone_spline_setup(), with just the parts for previewing editmode curve settings
+ *
+ * This assumes that prev/next bones don't have any impact (since they should all still be in the "straight"
+ * position here anyway), and that we can simply apply the bbone settings to get the desired effect...
+ */
+static void ebone_spline_preview(EditBone *ebone, Mat4 result_array[MAX_BBONE_SUBDIV])
+{
+ float h1[3], h2[3], length, hlength1, hlength2, roll1 = 0.0f, roll2 = 0.0f;
+ float mat3[3][3];
+ float data[MAX_BBONE_SUBDIV + 1][4], *fp;
+ int a;
+
+ length = ebone->length;
+
+ hlength1 = ebone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */
+ hlength2 = ebone->ease2 * length * 0.390464f;
+
+ /* find the handle points, since this is inside bone space, the
+ * first point = (0, 0, 0)
+ * last point = (0, length, 0)
+ *
+ * we also just apply all the "extra effects", since they're the whole reason we're doing this...
+ */
+ h1[0] = ebone->curveInX;
+ h1[1] = hlength1;
+ h1[2] = ebone->curveInY;
+ roll1 = ebone->roll1;
+
+ h2[0] = ebone->curveOutX;
+ h2[1] = -hlength2;
+ h2[2] = ebone->curveOutY;
+ roll2 = ebone->roll2;
+
+ /* make curve */
+ if (ebone->segments > MAX_BBONE_SUBDIV)
+ ebone->segments = MAX_BBONE_SUBDIV;
+
+ BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float));
+ BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float));
+ BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
+ BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
+
+ equalize_bbone_bezier(data[0], ebone->segments); /* note: does stride 4! */
+
+ /* make transformation matrices for the segments for drawing */
+ for (a = 0, fp = data[0]; a < ebone->segments; a++, fp += 4) {
+ sub_v3_v3v3(h1, fp + 4, fp);
+ vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
+
+ copy_m4_m3(result_array[a].mat, mat3);
+ copy_v3_v3(result_array[a].mat[3], fp);
+
+ /* "extra" scale facs... */
+ {
+ const int num_segments = ebone->segments;
+
+ const float scaleFactorIn = 1.0f + (ebone->scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
+ const float scaleFactorOut = 1.0f + (ebone->scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
+
+ const float scalefac = scaleFactorIn * scaleFactorOut;
+ float bscalemat[4][4], bscale[3];
+
+ bscale[0] = scalefac;
+ bscale[1] = 1.0f;
+ bscale[2] = scalefac;
+
+ size_to_mat4(bscalemat, bscale);
+
+ /* Note: don't multiply by inverse scale mat here, as it causes problems with scaling shearing and breaking segment chains */
+ mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
+ }
+ }
+}
+
+static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, EditBone *ebone, float xwidth, float length, float zwidth)
{
int segments = 0;
if (pchan)
segments = pchan->bone->segments;
+ else if (ebone)
+ segments = ebone->segments;
- if ((segments > 1) && (pchan)) {
+ if (segments > 1) {
float dlen = length / (float)segments;
Mat4 bbone[MAX_BBONE_SUBDIV];
int a;
-
- b_bone_spline_setup(pchan, 0, bbone);
-
+
+ if (pchan) {
+ b_bone_spline_setup(pchan, 0, bbone);
+ }
+ else if (ebone) {
+ ebone_spline_preview(ebone, bbone);
+ }
+
for (a = 0; a < segments; a++) {
glPushMatrix();
glMultMatrixf(bbone[a].mat);
@@ -1177,7 +1259,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
else
UI_ThemeColor(TH_BONE_SOLID);
- draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth);
+ draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth);
/* disable solid drawing */
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
@@ -1190,7 +1272,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) {
glEnable(GL_BLEND);
- draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth);
+ draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth);
glDisable(GL_BLEND);
}
@@ -1200,7 +1282,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
}
}
- draw_b_bone_boxes(OB_WIRE, pchan, xwidth, length, zwidth);
+ draw_b_bone_boxes(OB_WIRE, pchan, ebone, xwidth, length, zwidth);
}
}