-
-
Notifications
You must be signed in to change notification settings - Fork 642
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
improved particle system performance #372
Conversation
Well aren't you just awesome? E-hug! Seriously though, thanks for the pull request, and showing the numbers :D Just one small thing, please change the tabs from L476 down to 4 spaces. Just trying to keep things consistent, as a lot of the whitespace is bad in the project as is. Don't want to increase the issue. |
Awesome is melonJS. I am just giving back some of the time you save me ;) I just noticed that the particle effects are dependent on the frame rate, so I will have to change a few more things. |
Sure, no problem :) |
Using an But ... it's effectively the same code as before your patch. It might be worth optimizing |
I don't know what the problem with Using an With my last commit I use matrix2d for managing the transformations, but I am missing some methods (rotateLocal, setScale) :) |
+1 for Jason on the object container. however, i actually liked the idea of having the particles in the main world container, as we could then play with z order to fake a player sprite walking within the smoke, rain, or fire. |
var particle = this._particles[i]; | ||
if(!particle.isDead) { | ||
particle.inViewport = (particle.pos.x < viewport.pos.x + viewport.width && | ||
viewport.pos.x < particle.pos.x + particle.width && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know, I used that method before I inlined it, but there is something really bad going on with it in terms of performance.
The overlaps method of me.rect cost me around 5fps as you are using getters for left, right, top and bottom (https://bugzilla.mozilla.org/show_bug.cgi?id=626021).
I just went through the patch, and although there is indeed great improvements in terms of performances, I must say that I also agree with Jason, as we lost a lots in terms of readability..... I was wondering if we could not find a way in between that would more compromise with both approach ? in the mean time the provided examples are probably too much (amount of particles, etc...) for a regular game, and might not need that much performance improvements ? Jason, what is your opinion about being able to mix regular objects with the particles in the world container (see the use case I explained before) ? @insidiator at this point, and please don't get me wrong, but I'm not sure this is ready to be merged into the 1.0.0-dev branch, and I would prefer to have it on a separate branch until this patch is finalised and known to be working (when the viewport moving, etc..) |
@obiot I think it sounds neat in theory, but then again you could just use multiple emitters, each at a different z-index, and get the same visible result. :) |
@parasyte indeed, i did not think about it... ;) |
@obiot I know that this patch is not yet ready to be merged back in. I will change the code once more for better readability once I have identified and eliminated all performance killers and fixed the bugs I introduced. |
for sure it's not a problem for me, and I forgot to tell you it in my previous message, but thank you for your time on this one :) |
A few more updates. I changed the emitter to be an ObjectContainer and use the addChild, removeChild and draw method. I don't want to use the update method for now, as the isVisible function is quite slow (at least in firefox). I am also wondering if we could add a flag to ObjectContainer to specify if it should apply its position/transformation to its children, because particles should be positioned independent of the emitter. If we could set the position of the emitter independently of the particles, it would also be possible to set |
I tested the examples with chrome and noticed that the texture additive mode works perfectly fine there (no slowdown). Also found the bug report for this problem: https://bugzilla.mozilla.org/show_bug.cgi?id=762973 |
It sounds like it is treating position vectors as screen coordinates. This is the same effect as using |
I removed the need for I see several possible solutions:
|
To be quite honest, I prefer the first one. It isn't much different from the current way things are done, anyway. The only class that adds itself to the scene in its constructor is As a side note, I would like to suggest reconsidering the hierarchy in this refactored particle manager; A container is good for grouping particles, defining their boundaries, and transforming them as a single unit. That needs to stay as-is, IMHO. What needs to change is the API. It's illogical to treat the emitter as a top-level object in this hierarchy, when in fact the emitter is just a vector point (and a few other configurable parameters) within the top-level container. Here is my proposal for class hierarchy:
Pretty straight-forward. When I (as a game developer) want to use the particle manager, I create a // Create a particle manager
var pos = new me.Vector2d(20, 20);
var width = 200;
var height = 100;
var mgr = new me.ParticleManager(pos, width, height,
/* Default emitter definition */
{
"image" : me.loader.getImage("explosion"),
"pos" : new me.Vector2d(0, 0),
"angleRange" : [ 0, Math.PI * 2 ],
"speedRange" : [ 3, 7 ],
"scaleRange" : [ 0.6, 1.0 ],
"lifeRange" : [ 500, 2000 ],
"maxParticles" : 300,
"streamMaxParticles" : 80,
"gravity" : 0.3
}
);
// Emitter follows pointer
me.event.subscribe(me.event.MOUSEMOVE, function(e) {
mgr.emitters[0].pos.set(e.gameWorldX, e.gameWorldY);
});
// Add particle manager to scene
mgr.z = 10;
me.game.world.addChild(mgr); The manager creates a default emitter (which is added to itself mgr.createEmitter({
"image" : me.loader.getImage("fire"),
"pos" : new me.Vector2d(mgr.width / 2, mgr.height / 2),
"angleRange" : [ -0.08, 0.08 ],
"speedRange" : [ 2, 4 ],
"scaleRange" : [ 1.3, 0.2 ],
"lifeRange" : [ 100, 1000 ],
"maxParticles" : 300,
"gravity" : -1
}).startStream();
While I'm proposing API changes, I really dislike this concept of linear ranges. Using arrays like in the above snippets helps a little bit, but it still sucks a lot. What if I want to change the interpolation functions? Also, why so many numbers? The angle and speed can be expressed as a single magnitude vector. And two vectors can define their ranges. Another peeve I have is that this code calls for a static image for the particle. What if I want to use an animation? What if I don't want to use a raster image at all? Maybe I'm making a game using the canvas vector drawing API. For these I need the full |
I'll change it to manually adding the container to world then. I like the change that you propose as I thought about a similar structure myself (adding emitters to a particle system and rendering all particles in that system together), but I would also like to avoid bigger API changes in this ticket, as it should be about performance optimization. If it is okay with you, I would like to open a new ticket "particle system improvements and features", where we can discuss such ideas and bring this one to a close with the next commit(s). I will also do a new benchmark and post the results here. |
I gathered the results of my benchmark in a spreadsheet: The values where taken from the plugin that I added with my latest commits. Before each test, I reloaded the example page and then waited until all particles have spawned and the values stabilized. The values labeled with particle are the accumulated update and draw times for each individual particle in the old version and for the particle containers in the new version. The overall update and draw time is measured like in the debug panel, but instead of The major performance killers for the particle system where the sorting which occurred when a particle was added to the world and the call to |
@insidiator Yeah, API discussion in another ticket. That's fair. |
between your last exchanges and the new ticket on API changes, i'm very confused about what we shall do here. To be quite honest myself, I also prefer the approach proposed by Jason, i like the particle manager approach (simple and efficient), but also certainly because this is closer to the engine philosophy :p Also having a and finally, regarding the API, so far, and since this is completely new, we are still free to fully change it we want/need to, so no worries there ;) |
I also think the proposed API change is a step in the right direction, as it will make the particle system more flexible and easier to handle. But IMHO that are changes which should not happen in this ticket, which is about performance improvements. Before doing any big changes to the API I would like to coordinate them with @ciangames, because the particle system is originally his contribution and I think he is using it in his game. So please decide what to do here @agmcleod @parasyte @obiot, because ultimately it is your engine ;) |
👍 |
👍 voted ! |
I would add a big thank you to both of you guys @insidiator and @ciangames, and I would like to add that I rather see melonJS as a community based engine, rather than just our engine :P |
@insidiator Yes, I'm using the particle in my game, with nice effects :) @obiot I thank you for melonJS, and the ver. 1.0.0 will be awesome! |
@agmcleod good to go for you too ? |
Yep. I'll have to play with it at somepoint, as particle systems are a bit foreign to me. But it looks good. Given @ciangames the original writer also gives it a +1, I think you can merge it :) |
ok, merging this baby then :P |
improved particle system performance (Insidiator)
i did not notice that there is a new particleDebugPanel with a flame graph ! i always wanted to add a proper one into the regular debug panel, but never had the time to ! a good merge of both would nice now ;P |
@obiot proper is a bit of an overstatement. I just copied the one from the debug panel over and changed it a bit to not eat 5ms per frame ;) |
…… …rticles the issue was also reported here : https://groups.google.com/forum/m/#!topic/melonjs/dzqIAjMuyGY and is caused by the onDeactivate function that attempt to remove the particle container from its ancestor, where (previously) the ancestor reference was clear by the removeChild function before calling the `onDeactivateEvent` function : https://github.com/melonjs/melonJS/blob/master/src/renderable/container. js#L499
I tried the new particle system today and noticed, that it runs a bit slow, especially when using the additive mode.
After some profiling and tinkering around I managed to improve the performance a bit.
There is still much room for improvements, but I think it's a solid start.
The examples show the following fps improvements:
The rain and waterfall example look a bit different than before, but I have not looked into the cause yet.
I think the matrix class could be helpful in managing the transformation of the individual particles.
Also I am planning to try a different approach to the additive mode, because it costs too much performance to use the globalCompositionOperation.