Skip to content

NeoPixelAnimator object

Michael Miller edited this page Dec 10, 2018 · 10 revisions

NeoPixelAnimator object API

The NeoPixelAnimator manages the timing and lifetime for animations. It does not provide specific animations effects, as these are varied and specific to the application and left for you to create.

A single animation is managed by a Animation Channel. An animation channel contains the duration of the animation, the progress in that duration as the animation runs, and the method to call to actually calculate and apply any changes to the NeoPixelBus.

The NeoPixelAnimator manages these channels and the total number it can manage is defined at construction time.
It manages them by periodically comparing real time to the animation duration and progress and calling the update function with the state of the animation. It does this when your code calls the UpdateAnimations().

All time values are by default in milliseconds but this can be changed to manage long duration animations as well.
NOTE: Show() must still be called to push the color state to the physical NeoPixels. Usually this is done right after calling UpdateAnimations() in the main Loop() function.

Getting Started

For each animation you start, you will need to provide a function that will "apply" the animation with the given progress. The function will be called with a AnimationParam structure which contains three properties about the animation to update, with the important one being the unit progress (0.0 to 1.0).

To "apply" an animation takes several small pieces of code:

First, apply an optional curve to the AnimationParam.progress.

This progress is a linear time value from 0.0f at the start of the animation to 1.0f at the end of the animation. The term "linear time" means that progress will map 1:1 to real time. This progress is an abstraction from real time so that the update routine can use common methods to manipulate this progress and apply it to the values that need to be modified.
Sometimes what you want is to simulate "mass" so that the animation feels like it starts slow but ends up faster. To do this, we just modify the given progress by using a curve equation that will "ease-in", "ease-out", or "ease in and out". These functions maintain the range of 0.0 to 1.0 but will modify the results to apply a curve. Now the new value can be used instead. More on this subject below in the easing section.

void UpdateAnim(AnimationParam param)
{
    // apply a exponential curve to both front and back
    float progress = NeoEase::ExponentialInOut(param.progress);
...
}

Second, use the progress to effect the animation.

The animation maybe just moving one lit pixel along a strip of pixels, or it maybe blending from one color to another. Most interpolation functions will take this progress directly as they expect a 0.0 to 1.0 value. You can find interpolation functions for most properties you want to animate, like colors or even coordinates. The color objects provided in this library contain blend functions that can be used directly. Implementing your own is simple also.
NOTE: LERP is short for Linear Interpolation and you may have good success in using this term to find routines you need from your favorite search engine. More on this subject below in the lerp section.

void UpdateAnim(AnimationParam param)
{
    // apply a exponential curve to both front and back
    float progress = NeoEase::ExponentialInOut(param.progress);
    // lerp between Red and Green
    RgbColor color = RgbColor::LinearBlend(RgbColor(255,0,0), RgbColor(0,255,0), progress);
...
}

Lastly, apply the changes to the NeoPixelBus.

Usually you will just call SetPixelColor() somewhere in the animation update function; but you won't call Show() as that is always left in the Loop().

void UpdateAnim(AnimationParam param)
{
    // apply a exponential curve to both front and back
    float progress = NeoEase::ExponentialInOut(param.progress);
    // lerp between Red and Green
    RgbColor color = RgbColor::LinearBlend(RgbColor(255,0,0), RgbColor(0,255,0), progress);
    // in this case, just apply the color to first pixel
    strip.SetPixelColor(0, color);
}

To keep the NeoPixelAnimator running, you will need to call UpdateAnimations() in the Loop() of the sketch. Usually you will follow it with a Show() like this.

void loop()
{
    animations.UpdateAnimations();
    strip.Show();
}

Easing equations

Most easing equations are grouped by four basic types.

  • Ease In - Calculates a progress that is smoothly accelerating from a complete stop with no velocity.
  • Ease Out - Calculates a progress that is smoothly decelerating toward a complete stop.
  • Ease In/Out - Calculates a progress that is smoothly accelerating from a complete stop until the halfway point at which time it then smoothly decelerates toward a complete stop at the end. Using this curve will spend less time in the center of the progress.
  • Ease Center - Calculates a progress that quickly accelerating and smooths out at the halfway point at which time it then starts smooth and ends quickly. Using this curve will spend more time in the center of the progress.

In the NeoEase class you will find a whole series of these functions; each with a different curve. A great place to see them visualized is at Gizam.com Easing.

This first set are basically similar curve shapes but with more pronounced acceleration as you progress down the list.

  • QuadraticIn, QuadraticOut, QuadraticInOut, QuadraticCenter
  • CubicIn, CubicOut, CubicInOut, CubicCenter
  • QuarticIn, QuarticOut, QuarticInOut, QuarticCenter
  • QuinticIn, QuinticOut, QuinticInOut, QuinticCenter
  • SinusoidalIn, SinusoidalOut, SinusoidalInOut, SinusoidalCenter
  • ExponentialIn, ExponentialOut, ExponentialInOut, ExponentialCenter

The Circular equations have a more circular shape to the curve. They have a much more dramatic ease at the end.

  • CircularIn, CircularOut, CircularInOut, CircularCenter

This easing equation is specific to animating through a gamma corrected color.

  • Gamma

LERP - Linear Interpolation

To interpolate between two values using a 0.0 to 1.0 progress value is a simple equation.

v0 = value that is returned when the progress is zero
v1 = value that is returned when the progress is one
progress = a floating point value between 0.0 and 1.0 also referred to as time.

lerp = (v1 - v0) * progress + v0;
Clone this wiki locally