Game Development Community

dev|Pro Game Development Curriculum

Improved Particle Emitters

by Sebastiaan Keek · 04/08/2003 (1:42 pm) · 48 comments

Download Code File

First off this is my first attempt at torque coding besides coppy and pasting other code. The (not all that nicely) documented added and expanded fields have been tested to a good extend and "if" you get what the heck it is they actually do.. you'l find them very usefull for creating certain special effects and whatnot.

This code is meant for the latest head of approx early april 2003.
It seems to be incompatible with 1.1.1.

I've included a readme for reference an screenshot and a modified scorchedPlanet.mis to showcase some of the posibilities. And ofcourse the code files.
The code files overwrite your current particleEmitter and ParticleEngine source files. If you made any changes to them, you could try merging, thought I recommend testing out my version first to see if it's worth it ;).

But it's worth it.. trust me. The additions allow for creations of complex rotating fields of particles, cubic fields of particles and particles relative to objects..
Also it removes the need for a model node by introducing a virtual node in the emitter system.
I also enabled the ability for emitters to scale, either by datablock or by linked object wich allows for player jetpacks to dynamically scale along with the rest of the model.

However with the introduction of new fields also comes added complexity. I'l try to update my documentation and hopefully shed light on questions anyone might have.

Finally, please feel free to make comments, ask questions or make sugestions either by email or on this page.

*Updated to version 0.3
#21
12/14/2004 (11:26 am)
Hmm thanks, I might try and do that tonight... though I might be interested in doing the same, porting over mounting to gamebase... i tried to port mounting to particles unsuccessfully, then derived particles of shapebase instead of game base lol... to no avail

so if you have any pointers I can stumble my way through that
#22
12/14/2004 (10:04 pm)
If you really want to make mounting available for gamebase, simply do a general search for "mount" in the shapebase code and incoperate the relavant pieces to gamebase.
It's been over a year I did that... but I don't remember running into any serious troubles.
#23
12/15/2004 (5:40 am)
ahh, very cool.... I was wondering about that... after i tried to make particleEmitter derive of shapebase instead of game base...a nd that failed... I wondered how hard it would be to port mount to gamebase instead... thx for the tip :)


yesterday I added fire to my sword through the "stateEmitter" ... node and time values too... I went into the engine and tried adding three more state nodes... it all worked (after some tweaking)... expect it would onlydisplay the last node listed... I commented out them singularly and each work with their unique settings, but wont display together


so I found the startImageEmitter function in ShapeImage.cc and made a couple versions of that for each node... now it errors out on an error ending with "NOT reentrant"...

any idea what the halt on that is ? trace dit back to adding a "reentrant event"


btw thanks for the advice so far, much appreciated, and great resource !
#24
12/15/2004 (12:33 pm)
What your trying to do is the original methode of adding emitters to objects (much like players, vehicles and projectiles already have).
I'm afraid I know litle of that, since I went on creating my own methodes instead of trying to work with the available ones.

I suggest you take a close look at the excisting code (make sure your not using the same emitter object for all 3 nodes instead of making 3 seperate ones and using them seperate)
#25
12/16/2004 (6:27 am)
lol you are correct... I overlooked a single function... the preload function that was causing them to use the same datablock ( at least this is what I beleive the result was)... in any case, I modified this and now two nodes emit on my weapon... 3 and 4 still aren't working, but I'm guessing a simple error in some code by me, will need to look over it and maybe see if theres a better more efficient way to do this... or maybe an array, right now I have emitter... emitter2... etc etc

I started a little of the port of mount to gamebase, though going through code I realize how much code involves mounting... a question, if you happen to remember some of the process, did you move a huge chunk of shapebase code over to gamebase... the more I looked into it the more i moved over, it almost seemed I was making the use of shapebase much limited...

if you happen to remember... did you move the image code over, the results of mounting etc... or just the base mounting core... seems the more I looked at it I'd need to move more and more ove the image code over to ensure everything was handled properly ... sorry to keep asking questions about this... pretty impressive that you changed out so much of the code, hopefully I can get to that point, slowly figuring things out now
#26
12/16/2004 (6:36 am)
A question on the object linking also..

