Cubic Bézier Easing

I stumbled across this article and thought it might come in handy to have a cubic-bezier function. And here it is:

Code:
' Cubic Bézier interpolation for easing curves
' pA ... pD are Bézier curve points
' pX the value for which the corresponding curve Y value shall be found
' pPrecision defines up to which error in Y the result shall be
' Returns: curve Y value at pX
Function CubicBezierEase:Float(pA:Float, pB:Float, pC:Float, pD:Float, pX:Float, pPrecision:Float = 0.0001)
    ' boundary conditions
    If pX <= 0 Then Return 0
    If pX >= 1 Then Return 1
    ' polynomial factors, precalculated for performance
    Local pQuadr:Float = 3*pC - 6*pA
    Local pCubic:Float = 1 + 3*pA - 3*pC
    ' A cubic bezier spline is a vector function
    ' (x, y) = f(t)
    ' The algorithm finds t for a given x
    ' iteratively
    ' and returns the corresponding y value.
    ' start at t = pX
    Local t:Float = pX
    ' old value of t, step of t, how much t actually changed and next best guess for t
    Local oldt:Float, tstep:Float, dt:Float, dttarget:Float
    ' value of x, old value of x and how much x actually changed in last iteration
    Local x:Float, oldx:Float, dx:Float
    ' first iteration is special (in respect to calculation of tstep)
    Local firstrun:Int = True
    ' iterate
    Repeat
        ' calculate x of cubic bezier spline
        x = 3*pA*t + pQuadr * t*t + pCubic * t*t*t
        ' accurately found t?
        If Abs(x - pX) <= pPrecision Then
            Exit
        ' no, move t
        Else
            ' update tstep
            ' in first iteration
            If firstrun then
                firstrun = False
                ' tstep by how much x differs from target x
                tstep = pX - x
            ' after that
            Else
                ' adapt tstep by how much the value over- or undershoot
                dx = x - oldx
                dt = t - oldt
                dttarget = (pX - oldx) / dx * dt
                tstep = -dt + dttarget
            Endif
            ' update t and clamp
            oldt = t
            t += tstep
            If t > 1 then t=1
            If t < 0 then t=0
        EndIf
        oldx = x
    Forever
    ' calculate y of cubic bezier spline and return
    Return 3*pB*t + (3*pD - 6*pB) * t*t + (1 + 3*pB - 3*pD) * t*t*t
End Function
 
Last edited:

Comments

I updated the function. It now takes two more values: pY0 and pY1 which describe the start and end Y value. With this it's also possible to make curves that "pulse" or "fade out".

Code:
' Cubic Bézier interpolation for easing curves
' (Imagine a curve on the X-Y plane. Returns curve value at pX)
' pY0 and pY1 are curve Y values at X=0 and X=1 respectively
' pA ... pD are Bézier curve points
' pX the value for which the corresponding curve Y value shall be found
' pPrecision defines up to which error in Y the result shall be
' Returns: curve Y value at pX
Function CubicBezierEase:Float(pY0:Float, pY1:Float, pA:Float, pB:Float, pC:Float, pD:Float, pX:Float, pPrecision:Float = 0.0001)
    ' boundary conditions
    If pX <= 0 Then Return pY0
    If pX >= 1 Then Return pY1
    ' polynomial factors, precalculated for performance
    Local pLin:Float = 3*pA
    Local pQuadr:Float = 3*pC - 6*pA
    Local pCubic:Float = 1 + 3*pA - 3*pC
    ' A cubic bezier spline is a vector function
    ' (x, y) = f(t)
    ' The algorithm finds t for a given x
    ' iteratively
    ' and returns the corresponding y value.
    ' start at t = pX
    Local t:Float = pX
    ' old value of t, step of t, how much t actually changed and next best guess for t
    Local oldt:Float, tstep:Float, dt:Float, dttarget:Float
    ' value of x, old value of x and how much x actually changed in last iteration
    Local x:Float, oldx:Float, dx:Float
    ' first iteration is special (in respect to calculation of tstep)
    Local firstrun:Int = True
    ' iterate
    Repeat
        ' calculate x of cubic bezier spline
        x = pLin * t + pQuadr * t*t + pCubic * t*t*t
        ' accurately found t?
        If Abs(x - pX) <= pPrecision Then
            Exit
        ' no, move t
        Else
            ' update tstep
            ' in first iteration
            If firstrun then
                firstrun = False
                ' tstep by how much x differs from target x
                tstep = pX - x
            ' after that
            Else
                ' adapt tstep by how much the value over- or undershoot
                dx = x - oldx
                dt = t - oldt
                dttarget = (pX - oldx) / dx * dt
                tstep = -dt + dttarget
            Endif
            ' update t and clamp
            oldt = t
            t += tstep
            If t > 1 then t=1
            If t < 0 then t=0
        EndIf
        oldx = x
    Forever
    ' calculate y of cubic bezier spline and return
    Return pY0 + (3*pB - 3*pY0) * t + (3*pY0 - 6*pB + 3*pD) * t*t + (pY1 + 3*pB - 3*pD - pY0) * t*t*t
End
You may be wondering why I didn't add those as optional parameters? Because I tried it and - believe me - it looked horrible with those two essential values attached at the back. For me, it makes much more sense to have this order: Interpolate from, to, via, at point X
 
Nice! There is a lot of cool stuff in the material design guide.
That reminds me that I have some easing functions lying around since a long time. Maybe I should post them.
 
Top Bottom