ParticleEmitterComponent.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. // Copyright (C) 2009-2021, 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/Components/ParticleEmitterComponent.h>
  6. #include <AnKi/Scene/SceneGraph.h>
  7. #include <AnKi/Scene/SceneNode.h>
  8. #include <AnKi/Scene/Components/RenderComponent.h>
  9. #include <AnKi/Resource/ParticleEmitterResource.h>
  10. #include <AnKi/Resource/ResourceManager.h>
  11. #include <AnKi/Physics/PhysicsBody.h>
  12. #include <AnKi/Physics/PhysicsCollisionShape.h>
  13. #include <AnKi/Physics/PhysicsWorld.h>
  14. #include <AnKi/Math.h>
  15. #include <AnKi/Renderer/RenderQueue.h>
  16. namespace anki
  17. {
  18. ANKI_SCENE_COMPONENT_STATICS(ParticleEmitterComponent)
  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 ParticleEmitterComponent::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. Vec3 m_crntPosition;
  40. Bool isDead() const
  41. {
  42. return m_timeOfDeath < 0.0;
  43. }
  44. /// Kill the particle
  45. void killCommon()
  46. {
  47. ANKI_ASSERT(m_timeOfDeath > 0.0);
  48. m_timeOfDeath = -1.0;
  49. }
  50. /// Revive the particle
  51. void reviveCommon(const ParticleEmitterProperties& props, const Transform& trf, Second prevUpdateTime,
  52. Second crntTime)
  53. {
  54. ANKI_ASSERT(isDead());
  55. // life
  56. m_timeOfDeath = crntTime + getRandomRange(props.m_particle.m_minLife, props.m_particle.m_maxLife);
  57. m_timeOfBirth = crntTime;
  58. // Size
  59. m_initialSize = getRandomRange(props.m_particle.m_minInitialSize, props.m_particle.m_maxInitialSize);
  60. m_finalSize = getRandomRange(props.m_particle.m_minFinalSize, props.m_particle.m_maxFinalSize);
  61. // Alpha
  62. m_initialAlpha = getRandomRange(props.m_particle.m_minInitialAlpha, props.m_particle.m_maxInitialAlpha);
  63. m_finalAlpha = getRandomRange(props.m_particle.m_minFinalAlpha, props.m_particle.m_maxFinalAlpha);
  64. }
  65. /// Common sumulation code
  66. void simulateCommon(Second prevUpdateTime, Second crntTime)
  67. {
  68. const F32 lifeFactor = F32((crntTime - m_timeOfBirth) / (m_timeOfDeath - m_timeOfBirth));
  69. m_crntSize = mix(m_initialSize, m_finalSize, lifeFactor);
  70. m_crntAlpha = mix(m_initialAlpha, m_finalAlpha, lifeFactor);
  71. }
  72. };
  73. /// Simple particle for simple simulation
  74. class ParticleEmitterComponent::SimpleParticle : public ParticleEmitterComponent::ParticleBase
  75. {
  76. public:
  77. Vec3 m_velocity = Vec3(0.0f);
  78. Vec3 m_acceleration = Vec3(0.0f);
  79. void kill()
  80. {
  81. killCommon();
  82. }
  83. void revive(const ParticleEmitterProperties& props, const Transform& trf, Second prevUpdateTime, Second crntTime)
  84. {
  85. reviveCommon(props, trf, prevUpdateTime, crntTime);
  86. m_velocity = Vec3(0.0f);
  87. m_acceleration = getRandom(props.m_particle.m_minGravity, props.m_particle.m_maxGravity);
  88. // Set the initial position
  89. m_crntPosition = getRandom(props.m_particle.m_minStartingPosition, props.m_particle.m_maxStartingPosition);
  90. m_crntPosition += trf.getOrigin().xyz();
  91. }
  92. void simulate(Second prevUpdateTime, Second crntTime)
  93. {
  94. simulateCommon(prevUpdateTime, crntTime);
  95. const F32 dt = F32(crntTime - prevUpdateTime);
  96. const Vec3 xp = m_crntPosition;
  97. const Vec3 xc = m_acceleration * (dt * dt) + m_velocity * dt + xp;
  98. m_crntPosition = xc;
  99. m_velocity += m_acceleration * dt;
  100. }
  101. };
  102. /// Particle for bullet simulations
  103. class ParticleEmitterComponent::PhysicsParticle : public ParticleEmitterComponent::ParticleBase
  104. {
  105. public:
  106. PhysicsBodyPtr m_body;
  107. PhysicsParticle(const PhysicsBodyInitInfo& init, SceneNode* node, ParticleEmitterComponent* component)
  108. {
  109. m_body = node->getSceneGraph().getPhysicsWorld().newInstance<PhysicsBody>(init);
  110. m_body->setUserData(component);
  111. m_body->activate(false);
  112. m_body->setMaterialGroup(PhysicsMaterialBit::PARTICLE);
  113. m_body->setMaterialMask(PhysicsMaterialBit::STATIC_GEOMETRY);
  114. m_body->setAngularFactor(Vec3(0.0f));
  115. }
  116. void kill()
  117. {
  118. killCommon();
  119. m_body->activate(false);
  120. }
  121. void revive(const ParticleEmitterProperties& props, const Transform& trf, Second prevUpdateTime, Second crntTime)
  122. {
  123. reviveCommon(props, trf, prevUpdateTime, crntTime);
  124. // pre calculate
  125. const Bool forceFlag = props.forceEnabled();
  126. const Bool worldGravFlag = props.wordGravityEnabled();
  127. // Activate it
  128. m_body->activate(true);
  129. m_body->setLinearVelocity(Vec3(0.0f));
  130. m_body->setAngularVelocity(Vec3(0.0f));
  131. m_body->clearForces();
  132. // force
  133. if(forceFlag)
  134. {
  135. Vec3 forceDir = getRandom(props.m_particle.m_minForceDirection, props.m_particle.m_maxForceDirection);
  136. forceDir.normalize();
  137. // The forceDir depends on the particle emitter rotation
  138. forceDir = trf.getRotation().getRotationPart() * forceDir;
  139. const F32 forceMag =
  140. getRandomRange(props.m_particle.m_minForceMagnitude, props.m_particle.m_maxForceMagnitude);
  141. m_body->applyForce(forceDir * forceMag, Vec3(0.0f));
  142. }
  143. // gravity
  144. if(!worldGravFlag)
  145. {
  146. m_body->setGravity(getRandom(props.m_particle.m_minGravity, props.m_particle.m_maxGravity));
  147. }
  148. // Starting pos. In local space
  149. Vec3 pos = getRandom(props.m_particle.m_minStartingPosition, props.m_particle.m_maxStartingPosition);
  150. pos = trf.transform(pos);
  151. m_body->setTransform(Transform(pos.xyz0(), trf.getRotation(), 1.0f));
  152. m_crntPosition = pos;
  153. }
  154. void simulate(Second prevUpdateTime, Second crntTime)
  155. {
  156. simulateCommon(prevUpdateTime, crntTime);
  157. m_crntPosition = m_body->getTransform().getOrigin().xyz();
  158. }
  159. };
  160. ParticleEmitterComponent::ParticleEmitterComponent(SceneNode* node)
  161. : SceneComponent(node, getStaticClassId())
  162. , m_node(node)
  163. {
  164. }
  165. ParticleEmitterComponent::~ParticleEmitterComponent()
  166. {
  167. m_simpleParticles.destroy(m_node->getAllocator());
  168. m_physicsParticles.destroy(m_node->getAllocator());
  169. }
  170. Error ParticleEmitterComponent::loadParticleEmitterResource(CString filename)
  171. {
  172. // Create the debug drawer
  173. if(!m_dbgImage.isCreated())
  174. {
  175. ANKI_CHECK(m_node->getSceneGraph().getResourceManager().loadResource("EngineAssets/ParticleEmitter.ankitex",
  176. m_dbgImage));
  177. }
  178. // Load
  179. ANKI_CHECK(m_node->getSceneGraph().getResourceManager().loadResource(filename, m_particleEmitterResource));
  180. m_props = m_particleEmitterResource->getProperties();
  181. // Cleanup
  182. m_simpleParticles.destroy(m_node->getAllocator());
  183. m_physicsParticles.destroy(m_node->getAllocator());
  184. // Init particles
  185. m_simulationType = (m_props.m_usePhysicsEngine) ? SimulationType::PHYSICS_ENGINE : SimulationType::SIMPLE;
  186. if(m_simulationType == SimulationType::PHYSICS_ENGINE)
  187. {
  188. PhysicsCollisionShapePtr collisionShape = m_node->getSceneGraph().getPhysicsWorld().newInstance<PhysicsSphere>(
  189. m_props.m_particle.m_minInitialSize / 2.0f);
  190. PhysicsBodyInitInfo binit;
  191. binit.m_shape = collisionShape;
  192. m_physicsParticles.resizeStorage(m_node->getAllocator(), m_props.m_maxNumOfParticles);
  193. for(U32 i = 0; i < m_props.m_maxNumOfParticles; i++)
  194. {
  195. binit.m_mass = getRandomRange(m_props.m_particle.m_minMass, m_props.m_particle.m_maxMass);
  196. m_physicsParticles.emplaceBack(m_node->getAllocator(), binit, m_node, this);
  197. }
  198. }
  199. else
  200. {
  201. m_simpleParticles.create(m_node->getAllocator(), m_props.m_maxNumOfParticles);
  202. }
  203. m_vertBuffSize = m_props.m_maxNumOfParticles * VERTEX_SIZE;
  204. return Error::NONE;
  205. }
  206. Error ParticleEmitterComponent::update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated)
  207. {
  208. if(ANKI_UNLIKELY(!m_particleEmitterResource.isCreated()))
  209. {
  210. updated = false;
  211. return Error::NONE;
  212. }
  213. updated = true;
  214. if(m_simulationType == SimulationType::SIMPLE)
  215. {
  216. simulate(prevTime, crntTime, WeakArray<SimpleParticle>(m_simpleParticles));
  217. }
  218. else
  219. {
  220. ANKI_ASSERT(m_simulationType == SimulationType::PHYSICS_ENGINE);
  221. simulate(prevTime, crntTime, WeakArray<PhysicsParticle>(m_physicsParticles));
  222. }
  223. return Error::NONE;
  224. }
  225. template<typename TParticle>
  226. void ParticleEmitterComponent::simulate(Second prevUpdateTime, Second crntTime, WeakArray<TParticle> particles)
  227. {
  228. // - Deactivate the dead particles
  229. // - Calc the AABB
  230. // - Calc the instancing stuff
  231. Vec3 aabbMin(MAX_F32);
  232. Vec3 aabbMax(MIN_F32);
  233. m_aliveParticleCount = 0;
  234. F32* verts = reinterpret_cast<F32*>(m_node->getFrameAllocator().allocate(m_vertBuffSize));
  235. m_verts = verts;
  236. F32 maxParticleSize = -1.0f;
  237. for(TParticle& particle : particles)
  238. {
  239. if(particle.isDead())
  240. {
  241. // if its already dead so dont deactivate it again
  242. continue;
  243. }
  244. if(particle.m_timeOfDeath < crntTime)
  245. {
  246. // Just died
  247. particle.kill();
  248. }
  249. else
  250. {
  251. // It's alive
  252. // Do checks
  253. ANKI_ASSERT((ptrToNumber(verts) + VERTEX_SIZE - ptrToNumber(m_verts)) <= m_vertBuffSize);
  254. // This will calculate a new world transformation
  255. particle.simulate(prevUpdateTime, crntTime);
  256. const Vec3& origin = particle.m_crntPosition;
  257. aabbMin = aabbMin.min(origin);
  258. aabbMax = aabbMax.max(origin);
  259. verts[0] = origin.x();
  260. verts[1] = origin.y();
  261. verts[2] = origin.z();
  262. verts[3] = particle.m_crntSize;
  263. maxParticleSize = max(maxParticleSize, particle.m_crntSize);
  264. verts[4] = clamp(particle.m_crntAlpha, 0.0f, 1.0f);
  265. ++m_aliveParticleCount;
  266. verts += 5;
  267. }
  268. }
  269. // AABB
  270. if(m_aliveParticleCount != 0)
  271. {
  272. ANKI_ASSERT(maxParticleSize > 0.0f);
  273. const Vec3 min = aabbMin - maxParticleSize;
  274. const Vec3 max = aabbMax + maxParticleSize;
  275. m_worldBoundingVolume = Aabb(min, max);
  276. }
  277. else
  278. {
  279. m_worldBoundingVolume = Aabb(Vec3(0.0f), Vec3(0.001f));
  280. m_verts = nullptr;
  281. }
  282. //
  283. // Emit new particles
  284. //
  285. if(m_timeLeftForNextEmission <= 0.0)
  286. {
  287. U particleCount = 0; // How many particles I am allowed to emmit
  288. for(TParticle& particle : particles)
  289. {
  290. if(!particle.isDead())
  291. {
  292. // its alive so skip it
  293. continue;
  294. }
  295. particle.revive(m_props, m_transform, prevUpdateTime, crntTime);
  296. // do the rest
  297. ++particleCount;
  298. if(particleCount >= m_props.m_particlesPerEmission)
  299. {
  300. break;
  301. }
  302. } // end for all particles
  303. m_timeLeftForNextEmission = m_props.m_emissionPeriod;
  304. } // end if can emit
  305. else
  306. {
  307. m_timeLeftForNextEmission -= crntTime - prevUpdateTime;
  308. }
  309. }
  310. void ParticleEmitterComponent::draw(RenderQueueDrawContext& ctx) const
  311. {
  312. // Early exit
  313. if(ANKI_UNLIKELY(m_aliveParticleCount == 0))
  314. {
  315. return;
  316. }
  317. CommandBufferPtr& cmdb = ctx.m_commandBuffer;
  318. if(!ctx.m_debugDraw)
  319. {
  320. // Load verts
  321. StagingGpuMemoryToken token;
  322. void* gpuStorage = ctx.m_stagingGpuAllocator->allocateFrame(m_aliveParticleCount * VERTEX_SIZE,
  323. StagingGpuMemoryType::VERTEX, token);
  324. memcpy(gpuStorage, m_verts, m_aliveParticleCount * VERTEX_SIZE);
  325. // Program
  326. ShaderProgramPtr prog;
  327. m_particleEmitterResource->getRenderingInfo(ctx.m_key, prog);
  328. cmdb->bindShaderProgram(prog);
  329. // Vertex attribs
  330. cmdb->setVertexAttribute(U32(VertexAttributeId::POSITION), 0, Format::R32G32B32_SFLOAT, 0);
  331. cmdb->setVertexAttribute(U32(VertexAttributeId::SCALE), 0, Format::R32_SFLOAT, sizeof(Vec3));
  332. cmdb->setVertexAttribute(U32(VertexAttributeId::ALPHA), 0, Format::R32_SFLOAT, sizeof(Vec3) + sizeof(F32));
  333. // Vertex buff
  334. cmdb->bindVertexBuffer(0, token.m_buffer, token.m_offset, VERTEX_SIZE, VertexStepRate::INSTANCE);
  335. // Uniforms
  336. Array<Mat4, 1> trf = {Mat4::getIdentity()};
  337. RenderComponent::allocateAndSetupUniforms(m_particleEmitterResource->getMaterial(), ctx, trf, trf,
  338. *ctx.m_stagingGpuAllocator);
  339. // Draw
  340. cmdb->drawArrays(PrimitiveTopology::TRIANGLE_STRIP, 4, m_aliveParticleCount, 0, 0);
  341. }
  342. else
  343. {
  344. const Vec4 tsl = (m_worldBoundingVolume.getMin() + m_worldBoundingVolume.getMax()) / 2.0f;
  345. const Vec4 scale = (m_worldBoundingVolume.getMax() - m_worldBoundingVolume.getMin()) / 2.0f;
  346. // Set non uniform scale. Add a margin to avoid flickering
  347. Mat3 nonUniScale = Mat3::getZero();
  348. nonUniScale(0, 0) = scale.x();
  349. nonUniScale(1, 1) = scale.y();
  350. nonUniScale(2, 2) = scale.z();
  351. const Mat4 mvp = ctx.m_viewProjectionMatrix * Mat4(tsl.xyz1(), Mat3::getIdentity() * nonUniScale, 1.0f);
  352. const Bool enableDepthTest = ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DEPTH_TEST_ON);
  353. if(enableDepthTest)
  354. {
  355. cmdb->setDepthCompareOperation(CompareOperation::LESS);
  356. }
  357. else
  358. {
  359. cmdb->setDepthCompareOperation(CompareOperation::ALWAYS);
  360. }
  361. m_node->getSceneGraph().getDebugDrawer().drawCubes(
  362. ConstWeakArray<Mat4>(&mvp, 1), Vec4(1.0f, 0.0f, 1.0f, 1.0f), 2.0f,
  363. ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DITHERED_DEPTH_TEST_ON), 2.0f,
  364. *ctx.m_stagingGpuAllocator, cmdb);
  365. const Vec3 pos = m_transform.getOrigin().xyz();
  366. m_node->getSceneGraph().getDebugDrawer().drawBillboardTextures(
  367. ctx.m_projectionMatrix, ctx.m_viewMatrix, ConstWeakArray<Vec3>(&pos, 1), Vec4(1.0f),
  368. ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DITHERED_DEPTH_TEST_ON), m_dbgImage->getTextureView(),
  369. ctx.m_sampler, Vec2(0.75f), *ctx.m_stagingGpuAllocator, ctx.m_commandBuffer);
  370. // Restore state
  371. if(!enableDepthTest)
  372. {
  373. cmdb->setDepthCompareOperation(CompareOperation::LESS);
  374. }
  375. }
  376. }
  377. } // end namespace anki