ParticleEmitter.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. #include "anki/scene/ParticleEmitter.h"
  2. #include "anki/scene/SceneGraph.h"
  3. #include "anki/scene/InstanceNode.h"
  4. #include "anki/scene/Misc.h"
  5. #include "anki/resource/Model.h"
  6. #include "anki/util/Functions.h"
  7. #include "anki/physics/PhysicsWorld.h"
  8. #include "anki/Gl.h"
  9. namespace anki {
  10. //==============================================================================
  11. // Misc =
  12. //==============================================================================
  13. const U COMPONENTS = 3 + 1 + 1; // 3 position, 1 size, 1 alpha
  14. const PtrSize VERT_SIZE = COMPONENTS * sizeof(F32);
  15. //==============================================================================
  16. static F32 getRandom(F32 initial, F32 deviation)
  17. {
  18. return (deviation == 0.0)
  19. ? initial
  20. : initial + randFloat(deviation) * 2.0 - deviation;
  21. }
  22. //==============================================================================
  23. static Vec3 getRandom(const Vec3& initial, const Vec3& deviation)
  24. {
  25. if(deviation == Vec3(0.0))
  26. {
  27. return initial;
  28. }
  29. else
  30. {
  31. Vec3 out;
  32. for(U i = 0; i < 3; i++)
  33. {
  34. out[i] = getRandom(initial[i], deviation[i]);
  35. }
  36. return out;
  37. }
  38. }
  39. //==============================================================================
  40. // ParticleBase =
  41. //==============================================================================
  42. //==============================================================================
  43. void ParticleBase::revive(const ParticleEmitter& pe,
  44. F32 /*prevUpdateTime*/, F32 crntTime)
  45. {
  46. ANKI_ASSERT(isDead());
  47. const ParticleEmitterProperties& props = pe;
  48. // life
  49. m_timeOfDeath = getRandom(crntTime + props.m_particle.m_life,
  50. props.m_particle.m_lifeDeviation);
  51. m_timeOfBirth = crntTime;
  52. }
  53. //==============================================================================
  54. // ParticleSimple =
  55. //==============================================================================
  56. //==============================================================================
  57. void ParticleSimple::simulate(const ParticleEmitter& pe,
  58. F32 prevUpdateTime, F32 crntTime)
  59. {
  60. F32 dt = crntTime - prevUpdateTime;
  61. ANKI_ASSERT(
  62. static_cast<const ParticleEmitterProperties&>(pe).
  63. m_particle.m_gravity.getLength() > 0.0);
  64. Vec3 xp = m_position;
  65. Vec3 xc = m_acceleration * (dt * dt) + m_velocity * dt + xp;
  66. m_position = xc;
  67. m_velocity += m_acceleration * dt;
  68. }
  69. //==============================================================================
  70. void ParticleSimple::revive(const ParticleEmitter& pe,
  71. F32 prevUpdateTime, F32 crntTime)
  72. {
  73. ParticleBase::revive(pe, prevUpdateTime, crntTime);
  74. m_velocity = Vec3(0.0);
  75. const ParticleEmitterProperties& props = pe;
  76. m_acceleration = getRandom(props.m_particle.m_gravity,
  77. props.m_particle.m_gravityDeviation);
  78. // Set the initial position
  79. m_position = getRandom(props.m_particle.m_startingPos,
  80. props.m_particle.m_startingPosDeviation);
  81. m_position += pe.getWorldTransform().getOrigin();
  82. }
  83. //==============================================================================
  84. // Particle =
  85. //==============================================================================
  86. #if 0
  87. //==============================================================================
  88. Particle::Particle(
  89. const char* name, SceneGraph* scene, // SceneNode
  90. // RigidBody
  91. PhysicsWorld* masterContainer, const RigidBody::Initializer& init_)
  92. : ParticleBase(name, scene, PT_PHYSICS)
  93. {
  94. RigidBody::Initializer init = init_;
  95. getSceneGraph().getPhysics().newPhysicsObject<RigidBody>(body, init);
  96. sceneNodeProtected.rigidBodyC = body;
  97. }
  98. //==============================================================================
  99. Particle::~Particle()
  100. {
  101. getSceneGraph().getPhysics().deletePhysicsObject(body);
  102. }
  103. //==============================================================================
  104. void Particle::revive(const ParticleEmitter& pe,
  105. F32 prevUpdateTime, F32 crntTime)
  106. {
  107. ParticleBase::revive(pe, prevUpdateTime, crntTime);
  108. const ParticleEmitterProperties& props = pe;
  109. // pre calculate
  110. Bool forceFlag = props.forceEnabled;
  111. Bool worldGravFlag = props.wordGravityEnabled;
  112. // activate it (Bullet stuff)
  113. body->forceActivationState(ACTIVE_TAG);
  114. body->activate();
  115. body->clearForces();
  116. body->setLinearVelocity(btVector3(0.0, 0.0, 0.0));
  117. body->setAngularVelocity(btVector3(0.0, 0.0, 0.0));
  118. // force
  119. if(forceFlag)
  120. {
  121. Vec3 forceDir = getRandom(props.particle.forceDirection,
  122. props.particle.forceDirectionDeviation);
  123. forceDir.normalize();
  124. if(!pe.identityRotation)
  125. {
  126. // the forceDir depends on the particle emitter rotation
  127. forceDir = pe.getWorldTransform().getRotation() * forceDir;
  128. }
  129. F32 forceMag = getRandom(props.particle.forceMagnitude,
  130. props.particle.forceMagnitudeDeviation);
  131. body->applyCentralForce(toBt(forceDir * forceMag));
  132. }
  133. // gravity
  134. if(!worldGravFlag)
  135. {
  136. body->setGravity(toBt(getRandom(props.particle.gravity,
  137. props.particle.gravityDeviation)));
  138. }
  139. // Starting pos. In local space
  140. Vec3 pos = getRandom(props.particle.startingPos,
  141. props.particle.startingPosDeviation);
  142. if(pe.identityRotation)
  143. {
  144. pos += pe.getWorldTransform().getOrigin();
  145. }
  146. else
  147. {
  148. pos.transform(pe.getWorldTransform());
  149. }
  150. btTransform trf(
  151. toBt(Transform(pos, pe.getWorldTransform().getRotation(), 1.0)));
  152. body->setWorldTransform(trf);
  153. }
  154. #endif
  155. //==============================================================================
  156. // ParticleEmitter =
  157. //==============================================================================
  158. //==============================================================================
  159. ParticleEmitter::ParticleEmitter(
  160. const char* name, SceneGraph* scene,
  161. const char* filename)
  162. : SceneNode(name, scene),
  163. SpatialComponent(this),
  164. MoveComponent(this),
  165. RenderComponent(this),
  166. m_particles(getSceneAllocator()),
  167. m_transforms(getSceneAllocator())
  168. {
  169. addComponent(static_cast<MoveComponent*>(this));
  170. addComponent(static_cast<SpatialComponent*>(this));
  171. addComponent(static_cast<RenderComponent*>(this));
  172. m_obb.setCenter(Vec3(0.0));
  173. m_obb.setExtend(Vec3(1.0));
  174. m_obb.setRotation(Mat3::getIdentity());
  175. // Load resource
  176. m_particleEmitterResource.load(filename);
  177. // copy the resource to me
  178. ParticleEmitterProperties& me = *this;
  179. const ParticleEmitterProperties& other =
  180. m_particleEmitterResource->getProperties();
  181. me = other;
  182. if(m_usePhysicsEngine)
  183. {
  184. createParticlesSimulation(scene);
  185. m_simulationType = SimulationType::PHYSICS_ENGINE;
  186. }
  187. else
  188. {
  189. createParticlesSimpleSimulation(scene);
  190. m_simulationType = SimulationType::SIMPLE;
  191. }
  192. m_timeLeftForNextEmission = 0.0;
  193. RenderComponent::init();
  194. // Create the vertex buffer and object
  195. //
  196. PtrSize buffSize = m_maxNumOfParticles * VERT_SIZE * 3;
  197. GlManager& gl = GlManagerSingleton::get();
  198. GlJobChainHandle jobs(&gl);
  199. m_vertBuff = GlBufferHandle(jobs, GL_ARRAY_BUFFER, buffSize,
  200. GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
  201. // TODO Optimize that to avoir serialization
  202. jobs.finish();
  203. m_vertBuffMapping = (U8*)m_vertBuff.getPersistentMappingAddress();
  204. }
  205. //==============================================================================
  206. ParticleEmitter::~ParticleEmitter()
  207. {
  208. // Delete simple particles
  209. if(m_simulationType == SimulationType::SIMPLE)
  210. {
  211. for(ParticleBase* part : m_particles)
  212. {
  213. getSceneAllocator().deleteInstance(part);
  214. }
  215. }
  216. }
  217. //==============================================================================
  218. void ParticleEmitter::buildRendering(RenderingBuildData& data)
  219. {
  220. ANKI_ASSERT(data.m_subMeshIndicesCount <= m_transforms.size() + 1);
  221. if(m_aliveParticlesCount == 0)
  222. {
  223. return;
  224. }
  225. RenderingKey key = data.m_key;
  226. key.m_lod = 0;
  227. GlProgramPipelineHandle ppline =
  228. m_particleEmitterResource->getMaterial().getProgramPipeline(key);
  229. ppline.bind(data.m_jobs);
  230. PtrSize offset = (getGlobTimestamp() % 3) * (m_vertBuff.getSize() / 3);
  231. // Position
  232. m_vertBuff.bindVertexBuffer(data.m_jobs,
  233. 3, GL_FLOAT, false, VERT_SIZE, offset + 0, 0);
  234. // Scale
  235. m_vertBuff.bindVertexBuffer(data.m_jobs,
  236. 1, GL_FLOAT, false, VERT_SIZE, offset + sizeof(F32) * 3, 6);
  237. // Alpha
  238. m_vertBuff.bindVertexBuffer(data.m_jobs,
  239. 1, GL_FLOAT, false, VERT_SIZE, offset + sizeof(F32) * 4, 7);
  240. GlDrawcallArrays dc = GlDrawcallArrays(
  241. GL_POINTS,
  242. m_aliveParticlesCount,
  243. data.m_subMeshIndicesCount);
  244. dc.draw(data.m_jobs);
  245. }
  246. //==============================================================================
  247. const Material& ParticleEmitter::getMaterial()
  248. {
  249. return m_particleEmitterResource->getMaterial();
  250. }
  251. //==============================================================================
  252. void ParticleEmitter::componentUpdated(SceneComponent& comp,
  253. SceneComponent::UpdateType)
  254. {
  255. if(comp.getType() == MoveComponent::getClassType())
  256. {
  257. m_identityRotation =
  258. getWorldTransform().getRotation() == Mat3::getIdentity();
  259. }
  260. }
  261. //==============================================================================
  262. void ParticleEmitter::createParticlesSimulation(SceneGraph* scene)
  263. {
  264. #if 0
  265. collShape = getSceneAllocator().newInstance<btSphereShape>(particle.size);
  266. RigidBody::Initializer binit;
  267. binit.shape = collShape;
  268. binit.group = PhysicsWorld::CG_PARTICLE;
  269. binit.mask = PhysicsWorld::CG_MAP;
  270. particles.reserve(maxNumOfParticles);
  271. for(U i = 0; i < maxNumOfParticles; i++)
  272. {
  273. binit.mass = getRandom(particle.mass, particle.massDeviation);
  274. Particle* part = getSceneGraph().newSceneNode<Particle>(
  275. nullptr, &scene->getPhysics(), binit);
  276. part->size = getRandom(particle.size, particle.sizeDeviation);
  277. part->alpha = getRandom(particle.alpha, particle.alphaDeviation);
  278. part->getRigidBody()->forceActivationState(DISABLE_SIMULATION);
  279. particles.push_back(part);
  280. }
  281. #endif
  282. }
  283. //==============================================================================
  284. void ParticleEmitter::createParticlesSimpleSimulation(SceneGraph* scene)
  285. {
  286. m_particles.resize(m_maxNumOfParticles);
  287. for(U i = 0; i < m_maxNumOfParticles; i++)
  288. {
  289. ParticleSimple* part =
  290. getSceneAllocator().newInstance<ParticleSimple>();
  291. part->m_size = getRandom(m_particle.m_size, m_particle.m_sizeDeviation);
  292. part->m_alpha =
  293. getRandom(m_particle.m_alpha, m_particle.m_alphaDeviation);
  294. m_particles[i] = part;
  295. }
  296. }
  297. //==============================================================================
  298. void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime,
  299. SceneNode::UpdateType uptype)
  300. {
  301. if(uptype == SceneNode::SYNC_UPDATE)
  302. {
  303. return;
  304. }
  305. // - Deactivate the dead particles
  306. // - Calc the AABB
  307. // - Calc the instancing stuff
  308. //
  309. Vec3 aabbmin(MAX_F32);
  310. Vec3 aabbmax(MIN_F32);
  311. m_aliveParticlesCount = 0;
  312. F32* verts = (F32*)(m_vertBuffMapping
  313. + (getGlobTimestamp() % 3) * (m_vertBuff.getSize() / 3));
  314. F32* verts_base = verts;
  315. (void)verts_base;
  316. for(ParticleBase* p : m_particles)
  317. {
  318. if(p->isDead())
  319. {
  320. // if its already dead so dont deactivate it again
  321. continue;
  322. }
  323. if(p->getTimeOfDeath() < crntTime)
  324. {
  325. // Just died
  326. p->kill();
  327. }
  328. else
  329. {
  330. // It's alive
  331. // Do checks
  332. ANKI_ASSERT(((PtrSize)verts + VERT_SIZE
  333. - (PtrSize)m_vertBuffMapping) <= m_vertBuff.getSize());
  334. // This will calculate a new world transformation
  335. p->simulate(*this, prevUpdateTime, crntTime);
  336. const Vec3& origin = p->getPosition();
  337. for(U i = 0; i < 3; i++)
  338. {
  339. aabbmin[i] = std::min(aabbmin[i], origin[i]);
  340. aabbmax[i] = std::max(aabbmax[i], origin[i]);
  341. }
  342. F32 lifePercent = (crntTime - p->getTimeOfBirth())
  343. / (p->getTimeOfDeath() - p->getTimeOfBirth());
  344. verts[0] = origin.x();
  345. verts[1] = origin.y();
  346. verts[2] = origin.z();
  347. // XXX set a flag for scale
  348. verts[3] = p->m_size + (lifePercent * m_particle.m_sizeAnimation);
  349. // Set alpha
  350. if(m_particle.m_alphaAnimation)
  351. {
  352. verts[4] = sin((lifePercent) * getPi<F32>()) * p->m_alpha;
  353. }
  354. else
  355. {
  356. verts[4] = p->m_alpha;
  357. }
  358. ++m_aliveParticlesCount;
  359. verts += 5;
  360. }
  361. }
  362. if(m_aliveParticlesCount != 0)
  363. {
  364. Vec3 min = aabbmin - m_particle.m_size;
  365. Vec3 max = aabbmax + m_particle.m_size;
  366. Vec3 center = (min + max) / 2.0;
  367. m_obb = Obb(center, Mat3::getIdentity(), max - center);
  368. }
  369. else
  370. {
  371. m_obb = Obb(Vec3(0.0), Mat3::getIdentity(), Vec3(0.001));
  372. }
  373. SpatialComponent::markForUpdate();
  374. //
  375. // Emit new particles
  376. //
  377. if(m_timeLeftForNextEmission <= 0.0)
  378. {
  379. U particlesCount = 0; // How many particles I am allowed to emmit
  380. for(ParticleBase* pp : m_particles)
  381. {
  382. ParticleBase& p = *pp;
  383. if(!p.isDead())
  384. {
  385. // its alive so skip it
  386. continue;
  387. }
  388. p.revive(*this, prevUpdateTime, crntTime);
  389. // do the rest
  390. ++particlesCount;
  391. if(particlesCount >= m_particlesPerEmittion)
  392. {
  393. break;
  394. }
  395. } // end for all particles
  396. m_timeLeftForNextEmission = m_emissionPeriod;
  397. } // end if can emit
  398. else
  399. {
  400. m_timeLeftForNextEmission -= crntTime - prevUpdateTime;
  401. }
  402. // Do something more
  403. doInstancingCalcs();
  404. }
  405. //==============================================================================
  406. void ParticleEmitter::doInstancingCalcs()
  407. {
  408. // Gather the move components of the instances
  409. SceneFrameVector<MoveComponent*> instanceMoves(getSceneFrameAllocator());
  410. Timestamp instancesTimestamp = 0;
  411. SceneObject::visitThisAndChildren<SceneNode>([&](SceneNode& sn)
  412. {
  413. if(sn.tryGetComponent<InstanceComponent>())
  414. {
  415. MoveComponent& move = sn.getComponent<MoveComponent>();
  416. instanceMoves.push_back(&move);
  417. instancesTimestamp =
  418. std::max(instancesTimestamp, move.getTimestamp());
  419. }
  420. });
  421. // If instancing
  422. if(instanceMoves.size() != 0)
  423. {
  424. Bool transformsNeedUpdate = false;
  425. // Check if an instance was added or removed and reset the spatials and
  426. // the transforms
  427. if(instanceMoves.size() != m_transforms.size())
  428. {
  429. transformsNeedUpdate = true;
  430. // Check if instances added or removed
  431. if(m_transforms.size() < instanceMoves.size())
  432. {
  433. // Instances added
  434. U diff = instanceMoves.size() - m_transforms.size();
  435. while(diff-- != 0)
  436. {
  437. ObbSpatialComponent* newSpatial = getSceneAllocator().
  438. newInstance<ObbSpatialComponent>(this);
  439. addComponent(newSpatial);
  440. }
  441. }
  442. else
  443. {
  444. // Instances removed
  445. // TODO
  446. ANKI_ASSERT(0 && "TODO");
  447. }
  448. m_transforms.resize(instanceMoves.size());
  449. }
  450. if(transformsNeedUpdate || m_transformsTimestamp < instancesTimestamp)
  451. {
  452. m_transformsTimestamp = instancesTimestamp;
  453. // Update the transforms
  454. for(U i = 0; i < instanceMoves.size(); i++)
  455. {
  456. m_transforms[i] = instanceMoves[i]->getWorldTransform();
  457. }
  458. }
  459. // Update the spatials anyway
  460. U count = 0;
  461. iterateComponentsOfType<SpatialComponent>([&](SpatialComponent& sp)
  462. {
  463. // Skip the first
  464. if(count != 0)
  465. {
  466. ObbSpatialComponent* msp =
  467. staticCastPtr<ObbSpatialComponent*>(&sp);
  468. Obb aobb = m_obb;
  469. aobb.setCenter(Vec3(0.0));
  470. msp->obb = aobb.getTransformed(m_transforms[count - 1]);
  471. msp->markForUpdate();
  472. }
  473. ++count;
  474. });
  475. ANKI_ASSERT(count - 1 == m_transforms.size());
  476. } // end if instancing
  477. }
  478. //==============================================================================
  479. Bool ParticleEmitter::getHasWorldTransforms()
  480. {
  481. if(m_transforms.size() == 0)
  482. {
  483. return false;
  484. }
  485. else
  486. {
  487. return true;
  488. }
  489. }
  490. //==============================================================================
  491. void ParticleEmitter::getRenderWorldTransform(U index, Transform& trf)
  492. {
  493. ANKI_ASSERT(m_transforms.size() > 0);
  494. if(index == 0)
  495. {
  496. // Don't transform the particle positions. They are already in world
  497. // space
  498. trf = Transform::getIdentity();
  499. }
  500. else
  501. {
  502. --index;
  503. ANKI_ASSERT(index < m_transforms.size());
  504. // The particle positions are already in word space. Move them back to
  505. // local space
  506. Transform invTrf = getWorldTransform().getInverse();
  507. trf = Transform::combineTransformations(m_transforms[index], invTrf);
  508. }
  509. }
  510. } // end namespace anki