817 lines
24 KiB
C++
817 lines
24 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#ifndef NL_PS_FORCE_H
|
|
#define NL_PS_FORCE_H
|
|
|
|
#include "nel/misc/types_nl.h"
|
|
#include "nel/3d/ps_located.h"
|
|
#include "nel/3d/ps_util.h"
|
|
#include "nel/3d/ps_attrib_maker.h"
|
|
#include "nel/3d/ps_edit.h"
|
|
#include "nel/3d/ps_direction.h"
|
|
#include "nel/3d/particle_system.h"
|
|
|
|
|
|
namespace NL3D {
|
|
|
|
class CPSEmitterInfo;
|
|
|
|
/**
|
|
* All forces in the system derive from this class
|
|
* It has a list with all located on which the force can apply.
|
|
* Only the motion and toolRender passes are supported for a force.
|
|
* Not sharable accross systems.
|
|
* \author Nicolas Vizerie
|
|
* \author Nevrax France
|
|
* \date 2001
|
|
*/
|
|
class CPSForce : public CPSTargetLocatedBindable
|
|
{
|
|
public:
|
|
|
|
/// Constructor
|
|
CPSForce();
|
|
|
|
/// return this bindable type
|
|
uint32 getType(void) const { return PSForce; }
|
|
|
|
|
|
/// return priority for forces
|
|
|
|
virtual uint32 getPriority(void) const { return 4000; }
|
|
|
|
/// Override of CPSLocatedBindable::doesProduceBBox. forces usually are not part of the bbox
|
|
virtual bool doesProduceBBox(void) const { return false; }
|
|
|
|
/**
|
|
* process one pass for the force
|
|
*/
|
|
virtual void step(TPSProcessPass pass);
|
|
|
|
|
|
/// Compute the force on the targets. To be called inside the sim loop
|
|
virtual void computeForces(CPSLocated &target) = 0;
|
|
|
|
/// Show the force (edition mode)
|
|
virtual void show() = 0;
|
|
|
|
/// Serial the force definition. MUST be called by deriver during their serialisation
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
|
|
/// check whether this force is integrable over time. The default is false
|
|
virtual bool isIntegrable(void) const { return false; }
|
|
|
|
/// inherited from CPSLocatedBindableTarget, we use that to tell whether this force is integrable or not
|
|
virtual void attachTarget(CPSLocated *ptr);
|
|
|
|
/// inherited from CPSLocatedBindableTarget
|
|
void releaseTargetRsc(CPSLocated *target);
|
|
|
|
|
|
/** Integrate this force on the given located. If 'accumulate' is set to true, it just add the effect of this force on position
|
|
* otherwise, it must also integrate from the initial speed, and add this force effect. The first call to this must be done with
|
|
* 'accumulate' set to false.
|
|
* NB : works only with integrable forces
|
|
*/
|
|
virtual void integrate(float /* date */, CPSLocated * /* src */, uint32 /* startIndex */, uint32 /* numObjects */, NLMISC::CVector * /* destPos */ = NULL, NLMISC::CVector * /* destSpeed */ = NULL,
|
|
bool /* accumulate */ = false,
|
|
uint /* posStride */ = sizeof(NLMISC::CVector), uint /* speedStride */ = sizeof(NLMISC::CVector)
|
|
) const
|
|
{
|
|
nlassert(0); // not an integrable force
|
|
}
|
|
|
|
|
|
/** Compute a trajectory on several steps for a single object, rather than a step for several object.
|
|
* If the start date is lower than the creation date, the initial position is used
|
|
* NB : works only with integrable forces
|
|
*/
|
|
virtual void integrateSingle(float /* startDate */, float /* deltaT */, uint /* numStep */,
|
|
const CPSLocated * /* src */, uint32 /* indexInLocated */,
|
|
NLMISC::CVector * /* destPos */,
|
|
bool /* accumulate */ = false,
|
|
uint /* posStride */ = sizeof(NLMISC::CVector)) const
|
|
{
|
|
nlassert(0); // not an integrable force
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected:
|
|
friend class CPSLocated;
|
|
friend class CPSForceIntensity;
|
|
|
|
/// register integrable and non-integrable forces to the targets
|
|
void registerToTargets(void);
|
|
|
|
/// if this force is not integrable anymore, it tells that to its targets
|
|
void cancelIntegrable(void);
|
|
|
|
/// if this force has become integrable again, this method tells it to the target
|
|
void renewIntegrable(void);
|
|
|
|
/** inherited from CPSLocatedBindable. When we deal with integrable forces,
|
|
* they must be in the same basis than their target. If this change, we must notify the target of it.
|
|
*/
|
|
virtual void basisChanged(TPSMatrixMode systemBasis);
|
|
|
|
virtual void newElement(const CPSEmitterInfo &info) = 0;
|
|
|
|
/** Delete an element given its index
|
|
* Attributes of the located that hold this bindable are still accessible for of the index given
|
|
* index out of range -> nl_assert
|
|
*/
|
|
virtual void deleteElement(uint32 index) = 0;
|
|
|
|
/** Resize the bindable attributes containers DERIVERS SHOULD CALL THEIR PARENT VERSION
|
|
* should not be called directly. Call CPSLOcated::resize instead
|
|
*/
|
|
virtual void resize(uint32 size) = 0;
|
|
};
|
|
|
|
|
|
/// this is a class to set force instensity (acceleration for gravity, k coefficient for springs...)
|
|
class CPSForceIntensity
|
|
{
|
|
public:
|
|
|
|
// ctor
|
|
CPSForceIntensity() : _IntensityScheme(NULL)
|
|
{
|
|
}
|
|
|
|
virtual ~CPSForceIntensity();
|
|
|
|
|
|
/// get the constant intensity that was set for the force
|
|
float getIntensity(void) const { return _K; }
|
|
|
|
/// set a constant intensity for the force. this discard any previous call to setIntensityScheme
|
|
virtual void setIntensity(float value);
|
|
|
|
/// set a non-constant intensity
|
|
virtual void setIntensityScheme(CPSAttribMaker<float> *scheme);
|
|
|
|
// deriver have here the opportunity to setup the functor object. The default does nothing
|
|
virtual void setupFunctor(uint32 /* indexInLocated */) { }
|
|
|
|
/// get the attribute maker for a non constant intensity
|
|
CPSAttribMaker<float> *getIntensityScheme(void) { return _IntensityScheme; }
|
|
const CPSAttribMaker<float> *getIntensityScheme(void) const { return _IntensityScheme; }
|
|
void serialForceIntensity(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
|
|
protected:
|
|
|
|
/// deriver must return the located that own them here
|
|
virtual CPSLocated *getForceIntensityOwner(void) = 0;
|
|
|
|
|
|
// the intensity ...
|
|
float _K;
|
|
CPSAttribMaker<float> *_IntensityScheme;
|
|
|
|
void newForceIntensityElement(const CPSEmitterInfo &info)
|
|
{
|
|
if (_IntensityScheme && _IntensityScheme->hasMemory()) _IntensityScheme->newElement(info);
|
|
}
|
|
void deleteForceIntensityElement(uint32 index)
|
|
{
|
|
if (_IntensityScheme && _IntensityScheme->hasMemory()) _IntensityScheme->deleteElement(index);
|
|
}
|
|
void resizeForceIntensity(uint32 size)
|
|
{
|
|
if (_IntensityScheme && _IntensityScheme->hasMemory()) _IntensityScheme->resize(size, getForceIntensityOwner()->getSize());
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* this class defines the newElement, deleteElement, and resize method of a class that derives from CPSForceIntensity
|
|
* And that don't add per paerticle attribute
|
|
*/
|
|
class CPSForceIntensityHelper : public CPSForce, public CPSForceIntensity
|
|
{
|
|
public:
|
|
void serial(NLMISC::IStream &f) throw(NLMISC::EStream) ;
|
|
|
|
protected:
|
|
virtual CPSLocated *getForceIntensityOwner(void) { return _Owner; }
|
|
virtual void newElement(const CPSEmitterInfo &info) { newForceIntensityElement(info); }
|
|
virtual void deleteElement(uint32 index) { deleteForceIntensityElement(index); }
|
|
virtual void resize(uint32 size) { resizeForceIntensity(size); }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** a helper class to create isotropic force : they are independant of the basis, and have no position
|
|
* (fluid friction for example)
|
|
* To use this class you should provide to it a functor class that define the () operator with 3 parameters
|
|
* param1 = a const reference to the position of the particle
|
|
* param2 = a reference to the position, that must be updated
|
|
* param3 = a float giving the inverse of the mass
|
|
* param4 = the ellapsed time, in second (has the TAnimationTime type).
|
|
* Example of use :
|
|
* class MyForceFunctor
|
|
* {
|
|
* public:
|
|
* /// it is strongly recommended to have your operator inlined
|
|
* void operator() (const NLMISC::CVector &pos, NLMISC::CVector &speed, float invMass , CanimationTime ellapsedTime)
|
|
* {
|
|
* // perform the speed update there
|
|
* }
|
|
*
|
|
* // you can provide a serialization method. Note that that if the functor parameters are set before each use,
|
|
* // it useless to serial something ...
|
|
* void serial(NLMISC::IStream &f) throw(NLMISC::EStream)
|
|
*
|
|
* protected:
|
|
* ...
|
|
* };
|
|
*
|
|
*
|
|
* because of the serialization process, you must proceed like the following. (but you don't need to redefine serial, which
|
|
* will serilize the functor object you passed for you
|
|
*
|
|
* class MyForce : public CHomogenousForceT<MyForceFunctor>
|
|
* {
|
|
* public:
|
|
* MyForce();
|
|
* NLMISC_DECLARE_CLASS(Myforce);
|
|
*
|
|
* protected:
|
|
* ...
|
|
*
|
|
* };
|
|
*
|
|
*
|
|
* not that each functor may have its own parameter. the setupFunctor method will be called each time
|
|
*/
|
|
|
|
template <class T> class CIsotropicForceT : public CPSForce
|
|
{
|
|
public:
|
|
|
|
/// Compute the force on the targets
|
|
virtual void computeForces(CPSLocated &target);
|
|
|
|
|
|
/// serialization
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream)
|
|
{
|
|
f.serialVersion(1);
|
|
CPSForce::serial(f);
|
|
f.serial(_F); // serial the functor object 5does nothing most of the time ...)
|
|
}
|
|
|
|
|
|
/** Show the force (edition mode). The default does nothing
|
|
* TODO later
|
|
*/
|
|
|
|
void show() {}
|
|
|
|
|
|
/// setup the functor object. The default does nothing
|
|
|
|
virtual void setupFunctor(uint32 /* index */) {}
|
|
|
|
protected:
|
|
|
|
/// the functor object
|
|
T _F;
|
|
|
|
|
|
|
|
virtual void newElement(const CPSEmitterInfo &/* info */) {}
|
|
virtual void deleteElement(uint32 /* index */) {}
|
|
virtual void resize(uint32 /* size */) {}
|
|
|
|
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// implementation of method of the template class CHomogenousForceT //
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
template <class T> void CIsotropicForceT<T>::computeForces(CPSLocated &target)
|
|
{
|
|
nlassert(CParticleSystem::InsideSimLoop);
|
|
for (uint32 k = 0; k < _Owner->getSize(); ++k)
|
|
{
|
|
setupFunctor(k);
|
|
TPSAttribVector::iterator speedIt = target.getSpeed().begin(), endSpeedIt = target.getSpeed().end();
|
|
TPSAttribVector::const_iterator posIt = target.getPos().begin();
|
|
TPSAttribFloat::const_iterator invMassIt = target.getInvMass().begin();
|
|
|
|
for (; speedIt != endSpeedIt; ++speedIt, ++posIt, ++invMassIt)
|
|
{
|
|
_F(*posIt, *speedIt, *invMassIt);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* a force that has the same direction everywhere. Mass is also taken in account (which is not the case for gravity)
|
|
*/
|
|
|
|
class CPSDirectionnalForce : public CPSForceIntensityHelper, public CPSDirection
|
|
{
|
|
public:
|
|
/// Compute the force on the targets
|
|
virtual void computeForces(CPSLocated &target);
|
|
|
|
/// Show the force (edition mode)
|
|
virtual void show();
|
|
|
|
|
|
|
|
CPSDirectionnalForce(float i = 1.f)
|
|
{
|
|
if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("DirectionnalForce");
|
|
setIntensity(i);
|
|
_Dir = NLMISC::CVector(0, 0, -1);
|
|
}
|
|
|
|
/// serialization
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
|
|
|
|
NLMISC_DECLARE_CLASS(CPSDirectionnalForce);
|
|
|
|
///\name From CPSDirection
|
|
//@{
|
|
/// set the direction of the force
|
|
virtual void setDir(const NLMISC::CVector &dir) { _Dir = dir; }
|
|
/// get the direction of the force
|
|
virtual NLMISC::CVector getDir(void) const { return _Dir; }
|
|
// Tells that a global vector value of the system can be used as a direction
|
|
virtual bool supportGlobalVectorValue() const { return true; }
|
|
/// Bind the direction to a global vaariable (e.g "WIND" ). The value can be changed in CParticleSystem::setGlobalVectorValue
|
|
virtual void enableGlobalVectorValue(const std::string &name);
|
|
// See if the direction is bound to a global variable. Return an empty string if not
|
|
virtual std::string getGlobalVectorValueName() const;
|
|
//@}
|
|
protected:
|
|
NLMISC::CVector _Dir;
|
|
CParticleSystem::CGlobalVectorValueHandle _GlobalValueHandle; // a global vector value may override the value of _Dir (example of use : global direction for wind)
|
|
};
|
|
|
|
|
|
/// a gravity class. Mass isn't taken in account (true with a uniform gravity model, near earth )
|
|
class CPSGravity : public CPSForceIntensityHelper
|
|
{
|
|
public:
|
|
/// Compute the force on the targets
|
|
virtual void computeForces(CPSLocated &target);
|
|
|
|
/// Show the force (edition mode)
|
|
virtual void show();
|
|
|
|
|
|
|
|
CPSGravity(float g = 9.8f)
|
|
{
|
|
if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("Gravity");
|
|
setIntensity(g);
|
|
}
|
|
|
|
/// serialization
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
|
|
NLMISC_DECLARE_CLASS(CPSGravity);
|
|
|
|
|
|
virtual bool isIntegrable(void) const;
|
|
|
|
/// inherited from CPSForce
|
|
virtual void integrate(float date, CPSLocated *src, uint32 startIndex, uint32 numObjects, NLMISC::CVector *destPos = NULL, NLMISC::CVector *destSpeed = NULL,
|
|
bool accumulate = false,
|
|
uint posStride = sizeof(NLMISC::CVector), uint speedStride = sizeof(NLMISC::CVector)
|
|
) const;
|
|
|
|
virtual void integrateSingle(float startDate, float deltaT, uint numStep,
|
|
const CPSLocated *src, uint32 indexInLocated,
|
|
NLMISC::CVector *destPos,
|
|
bool accumulate = false,
|
|
uint posStride = sizeof(NLMISC::CVector)) const;
|
|
|
|
protected:
|
|
/// inherited from CPSForceIntensityHelper
|
|
virtual void setIntensity(float value);
|
|
/// inherited from CPSForceIntensityHelper
|
|
virtual void setIntensityScheme(CPSAttribMaker<float> *scheme);
|
|
};
|
|
|
|
|
|
/// a central gravity class. Mass is taken in account here
|
|
class CPSCentralGravity : public CPSForceIntensityHelper
|
|
{
|
|
public:
|
|
/// Compute the force on the targets
|
|
virtual void computeForces(CPSLocated &target);
|
|
|
|
/// Show the force (edition mode)
|
|
virtual void show();
|
|
|
|
|
|
|
|
CPSCentralGravity(float i = 1.f)
|
|
{
|
|
if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("CentralGravity");
|
|
setIntensity(i);
|
|
}
|
|
|
|
/// serialization
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
|
|
|
|
NLMISC_DECLARE_CLASS(CPSCentralGravity);
|
|
};
|
|
|
|
|
|
/// a spring class
|
|
class CPSSpring : public CPSForceIntensityHelper
|
|
{
|
|
public:
|
|
|
|
/// ctor : k is the coefficient of the spring
|
|
CPSSpring(float k = 1.0f)
|
|
{
|
|
if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("Spring");
|
|
setIntensity(k);
|
|
}
|
|
|
|
|
|
/// serialization
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
|
|
|
|
/// Compute the force on the targets
|
|
virtual void computeForces(CPSLocated &target);
|
|
|
|
/// Show the force (edition mode)
|
|
virtual void show();
|
|
|
|
|
|
NLMISC_DECLARE_CLASS(CPSSpring);
|
|
|
|
};
|
|
|
|
|
|
|
|
/// a fluid friction functor, it is used by the fluid friction class
|
|
class CPSFluidFrictionFunctor
|
|
{
|
|
public:
|
|
CPSFluidFrictionFunctor() : _K(1.f)
|
|
{
|
|
}
|
|
|
|
virtual ~CPSFluidFrictionFunctor() {}
|
|
|
|
#ifdef NL_OS_WINDOWS
|
|
__forceinline
|
|
#endif
|
|
void operator() (const NLMISC::CVector &/* pos */, NLMISC::CVector &speed, float invMass)
|
|
{
|
|
speed -= (CParticleSystem::EllapsedTime * _K * invMass * speed);
|
|
}
|
|
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream)
|
|
{
|
|
f.serialVersion(1);
|
|
// we don't save intensity info : it is saved by the owning object (and set before each use of this functor)
|
|
}
|
|
|
|
// get the friction coefficient
|
|
float getK(void) const { return _K; }
|
|
|
|
// set the friction coefficient
|
|
void setK(float coeff) { _K = coeff; }
|
|
protected:
|
|
// the friction coeff
|
|
float _K;
|
|
};
|
|
|
|
|
|
/** the fluid friction force. We don't derive from CPSForceIntensityHelper (which derives from CPSForce
|
|
* , because CIsotropicForceT also derives from CPSForce, and we don't want to use virtual inheritance
|
|
*/
|
|
|
|
|
|
class CPSFluidFriction : public CIsotropicForceT<CPSFluidFrictionFunctor>, public CPSForceIntensity
|
|
{
|
|
public:
|
|
// create the force with a friction coefficient
|
|
CPSFluidFriction(float frictionCoeff = 1.f)
|
|
{
|
|
setIntensity(frictionCoeff);
|
|
if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("FluidFriction");
|
|
}
|
|
|
|
// inherited from CIsotropicForceT
|
|
virtual void setupFunctor(uint32 index)
|
|
{
|
|
_F.setK(_IntensityScheme ? _IntensityScheme->get(_Owner, index) : _K);
|
|
}
|
|
|
|
NLMISC_DECLARE_CLASS(CPSFluidFriction)
|
|
|
|
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream)
|
|
{
|
|
f.serialVersion(1);
|
|
CIsotropicForceT<CPSFluidFrictionFunctor>::serial(f);
|
|
serialForceIntensity(f);
|
|
if (f.isReading())
|
|
{
|
|
registerToTargets();
|
|
}
|
|
}
|
|
|
|
|
|
protected:
|
|
virtual CPSLocated *getForceIntensityOwner(void) { return _Owner; }
|
|
virtual void newElement(const CPSEmitterInfo &info) { newForceIntensityElement(info); }
|
|
virtual void deleteElement(uint32 index) { deleteForceIntensityElement(index); }
|
|
virtual void resize(uint32 size) { resizeForceIntensity(size); }
|
|
};
|
|
|
|
|
|
/** A Brownian motion
|
|
*/
|
|
|
|
|
|
class CPSBrownianForce : public CPSForceIntensityHelper
|
|
{
|
|
public:
|
|
// create the force with a friction coefficient
|
|
CPSBrownianForce(float intensity = 1.f);
|
|
|
|
NLMISC_DECLARE_CLASS(CPSBrownianForce)
|
|
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
|
|
/// We provide a kind of integration on a predefined sequence
|
|
virtual bool isIntegrable(void) const;
|
|
|
|
virtual void integrate(float date, CPSLocated *src, uint32 startIndex, uint32 numObjects, NLMISC::CVector *destPos = NULL, NLMISC::CVector *destSpeed = NULL,
|
|
bool accumulate = false,
|
|
uint posStride = sizeof(NLMISC::CVector), uint speedStride = sizeof(NLMISC::CVector)
|
|
) const;
|
|
|
|
virtual void integrateSingle(float startDate, float deltaT, uint numStep,
|
|
const CPSLocated *src, uint32 indexInLocated,
|
|
NLMISC::CVector *destPos,
|
|
bool accumulate = false,
|
|
uint posStride = sizeof(NLMISC::CVector)) const;
|
|
|
|
/// perform initialisations
|
|
static void initPrecalc();
|
|
|
|
void setIntensity(float value);
|
|
void setIntensityScheme(CPSAttribMaker<float> *scheme);
|
|
|
|
/// Compute the force on the targets
|
|
virtual void computeForces(CPSLocated &target);
|
|
|
|
void show() {}
|
|
|
|
|
|
/** When used with parametric integration, this tells factor tells how fast the force acts on particle
|
|
* (how fast it go through the lookup table in fact)
|
|
*/
|
|
void setParametricFactor(float factor) { _ParametricFactor = factor; }
|
|
float getParametricFactor() const { return _ParametricFactor; }
|
|
|
|
protected:
|
|
virtual CPSLocated *getForceIntensityOwner(void) { return _Owner; }
|
|
virtual void newElement(const CPSEmitterInfo &info) { newForceIntensityElement(info); }
|
|
virtual void deleteElement(uint32 index) { deleteForceIntensityElement(index); }
|
|
virtual void resize(uint32 size) { resizeForceIntensity(size); }
|
|
|
|
float _ParametricFactor; // tells how fast this force act on a particle when parametric motion is used
|
|
static NLMISC::CVector PrecomputedPos[]; // after the sequence we must be back to the start position
|
|
static NLMISC::CVector PrecomputedSpeed[];
|
|
|
|
/// various impulsion for normal motion
|
|
static NLMISC::CVector PrecomputedImpulsions[];
|
|
|
|
};
|
|
|
|
|
|
/// a turbulence force functor
|
|
|
|
struct CPSTurbulForceFunc
|
|
{
|
|
virtual ~CPSTurbulForceFunc() {}
|
|
|
|
#ifdef NL_OS_WINDOWS
|
|
__forceinline
|
|
#endif
|
|
void operator() (const NLMISC::CVector &/* pos */, NLMISC::CVector &/* speed */, float /* invMass */)
|
|
{
|
|
nlassert(0);
|
|
|
|
// TODO : complete that
|
|
|
|
/* static const NLMISC::CVector v1(1.235f, - 45.32f, 157.5f);
|
|
static const NLMISC::CVector v2(-0.35f, 7.77f, 220.77f);
|
|
|
|
|
|
speed += ellapsedTime * _Intensity
|
|
* NLMISC::CVector(2.f * (-0.5f + CPSUtil::buildPerlinNoise(_Scale * pos, _NumOctaves))
|
|
, 2.f * (-0.5f + CPSUtil::buildPerlinNoise(_Scale * (pos + v1) , _NumOctaves))
|
|
, 2.f * (-0.5f + CPSUtil::buildPerlinNoise(_Scale * (pos + v2) , _NumOctaves))
|
|
);
|
|
*/
|
|
}
|
|
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream)
|
|
{
|
|
f.serialVersion(1);
|
|
f.serial(_Scale, _NumOctaves);
|
|
}
|
|
|
|
float _Scale;
|
|
float _Intensity;
|
|
uint32 _NumOctaves;
|
|
};
|
|
|
|
|
|
|
|
// the turbulence force
|
|
|
|
class CPSTurbul : public CIsotropicForceT<CPSTurbulForceFunc>, public CPSForceIntensity
|
|
{
|
|
public:
|
|
// create the force with a friction coefficient
|
|
CPSTurbul(float scale = 1.f , uint numOctaves = 4)
|
|
{
|
|
nlassert(numOctaves > 0);
|
|
setScale(scale);
|
|
setNumOctaves(numOctaves);
|
|
if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("Turbulence");
|
|
}
|
|
|
|
|
|
float getScale(void) const { return _F._Scale; }
|
|
void setScale(float scale) { _F._Scale = scale; }
|
|
|
|
|
|
uint getNumOctaves(void) const { return _F._NumOctaves; }
|
|
void setNumOctaves(uint numOctaves) { _F._NumOctaves = numOctaves; }
|
|
|
|
|
|
NLMISC_DECLARE_CLASS(CPSTurbul)
|
|
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream)
|
|
{
|
|
f.serialVersion(1);
|
|
CIsotropicForceT<CPSTurbulForceFunc>::serial(f);
|
|
serialForceIntensity(f);
|
|
if (f.isReading())
|
|
{
|
|
registerToTargets();
|
|
}
|
|
}
|
|
|
|
// inherited from CIsotropicForceT
|
|
virtual void setupFunctor(uint32 index)
|
|
{
|
|
_F._Intensity = (_IntensityScheme ? _IntensityScheme->get(_Owner, index) : _K);
|
|
}
|
|
|
|
protected:
|
|
virtual CPSLocated *getForceIntensityOwner(void) { return _Owner; }
|
|
virtual void newElement(const CPSEmitterInfo &info) { newForceIntensityElement(info); }
|
|
virtual void deleteElement(uint32 index) { deleteForceIntensityElement(index); }
|
|
virtual void resize(uint32 size) { resizeForceIntensity(size); }
|
|
};
|
|
|
|
|
|
|
|
|
|
/** a cylindric vortex. It has a limited extend
|
|
* It has unlimited extension in the z direction
|
|
* The model is aimed at tunability rather than realism
|
|
*/
|
|
|
|
class CPSCylindricVortex : public CPSForceIntensityHelper, public IPSMover
|
|
{
|
|
public:
|
|
/// Compute the force on the targets
|
|
virtual void computeForces(CPSLocated &target);
|
|
|
|
/// Show the force (edition mode)
|
|
virtual void show();
|
|
|
|
|
|
CPSCylindricVortex(float intensity = 1.f) : _RadialViscosity(.1f), _TangentialViscosity(.1f)
|
|
{
|
|
setIntensity(intensity);
|
|
if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("Cylindric Vortex");
|
|
}
|
|
|
|
// inherited from IPSMover
|
|
virtual bool supportUniformScaling(void) const { return true; }
|
|
virtual bool supportNonUniformScaling(void) const { return false; }
|
|
virtual void setScale(uint32 k, float scale) { _Radius[k] = scale; }
|
|
virtual NLMISC::CVector getScale(uint32 k) const { return NLMISC::CVector(_Radius[k], _Radius[k], _Radius[k]); }
|
|
virtual bool onlyStoreNormal(void) const { return true; }
|
|
virtual NLMISC::CVector getNormal(uint32 index) { return _Normal[index]; }
|
|
virtual void setNormal(uint32 index, NLMISC::CVector n) { _Normal[index] = n; }
|
|
|
|
virtual void setMatrix(uint32 index, const NLMISC::CMatrix &m);
|
|
virtual NLMISC::CMatrix getMatrix(uint32 index) const;
|
|
|
|
|
|
void setRadialViscosity(float v) { _RadialViscosity = v; }
|
|
float getRadialViscosity(void) const { return _RadialViscosity; }
|
|
|
|
void setTangentialViscosity(float v) { _TangentialViscosity = v; }
|
|
float getTangentialViscosity(void) const { return _TangentialViscosity; }
|
|
|
|
NLMISC_DECLARE_CLASS(CPSCylindricVortex);
|
|
|
|
|
|
|
|
// serialization
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
/// inherited from CPSForceIntensity
|
|
virtual CPSLocated *getForceIntensityOwner(void) { return _Owner; }
|
|
|
|
// the normal of the vortex
|
|
CPSAttrib<NLMISC::CVector> _Normal;
|
|
// radius of the vortex
|
|
TPSAttribFloat _Radius;
|
|
|
|
// radial viscosity : when it is near of 1, if tends to set the radial componenent of speed to 0
|
|
float _RadialViscosity;
|
|
|
|
// tangential viscosity : when set to 1, the tangential speed immediatly reach what it would be in a real vortex (w = 1 / r2)
|
|
float _TangentialViscosity;
|
|
|
|
virtual void newElement(const CPSEmitterInfo &info);
|
|
virtual void deleteElement(uint32 index);
|
|
virtual void resize(uint32 size);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
* a magnetic field that has the given direction
|
|
*/
|
|
class CPSMagneticForce : public CPSDirectionnalForce
|
|
{
|
|
public:
|
|
CPSMagneticForce(float i = 1.f) : CPSDirectionnalForce(i)
|
|
{
|
|
if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("MagneticForce");
|
|
}
|
|
virtual void computeForces(CPSLocated &target);
|
|
/// serialization
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
NLMISC_DECLARE_CLASS(CPSMagneticForce);
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
} // NL3D
|
|
|
|
|
|
#endif // NL_PS_FORCE_H
|
|
|
|
/* End of ps_force.h */
|