mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-29 17:15: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);
|
||||
|
||||
// (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 ©, 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
|
||||
{
|
||||
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…
Reference in a new issue