4
\$\begingroup\$

I would like to find out what Y is if X is a certain number from a cubic bezier curve to make a custom easing function, like it's done on this site: http://cubic-bezier.com/
Does anyone know a formula or a function to find Y if X is something of a cubic-bezier? (Coding in C#/XNA)

\$\endgroup\$
  • 2
    \$\begingroup\$ There are several correct values for y in a generic cubic bezier. \$\endgroup\$ – wolfdawn Mar 13 '14 at 9:35
  • \$\begingroup\$ The answer is now updated with an implementation. \$\endgroup\$ – wolfdawn Mar 13 '14 at 21:39
  • 1
    \$\begingroup\$ Is it necessary that the curve be a Bezier specifically, or will any function that smoothly maps the range [0,1] onto a curve beginning at 0 and ending at 1 with controllable tangents suffice? If the latter is okay, there are options for computing y as a function of x directly, rather than via an intermediate parameter t. Cubic Hermite is one example, although it's not as expressive as a Bezier (can't express vertical tangents, but it can mimic any of the standard easing types listed along the bottom of the example link), it's simpler and faster than searching for the right t. \$\endgroup\$ – DMGregory Mar 14 '14 at 3:36
4
\$\begingroup\$

Lets look at two approaches:

  1. Binary search - assuming the Bezier is set with values where there is one Y for each X, meaning that there is an injective function that receives an X and returns a Y then you can search for the correct t value that will return the x,y pair you are looking for.

  2. Precomputation: Computing 1000 values for t between in the range [0 1] should only take an instant and you can place the results in 200 buckets. Afterwards, you could easily get a tiny set of relevant x,y pairs by simply picking the relevant bucket from the array.

Lets explore this in more depth (this is the formula):

bezier formula

To do a binary search, we'll assume that you create a specialized function h(t) that commputes the x value for a given t and returns it.

We are looking for the y value where x=a for some a so we need to find the correct t such that h(t) (nearly) equals x.

h(t) : return (1 - t)^3 * x0 + 3(1 - t)^2t * x1 + 3(1 - t)t^2 * x2 + t^3 * x3;

//Util
sign(z) : (z >= 0)? 1 : -1;
abs(z) : z * sign(z);

//binary search :
lookup(a) : 
  t = 0.5;
  step = 0.5;
  precision = 0.0001;
  While(abs(h(t) - a) > precision) :
    step /= 2.0;
    t += sign(a - h(t)) * step;

I did not check the code for faults so you"re welcome to look for errors.

Other method:

Calculate the Y and X values for a 1000 values of t (in advance). Put the results into buckets in an array of length N. x is between [0 1] so place all results between M/N and (M + 1)/N in the list in index M in the bucket array. You can later use a (fast) lookup to find the x,y pair you want (by radix/range). Binary search (and Newton Raphson) are you friends when you want to quickly answer complex mathematical questions with the use of a computer. You can still use the binary search to increase precision after the look up by searching between the two closest values.

A quick recap: you store the x,y pairs in linked-lists within an array of buckets by creating lists of x,y pairs where the values of x(s) that are between [m/n (m+1)/n] are all stored in the mth index (i.e. in listarray[m]).

\$\endgroup\$
  • \$\begingroup\$ If you need an clarification, feel welcome \$\endgroup\$ – wolfdawn Mar 13 '14 at 9:49
  • \$\begingroup\$ A binary search is probably overkill for tweening. A numerically-precalculated 1D lookup table with fixed spacing on the X axis is probably a better approach. (Not sure how a hash is applicable here.) \$\endgroup\$ – Andrew Russell Mar 13 '14 at 11:04
  • \$\begingroup\$ Actually, if you're willing to do a binary search, and you can figure out if the curve is a function (possibly numerically or by constraining the inputs), then you don't even need the lookup table. You can do a binary search on B(t).X itself, and save yourself the lookup table (it's probably faster). \$\endgroup\$ – Andrew Russell Mar 13 '14 at 11:07
  • \$\begingroup\$ What you described as a 1D lookup table is what I described as a hash in my answer. ;) I mean the hash function is simply one that will provide the set of values between m/n and (m+1)/n when you look for some fraction representing x between 0 and 1. Hope that makes sense. \$\endgroup\$ – wolfdawn Mar 13 '14 at 11:09
  • \$\begingroup\$ @AndrewRussell Again, doing a binary search on the function (using t) is also the second part of the answer. \$\endgroup\$ – wolfdawn Mar 13 '14 at 11:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.