Mass Particle Simulation at Runtime -- Advice + Networking the Solution

As a solution to the issue of shifting particles from the “Atmospheric Effect” camp to the “Gameplay Mechanic” camp lets take a look at this one: Achieving up to 100 temporary textured particle emitters in a scene without a significant performance hit.

For the sake of simplicity lets say we’re building a shooter. We want to use visually obstructive particles as a mechanic to be used/abused by the player. For example our player is attempting to clear a warehouse of a hostile. He can’t take the entrance as they are covered, he has no tools or other weapons at his disposal save surprise. He charges through a loose section of wall and hoses the surrounding clutter but due to dust both on bullet collision with surfaces and blowback from his weapon he is unable to see anything and shot.

Perhaps a little specific but you get the point. We need to simulate multiple ‘dynamic’ particle sources in quick succession. The must be wind effected, sparks must collide and so on. Drawcalls aren’t so much the issue as the hundreds of calculations your CPU will be making.

My questions are these:

  • How can I achieve that result as a networkable and efficient solution.
  • Are there any third-party assets that will help?
  • Any in-house tricks that might apply here?

Thanks in advance.

You posit that, “Drawcalls aren’t so much the issue as the hundreds of calculations your CPU will be making.” but I believe you will find that your issue will be fill rate.

To your specific point, if you absolutely must accomplish what you’re describing your likely hack is to precompute most of the dynamics and then create a clever look up table and once you solve for X scenario look up Y outcome and then just push the pre-simulated outcomes.

Fill rate woes are typically managed by down sampling your particles and rendering them at progressively lower resolutions, similar to an LOD system for 3d assets.

Hope that’s helpful.

Okay thanks, I’ll get someone to take at look at this with me. I’m not a very technical guy but thanks anyway, it’ll get me somewhere.
I’m wondering if there is any way to recreate a “LOD” like system for collision resolution. Anyway, thanks again.

Networking shouldn’t be that hard - you’d network the location and state of the emitters, but leave the particles themselves to made by the client. Anti-hacking is harder of course…

Note: Back in the day when I played halo pc, people would deliberately turn down many of the effects like smoke/dust to gain a competitive advantage.

Plenty of games do similar things to this on a more local scale. Battlefield 3 and 4 (and possibly Bad Company 2) definitely use smoke, fiog, haze and other visual effects for this kind of gameplay mechanic.

“Hundreds of calculations” isn’t an issue. One of my current projects involves a particle system with tens of thousands of particles with complex behaviours. (Of course those “complex” behaviours are built up of a number of pretty-simple-to-calculate things for the sake of the CPU.) I agree that fill rate will be an issue, and typically this is managed by having a smaller number of larger, more dense particles as opposed to the opposite.

Something else to consider is that if particles are being used to obscure vision you don’t need to simulate all of them all of the time, because you’ve got a built in assumption that the nearby particles will obscure the more distant ones. So nearby effects can be done in detail, you use some heuristic to determine how visible distant effects are and change their quality accordingly. I’d consider some priority system for the systems on each client, possibly based on how far away a system is and how likely it is occluded by other particles, and how many systems are in a given priority group.

You can also use post-processing effects to your advantage.

You also don’t have to do all of the work with particles. If you want to obscure a specific part of someone’s field of vision or a particular area, whack a billboard on it, then just dress the billboard up with particles.

Keep particles that need to collide with the world to a minimum. World collisions mean ray casts. A small number of those won’t be a big deal, but applying it to all of your particles will just suck. It’s also not really suited to large particles, and large particles are what you need if you want to fill volume.

You could also look into volumetric fog or other 3d texture solutions to supplement the “mass” of particles.

Though not specifically what you are asking about, you might find Particle Playground of interest:

It does pretty slick stuff leveraging Unity’s particle system. Pretty decent performance and level of control.

Okay thanks to everyone who posted here, everything is much appreciated. I’ll start testing some of the techniques asap.
Special thanks to @zombiegorillia that was a very helpful asset. Cheers

Interesting ideas!
I’m not sure how this has turned out for you but I thought I’d jump on trying to give some input from my development perspective of Particle Playground.
Particle Playground can do what you’re asking and to run this into a networked solution I would recommend to run the entire particle simulation server side - if every particle need to appear exactly the same. What you probably would want in that case is to have one PlaygroundParticles object server side which calculates all particle positions - then each client side you have a “zombie” or, a little more advanced a lightweight prediction model, which inherits all/or parts of the particle data from the server. The most efficient way of doing it is though to let each client interpret its own particle system - which doesn’t require the server to send data into the PlaygroundParticles objects.

Anyhow! Sending data:

The essential data to transfer lives in the PlaygroundCache which you can access in every PlaygroundParticles object:

particles.playgroundCache // The cache is of type PlaygroundCache

There is a deep copy method available if needed:

var particleData : PlaygroundCache = particles.playgroundCache.Clone() // Copy all data

However it would be a waste of bandwidth sending that whole chunk of particle data. I believe what kind of data that has to be sent is a little bit different depending on how often you send it and what your particle system looks like. I’ll try to elaborate,

Zombie client
The server runs all particles each frame and just tell each client where every particle is. This method would mean it’s highly depending on server-client connection and speed - a lot of bandwidth will be needed throughout the simulation. You would essentially overwrite the entire PlaygroundCache for each client every time it receives an update from the server.

Prediction client
All clients get the entire PlaygroundCache data from the server at the beginning of simulation. However, each client run their own simulation of the particles and gets updated asynchronous from the server. Here the most essential data would be to send (depending on what settings you have on the Particle Playground System):

  • Size - Particle size (if you resize them during their lifetime)
  • Life - Lifetime of each particle
  • Birth - The time of birth
  • Death - The time of death
  • Velocity - The speed and direction of each particle

You would add a layer in between the server and client particle data, where the client will compensate towards the server’s velocities, each birth/death and size (if applicable). This could be as simple as a for-loop on the client side iterating through the received data from the server merging the numbers and finding the median value.

When the source moves (if applicable) on the server side, let it broadcast the data for:

  • targetPosition
  • previousTargetPosition

No data:

No server simulation
A third solution, which would be the quickest way to success is to let all clients run their own interpretation of the particle systems. Now, these can appear a bit different depending on your settings, but it’s quite easy to get similar results on all machines. They would differ as much as a Preset differs each time you instantiate it.
The server would only take care of all connected transforms to the particle systems, Particle Playground on each client will do the rest of calculations.

What’s interesting is that you could attach manipulators to each player (AI, objects etc.) and let them interact with the particles with a low cost on performance. Based on the essentials from the network methods mentioned all players would see the interaction which would appear to happen in realtime on all machines.

You mentioned collisions, these are currently highly depending on available frames as there are no logic that will check for “passed” colliders. Collision detection will have to run always on clients (and server if you send data). I’m hoping to update this in the future which will improve the collision appearance a bit. What’s positive is that you can manipulate the particles and still maintain collision detection (as long as they’re moving). Remember that it’s quite a heavy operation for thousands of particles, but should still be fine for around 3-4k particles each frame.

I hope it helps, otherwise ask and I’ll try chip in again!