Particle gravity doesn't rotate with parent node

I’m not sure if this is intended behavior, but if you rotate a node with a particle emitter, emitter’s gravity doesn’t rotate with everything else. Particles just keep flying into the same direction (world space) as before.
Is this a bug or is it intended and I’ll have to work around it?

Does setWorldSpace(false) gives you the correct behavior?

It is better, however not quite what I’m looking for. The best would be if particles already emitted kept their gravity while new ones had rotated gravity.
With world space to true, nothing gets rotated, while if set to false everything gets rotated.

What version of JME are you using? Because a bug about this has just been fixed in master.
Though if you are using 3.1, you can try emitter.setWroldSpace(true); emitter.setIgnoreTransforms(false).
That would also prove point to me.

I’ll post this here because it seems related.
I’m trying to use a ParticleEmitter with a custom EmitterShape that spawns particles at defined places all over a scene. I noticed that with setInWorldSpace(true) the particles don’t spawn at the expected position.

In the following test I spawn particles with totally random, uniformly distributed position inside a cube (white).
As a reference I added billboards (normal Geometries) that use the same code for positioning (red).

Result with world space = true (wrong distribution):

with world space = false (correct distribution):

It becomes more fancy when I align the particles in a pattern, like a grid.
With world space = true I get a star pattern where the particles are aligned to lines that meet in the center:

With world space = false I get the expected grid:

Don’t know what’s happening here. Probably something odd with the transformation.
The pattern does look a bit like a Box-Muller / Ziggurat transformation that could be used for nicer looking particle distributions - but I kinda doubt this would have been implemented in ParticleEmitter instead of an EmitterShape.

Here’s my test code if you want to check for yourself. It uses an image from the jme3-testdata lib.
I’m using the latest version from master.

import com.jme3.app.FlyCamAppState;
import com.jme3.app.SimpleApplication;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh.Type;
import com.jme3.effect.shapes.EmitterPointShape;
import com.jme3.effect.shapes.EmitterShape;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.control.BillboardControl;
import com.jme3.scene.shape.Quad;
import com.jme3.system.AppSettings;
import java.util.Random;

public class ParticlesEmitter extends SimpleApplication {
    private static class Sprite extends Geometry {
        private static final Mesh MESH = new Quad(1.0f, 1.0f);

        public Sprite() {
            setMesh(MESH);
            addControl(new BillboardControl());
        }
    }


    private class DebugShape extends EmitterPointShape {
        private static final float SIZE = 4.0f;
        private final Random rnd = new Random(System.currentTimeMillis());

        @Override
        public void getRandomPoint(Vector3f store) {
            store.x = (rnd.nextFloat() * SIZE) - (SIZE / 2);
            store.y = (rnd.nextFloat() * SIZE) - (SIZE / 2);
            store.z = (rnd.nextFloat() * SIZE) - (SIZE / 2);

            // Align particles in a grid
            store.x = Math.round(store.x);
            store.y = Math.round(store.y);
            store.z = Math.round(store.z);
        }

        @Override
        public void getRandomPointAndNormal(Vector3f store, Vector3f normal) {
            getRandomPoint(store);
            normal.set(0, 1, 0);
        }
    }


    private ParticlesEmitter() {
        super(new FlyCamAppState());
    }


    @Override
    public void simpleInitApp() {
        flyCam.setMoveSpeed(13);

        EmitterShape shape = new DebugShape();

        Material emMat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
        emMat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/shockwave.png"));

        ParticleEmitter em = new ParticleEmitter("emitter", Type.Triangle, 50000);
        em.setShape(shape);
        em.setMaterial(emMat);
        em.setParticlesPerSec(1000);
        em.setLowLife(2);
        em.setHighLife(2);
        em.setStartSize(0.07f);
        em.setEndSize(0.005f);
        em.setGravity(0, 0, 0);
        em.setRandomAngle(false);

        ///////// Uncomment this to get the correct particle distribution
        //em.setInWorldSpace(false);

        rootNode.attachChild(em);

        Vector3f pos = new Vector3f();
        for(int i=0; i<800; ++i) {
            shape.getRandomPoint(pos);

            Sprite sprite = new Sprite();
            sprite.setMaterial(emMat);
            sprite.setLocalTranslation(pos.clone());
            sprite.setLocalScale(0.07f);
            rootNode.attachChild(sprite);
        }
    }


    public static void main(String[] args) {
        AppSettings settings = new AppSettings(true);
        settings.setResolution(1024, 768);

        ParticlesEmitter test = new ParticlesEmitter();
        test.setSettings(settings);
        test.setShowSettings(false);
        test.start();
    }
}

Ok, it’s not related to transformations. The culprit is this line here:

And it’s explained here: Interpolation of particle spawning point
Something like that should be implemented in an EmitterShape IMO.

same question

latest version from master.

It’s not related to the transformation bug we had in mind after all, sorry for posting it here.

Still a bug IMO because it modifies particle position in an unexpected way when using ParticleEmitter with its default settings.

My last post has all the explanations.

I remember that one. I haven’t send a pull request for that, my bad. Fix is still present and functionnal in OpenRTS here.

Oh well now I at least understand that setWorldSpace method.

I also look for a way to have non linear scaling from start size to end size (i.e. exponential), not sure if that is possible… but I see others also just did their own particles emitter.

mhhh I don’t get what the change is looking at your code @methusalah

It was already added in November 2015 in this commit:

The problem with this is that it takes away full control over particle position. I would implement this interpolation in an EmitterShape’s getRandomPoint() method. This way it’s modular and doesn’t force the behaviour on users.
When a users sets a particle position with an EmitterShape, I bet he would expect to get a particle at exactly this place, which currently is not the case when using world transform = true.

@ia97lies
We have a similar use case and we added a influenceRealtime() method to ParticleInfluencer that gets called for each Particle in every update cycle. There you could overwrite the automatically calculated particle size.
You could also do that without modifying the engine code: Use ParticleEmitter.getParticles(), iterate over them in a Control (which is added after the ParticleEmitter’s Control) and calculate your own stuff there.

I think in 3.3 I will nuke out the particle emitter altogether.
There has been other implementations around for a long time that are promissing, myabe I’ll integrate one of them.

Oh I was not aware there are others. Which do you mean?

One by tonegod and one by zarch
Tonegod’s:

code:

(in javasabr repo, it was an old google code repo)

Zarch’s:

code :

Well it was a long time ago and it gave birth to a little drama that I rather not go back to.
In the end they were both very similar systems, and only the implementation differ (I guess, I didn’t dive extensively into them).
The first one is integrated into @javasabr editor.
Both systems were way more flexible than JME base system, and offered more features, like physics particles and such.
I don’t know about performances though but they seemed ok on this side.
Anyway… food for thought and work for the reckless.

I recently tested tonegod’s one and it works against jme 3.2-alpha1
Zarch’s one must work too.

2 Likes

I have integration with jME particles system as well :wink: