Changes to particles system

Hi everyone,

I’d like to commit several changes to particles system that could help me in importing more particles features from the blend files.



I’ve already added 3 new emitter shapes that emit particles from the mesh’s vertices, faces and convex hull.



I’ve added a new method to the EmitterShape interface.

[java]

public interface EmitterShape extends Savable, Cloneable {

public void getRandomPoint(Vector3f store);

public void getRandomPointAndNormal(Vector3f store, Vector3f normal);

public EmitterShape deepClone();

}

[/java]



The method

[java]

public void getRandomPointAndNormal(Vector3f store, Vector3f normal);

[/java]

fill the point as before but also fills in the normal which can be used as a start velocity for the new particle.

The shapes Box, Sphere and Point do not fill the normal, so they work as they did before.



The other major change is the use of particle influencer.

I’ve put the IParticleInfluencer interface in a separate package (com.jme3.effect.influencers).

It looks like this:

[java]

public interface IParticleInfluencer extends Savable, Cloneable {



void influenceParticle(Particle particle, EmitterShape emitterShape);



public IParticleInfluencer clone();



/**

  • @param initialVelocity Set the initial velocity a particle is spawned with,
  • the initial velocity given in the parameter will be varied according
  • to the velocity variation set in {@link ParticleEmitter#setVelocityVariation(float) }.
  • A particle will move toward its velocity unless it is effected by the
  • gravity.

    */

    void setInitialVelocity(Vector3f initialVelocity);



    Vector3f getInitialVelocity();



    /**
  • @param variation Set the variation by which the initial velocity
  • of the particle is determined. <code>variation</code> should be a value
  • from 0 to 1, where 0 means particles are to spawn with exactly
  • the velocity given in {@link ParticleEmitter#setStartVel(com.jme3.math.Vector3f) },
  • and 1 means particles are to spawn with a completely random velocity.

    */

    void setVelocityVariation(float variation);



    float getVelocityVariation();



    void updateBoundingVolume(Particle particle, Vector3f min, Vector3f max);



    void applyGravity(Particle particle, float tpf, float x, float y, float z);

    }

    [/java]

    Its methods are used by ParticleEmitter. The values and parts of the code were moved there.

    There are 3 implementations of this interface:
  1. DefaultParticleInfluencer which makes the particles behave just like they did before the changes.

    This influencer is (as the name suggests :slight_smile: ) the default one and is always set in the ParticleEmitter class.


  2. NewtonianParticleInfluencer will be the main influencer used by blender loader. It applies Newtonian Physics to the particles

    using the blender’s parameters.


  3. EmptyParticleInfluencer makes particles not to move at all. I’m not sure if it is needed, but is used when No physics is applied to particles in blender.



    As for the ParticlesEmitter itself I’ve made several changes.

    I added the influencer object inside and set it to DefaultInfluencer by default.



    I’ve added gravity to all axes. So the variable

    [java]private float gravity = 0.1f;[/java]

    was replaced with

    [java]private float[] gravity = new float[] {0.0f, 0.1f, 0.0f};[/java]

    Also methods changed:

    [java]

    /**
  • This method returns the gravity of Y axis.
  • @return the gravity value of Y axis

    */

    public float getGravity() {

    return gravity[1];

    }



    /**
  • This method sets the gravity value of Y axis.
  • By default the Y axis is the only one to have gravity value non zero.
  • @param gravity Set the gravity of Y axis, in units/sec/sec, of particles
  • spawned.

    */

    public void setGravity(float gravity) {

    this.gravity[1] = gravity;

    }





    public float[] getGravityOfAllAxes() {

    return gravity;

    }



    public void setGravityOfAllAxes(float[] gravity) {

    this.setGravityOfAllAxes(gravity[0], gravity[1], gravity[2]);

    }



    public void setGravityOfAllAxes(float x, float y, float z) {

    this.gravity[0] = x;

    this.gravity[1] = y;

    this.gravity[2] = z;

    }

    [/java]



    The methods[java]

    public Vector3f getInitialVelocity();

    public void setInitialVelocity(Vector3f initialVelocity);

    public float getVelocityVariation();

    public void setVelocityVariation(float variation);

    [/java]

    are now marked as Deprecated, because these factors are now moved to the influencers.

    These methods work of course, but I’d like to see them removed.



    And one other suggestion. I’d move the Emitter shapes to a separate package. There are 7 classes already and who knows, maybe there will be more in a future.





    Please let me know what do you think about the changes.

    They should be invincible for the end-user (until we remove deprecated methods :wink: ).



    An Kirill I’m waiting for your approval of these changes.

It looks to me like the “influence” interface is not general enough… I guess it should just get a bunch of single emitter points and be able to influence those or something… This is already quite specific with random variation etc…

