From 1e508d432bdbaf42defb4de8cc08f448ff18f073 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 12 Oct 2005 18:42:36 +0000 Subject: [PATCH] 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. --- VisualStudio/osgParticle/osgParticle.dsp | 12 ++ .../osgparticleeffects/osgparticleeffects.cpp | 7 +- include/osg/CullingSet | 5 +- include/osgParticle/ConnectedParticleSystem | 12 +- include/osgParticle/ConstantRateCounter | 75 +++++++ include/osgParticle/Particle | 44 +++- include/osgParticle/ParticleSystem | 4 +- include/osgParticle/SmokeTrailEffect | 52 +++++ src/osg/CullStack.cpp | 31 +-- src/osg/CullingSet.cpp | 34 +++ src/osgParticle/ConnectedParticleSystem.cpp | 195 ++++++++++++++++-- src/osgParticle/GNUmakefile | 1 + src/osgParticle/ModularEmitter.cpp | 8 + src/osgParticle/Particle.cpp | 31 ++- src/osgParticle/ParticleSystem.cpp | 24 ++- src/osgParticle/SmokeTrailEffect.cpp | 149 +++++++++++++ 16 files changed, 611 insertions(+), 73 deletions(-) create mode 100644 include/osgParticle/ConstantRateCounter create mode 100644 include/osgParticle/SmokeTrailEffect create mode 100644 src/osgParticle/SmokeTrailEffect.cpp diff --git a/VisualStudio/osgParticle/osgParticle.dsp b/VisualStudio/osgParticle/osgParticle.dsp index b092f77cc..e0fd9ea2e 100644 --- a/VisualStudio/osgParticle/osgParticle.dsp +++ b/VisualStudio/osgParticle/osgParticle.dsp @@ -163,6 +163,10 @@ SOURCE=..\..\src\osgParticle\SmokeEffect.cpp # End Source File # Begin Source File +SOURCE=..\..\src\osgParticle\SmokeTrailEffect.cpp +# End Source File +# Begin Source File + SOURCE=..\..\src\osgParticle\Version.cpp # End Source File # End Group @@ -187,6 +191,10 @@ SOURCE=..\..\include\osgParticle\Counter # End Source File # Begin Source File +SOURCE=..\..\include\osgParticle\ConstantRateCounter +# End Source File +# Begin Source File + SOURCE=..\..\include\osgParticle\Emitter # End Source File # Begin Source File @@ -307,6 +315,10 @@ SOURCE=..\..\include\osgParticle\SmokeEffect # End Source File # Begin Source File +SOURCE=..\..\include\osgParticle\SmokeTrailEffect +# End Source File +# Begin Source File + SOURCE=..\..\include\osgParticle\VariableRateCounter # End Source File # Begin Source File diff --git a/examples/osgparticleeffects/osgparticleeffects.cpp b/examples/osgparticleeffects/osgparticleeffects.cpp index e100bb9f3..bb8683009 100644 --- a/examples/osgparticleeffects/osgparticleeffects.cpp +++ b/examples/osgparticleeffects/osgparticleeffects.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include // for the grid data.. @@ -276,8 +277,12 @@ public: osgParticle::ExplosionEffect* explosion = new osgParticle::ExplosionEffect(position, scale, intensity); osgParticle::ExplosionDebrisEffect* explosionDebri = new osgParticle::ExplosionDebrisEffect(position, scale, intensity); - osgParticle::ParticleEffect* smoke = new osgParticle::SmokeEffect(position, scale, intensity); osgParticle::FireEffect* fire = new osgParticle::FireEffect(position, scale, intensity); + osgParticle::ParticleEffect* smoke = 0; + if (handleMovingModels) + smoke = new osgParticle::SmokeTrailEffect(position, scale, intensity); + else + smoke = new osgParticle::SmokeEffect(position, scale, intensity); explosion->setWind(wind); explosionDebri->setWind(wind); diff --git a/include/osg/CullingSet b/include/osg/CullingSet index 5bcf8776f..f217bcfc2 100644 --- a/include/osg/CullingSet +++ b/include/osg/CullingSet @@ -16,7 +16,7 @@ #include #include -#include +#include #include @@ -328,7 +328,10 @@ class OSG_EXPORT CullingSet : public Referenced void popOccludersCurrentMask(NodePath& nodePath); + static osg::Vec4 computePixelSizeVector(const Viewport& W, const Matrix& P, const Matrix& M); + virtual ~CullingSet(); + protected: diff --git a/include/osgParticle/ConnectedParticleSystem b/include/osgParticle/ConnectedParticleSystem index 1f12d1dd0..223a4e6f1 100644 --- a/include/osgParticle/ConnectedParticleSystem +++ b/include/osgParticle/ConnectedParticleSystem @@ -35,12 +35,10 @@ namespace osgParticle /// Create a new particle from the specified template (or the default one if ptemplate is null). virtual Particle* createParticle(const Particle* ptemplate); - /// Destroy the i-th particle. - virtual void destroyParticle(int i); + /// Reuse the i-th particle. + virtual void reuseParticle(int i); - /// Update the particles. Don't call this directly, use a ConnectedParticleSystemUpdater instead. - virtual void update(double dt); - + /// Draw the connected particles as either a line or a quad strip, depending upon viewing distance. . virtual void drawImplementation(osg::State& state) const; protected: @@ -49,8 +47,8 @@ namespace osgParticle ConnectedParticleSystem& operator=(const ConnectedParticleSystem&) { return *this; } - Particle* _startParticle; - Particle* _lastParticleCreated; + int _startParticle; + int _lastParticleCreated; }; } diff --git a/include/osgParticle/ConstantRateCounter b/include/osgParticle/ConstantRateCounter new file mode 100644 index 000000000..98909f91e --- /dev/null +++ b/include/osgParticle/ConstantRateCounter @@ -0,0 +1,75 @@ +/* -*-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. +*/ + +#ifndef OSGPARTICLE_CONSTANTRATECOUNTER +#define OSGPARTICLE_CONSTANTRATECOUNTER 1 + +#include + +#include +#include + +namespace osgParticle +{ + + class ConstantRateCounter: public Counter { + public: + ConstantRateCounter(): + Counter(), + _minimumNumberOfParticlesToCreate(0), + _numberOfParticlesPerSecondToCreate(0) + { + } + + ConstantRateCounter(const ConstantRateCounter& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY): + Counter(copy, copyop), + _minimumNumberOfParticlesToCreate(copy._minimumNumberOfParticlesToCreate), + _numberOfParticlesPerSecondToCreate(copy._numberOfParticlesPerSecondToCreate) + { + } + + + META_Object(osgParticle, ConstantRateCounter); + + void setMinimumNumberOfParticlesToCreate(int minNumToCreate) { _minimumNumberOfParticlesToCreate = minNumToCreate; } + int getMinimumNumberOfParticlesToCreate() const { return _minimumNumberOfParticlesToCreate; } + + void setNumberOfParticlesPerSecondToCreate(double numPerSecond) { _numberOfParticlesPerSecondToCreate = numPerSecond; } + double getNumberOfParticlesPerSecondToCreate() const { return _numberOfParticlesPerSecondToCreate; } + + /// Return the number of particles to be created in this frame + virtual int numParticlesToCreate(double dt) const + { + double v = (dt*_numberOfParticlesPerSecondToCreate); + int i = (int)(v); + _carryOver += (v-(double)i); + if (_carryOver>1.0) + { + ++i; + _carryOver -= 1.0; + } + return osg::maximum(_minimumNumberOfParticlesToCreate, i); + } + + protected: + virtual ~ConstantRateCounter() {} + + int _minimumNumberOfParticlesToCreate; + double _numberOfParticlesPerSecondToCreate; + mutable double _carryOver; + }; + +} + + +#endif diff --git a/include/osgParticle/Particle b/include/osgParticle/Particle index 1b5b2a407..b79941af7 100644 --- a/include/osgParticle/Particle +++ b/include/osgParticle/Particle @@ -28,6 +28,9 @@ namespace osgParticle { + // forward declare so we can reference it + class ParticleSystem; + /** Implementation of a particle. Objects of this class are particles, they have some graphical properties and some physical properties. Particles are created by emitters and then placed @@ -44,6 +47,11 @@ namespace osgParticle */ class OSGPARTICLE_EXPORT Particle { public: + + enum + { + INVALID_INDEX = -1 + }; /** Shape of particles. @@ -125,6 +133,18 @@ namespace osgParticle /// Get the previous angle vector. inline const osg::Vec3& getPreviousAngle() const; + + /// Get the current color + inline const osg::Vec4& getCurrentColor() const { return _current_color; } + + /// Get the current alpha + inline float getCurrentAlpha() const { return _current_alpha; } + + /// Get the s texture coordinate of the bottom left of the particle + inline const float getSTexCoord() const { return _s_coord; } + + /// Get the t texture coordinate of the bottom left of the particle + inline float getTCoord() const { return _t_coord; } /** Kill the particle on next update NOTE: after calling this function, the isAlive() method will still @@ -216,10 +236,26 @@ 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 + /// Specify how the particle texture is tiled inline void setTextureTile(int sTile, int tTile, int numTiles = 0); - private: + /// Set the previous particle + inline void setPreviousParticle(int previous) { _previousParticle = previous; } + + /// Get the previous particle + inline int getPreviousParticle() const { return _previousParticle; } + + /// Set the next particle + inline void setNextParticle(int next) { _nextParticle = next; } + + /// Get the const next particle + inline int getNextParticle() const { return _nextParticle; } + + /// Method for initializing a particles texture coords as part of a connected particle system. + void setUpTexCoordsAsPartOfConnectedParticleSystem(ParticleSystem* ps); + + protected: + Shape _shape; rangef _sr; @@ -259,8 +295,8 @@ namespace osgParticle float _t_coord; // previous and next Particles are only used in ConnectedParticleSystems - Particle* _previousParticle; - Particle* _nextParticle; + int _previousParticle; + int _nextParticle; }; // INLINE FUNCTIONS diff --git a/include/osgParticle/ParticleSystem b/include/osgParticle/ParticleSystem index 1aee1229c..9120887f6 100644 --- a/include/osgParticle/ParticleSystem +++ b/include/osgParticle/ParticleSystem @@ -123,6 +123,9 @@ namespace osgParticle /// Destroy the i-th particle. inline virtual void destroyParticle(int i); + /// Reuse the i-th particle. + inline virtual void reuseParticle(int i) { _deadparts.push(&(_particles[i])); } + /// Get the last frame number. inline int getLastFrameNumber() const; @@ -170,7 +173,6 @@ namespace osgParticle inline void update_bounds(const osg::Vec3& p, float r); void single_pass_render(osg::State& state, const osg::Matrix& modelview) const; - private: typedef std::vector Particle_vector; typedef std::stack Death_stack; diff --git a/include/osgParticle/SmokeTrailEffect b/include/osgParticle/SmokeTrailEffect new file mode 100644 index 000000000..9c2cd54c2 --- /dev/null +++ b/include/osgParticle/SmokeTrailEffect @@ -0,0 +1,52 @@ +/* -*-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. +*/ + +#ifndef OSGPARTICLE_SMOKETRAILEFFECT +#define OSGPARTICLE_SMOKETRAILEFFECT + +#include +#include +#include + +namespace osgParticle +{ + + class OSGPARTICLE_EXPORT SmokeTrailEffect : public ParticleEffect + { + public: + + SmokeTrailEffect(const osg::Vec3& position=osg::Vec3(0.0f,0.0f,0.0f), float scale=1.0f, float intensity=1.0f); + + SmokeTrailEffect(const SmokeTrailEffect& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + META_Node(osgParticle,SmokeTrailEffect); + + virtual void setDefaults(); + + virtual void setUpEmitterAndProgram(); + + virtual Emitter* getEmitter() { return _emitter.get(); } + virtual const Emitter* getEmitter() const { return _emitter.get(); } + + virtual Program* getProgram() { return _program.get(); } + virtual const Program* getProgram() const { return _program.get(); } + + protected: + + osg::ref_ptr _emitter; + osg::ref_ptr _program; + + }; +} + +#endif diff --git a/src/osg/CullStack.cpp b/src/osg/CullStack.cpp index d2b404144..2885e4ef5 100644 --- a/src/osg/CullStack.cpp +++ b/src/osg/CullStack.cpp @@ -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()) { diff --git a/src/osg/CullingSet.cpp b/src/osg/CullingSet.cpp index d458b2a3c..314a1ad6e 100644 --- a/src/osg/CullingSet.cpp +++ b/src/osg/CullingSet.cpp @@ -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; +} diff --git a/src/osgParticle/ConnectedParticleSystem.cpp b/src/osgParticle/ConnectedParticleSystem.cpp index ba70e3ffd..94c3f98f7 100644 --- a/src/osgParticle/ConnectedParticleSystem.cpp +++ b/src/osgParticle/ConnectedParticleSystem.cpp @@ -12,24 +12,23 @@ */ #include +#include +#include #include 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."<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)<=(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; + igetNextParticle()!=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; + igetNextParticle()!=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(); + } + } diff --git a/src/osgParticle/GNUmakefile b/src/osgParticle/GNUmakefile index caaed636d..2335a8366 100644 --- a/src/osgParticle/GNUmakefile +++ b/src/osgParticle/GNUmakefile @@ -6,6 +6,7 @@ CXXFILES =\ ExplosionEffect.cpp\ ExplosionDebrisEffect.cpp\ SmokeEffect.cpp\ + SmokeTrailEffect.cpp\ FireEffect.cpp\ FluidFrictionOperator.cpp\ FluidProgram.cpp\ diff --git a/src/osgParticle/ModularEmitter.cpp b/src/osgParticle/ModularEmitter.cpp index 17e753c99..0b6d9b8f0 100644 --- a/src/osgParticle/ModularEmitter.cpp +++ b/src/osgParticle/ModularEmitter.cpp @@ -1,5 +1,6 @@ #include #include +#include #include 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(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); } } } diff --git a/src/osgParticle/Particle.cpp b/src/osgParticle/Particle.cpp index 92b18f9cc..f8c252a5e 100644 --- a/src/osgParticle/Particle.cpp +++ b/src/osgParticle/Particle.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -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(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(_cur_tile * _t_tile) + 1); + + // osg::notify(osg::NOTICE)<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; + } +} diff --git a/src/osgParticle/ParticleSystem.cpp b/src/osgParticle/ParticleSystem.cpp index 3d27bc6cb..d207526a5 100644 --- a/src/osgParticle/ParticleSystem.cpp +++ b/src/osgParticle/ParticleSystem.cpp @@ -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; diff --git a/src/osgParticle/SmokeTrailEffect.cpp b/src/osgParticle/SmokeTrailEffect.cpp new file mode 100644 index 000000000..c2389971e --- /dev/null +++ b/src/osgParticle/SmokeTrailEffect.cpp @@ -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 + +#include +#include +#include +#include +#include + +#include + +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(_emitter->getCounter()); + if (counter) + { + counter->setMinimumNumberOfParticlesToCreate(1); + counter->setNumberOfParticlesPerSecondToCreate(0.0); + } + + osgParticle::SectorPlacer* placer = dynamic_cast(_emitter->getPlacer()); + if (placer) + { + placer->setCenter(_position); + placer->setRadiusRange(0.0f*_scale,0.0f*_scale); + } + + osgParticle::RadialShooter* shooter = dynamic_cast(_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); + } +}