Skip to main content
GameDev.net gamedev.net

Sub-frame emission: how do you stop fast-moving emitters looking chunky?

Started by samnovakk Aug 28 at 7:30 AM 1 replies 400+ views
Original Post
samnovakk
samnovakk

Something I keep re-solving badly, and I would like to know what people here settle on.


If an emitter is moving fast and you spawn N particles per frame at the emitter's current position, you get visible clumps: one blob per frame, spaced by however far the emitter travelled between frames. It reads as chunky at 30fps and gets worse the faster the emitter moves. Sparks trailing a projectile is the obvious case.


The fix most people eventually find is to spread the frame's emissions along the segment the emitter actually travelled, instead of putting them all at the current position. Roughly: for each of the n particles due this frame, pick a fraction s along the segment, lerp between prevPos and pos by s to get the spawn point, and give that particle a starting age of (1 - s) * dt.


That last part is the one I always forget. If you distribute the positions along the segment but give every particle age zero, you have fixed the spacing and broken the timing: they all still begin their lifetime curves on the same frame boundary, so the head of the trail pops. Pre-ageing each particle by the remaining fraction of the frame is what actually makes it read as continuous.


Three things I do not have good answers for.


First, do you interpolate emitter rotation and velocity across the segment as well, or is position alone enough in practice? I have only ever done position.


Second, on a curved path a straight lerp across the frame is visibly wrong at high speed. Is a hermite using the previous velocity worth the complexity, or do you just clamp dt and move on?


Third, does anyone do this GPU-side, or is spawn always CPU-side in your engines?


For context, I work on a browser-based particle editor, so I am trying to get this right once in a runtime rather than per-game, which is why I care about the general case more than any specific engine's answer.


If it helps, here is the lifetime-curve half in isolation as a small canvas demo: https://codepen.io/SonaArajyan03/details/xbqGxVm and the runtime notes are at https://nixiefx.com/threejs-runtime/ (disclosure: that one is mine).


Mostly curious whether sub-frame emission is something people bother with in 2D at all, or whether it stays a high-speed 3D concern.

Aressera
Aressera

You have the right idea for how to handle sub-frame emission. I have a similar way of doing it, where I forward integrate the position for the sub-time-step based on the emission velocity. This is used for more than just sub-frame emission too. It allows me to forward integrate the positions of rain/snow particles so that they can be spawned in the middle of a box volume while the camera is moving fast (avoiding the time it takes for the particle to fall from the top of the volume where they are normally emitted). This creates the sensation that the particles have always been falling when the camera moves quickly, there is no "warm up" period.

samnovakk wrote:

First, do you interpolate emitter rotation and velocity across the segment as well, or is position alone enough in practice? I have only ever done position.

In my particle engine I only extrapolate the position when spawning. It would be easy to add rotation, but I don't. I doubt it is noticeable.

samnovakk wrote:

Second, on a curved path a straight lerp across the frame is visibly wrong at high speed. Is a hermite using the previous velocity worth the complexity, or do you just clamp dt and move on?

Why would the path within a frame be curved? Usually in a game physics simulation forces and velocities are constant across a frame and we use semi-implicit Euler integration to determine the next velocity/position. With a reasonable time step (>60Hz), this piece-wise linear approximation of motion is good enough. I have a hard time imagining how you could see any artifacts, because literally almost every game or physics engine works this way.

samnovakk wrote:

Third, does anyone do this GPU-side, or is spawn always CPU-side in your engines?

My particle system is 100% CPU-based, and can handle about 200k particles in about 1ms per frame, using copious SIMD optimizations. More with multithreading. This is enough for my game to produce very dense snow storms (200 particles per m^3). I don't see the need for much more particles than that, unless doing something ridiculous like in Death Stranding 2:

To do more you would need to use GPU compute, but that would add a lot of complexity, e.g. doing collision detection or interaction with the physics engine becomes much harder. To spawn particles while using GPU compute, you probably would need to provide a lot of information from the CPU anyway, like emitter trajectory and shape and various other parameters. My particle effect class has >100 parameters to control the particles. It would be a lot of work to port to GPU.

Sign in to reply to this topic.