More behavior control for particles:

- ParticleSystemSceneNode does now affect the particle movement direction by default. Can be disabled to get old behavior.
- Allow interpolating postions which is useful when particles are attached to fast-moving nodes (to avoid regular patterns).
- Invisible behavior flags from check-in yesterday re-implemented with new general behavior flags.


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@4770 dfc29bdd-3216-0410-991c-e03cc46cb475
master
cutealien 2014-04-10 18:44:49 +00:00
parent ca6029b564
commit 322b1abef1
4 changed files with 92 additions and 33 deletions

View File

@ -1,7 +1,7 @@
--------------------------
Changes in 1.9 (not yet released)
- Allow more control over particle behavior when the ParticleSystemSceneNode is invisible.
- Allow more control over particle behavior. This also changed the default behavior.
- ISceneNodeAnimators can now be disabled and paused.
- Maya camera no longer get's stuck in "rotating" state when a mouse-up event is lost (thx @ JLouisB for reporting).
- Focus behavior of IGUIEnvironment now controllable (right-click focus, mouse-over focus). Disabled elements no longer get the focus unless users enforce it.

View File

@ -43,17 +43,29 @@ You can for example easily create a campfire by doing this:
\endcode
*/
//! Bitflags to control particle behavior when the IParticleSystemSceneNode is invisible
enum EParticleInvisible
//! Bitflags to control particle behavior
enum EParticleBehavior
{
//! Stop emitting new particles when invisible
EPI_STOP_EMITTERS = 1,
//! No longer affect particles when invisible
EPI_STOP_AFFECTORS = 2,
//! Stop updating particle positions or deleting them when invisible
EPI_STOP_ANIMATING = 4,
//! Continue emitting new particles even when the node is invisible
EPB_INVISIBLE_EMITTING = 1,
//! Continue affecting particles even when the node is invisible
EPB_INVISIBLE_AFFECTING = 2,
//! Continue updating particle positions or deleting them even when the node is invisible
EPB_INVISIBLE_ANIMATING = 4,
//! Clear all particles when node gets invisible
EPI_CLEAR_ON_INVISIBLE = 8
EPB_CLEAR_ON_INVISIBLE = 8,
//! Particle movement direction on emitting ignores the node rotation
//! This is mainly to allow backward compatible behavior to Irrlicht 1.8
EPB_EMITTER_VECTOR_IGNORE_ROTATION = 16,
//! On emitting global particles interpolate the positions randomly between the last and current node transformations.
//! This can be set to avoid gaps caused by fast node movement or low framerates, but will be somewhat
//! slower to calculate.
EPB_EMITTER_FRAME_INTERPOLATION = 32
};
class IParticleSystemSceneNode : public ISceneNode
@ -66,7 +78,7 @@ public:
const core::vector3df& rotation = core::vector3df(0,0,0),
const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f))
: ISceneNode(parent, mgr, id, position, rotation, scale)
, ParticleInvisibleBehavior(EPI_STOP_EMITTERS|EPI_STOP_AFFECTORS|EPI_STOP_ANIMATING|EPI_CLEAR_ON_INVISIBLE)
, ParticleBehavior(0)
{
}
@ -80,22 +92,22 @@ public:
Default is true. */
virtual void setParticlesAreGlobal(bool global=true) = 0;
//! Sets how particles behave when this node is invisible
/** Default is: EPIB_STOP_EMITTERS|EPIB_STOP_AFFECTORS|EPIB_STOP_ANIMATING|EPI_CLEAR_ON_INVISIBLE
\param flags Any combination of ::EParticleInvisibleBehavior flags
*/
virtual void setInvisibleBehavior(irr::u32 flags)
//! Bitflags to change the particle behavior
/**
\param flags A combination of ::EParticleBehavior bit-flags. Default is 0. */
virtual void setParticleBehavior(irr::u32 flags)
{
ParticleInvisibleBehavior = flags;
ParticleBehavior = flags;
}
//! Gets how particles behave when this node is invisible
//! Gets how particles behave in different situations
/**
\return A combination of ::EParticleInvisibleBehavior flags
*/
virtual irr::u32 getInvisibleBehavior() const
\return A combination of ::EParticleBehavior flags */
virtual irr::u32 getParticleBehavior() const
{
return ParticleInvisibleBehavior;
return ParticleBehavior;
}
//! Remove all currently visible particles
@ -541,17 +553,17 @@ public:
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_
{
out->addInt("ParticleInvisibleBehavior", ParticleInvisibleBehavior);
out->addInt("ParticleBehavior", ParticleBehavior);
}
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_
{
ParticleInvisibleBehavior = in->getAttributeAsInt("ParticleInvisibleBehavior", ParticleInvisibleBehavior);
ParticleBehavior = in->getAttributeAsInt("ParticleBehavior", ParticleBehavior);
}
protected:
s32 ParticleInvisibleBehavior;
s32 ParticleBehavior;
};
} // end namespace scene

