Implement planar collider for particles (Fixes #2149)

c++11
scrawl 10 years ago
parent c179977f20
commit 6d9deaa386

@ -65,8 +65,14 @@ namespace Nif
{
Controlled::read(nif);
// (I think) 4 floats + 4 vectors
nif->skip(4*16);
mBounceFactor = nif->getFloat();
/*unknown*/nif->getFloat();
for (int i=0;i<10;++i)
/*unknown*/nif->getFloat();
mPlaneNormal = nif->getVector3();
mPlaneDistance = nif->getFloat();
}
void NiParticleRotation::read(NIFStream *nif)

@ -103,6 +103,11 @@ class NiPlanarCollider : public Controlled
{
public:
void read(NIFStream *nif);
float mBounceFactor;
osg::Vec3f mPlaneNormal;
float mPlaneDistance;
};
class NiParticleRotation : public Controlled

@ -76,8 +76,8 @@ namespace Nif
}
nif->getUInt(); /* -1? */
extra.read(nif);
nif->getUInt(); /* -1? */
affectors.read(nif);
colliders.read(nif);
nif->getChar();
}
@ -85,7 +85,8 @@ namespace Nif
{
Controller::post(nif);
emitter.post(nif);
extra.post(nif);
affectors.post(nif);
colliders.post(nif);
}
void NiMaterialColorController::read(NIFStream *nif)

@ -72,7 +72,8 @@ public:
int activeCount;
std::vector<Particle> particles;
ExtraPtr extra;
ExtraPtr affectors;
ExtraPtr colliders;
void read(NIFStream *nif);
void post(NIFFile *nif);

@ -719,39 +719,44 @@ namespace NifOsg
}
}
void handleParticleAffectors(Nif::ExtraPtr e, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf)
void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf)
{
osgParticle::ModularProgram* program = new osgParticle::ModularProgram;
attachTo->addChild(program);
program->setParticleSystem(partsys);
program->setReferenceFrame(rf);
for (; !e.empty(); e = e->extra)
for (; !affectors.empty(); affectors = affectors->extra)
{
if (e->recType == Nif::RC_NiParticleGrowFade)
if (affectors->recType == Nif::RC_NiParticleGrowFade)
{
const Nif::NiParticleGrowFade *gf = static_cast<const Nif::NiParticleGrowFade*>(e.getPtr());
GrowFadeAffector* affector = new GrowFadeAffector(gf->growTime, gf->fadeTime);
program->addOperator(affector);
const Nif::NiParticleGrowFade *gf = static_cast<const Nif::NiParticleGrowFade*>(affectors.getPtr());
program->addOperator(new GrowFadeAffector(gf->growTime, gf->fadeTime));
}
else if (e->recType == Nif::RC_NiGravity)
else if (affectors->recType == Nif::RC_NiGravity)
{
const Nif::NiGravity* gr = static_cast<const Nif::NiGravity*>(e.getPtr());
GravityAffector* affector = new GravityAffector(gr);
program->addOperator(affector);
const Nif::NiGravity* gr = static_cast<const Nif::NiGravity*>(affectors.getPtr());
program->addOperator(new GravityAffector(gr));
}
else if (e->recType == Nif::RC_NiParticleColorModifier)
else if (affectors->recType == Nif::RC_NiParticleColorModifier)
{
const Nif::NiParticleColorModifier *cl = static_cast<const Nif::NiParticleColorModifier*>(e.getPtr());
const Nif::NiParticleColorModifier *cl = static_cast<const Nif::NiParticleColorModifier*>(affectors.getPtr());
const Nif::NiColorData *clrdata = cl->data.getPtr();
ParticleColorAffector* affector = new ParticleColorAffector(clrdata);
program->addOperator(affector);
program->addOperator(new ParticleColorAffector(clrdata));
}
else if (e->recType == Nif::RC_NiParticleRotation)
else if (affectors->recType == Nif::RC_NiParticleRotation)
{
// TODO: Implement?
}
else
std::cerr << "Unhandled particle modifier " << e->recName << std::endl;
std::cerr << "Unhandled particle modifier " << affectors->recName << std::endl;
}
for (; !colliders.empty(); colliders = colliders->extra)
{
if (colliders->recType == Nif::RC_NiPlanarCollider)
{
const Nif::NiPlanarCollider* planarcollider = static_cast<const Nif::NiPlanarCollider*>(colliders.getPtr());
program->addOperator(new PlanarCollider(planarcollider));
}
}
}
@ -888,7 +893,9 @@ namespace NifOsg
emitter->setUpdateCallback(callback);
// affectors must be attached *after* the emitter in the scene graph for correct update order
handleParticleAffectors(partctrl->extra, emitterNode, partsys.get(), rf);
// attach to same node as the ParticleSystem, we need osgParticle Operators to get the correct
// localToWorldMatrix for transforming to particle space
handleParticlePrograms(partctrl->affectors, partctrl->colliders, parentNode, partsys.get(), rf);
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(partsys);

@ -303,4 +303,46 @@ void FindRecIndexVisitor::apply(osg::Node &searchNode)
traverse(searchNode);
}
PlanarCollider::PlanarCollider(const Nif::NiPlanarCollider *collider)
: mBounceFactor(collider->mBounceFactor)
, mPlane(-collider->mPlaneNormal, collider->mPlaneDistance)
{
}
PlanarCollider::PlanarCollider()
: mBounceFactor(0.f)
{
}
PlanarCollider::PlanarCollider(const PlanarCollider &copy, const osg::CopyOp &copyop)
: osgParticle::Operator(copy, copyop)
, mBounceFactor(copy.mBounceFactor)
, mPlane(copy.mPlane)
, mPlaneInParticleSpace(copy.mPlaneInParticleSpace)
{
}
void PlanarCollider::beginOperate(osgParticle::Program *program)
{
mPlaneInParticleSpace = mPlane;
if (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF)
mPlaneInParticleSpace.transform(program->getLocalToWorldMatrix());
}
void PlanarCollider::operate(osgParticle::Particle *particle, double dt)
{
float dotproduct = particle->getVelocity() * mPlaneInParticleSpace.getNormal();
if (dotproduct > 0)
{
osg::BoundingSphere bs(particle->getPosition(), 0.f);
if (mPlaneInParticleSpace.intersect(bs) == 1)
{
osg::Vec3 reflectedVelocity = particle->getVelocity() - mPlaneInParticleSpace.getNormal() * (2 * dotproduct);
reflectedVelocity *= mBounceFactor;
particle->setVelocity(reflectedVelocity);
}
}
}
}

@ -17,6 +17,7 @@
namespace Nif
{
class NiGravity;
class NiPlanarCollider;
}
namespace NifOsg
@ -92,6 +93,24 @@ namespace NifOsg
float mLifetimeRandom;
};
class PlanarCollider : public osgParticle::Operator
{
public:
PlanarCollider(const Nif::NiPlanarCollider* collider);
PlanarCollider();
PlanarCollider(const PlanarCollider& copy, const osg::CopyOp& copyop);
META_Object(NifOsg, PlanarCollider)
virtual void beginOperate(osgParticle::Program* program);
virtual void operate(osgParticle::Particle* particle, double dt);
private:
float mBounceFactor;
osg::Plane mPlane;
osg::Plane mPlaneInParticleSpace;
};
class GrowFadeAffector : public osgParticle::Operator
{
public:

Loading…
Cancel
Save