I don’t see why you’re passing things like initial velocity, velocity variation, and gravity to the influencer?

Why can’t the method:

void influenceParticle(Particle particle, EmitterShape emitterShape);

Just take the ParticleEmitter instead and access those values directly?



I don’t understand why you need to change the bounding volume in the influencer? That part should be done automatically after all influences finish by using the particle position and size.



Slightly minor change, but is it possible to rename “IParticleInfluencer” to just “ParticleInfluencer”? In jME3 all interfaces do not have the “I” prefixed so it is better to keep things consistent.



About the changes in ParticleEmitter, why is gravity a float[] and not a Vector3f?

Perhaps instead of calling the vector-based gravity methods “GravityOfAllAxes” just call them “Gravity” and let them overload on the existing method that takes a float?

OK I’ve made some changes you suggested.



1.

IParticleInfluencer is renamed to ParticleInfluencer ← sorry for that, just my bad habit with interface names :wink:

Gravity and bounding volume are again applied in the emitter.

Gravity is now Vector3f instead of float[].



2.

As for “GravityOfAllAxes” name I can of course override the setter and rename it to setGravity and let it take Vector3f argument.

But I cannot do it with the getter since there is already one returning float. So it would be strange to have getter and setter to one variable with different names.

But if you insist I can of course rename the setters.



3.

The main task of the influencer is to affect initial velocity of the particle.

That is why I moved those into the influencer classes. I think it is better to have the functionality of setting/calculating the initial velocity in one place.

NewtonianParticleInfluencer is calculating those in a totally different way. EmptyInfluencer is not calculating at all and I plan to add

at least one more influencer that would do the same task.

Storing this functionality in particle emitter would make DefaultParticleInfluencer not needed and other influencers would

repeat calculations of the velocity after it is calculated by the emitter.

So in my opinion it would be better to keep it there.



4.

And one last thing.

How about moving shapes into separate package?? :slight_smile:

Kaelthas said:
2.
As for "GravityOfAllAxes" name I can of course override the setter and rename it to setGravity and let it take Vector3f argument.
But I cannot do it with the getter since there is already one returning float. So it would be strange to have getter and setter to one variable with different names.
But if you insist I can of course rename the setters.

In that case, perhaps its best to just deprecate the setGravity(float) method and remove the getGravity() method that returns a float. I don't think it will take too much effort for people to fix their code.

Kaelthas said:
3.
The main task of the influencer is to affect initial velocity of the particle.
That is why I moved those into the influencer classes. I think it is better to have the functionality of setting/calculating the initial velocity in one place.
NewtonianParticleInfluencer is calculating those in a totally different way. EmptyInfluencer is not calculating at all and I plan to add
at least one more influencer that would do the same task.
Storing this functionality in particle emitter would make DefaultParticleInfluencer not needed and other influencers would
repeat calculations of the velocity after it is calculated by the emitter.
So in my opinion it would be better to keep it there.

I see, Its fine then I guess.

Kaelthas said:
4.
And one last thing.
How about moving shapes into separate package?? :)

OK

OK then,

I’ll make the changes then and commit the code when I return home.

Hi,

I’ve recently updated the jme-engine with your changes. Now there’s an issue I don’t understand.

I have the following emitter:

[java]

@Override

public void simpleInitApp()

{

emit = new ParticleEmitter(“Emitter”, Type.Triangle, 100);

emit.setLowLife(1);

emit.setHighLife(1);

emit.setGravity(0,0,0);

emit.getParticleInfluencer().setVelocityVariation(0);

emit.getParticleInfluencer().setInitialVelocity(new Vector3f(10, 0f, 0));

emit.setImagesX(15);

Material mat = new Material(assetManager,“Common/MatDefs/Misc/Particle.j3md”);

mat.setTexture(“Texture”,assetManager.loadTexture(“Effects/Smoke/Smoke.png”));

emit.setMaterial(mat);

rootNode.attachChild(emit);

}

[/java]

Regarding the InitialVelocity the particles should walk along the x-axis, but they stay at the emitting position.

How can I make them move?



edit: I think, I found the problem. The old particleEmitter had a line “p.velocity.set(startVel)” in the emitParticle-method (Line 486 of revision 7333). I’ve added “p.velocity.set(particleInfluencer.getInitialVelocity());” before the particleInfluencer does it’s job.



[java]

private boolean emitParticle(Vector3f min, Vector3f max){







p.velocity.set(particleInfluencer.getInitialVelocity());

//shape.getRandomPoint(p.position);

particleInfluencer.influenceParticle(p, shape);







[/java]



Now it’s working properly.

You were right.

I made the same change but inside the influencer.

So update now and it should work properly.