Sign in to follow this  
fenomas

How to specify inactive particles in an SPS?

Recommended Posts

Hi,

I have a question about an SPS where not all of the particles are in use. That is, suppose the SPS has 10,000 particles in total, but at the moment only 5,000 of them are visible, and the other 5,000 are inactive, ready to be emitted.

At first glance, since setParticles takes "start, end" parameters, it looks like one can save performance by keeping the 5,000 dead particles at the end of the particles array. That way you can call "setParticles(0, 5000)" and the update loop won't have to visit the dead particles.

However, if I understand SPS correctly, it doesn't have any mechanism to skip rendering dead particles - it renders them, but if they're invisible it scales them down and moves them inside the camera frustum, right? And since that happens inside setParticles, this means that setParticles needs to be called even on invisible particles, right?

So is there any way to tell the SPS to skip unneeded particles? Or do you just need to mark them invisible but still include them in the setParticles loop so that they get moved to places where they don't render?

Share this post


Link to post
Share on other sites

You got everything.

Actually marking them as invisible turns them to ... invisible. This just means you won't see them, but you can still manage them (update them, etc).

Using start and end indexes allows to speed up the loop by processing only successive subparts of the particle array. Note that you can call it many times with different particles setParticles(500, 500); setParticles(510, 510)  will update only the 500th and the 510th ones.

The expected way to not manage dead particle would be to set them dead : particle.alive = false. ... and I just realize that I never made a test in the particle loop to skip dead particles from being computed. Maybe noone requested this before and just one used the property "alive" as simple marker in updateParticle(particle) ?

If everybody agree I can add this behavior that wouldn't be a breaking change :

if a particle is marked as "alive == false" then it's not processed in the particle loop, "not processed" meaning no computation (position, rotation, scaling, color, etc) is done for this particle except the call to updateParticle() ... in order to reactivate it if needed. "alive" would keep different from "visible" : it could be alive and invisible or dead and visible as well

Share this post


Link to post
Share on other sites

Yeah, I saw that "alive" wasn't being used, so I ignored it. It would make sense to implement something with that, yes!

But if dead particles are skipped entirely by setParticles, then recycling a particle by marking it invisible and dead wouldn't work, right? You'd need to mark it invisible but not dead, then call setParticles on it, and then mark it dead, or else it would remain visible, right?

(And incidentally, doing this on individual particles looks like a bad idea due to overhead. If you call "setParticles(n, n)" on 500 different values of n, then if billboard is set you just calculated view matrices 500 times?)

The background here is, when you render a VBO/IBO in GL, you specify start and end points right? I had thought that maybe Babylon exposed this somehow, so that if I kept my particles list partitioned between live and dead elements, I could tell BJS the span of live indices and the dead ones would get skipped entirely (so there was no need to scale them down or move them somewhere invisible).

But it looks like BJS doesn't expose anything like this, right?

Share this post


Link to post
Share on other sites

About invisible/alive, you're right. I wrote my answer late night without thinking much about this.

Well, I think that, in order to avoid the needed double-pass, I should probably add some hidden property to each particle, something like : _justDead = true

This would allow to set the just-dead particles as invisible ones also on the first pass, and then to skip their processing for the next calls to setParticles() until they're set alive back. I need to think more carefully about this. But this could be an easy approach, if I'm not wrong.

Yep, you're right also : calling setParticles(i, i) 500 times to manage 500 specific particles is not a good idea. In fact, this feature is makes sense to update only very few particles from a large pool without reprocessing the whole pool in order to keep good perfs.

About your last question : the SPS relies on mesh.updateVerticesData() what doesn't expose the ability to pass subparts of the concerned array (positions, normals, etc) to the VBO (or no start and end point). Maybe this feature is accessible deeper in the framework. Something else I need to check...

[EDIT] thinking about the property _justDead, this could also be generalized to the visibility with _justInvisible.

