Added SmokeTrailEffect which renders created particles as single quad or line
strip, in the case of the quad strip the strip is aligned to the be orthogonal with the eye point.
This commit is contained in:
@@ -79,37 +79,8 @@ void CullStack::pushCullingSet()
|
||||
const osg::Viewport& W = *_viewportStack.back();
|
||||
const osg::Matrix& P = *_projectionStack.back();
|
||||
const osg::Matrix& M = *_modelviewStack.back();
|
||||
|
||||
// pre adjust P00,P20,P23,P33 by multiplying them by the viewport window matrix.
|
||||
// here we do it in short hand with the knowledge of how the window matrix is formed
|
||||
// note P23,P33 are multiplied by an implicit 1 which would come from the window matrix.
|
||||
// Robert Osfield, June 2002.
|
||||
|
||||
// scaling for horizontal pixels
|
||||
float P00 = P(0,0)*W.width()*0.5f;
|
||||
float P20_00 = P(2,0)*W.width()*0.5f + P(2,3)*W.width()*0.5f;
|
||||
osg::Vec3 scale_00(M(0,0)*P00 + M(0,2)*P20_00,
|
||||
M(1,0)*P00 + M(1,2)*P20_00,
|
||||
M(2,0)*P00 + M(2,2)*P20_00);
|
||||
|
||||
// scaling for vertical pixels
|
||||
float P10 = P(1,1)*W.height()*0.5f;
|
||||
float P20_10 = P(2,1)*W.height()*0.5f + P(2,3)*W.height()*0.5f;
|
||||
osg::Vec3 scale_10(M(0,1)*P10 + M(0,2)*P20_10,
|
||||
M(1,1)*P10 + M(1,2)*P20_10,
|
||||
M(2,1)*P10 + M(2,2)*P20_10);
|
||||
|
||||
float P23 = P(2,3);
|
||||
float P33 = P(3,3);
|
||||
osg::Vec4 pixelSizeVector(M(0,2)*P23,
|
||||
M(1,2)*P23,
|
||||
M(2,2)*P23,
|
||||
M(3,2)*P23 + M(3,3)*P33);
|
||||
|
||||
float scaleRatio = 0.7071067811f/sqrtf(scale_00.length2()+scale_10.length2());
|
||||
|
||||
pixelSizeVector *= scaleRatio;
|
||||
|
||||
osg::Vec4 pixelSizeVector = CullingSet::computePixelSizeVector(W,P,M);
|
||||
|
||||
if (_index_modelviewCullingStack>=_modelviewCullingStack.size())
|
||||
{
|
||||
|
||||
@@ -63,3 +63,37 @@ void CullingSet::popOccludersCurrentMask(NodePath& nodePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
osg::Vec4 CullingSet::computePixelSizeVector(const Viewport& W, const Matrix& P, const Matrix& M)
|
||||
{
|
||||
// pre adjust P00,P20,P23,P33 by multiplying them by the viewport window matrix.
|
||||
// here we do it in short hand with the knowledge of how the window matrix is formed
|
||||
// note P23,P33 are multiplied by an implicit 1 which would come from the window matrix.
|
||||
// Robert Osfield, June 2002.
|
||||
|
||||
// scaling for horizontal pixels
|
||||
float P00 = P(0,0)*W.width()*0.5f;
|
||||
float P20_00 = P(2,0)*W.width()*0.5f + P(2,3)*W.width()*0.5f;
|
||||
osg::Vec3 scale_00(M(0,0)*P00 + M(0,2)*P20_00,
|
||||
M(1,0)*P00 + M(1,2)*P20_00,
|
||||
M(2,0)*P00 + M(2,2)*P20_00);
|
||||
|
||||
// scaling for vertical pixels
|
||||
float P10 = P(1,1)*W.height()*0.5f;
|
||||
float P20_10 = P(2,1)*W.height()*0.5f + P(2,3)*W.height()*0.5f;
|
||||
osg::Vec3 scale_10(M(0,1)*P10 + M(0,2)*P20_10,
|
||||
M(1,1)*P10 + M(1,2)*P20_10,
|
||||
M(2,1)*P10 + M(2,2)*P20_10);
|
||||
|
||||
float P23 = P(2,3);
|
||||
float P33 = P(3,3);
|
||||
osg::Vec4 pixelSizeVector(M(0,2)*P23,
|
||||
M(1,2)*P23,
|
||||
M(2,2)*P23,
|
||||
M(3,2)*P23 + M(3,3)*P33);
|
||||
|
||||
float scaleRatio = 0.7071067811f/sqrtf(scale_00.length2()+scale_10.length2());
|
||||
pixelSizeVector *= scaleRatio;
|
||||
|
||||
return pixelSizeVector;
|
||||
}
|
||||
|
||||
@@ -12,24 +12,23 @@
|
||||
*/
|
||||
|
||||
#include <osg/Notify>
|
||||
#include <osg/CullingSet>
|
||||
#include <osg/io_utils>
|
||||
#include <osgParticle/ConnectedParticleSystem>
|
||||
|
||||
using namespace osgParticle;
|
||||
|
||||
ConnectedParticleSystem::ConnectedParticleSystem():
|
||||
_startParticle(0),
|
||||
_lastParticleCreated(0)
|
||||
_startParticle(Particle::INVALID_INDEX),
|
||||
_lastParticleCreated(Particle::INVALID_INDEX)
|
||||
{
|
||||
}
|
||||
|
||||
ConnectedParticleSystem::ConnectedParticleSystem(const ConnectedParticleSystem& copy, const osg::CopyOp& copyop):
|
||||
ParticleSystem(copy,copyop),
|
||||
_startParticle(0),
|
||||
_lastParticleCreated(0)
|
||||
_startParticle(copy._startParticle),
|
||||
_lastParticleCreated(copy._lastParticleCreated)
|
||||
{
|
||||
// need to think about how to copy _startParticle and _lastParticleCreated...
|
||||
// should we just use indices? Should we compute offsets into the particle system?
|
||||
osg::notify(osg::NOTICE)<<"Warning: ConnectedParticleSystem copy constructor incomplete."<<std::endl;
|
||||
}
|
||||
|
||||
ConnectedParticleSystem::~ConnectedParticleSystem()
|
||||
@@ -38,20 +37,184 @@ ConnectedParticleSystem::~ConnectedParticleSystem()
|
||||
|
||||
Particle* ConnectedParticleSystem::createParticle(const Particle* ptemplate)
|
||||
{
|
||||
return ParticleSystem::createParticle(ptemplate);
|
||||
// osg::notify(osg::NOTICE)<<this<< " Creating particle "<<std::endl;
|
||||
|
||||
Particle* particle = ParticleSystem::createParticle(ptemplate);
|
||||
int particleIndex = (int)(particle - &_particles[0]);
|
||||
|
||||
if (particle)
|
||||
{
|
||||
|
||||
if (_startParticle == Particle::INVALID_INDEX)
|
||||
{
|
||||
// we are the fisrt particle create, so start the connect particle list
|
||||
_startParticle = particleIndex;
|
||||
}
|
||||
|
||||
if (_lastParticleCreated != Particle::INVALID_INDEX)
|
||||
{
|
||||
// osg::notify(osg::NOTICE)<<this<< " Connecting "<<_lastParticleCreated<<" to "<<particleIndex<<std::endl;
|
||||
|
||||
// write up the last created particle to this new particle
|
||||
_particles[_lastParticleCreated].setNextParticle(particleIndex);
|
||||
particle->setPreviousParticle(_lastParticleCreated);
|
||||
}
|
||||
|
||||
// set the new particle as the last particle created.
|
||||
_lastParticleCreated = particleIndex;
|
||||
|
||||
}
|
||||
|
||||
return particle;
|
||||
}
|
||||
|
||||
void ConnectedParticleSystem::destroyParticle(int i)
|
||||
void ConnectedParticleSystem::reuseParticle(int particleIndex)
|
||||
{
|
||||
return ParticleSystem::destroyParticle(i);
|
||||
}
|
||||
|
||||
void ConnectedParticleSystem::update(double dt)
|
||||
{
|
||||
ParticleSystem::update(dt);
|
||||
// osg::notify(osg::NOTICE)<<this<< " Reusing particle "<<particleIndex<<std::endl;
|
||||
|
||||
if (particleIndex<0 || particleIndex>=(int)_particles.size()) return;
|
||||
|
||||
Particle* particle = &_particles[particleIndex];
|
||||
int previous = particle->getPreviousParticle();
|
||||
int next = particle->getNextParticle();
|
||||
|
||||
// update start and last entries
|
||||
if (_startParticle == particleIndex)
|
||||
{
|
||||
_startParticle = particle->getNextParticle();
|
||||
}
|
||||
|
||||
if (_lastParticleCreated == particleIndex)
|
||||
{
|
||||
_lastParticleCreated = Particle::INVALID_INDEX;
|
||||
}
|
||||
|
||||
// join up the previous and next particles to account for
|
||||
// the deletion of the this particle
|
||||
if (previous != Particle::INVALID_INDEX)
|
||||
{
|
||||
_particles[previous].setNextParticle(next);
|
||||
}
|
||||
|
||||
if (next != Particle::INVALID_INDEX)
|
||||
{
|
||||
_particles[next].setPreviousParticle(previous);
|
||||
}
|
||||
|
||||
// reset the next and previous particle entries of this particle
|
||||
particle->setPreviousParticle(Particle::INVALID_INDEX);
|
||||
particle->setNextParticle(Particle::INVALID_INDEX);
|
||||
|
||||
// do the actual destroy of the particle
|
||||
ParticleSystem::destroyParticle(particleIndex);
|
||||
}
|
||||
|
||||
void ConnectedParticleSystem::drawImplementation(osg::State& state) const
|
||||
{
|
||||
ParticleSystem::drawImplementation(state);
|
||||
const Particle* particle = (_startParticle != Particle::INVALID_INDEX) ? &_particles[_startParticle] : 0;
|
||||
if (!particle) return;
|
||||
|
||||
osg::Vec4 pixelSizeVector = osg::CullingSet::computePixelSizeVector(*state.getCurrentViewport(),state.getProjectionMatrix(),state.getModelViewMatrix());
|
||||
float unitPixelSize = fabs(1.0/(particle->getPosition()*pixelSizeVector));
|
||||
float pixelSizeOfFirstParticle = unitPixelSize * particle->getCurrentSize();
|
||||
float desiredGapBetweenDrawnParticles = 50.0f/unitPixelSize;
|
||||
float desiredGapBetweenDrawnParticles2 = desiredGapBetweenDrawnParticles*desiredGapBetweenDrawnParticles;
|
||||
unsigned int maxNumParticlesToSkip = 200;
|
||||
float maxPixelError2 = osg::square(1.0f/unitPixelSize);
|
||||
|
||||
if (pixelSizeOfFirstParticle<1.0)
|
||||
{
|
||||
// draw the connected particles as a line
|
||||
glBegin(GL_LINE_STRIP);
|
||||
while(particle != 0)
|
||||
{
|
||||
|
||||
const osg::Vec4& color = particle->getCurrentColor();
|
||||
const osg::Vec3& pos = particle->getPosition();
|
||||
glColor4f( color.r(), color.g(), color.b(), color.a() * particle->getCurrentAlpha());
|
||||
glTexCoord2f( particle->getSTexCoord(), 0.5f );
|
||||
glVertex3fv(pos.ptr());
|
||||
|
||||
const Particle* nextParticle = (particle->getNextParticle() != Particle::INVALID_INDEX) ? &_particles[particle->getNextParticle()] : 0;
|
||||
if (nextParticle)
|
||||
{
|
||||
const osg::Vec3& nextPos = nextParticle->getPosition();
|
||||
osg::Vec3 startDelta = nextPos-pos;
|
||||
startDelta.normalize();
|
||||
float distance2 = 0.0;
|
||||
|
||||
// now skip particles of required
|
||||
for(unsigned int i=0;
|
||||
i<maxNumParticlesToSkip && ((distance2<maxPixelError2) && (nextParticle->getNextParticle()!=Particle::INVALID_INDEX));
|
||||
++i)
|
||||
{
|
||||
nextParticle = &_particles[nextParticle->getNextParticle()];
|
||||
const osg::Vec3& nextPos = nextParticle->getPosition();
|
||||
osg::Vec3 delta = nextPos-pos;
|
||||
distance2 = (delta^startDelta).length2();
|
||||
}
|
||||
}
|
||||
particle = nextParticle;
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// draw the connected particles as a quad stripped aligned to be orthogonal to the eye
|
||||
osg::Matrix eyeToLocalTransform;
|
||||
eyeToLocalTransform.invert(state.getModelViewMatrix());
|
||||
osg::Vec3 eyeLocal = osg::Vec3(0.0f,0.0,0.0f)*eyeToLocalTransform;
|
||||
|
||||
osg::Vec3 delta(0.0f,0.0f,1.0f);
|
||||
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
while(particle != 0)
|
||||
{
|
||||
const osg::Vec4& color = particle->getCurrentColor();
|
||||
const osg::Vec3& pos = particle->getPosition();
|
||||
|
||||
const Particle* nextParticle = (particle->getNextParticle() != Particle::INVALID_INDEX) ? &_particles[particle->getNextParticle()] : 0;
|
||||
|
||||
if (nextParticle)
|
||||
{
|
||||
const osg::Vec3& nextPos = nextParticle->getPosition();
|
||||
osg::Vec3 startDelta = nextPos-pos;
|
||||
startDelta.normalize();
|
||||
float distance2 = 0.0;
|
||||
|
||||
// now skip particles of required
|
||||
for(unsigned int i=0;
|
||||
i<maxNumParticlesToSkip && ((distance2<maxPixelError2) && (nextParticle->getNextParticle()!=Particle::INVALID_INDEX));
|
||||
++i)
|
||||
{
|
||||
nextParticle = &_particles[nextParticle->getNextParticle()];
|
||||
const osg::Vec3& nextPos = nextParticle->getPosition();
|
||||
delta = nextPos-pos;
|
||||
distance2 = (delta^startDelta).length2();
|
||||
}
|
||||
|
||||
delta = nextPos-pos;
|
||||
}
|
||||
|
||||
osg::Vec3 normal( delta ^ (pos-eyeLocal));
|
||||
normal.normalize();
|
||||
normal *= particle->getCurrentSize();
|
||||
|
||||
osg::Vec3 bottom(pos-normal);
|
||||
osg::Vec3 top(pos+normal);
|
||||
|
||||
glColor4f( color.r(), color.g(), color.b(), color.a() * particle->getCurrentAlpha());
|
||||
|
||||
glTexCoord2f( particle->getSTexCoord(), 0.0f );
|
||||
glVertex3fv(bottom.ptr());
|
||||
|
||||
glTexCoord2f( particle->getSTexCoord(), 1.0f );
|
||||
glVertex3fv(top.ptr());
|
||||
|
||||
particle = nextParticle;
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ CXXFILES =\
|
||||
ExplosionEffect.cpp\
|
||||
ExplosionDebrisEffect.cpp\
|
||||
SmokeEffect.cpp\
|
||||
SmokeTrailEffect.cpp\
|
||||
FireEffect.cpp\
|
||||
FluidFrictionOperator.cpp\
|
||||
FluidProgram.cpp\
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <osgParticle/ModularEmitter>
|
||||
#include <osgParticle/Emitter>
|
||||
#include <osgParticle/ConnectedParticleSystem>
|
||||
#include <osg/Notify>
|
||||
|
||||
osgParticle::ModularEmitter::ModularEmitter()
|
||||
@@ -22,6 +23,8 @@ osgParticle::ModularEmitter::ModularEmitter(const ModularEmitter& copy, const os
|
||||
|
||||
void osgParticle::ModularEmitter::emit(double dt)
|
||||
{
|
||||
ConnectedParticleSystem* cps = dynamic_cast<ConnectedParticleSystem*>(getParticleSystem());
|
||||
|
||||
if (getReferenceFrame() == RELATIVE_RF)
|
||||
{
|
||||
const osg::Matrix& ltw = getLocalToWorldMatrix();
|
||||
@@ -60,6 +63,9 @@ void osgParticle::ModularEmitter::emit(double dt)
|
||||
float r = ((float)rand()/(float)RAND_MAX);
|
||||
P->transformPositionVelocity(ltw, previous_ltw, r);
|
||||
//P->transformPositionVelocity(ltw);
|
||||
|
||||
if (cps) P->setUpTexCoordsAsPartOfConnectedParticleSystem(cps);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -77,6 +83,8 @@ void osgParticle::ModularEmitter::emit(double dt)
|
||||
{
|
||||
_placer->place(P);
|
||||
_shooter->shoot(P);
|
||||
|
||||
if (cps) P->setUpTexCoordsAsPartOfConnectedParticleSystem(cps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <osgParticle/Particle>
|
||||
#include <osgParticle/LinearInterpolator>
|
||||
#include <osgParticle/ParticleSystem>
|
||||
|
||||
#include <osg/Vec3>
|
||||
#include <osg/Vec4>
|
||||
@@ -48,8 +49,8 @@ osgParticle::Particle::Particle()
|
||||
_cur_tile(-1),
|
||||
_s_coord(0.0f),
|
||||
_t_coord(0.0f),
|
||||
_previousParticle(0),
|
||||
_nextParticle(0)
|
||||
_previousParticle(INVALID_INDEX),
|
||||
_nextParticle(INVALID_INDEX)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -81,10 +82,14 @@ bool osgParticle::Particle::update(double dt)
|
||||
int currentTile = static_cast<int>(x * _num_tile);
|
||||
|
||||
//If the current texture tile is different from previous, then compute new texture coords
|
||||
if(currentTile != _cur_tile) {
|
||||
if(currentTile != _cur_tile)
|
||||
{
|
||||
|
||||
_cur_tile = currentTile;
|
||||
_s_coord = _s_tile * fmod(_cur_tile , 1.0 / _s_tile);
|
||||
_t_coord = 1.0 - _t_tile * (static_cast<int>(_cur_tile * _t_tile) + 1);
|
||||
|
||||
// osg::notify(osg::NOTICE)<<this<<" setting tex coords "<<_s_coord<<" "<<_t_coord<<std::endl;
|
||||
}
|
||||
|
||||
// compute the current values for size, alpha and color.
|
||||
@@ -215,3 +220,23 @@ void osgParticle::Particle::render(const osg::Vec3& xpos, const osg::Vec3& px, c
|
||||
osg::notify(osg::WARN) << "Invalid shape for particles\n";
|
||||
}
|
||||
}
|
||||
|
||||
void osgParticle::Particle::setUpTexCoordsAsPartOfConnectedParticleSystem(ParticleSystem* ps)
|
||||
{
|
||||
if (getPreviousParticle()!=Particle::INVALID_INDEX)
|
||||
{
|
||||
update(0.0);
|
||||
|
||||
Particle* previousParticle = ps->getParticle(getPreviousParticle());
|
||||
const osg::Vec3& previousPosition = previousParticle->getPosition();
|
||||
const osg::Vec3& newPosition = getPosition();
|
||||
float distance = (newPosition-previousPosition).length();
|
||||
float s_coord_delta = 0.5f*distance/getCurrentSize();
|
||||
float s_coord = previousParticle->_s_coord + s_coord_delta;
|
||||
|
||||
setTextureTile(0,0,0);
|
||||
_cur_tile = 0;
|
||||
_s_coord = s_coord;
|
||||
_t_coord = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,17 +68,19 @@ void osgParticle::ParticleSystem::update(double dt)
|
||||
// reset bounds
|
||||
_reset_bounds_flag = true;
|
||||
|
||||
// set up iterators for particles
|
||||
Particle_vector::iterator i;
|
||||
Particle_vector::iterator end = _particles.end();
|
||||
|
||||
// update particles
|
||||
for (i=_particles.begin(); i!=end; ++i) {
|
||||
if (i->isAlive()) {
|
||||
if (i->update(dt)) {
|
||||
update_bounds(i->getPosition(), i->getCurrentSize());
|
||||
} else {
|
||||
_deadparts.push(&(*i));
|
||||
for(unsigned int i=0; i<_particles.size(); ++i)
|
||||
{
|
||||
Particle& particle = _particles[i];
|
||||
if (particle.isAlive())
|
||||
{
|
||||
if (particle.update(dt))
|
||||
{
|
||||
update_bounds(particle.getPosition(), particle.getCurrentSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
reuseParticle(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,6 +143,8 @@ void osgParticle::ParticleSystem::setDefaultAttributes(const std::string& textur
|
||||
texture->setImage(osgDB::readImageFile(texturefile));
|
||||
texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR);
|
||||
texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
|
||||
texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::MIRROR);
|
||||
texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::MIRROR);
|
||||
stateset->setTextureAttributeAndModes(texture_unit, texture, osg::StateAttribute::ON);
|
||||
|
||||
osg::TexEnv *texenv = new osg::TexEnv;
|
||||
|
||||
149
src/osgParticle/SmokeTrailEffect.cpp
Normal file
149
src/osgParticle/SmokeTrailEffect.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include <osgParticle/SmokeTrailEffect>
|
||||
|
||||
#include <osgParticle/ConstantRateCounter>
|
||||
#include <osgParticle/RadialShooter>
|
||||
#include <osgParticle/SectorPlacer>
|
||||
#include <osgParticle/ParticleSystemUpdater>
|
||||
#include <osgParticle/ConnectedParticleSystem>
|
||||
|
||||
#include <osg/Geode>
|
||||
|
||||
using namespace osgParticle;
|
||||
|
||||
SmokeTrailEffect::SmokeTrailEffect(const osg::Vec3& position, float scale, float intensity)
|
||||
{
|
||||
setDefaults();
|
||||
|
||||
_position = position;
|
||||
_scale = scale;
|
||||
_intensity = intensity;
|
||||
|
||||
_emitterDuration = 65.0;
|
||||
_defaultParticleTemplate.setLifeTime(5.0*_scale);
|
||||
|
||||
buildEffect();
|
||||
}
|
||||
|
||||
SmokeTrailEffect::SmokeTrailEffect(const SmokeTrailEffect& copy, const osg::CopyOp& copyop):
|
||||
ParticleEffect(copy,copyop)
|
||||
{
|
||||
}
|
||||
|
||||
void SmokeTrailEffect::setDefaults()
|
||||
{
|
||||
ParticleEffect::setDefaults();
|
||||
|
||||
_textureFileName = "Images/continous_smoke.rgb";
|
||||
_emitterDuration = 65.0;
|
||||
|
||||
// set up unit particle.
|
||||
_defaultParticleTemplate.setLifeTime(5.0*_scale);
|
||||
_defaultParticleTemplate.setSizeRange(osgParticle::rangef(0.75f, 2.0f));
|
||||
_defaultParticleTemplate.setAlphaRange(osgParticle::rangef(0.7f, 1.0f));
|
||||
_defaultParticleTemplate.setColorRange(osgParticle::rangev4(
|
||||
osg::Vec4(1, 1.0f, 1.0f, 1.0f),
|
||||
osg::Vec4(1, 1.0f, 1.f, 0.0f)));
|
||||
|
||||
|
||||
}
|
||||
|
||||
void SmokeTrailEffect::setUpEmitterAndProgram()
|
||||
{
|
||||
// set up particle system
|
||||
if (!_particleSystem)
|
||||
{
|
||||
_particleSystem = new osgParticle::ConnectedParticleSystem;
|
||||
}
|
||||
|
||||
if (_particleSystem.valid())
|
||||
{
|
||||
_particleSystem->setDefaultAttributes(_textureFileName, false, false);
|
||||
|
||||
osgParticle::Particle& ptemplate = _particleSystem->getDefaultParticleTemplate();
|
||||
|
||||
float radius = 0.5f*_scale;
|
||||
float density = 1.0f; // 1.0kg/m^3
|
||||
|
||||
ptemplate.setLifeTime(_defaultParticleTemplate.getLifeTime());
|
||||
|
||||
// the following ranges set the envelope of the respective
|
||||
// graphical properties in time.
|
||||
ptemplate.setSizeRange(osgParticle::rangef(radius*_defaultParticleTemplate.getSizeRange().minimum,
|
||||
radius*_defaultParticleTemplate.getSizeRange().maximum));
|
||||
ptemplate.setAlphaRange(_defaultParticleTemplate.getAlphaRange());
|
||||
ptemplate.setColorRange(_defaultParticleTemplate.getColorRange());
|
||||
|
||||
// these are physical properties of the particle
|
||||
ptemplate.setRadius(radius);
|
||||
ptemplate.setMass(density*radius*radius*radius*osg::PI*4.0f/3.0f);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// set up emitter
|
||||
if (!_emitter)
|
||||
{
|
||||
_emitter = new osgParticle::ModularEmitter;
|
||||
_emitter->setCounter(new osgParticle::ConstantRateCounter);
|
||||
_emitter->setPlacer(new osgParticle::SectorPlacer);
|
||||
_emitter->setShooter(new osgParticle::RadialShooter);
|
||||
}
|
||||
|
||||
if (_emitter.valid())
|
||||
{
|
||||
_emitter->setParticleSystem(_particleSystem.get());
|
||||
_emitter->setReferenceFrame(_useLocalParticleSystem?
|
||||
osgParticle::ParticleProcessor::ABSOLUTE_RF:
|
||||
osgParticle::ParticleProcessor::RELATIVE_RF);
|
||||
|
||||
_emitter->setStartTime(_startTime);
|
||||
_emitter->setLifeTime(_emitterDuration);
|
||||
_emitter->setEndless(false);
|
||||
|
||||
osgParticle::ConstantRateCounter* counter = dynamic_cast<osgParticle::ConstantRateCounter*>(_emitter->getCounter());
|
||||
if (counter)
|
||||
{
|
||||
counter->setMinimumNumberOfParticlesToCreate(1);
|
||||
counter->setNumberOfParticlesPerSecondToCreate(0.0);
|
||||
}
|
||||
|
||||
osgParticle::SectorPlacer* placer = dynamic_cast<osgParticle::SectorPlacer*>(_emitter->getPlacer());
|
||||
if (placer)
|
||||
{
|
||||
placer->setCenter(_position);
|
||||
placer->setRadiusRange(0.0f*_scale,0.0f*_scale);
|
||||
}
|
||||
|
||||
osgParticle::RadialShooter* shooter = dynamic_cast<osgParticle::RadialShooter*>(_emitter->getShooter());
|
||||
if (shooter)
|
||||
{
|
||||
shooter->setThetaRange(0.0f, 0.0f);
|
||||
shooter->setInitialSpeedRange(0.0f*_scale,0.0f*_scale);
|
||||
}
|
||||
}
|
||||
|
||||
// set up program.
|
||||
if (!_program)
|
||||
{
|
||||
_program = new osgParticle::FluidProgram;
|
||||
}
|
||||
|
||||
if (_program.valid())
|
||||
{
|
||||
_program->setParticleSystem(_particleSystem.get());
|
||||
_program->setWind(_wind);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user