Page 1 of 2
modification for particles system
Posted: Fri Aug 20, 2004 7:02 pm
by calimero
here is my proposal (as small as possible) to change the behaviour of the particules : as soon as they are emitted they are computed in world coordinates and not in local system node coordinates. The effect is quite pretty with a moving particles system node (like circle animator).
I know other people have made proposal to do the same but I think this method is the simplest and doesn't alter performances.
here is an example of the changed system particle rotating around a character (with circleanimator)
the only changes are in the CParticleSystemNode.cpp file
there is 2 places to updates (one to declare an identity matrix for rendering particle instead of local matrix of the system node and the other to update particle position in world coordinates after creation):
one side effect is that you lost the ability to scale the whole system with the methods setScale() but I think that a minor drawback.
* in the render method
Code: Select all
// render all
core::matrix4 matid;
driver->setTransform(video::ETS_WORLD, matid);
instead of the old setTransform line
and in the doParticleSystem(u32 time) method
replace the // run emitter paragraph with this one :
Code: Select all
// run emitter
if (Emitter)
{
SParticle* array = 0;
s32 newParticles = Emitter->emitt(now, timediff, array);
core::vector3df absolutepos = getAbsolutePosition();
if (newParticles && array)
for (s32 i=0; i<newParticles && Particles.size() < 16250; ++i)
{
array[i].pos = absolutepos;
Particles.push_back(array[i]);
}
}
Posted: Sat Aug 21, 2004 12:13 pm
by Electron
sweet pics, and I like your idea.
Posted: Sun Aug 22, 2004 4:10 am
by Guest
nice pic!
Posted: Wed Aug 25, 2004 7:13 am
by niko
Yep, I think your modification makes sence. Maybe it would be a good idea to add an option for making it behave the old way with relative coordinates, but I'm not sure.
Posted: Wed Aug 25, 2004 9:24 am
by calimero
niko,
we discuss that on irrlivhtnx forum with jox. Probably the good way is to put a bool like particleGlobal set to false by default in the constructor and add a method like setparticleGlobal.
Another setting may be to preserve the "local" emitter vector because with my patch I think all parameters become global
so we have have
3 settings :
* legacy mode (like now)
* full global (like my current patch)
* emitter vector local but all others effects global.
Posted: Wed Aug 25, 2004 12:36 pm
by Electron
Yeah, there could be cases when one would want to keep the particles together
new proposal
Posted: Wed Aug 25, 2004 2:11 pm
by calimero
ok, I made some test with a local emitter vector with global particles.
I'm not sure how to interface it properly.
but I suppose I have 2 booleans :
bool isParticleGlobal;
bool isEmitterVecGlobal;
if isParticleGlobal=false we have legacy mode (the other bool doesn't matter)
if isParticleGlobal=true :
the particle are computed in world coordinates.
if isEmitterVecGlobal=true then the emitter vector is expressed in world coordinates elsewhere it's expressed in particleSystemNode coordinates.
ok then the code (only the cpp file):
in the render method :
Code: Select all
// render all
if (isParticleGlobal)
{
core::matrix4 matid;
driver->setTransform(video::ETS_WORLD, matid);
}
else driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
in the doParticleSystem(u32 time) method :
Code: Select all
// run emitter
if (Emitter)
{
SParticle* array = 0;
s32 newParticles = Emitter->emitt(now, timediff, array);
core::vector3df absolutepos = getAbsolutePosition();
if (newParticles && array)
for (s32 i=0; i<newParticles && Particles.size() < 16250; ++i)
{
if (isParticleGlobal && (!isEmitterVecGlobal)) getAbsoluteTransformation().rotateVect(array[i].startVector);
if (isParticleGlobal) array[i].pos = absolutepos;
Particles.push_back(array[i]);
}
}
hope it works well.
I need help to implement a proper interface to set the booleans (in the constructor or via additional methods ?)
Posted: Wed Aug 25, 2004 3:14 pm
by Guest
I opt for both, constructor and methods
Posted: Thu Aug 26, 2004 12:54 pm
by jox
Well, how about 3 modes as an enum? Than it's one parameter.
scene::EPSM_LOCAL
scene::EPSM_GLOBAL
scene::EPSM_GLOBAL_EMITTER_LOCAL
(EPSM = enum particle system mode)
Anybody has proposals for better names?
What should be default? Normaly it would be scene::EPSM_LOCAL.
Posted: Thu Aug 26, 2004 2:18 pm
by jox
Ok i've implemented it!
I'm not sure about the EPSM_GLOBAL_EMITTER_LOCAL
I tested it with the special effects example by adding the flyCircleAnimator of the billboard to the particle system.
With EPSM_LOCAL it looks like this:
(original irrlicht behaviour)
With EPSM_GLOBAL it's looks this cool
But with with EPSM_GLOBAL_EMITTER_LOCAL the particles are a bit outta space...
Is it normal?
position and rotation are both (0,0,0)
So is this code correct?
Code: Select all
getAbsoluteTransformation().rotateVect(array[i].startVector);
Posted: Thu Aug 26, 2004 2:39 pm
by calimero
hello jox thanks a lot for doing the integration job !!!
for the last setting I'm surprised normally I've seen that circle animator move the object but doesn't rotate it so normally you may have had the same result as full global. maybe I misunderstood what the startvector is for Sparticle ? I have made just one test on my side and it seemed to work well but I will look at this.
jox can you try to set a particle emitter with a null emitter vector and then test it with the last 2 modes, normally you wouldn't see any differences.
p.s. i'm not sure but it may be a problem with the bouding box of the node, I don't care of it but with the modification it may be no correctly updated anymore. I say that because I experiment some strange clipping sometimes.
Posted: Thu Aug 26, 2004 3:55 pm
by jox
Sorry, forget screenshot #3 and the EPSM_GLOBAL_EMITTER_LOCAL thing. I did a mistake.
But another thing: how can I test the difference between EPSM_GLOBAL_EMITTER_LOCAL and EPSM_GLOBAL. I always get the same results. Any particle setup code example(s)?
Posted: Thu Aug 26, 2004 7:34 pm
by calimero
hello jox,
you will see a difference if the orientation of the particle system node is different from world orientation.
here is an example (direct copy paste from my code):
Code: Select all
scene::IParticleSystemSceneNode* ps = 0;
ps = smgr->addParticleSystemSceneNode(false,(ISceneNode*)((*(++listCar.begin()))->getNode())); // you can attach it directly to rootscenenode
//ps->setPosition(core::vector3df(50,50,50));
//ps->setScale(core::vector3df(2,2,2));
ps->setParticleSize(core::dimension2d<f32>(20.0f, 20.0f));
scene::IParticleEmitter* em = ps->createBoxEmitter(
core::aabbox3d<f32>(-7,0,-7,7,1,7),
core::vector3df(0.1f,0.01f,0.0f), // here is the emitter vector
50,100,
video::SColor(0,255,255,255), video::SColor(0,255,255,255),
500,1000,5);
ps->setParticleSize(core::dimension2d<f32>(10,10));
ps->setEmitter(em);
em->drop();
scene::IParticleAffector* paf = ps->createFadeOutParticleAffector(video::SColor(0,0,0,0),500);
ps->addAffector(paf);
paf->drop();
vector3df v1 = vector3df(0.0f,0.1f,0.0f);
vector3df v2 = -v1;
paf = ps->createGravityAffector(v1);
ps->addAffector(paf);
paf->drop();
ps->setMaterialFlag(video::EMF_LIGHTING, false);
ps->setMaterialTexture(0, driver->getTexture("C:/irrlicht/media/particle.bmp"));
ps->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
//anim = smgr->createFlyCircleAnimator(vector3df(0,20,0),30,0.003f);
anim = smgr->createRotationAnimator(vector3df(0,0.8f,0));
ps->addAnimator(anim);
anim->drop();
with code like that you'll see the difference.
last thing : I use a little optimization in my systemparticle code (in the render method) :
Code: Select all
core::vector3df v0 = horizontal + vertical;
core::vector3df v1 = horizontal - vertical;
// reallocate arrays, if they are too small
reallocateBuffers();
// create particle vertex data
s32 idx = 0;
for (u32 i=0; i<Particles.size(); ++i)
{
SParticle& particle = Particles[i];
Vertices[idx].Pos = particle.pos + v0;
Vertices[idx].Color = particle.color;
Vertices[idx].Normal = view;
idx++;
Vertices[idx].Pos = particle.pos + v1;
Vertices[idx].Color = particle.color;
Vertices[idx].Normal = view;
idx++;
Vertices[idx].Pos = particle.pos - v0;
Vertices[idx].Color = particle.color;
Vertices[idx].Normal = view;
idx++;
Vertices[idx].Pos = particle.pos - v1;
Vertices[idx].Color = particle.color;
Vertices[idx].Normal = view;
idx++;
}
the benefits are the suppression of 4 vector additions per particle(for calculation of particles position and the suppression of multiplications to calculate indices of particles.
I'm using theses little optimizations for a long time now and haven't exprimented any problems
Posted: Thu Aug 26, 2004 10:38 pm
by jox
Thanx calimero! I added it now to the IrrlichtNX CVS!
http://www.irrlichtnx.mmdevel.de/phpBB2 ... .php?p=482
I also included your optimization.
patch of the patch
Posted: Fri Aug 27, 2004 4:48 pm
by calimero
sorry jox for discovering the problem just now but the modes "global" don't respect the box emitters.
we have to make this slight modification :
Code: Select all
void CParticleSystemSceneNode::doParticleSystem(u32 time)
{
u32 now = os::Timer::getTime();
u32 timediff = now - lastEmitTime;
lastEmitTime = now;
// run emitter
// jox: changed for particle system global patch by calimero
if (Emitter)
{
SParticle* array = 0;
s32 newParticles = Emitter->emitt(now, timediff, array);
if (newParticles && array) {
core::matrix4 absolutetransf = getAbsoluteTransformation();
for (s32 i=0; i<newParticles && Particles.size() < 16250; ++i) {
if (Mode == EPSM_GLOBAL_EMITTER_LOCAL)
absolutetransf.rotateVect(array[i].startVector);
if (Mode != EPSM_LOCAL)
absolutetransf.transformVect(array[i].pos); // here is the important line to change
Particles.push_back(array[i]);
}
}
}
i also implement a new mode (EPSM_GLOBAL_AXIALBILLBOARD) with axial billboard instead of standard billboard (nice for making rain) but take it like a
beta version and as usual it lacks for interface to set the width and the orientation vector of the axialbillboard
if you are interested here is the code :
Code: Select all
//! render
// jox: changed for particle system global patch by calimero
void CParticleSystemSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
ICameraSceneNode* camera = SceneManager->getActiveCamera();
if (!camera || !driver)
return;
// reallocate arrays, if they are too small
reallocateBuffers();
// calculate vectors for letting particles look to camera
core::vector3df pos = getAbsolutePosition();
core::vector3df campos = camera->getAbsolutePosition();
if (Mode==EPSM_GLOBAL_AXIALBILLBOARD)
{
Material.BackfaceCulling = false;
// as you can see here I set directly the values
f32 width = 0.3f;
core::vector3df orientation = core::vector3df(0,-15,0);
s32 idx = 0;
for (u32 i=0; i<Particles.size(); ++i)
{
SParticle& particle = Particles[i];
pos = particle.pos;
core::vector3df perp = orientation.crossProduct(campos - pos);
perp.setLength(width);
// update normals of the node
core::vector3df norm = (orientation).crossProduct(perp);
norm.normalize();
Vertices[idx].Pos = pos + perp;
Vertices[idx].Color = particle.color;
Vertices[idx].Normal = norm;
idx++;
Vertices[idx].Pos = pos + orientation + perp;
Vertices[idx].Color = particle.color;
Vertices[idx].Normal = norm;
idx++;
Vertices[idx].Pos = pos + orientation - perp;
Vertices[idx].Color = particle.color;
Vertices[idx].Normal = norm;
idx++;
Vertices[idx].Pos = pos - perp;
Vertices[idx].Color = particle.color;
Vertices[idx].Normal = norm;
idx++;
}
}
else
{
core::vector3df target = camera->getTarget();
core::vector3df up = camera->getUpVector();
core::vector3df view = target - campos;
view.normalize();
core::vector3df horizontal = up.crossProduct(view);
horizontal.normalize();
core::vector3df vertical = horizontal.crossProduct(view);
vertical.normalize();
horizontal *= 0.5f * ParticleSize.Width;
vertical *= 0.5f * ParticleSize.Height;
view *= -1.0f;
core::vector3df v0 = horizontal + vertical;
core::vector3df v1 = horizontal - vertical;
// create particle vertex data
s32 idx = 0;
for (u32 i=0; i<Particles.size(); ++i)
{
SParticle& particle = Particles[i];
Vertices[idx].Pos = particle.pos + v0;
Vertices[idx].Color = particle.color;
Vertices[idx].Normal = view;
idx++;
Vertices[idx].Pos = particle.pos + v1;
Vertices[idx].Color = particle.color;
Vertices[idx].Normal = view;
idx++;
Vertices[idx].Pos = particle.pos - v0;
Vertices[idx].Color = particle.color;
Vertices[idx].Normal = view;
idx++;
Vertices[idx].Pos = particle.pos - v1;
Vertices[idx].Color = particle.color;
Vertices[idx].Normal = view;
idx++;
}
}
// render all
if (Mode != EPSM_LOCAL)
{
core::matrix4 matid;
driver->setTransform(video::ETS_WORLD, matid);
}
else driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
driver->setMaterial(Material);
driver->drawIndexedTriangleList(Vertices.pointer(), Particles.size()*4,
Indices.pointer(), Particles.size()*2);
// for debug purposes only:
if (DebugDataVisible)
{
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
driver->draw3DBox(Box, video::SColor(0,255,255,255));
}
}