ParticleEmitter.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. #include "anki/scene/ParticleEmitter.h"
  2. #include "anki/scene/Scene.h"
  3. #include "anki/resource/Model.h"
  4. #include "anki/util/Functions.h"
  5. #include "anki/physics/PhysWorld.h"
  6. #include <limits>
  7. namespace anki {
  8. //==============================================================================
  9. // Misc =
  10. //==============================================================================
  11. //==============================================================================
  12. F32 getRandom(F32 initial, F32 deviation)
  13. {
  14. return (deviation == 0.0) ? initial
  15. : initial + randFloat(deviation) * 2.0 - deviation;
  16. }
  17. //==============================================================================
  18. Vec3 getRandom(const Vec3& initial, const Vec3& deviation)
  19. {
  20. if(deviation == Vec3(0.0))
  21. {
  22. return initial;
  23. }
  24. else
  25. {
  26. Vec3 out;
  27. for(U i = 0; i < 3; i++)
  28. {
  29. out[i] = getRandom(initial[i], deviation[i]);
  30. }
  31. return out;
  32. }
  33. }
  34. //==============================================================================
  35. // ParticleBase =
  36. //==============================================================================
  37. //==============================================================================
  38. ParticleBase::ParticleBase(
  39. ParticleType type_,
  40. // SceneNode
  41. const char* name, Scene* scene,
  42. // Movable
  43. U32 movableFlags, Movable* movParent)
  44. : SceneNode(name, scene), Movable(movableFlags, movParent, *this),
  45. type(type_)
  46. {}
  47. //==============================================================================
  48. ParticleBase::~ParticleBase()
  49. {}
  50. //==============================================================================
  51. void ParticleBase::revive(const ParticleEmitter& pe,
  52. F32 /*prevUpdateTime*/, F32 crntTime)
  53. {
  54. ANKI_ASSERT(isDead());
  55. const ParticleEmitterProperties& props = pe;
  56. // life
  57. timeOfDeath = getRandom(crntTime + props.particle.life,
  58. props.particle.lifeDeviation);
  59. timeOfBirth = crntTime;
  60. }
  61. //==============================================================================
  62. // ParticleSimple =
  63. //==============================================================================
  64. //==============================================================================
  65. ParticleSimple::ParticleSimple(
  66. // SceneNode
  67. const char* name, Scene* scene,
  68. // Movable
  69. U32 movableFlags, Movable* movParent)
  70. : ParticleBase(PT_SIMPLE, name, scene, movableFlags, movParent)
  71. {}
  72. //==============================================================================
  73. void ParticleSimple::simulate(const ParticleEmitter& pe,
  74. F32 prevUpdateTime, F32 crntTime)
  75. {
  76. F32 dt = crntTime - prevUpdateTime;
  77. ANKI_ASSERT(props.particle.gravity.getLength() > 0.0);
  78. Transform trf = getWorldTransform();
  79. Vec3 xp = trf.getOrigin();
  80. Vec3 xc = acceleration * (dt * dt) + velocity * dt + xp;
  81. trf.setOrigin(xc);
  82. setLocalTransform(trf);
  83. velocity += acceleration * dt;
  84. }
  85. //==============================================================================
  86. void ParticleSimple::revive(const ParticleEmitter& pe,
  87. F32 prevUpdateTime, F32 crntTime)
  88. {
  89. ParticleBase::revive(pe, prevUpdateTime, crntTime);
  90. velocity = Vec3(0.0);
  91. const ParticleEmitterProperties& props = pe;
  92. acceleration = getRandom(props.particle.gravity,
  93. props.particle.gravityDeviation);
  94. // Set the initial position
  95. Vec3 pos = getRandom(props.particle.startingPos,
  96. props.particle.startingPosDeviation);
  97. pos += pe.getWorldTransform().getOrigin();
  98. Transform trf;
  99. trf.setIdentity();
  100. trf.setOrigin(pos);
  101. setLocalTransform(trf);
  102. }
  103. //==============================================================================
  104. // Particle =
  105. //==============================================================================
  106. //==============================================================================
  107. Particle::Particle(
  108. // Scene
  109. const char* name, Scene* scene,
  110. // Movable
  111. U32 movableFlags, Movable* movParent,
  112. // RigidBody
  113. PhysWorld* masterContainer, const Initializer& init)
  114. : ParticleBase(PT_PHYSICS, name, scene, movableFlags, movParent),
  115. RigidBody(masterContainer, init, this)
  116. {}
  117. //==============================================================================
  118. Particle::~Particle()
  119. {}
  120. //==============================================================================
  121. void Particle::revive(const ParticleEmitter& pe,
  122. F32 prevUpdateTime, F32 crntTime)
  123. {
  124. ParticleBase::revive(pe, prevUpdateTime, crntTime);
  125. const ParticleEmitterProperties& props = pe;
  126. RigidBody& body = *this;
  127. // pre calculate
  128. Bool forceFlag = props.forceEnabled;
  129. Bool worldGravFlag = props.wordGravityEnabled;
  130. // activate it (Bullet stuff)
  131. body.forceActivationState(ACTIVE_TAG);
  132. body.activate();
  133. body.clearForces();
  134. body.setLinearVelocity(btVector3(0.0, 0.0, 0.0));
  135. body.setAngularVelocity(btVector3(0.0, 0.0, 0.0));
  136. // force
  137. if(forceFlag)
  138. {
  139. Vec3 forceDir = getRandom(props.particle.forceDirection,
  140. props.particle.forceDirectionDeviation);
  141. forceDir.normalize();
  142. if(!pe.identityRotation)
  143. {
  144. // the forceDir depends on the particle emitter rotation
  145. forceDir = pe.getWorldTransform().getRotation() * forceDir;
  146. }
  147. F32 forceMag = getRandom(props.particle.forceMagnitude,
  148. props.particle.forceMagnitudeDeviation);
  149. body.applyCentralForce(toBt(forceDir * forceMag));
  150. }
  151. // gravity
  152. if(!worldGravFlag)
  153. {
  154. body.setGravity(toBt(getRandom(props.particle.gravity,
  155. props.particle.gravityDeviation)));
  156. }
  157. // Starting pos. In local space
  158. Vec3 pos = getRandom(props.particle.startingPos,
  159. props.particle.startingPosDeviation);
  160. if(pe.identityRotation)
  161. {
  162. pos += pe.getWorldTransform().getOrigin();
  163. }
  164. else
  165. {
  166. pos.transform(pe.getWorldTransform());
  167. }
  168. btTransform trf(
  169. toBt(Transform(pos, pe.getWorldTransform().getRotation(), 1.0)));
  170. body.setWorldTransform(trf);
  171. }
  172. //==============================================================================
  173. // ParticleEmitter =
  174. //==============================================================================
  175. //==============================================================================
  176. ParticleEmitter::ParticleEmitter(
  177. const char* filename,
  178. // SceneNode
  179. const char* name, Scene* scene,
  180. // Movable
  181. U32 movableFlags, Movable* movParent)
  182. : SceneNode(name, scene), Spatial(this, &aabb),
  183. Movable(movableFlags, movParent, *this)
  184. {
  185. // Load resource
  186. particleEmitterResource.load(filename);
  187. // copy the resource to me
  188. ParticleEmitterProperties& me = *this;
  189. const ParticleEmitterProperties& other =
  190. particleEmitterResource->getProperties();
  191. me = other;
  192. if(usePhysicsEngine)
  193. {
  194. createParticlesSimulation(scene);
  195. }
  196. else
  197. {
  198. createParticlesSimpleSimulation(scene);
  199. }
  200. timeLeftForNextEmission = 0.0;
  201. instancesCount = particles.size();
  202. Renderable::init(*this);
  203. // Find the "alpha" material variable
  204. for(auto it = Renderable::getVariablesBegin();
  205. it != Renderable::getVariablesEnd(); ++it)
  206. {
  207. if((*it)->getName() == "alpha")
  208. {
  209. alphaRenderableVar = *it;
  210. }
  211. }
  212. }
  213. //==============================================================================
  214. ParticleEmitter::~ParticleEmitter()
  215. {}
  216. //==============================================================================
  217. const ModelPatchBase& ParticleEmitter::getRenderableModelPatchBase() const
  218. {
  219. return *particleEmitterResource->getModel().getModelPatches()[0];
  220. }
  221. //==============================================================================
  222. const Material& ParticleEmitter::getRenderableMaterial() const
  223. {
  224. return
  225. particleEmitterResource->getModel().getModelPatches()[0]->getMaterial();
  226. }
  227. //==============================================================================
  228. void ParticleEmitter::movableUpdate()
  229. {
  230. identityRotation =
  231. getWorldTransform().getRotation() == Mat3::getIdentity();
  232. }
  233. //==============================================================================
  234. void ParticleEmitter::createParticlesSimulation(Scene* scene)
  235. {
  236. // create the particles
  237. collShape.reset(new btSphereShape(particle.size));
  238. RigidBody::Initializer binit;
  239. binit.shape = collShape.get();
  240. binit.group = PhysWorld::CG_PARTICLE;
  241. binit.mask = PhysWorld::CG_MAP;
  242. for(U i = 0; i < maxNumOfParticles; i++)
  243. {
  244. binit.mass = getRandom(particle.mass, particle.massDeviation);
  245. Particle* part = new Particle(
  246. (getName() + std::to_string(i)).c_str(), scene,
  247. Movable::MF_NONE, nullptr,
  248. &scene->getPhysics(), binit);
  249. particles.push_back(part);
  250. part->forceActivationState(DISABLE_SIMULATION);
  251. }
  252. }
  253. //==============================================================================
  254. void ParticleEmitter::createParticlesSimpleSimulation(Scene* scene)
  255. {
  256. for(U i = 0; i < maxNumOfParticles; i++)
  257. {
  258. ParticleSimple* p = new ParticleSimple(
  259. (getName() + std::to_string(i)).c_str(),
  260. scene, Movable::MF_NONE, nullptr);
  261. particles.push_back(p);
  262. }
  263. }
  264. //==============================================================================
  265. void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame)
  266. {
  267. SceneNode::frameUpdate(prevUpdateTime, crntTime, frame);
  268. // - Deactivate the dead particles
  269. // - Calc the AABB
  270. // - Calc the instancing stuff
  271. //
  272. Vec3 aabbmin(std::numeric_limits<F32>::max());
  273. Vec3 aabbmax(std::numeric_limits<F32>::min());
  274. instancingTransformations.clear();
  275. Vector<F32> alpha;
  276. for(ParticleBase* p : particles)
  277. {
  278. if(p->isDead())
  279. {
  280. // if its already dead so dont deactivate it again
  281. continue;
  282. }
  283. if(p->getTimeOfDeath() < crntTime)
  284. {
  285. // Just died
  286. p->kill();
  287. }
  288. else
  289. {
  290. // This will calculate a new world transformation
  291. p->simulate(*this, prevUpdateTime, crntTime);
  292. // An alive
  293. const Vec3& origin = p->Movable::getWorldTransform().getOrigin();
  294. for(U i = 0; i < 3; i++)
  295. {
  296. aabbmin[i] = std::min(aabbmin[i], origin[i]);
  297. aabbmax[i] = std::max(aabbmax[i], origin[i]);
  298. }
  299. F32 lifePercent = (crntTime - p->getTimeOfBirth())
  300. / (p->getTimeOfDeath() - p->getTimeOfBirth());
  301. Transform trf = p->Movable::getWorldTransform();
  302. // XXX set a flag for scale
  303. trf.setScale(
  304. particle.size + (lifePercent * particle.sizeAnimation));
  305. instancingTransformations.push_back(trf);
  306. // Set alpha
  307. if(alphaRenderableVar)
  308. {
  309. alpha.push_back((1.0 - lifePercent) * particle.alpha);
  310. }
  311. }
  312. }
  313. instancesCount = instancingTransformations.size();
  314. if(instancesCount != 0)
  315. {
  316. aabb = Aabb(aabbmin - particle.size, aabbmax + particle.size);
  317. }
  318. else
  319. {
  320. aabb = Aabb(Vec3(0.0), Vec3(0.01));
  321. }
  322. spatialMarkUpdated();
  323. if(alphaRenderableVar)
  324. {
  325. alphaRenderableVar->setValues(&alpha[0], alpha.size());
  326. }
  327. //
  328. // Emit new particles
  329. //
  330. if(timeLeftForNextEmission <= 0.0)
  331. {
  332. U particlesCount = 0; // How many particles I am allowed to emmit
  333. for(ParticleBase* pp : particles)
  334. {
  335. ParticleBase& p = *pp;
  336. if(!p.isDead())
  337. {
  338. // its alive so skip it
  339. continue;
  340. }
  341. p.revive(*this, prevUpdateTime, crntTime);
  342. // do the rest
  343. ++particlesCount;
  344. if(particlesCount >= particlesPerEmittion)
  345. {
  346. break;
  347. }
  348. } // end for all particles
  349. timeLeftForNextEmission = emissionPeriod;
  350. } // end if can emit
  351. else
  352. {
  353. timeLeftForNextEmission -= crntTime - prevUpdateTime;
  354. }
  355. }
  356. } // end namespace anki