diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-03-19 09:17:34 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-03-19 09:23:10 +0300 |
commit | 40e85a603c982b96fef51212deb086f6ddb73407 (patch) | |
tree | 872f67545795d0f80a8f10d3cbfcff2d6938db9f /source/blender/editors/armature/pose_slide.c | |
parent | e2ec045cc995bb8767a5f88e8830aa1062921011 (diff) |
Fix pose slide interpolation
- Quaternions weren't normalized before interpolating
causing incorrect results & assert.
- Make the newly calculated quaternion compatible with the previous
to avoid axis-flipping & setting values with large changes compared
to existing key-frames.
Diffstat (limited to 'source/blender/editors/armature/pose_slide.c')
-rw-r--r-- | source/blender/editors/armature/pose_slide.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 1545576e208..8b0bfadcbe7 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -558,54 +558,67 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) /* only if all channels exist, proceed */ if (fcu_w && fcu_x && fcu_y && fcu_z) { - float quat_prev[4], quat_next[4]; + float quat_prev[4], quat_prev_orig[4]; + float quat_next[4], quat_next_orig[4]; + float quat_curr[4], quat_curr_orig[4]; + float quat_final[4]; + + copy_qt_qt(quat_curr_orig, pchan->quat); /* get 2 quats */ - quat_prev[0] = evaluate_fcurve(fcu_w, prevFrameF); - quat_prev[1] = evaluate_fcurve(fcu_x, prevFrameF); - quat_prev[2] = evaluate_fcurve(fcu_y, prevFrameF); - quat_prev[3] = evaluate_fcurve(fcu_z, prevFrameF); + quat_prev_orig[0] = evaluate_fcurve(fcu_w, prevFrameF); + quat_prev_orig[1] = evaluate_fcurve(fcu_x, prevFrameF); + quat_prev_orig[2] = evaluate_fcurve(fcu_y, prevFrameF); + quat_prev_orig[3] = evaluate_fcurve(fcu_z, prevFrameF); + + quat_next_orig[0] = evaluate_fcurve(fcu_w, nextFrameF); + quat_next_orig[1] = evaluate_fcurve(fcu_x, nextFrameF); + quat_next_orig[2] = evaluate_fcurve(fcu_y, nextFrameF); + quat_next_orig[3] = evaluate_fcurve(fcu_z, nextFrameF); - quat_next[0] = evaluate_fcurve(fcu_w, nextFrameF); - quat_next[1] = evaluate_fcurve(fcu_x, nextFrameF); - quat_next[2] = evaluate_fcurve(fcu_y, nextFrameF); - quat_next[3] = evaluate_fcurve(fcu_z, nextFrameF); + normalize_qt_qt(quat_prev, quat_prev_orig); + normalize_qt_qt(quat_next, quat_next_orig); + normalize_qt_qt(quat_curr, quat_curr_orig); /* perform blending */ if (pso->mode == POSESLIDE_BREAKDOWN) { /* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */ - interp_qt_qtqt(pchan->quat, quat_prev, quat_next, pso->percentage); + interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage); } else if (pso->mode == POSESLIDE_PUSH) { - float quat_diff[4], quat_orig[4]; + float quat_diff[4]; /* calculate the delta transform from the previous to the current */ /* TODO: investigate ways to favour one transform more? */ - sub_qt_qtqt(quat_diff, pchan->quat, quat_prev); - - /* make a copy of the original rotation */ - copy_qt_qt(quat_orig, pchan->quat); + sub_qt_qtqt(quat_diff, quat_curr, quat_prev); /* increase the original by the delta transform, by an amount determined by percentage */ - add_qt_qtqt(pchan->quat, quat_orig, quat_diff, pso->percentage); + add_qt_qtqt(quat_final, quat_curr, quat_diff, pso->percentage); + + normalize_qt(quat_final); } else { - float quat_interp[4], quat_orig[4]; + BLI_assert(pso->mode == POSESLIDE_RELAX); + float quat_interp[4], quat_final_prev[4]; /* TODO: maybe a sensitivity ctrl on top of this is needed */ int iters = (int)ceil(10.0f * pso->percentage); + copy_qt_qt(quat_final, quat_curr); + /* perform this blending several times until a satisfactory result is reached */ while (iters-- > 0) { /* calculate the interpolation between the endpoints */ interp_qt_qtqt(quat_interp, quat_prev, quat_next, (cframe - pso->prevFrame) / (pso->nextFrame - pso->prevFrame)); - /* make a copy of the original rotation */ - copy_qt_qt(quat_orig, pchan->quat); + normalize_qt_qt(quat_final_prev, quat_final); /* tricky interpolations - blending between original and new */ - interp_qt_qtqt(pchan->quat, quat_orig, quat_interp, 1.0f / 6.0f); + interp_qt_qtqt(quat_final, quat_final_prev, quat_interp, 1.0f / 6.0f); } } + + /* Apply final to the pose bone, keeping compatible for similar keyframe positions. */ + quat_to_compatible_quat(pchan->quat, quat_final, quat_curr_orig); } /* free the path now */ |