Particle system that is not emitting uses draw calls

I didnt know were to post questions about the particle system so sorry if this is the wrong place.

We have switched out our bullet impact particles to nicer looking ones. They also emmit longer meaning our particle pool needs to create more because it only uses old ones when they are not emmiting.

Anyway, because of this I noticed very high uses of draw calls, and I have back tracked it to the particles. They are using craw calls when the game object is active even if no particles is emmiting. See this video I did

Maybe @richardkettlewell has an idea what is causing this.

Can you explain why you are using individual pooled objects in the first place? Are all your bullet impact effects very different from each other depending on calibre? I would just use a setup with a worldspace particle system for the main impact decal, that has several child particles for sparks, dust, and debris, and then use a script to manually reposition the emitter object of the particle system and emit one decal. That should keep the number of setpass calls consistently low, even when you fire 2000 shots. It has issues with draw order, but your effect doesn’t look like it would be very obvious.

2 Likes

Right now we only have different particle effects per material, but we might add also for different type of weapons/calibers. Here is a video showcasing effects on different materials

It seems most people do it like this, I wasnt aware it was another way if we want multiple particles to be alive at the same time. We dont want a particle system to play its loop half way, it will look ugly. Plus this is a MP game so multiple players and bots will generate these, If you guys have a better way of doing this plaease let me know.

Statistically - because the low barrier to entry - probably most people do things in Unity in a way that is far from optimal. So I wouldn’t act on “it’s what everyone does”.

You could have e.g. one particle system for sparks, one for wood splinters, one for concrete debris particles, one for dust, and 4 for impact decals on metal, concrete, plastic and wood. That should cover most scenarios imho.

I don’t understand what you mean by that. I can’t think of a situation where something would be cut off prematurely if you set everything up correctly.

Isn’t that an argument for the kind of manual batching that I proposed, because it’ll keep the drawcall number flat no matter how many shots are fired?

In your video you go from ~100 to ~450 setpass calls with just one mag. Even without the bug of causing setpass calls for particle systems without visible particles the peak wouldn’t be much lower, and with 10 people shooting a full mag onto the same wall that should be ~10 times the setpass call increase if you don’t limit the decals to really low numbers. I would ideally want all bulletholes to stay if it can be done within performance targets, because it gives a great sense of permanence. With a system of nested particle systems iirc you can set particle limits and lifetimes individually per system, so you could have the decals max out at 10k and stay for basically forever and the dust - which likely has the highest fillrate impact - could be limited to a much lower number of max particles.

1 Like

Do you have a article or tutorial covering your method? I dont quite understand what you mean.
Our systems are built like this, a game object with a particle and then sub gameobjects with sub particles

Your idea is somewhat to have this as a template and then clone copies of this into a empty particle system and change their position and rotation in local space?

This looks like it should cover sub-emitter setups well:

https://www.youtube.com/watch?v=nlLow7DbKkY

Then you need to set the simulation space of the particlesystem to worldspace, so that you can move the emitter gameobject around without moving any of the already spawned particle systems. Write a script that repositions the particle emitter object and manually call Emit() on that particlesystem to spawn a particle from script. I have made one monobehaviour called MParticleHub that holds all references to particle systems (only those that I “manually batch” this way, normal particle systems can happily coexist with this - zOrder sorting issues aside) and provides an easy to access api like FXSpark() or FXExplosion() that I can call from other scripts that need worldspace effects.

Heads up: if you have shaders that use motionvectors on your particles you need to set the motion vector mode for the particlesystem renderer to camera motion only, or else you will see glitches in motion blur every time you move the emitter to a new spawn position. Iirc you can only do that from script, since it is such a rarely needed setting, but that might have changed already.

Hmm, this is interesting, if i parent a bunch of particle systems undera a empty game object it seem to batch them or something, look here

I implemented this in a previous project (also a VR shooter) and it caused a massive performance boost over the traditional “one VFX GameObject for decal” way. I totally recommend to use that approach.

The only corner case I found, where this doesn’t work, is if you add bullet holes to dynamic objects, such as doors.

1 Like

Ok so I in a empty scene with Real time dir.light it seems to only generate very few draw calls when parented like that (dont know if pareting helps or if the draw call just is low in that scene for some reason), but in my actual scene it does not help

Hmm, more interesting findings. Unity “batches” particles if they are emmited from same position. Not if the position differs. So thats why I got so low draw calls in above test

Unity tries to dynamically batch particles that use the same material, but it also tries to do z-sorting to avoid particles looking wrong or flickering. Sorting takes precedence over batching, so you can get situations where either maximum number of particle systems gets batched, or none at all, and everything in between. “Manual batching” (one big system shared for all instances of that effect as has been proposed) gives you full control, doesn’t have the performance cost of Unity dynamically batching individual particlesystems each frame, but comes at the cost of z sorting issues. That can not be avoided anymore in this setup. But in your case I don’t think sorting issues would be very noticable if you use sorting layers with some thought.

The parenting of the individual systems shouldn’t matter for batching, but your experiment might correlate them with being in a more batchable position.

1 Like

Hmm, it seems the set pass bug is a bug in Unity 5.5, in 2017.2 it works. We off course get high set pass calls when they are enabled and emitting but they do not cost anything when enabled and not emitting like they did in 5.5.

Another thing I observe, Unity 2017.2 with shadow mask produces about 2x set pass calls from Unity 5.5 in
subtractive mode. Does specular cost 2x? Thats expensive :smile:

So maybe together with occlusion this is good enough for now. I can work on a manual batch solution and meanwhile release it as in when we move to 2017.2

I think it should be possible to parent particle system to the object in question and set particle space as “local”.

How did you deal with particle orientation by the way?

That’s correct, but it’s “the slow path”. In this case, the particle cannot be part of the single particle stream that is used to render all bullet holes in one go.

We defined that particle systems have to be created along the forward axis. In order to emit the particle with the proper rotation, I would get the normal of the impact point and set particle system rotation corresponding to this normal vector.

Then I just emit a particle as shown below and it uses the earlier assigned rotation:

var emission = _ParticleSystem.emission;
var count = emission.GetBursts(_BurstCache);
if (count > 0)
{
    var emitCount = _Random.Range(_BurstCache[0].minCount, _BurstCache[0].maxCount);
    _ParticleSystem.Emit(emitCount);
}
1 Like

We have not started with the bullet hole decals yet, but we have a system that raycasts the underlaying mesh vertices and then paints the decal on the mesh,even bends with the mesh if its a none flat surface

Unity really needs to get the patch going for 2017.2 so we can move away from 5.5.