2
\$\begingroup\$

I'm using Allegro 5 to create a software-generated "motion blur" effect for my 2D sprites. I basically just have a boost::circular_buffer of some length which holds "snapshots" of the sprite going back in time. Each render cycle a new "snapshot" of the main sprite is pushed onto the front of the buffer, and the last is popped off the back. The "snapshots" are then rendered with alpha values scaled by how old/far back in the buffer they are.

To save on CPU power I'd like to have the circular buffer dynamically resized so that the length of the trail is proportional to the object's velocity, i.e. don't store and push back lots of snapshots for trail sprites that won't be needed anyway because the object is moving too slowly.

The inputs I have to the data structure that holds the main sprite and its associated effect buffer are just the dx and dy values of how much its position vector changed since the last update cycle of the game logic. So I'm looking for a suggestion for an algorithm that can use that to increment/decrement some kind of unsigned counter that can be used to resize the buffer proportional to velocity.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

If the velocity can change over time, I would start with either a moving average (i.e. the average over the last N number of frames) or a moving max (i.e. the max value seen over the last N frames) & here's why:

Let's say your object starts out fast & then slows down. Initially, you'd have a large buffer & then switch to a smaller one. If you suddenly down size your buffer by an appreciable amount, the result will be visibly noticeable - probably jarringly so. Suddenly up sizing your buffer is also a bit problematic - what do you fill the extra slots with? You could space out your existing data & fill in the holes with replicated frames, but that may defeat the original goal of reducing the processing.

A somewhat related idea is to not use a moving target for the buffer size, but to use a dynamic correction. By that I mean, say your buffer is currently size N & your current measure of displacement gives you a target of size M. Then on every frame thereafter, increase or decrease the buffer by some small delta until the buffer size hits your target. Ideally, your delta will be big enough that it doesn't take too long to hit your target, but small enough to not create artifacts. You'll need to experiment a bit to find a balance. You could also use a proportional delta so that large changes will be accommodated more quickly than small ones.

In either case, the idea is to not change your buffer size too quickly.

All that being, I'm not sure the premise of saving CPU power is sound. If a lot of dynamic resizing is needed, the allocation / deallocation churn may be counter productive. On the other hand, if you don't need a lot of resizing, then why bother?

Also, I wouldn't put the sprite image data (i.e. he pixels themselves) into the buffer. Instead, I would buffer the indices of the desired sprite (i.e. a reference to look up the pixels). Moving the image data to the buffer & then to the screen has more overhead than moving the index into the buffer & then using the buffer to look up the desired image data & moving that to the screen.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks for the answer. Indeed it wouldn't be a good idea to store copies of the image data itself in the buffer; fortunately all sprites in the game are already "flyweight" types so all instances of a sprite that use the same bitmap only contain a reference to a single resource instance in memory. Interestingly while working on the problem the past couple days since I posted the question I independently decided on using a moving average based on the difference between the Euclidean norm of the position vector at t-1 and t. I have an implementation almost finished that works pretty well... \$\endgroup\$
    – MattyZ
    May 18, 2017 at 4:28
  • 1
    \$\begingroup\$ If this solution is essentially the same as your independently discovered solution, please mark it as accepted. Alternatively, if you feel your solution is different enough, write it up, post it as an answer & accept it instead. \$\endgroup\$
    – Pikalek
    May 18, 2017 at 18:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .