Page MenuHome

Incorrect behaviour when editing aligned handles in curve editor
Closed, ResolvedPublic

Description

Windows 7 Professional 64-bit w Service Pack 1
Display card: Nvidia GeForce GTX 760

Blender 2.69 - r60995

There is a bug editing aligned handles of an animation curve.

See attached file: “handle editing bug.blend”

To reproduce:

In the curve editor, select the right hand handle of the middle keyframe as in first image, “handle edit A.jpg”.

Now move press 'G' and move the handle to the position as indicated in the second image file, “handle edit B.jpg”

It will be seen that the behaviour of the handle on the opposite side of the keyframe anchor point is not moving correctly. It is as if the control point of the second handle wants to remain vertically locked to the frame it is on. This behviour is not correct and often leads to a wild overshoot of the bezier curve.

The correct behaviour of the handle on the opposite side when being edited is indicated in the last image, “handle edit C.jpg”. Here we see that the handle on the opposite side remains the same length (thus retaining the same 'tension') and simply rotates around the keyframe anchor point.

Event Timeline

Ignatz (ignatz) added a project: BF Blender.
Ignatz (ignatz) set Type to Bug.
Ignatz (ignatz) added a subscriber: Ignatz (ignatz).
Ignatz (ignatz) created this task.
Ignatz (ignatz) raised the priority of this task from to Needs Triage by Developer.

I can't tell if this is intentional, for the other handle the X coordinate (time) stays the same, which may be useful in some cases? It's pretty easy to change but I'll let Joshua decide.

1diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
2index 8567a57..2fc9042 100644
3--- a/source/blender/blenkernel/intern/curve.c
4+++ b/source/blender/blenkernel/intern/curve.c
5@@ -2904,6 +2904,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
6 float *p1, *p2, *p3, pt[3];
7 float dvec_a[3], dvec_b[3];
8 float len, len_a, len_b;
9+ float orig_len_ratio;
10 const float eps = 1e-5;
11
12 if (bezt->h1 == 0 && bezt->h2 == 0) {
13@@ -2948,6 +2949,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
14 if (len_a == 0.0f) len_a = 1.0f;
15 if (len_b == 0.0f) len_b = 1.0f;
16
17+ orig_len_ratio = len_a/len_b;
18
19 if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */
20 float tvec[3];
21@@ -3056,15 +3058,11 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
22
23 len_b = len_v3v3(p2, p2 + 3);
24 len_a = len_v3v3(p2, p2 - 3);
25- if (len_a == 0.0f)
26- len_a = 1.0f;
27- if (len_b == 0.0f)
28- len_b = 1.0f;
29
30 if (bezt->f1 & SELECT) { /* order of calculation */
31 if (bezt->h2 == HD_ALIGN) { /* aligned */
32 if (len_a > eps) {
33- len = len_b / len_a;
34+ len = 1.0f / orig_len_ratio;
35 p2[3] = p2[0] + len * (p2[0] - p2[-3]);
36 p2[4] = p2[1] + len * (p2[1] - p2[-2]);
37 p2[5] = p2[2] + len * (p2[2] - p2[-1]);
38@@ -3072,7 +3070,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
39 }
40 if (bezt->h1 == HD_ALIGN) {
41 if (len_b > eps) {
42- len = len_a / len_b;
43+ len = orig_len_ratio;
44 p2[-3] = p2[0] + len * (p2[0] - p2[3]);
45 p2[-2] = p2[1] + len * (p2[1] - p2[4]);
46 p2[-1] = p2[2] + len * (p2[2] - p2[5]);
47@@ -3082,7 +3080,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
48 else {
49 if (bezt->h1 == HD_ALIGN) {
50 if (len_b > eps) {
51- len = len_a / len_b;
52+ len = 1.0f / orig_len_ratio;
53 p2[-3] = p2[0] + len * (p2[0] - p2[3]);
54 p2[-2] = p2[1] + len * (p2[1] - p2[4]);
55 p2[-1] = p2[2] + len * (p2[2] - p2[5]);
56@@ -3090,7 +3088,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
57 }
58 if (bezt->h2 == HD_ALIGN) { /* aligned */
59 if (len_a > eps) {
60- len = len_b / len_a;
61+ len = orig_len_ratio;
62 p2[3] = p2[0] + len * (p2[0] - p2[-3]);
63 p2[4] = p2[1] + len * (p2[1] - p2[-2]);
64 p2[5] = p2[2] + len * (p2[2] - p2[-1]);

If I might politely point out: There is no advantage for the the end of the opposing handle to remain pinned to some arbitrary point in time. As I have attempted to show, this leads to the tension of the handle (its length) fluctuating wildly. It also means that handle positioning becomes a two-step process - first moving the handle on one side of the keyframe anchor point and then afterwards (re)positioning the handle on the other side of the keyframe anchor point to bring it (and the motion curve) back into some reasonable position.

This fix caused T40186, leaving this closed.

For now just leave this as a known limitation in the system.