Actually the invisible particles are scaled to zero and set at the camera position. Why ? scaling them to zero should be enough regarding their visibility. Well, getting them permanently outside the frustum also guarantees that won't be pickable.

So if setting a particle as dead implies its insivibility and it's not processed any longer in the same time (so not necessarily kept outside the frustum if the camera moves), I'm not sure they could avoid the pickability.

Not that obvious ...

Share this post


Link to post
Share on other sites

Yes, I follow you and agree with what you're saying. If you don't process every particle, inactive ones will get into the view, and one has to suspect that things will happen (whether with picking, or artifacts due to the material used, etc).

Basically, if the number of particles you need isn't constant, it feels like you should create a system large enough for your peak needs, and then just turn particles on and off as needed. But in light of the inner loop, dead particles are only moderately less costly than live ones, so it probably makes more sense to make several smaller SPSs and dispose the ones that aren't needed.

Looking at it very naively, I believe the GL call that renders VBOs lets you specify start and end points, so if BJS exposed that somehow then SPS could just skip dead particles entirely, both processing and rendering. But that's well into @Deltakosh territory, and even if you could skip vertices for rendering, making it work well with other systems (e.g. picking) would probably be a lot of work...

Share this post


Link to post
Share on other sites

I intend, in the next weeks, to bring some tiny improvements to the SPS (if it behaves like I wish) :

- to skip the inactive particles from the particle loop process : only the method updateParticles() will then be called (at least to set/uset them as inactive/active). The inactive solid particles would then keep their current state (position, rotation, visibility, etc) until reset to active. If everyone is OK, I would like to use the existing particle property .alive what wasn't used so far for this.

=> more performance for SPS with plenty of inactive particles

- to skip the invisible particles from the particle loop process as soon as the second call to setParticles(). As for the inactive (or dead) particles, only the method updateParticles() would still be called in order to eventually change this status once set. This feature requires some more test to be sure it's feasable.

=> more perfs for SPS with invisible particles

- in a second step, to add the ability to extend the SPS after it's already built, so to add more particles in the geometry : this won't be GC friendly, but if used correctly, so not each frame, this could be useful to many people.

Do you agree with this, folks ?

Share this post


Link to post
Share on other sites

Hey, since I started the topic I should answer you. In my particular case, I wound up not using SPS, and instead using my own hacked-up particle system code.

One complication was that, AFAICT, re-ordering particles seems to break something in SPS. That is, suppose I have 100 particles, and the first 50 are active and the last 50 are inactive. Then if particle #33 needs to become inactive, I would swap its details with particle #49 so that I still have contiguous lists of active/inactive particles. But when I did this in SPS things broke in non-obvious ways.

I should add, I looked into my code and it turns out that I am skipping inactive particles with code like this:

this.mesh.subMeshes[0].indexCount = numAlive * 6

That seems to effectively prevent the vertices at the end of the list from getting rendered, without transforming them all to certain positions, etc. I don't know if it would work for SPS though - with hit tests, for example.

Hope this helps!

Share this post


Link to post
Share on other sites

You're right. AFAIK, the best way to sort the active/inactive particles (say, putting the inactive ones at the end of the fixed size array) would probably a double-link system with a particle swap process.

For now, I don't want to implement such a mechanism because this kind of sort has also a CPU cost. I intend, for now, something quite simpler (so the term "to skip" is probably not the best) : the particle loop will still iterate over all the particles, but it will skip all the complex computations for inactive ones.

Share this post


Link to post
Share on other sites

PRed

SPS perf improvement : the inactive particles ( .alive = false ) and the invisible ones ( .isVisible = false ) are now skipped from the heavy computation iterations : positions, rotation, bbox, normals, etc.

  • the inactive/dead particles just keep their current status, including visibility, until reactivated
  • the invisible ones are scaled to zero and set to the origin at the first pass, then they aren't computed any longer until reset as visible

Both invisible and dead particles aren't then pickable.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.