Influencer-based ParticleEmitter candidate (mesh-based animated particles)

@nehon (or anyone else who may have an idea about how to do this correctly)

Some of the influencers are random chance based… this can be effected by the FPS. since the end effect ammount is not concerned with the FPS (one time event), I wasn’t quite sure how to create a similar frequency of… let’s take Impulse for instance.

My closes guess (off the top of my head) was:

[java]
if (FastMath.rand.nextFloat() > 1-(chance+tpf)) {

}
[/java]

This does increase the chance the slower your FPS is, however… it doesn’t seem quite right. Any thoughts on how you would go about this?

1 Like

Usually when you want to be FPS independent but still want something that varies over time, you stack the tpf into a time variable and use time as a factor in your function.

2 Likes
@t0neg0d said: Some of the influencers are random chance based... this can be effected by the FPS. since the end effect ammount is not concerned with the FPS (one time event), I wasn't quite sure how to create a similar frequency of... let's take Impulse for instance.

Any thoughts on how you would go about this?

This depends what you want to achieve.
If you want to have repeating event which will occur ‘chance’ times per second on average, just to
[java]
rand() 1 probability, you will need to fire more than one event per frame.
(if you want to proof it mathematically, sum for n=0…frames nnewton_binomial(n over frames) * p^n(1-p)*(frames-n), where p = is your per-second chance/frames)

Now, if you want to have one shot event… then it is bigger issue, you need to find the per-frame probability which will end up with same chances of happening at least once during the frame… but this will have different results depending on your reference time. Over my head at this moment in the morning.

2 Likes

Yeah, combining probabilities and variable frame rates makes for some tricky maths. Do you really need randomness in the frequency of emission?

@t0neg0d - yep, that’s what I was meaning. Much cleaner :slight_smile:

Just be careful if you use getClass anywhere since if anyone subclasses an influencer getClass will be different (hence the getInfluencerClass) method in my examples.

The constructor thing should make it a lot cleaner too if you do that.

1 Like
@zarch said: Just be careful if you use getClass anywhere since if anyone subclasses an influencer getClass will be different (hence the getInfluencerClass) method in my examples.

Can you describe a situation where this comes up and actually matters? Usually the caller is interested in a particular class. So they ask for it and get it. Subclassing that class will not change it because isAssignableFrom() will still work. Though I had to double-take because I was about to say isInstance() and for some reason state manager instead decides to use type.isAssignableFrom(state.getClass()). I have no idea why it doesn’t just use type.isInstance(state).

1 Like

If you have a map from class to object, and the addInfluencer method adds into the mapping ob.getClass mapping to ob then if you add a colour influencer and a subclass of colour influencer they will have different entries in the mapping instead of overwriting each other.

1 Like
@zarch said: If you have a map from class to object, and the addInfluencer method adds into the mapping ob.getClass mapping to ob then if you add a colour influencer and a subclass of colour influencer they will have different entries in the mapping instead of overwriting each other.

Which may be desirable. In fact, I wouldn’t use a map at all. Maybe you want 20 color influencers all of the exact same class.

1 Like

To be honest I wouldn’t have get/set influencer methods at all. I’d just put the influencers in a SafeArrayList, provide add/remove methods and then pass in influencers to the constructor (or add them with an adder).

Then the person outside has passed in the influencer so if they want to modify it they can keep a reference themselves.

The suggestion above was just trying to keep the same architecture that already existed but make it cleaner.

1 Like
@zarch said: To be honest I wouldn't have get/set influencer methods at all. I'd just put the influencers in a SafeArrayList, provide add/remove methods and then pass in influencers to the constructor (or add them with an adder).

Then the person outside has passed in the influencer so if they want to modify it they can keep a reference themselves.

The suggestion above was just trying to keep the same architecture that already existed but make it cleaner.

But JME has repeatedly used the get( Class ) pattern in many other places (AppStates, Controls) that just iterates over the list and returns the first one matching the passed type. It’s very convenient, common to the platform, and pretty easy to implement.

1 Like

P.S.: I agree, no set. Just add/remove/get.

1 Like

@pspeed
I agree about potentially wanting to stack the type of influencer. How would you or @zarch suggest accomplishing this with a getter that still returns that appropriate class? My guess would be a map that stores a String key and a map (class, object). In the case of added influencers by class the string key is getName() of the class, the internal map is the class and instance. Obviously the other method would allow for arbitrary keys that do not relate to the class.

Problem is, there would be multiple adds, removes, gets and it may seem a bit confusing to someone using it.

Ideas? Stacked impulse influencers with different settings would be great.

1 Like
@abies said: you need to find the per-frame probability which will end up with same chances of happening _at least once_ during the frame... but this will have different results depending on your reference time. Over my head at this moment in the morning.

