ParticleEmitterNode.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. // Copyright (C) 2009-2018, 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/PhysicsWorld.h>
  14. #include <anki/Gr.h>
  15. namespace anki
  16. {
  17. static F32 getRandom(F32 initial, F32 deviation)
  18. {
  19. return (deviation == 0.0) ? initial : initial + randFloat(deviation) * 2.0 - deviation;
  20. }
  21. static Vec3 getRandom(const Vec3& initial, const Vec3& deviation)
  22. {
  23. if(deviation == Vec3(0.0))
  24. {
  25. return initial;
  26. }
  27. else
  28. {
  29. Vec3 out;
  30. for(U i = 0; i < 3; i++)
  31. {
  32. out[i] = getRandom(initial[i], deviation[i]);
  33. }
  34. return out;
  35. }
  36. }
  37. void ParticleBase::revive(
  38. const ParticleEmitterNode& pe, const Transform& trf, Second /*prevUpdateTime*/, Second crntTime)
  39. {
  40. ANKI_ASSERT(isDead());
  41. const ParticleEmitterProperties& props = pe;
  42. // life
  43. m_timeOfDeath = getRandom(crntTime + props.m_particle.m_life, props.m_particle.m_lifeDeviation);
  44. m_timeOfBirth = crntTime;
  45. }
  46. void ParticleSimple::simulate(const ParticleEmitterNode& pe, Second prevUpdateTime, Second crntTime)
  47. {
  48. Second dt = crntTime - prevUpdateTime;
  49. Vec4 xp = m_position;
  50. Vec4 xc = m_acceleration * (dt * dt) + m_velocity * dt + xp;
  51. m_position = xc;
  52. m_velocity += m_acceleration * dt;
  53. }
  54. void ParticleSimple::revive(const ParticleEmitterNode& pe, const Transform& trf, Second prevUpdateTime, Second crntTime)
  55. {
  56. ParticleBase::revive(pe, trf, prevUpdateTime, crntTime);
  57. m_velocity = Vec4(0.0);
  58. const ParticleEmitterProperties& props = pe;
  59. m_acceleration = getRandom(props.m_particle.m_gravity, props.m_particle.m_gravityDeviation).xyz0();
  60. // Set the initial position
  61. m_position = getRandom(props.m_particle.m_startingPos, props.m_particle.m_startingPosDeviation).xyz0();
  62. m_position += trf.getOrigin();
  63. }
  64. #if 0
  65. Particle::Particle(
  66. const char* name, SceneGraph* scene, // SceneNode
  67. // RigidBody
  68. PhysicsWorld* masterContainer, const RigidBody::Initializer& init_)
  69. : ParticleBase(name, scene, PT_PHYSICS)
  70. {
  71. RigidBody::Initializer init = init_;
  72. getSceneGraph().getPhysics().newPhysicsObject<RigidBody>(body, init);
  73. sceneNodeProtected.rigidBodyC = body;
  74. }
  75. Particle::~Particle()
  76. {
  77. getSceneGraph().getPhysics().deletePhysicsObject(body);
  78. }
  79. void Particle::revive(const ParticleEmitterNode& pe,
  80. F32 prevUpdateTime, F32 crntTime)
  81. {
  82. ParticleBase::revive(pe, prevUpdateTime, crntTime);
  83. const ParticleEmitterProperties& props = pe;
  84. // pre calculate
  85. Bool forceFlag = props.forceEnabled;
  86. Bool worldGravFlag = props.wordGravityEnabled;
  87. // activate it (Bullet stuff)
  88. body->forceActivationState(ACTIVE_TAG);
  89. body->activate();
  90. body->clearForces();
  91. body->setLinearVelocity(btVector3(0.0, 0.0, 0.0));
  92. body->setAngularVelocity(btVector3(0.0, 0.0, 0.0));
  93. // force
  94. if(forceFlag)
  95. {
  96. Vec3 forceDir = getRandom(props.particle.forceDirection,
  97. props.particle.forceDirectionDeviation);
  98. forceDir.normalize();
  99. if(!pe.identityRotation)
  100. {
  101. // the forceDir depends on the particle emitter rotation
  102. forceDir = pe.getWorldTransform().getRotation() * forceDir;
  103. }
  104. F32 forceMag = getRandom(props.particle.forceMagnitude,
  105. props.particle.forceMagnitudeDeviation);
  106. body->applyCentralForce(toBt(forceDir * forceMag));
  107. }
  108. // gravity
  109. if(!worldGravFlag)
  110. {
  111. body->setGravity(toBt(getRandom(props.particle.gravity,
  112. props.particle.gravityDeviation)));
  113. }
  114. // Starting pos. In local space
  115. Vec3 pos = getRandom(props.particle.startingPos,
  116. props.particle.startingPosDeviation);
  117. if(pe.identityRotation)
  118. {
  119. pos += pe.getWorldTransform().getOrigin();
  120. }
  121. else
  122. {
  123. pos.transform(pe.getWorldTransform());
  124. }
  125. btTransform trf(
  126. toBt(Transform(pos, pe.getWorldTransform().getRotation(), 1.0)));
  127. body->setWorldTransform(trf);
  128. }
  129. #endif
  130. /// The derived render component for particle emitters.
  131. class ParticleEmitterRenderComponent : public MaterialRenderComponent
  132. {
  133. public:
  134. const ParticleEmitterNode& getNode() const
  135. {
  136. return static_cast<const ParticleEmitterNode&>(getSceneNode());
  137. }
  138. ParticleEmitterRenderComponent(SceneNode* node)
  139. : MaterialRenderComponent(
  140. node, static_cast<ParticleEmitterNode*>(node)->m_particleEmitterResource->getMaterial())
  141. {
  142. }
  143. void setupRenderableQueueElement(RenderableQueueElement& el) const override
  144. {
  145. getNode().setupRenderableQueueElement(el);
  146. }
  147. };
  148. /// Feedback component
  149. class MoveFeedbackComponent : public SceneComponent
  150. {
  151. public:
  152. MoveFeedbackComponent(SceneNode* node)
  153. : SceneComponent(SceneComponentType::NONE, node)
  154. {
  155. }
  156. ANKI_USE_RESULT Error update(Second, Second, Bool& updated) override
  157. {
  158. updated = false; // Don't care about updates for this component
  159. MoveComponent& move = m_node->getComponent<MoveComponent>();
  160. if(move.getTimestamp() == m_node->getGlobalTimestamp())
  161. {
  162. static_cast<ParticleEmitterNode*>(m_node)->onMoveComponentUpdate(move);
  163. }
  164. return Error::NONE;
  165. }
  166. };
  167. ParticleEmitterNode::ParticleEmitterNode(SceneGraph* scene, CString name)
  168. : SceneNode(scene, name)
  169. {
  170. }
  171. ParticleEmitterNode::~ParticleEmitterNode()
  172. {
  173. // Delete simple particles
  174. if(m_simulationType == SimulationType::SIMPLE)
  175. {
  176. for(ParticleBase* part : m_particles)
  177. {
  178. getSceneAllocator().deleteInstance(part);
  179. }
  180. }
  181. m_particles.destroy(getSceneAllocator());
  182. }
  183. Error ParticleEmitterNode::init(const CString& filename)
  184. {
  185. // Load resource
  186. ANKI_CHECK(getResourceManager().loadResource(filename, m_particleEmitterResource));
  187. // Move component
  188. newComponent<MoveComponent>();
  189. // Move component feedback
  190. newComponent<MoveFeedbackComponent>();
  191. // Spatial component
  192. newComponent<SpatialComponent>(&m_obb);
  193. // Render component
  194. newComponent<ParticleEmitterRenderComponent>();
  195. // Other
  196. m_obb.setCenter(Vec4(0.0));
  197. m_obb.setExtend(Vec4(1.0, 1.0, 1.0, 0.0));
  198. m_obb.setRotation(Mat3x4::getIdentity());
  199. // copy the resource to me
  200. ParticleEmitterProperties& me = *this;
  201. const ParticleEmitterProperties& other = m_particleEmitterResource->getProperties();
  202. me = other;
  203. if(m_usePhysicsEngine)
  204. {
  205. createParticlesSimulation(&getSceneGraph());
  206. m_simulationType = SimulationType::PHYSICS_ENGINE;
  207. }
  208. else
  209. {
  210. createParticlesSimpleSimulation();
  211. m_simulationType = SimulationType::SIMPLE;
  212. }
  213. // Create the vertex buffer and object
  214. m_vertBuffSize = m_maxNumOfParticles * VERTEX_SIZE;
  215. return Error::NONE;
  216. }
  217. void ParticleEmitterNode::drawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
  218. {
  219. ANKI_ASSERT(userData.getSize() == 1);
  220. const ParticleEmitterNode& self = *static_cast<const ParticleEmitterNode*>(userData[0]);
  221. // Early exit
  222. if(ANKI_UNLIKELY(self.m_aliveParticlesCount == 0))
  223. {
  224. return;
  225. }
  226. CommandBufferPtr& cmdb = ctx.m_commandBuffer;
  227. if(!ctx.m_debugDraw)
  228. {
  229. // Load verts
  230. StagingGpuMemoryToken token;
  231. void* gpuStorage = ctx.m_stagingGpuAllocator->allocateFrame(
  232. self.m_aliveParticlesCount * VERTEX_SIZE, StagingGpuMemoryType::VERTEX, token);
  233. memcpy(gpuStorage, self.m_verts, self.m_aliveParticlesCount * VERTEX_SIZE);
  234. // Program
  235. ShaderProgramPtr prog;
  236. self.m_particleEmitterResource->getRenderingInfo(ctx.m_key.m_lod, prog);
  237. cmdb->bindShaderProgram(prog);
  238. // Vertex attribs
  239. cmdb->setVertexAttribute(0, 0, Format::R32G32B32_SFLOAT, 0);
  240. cmdb->setVertexAttribute(1, 0, Format::R32_SFLOAT, sizeof(Vec3));
  241. cmdb->setVertexAttribute(2, 0, Format::R32_SFLOAT, sizeof(Vec3) + sizeof(F32));
  242. // Vertex buff
  243. cmdb->bindVertexBuffer(0, token.m_buffer, token.m_offset, VERTEX_SIZE, VertexStepRate::INSTANCE);
  244. // Uniforms
  245. Array<Mat4, 1> trf = {{Mat4::getIdentity()}};
  246. static_cast<const MaterialRenderComponent&>(self.getComponent<RenderComponent>())
  247. .allocateAndSetupUniforms(self.m_particleEmitterResource->getMaterial()->getDescriptorSetIndex(),
  248. ctx,
  249. trf,
  250. trf,
  251. *ctx.m_stagingGpuAllocator);
  252. // Draw
  253. cmdb->drawArrays(PrimitiveTopology::TRIANGLE_STRIP, 4, self.m_aliveParticlesCount, 0, 0);
  254. }
  255. else
  256. {
  257. // TODO
  258. }
  259. }
  260. void ParticleEmitterNode::onMoveComponentUpdate(MoveComponent& move)
  261. {
  262. m_identityRotation = move.getWorldTransform().getRotation() == Mat3x4::getIdentity();
  263. SpatialComponent& sp = getComponent<SpatialComponent>();
  264. sp.setSpatialOrigin(move.getWorldTransform().getOrigin());
  265. sp.markForUpdate();
  266. }
  267. void ParticleEmitterNode::createParticlesSimulation(SceneGraph* scene)
  268. {
  269. #if 0
  270. collShape = getSceneAllocator().newInstance<btSphereShape>(particle.size);
  271. RigidBody::Initializer binit;
  272. binit.shape = collShape;
  273. binit.group = PhysicsWorld::CG_PARTICLE;
  274. binit.mask = PhysicsWorld::CG_MAP;
  275. particles.reserve(maxNumOfParticles);
  276. for(U i = 0; i < maxNumOfParticles; i++)
  277. {
  278. binit.mass = getRandom(particle.mass, particle.massDeviation);
  279. Particle* part = getSceneGraph().newSceneNode<Particle>(
  280. nullptr, &scene->getPhysics(), binit);
  281. part->size = getRandom(particle.size, particle.sizeDeviation);
  282. part->alpha = getRandom(particle.alpha, particle.alphaDeviation);
  283. part->getRigidBody()->forceActivationState(DISABLE_SIMULATION);
  284. particles.push_back(part);
  285. }
  286. #endif
  287. }
  288. void ParticleEmitterNode::createParticlesSimpleSimulation()
  289. {
  290. m_particles.create(getSceneAllocator(), m_maxNumOfParticles);
  291. for(U i = 0; i < m_maxNumOfParticles; i++)
  292. {
  293. ParticleSimple* part = getSceneAllocator().newInstance<ParticleSimple>();
  294. part->m_size = getRandom(m_particle.m_size, m_particle.m_sizeDeviation);
  295. part->m_alpha = getRandom(m_particle.m_alpha, m_particle.m_alphaDeviation);
  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. for(ParticleBase* p : m_particles)
  313. {
  314. if(p->isDead())
  315. {
  316. // if its already dead so dont deactivate it again
  317. continue;
  318. }
  319. if(p->getTimeOfDeath() < crntTime)
  320. {
  321. // Just died
  322. p->kill();
  323. }
  324. else
  325. {
  326. // It's alive
  327. // Do checks
  328. ANKI_ASSERT((PtrSize(verts) + VERTEX_SIZE - PtrSize(verts_base)) <= m_vertBuffSize);
  329. // This will calculate a new world transformation
  330. p->simulate(*this, prevUpdateTime, crntTime);
  331. const Vec4& origin = p->getPosition();
  332. aabbmin = aabbmin.min(origin);
  333. aabbmax = aabbmax.max(origin);
  334. F32 lifePercent = (crntTime - p->getTimeOfBirth()) / (p->getTimeOfDeath() - p->getTimeOfBirth());
  335. verts[0] = origin.x();
  336. verts[1] = origin.y();
  337. verts[2] = origin.z();
  338. // XXX set a flag for scale
  339. verts[3] = p->m_size + (lifePercent * m_particle.m_sizeAnimation);
  340. // Set alpha
  341. if(m_particle.m_alphaAnimation)
  342. {
  343. verts[4] = sin(lifePercent * PI) * p->m_alpha;
  344. }
  345. else
  346. {
  347. verts[4] = p->m_alpha;
  348. }
  349. verts[4] = clamp(verts[4], 0.0f, 1.0f);
  350. ++m_aliveParticlesCount;
  351. verts += 5;
  352. }
  353. }
  354. if(m_aliveParticlesCount != 0)
  355. {
  356. Vec4 min = aabbmin - m_particle.m_size;
  357. Vec4 max = aabbmax + m_particle.m_size;
  358. Vec4 center = (min + max) / 2.0;
  359. m_obb = Obb(center.xyz0(), Mat3x4::getIdentity(), (max - center).xyz0());
  360. }
  361. else
  362. {
  363. m_obb = Obb(Vec4(0.0), Mat3x4::getIdentity(), Vec4(Vec3(0.001f), 0.0f));
  364. m_verts = nullptr;
  365. }
  366. getComponent<SpatialComponent>().markForUpdate();
  367. //
  368. // Emit new particles
  369. //
  370. if(m_timeLeftForNextEmission <= 0.0)
  371. {
  372. MoveComponent& move = getComponent<MoveComponent>();
  373. U particlesCount = 0; // How many particles I am allowed to emmit
  374. for(ParticleBase* pp : m_particles)
  375. {
  376. ParticleBase& p = *pp;
  377. if(!p.isDead())
  378. {
  379. // its alive so skip it
  380. continue;
  381. }
  382. p.revive(*this, move.getWorldTransform(), prevUpdateTime, crntTime);
  383. // do the rest
  384. ++particlesCount;
  385. if(particlesCount >= m_particlesPerEmittion)
  386. {
  387. break;
  388. }
  389. } // end for all particles
  390. m_timeLeftForNextEmission = m_emissionPeriod;
  391. } // end if can emit
  392. else
  393. {
  394. m_timeLeftForNextEmission -= crntTime - prevUpdateTime;
  395. }
  396. return Error::NONE;
  397. }
  398. } // end namespace anki