flockanimatortornado.cpp

00001 #include "debug.h"
00002 #include "flock.h"
00003 #include "boid.h"
00004 #include "flockanimatortornado.h"
00005 
00006 using namespace irr;
00007 using namespace core;
00008 using namespace scene;
00009 
00010 extern Debug* dbg;
00011 
00012 FlockAnimatorTornado::FlockAnimatorTornado(IrrlichtDevice* d)
00013 {
00014     // ctor
00015     device = d;
00016     pi = 3.1415926535897932384626433832795f;
00017     oneOverTwoPi = 1.0f / (2.0f * pi);
00018     fluidDensity = 1.225f;   
00019     gravitationalAccel = -9.8f;
00020     strength_0 = 0.5f;
00021     strength_500 = 250.0f;
00022     stormCenter = vector3df(0.0f, 0.0f, 0.0f);
00023         mass = 0.01f;                                       
00024         halfRhoSref = pi * 3 * 3 * 0.5f * fluidDensity;     
00025 
00026     dbg->log("create FlockAnimatorTornado");
00027 }
00028 
00029 FlockAnimatorTornado::~FlockAnimatorTornado()
00030 {
00031     // dtor
00032     dbg->log("FlockAnimatorTornado deleted");
00033 }
00034 
00035 void FlockAnimatorTornado::animateNode(ISceneNode* node, u32 timeMs)
00036 {
00037     // for each Boid in Flock
00038     Flock* f = ((Flock*) node);
00039     stormCenter = f->getTarget();
00040     list<Boid*>::Iterator it = f->getBoidList().begin();
00041     for (; it != f->getBoidList().end(); ++it)
00042     {
00043         vector3df force = getForce((*it), timeMs);
00044         force *= f->getTornadoWeight();
00045         (*it)->velocity += force;
00046 
00047         // debug
00048         if (it == f->getBoidList().begin())
00049         {
00050             dbg->show("first boid pos", (*it)->position);
00051             dbg->show("first boid force", force);
00052         }
00053     }
00054 
00056 }
00057 
00058 // calculate the storm strength at the sent altitude
00059 f32 FlockAnimatorTornado::getWindStrength(f32 altitude)
00060 {
00061         return (strength_0 + ((strength_500 - strength_0) * altitude * altitude / 250000.0f));
00062 }
00063 
00064 // calculate the wind velocity due to the storm, at the sent location
00066 vector3df FlockAnimatorTornado::getWindVelocity(vector3df location, u32 timeMs)
00067 {
00068     // return the resulting velosity;
00069     vector3df result;
00070 
00071         f32 dX = location.X - stormCenter.X;
00072         f32 dZ = location.Z - stormCenter.Z;
00073 
00074         f32 r = sqrtf(dX * dX + dZ * dZ);
00075         if (r < 1.e-4)
00076         {
00077                 r = 1.0f;
00078         }
00079 
00080     // for a true potential vortex, the velocity approaches
00081     // infinity at the core. We need to limit this to avoid
00082     // undesirable effects. We limit it here by artificially
00083     // forcing particles inside a certain radius to behave
00084     // as though they were at that limit radius. Another
00085     // approach would be to have the vortex strength fade
00086     // towards zero at the core.
00087         f32 oneOverR = 1.0f / r;
00088         if (oneOverR > 1.0f)
00089         {
00090                 oneOverR = 1.0f;
00091         }
00092 
00093     // TRUE_WIND_VELOCITY calculates the actual velocity at a point due to
00094     // a potential vortex. If this is NOT defined, a numerical approximation
00095     // to the velocity is calculated instead, based on the physics time step,
00096     // that is designed to keep a particle with zero mass on an exact circular
00097     // path (to floating point precision). The latter case can produce better
00098     // results, since it prevents particle drift due to anything other than
00099     // inertia. The former case, using the true potential vortex velocity,
00100     // will result in particles that drift away from a circular path just
00101     // due to truncation error in the time stepped solution.
00102     //#define TRUE_WIND_VELOCITY
00103 #define TRUE_WIND_VELOCITY
00104 #ifdef TRUE_WIND_VELOCITY
00105         f32 commonFactor = getWindStrength(location.Z) * oneOverR * oneOverTwoPi;
00106 
00107         result.X = dZ * commonFactor;          // original: location.Z * commonFactor
00108         result.Z = -dX * commonFactor;         // original: location.X * commonFactor
00109         vector3df dbgCheck=result;              
00110 
00111 #else
00112     f32 physicsTimeStep = timeMs / 1000.f;
00113         f32 tangentialVelocity = getWindStrength(location.Y) * oneOverR * oneOverTwoPi;
00114         f32 deltaAngle = tangentialVelocity * physicsTimeStep;
00115         f32 angle = atan2(dZ, dX) + deltaAngle;
00116         f32 newX = r * cos(angle);
00117         f32 newZ = r * sin(angle);
00118         result.X = (newX - location.X) / physicsTimeStep;
00119         result.Z = (newZ - location.Z) / physicsTimeStep;
00120 #endif // TRUE_WIND_VELOCITY
00121 
00122     // there is no vertical wind velocity due to the storm. We could add it to
00123     // get interesting effects, though.
00124         result.Y = 0.0f;
00125 
00126         return result;
00127 }
00128 
00129 vector3df FlockAnimatorTornado::getForce(Boid* b, u32 timeMs)
00130 {
00131         vector3df result;
00132         vector3df wind;
00133         vector3df force;
00134         f32 dragMagnitude;
00135         f32 relwind_squared;
00136         f32 speed;
00137 
00138         wind = getWindVelocity(b->position, timeMs);
00139 
00140         // turn wind into relative wind and compute its magnitude squared
00141         wind -= b->velocity;
00142 
00143         relwind_squared = wind.X * wind.X + wind.Y * wind.Y + wind.Z * wind.Z;
00144     speed = sqrtf(relwind_squared);
00145 
00146     // calculate the drag force. Assume Reynold's Number
00147         // is between 2000 and 200,000, and, therefore,
00148         // drag coefficient is roughly a constant at 0.4.
00149         const float cd = 0.4f;
00150 
00151     dragMagnitude = halfRhoSref * relwind_squared * cd;
00152 
00153     // wind / speed gives the direction of the drag force
00154     force = wind * dragMagnitude / speed;
00155 
00156         // increment the force to add in the weight of the particle.
00157         force.Y += gravitationalAccel * mass;
00158 
00159     // increment the velocity based on acceleration due to applied
00160         // forces. This is a simple Euler integration, which is easy
00161         // but certainly NOT the best choice for a robust game physics
00162         // implementation!
00163         result = force / mass;
00164 
00165     return result;
00166 }
00167 

Generated on Sun Dec 2 17:09:57 2007 for Swarm by  doxygen 1.4.6-NO