Particle Emitter cannot emit particles if its emissions per second is updated every frame

Within ParticleEmitter if the setParticlesPerSec is called every frame then no particle will ever be emitted. This is because setting ParticlesPerSec resets timeDifference. I can see this was done (in commit 07a6ca9) to solve the problem that after ParticlesPerSec has been zero for a long time timeDifference becomes huge.

The reason someone may want to call setParticlesPerSec every tick is to produce a smooth change in intensity, e.g. a slowly dying fire,

Test case (if reflection is used to just set the parameter it works fine, using the setter doesn’t)

public class Main extends SimpleApplication {

ParticleEmitter fire;
float particlesPerSecond = 10;
boolean useReflectionHack = false;

@Override
public void simpleUpdate(float tpf) {
    try {
        particlesPerSecond -= tpf;
        if (particlesPerSecond < 0) {
            particlesPerSecond = 5;
        }

        if(useReflectionHack){
            Field f = fire.getClass().getDeclaredField("particlesPerSec");
            f.setAccessible(true);
            f.set(fire, particlesPerSecond); //Works fine (in this use case)
        }else{
            fire.setParticlesPerSec(particlesPerSecond); //no particles ever emitted :(
        }
    } catch (NoSuchFieldException | IllegalAccessException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args){
    Main main = new Main();
    main.start();
}

@Override
public void simpleInitApp() {

    fire =
            new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30);
    Material mat_red = new Material(assetManager,
            "Common/MatDefs/Misc/Particle.j3md");
    mat_red.setTexture("Texture", assetManager.loadTexture(
            "Effects/Explosion/flame.png"));
    fire.setMaterial(mat_red);
    fire.setImagesX(2);
    fire.setImagesY(2); // 2x2 texture animation
    fire.setEndColor(  new ColorRGBA(1f, 0f, 0f, 1f));   // red
    fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow
    fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 2, 0));
    fire.setStartSize(1.5f);
    fire.setEndSize(0.1f);
    fire.setGravity(0, 0, 0);
    fire.setLowLife(1f);
    fire.setHighLife(3f);
    fire.getParticleInfluencer().setVelocityVariation(0.3f);
    fire.setParticlesPerSec(particlesPerSecond);
    rootNode.attachChild(fire);
 }

}

Instead could timeDifference be capped when setParticlesPerSec is called such that at most it is just about to emit a particle. So the new setParticlesPerSec would be

public void setParticlesPerSec(float particlesPerSec) {
    this.particlesPerSec = particlesPerSec;
    timeDifference = Math.min(timeDifference,1f / particlesPerSec); //prevent large accumulated timeDifference from causing a huge number of particles to be emitted
}

Notes:
Original commit discussed here ParticleEmitter particlesPerSecond set to 0 accumulates timeDiff

Original commit * Fix "particlesPerSecond set to 0 accumulates timeDiff" issue · jMonkeyEngine/jmonkeyengine@07a6ca9 · GitHub

1 Like

Good catch. Could you please open an issue and/or file a pull request at GitHub?
GitHub - jMonkeyEngine/jmonkeyengine: A complete 3D game development suite written purely in Java.

Here is the issue Particle Emitter cannot emit particles if its emissions per second is updated every frame · Issue #1113 · jMonkeyEngine/jmonkeyengine · GitHub

Here is the PR Issue 1113. Allow for Particle emitters that constantly have their pa… by richardTingle · Pull Request #1114 · jMonkeyEngine/jmonkeyengine · GitHub

(The PR itself seems to have created an issue, have I done this the right way?)

2 Likes

You did good. PRs and issues use the same set of ID numbers, but they’re 2 different things.

1 Like