ElementEmitter (2D Influencer-based Particle Emitter)

Soooo… originally, I was going to base this off of JME’s emitter, however… once I started poking around inside it, I realized that it wasn’t really influencer based.

The ElementEmitter… is!

There are 4 stock Influencers added to the chain by default… these are:

GravityInfluencer
ColorInfluencer
SizeInfluencer
RotationInfluencer

Writing influencers are very simple, as you are doing nothing more than implementing the Influencer interface, altering one or more of the public particle parameters… the rest is taken care of internal to the emitter.

The base Emitter:

Since it is 2D, you can set the width/height of the emitter (such as the screen width and 0 height, or 50x50… etc, etc)
The emitter has 3 basic parameters that influence particles:

  1. highLife
  2. lowLife
  3. force

This defines the variable life of the particle and the initial velocity. Past this, everything is altered using chained influencers.

I committed the package for people to play around with and I’ll be putting together the wiki on how to’s soon.

Basic usage (example 1)
[java]
ElementEmitter emitter1 = new ElementEmitter(screen,new Vector2f(screen.getWidth()/2,screen.getHeight()/2),10,10);
emitter1.setSprite(“Textures/emittersprite.png”, 4, 4, 4);
emitter1.setMaxParticles(60);
emitter1.setParticlesPerSecond(30);
emitter1.setForce(.045f);
emitter1.setHighLife(4f);
emitter1.setLowLife(1f);
((GravityInfluencer)emitter1.getInfluencer(ElementEmitter.InfluencerType.Gravity)).setGravity(new Vector2f(.05f,0.15f));
((RotationInfluencer)emitter1.getInfluencer(ElementEmitter.InfluencerType.Rotation)).setMaxRotationSpeed(3);
((ColorInfluencer)emitter1.getInfluencer(ElementEmitter.InfluencerType.Color)).setEndColor(ColorRGBA.Yellow);
emitter1.startEmitter(guiNode);
[/java]

Basic Usage (Example 2)
[java]
ElementEmitter emitter2 = new ElementEmitter(screen,new Vector2f(screen.getWidth()/2-200,screen.getHeight()/2),2,2);
emitter2.setSprite(“Textures/emittersprite.png”, 4, 4, 4);
emitter2.setMaxParticles(60);
emitter2.setParticlesPerSecond(30);
emitter2.setForce(.15f);
emitter2.setHighLife(4f);
emitter2.setLowLife(1.2f);
((GravityInfluencer)emitter2.getInfluencer(ElementEmitter.InfluencerType.Gravity)).setGravity(new Vector2f(0f,0f));
((RotationInfluencer)emitter2.getInfluencer(ElementEmitter.InfluencerType.Rotation)).setMaxRotationSpeed(.25f);
((ColorInfluencer)emitter2.getInfluencer(ElementEmitter.InfluencerType.Color)).setStartColor(ColorRGBA.Green);
((ColorInfluencer)emitter2.getInfluencer(ElementEmitter.InfluencerType.Color)).setEndColor(ColorRGBA.White);
((SizeInfluencer)emitter2.getInfluencer(ElementEmitter.InfluencerType.Size)).setStartSize(1f);
((SizeInfluencer)emitter2.getInfluencer(ElementEmitter.InfluencerType.Size)).setStartSize(.5f);
emitter2.startEmitter(guiNode);
[/java]

Basic Usage (Example 3)
[java]
ElementEmitter emitter3 = new ElementEmitter(screen,new Vector2f(screen.getWidth()/2,0),screen.getWidth(),0);
emitter3.setSprite(“Textures/emittersprite.png”, 4, 4, 4);
emitter3.setMaxParticles(60);
emitter3.setParticlesPerSecond(50);
emitter3.setForce(.15f);
emitter3.setHighLife(2f);
emitter3.setLowLife(1.6f);
((GravityInfluencer)emitter3.getInfluencer(ElementEmitter.InfluencerType.Gravity)).setGravity(new Vector2f(0f,-2f));
((RotationInfluencer)emitter3.getInfluencer(ElementEmitter.InfluencerType.Rotation)).setMaxRotationSpeed(.75f);
((ColorInfluencer)emitter3.getInfluencer(ElementEmitter.InfluencerType.Color)).setStartColor(ColorRGBA.White);
((ColorInfluencer)emitter3.getInfluencer(ElementEmitter.InfluencerType.Color)).setEndColor(ColorRGBA.Blue);
((SizeInfluencer)emitter3.getInfluencer(ElementEmitter.InfluencerType.Size)).setStartSize(3f);
((SizeInfluencer)emitter3.getInfluencer(ElementEmitter.InfluencerType.Size)).setStartSize(.5f);
emitter3.startEmitter(guiNode);
[/java]

