Commit: 7617ed972b50920726975c897429bdfa45f383fa Author: Alexander Gavrilov Date: Tue Aug 7 21:08:16 2018 +0300 Branches: temp-angavrilov-bbone-custom-handles https://developer.blender.org/rB7617ed972b50920726975c897429bdfa45f383fa
Fix T56268: display the correct rest shape for B-Bones in Edit Mode. The rest shape of B-Bones is actually affected by custom handles or the default connected parent/child mechanism. Ignoring these effects thus leads to the edit mode shape being different from the actual rest pose. This splits the b_bone_spline_setup function that is used to compute the correct rest and pose shape from pose channels into two parts, and applies the data structure independent half to edit mode. =================================================================== M source/blender/blenkernel/BKE_armature.h M source/blender/blenkernel/intern/armature.c M source/blender/draw/intern/draw_armature.c M source/blender/editors/include/ED_armature.h =================================================================== diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 17329beb325..67e7ae368b9 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -140,9 +140,32 @@ typedef struct Mat4 { float mat[4][4]; } Mat4; -void equalize_bbone_bezier(float *data, int desired); +typedef struct BBoneSplineParameters { + int segments; + float length; + + /* non-uniform scale correction */ + bool do_scale; + float scale[3]; + + /* handle control bone data */ + bool use_prev, prev_bbone; + bool use_next, next_bbone; + + float prev_h[3], next_h[3]; + float prev_mat[4][4], next_mat[4][4]; + + /* control values */ + float ease1, ease2; + float roll1, roll2; + float scaleIn, scaleOut; + float curveInX, curveInY, curveOutX, curveOutY; +} BBoneSplineParameters; + void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]); +void BKE_compute_b_bone_spline(struct BBoneSplineParameters *param, Mat4 result_array[MAX_BBONE_SUBDIV]); + /* like EBONE_VISIBLE */ #define PBONE_VISIBLE(arm, bone) ( \ CHECK_TYPE_INLINE(arm, bArmature *), \ diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 1e9f48d43c2..341c73bb65a 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -393,7 +393,7 @@ int bone_autoside_name(char name[MAXBONENAME], int UNUSED(strip_number), short a /* ************* B-Bone support ******************* */ /* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */ -void equalize_bbone_bezier(float *data, int desired) +static void equalize_bbone_bezier(float *data, int desired) { float *fp, totdist, ddist, dist, fac1, fac2; float pdist[MAX_BBONE_SUBDIV + 1]; @@ -439,24 +439,23 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB { bPoseChannel *next, *prev; Bone *bone = pchan->bone; - float h1[3], h2[3], scale[3], length, roll1 = 0.0f, roll2; - float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4]; - float data[MAX_BBONE_SUBDIV + 1][4], *fp; - int a; - bool do_scale = false; + BBoneSplineParameters param; + float imat[4][4], posemat[4][4]; - length = bone->length; + memset(¶m, 0, sizeof(param)); + + param.segments = bone->segments; + param.length = bone->length; if (!rest) { + float scale[3]; + /* check if we need to take non-uniform bone scaling into account */ mat4_to_size(scale, pchan->pose_mat); if (fabsf(scale[0] - scale[1]) > 1e-6f || fabsf(scale[1] - scale[2]) > 1e-6f) { - size_to_mat4(scalemat, scale); - invert_m4_m4(iscalemat, scalemat); - - length *= scale[1]; - do_scale = 1; + param.do_scale = true; + copy_v3_v3(param.scale, scale); } } @@ -488,7 +487,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB if (rest) { invert_m4_m4(imat, pchan->bone->arm_mat); } - else if (do_scale) { + else if (param.do_scale) { copy_m4_m4(posemat, pchan->pose_mat); normalize_m4(posemat); invert_m4_m4(imat, posemat); @@ -497,7 +496,11 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB invert_m4_m4(imat, pchan->pose_mat); if (prev) { - float difmat[4][4], result[3][3], imat3[3][3]; + float h1[3]; + bool done = false; + + param.use_prev = true; + param.prev_bbone = (prev->bone->segments > 1); /* transform previous point inside this bone space */ if (bone->bbone_prev_type == BBONE_HANDLE_RELATIVE) @@ -505,7 +508,8 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB /* Use delta movement (from restpose), and apply this relative to the current bone's head */ if (rest) { /* in restpose, arm_head == pose_head */ - h1[0] = h1[1] = h1[2] = 0.0f; + zero_v3(param.prev_h); + done = true; } else { float delta[3]; @@ -520,39 +524,25 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB else copy_v3_v3(h1, prev->pose_head); } - mul_m4_v3(imat, h1); - - if (prev->bone->segments > 1) { - /* if previous bone is B-bone too, use average handle direction */ - h1[1] -= length; - roll1 = 0.0f; - } - normalize_v3(h1); - negate_v3(h1); + if (!done) + mul_v3_m4v3(param.prev_h, imat, h1); - if (prev->bone->segments == 1) { + if (!param.prev_bbone) { /* find the previous roll to interpolate */ if (rest) - mul_m4_m4m4(difmat, imat, prev->bone->arm_mat); + mul_m4_m4m4(param.prev_mat, imat, prev->bone->arm_mat); else - mul_m4_m4m4(difmat, imat, prev->pose_mat); - copy_m3_m4(result, difmat); /* the desired rotation at beginning of next bone */ - - vec_roll_to_mat3(h1, 0.0f, mat3); /* the result of vec_roll without roll */ - - invert_m3_m3(imat3, mat3); - mul_m3_m3m3(mat3, result, imat3); /* the matrix transforming vec_roll to desired roll */ - - roll1 = atan2f(mat3[2][0], mat3[2][2]); + mul_m4_m4m4(param.prev_mat, imat, prev->pose_mat); } } - else { - h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f; - roll1 = 0.0f; - } + if (next) { - float difmat[4][4], result[3][3], imat3[3][3]; + float h2[3]; + bool done = false; + + param.use_next = true; + param.next_bbone = (next->bone->segments > 1); /* transform next point inside this bone space */ if (bone->bbone_next_type == BBONE_HANDLE_RELATIVE) @@ -560,7 +550,8 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB /* Use delta movement (from restpose), and apply this relative to the current bone's tail */ if (rest) { /* in restpose, arm_tail == pose_tail */ - h2[0] = h2[1] = h2[2] = 0.0f; + copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0); + done = true; } else { float delta[3]; @@ -575,23 +566,125 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB else copy_v3_v3(h2, next->pose_tail); } - mul_m4_v3(imat, h2); + + if (!done) + mul_v3_m4v3(param.next_h, imat, h2); + + /* find the next roll to interpolate as well */ + if (rest) + mul_m4_m4m4(param.next_mat, imat, next->bone->arm_mat); + else + mul_m4_m4m4(param.next_mat, imat, next->pose_mat); + } + + /* Add effects from bbone properties over the top + * - These properties allow users to hand-animate the + * bone curve/shape, without having to resort to using + * extra bones + * - The "bone" level offsets are for defining the restpose + * shape of the bone (e.g. for curved eyebrows for example). + * -> In the viewport, it's needed to define what the rest pose + * looks like + * -> For "rest == 0", we also still need to have it present + * so that we can "cancel out" this restpose when it comes + * time to deform some geometry, it won't cause double transforms. + * - The "pchan" level offsets are the ones that animators actually + * end up animating + */ + { + param.ease1 = bone->ease1 + (!rest ? pchan->ease1 : 0.0f); + param.ease2 = bone->ease2 + (!rest ? pchan->ease2 : 0.0f); + + param.roll1 = bone->roll1 + (!rest ? pchan->roll1 : 0.0f); + param.roll2 = bone->roll2 + (!rest ? pchan->roll2 : 0.0f); + + if (bone->flag & BONE_ADD_PARENT_END_ROLL) { + if (prev) { + if (prev->bone) + param.roll1 += prev->bone->roll2; + + if (!rest) + param.roll1 += prev->roll2; + } + } + + param.scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f); + param.scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f); + + /* extra curve x / y */ + param.curveInX = bone->curveInX + (!rest ? pchan->curveInX : 0.0f); + param.curveInY = bone->curveInY + (!rest ? pchan->curveInY : 0.0f); + + param.curveOutX = bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f); + param.curveOutY = bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f); + } + + BKE_compute_b_bone_spline(¶m, result_array); +} + +/* returns pointer to static array, filled with desired amount of bone->segments elements */ +/* this calculation is done within unit bone space */ +void BKE_compute_b_bone_spline(BBoneSplineParameters *param, Mat4 result_array[MAX_BBONE_SUBDIV]) +{ + float scalemat[4][4], iscalemat[4][4]; + float result[3][3], mat3[3][3], imat3[3][3]; + float h1[3], roll1, h2[3], roll2; + float data[MAX_BBONE_SUBDIV + 1][4], *fp; + int a; + + float length = param->length; + + if (param->do_scale) { + size_to_mat4(scalemat, param->scale); + invert_m4_m4(iscalemat, scalemat); + + length *= param->scale[1]; + } + + if (param->use_prev) { + copy_v3_v3(h1, param->prev_h); + + if (param->prev_bbone) { + /* if previous bone is B-bone too, use average handle direction */ + h1[1] -= length; + roll1 = 0.0f; + } + + normalize_v3(h1); + negate_v3(h1); + + if (!param->prev_bbone) { + /* find the previous roll to interpolate */ + copy_m3_m4(result, param->prev_mat); /* the desired rotation at beginning of next bone */ + + vec_roll_to_mat3(h1, 0.0f, mat3); /* the result of vec_roll without roll */ + + invert_m3_m3(imat3, mat3); + mul_m3_m3m3(mat3, result, imat3); /* the matrix transforming vec_roll to desired roll */ + + roll1 = atan2f(mat3[2][0], mat3[2][2]); + } + } + else { + h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f; + roll1 = 0.0f; + } + + if (param->use_next) { + copy_v3_v3(h2, param->next_h); /* if next bone is B-bone too, use average handle direction */ - if (next->bone->segments > 1) { + if (param->next_bbone) { /* pass */ } else { h2[1] -= length; } + normalize_v3(h2); /* find the next roll to interpolate as well */ - if (rest) - mul_m4_m4m4(difmat, imat, next->bone->arm_mat); - else - mul_m4_m4m4(difmat, imat, next->pose_mat); - copy_m3_m4(result, difmat); /* the desired rotation at beginning of next bone */ + copy_m3_m4(result, param->next_mat); /* the desired rotation at beginning of next bone */ vec_roll_to_mat3(h2, 0.0f, mat3); /* the result of vec_roll without roll */ @@ -599,7 +692,6 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB mul_m3_m3m3(mat3, imat3, result); /* the matrix transf @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org https://lists.blender.org/mailman/listinfo/bf-blender-cvs