forked from mirror/openmw-tes3mp
Merge pull request #1147 from MiroslavR/NiSphericalCollider
Implement NiSphericalCollider (Closes #3644)
This commit is contained in:
commit
9febb3e824
7 changed files with 116 additions and 1 deletions
|
@ -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…
Reference in a new issue