From be285c62c03a18ad3ae6f9e330f64041daf53869 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 25 Aug 2005 14:12:08 +0000 Subject: [PATCH] Added support for rapid movement of the emitter, with particle now seeding between the position of the emitter in the previous frame and the new position in the new frame, the number of particles added also scales up to compensate for this movement. --- .../osgparticleeffects/osgparticleeffects.cpp | 12 ++-- include/osgParticle/ModularEmitter | 19 +++++ include/osgParticle/MultiSegmentPlacer | 8 +++ include/osgParticle/Particle | 22 ++++-- include/osgParticle/ParticleProcessor | 39 +++++++++-- include/osgParticle/Placer | 4 ++ include/osgParticle/PointPlacer | 8 +++ include/osgParticle/SectorPlacer | 7 ++ include/osgParticle/SegmentPlacer | 9 +++ include/osgParticle/range | 5 ++ src/osgParticle/FireEffect.cpp | 1 + src/osgParticle/ModularEmitter.cpp | 70 ++++++++++++++++--- src/osgParticle/ParticleProcessor.cpp | 4 ++ src/osgParticle/SmokeEffect.cpp | 3 +- 14 files changed, 183 insertions(+), 28 deletions(-) diff --git a/examples/osgparticleeffects/osgparticleeffects.cpp b/examples/osgparticleeffects/osgparticleeffects.cpp index 2226e16dd..e100bb9f3 100644 --- a/examples/osgparticleeffects/osgparticleeffects.cpp +++ b/examples/osgparticleeffects/osgparticleeffects.cpp @@ -62,7 +62,7 @@ osg::Node* createMovingModel(const osg::Vec3& center, float radius) if (glider) { const osg::BoundingSphere& bs = glider->getBound(); - float size = radius/bs.radius()*0.3f; + float size = radius/bs.radius()*0.15f; osg::MatrixTransform* positioned = new osg::MatrixTransform; positioned->setDataVariance(osg::Object::STATIC); @@ -84,7 +84,7 @@ osg::Node* createMovingModel(const osg::Vec3& center, float radius) if (cessna) { const osg::BoundingSphere& bs = cessna->getBound(); - float size = radius/bs.radius()*0.3f; + float size = radius/bs.radius()*0.15f; osg::MatrixTransform* positioned = new osg::MatrixTransform; positioned->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); @@ -220,7 +220,7 @@ void build_world(osg::Group *root) // create the moving models. { - root->addChild(createMovingModel(osg::Vec3(500.0f,500.0f,500.0f),100.0f)); + root->addChild(createMovingModel(osg::Vec3(500.0f,500.0f,500.0f),300.0f)); } } @@ -271,12 +271,12 @@ public: } osg::Vec3 position = handleMovingModels ? hit.getLocalIntersectPoint() : hit.getWorldIntersectPoint(); - float scale = 20.0f * ((float)rand() / (float)RAND_MAX); - float intensity = handleMovingModels ? 5.0f : 1.0f; + float scale = 10.0f * ((float)rand() / (float)RAND_MAX); + float intensity = 1.0f; osgParticle::ExplosionEffect* explosion = new osgParticle::ExplosionEffect(position, scale, intensity); osgParticle::ExplosionDebrisEffect* explosionDebri = new osgParticle::ExplosionDebrisEffect(position, scale, intensity); - osgParticle::SmokeEffect* smoke = new osgParticle::SmokeEffect(position, scale, intensity); + osgParticle::ParticleEffect* smoke = new osgParticle::SmokeEffect(position, scale, intensity); osgParticle::FireEffect* fire = new osgParticle::FireEffect(position, scale, intensity); explosion->setWind(wind); diff --git a/include/osgParticle/ModularEmitter b/include/osgParticle/ModularEmitter index 7b27f3c90..412ec740c 100644 --- a/include/osgParticle/ModularEmitter +++ b/include/osgParticle/ModularEmitter @@ -57,6 +57,13 @@ namespace osgParticle /// Set the Counter object. inline void setCounter(Counter* c); + /// Get the ratio between number of particle to create in compenstation for movement of the emitter + inline float getNumParticlesToCreateMovementCompenstationRatio() const; + + /// Set the ratio between number of particle to create in compenstation for movement of the emitter + inline void setNumParticlesToCreateMovementCompenstationRatio(float r); + + /// Get the Placer object. inline Placer* getPlacer(); @@ -82,6 +89,8 @@ namespace osgParticle virtual void emit(double dt); private: + + float _numParticleToCreateMovementCompensationRatio; osg::ref_ptr _counter; osg::ref_ptr _placer; osg::ref_ptr _shooter; @@ -104,6 +113,16 @@ namespace osgParticle _counter = c; } + inline float ModularEmitter::getNumParticlesToCreateMovementCompenstationRatio() const + { + return _numParticleToCreateMovementCompensationRatio; + } + + inline void ModularEmitter::setNumParticlesToCreateMovementCompenstationRatio(float r) + { + _numParticleToCreateMovementCompensationRatio = r; + } + inline Placer* ModularEmitter::getPlacer() { return _placer.get(); diff --git a/include/osgParticle/MultiSegmentPlacer b/include/osgParticle/MultiSegmentPlacer index 1b830154d..eb6e8617f 100644 --- a/include/osgParticle/MultiSegmentPlacer +++ b/include/osgParticle/MultiSegmentPlacer @@ -64,6 +64,9 @@ namespace osgParticle { /// Place a partice. Called automatically by ModularEmitter, do not call this method manually. void place(Particle* P) const; + /// return the control position + inline osg::Vec3 getControlPosition() const; + protected: virtual ~MultiSegmentPlacer() {} MultiSegmentPlacer& operator=(const MultiSegmentPlacer&) { return *this; } @@ -123,6 +126,11 @@ namespace osgParticle { _vx.erase(_vx.begin()+i); recompute_length(); } + + inline osg::Vec3 MultiSegmentPlacer::getControlPosition() const + { + return _vx.empty() ? osg::Vec3(0.0f,0.0f,0.0f) : _vx[0].first; + } } #endif diff --git a/include/osgParticle/Particle b/include/osgParticle/Particle index 36d6b2eb0..7a4b2b93a 100644 --- a/include/osgParticle/Particle +++ b/include/osgParticle/Particle @@ -178,6 +178,9 @@ namespace osgParticle /// Transform position and velocity vectors by a matrix. inline void transformPositionVelocity(const osg::Matrix& xform); + /// Transform position and velocity vectors by a combination of two matrices + void Particle::transformPositionVelocity(const osg::Matrix& xform1, const osg::Matrix& xform2, float r); + /// Set the angle vector. inline void setAngle(const osg::Vec3& a); @@ -410,14 +413,19 @@ namespace osgParticle inline void Particle::transformPositionVelocity(const osg::Matrix& xform) { - // this should be optimized! - - osg::Vec3 p1 = _position + _velocity; - _position = xform.preMult(_position); - p1 = xform.preMult(p1); - - _velocity = p1 - _position; + _velocity = osg::Matrix::transform3x3(_velocity, xform); + } + + inline void Particle::transformPositionVelocity(const osg::Matrix& xform1, const osg::Matrix& xform2, float r) + { + osg::Vec3 position1 = xform1.preMult(_position); + osg::Vec3 velocity1 = osg::Matrix::transform3x3(_velocity, xform1); + osg::Vec3 position2 = xform2.preMult(_position); + osg::Vec3 velocity2 = osg::Matrix::transform3x3(_velocity, xform2); + float one_minus_r = 1.0f-r; + _position = position1*r + position2*one_minus_r; + _velocity = velocity1*r + velocity2*one_minus_r; } inline void Particle::setAngle(const osg::Vec3& a) diff --git a/include/osgParticle/ParticleProcessor b/include/osgParticle/ParticleProcessor index bb6bd6e1a..0d0867fcb 100644 --- a/include/osgParticle/ParticleProcessor +++ b/include/osgParticle/ParticleProcessor @@ -119,6 +119,13 @@ namespace osgParticle /// Get the current world-to-local transformation matrix (valid only during cull traversal). inline const osg::Matrix& getWorldToLocalMatrix(); + /// Get the previous local-to-world transformation matrix (valid only during cull traversal). + inline const osg::Matrix& getPreviousLocalToWorldMatrix(); + + /// Get the previous world-to-local transformation matrix (valid only during cull traversal). + inline const osg::Matrix& getPreviousWorldToLocalMatrix(); + + /// Transform a point from local to world coordinates (valid only during cull traversal). inline osg::Vec3 transformLocalToWorld(const osg::Vec3& P); @@ -144,10 +151,14 @@ namespace osgParticle bool _enabled; double _t0; osg::ref_ptr _ps; + bool _first_ltw_compute; bool _need_ltw_matrix; + bool _first_wtl_compute; bool _need_wtl_matrix; osg::Matrix _ltw_matrix; osg::Matrix _wtl_matrix; + osg::Matrix _previous_ltw_matrix; + osg::Matrix _previous_wtl_matrix; osg::NodeVisitor* _current_nodevisitor; bool _endless; @@ -252,9 +263,13 @@ namespace osgParticle inline const osg::Matrix& ParticleProcessor::getLocalToWorldMatrix() { if (_need_ltw_matrix) { - _ltw_matrix = osg::Matrix::identity(); - //_current_nodevisitor->getLocalToWorldMatrix(_ltw_matrix, this); + _previous_ltw_matrix = _ltw_matrix; _ltw_matrix = osg::computeLocalToWorld(_current_nodevisitor->getNodePath()); + if (_first_ltw_compute) + { + _previous_ltw_matrix = _ltw_matrix; + _first_ltw_compute = false; + } _need_ltw_matrix = false; } return _ltw_matrix; @@ -263,14 +278,30 @@ namespace osgParticle inline const osg::Matrix& ParticleProcessor::getWorldToLocalMatrix() { if (_need_wtl_matrix) { - _wtl_matrix = osg::Matrix::identity(); - //_current_nodevisitor->getWorldToLocalMatrix(_wtl_matrix, this); + _previous_wtl_matrix = _wtl_matrix; _wtl_matrix = osg::computeWorldToLocal(_current_nodevisitor->getNodePath()); + if (_first_wtl_compute) + { + _previous_wtl_matrix = _wtl_matrix; + _first_wtl_compute = false; + } _need_wtl_matrix = false; } return _wtl_matrix; } + inline const osg::Matrix& ParticleProcessor::getPreviousLocalToWorldMatrix() + { + if (_need_ltw_matrix) getLocalToWorldMatrix(); + return _previous_ltw_matrix; + } + + inline const osg::Matrix& ParticleProcessor::getPreviousWorldToLocalMatrix() + { + if (_need_wtl_matrix) getWorldToLocalMatrix(); + return _previous_wtl_matrix; + } + inline osg::Vec3 ParticleProcessor::transformLocalToWorld(const osg::Vec3& P) { return getLocalToWorldMatrix().preMult(P); diff --git a/include/osgParticle/Placer b/include/osgParticle/Placer index 302f5a19d..1b710d866 100644 --- a/include/osgParticle/Placer +++ b/include/osgParticle/Placer @@ -17,6 +17,7 @@ #include #include +#include namespace osgParticle { @@ -39,6 +40,9 @@ namespace osgParticle /// Place a particle. Must be implemented in descendant classes. virtual void place(Particle* P) const = 0; + /// Return the control position of particles that placer will generate. Must be implemented in descendant classes. + virtual osg::Vec3 getControlPosition() const = 0; + protected: ~Placer() {} Placer& operator=(const Placer& ) { return *this; } diff --git a/include/osgParticle/PointPlacer b/include/osgParticle/PointPlacer index 3f6d6dd0c..d6530aa25 100644 --- a/include/osgParticle/PointPlacer +++ b/include/osgParticle/PointPlacer @@ -41,6 +41,9 @@ namespace osgParticle */ inline void place(Particle* P) const; + /// return the control position + inline osg::Vec3 getControlPosition() const; + protected: virtual ~PointPlacer() {} PointPlacer& operator=(const PointPlacer&) { return *this; } @@ -64,6 +67,11 @@ namespace osgParticle } + inline osg::Vec3 PointPlacer::getControlPosition() const + { + return getCenter(); + } + } diff --git a/include/osgParticle/SectorPlacer b/include/osgParticle/SectorPlacer index 660f12d9d..78a43dd95 100644 --- a/include/osgParticle/SectorPlacer +++ b/include/osgParticle/SectorPlacer @@ -61,6 +61,9 @@ namespace osgParticle /// Place a particle. Do not call it manually. inline void place(Particle* P) const; + /// return the control position + inline osg::Vec3 getControlPosition() const; + protected: virtual ~SectorPlacer() {} SectorPlacer& operator=(const SectorPlacer&) { return *this; } @@ -127,6 +130,10 @@ namespace osgParticle P->setPosition(pos); } + inline osg::Vec3 SectorPlacer::getControlPosition() const + { + return getCenter(); + } } diff --git a/include/osgParticle/SegmentPlacer b/include/osgParticle/SegmentPlacer index eace16fe4..232e923f5 100644 --- a/include/osgParticle/SegmentPlacer +++ b/include/osgParticle/SegmentPlacer @@ -60,6 +60,9 @@ namespace osgParticle { /// Place a particle. This method is called by ModularEmitter, do not call it manually. inline void place(Particle* P) const; + /// return the control position + inline osg::Vec3 getControlPosition() const; + protected: virtual ~SegmentPlacer() {} SegmentPlacer& operator=(const SegmentPlacer&) { return *this; } @@ -121,6 +124,12 @@ namespace osgParticle { { _vertexB.set(x, y, z); } + + inline osg::Vec3 SegmentPlacer::getControlPosition() const + { + return (_vertexA+_vertexB)*0.5f; + } + } diff --git a/include/osgParticle/range b/include/osgParticle/range index 64b87fd7f..d4f3a02c2 100644 --- a/include/osgParticle/range +++ b/include/osgParticle/range @@ -70,6 +70,11 @@ namespace osgParticle { return minimum + (maximum - minimum) * sqrtf( static_cast(rand()) / static_cast(RAND_MAX) ); } + + ValueType mid() const + { + return (minimum+maximum)*0.5f; + } }; diff --git a/src/osgParticle/FireEffect.cpp b/src/osgParticle/FireEffect.cpp index 2c1c35d78..c850e4248 100644 --- a/src/osgParticle/FireEffect.cpp +++ b/src/osgParticle/FireEffect.cpp @@ -100,6 +100,7 @@ void FireEffect::setUpEmitterAndProgram() if (!_emitter) { _emitter = new osgParticle::ModularEmitter; + _emitter->setNumParticlesToCreateMovementCompenstationRatio(1.5f); _emitter->setCounter(new osgParticle::RandomRateCounter); _emitter->setPlacer(new osgParticle::SectorPlacer); _emitter->setShooter(new osgParticle::RadialShooter); diff --git a/src/osgParticle/ModularEmitter.cpp b/src/osgParticle/ModularEmitter.cpp index f9876019c..17e753c99 100644 --- a/src/osgParticle/ModularEmitter.cpp +++ b/src/osgParticle/ModularEmitter.cpp @@ -1,16 +1,19 @@ #include #include +#include osgParticle::ModularEmitter::ModularEmitter() : Emitter(), + _numParticleToCreateMovementCompensationRatio(0.0f), _counter(new RandomRateCounter), _placer(new PointPlacer), _shooter(new RadialShooter) { } -osgParticle::ModularEmitter::ModularEmitter(const ModularEmitter& copy, const osg::CopyOp& copyop) -: Emitter(copy, copyop), +osgParticle::ModularEmitter::ModularEmitter(const ModularEmitter& copy, const osg::CopyOp& copyop): + Emitter(copy, copyop), + _numParticleToCreateMovementCompensationRatio(copy._numParticleToCreateMovementCompensationRatio), _counter(static_cast(copyop(copy._counter.get()))), _placer(static_cast(copyop(copy._placer.get()))), _shooter(static_cast(copyop(copy._shooter.get()))) @@ -19,14 +22,61 @@ osgParticle::ModularEmitter::ModularEmitter(const ModularEmitter& copy, const os void osgParticle::ModularEmitter::emit(double dt) { - int n = _counter->numParticlesToCreate(dt); - for (int i=0; icreateParticle(getUseDefaultTemplate()? 0: &getParticleTemplate()); - if (P) { - _placer->place(P); - _shooter->shoot(P); - if (getReferenceFrame() == RELATIVE_RF) { - P->transformPositionVelocity(getLocalToWorldMatrix()); + if (getReferenceFrame() == RELATIVE_RF) + { + const osg::Matrix& ltw = getLocalToWorldMatrix(); + const osg::Matrix& previous_ltw = getPreviousLocalToWorldMatrix(); + + int n = _counter->numParticlesToCreate(dt); + + if (_numParticleToCreateMovementCompensationRatio>0.0f) + { + // compute the distance moved between frames + const osg::Vec3 controlPosition = _placer->getControlPosition(); + osg::Vec3 previousPosition = controlPosition * previous_ltw; + osg::Vec3 currentPosition = controlPosition * ltw; + float distance = (currentPosition-previousPosition).length(); + + float size = getUseDefaultTemplate() ? + getParticleSystem()->getDefaultParticleTemplate().getSizeRange().minimum : + getParticleTemplate().getSizeRange().minimum; + + float num_extra_samples = _numParticleToCreateMovementCompensationRatio*distance/size; + float rounded_down = floor(num_extra_samples); + float remainder = num_extra_samples-rounded_down; + + n = osg::maximum(n, int(rounded_down) + (((float) rand() < remainder * (float)RAND_MAX) ? 1 : 0)); + } + + for (int i=0; icreateParticle(getUseDefaultTemplate()? 0: &getParticleTemplate()); + if (P) + { + _placer->place(P); + _shooter->shoot(P); + + // now need to transform the position and velocity because we having a moving model. + float r = ((float)rand()/(float)RAND_MAX); + P->transformPositionVelocity(ltw, previous_ltw, r); + //P->transformPositionVelocity(ltw); + } + else + { + osg::notify(osg::NOTICE)<<"run out of particle"<numParticlesToCreate(dt); + for (int i=0; icreateParticle(getUseDefaultTemplate()? 0: &getParticleTemplate()); + if (P) + { + _placer->place(P); + _shooter->shoot(P); } } } diff --git a/src/osgParticle/ParticleProcessor.cpp b/src/osgParticle/ParticleProcessor.cpp index c3b790fc1..b9ab60cb6 100644 --- a/src/osgParticle/ParticleProcessor.cpp +++ b/src/osgParticle/ParticleProcessor.cpp @@ -17,7 +17,9 @@ osgParticle::ParticleProcessor::ParticleProcessor() _enabled(true), _t0(-1), _ps(0), + _first_ltw_compute(true), _need_ltw_matrix(false), + _first_wtl_compute(true), _need_wtl_matrix(false), _current_nodevisitor(0), _endless(true), @@ -35,7 +37,9 @@ osgParticle::ParticleProcessor::ParticleProcessor(const ParticleProcessor& copy, _enabled(copy._enabled), _t0(copy._t0), _ps(static_cast(copyop(copy._ps.get()))), + _first_ltw_compute(copy._first_ltw_compute), _need_ltw_matrix(copy._need_ltw_matrix), + _first_wtl_compute(copy._first_wtl_compute), _need_wtl_matrix(copy._need_wtl_matrix), _current_nodevisitor(0), _endless(copy._endless), diff --git a/src/osgParticle/SmokeEffect.cpp b/src/osgParticle/SmokeEffect.cpp index 1074582ae..ace6ef06e 100644 --- a/src/osgParticle/SmokeEffect.cpp +++ b/src/osgParticle/SmokeEffect.cpp @@ -50,7 +50,7 @@ void SmokeEffect::setDefaults() // set up unit particle. _defaultParticleTemplate.setLifeTime(5.0*_scale); - _defaultParticleTemplate.setSizeRange(osgParticle::rangef(0.75f, 3.0f)); + _defaultParticleTemplate.setSizeRange(osgParticle::rangef(0.75f, 2.0f)); _defaultParticleTemplate.setAlphaRange(osgParticle::rangef(0.1f, 1.0f)); _defaultParticleTemplate.setColorRange(osgParticle::rangev4( osg::Vec4(1, 1.0f, 1.0f, 1.0f), @@ -96,6 +96,7 @@ void SmokeEffect::setUpEmitterAndProgram() if (!_emitter) { _emitter = new osgParticle::ModularEmitter; + _emitter->setNumParticlesToCreateMovementCompenstationRatio(1.5f); _emitter->setCounter(new osgParticle::RandomRateCounter); _emitter->setPlacer(new osgParticle::SectorPlacer); _emitter->setShooter(new osgParticle::RadialShooter);