From 2f4a316a094c71aa947aa0161a22843afebe80f3 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 13 Mar 2023 11:41:23 +0800 Subject: [PATCH] Particles WIP --- Assets/Shaders/ParticleEmit_CS.glsl | 27 +++-- Assets/Shaders/ParticleEmit_CS.shshaderb | Bin 0 -> 7197 bytes .../Shaders/ParticleEmit_CS.shshaderb.shmeta | 3 + Assets/Shaders/ParticleUpdate_CS.glsl | 17 ++-- Assets/Shaders/ParticleUpdate_CS.shshaderb | Bin 0 -> 6229 bytes .../ParticleUpdate_CS.shshaderb.shmeta | 3 + Assets/Shaders/Particle_FS.glsl | 15 +++ Assets/Shaders/Particle_FS.shshaderb | Bin 0 -> 537 bytes Assets/Shaders/Particle_FS.shshaderb.shmeta | 3 + Assets/Shaders/Particle_VS.glsl | 93 +++++++++++++++++ Assets/Shaders/Particle_VS.shshaderb | Bin 0 -> 6005 bytes Assets/Shaders/Particle_VS.shshaderb.shmeta | 3 + .../Inspector/SHEditorComponentView.hpp | 29 ++++++ .../Graphics/Commands/SHVkCommandBuffer.cpp | 15 ++- .../src/Graphics/Commands/SHVkCommandBuffer.h | 7 +- .../Graphics/MiddleEnd/Batching/SHBatch.cpp | 2 +- .../GlobalData/SHGraphicsPredefinedData.cpp | 2 +- .../MiddleEnd/Interface/SHDebugDrawSystem.cpp | 2 +- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 7 ++ .../MiddleEnd/Interface/SHGraphicsSystem.h | 4 + .../Particles/SHParticleEmitterComponent.cpp | 20 ++++ .../Particles/SHParticleEmitterComponent.h | 6 ++ .../Particles/SHParticleSubSystem.cpp | 94 ++++++++++++++---- .../MiddleEnd/Particles/SHParticleSubSystem.h | 2 + .../SHTrajectoryRenderingSubSystem.cpp | 2 +- 25 files changed, 314 insertions(+), 42 deletions(-) create mode 100644 Assets/Shaders/ParticleEmit_CS.shshaderb create mode 100644 Assets/Shaders/ParticleEmit_CS.shshaderb.shmeta create mode 100644 Assets/Shaders/ParticleUpdate_CS.shshaderb create mode 100644 Assets/Shaders/ParticleUpdate_CS.shshaderb.shmeta create mode 100644 Assets/Shaders/Particle_FS.glsl create mode 100644 Assets/Shaders/Particle_FS.shshaderb create mode 100644 Assets/Shaders/Particle_FS.shshaderb.shmeta create mode 100644 Assets/Shaders/Particle_VS.glsl create mode 100644 Assets/Shaders/Particle_VS.shshaderb create mode 100644 Assets/Shaders/Particle_VS.shshaderb.shmeta diff --git a/Assets/Shaders/ParticleEmit_CS.glsl b/Assets/Shaders/ParticleEmit_CS.glsl index 421e2ce1..33beaccc 100644 --- a/Assets/Shaders/ParticleEmit_CS.glsl +++ b/Assets/Shaders/ParticleEmit_CS.glsl @@ -7,7 +7,7 @@ struct EmitterParameters vec4 angularMin; vec4 angularMax; vec4 lifeAndSizeRange; // min life, max life, min size, max size -} +}; struct ParticleData { @@ -18,7 +18,7 @@ struct ParticleData vec4 scaleAndDecay; float life; uint textureIndex; -} +}; struct GenericData { @@ -96,9 +96,15 @@ float rand(inout uint state) return float(x)*uintBitsToFloat(0x2f800004u); } +float map(float value, float inMin, float inMax, float outMin, float outMax) +{ + return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin); +} + void main() { uint emitterInvocationIndex = gl_GlobalInvocationID.x; + vec4 emitterPosition = emitterPushConstant.emitterPosition; if (emitterInvocationIndex >= emitterPushConstant.emissionCount) return; @@ -109,9 +115,18 @@ void main() ParticleData particle; - int index = freelist.freeIndices[freelistIndex]; - particle.position = emitterPosition; - particle.life = emitterParams.10.0f; + // Get seed for randomization + uint pixel_index = uint (emitterPosition.x + emitterPosition.y + floatBitsToUint(genericDataBuffer.data.elapsedTime) * (gl_GlobalInvocationID.x + 1)); + uint seed = pcg_hash (pixel_index); - particles[index] = particle; + int index = freelist.freeIndices[freelistIndex]; + + // emit particle from emitter position + particle.position = vec4 (emitterPosition.xyz, 1.0f); + + // randomize life value that ranges from minLife to maxLife + particle.life = map (rand(seed), -1.0f, 1.0f, emitterParams.data.lifeAndSizeRange.x, emitterParams.data.lifeAndSizeRange.y); + + + inputParticles.data[index] = particle; } \ No newline at end of file diff --git a/Assets/Shaders/ParticleEmit_CS.shshaderb b/Assets/Shaders/ParticleEmit_CS.shshaderb new file mode 100644 index 0000000000000000000000000000000000000000..e0318886a5ac002a537ec1c652a1d9c162dc37f8 GIT binary patch literal 7197 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 k(y86>Rno&ekuW~+yL>%YOD7k$?Vig?XI 0.0f) + if (particle.life > 0.0f) { - // particle.position += particle.velocity * dt; - - // particle.lifetime -= dt; - // particle.size -= 1.2f * dt; - // particle.color += 1.0f * dt; - if (particle.lifetime < 0.0f || particle.size < 0.0f) + if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f) { - particle.lifetime = 0.0f; + particle.life = 0.0f; particle.position.x = 99999.0f; outputParticles.data[index] = particle; diff --git a/Assets/Shaders/ParticleUpdate_CS.shshaderb b/Assets/Shaders/ParticleUpdate_CS.shshaderb new file mode 100644 index 0000000000000000000000000000000000000000..53c89d01ec7756fe8677723c7f5996f0278f6b8d GIT binary patch literal 6229 zcmZ{n>31B}5ycy8MiLOf7_)?ckQbKN#E8TY5|&t4_EBgBX{Xs$0e6u|3~tcMr$y>CQ^G8Ru!YGd)$T4@a9c z&&64uHrvTmoX0Y?gAzyYb^9rV5NAJGH!lK(IQv^k+TCWFpD6K>B0gPP7rA<|juqQC8QL7f0A{fDLJ$?<$SOQx%B%C8=67T&A&fqz|$OEsTu zZ{Upedjmh)-oVecH}D_Z8*4wdH`dng4eacD8;vg4n)lJ4?(~-PyO$Rhl1y;XE7lpU z>ipRIPi3dL4v6F&jUE<0fM%ETFc^Jjoe{=5D7#y@4wyx(CE){Pf0iWewC~cmL##6v zw6wRo+{vXIr_bOz#I%|86|Ww3D~vEw3+$xkRu&)gVY7#S3!4%)nPu?_HKhDxCbPwU z*$>tk%|XtQfsNnoZ`rdd+Us3s`(n~PL5ASll zz}fFg@7}oVdx;hII8Ba$k`q4r>}B1fVAS@W>}HS$?0sR4q?2T6v#PgNV1lET5>N|1 z6BtOk4R8`FV}}E2@dL14+7gMDghJ2f~A#gG*1{tTEQ^ z=}7dE?8UVj2mZu5qqTiYX`Uz9+;acO-fnTG^q^eRa+Fl-e)7Cl>}e_O_w^3?9uxDE zfD^`S=*#EbMXr(@P`!NLjBVvKz=#dDQDQ%O1vVaF^azX}BKz^afb9t|-W9O90OMT& zdq_fUmuUt&Bsn14?+0^eU$V~Tr<2_FCnlqz8w55~=(XbQ*(#lVkdL=$i-f&mQ%9KJ zZ;tcZF7vOwNnt*GobRCYFdsJgoWCudeDsU``CW28+s~>;m2>iG2(#zq`+#$8zps6FK-sZ_1bnm>IEYXXT)0- z){9NO+%MK&)*SZKZd{5jZ_Uw1h@i-$e`bCZQ zasM{1!}P~r_05$$dK&WFzTjVa3kR1)W$nX zAHdiPHuu`Sxl;PLg!8~e7)}O3&_KUq(*~G^_TG>8_wrqMhrZwJVbTEAR9~*LklM9=-8I1K_rI-BS z;+-aLD4g#pVZ7mRUZ^-=#Kb;bVeH#)C%jjLW5av3@&SW~%{%CGBj;O^RmqL2fNz0! z5sW?~SBUqHW_nZJ@A7X%Y;X(t-jz*k-Xrp1^B#eXDL(H9Jw?1!ib>Pv+bp9nSR=9Blj?^H%AO$$60b*Anp06odEYw-v^_^nb;;Lo?%B`LlMr1dRKI z?$~!qUmyD}Vc?%uv41BWjM)EEJo4?4fRpQP%?xtw(L5;uBNsY%i{9*&kc)o$ezKP- z32V-`ufoXpjbb``3$O+lLBlxG=DOVB=@b)6(IDcjT|K;ZQHNV&iAd-=xC{@5nQ< z;rNbV<7dvQbU5K1`MYd5z9ZPH5_6uF4yPvZex8#K$9Du9KR6pTKQDn3-jRREhBF~y zKiK%e;a>bx0w=s9|B?;IcLW gA)PaK{5Pe)CLun)!~nyOxAzXs+#6=@&~1|M0SN<74*&oF literal 0 HcmV?d00001 diff --git a/Assets/Shaders/ParticleUpdate_CS.shshaderb.shmeta b/Assets/Shaders/ParticleUpdate_CS.shshaderb.shmeta new file mode 100644 index 00000000..cf9a5051 --- /dev/null +++ b/Assets/Shaders/ParticleUpdate_CS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: ParticleUpdate_CS +ID: 36260925 +Type: 2 diff --git a/Assets/Shaders/Particle_FS.glsl b/Assets/Shaders/Particle_FS.glsl new file mode 100644 index 00000000..d365b110 --- /dev/null +++ b/Assets/Shaders/Particle_FS.glsl @@ -0,0 +1,15 @@ +#version 460 core + +layout (location = 0) out vec4 fragColor; + +// between shader stages +layout(location = 0) in struct +{ + vec2 uv; // location = 0 + +} In; + +void main () +{ + fragColor = vec4 (1.0f); +} diff --git a/Assets/Shaders/Particle_FS.shshaderb b/Assets/Shaders/Particle_FS.shshaderb new file mode 100644 index 0000000000000000000000000000000000000000..19e503b2eeedd6e8d92ec7b00034a41a3fd84484 GIT binary patch literal 537 zcmYjN!AiqG6daQ#t*vb%g5FBSqf$I*5d?cE5`;hxe!xzLb0v2i(UVMK2Lw?AJkvkr=QQg_k>Fxe0h%NobTD+_TVutdW&NXMAEK;=^>2vxFB=5(kQ|s2|;MUs-MsGGaak-YN%u^aOF;WKI>)eeE$M>f4l8oZ8`2wPt##)fh|bH3Ns})xHLyW;V;NU(Yp!%!c(Ay6N#^(qguQ;LMuOp}+ew z3cuNG;;!Yhje^~5Hu0OyCjL&dX?v&Hv@M@a?B=trOb%m*fLHd)40zw|n-wXHacx%2_Yt?Vu z_gVZ}?e1KynLVF2oNFL?7Od7f*Yx0w_pZg+obs&8i)KHbH#er%Jkf5X%_9CXSbo1q z;4HsDr~Y)>Ev`5!Xn`whi)-qg)8BK<@vPN5MQi$n&9lUIq?vWbvSOwso9C%*q1jxr zxgS?dz_RD7@FTT3ZgVk+y@@fmyrLZ9gMsoondz zN*%GkfQ_fEw42q-^Bc%9;G{tTd(p?5X|vXuPaCJRxfFCb$D?ki-R+&p8ol%Qh0Xf* zq-`S2&YdTp=l56eO3fSYo;Fuw>Fy0De@8!ey~id0aqfoStt|$y)cqd&9h6T{Z4~ah zuV71<^N6j7!p~X6Mk<&yi1`O0{CtOEqZMqh#HK5l?@zzeki8v(i=Blg&=131{)wvU z8*=^nJ2Z!DoO@$Te=ZN?Z*m**ii*Cqq8~-Jp8cBt7~B>0LXUc(SL=yIJ>PJ(p1SqS z?|l9pbnkaU?v?MxCFTmO4_Qnem@|l3D==lTB7c9LPe1Kf;jZY_`NYiWS%i|Mwu9Uu=J=Z!fXvX$QJX|M$Y}&))S{_xmHJ{R43G zS<5}x1GgVB?GM78Up#t!1etYk7iVVNK1fV5$A{qN@cg&n;qM!<<)n{$WSs+W>*#CD zD15npJudvdv_eY z57Pf5rOjOGA1(FKQhx&OO!ggTa|YQOp+AM}UWfi^WcMxfv&e&x`D<|Vxo=@_AX{Hu z&d-Xa{<_Hedq$hEUx3?-`OU{q=iDy73rXAakayAh85Fk9l~~mtwihb?VGrBqD>id# z*Jj-pA#0l39Qxi%Z$F1Sr}J!KGQZdMC#FquhF`+nKkc58`V~mbxT|pEtQBP3uh2aQ z?Z&BJD>3bFl(I4EZ^O-LF7x{Bvlq#Im%LAYue2HSH@G##tfB5VOzaU(Rqk21%>5q_ z&sty4&Hty7t3L?eThR|7AFSxwXDfOQ`PquzMV_zdp1r?EBft9PQh%I!elK=Hek)!; zcfMUEc7Sf}P5rU*8?YOBH6(rr%dzQzS_KZ_TV0h$BZ9F_Dvrm#`io4O+fanO+RNp0cq3E zcRmG;LHcRaZxlWaX|pfy%E=Og<#Rs)KLvSq#@ds*ei3sT**wnTUK#T-$e8tzG3xq7 z%#+B*c&8%fam=Vm^s%%u|pt>iR{@r;v^D-bT!4kd5)%WsJIh z#;k@;nPOeXCo9o9c1yPv zA?x1-8L!=XzFTcER}a~_+~1gM0a<*CT)vw{NKA4$lev8J+LSNCUxcE^myoqrd%T1$ z?mhRMUWSa@0qJKRu}e_o`2whbL;9IVOh4tzaC?ir`VzAH;JLV0 zUxwVPwUD;R`xRtktNn@TAGyAYT+Q`0baSnNv_-D3BS)_2QB42H^$p}|u5Y48E^RNB z_u*T}+9LP2kJi6l$f#8 z+-Gb36f$0a?e{>@+s}}lCB9MW`fGm!{%hzO#9&LpL0=8IZiV*YHw<3|`CDQQJbp{8Mb_qQL-5-m{r*Xwb?|pV?w5G{z28vc);C@~ z;_pBf`xo)%yA!${5`PP96Z|end?WN``Ht@`ap%7qihNs;tNGrIz8Mmad?U!>)qGpg V#UtNzxi8zmtfl>b?1j4f_J8TFFVFx0 literal 0 HcmV?d00001 diff --git a/Assets/Shaders/Particle_VS.shshaderb.shmeta b/Assets/Shaders/Particle_VS.shshaderb.shmeta new file mode 100644 index 00000000..8b44df47 --- /dev/null +++ b/Assets/Shaders/Particle_VS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: Particle_VS +ID: 35035037 +Type: 2 diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 03a37a69..388667a3 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -30,6 +30,7 @@ #include "../SHEditorWindowManager.h" #include "../AssetBrowser/SHAssetBrowser.h" #include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h" +#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h" #include "Animation/SHAnimationClip.h" namespace SHADE @@ -804,4 +805,32 @@ namespace SHADE ImGui::PopID(); } + template<> + static void DrawComponent(SHParticleEmitterComponent* component) + { + if (!component) + return; + + ImGui::PushID(SHFamilyID::GetID()); + + const auto componentType = rttr::type::get(*component); + + SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); + + ImGui::SameLine(); + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) + { + DrawContextMenu(component); + + SHEditorWidgets::DragFloat("Emission Count", [comp = component]() {return comp->GetEmissionCount(); }, [comp = component](float count) {comp->SetEmissionCount(count);}); + SHEditorWidgets::CheckBox("Is Passive", [comp = component]() {return comp->GetPassive(); }, [comp = component](bool flag) {comp->SetPassive(flag); }); + + } + else + { + DrawContextMenu(component); + } + ImGui::PopID(); + } + } diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp index 37b89883..3aea863c 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp @@ -450,7 +450,7 @@ namespace SHADE */ /***************************************************************************/ - void SHVkCommandBuffer::DrawMultiIndirect(Handle indirectDrawData, uint32_t drawCount) + void SHVkCommandBuffer::DrawMultiIndirectIndexed(Handle indirectDrawData, uint32_t drawCount) { if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING) { @@ -462,6 +462,19 @@ namespace SHADE vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand)); } + void SHVkCommandBuffer::DrawMultiIndirect(Handle indirectDrawData, uint32_t drawCount) + { + if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING) + { + SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound."); + return; + } + + if (indirectDrawData) + vkCommandBuffer.drawIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand)); + + } + void SHVkCommandBuffer::ComputeDispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept { vkCommandBuffer.dispatch (groupCountX, groupCountY, groupCountZ); diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h index c6a17d2a..c42ff33c 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h @@ -128,9 +128,10 @@ namespace SHADE void BindDescriptorSet (Handle descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span const dynamicOffsets); // Draw Commands - void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept; - void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept; - void DrawMultiIndirect (Handle indirectDrawData, uint32_t drawCount); + void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept; + void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept; + void DrawMultiIndirectIndexed (Handle indirectDrawData, uint32_t drawCount); + void DrawMultiIndirect (Handle indirectDrawData, uint32_t drawCount); // Compute Commands void ComputeDispatch (uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index 4aa33de5..e2a6ec66 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -755,7 +755,7 @@ namespace SHADE } } - cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast(drawData.size())); + cmdBuffer->DrawMultiIndirectIndexed(drawDataBuffer[frameIndex], static_cast(drawData.size())); cmdBuffer->EndLabeledSegment(); } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp index 76d34ff7..d07ad2f4 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp @@ -251,7 +251,7 @@ namespace SHADE // particle draw call binding SHVkDescriptorSetLayout::Binding particleDrawDataBinding { - .Type = vk::DescriptorType::eUniformBufferDynamic, // UBO (Because lesser data), dynamic (1 set for each frame) + .Type = vk::DescriptorType::eStorageBufferDynamic, // UBO (Because lesser data), dynamic (1 set for each frame) .Stage = vk::ShaderStageFlagBits::eCompute, .BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA, .DescriptorCount = 1, diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index d9a740ac..1fb9babe 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -730,7 +730,7 @@ namespace SHADE cmdBuffer->BindVertexBuffer(COLOR_BIND_PT, batch.InstanceColorBuffer[frameIndex], 0); // Execute draw - cmdBuffer->DrawMultiIndirect(batch.MDIBuffer[frameIndex], static_cast(batch.MDIData.size())); + cmdBuffer->DrawMultiIndirectIndexed(batch.MDIBuffer[frameIndex], static_cast(batch.MDIData.size())); } void SHDebugDrawSystem::destroyBatch(MeshBatch& batch) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 69aa4188..59813cd3 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -144,6 +144,10 @@ namespace SHADE //SHAssetManager::CompileAsset("../../Assets/Shaders/Trajectory_FS.glsl", false); //SHAssetManager::CompileAsset("../../Assets/Shaders/ShadowMapBlur_CS.glsl", false); //SHAssetManager::CompileAsset("../../Assets/Shaders/Anim_VS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/Particle_VS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/Particle_FS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/ParticleEmit_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/ParticleUpdate_CS.glsl", false); // Load Built In Shaders static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet(VS_DEFAULT); @@ -165,6 +169,9 @@ namespace SHADE static constexpr AssetID TRAJECTORY_VS = 41042628; trajectoryVS = SHResourceManager::LoadOrGet(TRAJECTORY_VS); static constexpr AssetID TRAJECTORY_FS = 45635685; trajectoryFS = SHResourceManager::LoadOrGet(TRAJECTORY_FS); static constexpr AssetID SHADOW_BLUR_CS = 38004013; shadowMapBlurCS = SHResourceManager::LoadOrGet(SHADOW_BLUR_CS); + static constexpr AssetID PARTICLE_VS = 35035037; particleVS = SHResourceManager::LoadOrGet(PARTICLE_VS); + static constexpr AssetID PARTICLE_EMIT_CS = 42509714; particleEmitCS = SHResourceManager::LoadOrGet(PARTICLE_EMIT_CS); + static constexpr AssetID PARTICLE_UPDATE_CS = 36260925; particleUpdateCS = SHResourceManager::LoadOrGet(PARTICLE_UPDATE_CS); } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index e674efb6..a199464c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -484,6 +484,10 @@ namespace SHADE Handle trajectoryVS; Handle trajectoryFS; Handle shadowMapBlurCS; + Handle particleVS; + Handle particleFS; + Handle particleEmitCS; + Handle particleUpdateCS; // Fonts Handle testFont; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp index 12690ece..c7dca2a0 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp @@ -20,4 +20,24 @@ namespace SHADE toEmit = true; } + void SHParticleEmitterComponent::SetEmissionCount(float count) noexcept + { + emissionCount = count; + } + + bool SHParticleEmitterComponent::SetPassive(bool flag) noexcept + { + isPassive = flag; + } + + float SHParticleEmitterComponent::GetEmissionCount(void) noexcept + { + return emissionCount; + } + + bool SHParticleEmitterComponent::GetPassive(void) noexcept + { + return isPassive; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h index 30f7f107..7b519e85 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h @@ -105,6 +105,12 @@ namespace SHADE void Emit (void) noexcept; + void SetEmissionCount (float count) noexcept; + bool SetPassive (bool flag) noexcept; + + float GetEmissionCount (void) noexcept; + bool GetPassive (void) noexcept; + friend class SHParticleSubSystem; }; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp index 7c3d9c74..95e9818f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp @@ -60,7 +60,7 @@ namespace SHADE } // buffer to store draw call data. Non-indexed, host-visible mapped, triple buffered. - comp.drawCallData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmd, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmd, vk::BufferUsageFlagBits::eUniformBuffer | vk::BufferUsageFlagBits::eIndirectBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT); + comp.drawCallData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmd, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmd, vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndirectBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT); } @@ -150,6 +150,59 @@ namespace SHADE void SHParticleSubSystem::RenderComponent(Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept { + cmdBuffer->DrawMultiIndirect(comp.drawCallData, 1); + } + + void SHParticleSubSystem::PreparePrePostUpdateBarriers(std::vector& preUpdateBarriers, std::vector& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept + { + // pre-update particles data barrier. Note that this is for input because we want the input to be available before we use it. + vk::BufferMemoryBarrier particleDataBarrier + { + .srcAccessMask = vk::AccessFlagBits::eShaderWrite, + .dstAccessMask = vk::AccessFlagBits::eShaderRead, + .buffer = emitter.particleData->GetVkBuffer(), + .offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_PARTICLE_INPUT], + .size = emitter.chunkSize + }; + + // pre-update free list data barrier + vk::BufferMemoryBarrier freelistDataBarrier + { + .srcAccessMask = vk::AccessFlagBits::eShaderWrite, + .dstAccessMask = vk::AccessFlagBits::eShaderRead, + .buffer = emitter.freelistData->GetVkBuffer(), + .offset = 0, // Only 1 copy of freelist data, so offset is at 0 + .size = static_cast(sizeof (uint32_t)) * (emitter.maxParticles + 1) + }; + + // ...copy assign barriers on heap + preUpdateBarriers[EMITTER_INDEX * 2] = particleDataBarrier; + preUpdateBarriers[(EMITTER_INDEX * 2) + 1] = freelistDataBarrier; + + // make new barrier on stack... + vk::BufferMemoryBarrier particleDataBarrierPost + { + .srcAccessMask = vk::AccessFlagBits::eShaderWrite, + .dstAccessMask = vk::AccessFlagBits::eShaderRead, + .buffer = emitter.particleData->GetVkBuffer(), + .offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_PARTICLE_OUTPUT], + .size = emitter.chunkSize + }; + + // make new barrier on stack... + vk::BufferMemoryBarrier indicesDataBarrier + { + .srcAccessMask = vk::AccessFlagBits::eShaderWrite, + .dstAccessMask = vk::AccessFlagBits::eShaderRead, + .buffer = emitter.indicesData->GetVkBuffer(), + .offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_INDICES_DATA], + .size = static_cast(sizeof(uint32_t)) * emitter.maxParticles + }; + + + // ...copy assign barriers on heap + postUpdateBarriers[EMITTER_INDEX * 2] = particleDataBarrierPost; + postUpdateBarriers[(EMITTER_INDEX * 2) + 1] = indicesDataBarrier; } @@ -203,10 +256,19 @@ namespace SHADE // Get offset into GPU emitter data (for updating) uint32_t emitterDataOffset = frameIndex * sizeof (SHParticleEmitterComponent::GPUEmitterStruct); + // TODO: OPTIONAL but eventually these barriers can be moved to the system as member variables. This would require additional bookkeeping + // but it will be more efficient than populating a vector every frame. + // Barriers to make sure emitting shader is done completely before update is run. - // Every emitter will have its own barrier. + // Every emitter will have its own barrier for its particle data and freelist data. Indices data is not needed since + // it's mainly used in update and rendering so a barrier for it is NOT needed here. std::vector preUpdateBarriers{}; - preUpdateBarriers.resize(emitters.size()); + preUpdateBarriers.resize(emitters.size() * 2); + + // After we invoke the updates for the emitters, we need to make sure all particles and indices data are done updating + // before we issue them for rendering. + std::vector postUpdateBarriers{}; + postUpdateBarriers.resize(emitters.size() * 2); // If we wanted to be VERY safe, a barrier would be good here to make sure output particles have finish reading input particles in // the update compute. HOWEVER since a NUM_FRAME_BUFFERS frames would have passed by then, we will not insert 1 here. @@ -255,19 +317,10 @@ namespace SHADE EmitComponent(cmdBuffer, emitter, frameIndex); } - // make new barrier on stack... - vk::BufferMemoryBarrier barrier - { - .srcAccessMask = vk::AccessFlagBits::eShaderWrite, - .dstAccessMask = vk::AccessFlagBits::eShaderRead, - .buffer = emitter.particleData->GetVkBuffer(), - .offset = emitter.dynamicOffsets[frameIndex][DYOFF_INDEX_PARTICLE_INPUT], - .size = emitter.chunkSize - }; - - // ...copy assign barrier on heap - preUpdateBarriers[i] = barrier; + // prepare barriers + PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, emitter, i, frameIndex); + // Emitter will emit once and stop emitting next frame (unless specified before reaching here to do so). emitter.toEmit = false; ++i; } @@ -275,6 +328,8 @@ namespace SHADE // issue the barrier to wait cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {}); + + /*-----------------------------------------------------------------------*/ /* EMITTING PARTICLES DONE, BEGIN UPDATES.... */ /*-----------------------------------------------------------------------*/ @@ -287,7 +342,12 @@ namespace SHADE UpdateCompoennt(cmdBuffer, emitter, frameIndex); } - + /*-----------------------------------------------------------------------*/ + /* AFTER UPDATING, RENDER PARTICLES */ + /*-----------------------------------------------------------------------*/ + // issue the barrier to wait for output particles to be done updating and indices data to finish being modified. + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, postUpdateBarriers, {}); + } void SHParticleSubSystem::Render(Handle cmdBuffer, Handle renderer, uint32_t frameIndex) noexcept @@ -297,7 +357,7 @@ namespace SHADE // TODO: Issue barrier for output particle data. Semaphore should also be issued outside in SHGraphicsSystem for (auto& emitter : emitters) { - + RenderComponent(cmdBuffer, emitter, frameIndex); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h index ed697a59..9003f169 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h @@ -81,6 +81,8 @@ namespace SHADE void UpdateCompoennt(Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept; void RenderComponent(Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept; + void PreparePrePostUpdateBarriers (std::vector& preUpdateBarriers, std::vector& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept; + public: void Init(Handle device, Handle inDescPool, Handle compatibleRenderpass, Handle subpass, Handle VS, Handle FS, Handle emitCS, Handle defaultUpdateCS) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderingSubSystem.cpp index f923add4..cf2046ba 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderingSubSystem.cpp @@ -198,7 +198,7 @@ namespace SHADE cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRAJECTORY_TRANSFORM, transformBuffer, 0); // call draw call - cmdBuffer->DrawMultiIndirect(drawDataBuffer, drawData.size()); + cmdBuffer->DrawMultiIndirectIndexed(drawDataBuffer, drawData.size()); // clear CPU transform and draw data transformData.clear();