ParticleEmitter.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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. // ParticleBase =
  10. //==============================================================================
  11. //==============================================================================
  12. ParticleBase::ParticleBase(
  13. // SceneNode
  14. const char* name, Scene* scene,
  15. // Movable
  16. U32 movableFlags, Movable* movParent)
  17. : SceneNode(name, scene), Movable(movableFlags, movParent, *this)
  18. {}
  19. //==============================================================================
  20. ParticleBase::~ParticleBase()
  21. {}
  22. //==============================================================================
  23. // Particle =
  24. //==============================================================================
  25. //==============================================================================
  26. Particle::Particle(
  27. // Scene
  28. const char* name, Scene* scene,
  29. // Movable
  30. U32 movableFlags, Movable* movParent,
  31. // RigidBody
  32. PhysWorld* masterContainer, const Initializer& init)
  33. : ParticleBase(name, scene, movableFlags, movParent),
  34. RigidBody(masterContainer, init, this)
  35. {}
  36. //==============================================================================
  37. Particle::~Particle()
  38. {}
  39. //==============================================================================
  40. // ParticleEmitter =
  41. //==============================================================================
  42. //==============================================================================
  43. ParticleEmitter::ParticleEmitter(
  44. const char* filename,
  45. // SceneNode
  46. const char* name, Scene* scene,
  47. // Movable
  48. U32 movableFlags, Movable* movParent)
  49. : SceneNode(name, scene), Spatial(this, &aabb),
  50. Movable(movableFlags, movParent, *this)
  51. {
  52. init(filename, scene);
  53. instancesCount = particles.size();
  54. Renderable::init(*this);
  55. // Find the "alpha" material variable
  56. for(auto it = Renderable::getVariablesBegin();
  57. it != Renderable::getVariablesEnd(); ++it)
  58. {
  59. if((*it)->getName() == "alpha")
  60. {
  61. alphaRenderableVar = *it;
  62. }
  63. }
  64. }
  65. //==============================================================================
  66. ParticleEmitter::~ParticleEmitter()
  67. {}
  68. //==============================================================================
  69. F32 ParticleEmitter::getRandom(F32 initial, F32 deviation)
  70. {
  71. return (deviation == 0.0) ? initial
  72. : initial + randFloat(deviation) * 2.0 - deviation;
  73. }
  74. //==============================================================================
  75. Vec3 ParticleEmitter::getRandom(const Vec3& initial, const Vec3& deviation)
  76. {
  77. if(deviation == Vec3(0.0))
  78. {
  79. return initial;
  80. }
  81. else
  82. {
  83. Vec3 out;
  84. for(U i = 0; i < 3; i++)
  85. {
  86. out[i] = getRandom(initial[i], deviation[i]);
  87. }
  88. return out;
  89. }
  90. }
  91. //==============================================================================
  92. const ModelPatchBase& ParticleEmitter::getRenderableModelPatchBase() const
  93. {
  94. return *particleEmitterResource->getModel().getModelPatches()[0];
  95. }
  96. //==============================================================================
  97. const Material& ParticleEmitter::getRenderableMaterial() const
  98. {
  99. return
  100. particleEmitterResource->getModel().getModelPatches()[0]->getMaterial();
  101. }
  102. //==============================================================================
  103. void ParticleEmitter::movableUpdate()
  104. {
  105. identityRotation =
  106. getWorldTransform().getRotation() == Mat3::getIdentity();
  107. }
  108. //==============================================================================
  109. void ParticleEmitter::init(const char* filename, Scene* scene)
  110. {
  111. particleEmitterResource.load(filename);
  112. // copy the resource to me
  113. ParticleEmitterProperties& me = *this;
  114. const ParticleEmitterProperties& other =
  115. particleEmitterResource->getProperties();
  116. me = other;
  117. // create the particles
  118. collShape.reset(new btSphereShape(particle.size));
  119. RigidBody::Initializer binit;
  120. binit.shape = collShape.get();
  121. binit.group = PhysWorld::CG_PARTICLE;
  122. binit.mask = PhysWorld::CG_MAP;
  123. for(U i = 0; i < maxNumOfParticles; i++)
  124. {
  125. binit.mass = getRandom(particle.mass, particle.massDeviation);
  126. Particle* part = new Particle(
  127. (getName() + std::to_string(i)).c_str(), scene,
  128. Movable::MF_NONE, nullptr,
  129. &scene->getPhysics(), binit);
  130. particles.push_back(part);
  131. part->forceActivationState(DISABLE_SIMULATION);
  132. }
  133. timeLeftForNextEmission = 0.0;
  134. }
  135. //==============================================================================
  136. void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame)
  137. {
  138. SceneNode::frameUpdate(prevUpdateTime, crntTime, frame);
  139. // - Deactivate the dead particles
  140. // - Calc the AABB
  141. // - Calc the instancing stuff
  142. //
  143. Vec3 aabbmin(std::numeric_limits<F32>::max());
  144. Vec3 aabbmax(std::numeric_limits<F32>::min());
  145. instancingTransformations.clear();
  146. Vector<F32> alpha;
  147. for(Particle* p : particles)
  148. {
  149. if(p->isDead())
  150. {
  151. // if its already dead so dont deactivate it again
  152. continue;
  153. }
  154. if(p->getTimeOfDeath() < crntTime)
  155. {
  156. // Just died
  157. p->setActivationState(DISABLE_SIMULATION);
  158. p->setTimeOfDeath(-1.0);
  159. }
  160. else
  161. {
  162. // An alive
  163. const Vec3& origin = p->Movable::getWorldTransform().getOrigin();
  164. for(U i = 0; i < 3; i++)
  165. {
  166. aabbmin[i] = std::min(aabbmin[i], origin[i]);
  167. aabbmax[i] = std::max(aabbmax[i], origin[i]);
  168. }
  169. F32 lifePercent = (crntTime - p->getTimeOfBirth())
  170. / (p->getTimeOfDeath() - p->getTimeOfBirth());
  171. Transform trf = p->Movable::getWorldTransform();
  172. // XXX set a flag for scale
  173. trf.setScale(
  174. particle.size + (lifePercent * particle.sizeAnimation));
  175. instancingTransformations.push_back(trf);
  176. // Set alpha
  177. if(alphaRenderableVar)
  178. {
  179. alpha.push_back((1.0 - lifePercent) * particle.alpha);
  180. }
  181. }
  182. }
  183. instancesCount = instancingTransformations.size();
  184. if(instancesCount != 0)
  185. {
  186. aabb = Aabb(aabbmin - particle.size, aabbmax + particle.size);
  187. }
  188. else
  189. {
  190. aabb = Aabb(Vec3(0.0), Vec3(0.01));
  191. }
  192. spatialMarkUpdated();
  193. if(alphaRenderableVar)
  194. {
  195. alphaRenderableVar->setValues(&alpha[0], alpha.size());
  196. }
  197. //
  198. // Emit new particles
  199. //
  200. if(timeLeftForNextEmission <= 0.0)
  201. {
  202. U particlesCount = 0; // How many particles I am allowed to emmit
  203. for(Particle* pp : particles)
  204. {
  205. Particle& p = *pp;
  206. if(!p.isDead())
  207. {
  208. // its alive so skip it
  209. continue;
  210. }
  211. reanimateParticle(p, crntTime);
  212. // do the rest
  213. ++particlesCount;
  214. if(particlesCount >= particlesPerEmittion)
  215. {
  216. break;
  217. }
  218. } // end for all particles
  219. timeLeftForNextEmission = emissionPeriod;
  220. } // end if can emit
  221. else
  222. {
  223. timeLeftForNextEmission -= crntTime - prevUpdateTime;
  224. }
  225. }
  226. //==============================================================================
  227. void ParticleEmitter::reanimateParticle(ParticleBase& p, F32 crntTime)
  228. {
  229. ANKI_ASSERT(p.isDead());
  230. ANKI_ASSERT(p.getRigidBody() != nullptr);
  231. RigidBody& body = *p.getRigidBody();
  232. // pre calculate
  233. Bool forceFlag = forceEnabled;
  234. Bool worldGravFlag = wordGravityEnabled;
  235. // life
  236. p.setTimeOfDeath(
  237. getRandom(crntTime + particle.life, particle.lifeDeviation));
  238. p.setTimeOfBirth(crntTime);
  239. // activate it (Bullet stuff)
  240. body.forceActivationState(ACTIVE_TAG);
  241. body.activate();
  242. body.clearForces();
  243. body.setLinearVelocity(btVector3(0.0, 0.0, 0.0));
  244. body.setAngularVelocity(btVector3(0.0, 0.0, 0.0));
  245. // force
  246. if(forceFlag)
  247. {
  248. Vec3 forceDir = getRandom(particle.forceDirection,
  249. particle.forceDirectionDeviation);
  250. forceDir.normalize();
  251. if(!identityRotation)
  252. {
  253. // the forceDir depends on the particle emitter rotation
  254. forceDir = getWorldTransform().getRotation() * forceDir;
  255. }
  256. F32 forceMag = getRandom(particle.forceMagnitude,
  257. particle.forceMagnitudeDeviation);
  258. body.applyCentralForce(toBt(forceDir * forceMag));
  259. }
  260. // gravity
  261. if(!worldGravFlag)
  262. {
  263. body.setGravity(
  264. toBt(getRandom(particle.gravity, particle.gravityDeviation)));
  265. }
  266. // Starting pos. In local space
  267. Vec3 pos = getRandom(particle.startingPos, particle.startingPosDeviation);
  268. if(identityRotation)
  269. {
  270. pos += getWorldTransform().getOrigin();
  271. }
  272. else
  273. {
  274. pos.transform(getWorldTransform());
  275. }
  276. btTransform trf(
  277. toBt(Transform(pos, getWorldTransform().getRotation(), 1.0)));
  278. body.setWorldTransform(trf);
  279. }
  280. } // end namespace anki