This is exactly what it should do. My cheesy solution simulates this in a very non-precise way… but does at least give an increased chance depending on the time between frames (probability goes up based on fps). What I need is the real solution =) I’m putting this on the back-burner for now (and it will probably stay this way until after I submit the code for review), but wanted to mention this so others were aware it needed to be updated eventually.

EDIT: actually… the way I am calculating the number of particles that should have happened depending on the time between frames may work in this case as well. I’ll give that a shot and if it works, will post the solution.

Ok… this may work. I don’t need to adjust the probability. I need to decide how many times the influencer should attempt the fixed chance based on time between frames. This will have the same result as trying to determine a sliding chance factor without the headache of how that works.

I lied… the moment I hit submit, the reason why this wouldn’t work hit me. Just ignore everything past… I need help! lol

1 Like
@t0neg0d said: @pspeed I agree about potentially wanting to stack the type of influencer. How would you or @zarch suggest accomplishing this with a getter that still returns that appropriate class? My guess would be a map that stores a String key and a map (class, object). In the case of added influencers by class the string key is getName() of the class, the internal map is the class and instance. Obviously the other method would allow for arbitrary keys that do not relate to the class.

Problem is, there would be multiple adds, removes, gets and it may seem a bit confusing to someone using it.

Ideas? Stacked impulse influencers with different settings would be great.

Do it exactly like AppStates. Just a list of influencers (SafeArrayList in this case). Iterate over it to find the right one for the class. If the user adds more than one of the same class then they are on their own. Provide a method for iterating over the list if they want to sort out their multiple versions of the same class.

In my opinion, it’s the best balance between making the easy use-cases simple and the harder use cases “not that much harder”, balanced with simpler code.

2 Likes
@t0neg0d said: This is exactly what it *should* do. My cheesy solution simulates this in a very non-precise way... but does at least give an increased chance depending on the time between frames (probability goes up based on fps).
What is the use case for that? Do you have the event which occurs only once during entire lifetime of emitter?
1 Like

/sigh I hate to be a bother, but I need a bit more assistance with the PreferredDestinationinfluencer

Here is what it is supposed to do, however the attempts thus far haven’t worked out quite as I expected.

Each frame there should be a chance that the particle will try to adjust it’s velocity vector towards a specified destination.

What I thought would work (but apparently missed something):

  • Use a temporary Node store, set the position, direction using the current particle.
  • Use lookAt(destination) to determine the desired directional vector
  • Interpolate using this new vector.
  • Update the particle data.

Unless I am way off in my guess on how to do this (this actually seems to be working mostly), I think the issue is how I am converting the new rotation to a directional vector. So, the question is:

How to you get a Vector3f direction from a Quaternion?

1 Like
@abies said: What is the use case for that? Do you have the event which occurs only once during entire lifetime of emitter?

Oh… no. Sorry. There is an initialize method of the influencer to account for that type of thing. This needs to determine how likely an event would be based on the time between frames. And actually, the life counter may be critical in simplifying this.

The particle has a randomly determine life cycle (within the defined parameters)
Over the course of it’s life, the ImpulseInfluencer has a certain % chance of influencing the direction of the particle each frame.
The problem is, the slower the frame rate, the fewer times the influencer’s update loop is called , thus the fewer times it checks against the chance of effecting the particle.

[java]
if (FastMath.rand.nextFloat() > 1-(chance+tpf)) {

}
[/java]

This, semi-accounts for the above, though I get the impression that it is not the proper way of doing this.

1 Like

Get unit vector and multiply it by quaternion? Or, if you have Matrix4f, use multNormal (to avoid translation and size components).

Regarding the ‘each frame there should be a chance’ - if this is the case, use my first suggestion, just divide chance-per-second by 1/tpf to get a chance of it happening in given frame. Will work even with chances per second bigger than 100%, as long as you don’t put more than fps*100% chance.

2 Likes
@abies said: Get unit vector and multiply it by quaternion? Or, if you have Matrix4f, use multNormal (to avoid translation and size components).

Regarding the ‘each frame there should be a chance’ - if this is the case, use my first suggestion, just divide chance-per-second by 1/tpf to get a chance of it happening in given frame. Will work even with chances per second bigger than 100%, as long as you don’t put more than fps*100% chance.

Sorry for the stupid question (I have a whole bag full of them if you ever need to borrow one):

Unit vector = up vector? Or the current vector?

1 Like

It depends on what you think ‘base’ quaternion is. Important thing is that if you multiply it by no-rotation quaternion, you will get same thing back. So if you put up vector, you will get up vector after rotation. Most probably you mean ‘straight ahead’ vector, which might be 0,0,1 ?

2 Likes

So, I had to make another edit to the ParticleTriMesh class to account for rotation along separate axis’.

This makes me wonder if billboard would be a separate thing at all. Between normal direction and rotation, don’t you have everything necessary to face and spin the particle any way you would want?

I guess billboarding along axis’ or axis to camera would be booleans at this point, that disable axis control in the rotation influencer.

Or, am I missing some other possibility here?

1 Like