now this might be usefull since its being linked to the sword...

say I create a particle... SwordSpark
then an emitter... SwordSparkEmitter...a nd thats what I put on my sword (quite originally named Sword :) )

would I then do SwordSparkEmitter.linkObject = Sword;

then manipulate the linkRotation ... etc.


would it be in the emitter datablock ?

as linkObject = Sword; like
linkRotation = true;

or would it be defined afterword, maybe in console or from a script initiated after the objects are created, or do I have the whole Sword reference thing wrong... lol sorry to bug you about this, if your busy I understand
#27
12/16/2004 (8:42 am)
Ok first off
|||Mounting in gamebase|||
Notice there's a large difference between mounting "images" and "objects" to other objects.
The mounting code I used bassically is about
struct MountInfo { ... }  mMount;
from shapebase.h

The majority of the functionality comes from using the information about what's mounted to what in:
GameBase::processTick(const Move*) and GameBase::advanceTime(F32 dt)
This is where you simply make the location of your object where you want it to be (ie. the location of the node the object is mounted to).

Here's all I ported over to gamebase (I coppied this from my gamebase.h)

struct MountInfo {
      GameBase* list;              // Objects mounted on this object
      GameBase* object;            // Object this object is mounted on.
      GameBase* link;              // Object link of next object mounted to this object's mount
      U32 node;                    // Node point.
   } mMount;

   virtual void onMount(GameBase* obj,S32 node);
   virtual void onUnmount(GameBase* obj,S32 node);

   //more Mounted objects
   virtual void mountObject(GameBase* obj,U32 node);
   void unmountObject(GameBase *obj);
   void unmount();
   GameBase* getObjectMount()  { return mMount.object; }
   GameBase* getMountLink()  { return mMount.link; }
   GameBase* getMountList()  { return mMount.list; }
   U32 getMountNode()  { return mMount.node; }
   bool isMounted() { return mMount.object != 0; }
   S32 getMountedObjectCount();
   GameBase* getMountedObject(S32 idx);
   S32 getMountedObjectNode(S32 idx);
   GameBase* getMountNodeObject(S32 node);
   void getMountTransform(U32 mountPoint,MatrixF* mat);

|||Mounting of particle emitters|||
The way I would go about this is as follows:
Create a console-accessable function that lets you set the .linkObject of the emitter that's connected a certain particle emitter node.

The problem in your case, you have one object (sword) wich should emmit particles (or be able to) in the same fashion everytime it's created. Again I stress this is very simular how projectiles,weapons,vehicles and players have source coded emitters.

Doing it through particle emitter nodes allows very much freedom in scripting and working with it like this.. but again.. if you don't need such freedom but rather just a flameing sword (much like rockets always have smoketrails) your better of making sourcecode based emitters.
#28
01/25/2005 (7:48 am)
I was implementing this in 1.3 and had one problem:
Rad = pow(min + SteppedRandom(mDataBlock->VarianceSteps)*(max-min),0.5);

would not compile because of pow(F32, double), so I newbishly changed it to:
Rad = pow(double(min + SteppedRandom(mDataBlock->VarianceSteps)*(max-min)),0.5);

which does compile fine, and I got the smokeParticle texture from the rifile in fine, but I cannot load the mission "Scorched Earth" because of "Invalid Packet"

Any help? Thanks!
#29
01/25/2005 (8:57 am)
the line you changed "should" have nothing to do with packets.

Scorched Earth is a particle heavy example map that was supposed to show of some of the new features of this code. My best gues would be that there's something wrong with the packet sending and retrieving part of the code in 1.3, wich would either be for the datablock or the object packet sending parts.
Since I've been out of the loop for a good time and have no experience with 1.3 I have no clue what could be going on but if you seriously want to fix this I suggest you start looking at those parts first.
#30
01/25/2005 (9:02 am)
Thank you for the promt reply! I figured out the problem, (checked my console log, far be it from me to do that before asking for help... heh) and got all of the scorched earth files in from my old demo stuff. Thank you so much for your help, and great resource!

