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)
-
2\$\begingroup\$ There are several correct values for y in a generic cubic bezier. \$\endgroup\$– AturSamsCommented Mar 13, 2014 at 9:35
-
\$\begingroup\$ The answer is now updated with an implementation. \$\endgroup\$– AturSamsCommented Mar 13, 2014 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 ♦Commented Mar 14, 2014 at 3:36
1 Answer
Lets look at two approaches:
Binary search - assuming the Bezier is set with values where there is one
Y
for eachX
, meaning that there is an injective function that receives anX
and returns aY
then you can search for the correctt
value that will return thex,y
pair you are looking for.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 relevantx,y
pairs by simply picking the relevant bucket from the array.
Lets explore this in more depth (this is the 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 m
th index (i.e. in listarray[m]
).
-
\$\begingroup\$ If you need an clarification, feel welcome \$\endgroup\$– AturSamsCommented Mar 13, 2014 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\$ Commented Mar 13, 2014 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\$ Commented Mar 13, 2014 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\$– AturSamsCommented Mar 13, 2014 at 11:09
-
\$\begingroup\$ @AndrewRussell Again, doing a binary search on the function (using t) is also the second part of the answer. \$\endgroup\$– AturSamsCommented Mar 13, 2014 at 11:10