I have a 2D fixed-timestep simulation (a bunch of moving sprites) that ticks several times per render frame.

I would like to render the state of each tick, so that all the ticks between render frames A and A+1 contribute to the image at A+1: a discrete approximation of motion blur. I assumed this would be trivial, but so far I'm pretty stumped!

My current approach is: given N sim ticks, draw the sprites at each tick with alpha = 1/N. However, so far this feels like it's not the correct approach, and I was hoping someone here could point me in the right direction.

I've tried alpha compositing (ie equivalent to (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)), but this doesn't work: the sprites all become somewhat transparent, because by definition if you alpha-composite N images which have alpha < 1, you'll always get some background colour blended into the result.

Then I tried additive blending (ie (GL_ONE, GL_ONE)): this produces the correct result in isolation (ie a stationary sprite is drawn fully opaque, since it gets drawn N times with 1/N alpha; a moving sprite is opaque where all its ticks overlap, and transparent at the edges where only some ticks overlap), however if there's anything behind the sprites (which there will be – ie sprites moving through each other, a parallax background, etc.) then the additive blend ruins this by making everything over-bright.

Am I missing something basic?? This seems like it should be pretty straightforward, but so far all I can think of is that I would need to composite things in multiple steps: for each sprite, use additive blending to render it into a buffer, then alpha-composite that buffer with the rest of the scene.

Is that really the best I can do? It seems ugly and complicated; why shouldn't I be able to draw the background image, along with everything else in the scene, N times with 1/N alpha?

Everything I've found via google is for pixel shaders which approximate motion blur per-object via multisampling. In my case, I already have the scene multi-sampled, I just don't understand how to correctly blend all the samples together!

Anyway, any tips or pointers are greatly appreciated! Thanks. : )


1 Answer 1


You can draw your first tick at 100% alpha.

Your second tick can be drawn at 50% alpha, so you get 50% of tick 1 showing through.

Your third tick can be drawn at 33% alpha, so you get 67% of ticks 1+2 (50% each, so about 33% net).

Your fourth tick can be drawn at 25% alpha, so you get 75% of ticks 1-3 (at 33% each, so 25% net).

And so on. The \$i^{\text{th}}\$ layer can be drawn with alpha \$\frac 1 i\$ to get approximately equal weighting of this and all underlying layers.

Note however that if you want an object to be opaque relative to things it overlaps in a single tick, then you'll want to pre-compose the entire rendered frame for the tick into its own buffer using the sprites' normal alpha values. Then you can blend that pre-composed frame with the accumulated frames from previous ticks in a separate buffer.

  • \$\begingroup\$ Thanks -- the full-screen compositing idea feels like the way to go, I'm not sure why I didn't think of it. (Maybe: because of the horrible amount of fillrate that's going to eat! ;-; ) AFAICT "start at 100% alpha" doesn't work: imagine an object that moves by more than its radius each tick, it should be drawn as N sprites with equal transparency -- it doesn't make sense that the earliest tick is fully opaque. (Also I was hoping to get "free" anti-aliasing by jittering the position of each sprite by a sub-pixel amount each tick, which means proper compositing/uniform alpha per tick.) \$\endgroup\$ Aug 12, 2021 at 14:08
  • \$\begingroup\$ You'd mentioned that your game includes a background, so the background in tick 2 should draw over the sprite from tick 1, dimming it down to 50% opacity even if the object moved enough to not overlap itself. If that's not the case, you should edit your question to clarify. \$\endgroup\$
    – DMGregory
    Aug 12, 2021 at 18:35
  • \$\begingroup\$ ah right! Sorry I wan't thinking about this properly; I'll give it a shot.. \$\endgroup\$ Aug 13, 2021 at 18:01

You must log in to answer this question.

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