Algorithm puzzle: How to define a frame of animation involving a string of lights that scroll with realistic motion trail and arbitrary velocity

algorithmsinterpolationmodular arithmeticphysicstrigonometry

I have a problem I'm trying to solve. It has to do with animation and programming (drawing pixels on the screen), but it's not specific to any particular language and the problem is more abstract… so that's why I've come here instead of stackoverflow.

Anyway… what I'm trying to do is simulate a string of lights/bulbs that "scrolls"/animates such that only a single bulb is fully lit… and this lit bulbs scrolls/iterates down the line.

Doesn't seem like this should be too hard since it was achieved mechanically on marquees in the late 1800s.

I think I have solved this restricted problem so far. The contributing factors are:

  • The number of lights, N
  • The time that has elapsed, T
  • The duration a cycle, D

So let's take an arbitrary example and say there are 99 lights.
The time that has elapsed is 12 seconds.
The duration of a cycle is 7 seconds.

That means that at any point in time, we could say our current cycle completion percentage, P is (T mod D) / D. And the light that should be lit is N * P rounded to the nearest integer.

So in this case, the cycle would be (12 mod 7) / 7, that is 5/7, that is .714 complete, and so .714 * 99 = 70.71, so the seventy-first light would be the brightest.

So that was just a very limited example… and I'm not necessarily approaching the problem that way.

But, assuming that is even correct so far, what is really blowing my mind is trying to expand the problem to include:

  • The perceived "persistence" of light — the trail of lights behind the currently lit light (imagine an real-life set of bulbs… they would have a characteristic that after having received a jolt of electricity, they would appear to softly fade at a fixed rate of time… the faster the animation goes, the longer the tail would be).

However, the way this is done on a computer, at least in my case, is by creating a "custom painter" where I author all the logic to paint an individual frame, that takes any variables as input that I choose. Currently those variables are elapsed time and the duration of a cycle. Thus far in my model, an individual frame has no knowledge of velocity, so I don't think I can incorporate the "trail of lights" effect the way I am approaching it so far.

So I'm thinking that this frame-drawing logic will require some additional variables: the time of the previous frame and/or the array of brightness values from the previous frame in order to calculate velocity.

So… I suppose my question is,

Given:

  1. An initial array of N bulbs (presumably with initial brightness values of zero)
  2. "Bulb persistence duration" (how long a bulb takes to fade out), F (constant value)
  3. Cycle duration, D (constant value)
  4. Time of current frame, Tc
  5. Time of previous frame, Tp, or simply velocity, V

…at any point in time, the array of brightness values for all bulbs could/should be able to be expressed as function of the above… sooo does anyone know what that function might be?

Clarification:

  • while the algorithm (which can take any of the items 0-4 above as arguments) is executed on each frame at the exact time the frame draws, Frames do not “drive” the animation as the frame rate is unknown
    (technically it is decided by the computer at runtime and is synced to the frame
    rate of the device (which varies by device because the code is multi-platform) and also, frames can
    skip/delay)).
  • the velocity of the light (the distance it moves in a fixed unit of time) is not necessarily linear. It can have an “animation curve” applied to it such as “ease in, ease out”, for example, meaning one cycle would begin at zero, increase, then decrease and end again with velocity zero).

EDIT (After mulling over this more):

  • In my case, we are dealing with a single cycle that repeats… so we only need to think in terms of one cycle.
  • We don't need to worry about the "wrap around" affecting the motion trail effect because every cycle (conveniently for me) begins and ends at velocity zero.
  • It would probably be better if everything were expressed as a value from zero to one rather than actual duration, number of bulbs etc… – duration of a cycle is always 1,
  • current time elapsed will always be a value from 0-1,
  • Regardless of how complex the variation in velocity may be, every cycle is identical… and so for any configuration, each individual bulb must have an exact moment in time (expressed as a value from 0-1) that it lights up.
  • If an array of bulb objects could be established, each with that "light up time" as a property, then the brightness of each bulb could be calculated at any moment in time using only one input variable: time elapsed. This means we would no longer need to consider velocity, but will still see its effects!!
  • There is a relationship between "bulb number" (0-1) and "time that bulb lights up" (0-1) that is a function… and in the linear case simply looks like "y=x".
  • "animation curves" are simply a result of non-linear functions being applied instead.

PPS – I don't really know the appropriate tags for whatever we are discussing, so feel free to edit them.

Best Answer

  • Imagine the currently-lit light as the head of a wave of light. The wave moves around the marquee, and we light up the bulbs to show where the wave is.
  • You can specify the speed of the wave as $F$, in units of frames per light bulb, meaning how many animation frames does it take the wave to move to light up the next light bulb. If $F > 1$, then the wave is slow: it takes several frames for the head of the wave to move from one lit bulb to the next. If $F<1$, then the wave is fast—the lit bulb will skip across the marquee, and not every bulb will get to be the head of the wave.
  • You can specify the lingering effect of the wave as $G$, the amount of frames it takes a totally lit bulb to extinguish completely. If $G$ is large, then the bulb will fade out slowly. (I'll assume the bulb fades out linearly, but there are other options.)
  • If $G$ is very very large, then the wave might make a complete lap before the first bulb has extinguished completely. To make the approach simple, I'll assume that $G$ isn't that large.

Compute the brightness of each bulb separately...

Then you can compute the brightness of the bulb during the entire animation as follows. Let $N$ be the total number of light bulbs.

  1. Let $n$ be the current animation frame number (i.e. the time of current frame.)

  2. Then the head of the wave is at light bulb number $i\equiv \lfloor Fn \rfloor \mod N$.

  3. And the length of the tail of the wave is $FG$ light bulbs long. (To avoid difficulties, pick your parameters $F$ and $G$ so that $FG<N$.)

  4. The brightness of each light bulb (at array index $j$) is computed as:

    $$L(j) = \begin{cases}\frac{j-FG}{i-FG}& \text{if }i-FG\leq j \leq i\\ 0 &\text{otherwise}\end{cases}$$

    with appropriate adjustments so that the marquee wraps around appropriately.

...or slide the wave-pattern template around the array

Alternatively, it might be easier to simply make a constant array storing the wave of light in its initial position. Then, to do the animation, copy the old array into the new array with an appropriate offset. So, first define the brightness of the bulbs when the wave is in its initial position:

$$A(i) = \max\left(0, 1-\frac{i}{FG}\right)$$

This constant array will be a template that you slide around at subsequent time steps. The brightness of the bulbs at any subsequent time $t$ is simply:

$$B_t(i) = A(i - F\cdot t)$$

You compute the new array of brightnesses by copying over the initial wave into a displaced position. (Note that the index $i-F\cdot t$ should be taken modulo $N$, the total number of bulbs.)


An advantage of this approach is you can specify the initial template $A$ using whatever hand-made pattern of brightnesses you like. You can even hardcode it instead of using a mathematical formula— whatever looks artistically correct. The formula $B_t(i)$ for the animation still remains the same.

For example, here's one variant version: $$A^\star(i) = \begin{cases}0 & \text{if }i > FG \\ 0.8^{FG-i} & \text{otherwise}\end{cases}$$

I think this might look a bit more like a realistic marquee because it has an exponential light decay instead of a linear one. And you can tweak the factor 0.8 to make the light decay faster (when the factor is closer to 0) or slower (when the factor is closer to 1).

Related Question