# include <simgear_config.h>
#endif
+#include <simgear/math/SGMath.hxx>
+#include <simgear/math/SGGeod.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include <osgParticle/SectorPlacer>
#include <osgParticle/ConstantRateCounter>
#include <osgParticle/ParticleSystemUpdater>
+#include <osgParticle/ParticleSystem>
#include <osgParticle/FluidProgram>
#include <osg/Geode>
+#include <osg/Group>
#include <osg/MatrixTransform>
+#include <osg/Node>
#include "particles.hxx"
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:"<<w[0]<<","<<w[1]<<","<<w[2]<<"\n");
osg::ref_ptr<osg::Group> Particles::commonRoot;
osg::ref_ptr<osgParticle::ParticleSystemUpdater> Particles::psu = new osgParticle::ParticleSystemUpdater;
osg::ref_ptr<osg::Geode> Particles::commonGeode = new osg::Geode;;
+osg::Vec3 Particles::_wind;
+
+Particles::Particles() :
+ useGravity(false),
+ useWind(false)
+{
+}
template <typename Object>
class PointerGuard{
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*
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")) {
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));
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()
}
}
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)
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
#define _SG_PARTICLES_HXX 1
#include <osg/ref_ptr>
-#include <osg/Group>
-#include <osg/Node>
-#include <osg/NodeVisitor>
-#include <osg/Texture2D>
#include <osgParticle/SmokeTrailEffect>
#include <osgParticle/Particle>
#include <osgParticle/ModularEmitter>
-#include <osgParticle/ParticleSystemUpdater>
-#include <osgParticle/ParticleSystem>
-#include <osg/MatrixTransform>
#include <osgDB/ReaderWriter>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osg/Notify>
#include <osg/Vec3>
+namespace osg
+{
+class Group;
+class MatrixTransform;
+class Node;
+class NodeVisitor;
+}
+
+namespace osgParticle
+{
+class ParticleSystem;
+class ParticleSystemUpdater;
+}
#include <simgear/scene/util/SGNodeMasks.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/structure/SGExpression.hxx>
+#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/math/SGQuat.hxx>
#include <simgear/math/SGMatrix.hxx>
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);
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()
{
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<SGExpressiond> shooterValue;
+ SGSharedPtr<SGExpressiond> counterValue;
+ SGSharedPtr<SGExpressiond> colorComponents[8];
+ SGSharedPtr<SGExpressiond> startSizeValue;
+ SGSharedPtr<SGExpressiond> endSizeValue;
+ SGSharedPtr<SGExpressiond> lifeValue;
+ SGSharedPtr<SGCondition> counterCond;
float staticColorComponents[8];
float startSize;
float endSize;
osg::ref_ptr<osgParticle::RandomRateCounter> counter;
osg::ref_ptr<osgParticle::ParticleSystem> particleSys;
osg::ref_ptr<osgParticle::FluidProgram> program;
+ osg::ref_ptr<osg::MatrixTransform> particleFrame;
+
bool useGravity;
bool useWind;
static osg::ref_ptr<osgParticle::ParticleSystemUpdater> psu;
static osg::ref_ptr<osg::Group> commonRoot;
static osg::ref_ptr<osg::Geode> commonGeode;
+ static osg::Vec3 _wind;
};
}
#endif