View File

@ -410,6 +410,7 @@ void CParticleSystemSceneNode::doParticleSystem(u32 time)
if (LastEmitTime==0)
{
LastEmitTime = time;
LastAbsoluteTransformation = AbsoluteTransformation;
return;
}
@ -418,10 +419,11 @@ void CParticleSystemSceneNode::doParticleSystem(u32 time)
LastEmitTime = time;
int stop = isVisible() ? 0 : getInvisibleBehavior();
bool visible = isVisible();
int behavior = getParticleBehavior();
// run emitter
if (Emitter && !(stop & EPI_STOP_EMITTERS) )
if (Emitter && (visible || behavior & EPB_INVISIBLE_EMITTING) )
{
SParticle* array = 0;
s32 newParticles = Emitter->emitt(now, timediff, array);
@ -435,15 +437,54 @@ void CParticleSystemSceneNode::doParticleSystem(u32 time)
for (s32 i=j; i<j+newParticles; ++i)
{
Particles[i]=array[i-j];
AbsoluteTransformation.rotateVect(Particles[i].startVector);
if (ParticlesAreGlobal)
AbsoluteTransformation.transformVect(Particles[i].pos);
if ( ParticlesAreGlobal && behavior & EPB_EMITTER_FRAME_INTERPOLATION )
{
// Interpolate between current node transformations and last ones.
// (Lazy solution - calculating twice and interpolating results)
f32 randInterpolate = (f32)(os::Randomizer::rand() % 101) / 100.f; // 0 to 1
core::vector3df posNow(Particles[i].pos);
core::vector3df posLast(Particles[i].pos);
AbsoluteTransformation.transformVect(posNow);
LastAbsoluteTransformation.transformVect(posLast);
Particles[i].pos = posNow.getInterpolated(posLast, randInterpolate);
if ( !(behavior & EPB_EMITTER_VECTOR_IGNORE_ROTATION) )
{
core::vector3df vecNow(Particles[i].startVector);
core::vector3df vecOld(Particles[i].startVector);
AbsoluteTransformation.rotateVect(vecNow);
LastAbsoluteTransformation.rotateVect(vecOld);
Particles[i].startVector = vecNow.getInterpolated(vecOld, randInterpolate);
vecNow = Particles[i].vector;
vecOld = Particles[i].vector;
AbsoluteTransformation.rotateVect(vecNow);
LastAbsoluteTransformation.rotateVect(vecOld);
Particles[i].vector = vecNow.getInterpolated(vecOld, randInterpolate);
}
}
else
{
if (ParticlesAreGlobal)
AbsoluteTransformation.transformVect(Particles[i].pos);
if ( !(behavior & EPB_EMITTER_VECTOR_IGNORE_ROTATION) )
{
if (!ParticlesAreGlobal)
AbsoluteTransformation.rotateVect(Particles[i].pos);
AbsoluteTransformation.rotateVect(Particles[i].startVector);
AbsoluteTransformation.rotateVect(Particles[i].vector);
}
}
}
}
}
// run affectors
if ( !(stop & EPI_STOP_AFFECTORS) )
if ( visible || behavior & EPB_INVISIBLE_AFFECTING )
{
core::list<IParticleAffector*>::Iterator ait = AffectorList.begin();
for (; ait != AffectorList.end(); ++ait)
@ -456,7 +497,7 @@ void CParticleSystemSceneNode::doParticleSystem(u32 time)
Buffer->BoundingBox.reset(core::vector3df(0,0,0));
// animate all particles
if ( !(stop & EPI_STOP_ANIMATING) )
if ( visible || behavior & EPB_INVISIBLE_ANIMATING )
{
f32 scale = (f32)timediff;
@ -495,6 +536,8 @@ void CParticleSystemSceneNode::doParticleSystem(u32 time)
core::matrix4 absinv( AbsoluteTransformation, core::matrix4::EM4CONST_INVERSE );
absinv.transformBoxEx(Buffer->BoundingBox);
}
LastAbsoluteTransformation = AbsoluteTransformation;
}
@ -516,8 +559,11 @@ void CParticleSystemSceneNode::clearParticles()
void CParticleSystemSceneNode::setVisible(bool isVisible)
{
IParticleSystemSceneNode::setVisible(isVisible);
if ( !isVisible && getInvisibleBehavior() & EPI_CLEAR_ON_INVISIBLE )
if ( !isVisible && getParticleBehavior() & EPB_CLEAR_ON_INVISIBLE )
{
clearParticles();
LastEmitTime = 0;
}
}
//! Sets the size of all particles.

View File

@ -220,6 +220,7 @@ private:
core::array<SParticle> Particles;
core::dimension2d<f32> ParticleSize;
u32 LastEmitTime;
core::matrix4 LastAbsoluteTransformation;
SMeshBuffer* Buffer;