ParticleEmitter.cpp 12 KB

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