ParticleEmitter2Component.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // Copyright (C) 2009-present, 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/ParticleEmitter2Component.h>
  6. #include <AnKi/Scene/Components/MeshComponent.h>
  7. #include <AnKi/Scene/Components/MoveComponent.h>
  8. #include <AnKi/Resource/ParticleEmitterResource2.h>
  9. #include <AnKi/Resource/ResourceManager.h>
  10. #include <AnKi/Resource/MeshResource.h>
  11. #include <AnKi/GpuMemory/RebarTransientMemoryPool.h>
  12. namespace anki {
  13. // Contains some shared geometry data and it's a singleton because we don't want to be wasting time and memory for every emitter
  14. class ParticleEmitter2Component::ParticleEmitterQuadGeometry : public MakeSingletonLazyInit<ParticleEmitterQuadGeometry>
  15. {
  16. public:
  17. UnifiedGeometryBufferAllocation m_quadPositions;
  18. UnifiedGeometryBufferAllocation m_quadUvs;
  19. UnifiedGeometryBufferAllocation m_quadIndices;
  20. GpuSceneArrays::MeshLod::Allocation m_gpuSceneMeshLods;
  21. U32 m_userCount = 0;
  22. SpinLock m_mtx;
  23. void init()
  24. {
  25. initGeom();
  26. initGpuScene();
  27. }
  28. void initGeom()
  29. {
  30. // Allocate and populate a quad
  31. const U32 vertCount = 4;
  32. const U32 indexCount = 6;
  33. m_quadPositions = UnifiedGeometryBuffer::getSingleton().allocateFormat(kMeshRelatedVertexStreamFormats[VertexStreamId::kPosition], vertCount);
  34. m_quadUvs = UnifiedGeometryBuffer::getSingleton().allocateFormat(kMeshRelatedVertexStreamFormats[VertexStreamId::kUv], vertCount);
  35. m_quadIndices = UnifiedGeometryBuffer::getSingleton().allocateFormat(Format::kR16_Uint, indexCount);
  36. static_assert(kMeshRelatedVertexStreamFormats[VertexStreamId::kPosition] == Format::kR16G16B16A16_Unorm);
  37. WeakArray<U16Vec4> transientPositions;
  38. const BufferView positionsAlloc = RebarTransientMemoryPool::getSingleton().allocateCopyBuffer(vertCount, transientPositions);
  39. transientPositions[0] = U16Vec4(0, 0, 0, 0);
  40. transientPositions[1] = U16Vec4(kMaxU16, 0, 0, 0);
  41. transientPositions[2] = U16Vec4(kMaxU16, kMaxU16, 0, 0);
  42. transientPositions[3] = U16Vec4(0, kMaxU16, 0, 0);
  43. static_assert(kMeshRelatedVertexStreamFormats[VertexStreamId::kUv] == Format::kR32G32_Sfloat);
  44. WeakArray<Vec2> transientUvs;
  45. const BufferView uvsAlloc = RebarTransientMemoryPool::getSingleton().allocateCopyBuffer(vertCount, transientUvs);
  46. transientUvs[0] = Vec2(0.0f);
  47. transientUvs[1] = Vec2(1.0f, 0.0f);
  48. transientUvs[2] = Vec2(1.0f, 1.0f);
  49. transientUvs[3] = Vec2(0.0f, 1.0f);
  50. WeakArray<U16> transientIndices;
  51. const BufferView indicesAlloc = RebarTransientMemoryPool::getSingleton().allocateCopyBuffer(indexCount, transientIndices);
  52. transientIndices[0] = 0;
  53. transientIndices[1] = 1;
  54. transientIndices[2] = 3;
  55. transientIndices[3] = 1;
  56. transientIndices[4] = 2;
  57. transientIndices[5] = 3;
  58. CommandBufferInitInfo cmdbInit("Particle quad upload");
  59. cmdbInit.m_flags |= CommandBufferFlag::kSmallBatch;
  60. CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cmdbInit);
  61. Buffer* dstBuff = &UnifiedGeometryBuffer::getSingleton().getBuffer();
  62. cmdb->copyBufferToBuffer(positionsAlloc, m_quadPositions);
  63. cmdb->copyBufferToBuffer(uvsAlloc, m_quadUvs);
  64. cmdb->copyBufferToBuffer(indicesAlloc, m_quadIndices);
  65. BufferBarrierInfo barrier;
  66. barrier.m_bufferView = BufferView(dstBuff);
  67. barrier.m_previousUsage = BufferUsageBit::kCopyDestination;
  68. barrier.m_nextUsage = dstBuff->getBufferUsage();
  69. cmdb->setPipelineBarrier({}, {&barrier, 1}, {});
  70. cmdb->endRecording();
  71. GrManager::getSingleton().submit(cmdb.get());
  72. }
  73. void initGpuScene()
  74. {
  75. GpuSceneMeshLod meshLod = {};
  76. meshLod.m_vertexOffsets[U32(VertexStreamId::kPosition)] =
  77. m_quadPositions.getOffset() / getFormatInfo(kMeshRelatedVertexStreamFormats[VertexStreamId::kPosition]).m_texelSize;
  78. meshLod.m_vertexOffsets[U32(VertexStreamId::kUv)] =
  79. m_quadUvs.getOffset() / getFormatInfo(kMeshRelatedVertexStreamFormats[VertexStreamId::kUv]).m_texelSize;
  80. meshLod.m_indexCount = 6;
  81. meshLod.m_firstIndex = m_quadIndices.getOffset() / sizeof(U16);
  82. meshLod.m_positionScale = 1.0f;
  83. meshLod.m_positionTranslation = Vec3(-0.5f, -0.5f, 0.0f);
  84. Array<GpuSceneMeshLod, kMaxLodCount> meshLods;
  85. meshLods.fill(meshLod);
  86. m_gpuSceneMeshLods.allocate();
  87. m_gpuSceneMeshLods.uploadToGpuScene(meshLods);
  88. }
  89. void deinit()
  90. {
  91. UnifiedGeometryBuffer::getSingleton().deferredFree(m_quadPositions);
  92. UnifiedGeometryBuffer::getSingleton().deferredFree(m_quadUvs);
  93. UnifiedGeometryBuffer::getSingleton().deferredFree(m_quadIndices);
  94. m_gpuSceneMeshLods.free();
  95. }
  96. void addUser()
  97. {
  98. LockGuard lock(m_mtx);
  99. if(m_userCount == 0)
  100. {
  101. init();
  102. }
  103. ++m_userCount;
  104. }
  105. void removeUser()
  106. {
  107. LockGuard lock(m_mtx);
  108. ANKI_ASSERT(m_userCount > 0);
  109. if(m_userCount == 1)
  110. {
  111. deinit();
  112. }
  113. --m_userCount;
  114. }
  115. };
  116. ParticleEmitter2Component::ParticleEmitter2Component(SceneNode* node)
  117. : SceneComponent(node, kClassType)
  118. {
  119. ParticleEmitterQuadGeometry::getSingleton().addUser();
  120. }
  121. ParticleEmitter2Component::~ParticleEmitter2Component()
  122. {
  123. ParticleEmitterQuadGeometry::getSingleton().removeUser();
  124. }
  125. ParticleEmitter2Component& ParticleEmitter2Component::setParticleEmitterFilename(CString fname)
  126. {
  127. ParticleEmitterResource2Ptr newRsrc;
  128. const Error err = ResourceManager::getSingleton().loadResource(fname, newRsrc);
  129. if(err)
  130. {
  131. ANKI_SCENE_LOGE("Failed to load resource: %s", fname.cstr());
  132. }
  133. else
  134. {
  135. m_particleEmitterResource = std::move(newRsrc);
  136. m_anyDirty = true;
  137. }
  138. return *this;
  139. }
  140. CString ParticleEmitter2Component::getParticleEmitterFilename() const
  141. {
  142. if(m_particleEmitterResource)
  143. {
  144. return m_particleEmitterResource->getFilename();
  145. }
  146. else
  147. {
  148. return "*Error*";
  149. }
  150. }
  151. void ParticleEmitter2Component::onOtherComponentRemovedOrAdded(SceneComponent* other, Bool added)
  152. {
  153. ANKI_ASSERT(other);
  154. if(other->getType() == SceneComponentType::kMesh)
  155. {
  156. bookkeepComponent(m_meshComponent, other, added);
  157. m_anyDirty = true;
  158. }
  159. }
  160. Bool ParticleEmitter2Component::isValid() const
  161. {
  162. Bool valid = !!m_particleEmitterResource;
  163. if(m_geomType == ParticleGeometryType::kMeshComponent)
  164. {
  165. valid = valid && m_meshComponent->isValid();
  166. }
  167. return valid;
  168. }
  169. void ParticleEmitter2Component::update(SceneComponentUpdateInfo& info, Bool& updated)
  170. {
  171. m_gpuSceneReallocationsThisFrame = false;
  172. m_dt = F32(info.m_dt);
  173. if(!isValid()) [[unlikely]]
  174. {
  175. for(auto& s : m_gpuScene.m_particleStreams)
  176. {
  177. GpuSceneBuffer::getSingleton().deferredFree(s);
  178. }
  179. GpuSceneBuffer::getSingleton().deferredFree(m_gpuScene.m_aliveParticleIndices);
  180. GpuSceneBuffer::getSingleton().deferredFree(m_gpuScene.m_anKiParticleEmitterProperties);
  181. m_gpuScene.m_gpuSceneParticleEmitter.free();
  182. m_gpuSceneReallocationsThisFrame = true;
  183. return;
  184. }
  185. if(!m_anyDirty) [[likely]]
  186. {
  187. return;
  188. }
  189. // From now on it's dirty, do all updates
  190. m_gpuSceneReallocationsThisFrame = true; // Difficult to properly track so set it to true and don't bother
  191. m_anyDirty = false;
  192. updated = true;
  193. const ParticleEmitterResourceCommonProperties& commonProps = m_particleEmitterResource->getCommonProperties();
  194. // Streams
  195. for(ParticleProperty prop : EnumIterable<ParticleProperty>())
  196. {
  197. GpuSceneBuffer::getSingleton().deferredFree(m_gpuScene.m_particleStreams[prop]);
  198. m_gpuScene.m_particleStreams[prop] =
  199. GpuSceneBuffer::getSingleton().allocate(commonProps.m_particleCount * kParticlePropertySize[prop], alignof(U32));
  200. }
  201. // Alive particles index buffer
  202. {
  203. GpuSceneBuffer::getSingleton().deferredFree(m_gpuScene.m_aliveParticleIndices);
  204. m_gpuScene.m_aliveParticleIndices = GpuSceneBuffer::getSingleton().allocate(commonProps.m_particleCount * sizeof(U32), alignof(U32));
  205. }
  206. // AnKiParticleEmitterProperties
  207. {
  208. GpuSceneBuffer::getSingleton().deferredFree(m_gpuScene.m_anKiParticleEmitterProperties);
  209. ConstWeakArray<U8> prefilled = m_particleEmitterResource->getPrefilledAnKiParticleEmitterProperties();
  210. m_gpuScene.m_anKiParticleEmitterProperties = GpuSceneBuffer::getSingleton().allocate(prefilled.getSizeInBytes(), alignof(U32));
  211. GpuSceneMicroPatcher::getSingleton().newCopy(*info.m_framePool, m_gpuScene.m_anKiParticleEmitterProperties, prefilled);
  212. }
  213. // GpuSceneParticleEmitter2
  214. {
  215. if(!m_gpuScene.m_gpuSceneParticleEmitter)
  216. {
  217. m_gpuScene.m_gpuSceneParticleEmitter.allocate();
  218. }
  219. GpuSceneParticleEmitter2 emitter;
  220. zeroMemory(emitter);
  221. for(ParticleProperty prop : EnumIterable<ParticleProperty>())
  222. {
  223. emitter.m_particleStateSteamOffsets[U32(prop)] = m_gpuScene.m_particleStreams[prop].getOffset();
  224. }
  225. emitter.m_aliveParticleIndicesOffset = m_gpuScene.m_aliveParticleIndices.getOffset();
  226. emitter.m_particleCount = commonProps.m_particleCount;
  227. emitter.m_emissionPeriod = commonProps.m_emissionPeriod;
  228. emitter.m_particlesPerEmission = commonProps.m_particlesPerEmission;
  229. emitter.m_particleEmitterPropertiesOffset = m_gpuScene.m_anKiParticleEmitterProperties.getOffset();
  230. if(m_geomType == ParticleGeometryType::kMeshComponent)
  231. {
  232. const MeshResource& meshr = m_meshComponent->getMeshResource();
  233. emitter.m_particleAabbMin = meshr.getBoundingShape().getMin().xyz();
  234. emitter.m_particleAabbMax = meshr.getBoundingShape().getMax().xyz();
  235. }
  236. else
  237. {
  238. emitter.m_particleAabbMin = Vec3(-0.5f);
  239. emitter.m_particleAabbMax = Vec3(+0.5f);
  240. }
  241. emitter.m_reinitializeOnNextUpdate = 1;
  242. emitter.m_worldTransformsIndex = info.m_node->getFirstComponentOfType<MoveComponent>().getGpuSceneTransformsIndex();
  243. emitter.m_uuid = getUuid();
  244. m_gpuScene.m_gpuSceneParticleEmitter.uploadToGpuScene(emitter);
  245. }
  246. }
  247. U32 ParticleEmitter2Component::getGpuSceneMeshLodIndex(U32 submeshIdx) const
  248. {
  249. ANKI_ASSERT(isValid());
  250. if(m_geomType == ParticleGeometryType::kQuad)
  251. {
  252. return ParticleEmitterQuadGeometry::getSingleton().m_gpuSceneMeshLods.getIndex() * kMaxLodCount;
  253. }
  254. else
  255. {
  256. return m_meshComponent->getGpuSceneMeshLodsIndex(submeshIdx);
  257. }
  258. }
  259. } // end namespace anki