ParticleEmitterNode.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. // Copyright (C) 2009-2020, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <anki/scene/ParticleEmitterNode.h>
  6. #include <anki/scene/SceneGraph.h>
  7. #include <anki/scene/components/MoveComponent.h>
  8. #include <anki/scene/components/SpatialComponent.h>
  9. #include <anki/scene/components/RenderComponent.h>
  10. #include <anki/resource/ModelResource.h>
  11. #include <anki/resource/ResourceManager.h>
  12. #include <anki/util/Functions.h>
  13. #include <anki/physics/PhysicsBody.h>
  14. #include <anki/physics/PhysicsWorld.h>
  15. #include <anki/physics/PhysicsCollisionShape.h>
  16. #include <anki/Gr.h>
  17. namespace anki
  18. {
  19. static Vec3 getRandom(const Vec3& min, const Vec3& max)
  20. {
  21. Vec3 out;
  22. out.x() = mix(min.x(), max.x(), getRandomRange(0.0f, 1.0f));
  23. out.y() = mix(min.y(), max.y(), getRandomRange(0.0f, 1.0f));
  24. out.z() = mix(min.z(), max.z(), getRandomRange(0.0f, 1.0f));
  25. return out;
  26. }
  27. /// Particle base
  28. class ParticleEmitterNode::ParticleBase
  29. {
  30. public:
  31. Second m_timeOfBirth; ///< Keep the time of birth for nice effects
  32. Second m_timeOfDeath = -1.0; ///< Time of death. If < 0.0 then dead
  33. F32 m_initialSize;
  34. F32 m_finalSize;
  35. F32 m_crntSize;
  36. F32 m_initialAlpha;
  37. F32 m_finalAlpha;
  38. F32 m_crntAlpha;
  39. Vec4 m_crntPosition;
  40. virtual ~ParticleBase()
  41. {
  42. }
  43. Bool isDead() const
  44. {
  45. return m_timeOfDeath < 0.0;
  46. }
  47. /// Kill the particle
  48. virtual void kill()
  49. {
  50. ANKI_ASSERT(m_timeOfDeath > 0.0);
  51. m_timeOfDeath = -1.0;
  52. }
  53. /// Revive the particle
  54. virtual void revive(const ParticleEmitterProperties& props, const Transform& trf, Second prevUpdateTime,
  55. Second crntTime)
  56. {
  57. ANKI_ASSERT(isDead());
  58. // life
  59. m_timeOfDeath = crntTime + getRandomRange(props.m_particle.m_minLife, props.m_particle.m_maxLife);
  60. m_timeOfBirth = crntTime;
  61. // Size
  62. m_initialSize = getRandomRange(props.m_particle.m_minInitialSize, props.m_particle.m_maxInitialSize);
  63. m_finalSize = getRandomRange(props.m_particle.m_minFinalSize, props.m_particle.m_maxFinalSize);
  64. // Alpha
  65. m_initialAlpha = getRandomRange(props.m_particle.m_minInitialAlpha, props.m_particle.m_maxInitialAlpha);
  66. m_finalAlpha = getRandomRange(props.m_particle.m_minFinalAlpha, props.m_particle.m_maxFinalAlpha);
  67. }
  68. /// Common sumulation code
  69. virtual void simulate(Second prevUpdateTime, Second crntTime)
  70. {
  71. const F32 lifeFactor = F32((crntTime - m_timeOfBirth) / (m_timeOfDeath - m_timeOfBirth));
  72. m_crntSize = mix(m_initialSize, m_finalSize, lifeFactor);
  73. m_crntAlpha = mix(m_initialAlpha, m_finalAlpha, lifeFactor);
  74. }
  75. };
  76. /// Simple particle for simple simulation
  77. class ParticleEmitterNode::ParticleSimple : public ParticleEmitterNode::ParticleBase
  78. {
  79. public:
  80. Vec4 m_velocity = Vec4(0.0);
  81. Vec4 m_acceleration = Vec4(0.0);
  82. void revive(const ParticleEmitterProperties& props, const Transform& trf, Second prevUpdateTime,
  83. Second crntTime) override
  84. {
  85. ParticleBase::revive(props, trf, prevUpdateTime, crntTime);
  86. m_velocity = Vec4(0.0);
  87. m_acceleration = getRandom(props.m_particle.m_minGravity, props.m_particle.m_maxGravity).xyz0();
  88. // Set the initial position
  89. m_crntPosition =
  90. getRandom(props.m_particle.m_minStartingPosition, props.m_particle.m_maxStartingPosition).xyz0();
  91. m_crntPosition += trf.getOrigin();
  92. }
  93. void simulate(Second prevUpdateTime, Second crntTime) override
  94. {
  95. ParticleBase::simulate(prevUpdateTime, crntTime);
  96. F32 dt = F32(crntTime - prevUpdateTime);
  97. Vec4 xp = m_crntPosition;
  98. Vec4 xc = m_acceleration * (dt * dt) + m_velocity * dt + xp;
  99. m_crntPosition = xc;
  100. m_velocity += m_acceleration * dt;
  101. }
  102. };
  103. /// Particle for bullet simulations
  104. class ParticleEmitterNode::PhysParticle : public ParticleEmitterNode::ParticleBase
  105. {
  106. public:
  107. PhysicsBodyPtr m_body;
  108. PhysParticle(const PhysicsBodyInitInfo& init, SceneNode* node)
  109. {
  110. m_body = node->getSceneGraph().getPhysicsWorld().newInstance<PhysicsBody>(init);
  111. m_body->setUserData(node);
  112. m_body->activate(false);
  113. m_body->setMaterialGroup(PhysicsMaterialBit::PARTICLE);
  114. m_body->setMaterialMask(PhysicsMaterialBit::STATIC_GEOMETRY);
  115. m_body->setAngularFactor(Vec3(0.0f, 0.0f, 0.0f));
  116. }
  117. void kill() override
  118. {
  119. ParticleBase::kill();
  120. m_body->activate(false);
  121. }
  122. void revive(const ParticleEmitterProperties& props, const Transform& trf, Second prevUpdateTime,
  123. Second crntTime) override
  124. {
  125. ParticleBase::revive(props, trf, prevUpdateTime, crntTime);
  126. // pre calculate
  127. const Bool forceFlag = props.forceEnabled();
  128. const Bool worldGravFlag = props.wordGravityEnabled();
  129. // Activate it
  130. m_body->activate(true);
  131. m_body->setLinearVelocity(Vec3(0.0f));
  132. m_body->setAngularVelocity(Vec3(0.0f));
  133. m_body->clearForces();
  134. // force
  135. if(forceFlag)
  136. {
  137. Vec3 forceDir = getRandom(props.m_particle.m_minForceDirection, props.m_particle.m_maxForceDirection);
  138. forceDir.normalize();
  139. // the forceDir depends on the particle emitter rotation
  140. forceDir = trf.getRotation().getRotationPart() * forceDir;
  141. const F32 forceMag =
  142. getRandomRange(props.m_particle.m_minForceMagnitude, props.m_particle.m_maxForceMagnitude);
  143. m_body->applyForce(forceDir * forceMag, Vec3(0.0f));
  144. }
  145. // gravity
  146. if(!worldGravFlag)
  147. {
  148. m_body->setGravity(getRandom(props.m_particle.m_minGravity, props.m_particle.m_maxGravity));
  149. }
  150. // Starting pos. In local space
  151. Vec3 pos = getRandom(props.m_particle.m_minStartingPosition, props.m_particle.m_maxStartingPosition);
  152. pos = trf.transform(pos);
  153. m_body->setTransform(Transform(pos.xyz0(), trf.getRotation(), 1.0f));
  154. m_crntPosition = pos.xyz0();
  155. }
  156. void simulate(Second prevUpdateTime, Second crntTime) override
  157. {
  158. ParticleBase::simulate(prevUpdateTime, crntTime);
  159. m_crntPosition = m_body->getTransform().getOrigin();
  160. }
  161. };
  162. /// Feedback component
  163. class ParticleEmitterNode::MoveFeedbackComponent : public SceneComponent
  164. {
  165. public:
  166. MoveFeedbackComponent()
  167. : SceneComponent(SceneComponentType::NONE)
  168. {
  169. }
  170. ANKI_USE_RESULT Error update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated) override
  171. {
  172. updated = false; // Don't care about updates for this component
  173. MoveComponent& move = node.getFirstComponentOfType<MoveComponent>();
  174. if(move.getTimestamp() == node.getGlobalTimestamp())
  175. {
  176. static_cast<ParticleEmitterNode&>(node).onMoveComponentUpdate(move);
  177. }
  178. return Error::NONE;
  179. }
  180. };
  181. ParticleEmitterNode::ParticleEmitterNode(SceneGraph* scene, CString name)
  182. : SceneNode(scene, name)
  183. {
  184. }
  185. ParticleEmitterNode::~ParticleEmitterNode()
  186. {
  187. // Delete simple particles
  188. for(ParticleBase* part : m_particles)
  189. {
  190. getAllocator().deleteInstance(part);
  191. }
  192. m_particles.destroy(getAllocator());
  193. }
  194. Error ParticleEmitterNode::init(const CString& filename)
  195. {
  196. // Load resource
  197. ANKI_CHECK(getResourceManager().loadResource(filename, m_particleEmitterResource));
  198. // Move component
  199. newComponent<MoveComponent>();
  200. // Move component feedback
  201. newComponent<MoveFeedbackComponent>();
  202. // Spatial component
  203. newComponent<SpatialComponent>(this, &m_obb);
  204. // Render component
  205. RenderComponent* rcomp = newComponent<RenderComponent>();
  206. rcomp->initRaster(drawCallback, this, 0); // No merging
  207. rcomp->setFlagsFromMaterial(m_particleEmitterResource->getMaterial());
  208. // Other
  209. m_obb.setCenter(Vec4(0.0));
  210. m_obb.setExtend(Vec4(1.0, 1.0, 1.0, 0.0));
  211. m_obb.setRotation(Mat3x4::getIdentity());
  212. // copy the resource to me
  213. ParticleEmitterProperties& me = *this;
  214. const ParticleEmitterProperties& other = m_particleEmitterResource->getProperties();
  215. me = other;
  216. if(m_usePhysicsEngine)
  217. {
  218. createParticlesPhysicsSimulation(&getSceneGraph());
  219. m_simulationType = SimulationType::PHYSICS_ENGINE;
  220. }
  221. else
  222. {
  223. createParticlesSimpleSimulation();
  224. m_simulationType = SimulationType::SIMPLE;
  225. }
  226. // Create the vertex buffer and object
  227. m_vertBuffSize = m_maxNumOfParticles * VERTEX_SIZE;
  228. return Error::NONE;
  229. }
  230. void ParticleEmitterNode::drawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
  231. {
  232. ANKI_ASSERT(userData.getSize() == 1);
  233. const ParticleEmitterNode& self = *static_cast<const ParticleEmitterNode*>(userData[0]);
  234. // Early exit
  235. if(ANKI_UNLIKELY(self.m_aliveParticlesCount == 0))
  236. {
  237. return;
  238. }
  239. CommandBufferPtr& cmdb = ctx.m_commandBuffer;
  240. if(!ctx.m_debugDraw)
  241. {
  242. // Load verts
  243. StagingGpuMemoryToken token;
  244. void* gpuStorage = ctx.m_stagingGpuAllocator->allocateFrame(self.m_aliveParticlesCount * VERTEX_SIZE,
  245. StagingGpuMemoryType::VERTEX, token);
  246. memcpy(gpuStorage, self.m_verts, self.m_aliveParticlesCount * VERTEX_SIZE);
  247. // Program
  248. ShaderProgramPtr prog;
  249. self.m_particleEmitterResource->getRenderingInfo(ctx.m_key, prog);
  250. cmdb->bindShaderProgram(prog);
  251. // Vertex attribs
  252. cmdb->setVertexAttribute(0, 0, Format::R32G32B32_SFLOAT, 0);
  253. cmdb->setVertexAttribute(1, 0, Format::R32_SFLOAT, sizeof(Vec3));
  254. cmdb->setVertexAttribute(2, 0, Format::R32_SFLOAT, sizeof(Vec3) + sizeof(F32));
  255. // Vertex buff
  256. cmdb->bindVertexBuffer(0, token.m_buffer, token.m_offset, VERTEX_SIZE, VertexStepRate::INSTANCE);
  257. // Uniforms
  258. Array<Mat4, 1> trf = {Mat4::getIdentity()};
  259. RenderComponent::allocateAndSetupUniforms(self.m_particleEmitterResource->getMaterial(), ctx, trf, trf,
  260. *ctx.m_stagingGpuAllocator);
  261. // Draw
  262. cmdb->drawArrays(PrimitiveTopology::TRIANGLE_STRIP, 4, self.m_aliveParticlesCount, 0, 0);
  263. }
  264. else
  265. {
  266. // TODO
  267. }
  268. }
  269. void ParticleEmitterNode::onMoveComponentUpdate(MoveComponent& move)
  270. {
  271. m_identityRotation = move.getWorldTransform().getRotation() == Mat3x4::getIdentity();
  272. SpatialComponent& sp = getFirstComponentOfType<SpatialComponent>();
  273. sp.setSpatialOrigin(move.getWorldTransform().getOrigin());
  274. sp.markForUpdate();
  275. }
  276. void ParticleEmitterNode::createParticlesPhysicsSimulation(SceneGraph* scene)
  277. {
  278. PhysicsCollisionShapePtr collisionShape =
  279. getSceneGraph().getPhysicsWorld().newInstance<PhysicsSphere>(m_particle.m_minInitialSize / 2.0f);
  280. PhysicsBodyInitInfo binit;
  281. binit.m_shape = collisionShape;
  282. m_particles.create(getAllocator(), m_maxNumOfParticles);
  283. for(U32 i = 0; i < m_maxNumOfParticles; i++)
  284. {
  285. binit.m_mass = getRandomRange(m_particle.m_minMass, m_particle.m_maxMass);
  286. PhysParticle* part = getAllocator().newInstance<PhysParticle>(binit, this);
  287. m_particles[i] = part;
  288. }
  289. }
  290. void ParticleEmitterNode::createParticlesSimpleSimulation()
  291. {
  292. m_particles.create(getAllocator(), m_maxNumOfParticles);
  293. for(U32 i = 0; i < m_maxNumOfParticles; i++)
  294. {
  295. ParticleSimple* part = getAllocator().newInstance<ParticleSimple>();
  296. m_particles[i] = part;
  297. }
  298. }
  299. Error ParticleEmitterNode::frameUpdate(Second prevUpdateTime, Second crntTime)
  300. {
  301. // - Deactivate the dead particles
  302. // - Calc the AABB
  303. // - Calc the instancing stuff
  304. //
  305. Vec4 aabbmin(MAX_F32, MAX_F32, MAX_F32, 0.0f);
  306. Vec4 aabbmax(MIN_F32, MIN_F32, MIN_F32, 0.0f);
  307. m_aliveParticlesCount = 0;
  308. F32* verts = reinterpret_cast<F32*>(getFrameAllocator().allocate(m_vertBuffSize));
  309. m_verts = verts;
  310. const F32* verts_base = verts;
  311. (void)verts_base;
  312. F32 maxParticleSize = -1.0f;
  313. for(ParticleBase* p : m_particles)
  314. {
  315. if(p->isDead())
  316. {
  317. // if its already dead so dont deactivate it again
  318. continue;
  319. }
  320. if(p->m_timeOfDeath < crntTime)
  321. {
  322. // Just died
  323. p->kill();
  324. }
  325. else
  326. {
  327. // It's alive
  328. // Do checks
  329. ANKI_ASSERT((PtrSize(verts) + VERTEX_SIZE - PtrSize(verts_base)) <= m_vertBuffSize);
  330. // This will calculate a new world transformation
  331. p->simulate(prevUpdateTime, crntTime);
  332. const Vec4& origin = p->m_crntPosition;
  333. aabbmin = aabbmin.min(origin);
  334. aabbmax = aabbmax.max(origin);
  335. verts[0] = origin.x();
  336. verts[1] = origin.y();
  337. verts[2] = origin.z();
  338. verts[3] = p->m_crntSize;
  339. maxParticleSize = max(maxParticleSize, p->m_crntSize);
  340. verts[4] = clamp(p->m_crntAlpha, 0.0f, 1.0f);
  341. ++m_aliveParticlesCount;
  342. verts += 5;
  343. }
  344. }
  345. if(m_aliveParticlesCount != 0)
  346. {
  347. ANKI_ASSERT(maxParticleSize > 0.0f);
  348. Vec4 min = aabbmin - maxParticleSize;
  349. Vec4 max = aabbmax + maxParticleSize;
  350. Vec4 center = (min + max) / 2.0;
  351. m_obb = Obb(center.xyz0(), Mat3x4::getIdentity(), (max - center).xyz0());
  352. }
  353. else
  354. {
  355. m_obb = Obb(Vec4(0.0), Mat3x4::getIdentity(), Vec4(Vec3(0.001f), 0.0f));
  356. m_verts = nullptr;
  357. }
  358. getFirstComponentOfType<SpatialComponent>().markForUpdate();
  359. //
  360. // Emit new particles
  361. //
  362. if(m_timeLeftForNextEmission <= 0.0)
  363. {
  364. MoveComponent& move = getFirstComponentOfType<MoveComponent>();
  365. U particlesCount = 0; // How many particles I am allowed to emmit
  366. for(ParticleBase* pp : m_particles)
  367. {
  368. ParticleBase& p = *pp;
  369. if(!p.isDead())
  370. {
  371. // its alive so skip it
  372. continue;
  373. }
  374. p.revive(*this, move.getWorldTransform(), prevUpdateTime, crntTime);
  375. // do the rest
  376. ++particlesCount;
  377. if(particlesCount >= m_particlesPerEmission)
  378. {
  379. break;
  380. }
  381. } // end for all particles
  382. m_timeLeftForNextEmission = m_emissionPeriod;
  383. } // end if can emit
  384. else
  385. {
  386. m_timeLeftForNextEmission -= crntTime - prevUpdateTime;
  387. }
  388. return Error::NONE;
  389. }
  390. } // end namespace anki