BTW... is there something else I should do with the pow() function? It seems like my typecasting fixed it fine from what I can tell....

Thanks again.
#31
01/25/2005 (10:19 am)
Pow(x,0.5) simply raises x to the 0.5'ed power.. or in this case the square root of x.
The fact that it apparantly used to take F32's too instead of just doubles is why it was in it's orignial form.
It doesn't really matter tho.. doubles and F32's it's all bassically the same since no special operation is done on the eventual outcome and special accuracy that F32 might have over doubles(or the otherway around) is pretty pointless since it's just a particle engine.

Since the routines applied in this example as of a very basic and simple nature I always apply the following rule when I am done with coding:
If it compiles, it will do what I want.
#32
07/20/2005 (10:08 pm)
I got this to compile with Torque 1.3 by changing 0.5 to 0.5f in that Pow call like mentioned above. No sweat, but once I tried it, I realized there are a few problems

1) It breaks compatibility with existing particle emitter nodes' direction, and uses a default world orientation instead, like the emitter by default always emits toward the world y forward instead of the node's y forward (this broke my muzzle flash)
2) With none of the new features enabled, it doesn't place the particles exactly where they were. I noticed my projectile particle emitters are now placing particles slightly out of place, which looks strange.
3) It never fixed the placement algorithm for explosions, which placed particles within a square instead of a hemisphere.

I'm going to dig into this to see if it can be cleaned up to fix the problems I listed above. If anyone else has refined this code already, please let me know. Thanks
#33
02/26/2006 (4:47 pm)
Has anyone tested this with ver 1.4?
#34
09/08/2006 (11:33 pm)
I guess not? Anybody yet?
#35
09/13/2006 (7:42 pm)
Im working in it right now with mounting of particles as well. I had to do it by hand b/c a lot of the stuff just wasnt right and i couldnt figure it out. I do have it compiling though but havent tested the new particles. All my old ones do work though.

The main problem i have now is that i am trying to mount the particles to other objects. I read what they mentioned above and for some reason when i do the linkObject stuff it crashes and gives me no real clear error. Here is my console function

ConsoleMethod( ParticleEmitterNode, mountToObject, bool, 4, 4, "( GameBase object, int slot )"
              "Mount ourselves on an object in the specified slot.")
{
   GameBase *target;
 
   if (Sim::findObject(argv[2],target)) {
      S32 node = -1;
      dSscanf(argv[3],"%d",&node);
      if (node >= 0 && node < GameBaseData::NumMountPoints)
         target->mountObject(object,node);
         //object->getParticleEmitter()->LinkObject = target;
      return true;
   }
   return false;
}

the commented out line is what i am trying and it crashes. Does anyone have a clue on this?

Thanks
#36
09/13/2006 (7:48 pm)
Actually I already fixed most of the problems with this but never posted the code. It was a while ago, but I think I could dig it up if there is enough interest. I wrote the thing to attach particle emitters to objects successfully and had it working just fine. I also fixed the square explosions with this.
#37
09/14/2006 (8:02 am)
that would be great if you could do that. Did you end up having to change mounting over to game base?

i currently did this and it will do the initial mount of the particleemitter node but then it wont move if you move the object or animate with objects.

I would definately love to have this working.

Also, is it implemented into 1.4? Just a question more so than a necessity, since i have already ported over what was there to 1.4.

Thanks, Kip
#38
09/14/2006 (3:19 pm)
I'd be very interested in this resource as well if you wouldn't mind posting it
#39
09/14/2006 (4:24 pm)
I have been looking at the code and it seems the problem i had with earlier is that it doesn see that the particleEmitterNode has an Emitter and hence why it cant set the linkobject. this is really wierd to me and i cant see why it wouldnt have one. Any clues?
#40
09/14/2006 (4:52 pm)
I'll post my solution tomorrow or possibly even tonight. The problem is fairly deep so it requires modification to a few lower level classes.