From 19aac5b14c5d5adcb56009f0f5dbe3bfe7adc4a4 Mon Sep 17 00:00:00 2001 From: timoore Date: Thu, 11 Sep 2008 10:19:05 +0000 Subject: [PATCH] Keep non-local particles in a Z-up frame that is periodically moved. This eliminates jitter and other rendering problems. For the moment this is dependent on an osg fix. Also, don't read wind properties from FlightGear; provide a mechanism for fg to set the wind. --- simgear/scene/model/SGReaderWriterXML.cxx | 1 + simgear/scene/model/particles.cxx | 90 +++++++++++++++++++++-- simgear/scene/model/particles.hxx | 72 +++++++++--------- 3 files changed, 119 insertions(+), 44 deletions(-) diff --git a/simgear/scene/model/SGReaderWriterXML.cxx b/simgear/scene/model/SGReaderWriterXML.cxx index 9d6a42c5..2d48e7e2 100644 --- a/simgear/scene/model/SGReaderWriterXML.cxx +++ b/simgear/scene/model/SGReaderWriterXML.cxx @@ -20,6 +20,7 @@ # include #endif +#include #include #include #include diff --git a/simgear/scene/model/particles.cxx b/simgear/scene/model/particles.cxx index 9fdc4bf5..0194e960 100644 --- a/simgear/scene/model/particles.cxx +++ b/simgear/scene/model/particles.cxx @@ -21,6 +21,8 @@ # include #endif +#include +#include #include #include #include @@ -32,10 +34,13 @@ #include #include #include +#include #include #include +#include #include +#include #include "particles.hxx" @@ -49,9 +54,8 @@ void GlobalParticleCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) osg::Matrix om(q.osg()); osg::Vec3 v(0,0,9.81); gravity = om.preMult(v); - - osg::Vec3 w(-modelRoot->getFloatValue("/environment/wind-from-north-fps",0) * SG_FEET_TO_METER, - -modelRoot->getFloatValue("/environment/wind-from-east-fps",0) * SG_FEET_TO_METER, 0); + const osg::Vec3& zUpWind = Particles::getWindVector(); + osg::Vec3 w(zUpWind.y(), zUpWind.x(), - zUpWind.z()); wind = om.preMult(w); //SG_LOG(SG_GENERAL, SG_ALERT, "wind vector:"< Particles::commonRoot; osg::ref_ptr Particles::psu = new osgParticle::ParticleSystemUpdater; osg::ref_ptr Particles::commonGeode = new osg::Geode;; +osg::Vec3 Particles::_wind; + +Particles::Particles() : + useGravity(false), + useWind(false) +{ +} template class PointerGuard{ @@ -81,6 +92,36 @@ private: Object* _ptr; }; +osg::Group* Particles::getCommonRoot() +{ + if(!commonRoot.valid()) + { + SG_LOG(SG_GENERAL, SG_DEBUG, "Particle common root called!\n"); + commonRoot = new osg::Group; + commonRoot.get()->setName("common particle system root"); + commonGeode.get()->setName("common particle system geode"); + commonRoot.get()->addChild(commonGeode.get()); + commonRoot.get()->addChild(psu.get()); + } + return commonRoot.get(); +} + +// Enable this once particle fix is in OSG. +// #define OSG_PARTICLE_FIX 1 +void transformParticles(osgParticle::ParticleSystem* particleSys, + const osg::Matrix& mat) +{ + const int numParticles = particleSys->numParticles(); + if (particleSys->areAllParticlesDead()) + return; + for (int i = 0; i < numParticles; ++i) { + osgParticle::Particle* P = particleSys->getParticle(i); + if (!P->isAlive()) + continue; + P->transformPositionVelocity(mat); + } +} + osg::Group * Particles::appendParticles(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const osgDB::ReaderWriter::Options* @@ -140,9 +181,19 @@ osg::Group * Particles::appendParticles(const SGPropertyNode* configNode, osg::Geode* g = new osg::Geode; align->addChild(g); g->addDrawable(particleSys); +#ifndef OSG_PARTICLE_FIX emitter->setReferenceFrame(osgParticle::Emitter::ABSOLUTE_RF); +#endif } else { +#ifdef OSG_PARTICLE_FIX + callback()->particleFrame = new osg::MatrixTransform(); + osg::Geode* g = new osg::Geode; + g->addDrawable(particleSys); + callback()->particleFrame->addChild(g); + getCommonRoot()->addChild(callback()->particleFrame.get()); +#else getCommonGeode()->addDrawable(particleSys); +#endif } std::string textureFile; if (configNode->hasValue("texture")) { @@ -415,10 +466,14 @@ osg::Group * Particles::appendParticles(const SGPropertyNode* configNode, program->setFluidToWater(); if (programnode->getBoolValue("gravity", true)) { +#ifdef OSG_PARTICLE_FIX + program->setToGravity(); +#else if (attach == "world") callback()->setupProgramGravity(true); else program->setToGravity(); +#endif } else program->setAcceleration(osg::Vec3(0,0,0)); @@ -447,7 +502,7 @@ osg::Group * Particles::appendParticles(const SGPropertyNode* configNode, void Particles::operator()(osg::Node* node, osg::NodeVisitor* nv) { //SG_LOG(SG_GENERAL, SG_ALERT, "callback!\n"); - + using namespace osg; if (shooterValue) shooter->setInitialSpeedRange(shooterValue->getValue(), (shooterValue->getValue() @@ -468,7 +523,7 @@ void Particles::operator()(osg::Node* node, osg::NodeVisitor* nv) } } if (colorchange) - particleSys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4( osg::Vec4(staticColorComponents[0], staticColorComponents[1], staticColorComponents[2], staticColorComponents[3]), osg::Vec4(staticColorComponents[4], staticColorComponents[5], staticColorComponents[6], staticColorComponents[7]))); + particleSys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4( Vec4(staticColorComponents[0], staticColorComponents[1], staticColorComponents[2], staticColorComponents[3]), Vec4(staticColorComponents[4], staticColorComponents[5], staticColorComponents[6], staticColorComponents[7]))); if (startSizeValue) startSize = startSizeValue->getValue(); if (endSizeValue) @@ -477,11 +532,36 @@ void Particles::operator()(osg::Node* node, osg::NodeVisitor* nv) particleSys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(startSize, endSize)); if (lifeValue) particleSys->getDefaultParticleTemplate().setLifeTime(lifeValue->getValue()); +#ifdef OSG_PARTICLE_FIX + if (particleFrame.valid()) { + MatrixList mlist = node->getWorldMatrices(); + if (!mlist.empty()) { + const Matrix& particleMat = particleFrame->getMatrix(); + Vec3d emitOrigin(mlist[0](3, 0), mlist[0](3, 1), mlist[0](3, 2)); + Vec3d displace + = emitOrigin - Vec3d(particleMat(3, 0), particleMat(3, 1), + particleMat(3, 2)); + if (displace * displace > 10000.0 * 10000.0) { + // Make new frame for particle system, coincident with + // the emitter frame, but oriented with local Z. + SGGeod geod = SGGeod::fromCart(SGVec3d(emitOrigin)); + Matrix newParticleMat = geod.makeZUpFrame(); + Matrix changeParticleFrame + = particleMat * Matrix::inverse(newParticleMat); + particleFrame->setMatrix(newParticleMat); + transformParticles(particleSys.get(), changeParticleFrame); + } + } + } + if (program.valid() && useWind) + program->setWind(_wind); +#else if (program.valid()) { if (useGravity) program->setAcceleration(GlobalParticleCallback::getGravityVector()); if (useWind) program->setWind(GlobalParticleCallback::getWindVector()); } +#endif } } // namespace simgear diff --git a/simgear/scene/model/particles.hxx b/simgear/scene/model/particles.hxx index 359f6acd..4c9d5053 100644 --- a/simgear/scene/model/particles.hxx +++ b/simgear/scene/model/particles.hxx @@ -20,16 +20,9 @@ #define _SG_PARTICLES_HXX 1 #include -#include -#include -#include -#include #include #include #include -#include -#include -#include #include #include #include @@ -37,11 +30,25 @@ #include #include +namespace osg +{ +class Group; +class MatrixTransform; +class Node; +class NodeVisitor; +} + +namespace osgParticle +{ +class ParticleSystem; +class ParticleSystemUpdater; +} #include #include #include #include +#include #include #include @@ -90,18 +97,7 @@ private: class Particles : public osg::NodeCallback { public: - Particles() : - shooterValue(NULL), - counterValue(NULL), - startSizeValue(NULL), - endSizeValue(NULL), - lifeValue(NULL), - counterCond(NULL), - useGravity(false), - useWind(false) - { - memset(colorComponents, 0, sizeof(colorComponents)); - } + Particles(); static osg::Group * appendParticles(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const osgDB::ReaderWriter::Options* options); @@ -229,19 +225,7 @@ public: staticColorComponents[7] = a2; } - static osg::Group * getCommonRoot() - { - if(!commonRoot.valid()) - { - SG_LOG(SG_GENERAL, SG_DEBUG, "Particle common root called!\n"); - commonRoot = new osg::Group; - commonRoot.get()->setName("common particle system root"); - commonGeode.get()->setName("common particle system geode"); - commonRoot.get()->addChild(commonGeode.get()); - commonRoot.get()->addChild(psu.get()); - } - return commonRoot.get(); - } + static osg::Group * getCommonRoot(); static osg::Geode * getCommonGeode() { @@ -253,16 +237,23 @@ public: return psu.get(); } + /** + * Set and get the wind vector for particles in the + * atmosphere. This vector is in the Z-up Y-north frame, and the + * magnitude is the velocity in meters per second. + */ + static void setWindVector(const osg::Vec3& wind) { _wind = wind; } + static const osg::Vec3& getWindVector() { return _wind; } protected: float shooterExtraRange; float counterExtraRange; - SGExpressiond* shooterValue; - SGExpressiond* counterValue; - SGExpressiond* colorComponents[8]; - SGExpressiond* startSizeValue; - SGExpressiond* endSizeValue; - SGExpressiond* lifeValue; - SGCondition* counterCond; + SGSharedPtr shooterValue; + SGSharedPtr counterValue; + SGSharedPtr colorComponents[8]; + SGSharedPtr startSizeValue; + SGSharedPtr endSizeValue; + SGSharedPtr lifeValue; + SGSharedPtr counterCond; float staticColorComponents[8]; float startSize; float endSize; @@ -272,11 +263,14 @@ protected: osg::ref_ptr counter; osg::ref_ptr particleSys; osg::ref_ptr program; + osg::ref_ptr particleFrame; + bool useGravity; bool useWind; static osg::ref_ptr psu; static osg::ref_ptr commonRoot; static osg::ref_ptr commonGeode; + static osg::Vec3 _wind; }; } #endif -- 2.39.5