I’ll be adding one more standard influencer soon for transparency.

End of line

Oh… here is a sample of what an influencer consists of:

[java]
public class RotationInfluencer implements Influencer {
private boolean isEnabled = true;
private float maxRotationSpeed;

@Override
public void update(ElementParticle particle, float tpf) {
	if (isEnabled) {
		if (particle.rotateDir)
			particle.angle += particle.rotateSpeed * tpf;
		else
			particle.angle -= particle.rotateSpeed * tpf;
	}
}

@Override
public void initialize(ElementParticle particle) {
	particle.angle = 0;
	particle.rotateSpeed = FastMath.rand.nextFloat()*maxRotationSpeed;
}

@Override
public void setIsEnabled(boolean isEnabled) {
	this.isEnabled = isEnabled;
}

@Override
public boolean getIsEnabled() {
	return this.isEnabled;
}

public void setMaxRotationSpeed(float maxRotationSpeed) {
	this.maxRotationSpeed = maxRotationSpeed;
}

@Override
public RotationInfluencer clone() {
	RotationInfluencer clone = new RotationInfluencer();
	clone.setMaxRotationSpeed(maxRotationSpeed);
	return clone;
}

}
[/java]

Tomorrow I’ll post an update that allows you to set a target element. If it is null particles are rendered directly to the screen.

This has the effect of having particles follow the emitter when the parent element is moved.

Otherwise, you move the emitter position and the particles trail.

Options… options… etc, etc.

P.S. Update to how sprites update tex coords. nice improvement. Me likes!

I want to change the way the JME ParticleEmitter influencers work. Right now they just give an impulse to the particles when they are emitted.
As Normen says that’s an “half assed” design. Influencers should control all particles’ aspects during the whole duration of the emission.
It looks like it’s the direction you’re heading to.

I absolutely don’t want to be dismissive, and I guess you went on your implementation because you didn’t feel like modifying something in the core.
But IMO this shouldn’t be part of an UI library.
Maybe we could discuss how to redesign JME particle emitters, so that they have a real influencer system, and so you could use stock Emitters?
What do you think?

cool, wheres your normal video demonstration? ^^ :stuck_out_tongue: After i updated to nightly, a few of nifty screens seems to have broke, so I may be using your framework sooner or later!! so keep up the good work!! ^^

Particles are a sweet addition, and if they can solve this issue: http://hub.jmonkeyengine.org/forum/topic/particle-emitter-freeze-my-android-2-3-x/ then a core integration would be most appreciated, and judging by your speed, shouldn’t take more than 10 minutes to create :).

A couple of things i noticed, you set the start size twice (nothing big):

java.setStartSize(1f);
((SizeInfluencer)emitter2.getInfluencer(ElementEmitter.InfluencerType.Size)).setStartSize(.5f);
[/java]

To be more consistent with jME, it should be setEnabled and isEnabled, rather than:

[java] @Override
public void setIsEnabled(boolean isEnabled) {
this.isEnabled = isEnabled;
}

@Override
public boolean getIsEnabled() {
    return this.isEnabled;
}[/java]

again nothing big :slight_smile:

@nehon said: I want to change the way the JME ParticleEmitter influencers work. Right now they just give an impulse to the particles when they are emitted. As Normen says that's an "half assed" design. Influencers should control all particles' aspects during the whole duration of the emission. It looks like it's the direction you're heading to.

I absolutely don’t want to be dismissive, and I guess you went on your implementation because you didn’t feel like modifying something in the core.
But IMO this shouldn’t be part of an UI library.
Maybe we could discuss how to redesign JME particle emitters, so that they have a real influencer system, and so you could use stock Emitters?
What do you think?

