Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performance for particle system

Situation

I created a particle system with JavaFX using the following technique:

Each particle is an ImageView which contains an Image with a radial gradient:

enter image description here

The particle handling loop is an AnimationTimer in which the list of particles is handled via the list's stream().parallel() method, it actually gives the whole system a boost. Something like this:

loop = new AnimationTimer() {

    @Override
    public void handle(long now) {

        addParticle();

        // apply force: gravity
        allParticles.stream().parallel().forEach(Particle::applyForceGravity);

        // move particle
        allParticles.stream().parallel().forEach(Particle::move);

        // update position in fx scene
        allParticles.forEach(Particle::display);

        // remove all particles that aren't visible anymore
        removeDeadParticles();

    }
};

The particle's color changes via ColorAdjust during its lifecycle. I used fire colors for testing, something like this which contains 1700 particles:

enter image description here

What I've learned:

  • not using parallel() is slower
  • using Circle with transparency is way slower than using an ImageView
  • using a Blend Mode is very slow
  • using a PixelWriter to change the image color is unbearable slow. Question arises: how does ColorAdjust change the color (via d3d & hardware)? I haven't found the mechanism in the JavaFX source code.

Question

Is there a better way to implement a particle system in JavaFX (other Node types, Thread, etc) in regards to performance?

I can post some code if anyone wants to toy around.

Thank you very much for the expertise!


Edit: Since it was asked, you can get the full code which uses nodes as particles with coloradjust from this gist. Btw, even if you pre-render the images and don't use coloradjust, the performance is low.

However, the question is more of a theoretical kind, so digging through the code isn't really necessary.

like image 386
Roland Avatar asked Jul 24 '15 14:07

Roland


Video Answer


1 Answers

I think I can add an answer to my own question. But I hope someone else with more experience can share their knowledge, because what I came up with was just the result of toying around:

Painting on a Canvas instead of using JavaFX ImageView nodes surprisingly resulted in a factor of at least 10x speed increase. This is basically what I did:

  • pre-calculate the images with the gradients, i. e. the color and the size of them depending on the particle's lifespan
  • in the animation timer get the pre-calculated image and paint it on the canvas

If anyone is interested, you can get the full code from this gist. Just click "Download Zip" and put the code of the zip in an "application" package of a JavaFX project and start the Main class. The difference to the code in the question is in the Particle.java class. In the question the particles are used as nodes and moved in the animation timer, but in this answer only the data is used for drawing an image on a canvas in the animation timer, the node itself isn't put on the scene.

You can use the Settings class in order to specify resolution, number of new particles per frame, etc.

This screenshot shows 3 repellers and 25400 particles on the screen in Full-HD resolution, running at 60fps:

enter image description here

like image 68
Roland Avatar answered Oct 04 '22 21:10

Roland