Easing Functions in Processing
TLDR: I implemented a more flexible map() function for Processing incorporating various common easing functions. You can find all the source code over here on Github.
In my last post I had made the following image using Cohen-Sutherland line clipping.
To create the above image, I had picked a random angle for the lines in each square and varied the spacing between lines based on the Y-axis location of the square.
Something about the above image bothered me: I wanted more darkness in the
lower half. Unfortunately, Processing’s
map() function that I use only does
linear interpolation in the range that it is provided (as far as I know).
So I went ahead and implemented some more options! Here is the same image using
map() replacement (called
map2() of course) with a quartic
ease-out to calculate the spacing between
the parallel lines in each grid square, in place of the standard linear mapping. If that doesn’t make any
sense yet, keep reading!
Processing’s map() Function
Let’s first try to understand how the Processing
map() function works. The
map() function translates an input range into an output range linearly.
A simply way to visualize this is to look at a 2D space as shown below, where I’ve used a value between 0 and 100 on the X axis, and map it to a color between white and black on the Y axis.
A visual representation of Processing’s linear
map() function essentially allows one to “traverse” this space in a
The effect of this is shown in the color slider above, where each shade of
gray is represented equally. That is, gray values are uniformly distributed.
Unfortunately, that means that simply sticking with the default
implementation limits our options. What if we want darker tones
to be represented more with only a quick transition at the end to lighter ones?
Luckily, a straight line through the 2D space shown above is not the only route we can take! In fact, we can take an arbitrary walk through this space to get to our destination. Enter easing functions.
The idea behind easing functions is to use a more complex curve rather than a straight line, to traverse the 2D region mapping our input range (on the X axis) to our output range (on the Y axis).
Here is an example of a quartic curve, where the Y-axis values are a function of $x^4$. (This is in contrast to a line which is simply a function of $x$.)
A visual representation of a sinusoidal easing function.
Understanding the Visualization
Let’s try to understand what is going on in the above animation a bit more.
First, the animation shows three curves, which correspond to different types of easings or transitions. The red curve shows easing in, where it starts out slowly and then speeds up to the final speed. You can see this if you look at the Y position of the red dot as the slider below moves at a fixed speed. It stays for a while in the lower part and only later jumps up to the upper area.
The green curve shows easing out, which is the opposite of easing in. The green dot moves through the output range (the Y position) very quickly in the beginning but slows down once it reaches the upper regions.
Finally, the blue curve shows a combined easing in and out. In this case, the initial and final parts of the range are traversed slowly, with only the middle region being fast.
Easing Functions & Color Distribution
In the animation above, the three bars at the bottom capture the Y value of the curve (in the form of a gray value) as a function of the X value (the position of the slider).
What we see is that easing in stays primarily in the lighter regions.
In contrast, easing out stays primarily in the darker regions.
Finally, combined easing in and out results in a lot of light and dark with very little mid-tone.
This way, we can play with the curves and easings to achieve the right distribution of the output range (in this case, gray values) that we want.
A Better map() Replacement
I’ve gone ahead and implemented a set of easing functions (see Robert Penner’s easing equations here)
in Processing within a new
map2() function. The function takes two
more arguments compared to the standard Processing
The first is the easing type and is one of
The second is a parameter specifying where to apply the easing, and is one of
/* Old map() function */ map(value, 0, 100, 0, 255); /* New map2() function */ map2(value, 0, 100, 0, 255, QUADRATIC, EASE_IN_OUT);
SINUSOIDAL to EXPONENTIAL Easing
From the easing functions mentioned above, the curves become steeper and steeper
as we go through the sequence
EXPONENTIAL. The animations for the first and last one are
shown below for comparison.
You can clearly see that under the
easing (right side) the dots spend more time in the extremes and move very quickly through
the middle areas, while it is more gentle in the case of the
SINUSOIDAL easing (left side).
What this means for our visualization is that the colors that you will primarily
see in the case of our exponential easing are either very light or very dark
(depending on where you apply the easing), with a relatively sharp transition
and very few mid-tones.
The sinusoidal easing on the other hand is more gentle in its transitions.
This is particularly evident when looking at the middle
region of the blue
LINEAR and CIRCULAR Easing
LINEAR easing function is equivalent to the standard
provided by Processing, while
CIRCULAR easing is relatively gentle when
only easing in or out, but very sharp in the middle region when combining
easing in and out.
SQRT and Polynomial Easing
So far, we’ve seen that as we go from
EXPONENTIAL, the focus
is removed more and more from the middle regions and pushed towards the extremes.
What if we want to do the opposite? That is, emphasize the mid-tones and de-emphasize
the extreme lights and darks?
This is where the
SQRT easing function comes in. Below is the
(left) compared with a
QUADRATIC animation (right). You can see that it’s
basically flipped, and the dots stay for a longer time in the middle region
in the case of
SQRT. The resulting bars show the contrast between the two.
Finally, we can generalize this to a mapping where you specify what power the
X variable is raised to. This allows us to have even stronger focus on the
mid-tones using an exponent less that one. I’ve implemented a
that allows this. Here are two examples with an exponent of
0.3 (left) and
Notice how the focus in the bars has changed almost entirely towards the mid-ranges and de-emphasize the extremes.
Easing functions provide a lot of control over the distribution of values of
your output range. I started with my example of using it to create more darks
for the image below: I used a quartic ease-out to map the spacing between
the parallel lines in each grid square instead of the
map() function. All of that should make sense to you now!
If you’re interested in learning more, you should check out the following video recommended to me by Benjamin Kovach:
You can find all the source code for the easing functions in Processing over here on Github