From Martin Scheffler, "osgParticle: method to set start and end tile for particle texture (for animated particles). I also updated examples/osgParticle to show the feature.
The texture in data/Images should be copied to osg-data. I created the texture myself with the help of an explosion generator, so no license issues there. "
This commit is contained in:
parent
f79f465467
commit
a3adc3d07c
@ -323,6 +323,121 @@ osgParticle::ParticleSystem *create_complex_particle_system(osg::Group *root)
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ANIMATED PARTICLE SYSTEM CREATION
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
osgParticle::ParticleSystem *create_animated_particle_system(osg::Group *root)
|
||||
{
|
||||
|
||||
// Now we will create a particle system that uses two emitters to
|
||||
// display two animated particles, one showing an explosion, the other
|
||||
// a smoke cloud. A particle system can only use one texture, so
|
||||
// the animations for both particles are stored in a single bitmap.
|
||||
// The frames of the animation are stored in tiles. For each particle
|
||||
// template, the start and end tile of their animation have to be given.
|
||||
// The example file used here has 64 tiles, stored in eight rows with
|
||||
// eight images each.
|
||||
|
||||
// First create a prototype for the explosion particle.
|
||||
osgParticle::Particle pexplosion;
|
||||
|
||||
// The frames of the explosion particle are played from birth to
|
||||
// death of the particle. So if lifetime is one second, all 16 images
|
||||
// of the particle are shown in this second.
|
||||
pexplosion.setLifeTime(1);
|
||||
|
||||
// some other particle properties just as in the last example.
|
||||
pexplosion.setSizeRange(osgParticle::rangef(0.75f, 3.0f));
|
||||
pexplosion.setAlphaRange(osgParticle::rangef(0.5f, 1.0f));
|
||||
pexplosion.setColorRange(osgParticle::rangev4(
|
||||
osg::Vec4(1, 1, 1, 1),
|
||||
osg::Vec4(1, 1, 1, 1)));
|
||||
pexplosion.setRadius(0.05f);
|
||||
pexplosion.setMass(0.05f);
|
||||
|
||||
// This command sets the animation tiles to be shown for the particle.
|
||||
// The first two parameters define the tile layout of the texture image.
|
||||
// 8, 8 means the texture has eight rows of tiles with eight columns each.
|
||||
// 0, 15 defines the start and end tile
|
||||
pexplosion.setTextureTileRange(8, 8, 0, 15);
|
||||
|
||||
// The smoke particle is just the same, only plays another tile range.
|
||||
osgParticle::Particle psmoke = pexplosion;
|
||||
psmoke.setTextureTileRange(8, 8, 32, 45);
|
||||
|
||||
// Create a single particle system for both particle types
|
||||
osgParticle::ParticleSystem *ps = new osgParticle::ParticleSystem;
|
||||
|
||||
// Assign the tiled texture
|
||||
ps->setDefaultAttributes("Images/fireparticle8x8.png", false, false);
|
||||
|
||||
// Create two emitters, one for the explosions, one for the smoke balls.
|
||||
osgParticle::ModularEmitter *emitter1 = new osgParticle::ModularEmitter;
|
||||
emitter1->setParticleSystem(ps);
|
||||
emitter1->setParticleTemplate(pexplosion);
|
||||
|
||||
osgParticle::ModularEmitter *emitter2 = new osgParticle::ModularEmitter;
|
||||
emitter2->setParticleSystem(ps);
|
||||
emitter2->setParticleTemplate(psmoke);
|
||||
|
||||
// create a counter each. We could reuse the counter for both emitters, but
|
||||
// then we could not control the ratio of smoke balls to explosions
|
||||
osgParticle::RandomRateCounter *counter1 = new osgParticle::RandomRateCounter;
|
||||
counter1->setRateRange(10, 10);
|
||||
emitter1->setCounter(counter1);
|
||||
|
||||
osgParticle::RandomRateCounter *counter2 = new osgParticle::RandomRateCounter;
|
||||
counter2->setRateRange(3, 4);
|
||||
emitter2->setCounter(counter2);
|
||||
|
||||
// setup a single placer for both emitters.
|
||||
osgParticle::SectorPlacer *placer = new osgParticle::SectorPlacer;
|
||||
placer->setCenter(-8, 0, 0);
|
||||
placer->setRadiusRange(2.5, 5);
|
||||
placer->setPhiRange(0, 2 * osg::PI); // 360° angle to make a circle
|
||||
emitter1->setPlacer(placer);
|
||||
emitter2->setPlacer(placer);
|
||||
|
||||
// the shooter is reused for both emitters
|
||||
osgParticle::RadialShooter *shooter = new osgParticle::RadialShooter;
|
||||
shooter->setInitialSpeedRange(0, 0);
|
||||
|
||||
// give particles a little spin
|
||||
shooter->setInitialRotationalSpeedRange(osgParticle::rangev3(
|
||||
osg::Vec3(0, 0, -1),
|
||||
osg::Vec3(0, 0, 1)));
|
||||
emitter1->setShooter(shooter);
|
||||
emitter2->setShooter(shooter);
|
||||
|
||||
// add both emitters to the scene graph
|
||||
root->addChild(emitter1);
|
||||
root->addChild(emitter2);
|
||||
|
||||
// create a program, just as before
|
||||
osgParticle::ModularProgram *program = new osgParticle::ModularProgram;
|
||||
program->setParticleSystem(ps);
|
||||
|
||||
// create an operator that moves the particles upwards
|
||||
osgParticle::AccelOperator *op1 = new osgParticle::AccelOperator;
|
||||
op1->setAcceleration(osg::Vec3(0, 0, 2.0f));
|
||||
program->addOperator(op1);
|
||||
|
||||
// add the program to the scene graph
|
||||
root->addChild(program);
|
||||
|
||||
// create a Geode to contain our particle system.
|
||||
osg::Geode *geode = new osg::Geode;
|
||||
geode->addDrawable(ps);
|
||||
|
||||
// add the geode to the scene graph.
|
||||
root->addChild(geode);
|
||||
|
||||
return ps;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// MAIN SCENE GRAPH BUILDING FUNCTION
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@ -341,6 +456,7 @@ void build_world(osg::Group *root)
|
||||
|
||||
osgParticle::ParticleSystem *ps1 = create_simple_particle_system(root);
|
||||
osgParticle::ParticleSystem *ps2 = create_complex_particle_system(root);
|
||||
osgParticle::ParticleSystem *ps3 = create_animated_particle_system(root);
|
||||
|
||||
// Now that the particle systems and all other related objects have been
|
||||
// created, we have to add an "updater" node to the scene graph. This node
|
||||
@ -349,6 +465,7 @@ void build_world(osg::Group *root)
|
||||
osgParticle::ParticleSystemUpdater *psu = new osgParticle::ParticleSystemUpdater;
|
||||
psu->addParticleSystem(ps1);
|
||||
psu->addParticleSystem(ps2);
|
||||
psu->addParticleSystem(ps3);
|
||||
|
||||
// add the updater node to the scene graph
|
||||
root->addChild(psu);
|
||||
|
@ -154,7 +154,7 @@ namespace osgParticle
|
||||
inline int getTileT() const;
|
||||
|
||||
/// Get number of texture tiles
|
||||
inline int getNumTiles() const { return _num_tile; }
|
||||
inline int getNumTiles() const { return _end_tile - _start_tile + 1; }
|
||||
|
||||
/** Kill the particle on next update
|
||||
NOTE: after calling this function, the <CODE>isAlive()</CODE> method will still
|
||||
@ -246,8 +246,13 @@ namespace osgParticle
|
||||
/// Get the current (interpolated) polygon size. Valid only after the first call to update().
|
||||
inline float getCurrentSize() const;
|
||||
|
||||
/// Specify how the particle texture is tiled
|
||||
inline void setTextureTile(int sTile, int tTile, int numTiles = 0);
|
||||
/// Specify how the particle texture is tiled.
|
||||
/// All tiles in the given range are sequentially displayed during the lifetime
|
||||
/// of the particle. When no range is given, all tiles are displayed during the lifetime.
|
||||
inline void setTextureTileRange(int sTile, int tTile, int startTile, int endTile);
|
||||
|
||||
/// Same as above, range starts at 0 and ends at end
|
||||
inline void setTextureTile(int sTile, int tTile, int end = -1);
|
||||
|
||||
/// Set the previous particle
|
||||
inline void setPreviousParticle(int previous) { _previousParticle = previous; }
|
||||
@ -299,7 +304,8 @@ namespace osgParticle
|
||||
|
||||
float _s_tile;
|
||||
float _t_tile;
|
||||
int _num_tile;
|
||||
int _start_tile;
|
||||
int _end_tile;
|
||||
int _cur_tile;
|
||||
float _s_coord;
|
||||
float _t_coord;
|
||||
@ -566,20 +572,35 @@ namespace osgParticle
|
||||
return _current_size;
|
||||
}
|
||||
|
||||
inline void Particle::setTextureTile(int sTile, int tTile, int numTiles)
|
||||
|
||||
inline void Particle::setTextureTile(int sTile, int tTile, int end)
|
||||
{
|
||||
_s_tile = (sTile>0) ? 1.0f / static_cast<float>(sTile) : 1.0f;
|
||||
_t_tile = (tTile>0) ? 1.0f / static_cast<float>(tTile) : 1.0f;
|
||||
if (numTiles <= 0)
|
||||
{
|
||||
_num_tile = sTile * tTile;
|
||||
}
|
||||
else
|
||||
{
|
||||
_num_tile = numTiles;
|
||||
}
|
||||
setTextureTileRange(sTile, tTile, -1, end);
|
||||
}
|
||||
|
||||
inline void Particle::setTextureTileRange(int sTile, int tTile, int startTile, int endTile)
|
||||
{
|
||||
_s_tile = (sTile>0) ? 1.0f / static_cast<float>(sTile) : 1.0f;
|
||||
_t_tile = (tTile>0) ? 1.0f / static_cast<float>(tTile) : 1.0f;
|
||||
|
||||
if(startTile == -1)
|
||||
{
|
||||
_start_tile = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_start_tile = startTile;
|
||||
}
|
||||
|
||||
if(endTile == -1)
|
||||
{
|
||||
_end_tile = sTile * tTile;
|
||||
}
|
||||
else
|
||||
{
|
||||
_end_tile = endTile;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,8 @@ osgParticle::Particle::Particle()
|
||||
_current_alpha(0),
|
||||
_s_tile(1.0f),
|
||||
_t_tile(1.0f),
|
||||
_num_tile(1),
|
||||
_start_tile(0),
|
||||
_end_tile(0),
|
||||
_cur_tile(-1),
|
||||
_s_coord(0.0f),
|
||||
_t_coord(0.0f),
|
||||
@ -79,7 +80,7 @@ bool osgParticle::Particle::update(double dt)
|
||||
}
|
||||
|
||||
//Compute the current texture tile based on our normalized age
|
||||
int currentTile = static_cast<int>(x * _num_tile);
|
||||
int currentTile = _start_tile + static_cast<int>(x * getNumTiles());
|
||||
|
||||
//If the current texture tile is different from previous, then compute new texture coords
|
||||
if(currentTile != _cur_tile)
|
||||
|
Loading…
Reference in New Issue
Block a user