diff --git a/components/nif/controlled.cpp b/components/nif/controlled.cpp index bf391d388..5c63094ce 100644 --- a/components/nif/controlled.cpp +++ b/components/nif/controlled.cpp @@ -54,10 +54,7 @@ namespace Nif { Controlled::read(nif); - float decay = nif->getFloat(); - if (decay != 0.f) - nif->file->warn("Unhandled gravity decay factor"); - + mDecay = nif->getFloat(); mForce = nif->getFloat(); mType = nif->getUInt(); mPosition = nif->getVector3(); diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 36d90b03d..4bd7ce1f9 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -92,6 +92,7 @@ public: * 1 - Point (fixed origin) */ int mType; + float mDecay; osg::Vec3f mPosition; osg::Vec3f mDirection; diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 59a4a981b..3cfd91f1f 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -155,13 +155,14 @@ void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* d GravityAffector::GravityAffector(const Nif::NiGravity *gravity) : mForce(gravity->mForce) , mType(static_cast(gravity->mType)) + , mDecay(gravity->mDecay) , mPosition(gravity->mPosition) , mDirection(gravity->mDirection) { } GravityAffector::GravityAffector() - : mForce(0), mType(Type_Wind) + : mForce(0), mType(Type_Wind), mDecay(0.f) { } @@ -175,10 +176,12 @@ GravityAffector::GravityAffector(const GravityAffector ©, const osg::CopyOp void GravityAffector::beginOperate(osgParticle::Program* program) { bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF); - if (mType == Type_Wind) - mCachedWorldPositionDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; - else // Type_Point - mCachedWorldPositionDirection = absolute ? program->transformLocalToWorld(mPosition) : mPosition; + + if (mType == Type_Point || mDecay != 0.f) // we don't need the position for Wind gravity, except if decay is being applied + mCachedWorldPosition = absolute ? program->transformLocalToWorld(mPosition) : mPosition; + + mCachedWorldDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; + mCachedWorldDirection.normalize(); } void GravityAffector::operate(osgParticle::Particle *particle, double dt) @@ -187,18 +190,33 @@ void GravityAffector::operate(osgParticle::Particle *particle, double dt) switch (mType) { case Type_Wind: - particle->addVelocity(mCachedWorldPositionDirection * mForce * dt * magic); + { + float decayFactor = 1.f; + if (mDecay != 0.f) + { + osg::Plane gravityPlane(mCachedWorldDirection, mCachedWorldPosition); + float distance = std::abs(gravityPlane.distance(particle->getPosition())); + decayFactor = std::exp(-1.f * mDecay * distance); + } + + particle->addVelocity(mCachedWorldDirection * mForce * dt * decayFactor * magic); + break; + } case Type_Point: { - osg::Vec3f diff = mCachedWorldPositionDirection - particle->getPosition(); + osg::Vec3f diff = mCachedWorldPosition - particle->getPosition(); + + float decayFactor = 1.f; + if (mDecay != 0.f) + decayFactor = std::exp(-1.f * mDecay * diff.length()); + diff.normalize(); - particle->addVelocity(diff * mForce * dt * magic); + + particle->addVelocity(diff * mForce * dt * decayFactor * magic); break; } } - - // velocity *= e^-[(dist/decay)^2] } Emitter::Emitter() diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 99db3c83a..416477cdd 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -169,7 +169,9 @@ namespace NifOsg ForceType mType; osg::Vec3f mPosition; osg::Vec3f mDirection; - osg::Vec3f mCachedWorldPositionDirection; + float mDecay; + osg::Vec3f mCachedWorldPosition; + osg::Vec3f mCachedWorldDirection; }; // NodeVisitor to find a child node with the given record index, stored in the node's user data container.