Actually… converfting the existing emitter to be influencer based would probably take about 30 minutes tops. Here are the core changes between the two:

  • The emitter is the only control… particles are managed by the emitter. Not sure if this is a good thing or bad, but I’m not seeing anything negative yet. If there is a needed benefit to each particle being a control, this isn’t a major thing… but, from what I could tell this was so you could stop the emitter and still have the final particles do their thing. This is still possible with a single control.

  • The inner particle class is mostly identical to JME’s, though I moved the update, initialize and remove methods to the particle itself. Oh… and I think I am storing the current frame’s blend.

  • in the update loop it does the following: Updates the life counter, calculates the current blend for influencers to leverage, the cycles through each influencer calling it’s update loop and passing in the current particle. After all mods are applied to the fields of the particle, it updates the 4 visual components of the element.
    [java]
    public void update(float tpf) {
    life -= tpf;
    blend = (startlife - life) / startlife;

    if (life < 0) {
    killParticle();
    return;
    }

    for (Influencer inf : influencers.values()) {
    if (inf.getIsEnabled())
    inf.update(this, tpf);
    }

    particle.setPosition(position);
    particle.setLocalScale(size);
    particle.getElementMaterial().setColor("Color", color);
    particle.setLocalRotation(particle.getLocalRotation().fromAngleAxis(angle, Vector3f.UNIT_Z));
    };
    [/java]

If you look at each of the current influencers, you'll find (in most cases), I cut & pasted directly from JME's emitter, since none of the logic would have to change at all.

Additions for today, I need to add a UserData HashMap to the particle for influencers to store / retrieve new per-particle data to. The impulse influencer currently in JME emitter… I didn't realize what this was and hadn't finished looking through everything. VERY important!

Side notes:

If the JME emitter can be updated and works in the guiNode as well as the root, then I consider what I am currently working on a testing ground that can be dropped as quickly as it was added.

Side note 2:

Last night, I tested out wrtting a few influencers to see how they would plug in and function. Happy to report that this worked very well! I added an alpha influencer, another that spirals the particle as it moves outward and a third uses the current velocity vector and alters the path along a sinewave.

The nice part is, each influencers update loop is no more than 2-4 lines of code and they play with other influencers that modify the same data nicely.

@wezrule said: cool, wheres your normal video demonstration? ^_^ :P After i updated to nightly, a few of nifty screens seems to have broke, so I may be using your framework sooner or later!! so keep up the good work!! ^_^

Particles are a sweet addition, and if they can solve this issue: http://hub.jmonkeyengine.org/forum/topic/particle-emitter-freeze-my-android-2-3-x/ then a core integration would be most appreciated, and judging by your speed, shouldn’t take more than 10 minutes to create :).

A couple of things i noticed, you set the start size twice (nothing big):

java.setStartSize(1f);
((SizeInfluencer)emitter2.getInfluencer(ElementEmitter.InfluencerType.Size)).setStartSize(.5f);
[/java]

To be more consistent with jME, it should be setEnabled and isEnabled, rather than:

[java] @Override
public void setIsEnabled(boolean isEnabled) {
this.isEnabled = isEnabled;
}

@Override
public boolean getIsEnabled() {
    return this.isEnabled;
}[/java]

again nothing big :slight_smile:

Ooops… thanks for the catch… that’s what cut/paste will get you when you are tired!

And the getIsEnabled thing… I think I started using this in the library when I first began before realizing it didn’t follow convention with JME. unfortunately, I’m a little stuck in this department now… well… I may deprecate the method, leave it in place and add the correctly named for all other controls and just change this outright as no one has used it yet.

EDIT: I have a thought as to why the particle emitter freezes on android. It may be due to how the current emitter times itself for particles per second. If I am correct, this is resolved in this version and can easily be fixed in the current…

@wezrule
Oh… video… yeah… I’m a bit on the lazy side. How about a screen cap? Ok… not as useful, but gives the basic idea.

Um… the thing in the top left corner is a sprite… ignore it =)

1 Like

@nehon
I’m going to make a local copy of the particle emitter related files and see what I can do about porting the ideas here. Once complete, I’ll grab the sources and create a diff patch for you to try out. At that point, you can either yell at me with changes that need to happen, or make them yourself… which ever is easiest for you. But I think a straight conversion of the changes I implemented will be a better way of discussing possibilities (what works, what sucks, etc)

1 Like
@t0neg0d said: @nehon I'm going to make a local copy of the particle emitter related files and see what I can do about porting the ideas here. Once complete, I'll grab the sources and create a diff patch for you to try out. At that point, you can either yell at me with changes that need to happen, or make them yourself... which ever is easiest for you. But I think a straight conversion of the changes I implemented will be a better way of discussing possibilities (what works, what sucks, etc)
Sounds good! as long as I still have the option to yell at you :p

