Mounting Particle Emitters to a Node
by Dallas Anderson · 11/12/2007 (1:44 pm) · 1 comments
First I will give all the code used to emit particles at a given node in the .dts file. At the end of all the code I will go through it in stepwise fashion. I decided against explaining it inside of comments. Sorry for the bad format and any problems reading it.
Note the code is in addition to the code already in the method unless otherwise specified. I omitted the code from each method that did not have to do witht he goal of mounting particle emitters to node.
/********sourcecodefilename******//
/** methodName**//
/******** HoverVehicle.h ******/
//**class HoverVehicleData : public VehicleData**
enum Jets {
MaxJetEmitters = 3,
};
enum JetNodes {
maxJetNodes = 3,
};
ParticleEmitterData* jetEmitter[MaxJetEmitters];
S32 jetNode[MaxJetNodes];
// static const char *sJetNode[MaxJetNodes]; If you want to use an array of node names.
//** class HoverVehicle : public Vehicle**/
SimObjectPtr mJetEmitter[HoverVehicleData::MaxJetNodes];
/*******hoverVehicle.cc********/
//** HoverVehicleData::HoverVehicleData()**/
for (S32 k = 0; k < MaxJetNodes; k++)
jetNode[k] = -1;
for (S32 j = 0; j < MaxJetEmitters; j++)
jetEmitter[j] = 0;
//** void HoverVehicleData::initPersistFields()**/
addField("forwardJetEmitter0",TypeParticleEmitterDataPtr, Offset(jetEmitter[0], HoverVehicleData));
addField("forwardJetEmitter1",TypeParticleEmitterDataPtr, Offset(jetEmitter[1], HoverVehicleData));
addField("ForwardJetEmitter2",TypeParticleEmitterDataPtr, Offset(jetEmitter[2], HoverVehicleData));
//** void HoverVehicleData::packData(BitStream* stream) **/
for (S32 j = 0; j < MaxJetEmitters; j++)
{
if (stream->writeFlag(jetEmitter[j]))
{
SimObjectId writtenId = packed ? SimObjectId(jetEmitter[j]) : jetEmitter[j]->getId();
stream->writeRangedU32(writtenId, DataBlockObjectIdFirst,DataBlockObjectIdLast);
}
}
//** void HoverVehicleData::unpackData(BitStream* stream) **/
for (S32 j = 0; j < MaxJetEmitters; j++) {
jetEmitter[j] = NULL;
if (stream->readFlag())
jetEmitter[j] = (ParticleEmitterData*)stream->readRangedU32(DataBlockObjectIdFirst,
DataBlockObjectIdLast);
}
//** bool HoverVehicleData::preload(bool server, char errorBuffer[256]) **/
if (!server)
{
for (S32 j = 0; j < MaxJetEmitters; j++)
if (jetEmitter[j])
Sim::findObject(SimObjectId(jetEmitter[j]),jetEmitter[j]);//
};
jetNode[0] = shape->findNode("jetex");
jetNode[1] = shape->findNode("jetexb");
jetNode[2] = shape->findNode("jetexa");
// you can also pass an array of char strings
// for (S32 j = 0; j < MaxJetNodes; j++){
// jetNode[j] = shape->findNode(sJetNode[j]);
// where sJetNode[j] stores the names ("jetex", "jetexb", "jetexa")
//** void HoverVehicle::updateJet(F32 dt) **//
if(mThrustDirection == ThrustForward){ //This checks if person is holding W key down
for (S32 j = 0; j < MaxJetEmitter; j++)
updateEmitter(true,dt,mDataBlock->jetEmitter[j],j);
}
else{
updateEmitter(false,dt,mDataBlock->jetEmitter[0],0); //0,2
//** The entire function is below **//
HoverVehicle::updateEmitter(bool active,F32 dt,ParticleEmitterData *emitter,S32 k)
{
if (active)
{
if (!bool(mJetEmitter[k]) )
{
mJetEmitter[k] = new ParticleEmitter;
mJetEmitter[k]->onNewDataBlock(emitter);
mJetEmitter[k]->registerObject();
}
MatrixF mat;
Point3F pos,axis;
mat.mul(getRenderTransform(),
mShapeInstance->mNodeTransforms[mDataBlock->jetNode[k]]);
mat.getColumn(1,&axis);
mat.getColumn(3,&pos);
mJetEmitter[k]->emitParticles(pos,true,axis,getVelocity(),(U32)(dt*1000));
}
else
{
for (S32 j = 0; j < 3; j++)
{
if (bool(mJetEmitter[j]))
{
mJetEmitter[j]->deleteWhenEmpty();
mJetEmitter[j] = 0;
}
}
}
}
//********************** END OF CODE*******************//
Documentation
We start with hoverVehicle.h. It is the header file of the shape we are going to be adding nodes and emitters to. Here the enumerations of the maxNumber of nodes and Emitters are stored. Also arrays that will contain or point to the nodes/Emitters are also created.
//** HoverVehicleData::HoverVehicleData()**/
Inside the constructor we want to initialize our array of nodes/emitters to -1/0 respectively.
//** void HoverVehicleData::initPersistFields()**/
Inside initPersistFields we fill jetEmitter[] with pointers jetEmitterData that are defined in script.
//** void HoverVehicleData::packData(BitStream* stream) **/
//** void HoverVehicleData::unpackData(BitStream* stream) **/
both are just for sending/recieving information about hoverVehicle Objects and how to handle it. It is important to make sure that it is done in the correct order (the same as you put it in initPersistFields(), you can just look at any source code for examples of how to do this).
//** bool HoverVehicleData::preload(bool server, char errorBuffer[256]) **/
If not server then it set's up the jetEmitters. It also fills jetNode[] with the correct node as it appears in the .dts file. I used the explicit name - findNode("jetex"); - instead of using an array of characters.
//** void HoverVehicle::updateJet(F32 dt) **//
This could be a plain update method but hovervehicles have a specific method for Jets so I decided to put the update here. You could use any if statement to decide whether to emit or not. I use
if(mThrustDirection == ThrustForward) because I want my nodes to emit particles when it is thrusting forward. If it is thrusting forward then it update's that emitter with true set. If it is not I used a shortcut and just send one message to turn them all off.
//** HoverVehicle::updateEmitter(bool active,F32 dt,ParticleEmitterData *emitter,S32 k)
There are two main branches of this method. Turning on the particle emitter or turning the particle emitter off. If it is being turned on it checks if there is a mJetEmitter[k] corresponding to k. If not it creates a new one. Then the position and axis of the node are extrapolated. Then it tells the emitter to emit particles with that data.
If it is being turned off it simply turns off the emitter once it is empty.
That is the basics to mounting a particle emitter to a node in your .dts file. While my example is for hoverVehicle it should be applicable to many things.
Note the code is in addition to the code already in the method unless otherwise specified. I omitted the code from each method that did not have to do witht he goal of mounting particle emitters to node.
/********sourcecodefilename******//
/** methodName**//
/******** HoverVehicle.h ******/
//**class HoverVehicleData : public VehicleData**
enum Jets {
MaxJetEmitters = 3,
};
enum JetNodes {
maxJetNodes = 3,
};
ParticleEmitterData* jetEmitter[MaxJetEmitters];
S32 jetNode[MaxJetNodes];
// static const char *sJetNode[MaxJetNodes]; If you want to use an array of node names.
//** class HoverVehicle : public Vehicle**/
SimObjectPtr
/*******hoverVehicle.cc********/
//** HoverVehicleData::HoverVehicleData()**/
for (S32 k = 0; k < MaxJetNodes; k++)
jetNode[k] = -1;
for (S32 j = 0; j < MaxJetEmitters; j++)
jetEmitter[j] = 0;
//** void HoverVehicleData::initPersistFields()**/
addField("forwardJetEmitter0",TypeParticleEmitterDataPtr, Offset(jetEmitter[0], HoverVehicleData));
addField("forwardJetEmitter1",TypeParticleEmitterDataPtr, Offset(jetEmitter[1], HoverVehicleData));
addField("ForwardJetEmitter2",TypeParticleEmitterDataPtr, Offset(jetEmitter[2], HoverVehicleData));
//** void HoverVehicleData::packData(BitStream* stream) **/
for (S32 j = 0; j < MaxJetEmitters; j++)
{
if (stream->writeFlag(jetEmitter[j]))
{
SimObjectId writtenId = packed ? SimObjectId(jetEmitter[j]) : jetEmitter[j]->getId();
stream->writeRangedU32(writtenId, DataBlockObjectIdFirst,DataBlockObjectIdLast);
}
}
//** void HoverVehicleData::unpackData(BitStream* stream) **/
for (S32 j = 0; j < MaxJetEmitters; j++) {
jetEmitter[j] = NULL;
if (stream->readFlag())
jetEmitter[j] = (ParticleEmitterData*)stream->readRangedU32(DataBlockObjectIdFirst,
DataBlockObjectIdLast);
}
//** bool HoverVehicleData::preload(bool server, char errorBuffer[256]) **/
if (!server)
{
for (S32 j = 0; j < MaxJetEmitters; j++)
if (jetEmitter[j])
Sim::findObject(SimObjectId(jetEmitter[j]),jetEmitter[j]);//
};
jetNode[0] = shape->findNode("jetex");
jetNode[1] = shape->findNode("jetexb");
jetNode[2] = shape->findNode("jetexa");
// you can also pass an array of char strings
// for (S32 j = 0; j < MaxJetNodes; j++){
// jetNode[j] = shape->findNode(sJetNode[j]);
// where sJetNode[j] stores the names ("jetex", "jetexb", "jetexa")
//** void HoverVehicle::updateJet(F32 dt) **//
if(mThrustDirection == ThrustForward){ //This checks if person is holding W key down
for (S32 j = 0; j < MaxJetEmitter; j++)
updateEmitter(true,dt,mDataBlock->jetEmitter[j],j);
}
else{
updateEmitter(false,dt,mDataBlock->jetEmitter[0],0); //0,2
//** The entire function is below **//
HoverVehicle::updateEmitter(bool active,F32 dt,ParticleEmitterData *emitter,S32 k)
{
if (active)
{
if (!bool(mJetEmitter[k]) )
{
mJetEmitter[k] = new ParticleEmitter;
mJetEmitter[k]->onNewDataBlock(emitter);
mJetEmitter[k]->registerObject();
}
MatrixF mat;
Point3F pos,axis;
mat.mul(getRenderTransform(),
mShapeInstance->mNodeTransforms[mDataBlock->jetNode[k]]);
mat.getColumn(1,&axis);
mat.getColumn(3,&pos);
mJetEmitter[k]->emitParticles(pos,true,axis,getVelocity(),(U32)(dt*1000));
}
else
{
for (S32 j = 0; j < 3; j++)
{
if (bool(mJetEmitter[j]))
{
mJetEmitter[j]->deleteWhenEmpty();
mJetEmitter[j] = 0;
}
}
}
}
//********************** END OF CODE*******************//
Documentation
We start with hoverVehicle.h. It is the header file of the shape we are going to be adding nodes and emitters to. Here the enumerations of the maxNumber of nodes and Emitters are stored. Also arrays that will contain or point to the nodes/Emitters are also created.
//** HoverVehicleData::HoverVehicleData()**/
Inside the constructor we want to initialize our array of nodes/emitters to -1/0 respectively.
//** void HoverVehicleData::initPersistFields()**/
Inside initPersistFields we fill jetEmitter[] with pointers jetEmitterData that are defined in script.
//** void HoverVehicleData::packData(BitStream* stream) **/
//** void HoverVehicleData::unpackData(BitStream* stream) **/
both are just for sending/recieving information about hoverVehicle Objects and how to handle it. It is important to make sure that it is done in the correct order (the same as you put it in initPersistFields(), you can just look at any source code for examples of how to do this).
//** bool HoverVehicleData::preload(bool server, char errorBuffer[256]) **/
If not server then it set's up the jetEmitters. It also fills jetNode[] with the correct node as it appears in the .dts file. I used the explicit name - findNode("jetex"); - instead of using an array of characters.
//** void HoverVehicle::updateJet(F32 dt) **//
This could be a plain update method but hovervehicles have a specific method for Jets so I decided to put the update here. You could use any if statement to decide whether to emit or not. I use
if(mThrustDirection == ThrustForward) because I want my nodes to emit particles when it is thrusting forward. If it is thrusting forward then it update's that emitter with true set. If it is not I used a shortcut and just send one message to turn them all off.
//** HoverVehicle::updateEmitter(bool active,F32 dt,ParticleEmitterData *emitter,S32 k)
There are two main branches of this method. Turning on the particle emitter or turning the particle emitter off. If it is being turned on it checks if there is a mJetEmitter[k] corresponding to k. If not it creates a new one. Then the position and axis of the node are extrapolated. Then it tells the emitter to emit particles with that data.
If it is being turned off it simply turns off the emitter once it is empty.
That is the basics to mounting a particle emitter to a node in your .dts file. While my example is for hoverVehicle it should be applicable to many things.

Sailendu Behera