From c28f997c8723cdf0ae561f205229e5b4d2fcf7fe Mon Sep 17 00:00:00 2001 From: Alexei Dobrohotov Date: Sun, 3 Apr 2022 23:05:01 +0300 Subject: [PATCH] Make NiPlanarCollider finite-size --- components/nif/controlled.cpp | 8 ++--- components/nif/controlled.hpp | 7 +++-- components/nifosg/particle.cpp | 57 ++++++++++++++++++++++++---------- components/nifosg/particle.hpp | 11 ++++--- 4 files changed, 57 insertions(+), 26 deletions(-) diff --git a/components/nif/controlled.cpp b/components/nif/controlled.cpp index 73359aeb2a..0491dd7d98 100644 --- a/components/nif/controlled.cpp +++ b/components/nif/controlled.cpp @@ -111,11 +111,11 @@ namespace Nif void NiPlanarCollider::read(NIFStream *nif) { NiParticleCollider::read(nif); - /* osg::Vec2f mExtents = */nif->getVector2(); - /* osg::Vec3f mPosition = */nif->getVector3(); - /* osg::Vec3f mXVector = */nif->getVector3(); - /* osg::Vec3f mYVector = */nif->getVector3(); + mExtents = nif->getVector2(); + mPosition = nif->getVector3(); + mXVector = nif->getVector3(); + mYVector = nif->getVector3(); mPlaneNormal = nif->getVector3(); mPlaneDistance = nif->getFloat(); } diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 0d93381eab..5094f1fd87 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -131,10 +131,13 @@ struct NiParticleCollider : public NiParticleModifier // NiPinaColada struct NiPlanarCollider : public NiParticleCollider { - void read(NIFStream *nif) override; - + osg::Vec2f mExtents; + osg::Vec3f mPosition; + osg::Vec3f mXVector, mYVector; osg::Vec3f mPlaneNormal; float mPlaneDistance; + + void read(NIFStream *nif) override; }; struct NiSphericalCollider : public NiParticleCollider diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 493143a7a3..3b66a956e8 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -468,18 +468,24 @@ void FindGroupByRecIndex::applyNode(osg::Node &searchNode) PlanarCollider::PlanarCollider(const Nif::NiPlanarCollider *collider) : mBounceFactor(collider->mBounceFactor) + , mExtents(collider->mExtents) + , mPosition(collider->mPosition) + , mXVector(collider->mXVector) + , mYVector(collider->mYVector) , 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) + , mExtents(copy.mExtents) + , mPosition(copy.mPosition) + , mPositionInParticleSpace(copy.mPositionInParticleSpace) + , mXVector(copy.mXVector) + , mXVectorInParticleSpace(copy.mXVectorInParticleSpace) + , mYVector(copy.mYVector) + , mYVectorInParticleSpace(copy.mYVectorInParticleSpace) , mPlane(copy.mPlane) , mPlaneInParticleSpace(copy.mPlaneInParticleSpace) { @@ -487,25 +493,44 @@ PlanarCollider::PlanarCollider(const PlanarCollider ©, const osg::CopyOp &co void PlanarCollider::beginOperate(osgParticle::Program *program) { + mPositionInParticleSpace = mPosition; mPlaneInParticleSpace = mPlane; + mXVectorInParticleSpace = mXVector; + mYVectorInParticleSpace = mYVector; if (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF) + { + mPositionInParticleSpace = program->transformLocalToWorld(mPosition); mPlaneInParticleSpace.transform(program->getLocalToWorldMatrix()); + mXVectorInParticleSpace = program->rotateLocalToWorld(mXVector); + mYVectorInParticleSpace = program->rotateLocalToWorld(mYVector); + } } void PlanarCollider::operate(osgParticle::Particle *particle, double dt) { - float dotproduct = particle->getVelocity() * mPlaneInParticleSpace.getNormal(); + // Does the particle in question move towards the collider? + float velDotProduct = particle->getVelocity() * mPlaneInParticleSpace.getNormal(); + if (velDotProduct <= 0) + return; - 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); - } - } + // Does it intersect the collider's plane? + osg::BoundingSphere bs(particle->getPosition(), 0.f); + if (mPlaneInParticleSpace.intersect(bs) != 1) + return; + + // Is it inside the collider's bounds? + osg::Vec3f relativePos = particle->getPosition() - mPositionInParticleSpace; + float xDotProduct = relativePos * mXVectorInParticleSpace; + float yDotProduct = relativePos * mYVectorInParticleSpace; + if (-mExtents.x() * 0.5f > xDotProduct || mExtents.x() * 0.5f < xDotProduct) + return; + if (-mExtents.y() * 0.5f > yDotProduct || mExtents.y() * 0.5f < yDotProduct) + return; + + // Deflect the particle + osg::Vec3 reflectedVelocity = particle->getVelocity() - mPlaneInParticleSpace.getNormal() * (2 * velDotProduct); + reflectedVelocity *= mBounceFactor; + particle->setVelocity(reflectedVelocity); } SphericalCollider::SphericalCollider(const Nif::NiSphericalCollider* collider) diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 9e68cdf347..155d35ad2c 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -104,7 +104,7 @@ namespace NifOsg { public: PlanarCollider(const Nif::NiPlanarCollider* collider); - PlanarCollider(); + PlanarCollider() = default; PlanarCollider(const PlanarCollider& copy, const osg::CopyOp& copyop); META_Object(NifOsg, PlanarCollider) @@ -113,9 +113,12 @@ namespace NifOsg void operate(osgParticle::Particle* particle, double dt) override; private: - float mBounceFactor; - osg::Plane mPlane; - osg::Plane mPlaneInParticleSpace; + float mBounceFactor{0.f}; + osg::Vec2f mExtents; + osg::Vec3f mPosition, mPositionInParticleSpace; + osg::Vec3f mXVector, mXVectorInParticleSpace; + osg::Vec3f mYVector, mYVectorInParticleSpace; + osg::Plane mPlane, mPlaneInParticleSpace; }; class SphericalCollider : public osgParticle::Operator