Your approach is what I had in mind, so I totally agree. Only thing that bothers me is that there is a chance that this will be a breaking change.
Maybe we’d be able to make suitable influencers for compatibility.

It will be a breaking change for sure, because current implementation was not done with all these options in mind.
What about integrating particles system with some sprite system? It is essentially the same thing, except that “normal” sprites wouldn’t need emitter and influencers?

@nehon
I’m thinking there may be a slight issue with how gravity is being handled in the particle emitter atm. For some reason, it doesn’t scale with tpf. I do not see a reasn for this, but where it becomes noticeable is using the videorecorder appstate and a few emitters. Gravity stays constant over actual time and the slower the frame rate, the less gravity effects the particles… until they barely move.

The only reason I mention this is… I can’t find a reason for it. It is really starting to hurt my head =)

IMPORTANT to mention: This doesn’t happen with color, size, etc… only gravity.

EDIT Forget everything I just said… this was my issue. Soooo sorry.

[java]
p.velocity.x -= gravity.x * tpf;
p.velocity.y -= gravity.y * tpf;
p.position.addLocal(new Vector2f(p.velocity.x,p.velocity.y));
[/java]

As this seems t be only place where velocity is being applied to the particle (you should move it elsewhere, to allow constant velocity particles without gravity), it should be multipled by tpf as well.

@abies said: [java] p.velocity.x -= gravity.x * tpf; p.velocity.y -= gravity.y * tpf; p.position.addLocal(new Vector2f(p.velocity.x,p.velocity.y)); [/java]

As this seems t be only place where velocity is being applied to the particle (you should move it elsewhere, to allow constant velocity particles without gravity), it should be multipled by tpf as well.

Yeah… I caught this after the fact =) I have a number of updates for this I’ll be pushing out later today. As well as the impulse and alpha influencer… here be a vid of the final with patches and using:

Gravity
Color
Size
Rotation
Impulse
Alpha

And they are all being run as individual sprites as well:

[video]http://youtu.be/01GIEmbkeLY[/video]

Um… I also removed all new Vec calls for temp stores. Not sure what I was thinking. As well as provided a mechanism for getting setting new particle data for custom influencers.

@t0neg0d
That looks good!
One should be able to create its own influencer. Idk if that’s what you have in mind.
Like
myEmitter.setInfluencer(new WhateverInfluencerThatIMadeMyself());
Of course the gravity, color, and so on would be provided as stock influencers.

Or do you have in mind to make some influencer composition?
like
myEmitter.andInfluencer(new WhateverInfluencerThatIMadeMyself());
myEmitter.andInfluencer(new WhateverOtherInfluencerThatIMadeMyself());

@InShadow said: It will be a breaking change for sure, because current implementation was not done with all these options in mind. What about integrating particles system with some sprite system? It is essentially the same thing, except that "normal" sprites wouldn't need emitter and influencers?
About the breaking change, I'll manage. Maybe I'll have to deprecate some things...we'll see. Right now the particle material does have some kind of sprite mechanism, but you can't control the speed of the texture changes. That's why I think influencers should be able to control almost everything on the particle and maybe even on the particle material.
1 Like

@nehon:

I totally agreed that we should change ParticleSystem. I made changes to fit my needs like:

  • Let Emitter just emit and consider it the root of movement…
  • ParticleInfluencer can have hierchy structure, mean one force can be calculated by composing of others forces.
  • Introduce curve value for the good of eyecandy effect
    +) Let Particle type can also be Node or Geometry? So you can put anything into a moving Particle. In fact what I do is introduce another thing, which kind of make the system more complex, the ExParticleControl, It’s a plugable Control which tell a single Particle Quad change its sprite like the current system, also can make a Particle which also an Emiter (a Geometry or animated Node) change its animation from time to time.

Such system can be complex but I don’t see anything so difficult to refactor! Just my 2 cents, in fact, it’s still considerable keep the new things separate, like I do, but i you see it should change, go on and improve the way you like it.

P/s: And talking about making good Effect out of Particle, if you finish make your changes like you said, I can also provide the stylish editor made for Particle, instead of using Properties like current JMP.

@tonegod: One more nice feature! Keep rocking! Now we can even make a 2D game out of your libs with JME3 rendering system.

1 Like

