Implement NiSphericalCollider (Closes #3644)

pull/1147/head
MiroslavR 8 years ago
parent 3ac66ec9d4
commit 99bcf47167

@ -87,6 +87,15 @@ namespace Nif
nif->skip(17);
}
void NiSphericalCollider::read(NIFStream* nif)
{
Controlled::read(nif);
mBounceFactor = nif->getFloat();
mRadius = nif->getFloat();
mCenter = nif->getVector3();
}

@ -111,6 +111,16 @@ public:
float mPlaneDistance;
};
class NiSphericalCollider : public Controlled
{
public:
float mBounceFactor;
float mRadius;
osg::Vec3f mCenter;
void read(NIFStream *nif);
};
class NiParticleRotation : public Controlled
{
public:

@ -89,6 +89,7 @@ static std::map<std::string,RecordFactoryEntry> makeFactory()
newFactory.insert(makeEntry("NiStringExtraData", &construct <NiStringExtraData> , RC_NiStringExtraData ));
newFactory.insert(makeEntry("NiGravity", &construct <NiGravity> , RC_NiGravity ));
newFactory.insert(makeEntry("NiPlanarCollider", &construct <NiPlanarCollider> , RC_NiPlanarCollider ));
newFactory.insert(makeEntry("NiSphericalCollider", &construct <NiSphericalCollider> , RC_NiSphericalCollider ));
newFactory.insert(makeEntry("NiParticleGrowFade", &construct <NiParticleGrowFade> , RC_NiParticleGrowFade ));
newFactory.insert(makeEntry("NiParticleColorModifier", &construct <NiParticleColorModifier> , RC_NiParticleColorModifier ));
newFactory.insert(makeEntry("NiParticleRotation", &construct <NiParticleRotation> , RC_NiParticleRotation ));

@ -92,7 +92,8 @@ enum RecordType
RC_NiSequenceStreamHelper,
RC_NiSourceTexture,
RC_NiSkinInstance,
RC_RootCollisionNode
RC_RootCollisionNode,
RC_NiSphericalCollider
};
/// Base class for all records

@ -871,6 +871,13 @@ namespace NifOsg
const Nif::NiPlanarCollider* planarcollider = static_cast<const Nif::NiPlanarCollider*>(colliders.getPtr());
program->addOperator(new PlanarCollider(planarcollider));
}
else if (colliders->recType == Nif::RC_NiSphericalCollider)
{
const Nif::NiSphericalCollider* sphericalcollider = static_cast<const Nif::NiSphericalCollider*>(colliders.getPtr());
program->addOperator(new SphericalCollider(sphericalcollider));
}
else
std::cerr << "Unhandled particle collider " << colliders->recName << " in " << mFilename << std::endl;
}
}

@ -376,4 +376,73 @@ void PlanarCollider::operate(osgParticle::Particle *particle, double dt)
}
}
SphericalCollider::SphericalCollider(const Nif::NiSphericalCollider* collider)
: mBounceFactor(collider->mBounceFactor),
mSphere(collider->mCenter, collider->mRadius)
{
}
SphericalCollider::SphericalCollider()
: mBounceFactor(1.0f)
{
}
SphericalCollider::SphericalCollider(const SphericalCollider& copy, const osg::CopyOp& copyop)
: osgParticle::Operator(copy, copyop)
, mBounceFactor(copy.mBounceFactor)
, mSphere(copy.mSphere)
, mSphereInParticleSpace(copy.mSphereInParticleSpace)
{
}
void SphericalCollider::beginOperate(osgParticle::Program* program)
{
mSphereInParticleSpace = mSphere;
if (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF)
mSphereInParticleSpace.center() = program->transformLocalToWorld(mSphereInParticleSpace.center());
}
void SphericalCollider::operate(osgParticle::Particle* particle, double dt)
{
osg::Vec3f cent = (particle->getPosition() - mSphereInParticleSpace.center()); // vector from sphere center to particle
bool insideSphere = cent.length2() <= mSphereInParticleSpace.radius2();
if (insideSphere
|| (cent * particle->getVelocity() < 0.0f)) // if outside, make sure the particle is flying towards the sphere
{
// Collision test (finding point of contact) is performed by solving a quadratic equation:
// ||vec(cent) + vec(vel)*k|| = R /^2
// k^2 + 2*k*(vec(cent)*vec(vel))/||vec(vel)||^2 + (||vec(cent)||^2 - R^2)/||vec(vel)||^2 = 0
float b = -(cent * particle->getVelocity()) / particle->getVelocity().length2();
osg::Vec3f u = cent + particle->getVelocity() * b;
if (insideSphere
|| (u.length2() < mSphereInParticleSpace.radius2()))
{
float d = (mSphereInParticleSpace.radius2() - u.length2()) / particle->getVelocity().length2();
float k = insideSphere ? (std::sqrt(d) + b) : (b - std::sqrt(d));
if (k < dt)
{
// collision detected; reflect off the tangent plane
osg::Vec3f contact = particle->getPosition() + particle->getVelocity() * k;
osg::Vec3 normal = (contact - mSphereInParticleSpace.center());
normal.normalize();
float dotproduct = particle->getVelocity() * normal;
osg::Vec3 reflectedVelocity = particle->getVelocity() - normal * (2 * dotproduct);
reflectedVelocity *= mBounceFactor;
particle->setVelocity(reflectedVelocity);
}
}
}
}
}

@ -16,6 +16,7 @@ namespace Nif
{
class NiGravity;
class NiPlanarCollider;
class NiSphericalCollider;
class NiColorData;
}
@ -110,6 +111,23 @@ namespace NifOsg
osg::Plane mPlaneInParticleSpace;
};
class SphericalCollider : public osgParticle::Operator
{
public:
SphericalCollider(const Nif::NiSphericalCollider* collider);
SphericalCollider();
SphericalCollider(const SphericalCollider& copy, const osg::CopyOp& copyop);
META_Object(NifOsg, SphericalCollider)
virtual void beginOperate(osgParticle::Program* program);
virtual void operate(osgParticle::Particle* particle, double dt);
private:
float mBounceFactor;
osg::BoundingSphere mSphere;
osg::BoundingSphere mSphereInParticleSpace;
};
class GrowFadeAffector : public osgParticle::Operator
{
public:

Loading…
Cancel
Save