mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-06 15:45:32 +00:00
Implement planar collider for particles (Fixes #2149)
This commit is contained in:
parent
c179977f20
commit
6d9deaa386
7 changed files with 104 additions and 23 deletions
|
@ -65,8 +65,14 @@ namespace Nif
|
||||||
{
|
{
|
||||||
Controlled::read(nif);
|
Controlled::read(nif);
|
||||||
|
|
||||||
// (I think) 4 floats + 4 vectors
|
mBounceFactor = nif->getFloat();
|
||||||
nif->skip(4*16);
|
/*unknown*/nif->getFloat();
|
||||||
|
|
||||||
|
for (int i=0;i<10;++i)
|
||||||
|
/*unknown*/nif->getFloat();
|
||||||
|
|
||||||
|
mPlaneNormal = nif->getVector3();
|
||||||
|
mPlaneDistance = nif->getFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiParticleRotation::read(NIFStream *nif)
|
void NiParticleRotation::read(NIFStream *nif)
|
||||||
|
|
|
@ -103,6 +103,11 @@ class NiPlanarCollider : public Controlled
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
|
|
||||||
|
float mBounceFactor;
|
||||||
|
|
||||||
|
osg::Vec3f mPlaneNormal;
|
||||||
|
float mPlaneDistance;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NiParticleRotation : public Controlled
|
class NiParticleRotation : public Controlled
|
||||||
|
|
|
@ -76,8 +76,8 @@ namespace Nif
|
||||||
}
|
}
|
||||||
|
|
||||||
nif->getUInt(); /* -1? */
|
nif->getUInt(); /* -1? */
|
||||||
extra.read(nif);
|
affectors.read(nif);
|
||||||
nif->getUInt(); /* -1? */
|
colliders.read(nif);
|
||||||
nif->getChar();
|
nif->getChar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,8 @@ namespace Nif
|
||||||
{
|
{
|
||||||
Controller::post(nif);
|
Controller::post(nif);
|
||||||
emitter.post(nif);
|
emitter.post(nif);
|
||||||
extra.post(nif);
|
affectors.post(nif);
|
||||||
|
colliders.post(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiMaterialColorController::read(NIFStream *nif)
|
void NiMaterialColorController::read(NIFStream *nif)
|
||||||
|
|
|
@ -72,7 +72,8 @@ public:
|
||||||
int activeCount;
|
int activeCount;
|
||||||
std::vector<Particle> particles;
|
std::vector<Particle> particles;
|
||||||
|
|
||||||
ExtraPtr extra;
|
ExtraPtr affectors;
|
||||||
|
ExtraPtr colliders;
|
||||||
|
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
void post(NIFFile *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;
|
osgParticle::ModularProgram* program = new osgParticle::ModularProgram;
|
||||||
attachTo->addChild(program);
|
attachTo->addChild(program);
|
||||||
program->setParticleSystem(partsys);
|
program->setParticleSystem(partsys);
|
||||||
program->setReferenceFrame(rf);
|
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());
|
const Nif::NiParticleGrowFade *gf = static_cast<const Nif::NiParticleGrowFade*>(affectors.getPtr());
|
||||||
GrowFadeAffector* affector = new GrowFadeAffector(gf->growTime, gf->fadeTime);
|
program->addOperator(new GrowFadeAffector(gf->growTime, gf->fadeTime));
|
||||||
program->addOperator(affector);
|
|
||||||
}
|
}
|
||||||
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());
|
const Nif::NiGravity* gr = static_cast<const Nif::NiGravity*>(affectors.getPtr());
|
||||||
GravityAffector* affector = new GravityAffector(gr);
|
program->addOperator(new GravityAffector(gr));
|
||||||
program->addOperator(affector);
|
|
||||||
}
|
}
|
||||||
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();
|
const Nif::NiColorData *clrdata = cl->data.getPtr();
|
||||||
ParticleColorAffector* affector = new ParticleColorAffector(clrdata);
|
program->addOperator(new ParticleColorAffector(clrdata));
|
||||||
program->addOperator(affector);
|
|
||||||
}
|
}
|
||||||
else if (e->recType == Nif::RC_NiParticleRotation)
|
else if (affectors->recType == Nif::RC_NiParticleRotation)
|
||||||
{
|
{
|
||||||
// TODO: Implement?
|
// TODO: Implement?
|
||||||
}
|
}
|
||||||
else
|
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);
|
emitter->setUpdateCallback(callback);
|
||||||
|
|
||||||
// affectors must be attached *after* the emitter in the scene graph for correct update order
|
// 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);
|
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
|
||||||
geode->addDrawable(partsys);
|
geode->addDrawable(partsys);
|
||||||
|
|
|
@ -303,4 +303,46 @@ void FindRecIndexVisitor::apply(osg::Node &searchNode)
|
||||||
traverse(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 ©, const osg::CopyOp ©op)
|
||||||
|
: 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
|
namespace Nif
|
||||||
{
|
{
|
||||||
class NiGravity;
|
class NiGravity;
|
||||||
|
class NiPlanarCollider;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace NifOsg
|
namespace NifOsg
|
||||||
|
@ -92,6 +93,24 @@ namespace NifOsg
|
||||||
float mLifetimeRandom;
|
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
|
class GrowFadeAffector : public osgParticle::Operator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in a new issue