So, big particle emitter redesign, even for 3d case? Then I’ll throw in my 2 cents - use cases I had to cover (or yet need to cover) when implementing NWN particle emitter, which I’m not sure if are covered by current particle emitter

  • rectangular particles - ability to have them longer at y axis and growing independent from x direction
  • motion blur-like behaviour - achieved by linking particle to velocity direction and y-size to speed; very useful for many effects (warp-like particles, fire etc)
  • gravity centered in certain point instead of uniform direction and dependent on distance from that point; allows orbiting particles
  • drag - pseudo-acceleration which slows down the velocity
  • fully random images - not only starting from random image index, but change to different random one each frame
  • linking front end of particles either to fix point to space or to back end of previous particle; allows lightning/rope-like effects
  • billboard-to ground (think stargate teleporter rings)
  • align y to vertical axis, but billboard x to screen (for fire, columns of light etc)

Probably gravity/drag can be easily made with velocity influencers, but other things might require exposing some extra properties.

Some of effects are actually composed from others - for example, align to velocity is just smart rotation + changing y-size to cover for angle between velocity and eye vector. Motion blur is multiplying y-size before that computation by speed*constant. This means it will be enough to just expose rotation and y-size of particle to allow implementing this effect purely in influencer.
Things which will require real low-level support are billboard/aligns.

@nehon said: @t0neg0d That looks good! One should be able to create its own influencer. Idk if that's what you have in mind. Like myEmitter.setInfluencer(new WhateverInfluencerThatIMadeMyself()); Of course the gravity, color, and so on would be provided as stock influencers.

Or do you have in mind to make some influencer composition?
like
myEmitter.andInfluencer(new WhateverInfluencerThatIMadeMyself());
myEmitter.andInfluencer(new WhateverOtherInfluencerThatIMadeMyself());

About the breaking change, I’ll manage. Maybe I’ll have to deprecate some things…we’ll see.
Right now the particle material does have some kind of sprite mechanism, but you can’t control the speed of the texture changes. That’s why I think influencers should be able to control almost everything on the particle and maybe even on the particle material.

Currently the influncers work like this:

You create a new influencer and register it with a String key.
You retrieve the influencer by passing in the key.
There is an emun for the stock influencers so you don’t have to remember the keys for those

[java]
// register
emitter.addInfluencer(“Swarm”, mySwarmInfluencer);

// get and manipulate during runtime
emitter.getInfluencer(“Swarm”).setIrritationFactor(.5f);
[/java]

If you don’t want the current API to change, all of the setters and getters can remain and pass parameters to the influencers, since there should be a list of stock influencers that are preloaded anyways. The only additions would be methods for enabling/disabling each.

So, yesterday I started playing around with the current emitter to see what it would take to modify it. There a couple things I am unclear about… (these are fairly random, so bare with me):

  1. I’m not quite clear on the use of TempVars, however I understand they are used to recalculate the BoundingBox. I propbably wouldn’t be having issues understanding the use if I went and read the class/javadocs =) I just haven’t had a chance yet. I think my biggest question is… is this class used globally? Or was it specifically written for the emitter?
  2. I’m still plodding through the EmitterMesh class. It’s really nicely done! The question I have is… why is the BoundingBox calculated outside of the mesh class? Doesn’t this happen automatically here (when calling updateBounds or whatever)? And part two of this question… is the geometry (emitter) aware of an update this way?
  3. Ah… almost forgot. Would it be a terrible issue to make the emitter a Node… or possible BatchNode to simplify some aspects of the emitter? I haven’t really thought this through, but since the particles are pre-generated… a BatchNode might work well? I’m betting the Emitter was written before BatchNode, yes?
  4. WorldTranslation is used to allow particles to appear to act independant of others (e.i. trail behind a moved emitter), this is the reason it doesn’t work in the GUI node (I realize you know this). Are there any other options for making this happen? Or should the emitter be updated to work in 2d/3d modes independently? Thoughts… is it possible to calculate and translate world coords without ever applying them? This way the particles could appear to function the same without limiting the use. I have a feeling this is a silly question, as I know the answer… but, I don’t know if this would cause problems in some other way I am unaware of.

I have more questions… but these are a good start.

Actually… I do have a few other things worth mentioning now:

Couple of potential mods that may/may not be useful:

  1. Emitter shapes that are 3D Initial velocity can emit either in a preferred direction, or outward from a random faces normal?
  2. Another question… why are there 2 particle shapes? My guess is a point can not be rotated around an axis… however the triangle based can. Is this a correct assumption?

Ok… that’s it for now.

Sorry for the brain dump.