From 2f4a316a094c71aa947aa0161a22843afebe80f3 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 13 Mar 2023 11:41:23 +0800 Subject: [PATCH 01/16] 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(); From 8fac6fd9113f20a8edbc6e2f14b24509dd8c87f8 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 13 Mar 2023 22:23:15 +0800 Subject: [PATCH 02/16] Particles WIP --- Assets/Scenes/Scene2.shade | 11 +++ SHADE_Engine/src/Common/SHAllComponents.h | 1 + .../Inspector/SHEditorComponentView.hpp | 6 +- .../Inspector/SHEditorInspector.cpp | 7 ++ .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 15 +++- .../MiddleEnd/Interface/SHGraphicsSystem.h | 2 + .../Particles/SHParticleEmitterComponent.cpp | 40 +++++++++- .../Particles/SHParticleEmitterComponent.h | 14 +++- .../Particles/SHParticleSubSystem.cpp | 78 ++++++++++++++----- .../MiddleEnd/Particles/SHParticleSubSystem.h | 2 +- .../RenderGraph/SHRenderGraphNode.cpp | 12 +++ .../Graphics/RenderGraph/SHRenderGraphNode.h | 8 ++ .../src/Serialization/SHSerialization.cpp | 2 + 13 files changed, 169 insertions(+), 29 deletions(-) diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index c45d8b51..704d2028 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -145,4 +145,15 @@ End Alpha: 1 "Color Eval Rate ": 0.192000002 IsActive: true + Scripts: ~ +- EID: 7 + Name: ParticleTest + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 0, z: 0} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true Scripts: ~ \ No newline at end of file diff --git a/SHADE_Engine/src/Common/SHAllComponents.h b/SHADE_Engine/src/Common/SHAllComponents.h index ee900736..32efee1f 100644 --- a/SHADE_Engine/src/Common/SHAllComponents.h +++ b/SHADE_Engine/src/Common/SHAllComponents.h @@ -15,3 +15,4 @@ #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "AudioSystem/SHAudioListenerComponent.h" #include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h" +#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h" \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 388667a3..8f4e6f47 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -822,7 +822,11 @@ namespace SHADE { DrawContextMenu(component); - SHEditorWidgets::DragFloat("Emission Count", [comp = component]() {return comp->GetEmissionCount(); }, [comp = component](float count) {comp->SetEmissionCount(count);}); + SHEditorWidgets::DragInt("Emission Count", [comp = component]() {return comp->GetEmissionCount(); }, [comp = component](uint32_t count) {comp->SetEmissionCount(count);}); + SHEditorWidgets::DragFloat("Emission Interval", [comp = component]() {return comp->GetEmissionInterval(); }, [comp = component](float interval) {comp->SetEmissionInterval(interval); }); + SHEditorWidgets::DragFloat("Min Life", [comp = component]() {return comp->GetMinLife(); }, [comp = component](float val) {comp->SetMinLife(val); }); + SHEditorWidgets::DragFloat("Max Life", [comp = component]() {return comp->GetMaxLife(); }, [comp = component](float val) {comp->SetMaxLife(val); }); + SHEditorWidgets::CheckBox("Is Passive", [comp = component]() {return comp->GetPassive(); }, [comp = component](bool flag) {comp->SetPassive(flag); }); } diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index f331f499..e9da2f09 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -26,6 +26,7 @@ #include "SHEditorComponentView.h" #include "AudioSystem/SHAudioListenerComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" +#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h" #include "Camera/SHCameraSystem.h" #include "FRC/SHFramerateController.h" @@ -188,6 +189,10 @@ namespace SHADE { DrawComponent(trajectoryComponent); } + if (auto particleComponent = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(particleComponent); + } ImGui::Separator(); // Render Scripts SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); @@ -204,6 +209,7 @@ namespace SHADE DrawAddComponentButton(eid); DrawAddComponentButton(eid); DrawAddComponentButton(eid); + DrawAddComponentButton(eid); // Components that require Transforms @@ -213,6 +219,7 @@ namespace SHADE DrawAddComponentWithEnforcedComponentButton(eid); DrawAddComponentWithEnforcedComponentButton(eid); DrawAddComponentWithEnforcedComponentButton(eid); + //DrawAddComponentWithEnforcedComponentButton(eid); ImGui::EndMenu(); } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 59813cd3..b34eb8de 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -48,6 +48,7 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Input/SHInputManager.h" #include "Assets/Events/SHAssetManagerEvents.h" +#include "Graphics/MiddleEnd/Particles/SHParticleSubSystem.h" namespace SHADE { @@ -170,7 +171,8 @@ namespace SHADE 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_FS = 42509714; particleFS = SHResourceManager::LoadOrGet(PARTICLE_FS); + static constexpr AssetID PARTICLE_EMIT_CS = 49959611; particleEmitCS = SHResourceManager::LoadOrGet(PARTICLE_EMIT_CS); static constexpr AssetID PARTICLE_UPDATE_CS = 36260925; particleUpdateCS = SHResourceManager::LoadOrGet(PARTICLE_UPDATE_CS); } @@ -350,11 +352,16 @@ namespace SHADE /*-----------------------------------------------------------------------*/ auto vfxPass = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data(), { "Scene", "Depth Buffer" }, { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data() }); auto vfxSubpass = vfxPass->AddSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS.data(), worldViewport, worldRenderer); + vfxPass->AddPreBeginFunction([=](Handle cmdBuffer, uint32_t frameIndex) + { + particleSubSystem->Run(cmdBuffer, frameIndex); + }); vfxSubpass->AddColorOutput("Scene"); vfxSubpass->AddDepthOutput("Depth Buffer"); vfxSubpass->AddExteriorDrawCalls([=](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { trajectoryRenderingSubSystem->Render(cmdBuffer, renderer, frameIndex); + //particleSubSystem->Render(cmdBuffer, renderer, frameIndex); }); /*-----------------------------------------------------------------------*/ @@ -497,6 +504,12 @@ namespace SHADE trajectoryRenderingSubSystem = resourceManager.Create(); + auto vfxPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data()); + + // particle sub system initialization + particleSubSystem = resourceManager.Create(); + particleSubSystem->Init(device, descPool, vfxPass->GetRenderpass(), vfxPass->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS), particleVS, particleFS, particleEmitCS, particleUpdateCS); + auto vfxNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data()); trajectoryRenderingSubSystem->Init(device, vfxNode->GetRenderpass(), vfxNode->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS), trajectoryVS, trajectoryFS); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index a199464c..2627415c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -59,6 +59,7 @@ namespace SHADE class SHMaterialInstance; class SHMousePickSystem; class SHTextRenderingSubSystem; + class SHParticleSubSystem; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -527,6 +528,7 @@ namespace SHADE Handle lightingSubSystem; Handle textRenderingSubSystem; Handle trajectoryRenderingSubSystem; + Handle particleSubSystem; Handle ssaoStorage; uint32_t resizeWidth = 1; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp index c7dca2a0..8a652381 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp @@ -20,24 +20,56 @@ namespace SHADE toEmit = true; } - void SHParticleEmitterComponent::SetEmissionCount(float count) noexcept + void SHParticleEmitterComponent::SetEmissionCount(uint32_t count) noexcept { emissionCount = count; } - bool SHParticleEmitterComponent::SetPassive(bool flag) noexcept + void SHParticleEmitterComponent::SetPassive(bool flag) noexcept { isPassive = flag; } - float SHParticleEmitterComponent::GetEmissionCount(void) noexcept + void SHParticleEmitterComponent::SetEmissionInterval(float interval) noexcept + { + emissionInterval = interval; + timeBeforeEmission = emissionInterval; + } + + void SHParticleEmitterComponent::SetMinLife(float val) noexcept + { + cpuEmitterData.lifeAndSizeRange.x = val; + } + + void SHParticleEmitterComponent::SetMaxLife(float val) noexcept + { + cpuEmitterData.lifeAndSizeRange.y = val; + } + + uint32_t SHParticleEmitterComponent::GetEmissionCount(void) const noexcept { return emissionCount; } - bool SHParticleEmitterComponent::GetPassive(void) noexcept + bool SHParticleEmitterComponent::GetPassive(void) const noexcept { return isPassive; } + float SHParticleEmitterComponent::GetEmissionInterval(void) const noexcept + { + return emissionInterval; + } + + float SHParticleEmitterComponent::GetMinLife(void) const noexcept + { + return cpuEmitterData.lifeAndSizeRange.x; + } + + float SHParticleEmitterComponent::GetMaxLife(void) const noexcept + { + return cpuEmitterData.lifeAndSizeRange.y; + + } + } \ 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 7b519e85..ac2556b1 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h @@ -105,11 +105,17 @@ namespace SHADE void Emit (void) noexcept; - void SetEmissionCount (float count) noexcept; - bool SetPassive (bool flag) noexcept; + void SetEmissionCount (uint32_t count) noexcept; + void SetPassive (bool flag) noexcept; + void SetEmissionInterval (float interval) noexcept; + void SetMinLife (float val) noexcept; + void SetMaxLife (float val) noexcept; - float GetEmissionCount (void) noexcept; - bool GetPassive (void) noexcept; + uint32_t GetEmissionCount (void) const noexcept; + bool GetPassive (void) const noexcept; + float GetEmissionInterval (void) const noexcept; + float GetMinLife (void) const noexcept; + float GetMaxLife (void) const 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 95e9818f..5141112e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp @@ -10,23 +10,29 @@ #include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" #include "Math/Transform/SHTransformComponent.h" #include "Graphics/Buffers/SHVkBuffer.h" +#include "FRC/SHFramerateController.h" +#include "Graphics/Pipeline/SHVkPipeline.h" +#include "Graphics/RenderGraph/SHSubpass.h" +#include "Graphics/SHVkUtil.h" namespace SHADE { void SHParticleSubSystem::InitializeComponent(SHParticleEmitterComponent& comp) noexcept { - uint32_t emitterStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUEmitterStruct)); - uint32_t particleStructAligned = logicalDevice->PadUBOSize(sizeof (SHParticleEmitterComponent::GPUParticleStruct)); - uint32_t sizeofIndirectCmd = static_cast(sizeof(vk::DrawIndirectCommand)); - uint32_t sizeofUint = static_cast(sizeof(uint32_t)); - // TODO: temporary only. - static constexpr uint32_t NUM_PARTICLES = 500; + static constexpr uint32_t NUM_PARTICLES = 5; comp.maxParticles = NUM_PARTICLES; + uint32_t sizeofUint = static_cast(sizeof(uint32_t)); + uint32_t sizeofIndirectCmdAligned = logicalDevice->PadSSBOSize(sizeof(vk::DrawIndirectCommand)); + uint32_t emitterStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUEmitterStruct)); + uint32_t particleChunkStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUParticleStruct) * comp.maxParticles); + uint32_t indicesDataAligned = logicalDevice->PadSSBOSize(sizeofUint * comp.maxParticles); + + // offset into the buffer for input and output - uint32_t const PARTICLE_FRAME_CHUNK_SIZE = (particleStructAligned * comp.maxParticles); + uint32_t const PARTICLE_FRAME_CHUNK_SIZE = particleChunkStructAligned; // Buffer Initialization { @@ -40,14 +46,14 @@ namespace SHADE // buffer for particle data: pure GPU memory, no transfers, no flags. We want to triple buffer this so that we can submit work to the GPU // without having to wait for rendering to finish reading the data - comp.particleData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * particleStructAligned * NUM_PARTICLES, nullptr, 0, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, {}); + comp.particleData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * particleChunkStructAligned, nullptr, 0, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, {}); // Buffer for freelist data. 1 copy only, host-visible mapped. We only need 1 copy because it is only required in compute. If it was used or read in another // stage we would need more copies. comp.freelistData = logicalDevice->CreateBuffer(sizeofUint * (comp.maxParticles + 1), freelistInit.data(), sizeofUint * (comp.maxParticles + 1), vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT); // Buffer for indices. NUM_FRAME_BUFFERS copies since it's used in rendering. host-visible mapped. - comp.indicesData = logicalDevice->CreateBuffer(sizeofUint * comp.maxParticles, nullptr, 0, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT); + comp.indicesData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * indicesDataAligned, nullptr, 0, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT); // Draw call data will not be tampered with after this initialization except for one variable: instanceCount, which will be modified from compute shader std::array indirectCommands{}; @@ -60,7 +66,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::eStorageBuffer | 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 * sizeofIndirectCmdAligned, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, 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); } @@ -73,7 +79,7 @@ namespace SHADE static constexpr uint32_t PARTICLE_DATA_SET_INDEX = 0; // Variable desc counts, all ignored anyway (This is required but its a dumb interface. You can only blame yourself, Brandon. ) - std::vector const VARIABLE_COUNTS = {0u,0u,0u,0u,0u}; + std::vector const VARIABLE_COUNTS = {0u}; // allocate new desc set comp.particleDescriptorSet = descPool->Allocate(descSetLayout, VARIABLE_COUNTS); @@ -87,7 +93,14 @@ namespace SHADE set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_OUTPUT_DATA, { &comp.particleData, 1 }, 0, PARTICLE_FRAME_CHUNK_SIZE); set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_FREELIST_DATA, { &comp.freelistData, 1 }, 0, sizeofUint * (comp.maxParticles + 1)); set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INDICES_DATA, { &comp.indicesData, 1 }, 0, sizeofUint * (comp.maxParticles)); - set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA, { &comp.drawCallData, 1 }, 0, sizeofIndirectCmd); + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA, { &comp.drawCallData, 1 }, 0, sizeofIndirectCmdAligned); + + set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_EMITTER_DATA); + set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INPUT_DATA); + set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_OUTPUT_DATA); + set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_FREELIST_DATA); + set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INDICES_DATA); + set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA); } comp.initialized = true; @@ -110,8 +123,8 @@ namespace SHADE offsets[DYOFF_INDEX_EMITTER] = i * emitterStructAligned; offsets[DYOFF_INDEX_PARTICLE_INPUT] = inputOffset; offsets[DYOFF_INDEX_PARTICLE_OUTPUT] = outputOffset; - offsets[DYOFF_INDEX_INDICES_DATA] = i * sizeofUint * comp.maxParticles; - offsets[DYOFF_INDEX_DRAW_DATA] = i * sizeofIndirectCmd; + offsets[DYOFF_INDEX_INDICES_DATA] = i * indicesDataAligned; + offsets[DYOFF_INDEX_DRAW_DATA] = i * sizeofIndirectCmdAligned; } } @@ -140,7 +153,6 @@ namespace SHADE // reset instance count to 0 comp.drawCallData->WriteToMemory (&ZERO, sizeof(uint32_t), 0, instanceCountOffset); - // bind the descriptor sets required for emitting particles cmdBuffer->BindDescriptorSet(comp.particleDescriptorSet, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), comp.dynamicOffsets[frameIndex]); @@ -223,6 +235,33 @@ namespace SHADE renderingPipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(plParams); renderingPipelineData.pipeline = logicalDevice->CreateGraphicsPipeline(renderingPipelineData.pipelineLayout, nullptr, compatibleRenderpass, subpass); + SHColorBlendState colorBlendState{}; + colorBlendState.logic_op_enable = VK_FALSE; + colorBlendState.logic_op = vk::LogicOp::eCopy; + + auto const& subpassColorReferences = subpass->GetColorAttachmentReferences(); + colorBlendState.attachments.reserve(subpassColorReferences.size()); + + + for (auto& att : subpassColorReferences) + { + colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState + { + .blendEnable = SHVkUtil::IsBlendCompatible(subpass->GetFormatFromAttachmentReference(att.attachment)), + .srcColorBlendFactor = vk::BlendFactor::eSrcAlpha, + .dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, + .colorBlendOp = vk::BlendOp::eAdd, + .srcAlphaBlendFactor = vk::BlendFactor::eSrcAlpha, + .dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, + .alphaBlendOp = vk::BlendOp::eAdd, + .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, + } + ); + } + + renderingPipelineData.pipeline->GetPipelineState().SetColorBlenState(colorBlendState); + renderingPipelineData.pipeline->ConstructPipeline(); + SHPipelineLayoutParams emitPlParams { .shaderModules = {emitCS}, @@ -231,6 +270,7 @@ namespace SHADE emittingPipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(emitPlParams); emittingPipelineData.pipeline = logicalDevice->CreateComputePipeline(emittingPipelineData.pipelineLayout); + emittingPipelineData.pipeline->ConstructPipeline(); SHPipelineLayoutParams defaultUpdatePlParams { @@ -240,7 +280,7 @@ namespace SHADE defaultUpdatePipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(defaultUpdatePlParams); defaultUpdatePipelineData.pipeline = logicalDevice->CreateComputePipeline(defaultUpdatePipelineData.pipelineLayout); - + defaultUpdatePipelineData.pipeline->ConstructPipeline(); /*-----------------------------------------------------------------------*/ /* OTHER INITIALIZATION */ @@ -248,8 +288,10 @@ namespace SHADE SHComponentManager::CreateComponentSparseSet(); } - void SHParticleSubSystem::Run(Handle cmdBuffer, uint32_t frameIndex, float dt) noexcept + void SHParticleSubSystem::Run(Handle cmdBuffer, uint32_t frameIndex) noexcept { + float dt = static_cast(SHFrameRateController::GetRawDeltaTime()); + auto& emitters = SHComponentManager::GetDense(); auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING); @@ -346,7 +388,7 @@ namespace SHADE /* 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, {}); + //cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, postUpdateBarriers, {}); } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h index 9003f169..73404e3d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h @@ -86,7 +86,7 @@ namespace SHADE public: void Init(Handle device, Handle inDescPool, Handle compatibleRenderpass, Handle subpass, Handle VS, Handle FS, Handle emitCS, Handle defaultUpdateCS) noexcept; - void Run(Handle cmdBuffer, uint32_t frameIndex, float dt) noexcept; + void Run(Handle cmdBuffer, uint32_t frameIndex) noexcept; void Render(Handle cmdBuffer, Handle renderer, uint32_t frameIndex) noexcept; void Exit(void) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 53363a63..4a89290a 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -372,6 +372,7 @@ namespace SHADE , ISelfHandle{std::move(rhs)} , dynamicIsActive {rhs.dynamicIsActive} , isDynamic {rhs.isDynamic} + , preBeginFuncs{std::move(rhs.preBeginFuncs)} { rhs.renderpass = {}; @@ -399,6 +400,7 @@ namespace SHADE name = std::move(rhs.name); dynamicIsActive = rhs.dynamicIsActive; isDynamic = rhs.isDynamic; + preBeginFuncs = std::move(rhs.preBeginFuncs); rhs.renderpass = {}; @@ -493,6 +495,11 @@ namespace SHADE return nodeCompute; } + void SHRenderGraphNode::AddPreBeginFunction(PreBeginFunction const& func) noexcept + { + preBeginFuncs.push_back(func); + } + /***************************************************************************/ /*! @@ -664,6 +671,11 @@ namespace SHADE void SHRenderGraphNode::Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept { + for (auto& func : preBeginFuncs) + { + func(commandBuffer, frameIndex); + } + if (renderpass) { uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index 971a84ae..72494b6a 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -27,6 +27,10 @@ namespace SHADE class SH_API SHRenderGraphNode : public ISelfHandle { + public: + using PreBeginFunction = std::function, uint32_t)>; + + private: /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -74,6 +78,9 @@ namespace SHADE //! of drawing objects on the image (i.e. compute). std::vector> nodeComputes; + //! Calls before renderpass begins + std::vector preBeginFuncs; + //! Whether or not the node has finished execution bool executed; @@ -118,6 +125,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) noexcept; + void AddPreBeginFunction (PreBeginFunction const& func) noexcept; void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index b6455935..2451414d 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -248,6 +248,7 @@ namespace SHADE AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); node[ComponentsNode] = components; @@ -398,5 +399,6 @@ namespace SHADE SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); } } From 070f01bf67453b8f53151e08f63e4d0ce0d33dda Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Tue, 14 Mar 2023 10:55:53 +0800 Subject: [PATCH 03/16] Particles WIP --- Assets/Scenes/Scene2.shade | 25 ++++-- Assets/Shaders/ParticleEmit_CS.glsl | 16 +++- Assets/Shaders/ParticleEmit_CS.shshaderb | Bin 7197 -> 7685 bytes .../Inspector/SHEditorComponentView.hpp | 42 ++++++++++ .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 2 +- .../Particles/SHParticleEmitterComponent.cpp | 60 ++++++++++++++ .../Particles/SHParticleEmitterComponent.h | 29 +++++-- .../Particles/SHParticleSubSystem.cpp | 23 ++++-- .../src/Serialization/SHSerialization.cpp | 1 + .../src/Serialization/SHYAMLConverters.h | 75 ++++++++++++++++++ 10 files changed, 253 insertions(+), 20 deletions(-) diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index 704d2028..96d2e525 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -22,18 +22,18 @@ Scripts: ~ - EID: 1 Name: Raccoon - IsActive: true + IsActive: false NumberOfChildren: 1 Components: Transform Component: Translate: {x: 0, y: 0.201105013, z: 0} Rotate: {x: 0.00523597933, y: -2.96353412, z: -6.40293041e-10} Scale: {x: 1.00000191, y: 1, z: 1.00000191} - IsActive: true + IsActive: false Renderable Component: Mesh: 149697411 Material: 126974645 - IsActive: true + IsActive: false Scripts: ~ - EID: 3 Name: Bag @@ -87,18 +87,18 @@ Scripts: ~ - EID: 5 Name: Floor - IsActive: true + IsActive: false NumberOfChildren: 0 Components: Transform Component: Translate: {x: 0, y: 0.0810000002, z: 0} Rotate: {x: -1.57079625, y: 0, z: -0} Scale: {x: 50, y: 49.9999924, z: 49.9999924} - IsActive: true + IsActive: false Renderable Component: Mesh: 141771688 Material: 124370424 - IsActive: true + IsActive: false Scripts: ~ - EID: 6 Name: TrajectoryTest @@ -156,4 +156,17 @@ Rotate: {x: 0, y: 0, z: 0} Scale: {x: 1, y: 1, z: 1} IsActive: true + classSHADE::SHParticleEmitterComponent: + Emission Count: 1 + Is Passive: false + Emission Interval: 3 + Min Life: 7 + Max Life: 20 + Angular Min: {x: 2.29999995, y: 1.70000005, z: 2.9000001} + Angular Max: {x: 0, y: 0, z: 0} + Minimum Velocity: {x: 2, y: 3, z: 4} + Maximum Velocity: {x: 0, y: 0, z: 0} + Minimum Size: 5 + Maximum Size: 10 + IsActive: true Scripts: ~ \ No newline at end of file diff --git a/Assets/Shaders/ParticleEmit_CS.glsl b/Assets/Shaders/ParticleEmit_CS.glsl index 33beaccc..f54a58fa 100644 --- a/Assets/Shaders/ParticleEmit_CS.glsl +++ b/Assets/Shaders/ParticleEmit_CS.glsl @@ -6,6 +6,8 @@ struct EmitterParameters { vec4 angularMin; vec4 angularMax; + vec4 minVel; + vec4 maxVel; vec4 lifeAndSizeRange; // min life, max life, min size, max size }; @@ -109,6 +111,7 @@ void main() if (emitterInvocationIndex >= emitterPushConstant.emissionCount) return; +// Freecount will start at max particles. Here we subtract every time we emit. int freelistIndex = atomicAdd (freelist.freeCount, -1) - 1; if (freelistIndex < 0) atomicAdd (freelist.freeCount, 1); @@ -124,9 +127,18 @@ void main() // 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); + // Set its velocity + particle.velocity = emitterParams.data.minVel; + // randomize life value that ranges from minLife to maxLife + particle.life = map (rand(seed), 0.0f, 1.0f, emitterParams.data.lifeAndSizeRange.x, emitterParams.data.lifeAndSizeRange.y); + + // Set size of particle + particle.scaleAndDecay.x = emitterParams.data.lifeAndSizeRange.z; + particle.scaleAndDecay.y = emitterParams.data.lifeAndSizeRange.z; + + particle.rotation = vec4 (5.0f); + particle.acceleration = vec4 (0.01f); inputParticles.data[index] = particle; } \ No newline at end of file diff --git a/Assets/Shaders/ParticleEmit_CS.shshaderb b/Assets/Shaders/ParticleEmit_CS.shshaderb index e0318886a5ac002a537ec1c652a1d9c162dc37f8..8e2eba23cc690b20ad995dc63d858c62bda47d8f 100644 GIT binary patch delta 2477 zcmZ9MOKcTY7{|}_zG?}r3UW2XTIkX)h>1xX3u#FWupr@KTsvu}i>5-=XRL6`RDuo-}&BW=DyqcR(G*& z@o8h9OhbFY7|%4BwWh&4Ti{zZy^nc`oi`0PVGZ|23dpRm+l z4*KHitO&cFT9|+ADRkCS9S;4lG^}NGI`{%lNkmtr>smf&K)m)>-~z1zk9AdYPXYgUw2^N5+R<(u0hE`l3pZuSXhuAe1o z2^(|6*(o;87h;`Q*UFM~#^L-yd=BRvX*^@zl;{vU0QKnHt6gfI+{^z=L7>)p$(a=A ze ze@6IRcwgX*mf>BB<(f|kj|Q1f97)5PCJugyh$PYn<2S zRe|Ib{6^rMIOd1DxNoIT^QAH|fo}^g@SJoU2%MFKcj=WN>3LzJK!Y?!LnOzKEpa&) z1h#ZiAP1Z{SA0&oZCdqhab9p&{E~DWxEhjO7D(o%BOx~YT*52TlUqpUyQ(wJUB2(6 zyL=H-lMo}0?w)VNPUG=8{CeX2$M~GDi+DI+5<`TNzX+2tKO%WYpeRi&NZu9nxkPsT zIPcZ!Dw4knIP=g9FXwLp0bCWu;P|$zuF#*- z336{Y97h-Qmvjp0tE|WTEu9#*2{?W(<{#xo%$_WHb rNd6}f45XO6$O^E~|5HMp95 zz5~hbyg%Uc$B*G(<;EAJN5e5^T)SS@Jp=9Si9X?o>fvV{j;G@2u)Gt}310_P51Wv= zE1mB&WbUoN_gCP_JWkg~N`n!TO`nKVtjo&J>h0-Irjk86L+%vW^oX}xAkWc6XHQ!) zbv(Bl6?Zlg3uM!OBC&EZge9HH_C$VvQ#2NsPVb9uD4)iu*{dA{8~AG0E^#W?xG5zl#0n(m%S<2xj27PdpISbYxHag|-Dcrp>6;Q`hQ_MAYvFNNsq)6lbyX|=wlq^2 zmu&YiBgaR+l=K}BSDDrBv~4b*POm90ayUFwrUr)qQ{%Zb`S4K#%t7$6|H`xBf@eKU ze%r$**$luk&7C|67PLWfZh`>xqGU)?C)6RmBv~}+bHyXA{CY$s^j0R# zH|ocHqkhac>c@Peems>qTk<#P?DQ&M)Aj|)E**eU;09d{S9M*oR)XKg-|#T;@W9x# zMLaewan0DYb4AjqCWfUSNG6P4>3|IG?udls6nrQl03v;ZE%A|T5tn(VWn123+3drc zk_I>EJ&^N>BqpIj8l#~}z7hf(by9}?FC-%#z9jupLVTm{iwE*r z!lU6(#I`DLxAYqcu`Fuwc-~50tG*jdF&qS1(wuBa0f{BOlTDF92^{d8#B$!thQq_M zoDZ_$Fl9Jk;@~)R_fZ0gr)x={WkcdgLjn_L3w@Cdhv#iM-(GetEmissionInterval(); }, [comp = component](float interval) {comp->SetEmissionInterval(interval); }); SHEditorWidgets::DragFloat("Min Life", [comp = component]() {return comp->GetMinLife(); }, [comp = component](float val) {comp->SetMinLife(val); }); SHEditorWidgets::DragFloat("Max Life", [comp = component]() {return comp->GetMaxLife(); }, [comp = component](float val) {comp->SetMaxLife(val); }); + SHEditorWidgets::DragFloat("Min Size", [comp = component]() {return comp->GetMinSize(); }, [comp = component](float val) {comp->SetMinSize(val); }); + SHEditorWidgets::DragFloat("Man Size", [comp = component]() {return comp->GetMaxSize(); }, [comp = component](float val) {comp->SetMaxSize(val); }); + + SHEditorWidgets::DragVec3("Angular Min", {"x", "y", "z"}, + [comp = component]() + { + return comp->GetAngularMin(); + }, + [comp = component](SHVec3 const& val) + { + comp->SetAngularMin(val); + }); + + SHEditorWidgets::DragVec3("Angular Max", { "x", "y", "z" }, + [comp = component]() + { + return comp->GetAngularMax(); + }, + [comp = component](SHVec3 const& val) + { + comp->SetAngularMax(val); + }); + + SHEditorWidgets::DragVec3("Min Vel", { "x", "y", "z" }, + [comp = component]() + { + return comp->GetMinVelocity(); + }, + [comp = component](SHVec3 const& val) + { + comp->SetMinVelocity(val); + }); + + SHEditorWidgets::DragVec3("Max Vel", { "x", "y", "z" }, + [comp = component]() + { + return comp->GetMaxVelocity(); + }, + [comp = component](SHVec3 const& val) + { + comp->SetMaxVelocity(val); + }); SHEditorWidgets::CheckBox("Is Passive", [comp = component]() {return comp->GetPassive(); }, [comp = component](bool flag) {comp->SetPassive(flag); }); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index b34eb8de..62e3c455 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -361,7 +361,7 @@ namespace SHADE vfxSubpass->AddExteriorDrawCalls([=](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { trajectoryRenderingSubSystem->Render(cmdBuffer, renderer, frameIndex); - //particleSubSystem->Render(cmdBuffer, renderer, frameIndex); + particleSubSystem->Render(cmdBuffer, renderer, frameIndex); }); /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp index 8a652381..d2c0e05a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp @@ -46,6 +46,36 @@ namespace SHADE cpuEmitterData.lifeAndSizeRange.y = val; } + void SHParticleEmitterComponent::SetAngularMin(SHVec3 const& min) noexcept + { + cpuEmitterData.angularMin = SHVec4 (min); + } + + void SHParticleEmitterComponent::SetAngularMax(SHVec3 const& max) noexcept + { + cpuEmitterData.angularMax = SHVec4(max); + } + + void SHParticleEmitterComponent::SetMinVelocity(SHVec3 const& vel) noexcept + { + cpuEmitterData.minVel = vel; + } + + void SHParticleEmitterComponent::SetMaxVelocity(SHVec3 const& vel) noexcept + { + cpuEmitterData.maxVel = vel; + } + + void SHParticleEmitterComponent::SetMinSize(float size) noexcept + { + cpuEmitterData.lifeAndSizeRange.z = size; + } + + void SHParticleEmitterComponent::SetMaxSize(float size) noexcept + { + cpuEmitterData.lifeAndSizeRange.w = size; + } + uint32_t SHParticleEmitterComponent::GetEmissionCount(void) const noexcept { return emissionCount; @@ -72,4 +102,34 @@ namespace SHADE } + SHVec3 SHParticleEmitterComponent::GetAngularMin(void) const noexcept + { + return SHVec3 (cpuEmitterData.angularMin.x, cpuEmitterData.angularMin.y, cpuEmitterData.angularMin.z); + } + + SHVec3 SHParticleEmitterComponent::GetMinVelocity(void) const noexcept + { + return SHVec3(cpuEmitterData.minVel.x, cpuEmitterData.minVel.y, cpuEmitterData.minVel.z); + } + + SHVec3 SHParticleEmitterComponent::GetMaxVelocity(void) const noexcept + { + return SHVec3(cpuEmitterData.maxVel.x, cpuEmitterData.maxVel.y, cpuEmitterData.maxVel.z); + } + + float SHParticleEmitterComponent::GetMinSize(void) const noexcept + { + return cpuEmitterData.lifeAndSizeRange.z; + } + + float SHParticleEmitterComponent::GetMaxSize(void) const noexcept + { + return cpuEmitterData.lifeAndSizeRange.w; + } + + SHVec3 SHParticleEmitterComponent::GetAngularMax(void) const noexcept + { + return SHVec3(cpuEmitterData.angularMax.x, cpuEmitterData.angularMax.y, cpuEmitterData.angularMax.z); + } + } \ 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 ac2556b1..7781c29f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h @@ -22,6 +22,12 @@ namespace SHADE //! Maximum emitting angular range SHVec4 angularMax; + //! minimum starting velocity + SHVec4 minVel; + + //! Maximum starting velocity + SHVec4 maxVel; + //! Spawn lifetime and size range (min and max) SHVec4 lifeAndSizeRange; }; @@ -110,12 +116,25 @@ namespace SHADE void SetEmissionInterval (float interval) noexcept; void SetMinLife (float val) noexcept; void SetMaxLife (float val) noexcept; + void SetAngularMin (SHVec3 const& min) noexcept; + void SetAngularMax (SHVec3 const& max) noexcept; + void SetMinVelocity (SHVec3 const& vel) noexcept; + void SetMaxVelocity (SHVec3 const& vel) noexcept; + void SetMinSize (float size) noexcept; + void SetMaxSize (float size) noexcept; - uint32_t GetEmissionCount (void) const noexcept; - bool GetPassive (void) const noexcept; - float GetEmissionInterval (void) const noexcept; - float GetMinLife (void) const noexcept; - float GetMaxLife (void) const noexcept; + + uint32_t GetEmissionCount (void) const noexcept; + bool GetPassive (void) const noexcept; + float GetEmissionInterval (void) const noexcept; + float GetMinLife (void) const noexcept; + float GetMaxLife (void) const noexcept; + SHVec3 GetAngularMax (void) const noexcept; + SHVec3 GetAngularMin (void) const noexcept; + SHVec3 GetMinVelocity (void) const noexcept; + SHVec3 GetMaxVelocity (void) const noexcept; + float GetMinSize (void) const noexcept; + float GetMaxSize (void) const 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 5141112e..5e526ae2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp @@ -27,7 +27,7 @@ namespace SHADE uint32_t sizeofUint = static_cast(sizeof(uint32_t)); uint32_t sizeofIndirectCmdAligned = logicalDevice->PadSSBOSize(sizeof(vk::DrawIndirectCommand)); uint32_t emitterStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUEmitterStruct)); - uint32_t particleChunkStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUParticleStruct) * comp.maxParticles); + uint32_t particleChunkStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUParticleStruct)) * comp.maxParticles; uint32_t indicesDataAligned = logicalDevice->PadSSBOSize(sizeofUint * comp.maxParticles); @@ -36,9 +36,11 @@ namespace SHADE // Buffer Initialization { - // count, value + // count, value. Initialize free count to max particles and indices to particle indices std::vector freelistInit(comp.maxParticles + 1, 0); freelistInit[0] = comp.maxParticles; + for (uint32_t i = 0; i < comp.maxParticles; ++i) + freelistInit[i + 1] = i; // Particle emitter buffer. Multiple copies, Host-visible mapped. We want multiple copies because we'll be writing to it from the CPU. We don't want to do that while the GPU // is using it during compute operations so we write to another portion. @@ -89,10 +91,10 @@ namespace SHADE // After buffers are created, we want to populate all bindings(6) with the buffers set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_EMITTER_DATA, { &comp.emitterData, 1 }, 0, emitterStructAligned); - set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INPUT_DATA, { &comp.particleData, 1 }, 0, PARTICLE_FRAME_CHUNK_SIZE); // input and output will be th same until we bind using dynamic offsets - set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_OUTPUT_DATA, { &comp.particleData, 1 }, 0, PARTICLE_FRAME_CHUNK_SIZE); + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INPUT_DATA, { &comp.particleData, 1 }, 0, particleChunkStructAligned); // input and output will be th same until we bind using dynamic offsets + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_OUTPUT_DATA, { &comp.particleData, 1 }, 0, particleChunkStructAligned); set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_FREELIST_DATA, { &comp.freelistData, 1 }, 0, sizeofUint * (comp.maxParticles + 1)); - set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INDICES_DATA, { &comp.indicesData, 1 }, 0, sizeofUint * (comp.maxParticles)); + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INDICES_DATA, { &comp.indicesData, 1 }, 0, indicesDataAligned); set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA, { &comp.drawCallData, 1 }, 0, sizeofIndirectCmdAligned); set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_EMITTER_DATA); @@ -139,6 +141,8 @@ namespace SHADE cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emitterPosition", transform->GetWorldPosition(), SH_PIPELINE_TYPE::COMPUTE); cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emissionCount", comp.emissionCount, SH_PIPELINE_TYPE::COMPUTE); + cmdBuffer->SubmitPushConstants(SH_PIPELINE_TYPE::COMPUTE); + // emit particles cmdBuffer->ComputeDispatch((comp.emissionCount / EMITTER_WORKGROUP_SIZE) + 1, 1, 1); } @@ -388,17 +392,24 @@ namespace SHADE /* 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, {}); + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, postUpdateBarriers, {}); } void SHParticleSubSystem::Render(Handle cmdBuffer, Handle renderer, uint32_t frameIndex) noexcept { auto& emitters = SHComponentManager::GetDense(); + auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING); + + // bind the pipeline for updating + cmdBuffer->BindPipeline(renderingPipelineData.pipeline); // TODO: Issue barrier for output particle data. Semaphore should also be issued outside in SHGraphicsSystem for (auto& emitter : emitters) { + // bind the descriptor sets required for emitting particles + cmdBuffer->BindDescriptorSet(emitter.particleDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), emitter.dynamicOffsets[frameIndex]); + RenderComponent(cmdBuffer, emitter, frameIndex); } } diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 2451414d..8dec9ad6 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -311,6 +311,7 @@ namespace SHADE AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); return componentIDList; } diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 0bf66a16..6826efa7 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -17,6 +17,7 @@ #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h" #include "Physics/Collision/Shapes/SHCapsule.h" +#include namespace YAML { @@ -35,6 +36,9 @@ namespace YAML struct HasYAMLConv : std::true_type {}; template<> struct HasYAMLConv : std::true_type {}; + template<> + struct HasYAMLConv : std::true_type {}; + template<> struct convert @@ -497,4 +501,75 @@ namespace YAML } }; + template<> + struct convert + { + static constexpr std::string_view EMISSION_COUNT_TAG = "Emission Count"; + static constexpr std::string_view IS_PASSIVE_TAG = "Is Passive"; + static constexpr std::string_view EMISSION_INTERVAL_TAG = "Emission Interval"; + static constexpr std::string_view MIN_LIFE_TAG = "Min Life"; + static constexpr std::string_view MAX_LIFE_TAG = "Max Life"; + static constexpr std::string_view ANGULAR_MIN_TAG = "Angular Min"; + static constexpr std::string_view ANGULAR_MAX_TAG = "Angular Max"; + static constexpr std::string_view MIN_VEL_TAG = "Minimum Velocity"; + static constexpr std::string_view MAX_VEL_TAG = "Maximum Velocity"; + static constexpr std::string_view MIN_SIZE_TAG = "Minimum Size"; + static constexpr std::string_view MAX_SIZE_TAG = "Maximum Size"; + + static YAML::Node encode(SHParticleEmitterComponent const& rhs) + { + YAML::Node node; + node[EMISSION_COUNT_TAG.data()] = rhs.GetEmissionCount(); + node[IS_PASSIVE_TAG.data()] = rhs.GetPassive(); + node[EMISSION_INTERVAL_TAG.data()] = rhs.GetEmissionInterval(); + node[MIN_LIFE_TAG.data()] = rhs.GetMinLife(); + node[MAX_LIFE_TAG.data()] = rhs.GetMaxLife(); + node[ANGULAR_MIN_TAG.data()] = rhs.GetAngularMin(); + node[ANGULAR_MAX_TAG.data()] = rhs.GetAngularMax(); + node[MIN_VEL_TAG.data()] = rhs.GetMinVelocity(); + node[MAX_VEL_TAG.data()] = rhs.GetMaxVelocity(); + node[MIN_SIZE_TAG.data()] = rhs.GetMinSize(); + node[MAX_SIZE_TAG.data()] = rhs.GetMaxSize(); + + return node; + } + static bool decode(YAML::Node const& node, SHParticleEmitterComponent& rhs) + { + if (node[EMISSION_COUNT_TAG.data()].IsDefined()) + rhs.SetEmissionCount(node[EMISSION_COUNT_TAG.data()].as()); + + if (node[IS_PASSIVE_TAG.data()].IsDefined()) + rhs.SetPassive(node[IS_PASSIVE_TAG.data()].as()); + + if (node[EMISSION_INTERVAL_TAG.data()].IsDefined()) + rhs.SetEmissionInterval(node[EMISSION_INTERVAL_TAG.data()].as()); + + if (node[MIN_LIFE_TAG.data()].IsDefined()) + rhs.SetMinLife(node[MIN_LIFE_TAG.data()].as()); + + if (node[MAX_LIFE_TAG.data()].IsDefined()) + rhs.SetMaxLife(node[MAX_LIFE_TAG.data()].as()); + + if (node[ANGULAR_MIN_TAG.data()].IsDefined()) + rhs.SetAngularMin(node[ANGULAR_MIN_TAG.data()].as()); + + if (node[ANGULAR_MAX_TAG.data()].IsDefined()) + rhs.SetAngularMax(node[ANGULAR_MAX_TAG.data()].as()); + + if (node[MIN_VEL_TAG.data()].IsDefined()) + rhs.SetMinVelocity(node[MIN_VEL_TAG.data()].as()); + + if (node[MAX_VEL_TAG.data()].IsDefined()) + rhs.SetMaxVelocity(node[MAX_VEL_TAG.data()].as()); + + if (node[MIN_SIZE_TAG.data()].IsDefined()) + rhs.SetMinSize(node[MIN_SIZE_TAG.data()].as()); + + if (node[MAX_SIZE_TAG.data()].IsDefined()) + rhs.SetMaxSize(node[MAX_SIZE_TAG.data()].as()); + + return true; + } + }; + } From 69fc9973616a6fd81bfe80546476b3516034680b Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Tue, 14 Mar 2023 19:34:26 +0800 Subject: [PATCH 04/16] Particles WIP --- Assets/Shaders/ParticleEmit_CS.glsl | 2 +- Assets/Shaders/ParticleEmit_CS.shshaderb | Bin 7685 -> 7685 bytes Assets/Shaders/ParticleUpdate_CS.glsl | 2 ++ Assets/Shaders/Particle_VS.glsl | 7 +++-- Assets/Shaders/Particle_VS.shshaderb | Bin 6005 -> 5869 bytes .../Graphics/Commands/SHVkCommandBuffer.cpp | 4 +-- .../src/Graphics/Commands/SHVkCommandBuffer.h | 2 +- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 10 +++---- .../Particles/SHParticleSubSystem.cpp | 26 +++++++++++++++--- 9 files changed, 37 insertions(+), 16 deletions(-) diff --git a/Assets/Shaders/ParticleEmit_CS.glsl b/Assets/Shaders/ParticleEmit_CS.glsl index f54a58fa..6c65ff83 100644 --- a/Assets/Shaders/ParticleEmit_CS.glsl +++ b/Assets/Shaders/ParticleEmit_CS.glsl @@ -135,7 +135,7 @@ void main() // Set size of particle particle.scaleAndDecay.x = emitterParams.data.lifeAndSizeRange.z; - particle.scaleAndDecay.y = emitterParams.data.lifeAndSizeRange.z; + particle.scaleAndDecay.z = emitterParams.data.lifeAndSizeRange.z; particle.rotation = vec4 (5.0f); particle.acceleration = vec4 (0.01f); diff --git a/Assets/Shaders/ParticleEmit_CS.shshaderb b/Assets/Shaders/ParticleEmit_CS.shshaderb index 8e2eba23cc690b20ad995dc63d858c62bda47d8f..898baf45d9f8cfbeb4c6f34f99c06f4751117f51 100644 GIT binary patch delta 14 VcmZp*X|>rfRgCfG=4oR2>;Nnn1&sgz delta 14 VcmZp*X|>rfRgAG`^E9!1b^t0$1wa4* diff --git a/Assets/Shaders/ParticleUpdate_CS.glsl b/Assets/Shaders/ParticleUpdate_CS.glsl index 89c0ae6c..33da0d5e 100644 --- a/Assets/Shaders/ParticleUpdate_CS.glsl +++ b/Assets/Shaders/ParticleUpdate_CS.glsl @@ -132,5 +132,7 @@ void main() outputParticles.data[index] = particle; uint drawIndex = atomicAdd (indirectArgs.instanceCount, 1); indices[drawIndex] = index; + + // indirectArgs.instanceCount = 1; } } \ No newline at end of file diff --git a/Assets/Shaders/Particle_VS.glsl b/Assets/Shaders/Particle_VS.glsl index 07594fbe..d5703c82 100644 --- a/Assets/Shaders/Particle_VS.glsl +++ b/Assets/Shaders/Particle_VS.glsl @@ -78,16 +78,17 @@ void main() vec2 particleScaleData = particle.scaleAndDecay.xz; // x and y mat4 localModel = mat4 (1.0f); - localModel[0][0] = particleScaleData.x; - localModel[1][1] = particleScaleData.y; + localModel[0][0] = 1.0f; + localModel[1][1] = 1.0f; mat4 rotate = mat4(1.0f); rotate[0][0] = cos(angle); rotate[0][1] = sin(angle); rotate[1][0] = -sin(angle); rotate[1][1] = cos(angle); - localModel = rotate * localModel; + // localModel = rotate * localModel; localModel[3] = vec4 (particle.position.xyz, 1.0f); gl_Position = cameraData.vpMat * localModel * vec4(vertexPos, 1.0f); + // gl_Position = vec4(vertexPos, 1.0f); } \ No newline at end of file diff --git a/Assets/Shaders/Particle_VS.shshaderb b/Assets/Shaders/Particle_VS.shshaderb index 00b333cb2a3486c787210690902f87fce0516b70..82cb32311ab8fc2a4094ab06865219819200ad59 100644 GIT binary patch delta 1866 zcmZ9LyH6BR7{%|f4}7r1!~_ZwBhY9eMy-gV;Sr(Gh+-@(G!q!iAh4Td1*KrX_gi3n zf+D`rRg9sqv-F>^wXv|&+Vh*43mfm|2d`={ymjvD7@jR{wxqOsB#$80be z^LeJG$C>*wFrU~yC1*Zca0{L>DU&vjWuF;5-R{Np4c>eu_;;GjMs@3S%0|D z&1-LWhrGPo;TGJe1{^Dw9q|i( zc9?TI)>3seci1hIaa0@iy)js;ONh(mvjcF{c_zCzs&go_yJe8_*O2zS1-L8-Fm*r_Y*Wd5u#nB8tR$o|^p)1Yu z%J7v1$!TvEjCdsKF+#Td)P;{*R-{@;GebrcJOG2x$YEgicA;sjhjs27%74U9U5X z!lmdKCN1aCQ;6HKI@|O*I7`}&s$!viF@jk%1ZNvs)|rM_G_<_Zw*E&VcqEg&gTfX) zJ+HAZ=J0{7l0VT-N&I_bn|}lxam-HKSQ&_WDw`JY6Nk;+z{%fW7Gi@y0^VyUDalA& zDt^n<)-wrLhT@ZU!r@4Xy7mR8VVh7Z>{nX2I-ymG(M$?x z_>8y#G?UuVaGugWA+)Frw{%fBD^w{S`;y=Y)dIdSFGVg31eX_wBfuuRqH}q&tFlR! z5%Ae2ujy=a*(Tx8+g#Umwz-<=?1o^I;SAylZpJ>F{FZEza|5--h0QwyX1Og`#a*4P z!j^}-6KYcCnD%?Z0fBL8iN~83;E(90c4?o9Id~S`@r+0HZ=mB@K^ksvjVwlFD7M1; zF-LH>{(uyFAdmn({^*gT<{rxCkxvRdDmMC773S-EF7Qcm1uZ5>hTrg_3>-|ur};u4 z$*h8~UkZx?JQ^l^CF~JwqpxF5+bZ`a=9u2<-o{)w(4lyucOpqZ00JhOQE{eS5@-Mo WQ}CbpAn=Fe378UlX=Qg!yYmn2#@G1( delta 2025 zcmZ9MNlz3}6op^eG@ybpF~WkxIK)I3YKV!^I7Kw##)v~)xX@IfFoiAMX<8f>mJ`ks zv@=dP&tfCGGp_s-{sI>+b!X!Fs_SCKM^4_o=g#*P{d3W;#Z6wW*~KR_XFU?o{pfnGbomVL&Vm?mlxMGufXah9{I4h zv^_kcI6Ug&$VpY(`dnDp5cZY)-p-(ED<7?CiAHeM$?ETs?)Coupy+S#OMbNm9H)@) z3rk_X7r8d^rD}g+vtLSaRO=6egRth85mzYYd*G<^M0#hn&c?V9WJP3q&>IxP&bWH5 ztBE<$u1ggd7$1rTIls^sbnOWDS4XLocV}C?O8H2(rFBg9RGzj2-Q7V^9L-?kbj4K} zy3UP{ean9KBDTnxTD{yR8Evz0lr@eS;h4)fWVjlkT^3^T!)`mAC!MoNUU1~h#(FlI zAaI&qB_}w2BnejyBykcL`=AroAy`4U|Kn&f9fwZbRTupWgtR~=p;MBzt7~3vu0ZFe z&ymcbFb~8bDaSbc;nSBfs=i%dzvT&5-_Tp zLL?(`rTnF_c@C4XGCV%&CLE5G=;P(zjlrSLj|!IHwB&t4 zgBqc+GlC~f6R=t0vyzETHwcHncaCOi>Xw{75g!khj=I!SCJ zFD2sxj}H^R5|#?q=<9^jHNm}+9O0Or=&f|P^hEEZlYjv1Of;y5nfARv1Nbn+sO}HK ch`&!*oU!Z5~z5oCK diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp index 3aea863c..2ba35ad7 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp @@ -462,7 +462,7 @@ namespace SHADE vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand)); } - void SHVkCommandBuffer::DrawMultiIndirect(Handle indirectDrawData, uint32_t drawCount) + void SHVkCommandBuffer::DrawMultiIndirect(Handle indirectDrawData, uint32_t drawCount, uint32_t offset/* = 0*/) { if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING) { @@ -471,7 +471,7 @@ namespace SHADE } if (indirectDrawData) - vkCommandBuffer.drawIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand)); + vkCommandBuffer.drawIndirect(indirectDrawData->GetVkBuffer(), offset, drawCount, sizeof(vk::DrawIndirectCommand)); } diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h index c42ff33c..510dcc3b 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h @@ -131,7 +131,7 @@ namespace SHADE 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); + void DrawMultiIndirect (Handle indirectDrawData, uint32_t drawCount, uint32_t offset = 0); // Compute Commands void ComputeDispatch (uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 62e3c455..57b373dd 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -352,10 +352,10 @@ namespace SHADE /*-----------------------------------------------------------------------*/ auto vfxPass = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data(), { "Scene", "Depth Buffer" }, { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data() }); auto vfxSubpass = vfxPass->AddSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS.data(), worldViewport, worldRenderer); - vfxPass->AddPreBeginFunction([=](Handle cmdBuffer, uint32_t frameIndex) - { - particleSubSystem->Run(cmdBuffer, frameIndex); - }); + //vfxPass->AddPreBeginFunction([=](Handle cmdBuffer, uint32_t frameIndex) + // { + // particleSubSystem->Run(cmdBuffer, frameIndex); + // }); vfxSubpass->AddColorOutput("Scene"); vfxSubpass->AddDepthOutput("Depth Buffer"); vfxSubpass->AddExteriorDrawCalls([=](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) @@ -689,7 +689,6 @@ namespace SHADE textRenderingSubSystem->Run(frameIndex); trajectoryRenderingSubSystem->Run(frameIndex); - for (auto renderer : renderers) { #ifdef SHEDITOR @@ -711,6 +710,7 @@ namespace SHADE renderGraph->Begin(frameIndex); auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex); + particleSubSystem->Run(cmdBuffer, frameIndex); renderGraph->Execute(frameIndex, descPool, MESH_DATA); renderGraph->End(frameIndex); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp index 5e526ae2..8e1ce707 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp @@ -166,7 +166,8 @@ namespace SHADE void SHParticleSubSystem::RenderComponent(Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept { - cmdBuffer->DrawMultiIndirect(comp.drawCallData, 1); + cmdBuffer->DrawMultiIndirect(comp.drawCallData, 1, static_cast(sizeof(vk::DrawIndirectCommand)) * frameIndex); + //cmdBuffer->DrawArrays(4, 1, 0, 0); } void SHParticleSubSystem::PreparePrePostUpdateBarriers(std::vector& preUpdateBarriers, std::vector& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept @@ -215,10 +216,20 @@ namespace SHADE .size = static_cast(sizeof(uint32_t)) * emitter.maxParticles }; + // make new barrier on stack... + vk::BufferMemoryBarrier drawDataBarrier + { + .srcAccessMask = vk::AccessFlagBits::eShaderWrite, + .dstAccessMask = vk::AccessFlagBits::eShaderRead, + .buffer = emitter.drawCallData->GetVkBuffer(), + .offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_DRAW_DATA], + .size = static_cast(sizeof(vk::DrawIndirectCommand)) + }; // ...copy assign barriers on heap - postUpdateBarriers[EMITTER_INDEX * 2] = particleDataBarrierPost; - postUpdateBarriers[(EMITTER_INDEX * 2) + 1] = indicesDataBarrier; + postUpdateBarriers[EMITTER_INDEX * 3] = particleDataBarrierPost; + postUpdateBarriers[(EMITTER_INDEX * 3) + 1] = indicesDataBarrier; + postUpdateBarriers[(EMITTER_INDEX * 3) + 2] = drawDataBarrier; } @@ -264,6 +275,13 @@ namespace SHADE } renderingPipelineData.pipeline->GetPipelineState().SetColorBlenState(colorBlendState); + + // Sets the input assembly state for rendering particles + SHInputAssemblyState inputAssemblyState{}; + inputAssemblyState.topology = vk::PrimitiveTopology::eTriangleFan; + renderingPipelineData.pipeline->GetPipelineState().SetInputAssemblyState(inputAssemblyState); + + renderingPipelineData.pipeline->ConstructPipeline(); SHPipelineLayoutParams emitPlParams @@ -314,7 +332,7 @@ namespace SHADE // 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); + postUpdateBarriers.resize(emitters.size() * 3); // 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. From 0bfe350477b95483b48516fbec71d95f6bec3e7a Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Tue, 14 Mar 2023 19:37:34 +0800 Subject: [PATCH 05/16] Particles WIP --- Assets/Scenes/Scene2.shade | 8 ++++---- Assets/Shaders/Particle_VS.glsl | 4 ++-- Assets/Shaders/Particle_VS.shshaderb | Bin 5869 -> 5941 bytes 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index 96d2e525..2cfa3fb7 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -164,9 +164,9 @@ Max Life: 20 Angular Min: {x: 2.29999995, y: 1.70000005, z: 2.9000001} Angular Max: {x: 0, y: 0, z: 0} - Minimum Velocity: {x: 2, y: 3, z: 4} - Maximum Velocity: {x: 0, y: 0, z: 0} - Minimum Size: 5 - Maximum Size: 10 + Minimum Velocity: {x: 1, y: 1, z: 0} + Maximum Velocity: {x: 2, y: 2, z: 0} + Minimum Size: 1 + Maximum Size: 3 IsActive: true Scripts: ~ \ No newline at end of file diff --git a/Assets/Shaders/Particle_VS.glsl b/Assets/Shaders/Particle_VS.glsl index d5703c82..e6f73eb2 100644 --- a/Assets/Shaders/Particle_VS.glsl +++ b/Assets/Shaders/Particle_VS.glsl @@ -78,8 +78,8 @@ void main() vec2 particleScaleData = particle.scaleAndDecay.xz; // x and y mat4 localModel = mat4 (1.0f); - localModel[0][0] = 1.0f; - localModel[1][1] = 1.0f; + localModel[0][0] = particleScaleData.x; + localModel[1][1] = particleScaleData.y; mat4 rotate = mat4(1.0f); rotate[0][0] = cos(angle); diff --git a/Assets/Shaders/Particle_VS.shshaderb b/Assets/Shaders/Particle_VS.shshaderb index 82cb32311ab8fc2a4094ab06865219819200ad59..7afc020263359dad7b8472dd42cf88966eaeb831 100644 GIT binary patch delta 1939 zcmZ9MNlz3}6op^eG&n&>jIbav0x{7)gQmYP+ySWALI+c31VyEiybx18}WLvA{!1D z`omL-Ls3_WTu}A(WWwC`aHQZ54+K?T@pMf~^aQC^TK}GE@9~cXd4IcK@T)c8Sh?&- zSO~MjoNHq(RY!BX{6d1G+GrSz!I~~5E|HI8zB2V}6p`jozj%M(&1}jw= zy3Uo#Khod4h+AYWscvqkoOZKtlr@eS;h4)f&TutCuRO$}!*6%kE}OMeDmZecD|R}X zClEDO$$3s6Nz7FPNgM}OG}y%T304s9|2UdV#$gjT;i7+mkQT@!bV{;bbqj6V5Q`bwNn!Rrr72e0Y@CO6E~IsanEGa0)FDKX9PI;+uZZmAdrBM+DS?> z63-RC*EhE^30H>Vi*~}{NQqr4{;8k##>-O;zfw`!`J(htZbaaJkS&rifVyydwdn>>v|h5{slM96tu`)R=vT-5ofuvCrE z*d@Ue8U%cn__EH#CL4r9Z@I4MoXoZAstA(R3pg#=HJvS4rdV3GK0-25RX`AQX#awct s*_cZX^j;kC=3}_nh*Lz1BjS{AKxc|Up7y`l-M82v&(zDzm*-~Q~&?~ delta 1866 zcmZ9LyH6BR7{%|f4}1VIF+xFN1R5>G5G$f+ctj{Pq8JMc%>)KB2<&EAK`9vU{T5iC zponjD6=R68v-F>^wXv|Vu=f0B=EBCiIl1>c-}zqm&VFh9y|dc+S#83VC~GJ;#xWaA zrTH{d-Q&!C9+*$;n36M>$-8;an3PGIN3u^3p6d2;$Gu$MJ4b99zR;MgX~yfsii|&; z@A1bKhoU@;EQ@^YgMPNdAIZDJyO7U*8`U`w7J@8_?DU4coZlN(Pn%@O zi8g(zz`$rI>J7Tt5wGuo|xslSQ5xc}p5vNR5xxM>rt1wz_DCZSW3b*gJ#u3n&XYuD+_ zqHr-fhDl2~^c3QDtj;#Q4$hLcql#E)UyNWD4Z+!lmUX5f77Z=0w5|V<2p-BL@1U?% zPtR-YjX8W^o8*tRQxgB4*ybMrM;x;gH&z1Tp2(&J{KR2%H*oUTn}ygQkbrmENlG#j z7YpAiYwDPUD?{;7JK=Do#9l7^t(}KO1=Z~)7f>wCc_!T6WoY>Hu+82ByDyLcJ^tvCqvjsS=8;bbJSsN&Ru$&!dnWKnas@3WNQU3=q6{2N!>9RN zAjzzPuwMv^0z4Wfd@1Y}Y@@GYPTMN?I_8+(>fXd$IMBg(qPHSRKmY Date: Wed, 15 Mar 2023 10:28:51 +0800 Subject: [PATCH 06/16] Solved particles flickering (I hope) - Good reminder how strict Vulkan is with memory accesses --- Assets/Shaders/ParticleUpdate_CS.glsl | 3 + Assets/Shaders/Particle_VS.glsl | 11 ++- Assets/Shaders/Particle_VS.shshaderb | Bin 5941 -> 5761 bytes .../GlobalData/SHGraphicsPredefinedData.cpp | 2 +- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 2 + .../Particles/SHParticleSubSystem.cpp | 83 ++++++++++++++---- .../MiddleEnd/Particles/SHParticleSubSystem.h | 6 +- .../src/Graphics/Synchronization/SHVkFence.h | 2 +- 8 files changed, 84 insertions(+), 25 deletions(-) diff --git a/Assets/Shaders/ParticleUpdate_CS.glsl b/Assets/Shaders/ParticleUpdate_CS.glsl index 33da0d5e..722833ad 100644 --- a/Assets/Shaders/ParticleUpdate_CS.glsl +++ b/Assets/Shaders/ParticleUpdate_CS.glsl @@ -118,6 +118,9 @@ void main() if (particle.life > 0.0f) { + // update position from velocity + // particle.position += particle.velocity * genericDataBuffer.data.dt; + // particle.life -= genericDataBuffer.data.dt; if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f) { diff --git a/Assets/Shaders/Particle_VS.glsl b/Assets/Shaders/Particle_VS.glsl index e6f73eb2..2645fe87 100644 --- a/Assets/Shaders/Particle_VS.glsl +++ b/Assets/Shaders/Particle_VS.glsl @@ -78,8 +78,11 @@ void main() vec2 particleScaleData = particle.scaleAndDecay.xz; // x and y mat4 localModel = mat4 (1.0f); - localModel[0][0] = particleScaleData.x; - localModel[1][1] = particleScaleData.y; + localModel[0][0] = 1.0f; + localModel[1][1] = 1.0f; + + // localModel[0][0] = particleScaleData.x; + // localModel[1][1] = particleScaleData.y; mat4 rotate = mat4(1.0f); rotate[0][0] = cos(angle); @@ -89,6 +92,6 @@ void main() // localModel = rotate * localModel; localModel[3] = vec4 (particle.position.xyz, 1.0f); - gl_Position = cameraData.vpMat * localModel * vec4(vertexPos, 1.0f); - // gl_Position = vec4(vertexPos, 1.0f); + // gl_Position = cameraData.vpMat * localModel * vec4(vertexPos, 1.0f); + gl_Position = vec4(vertexPos, 1.0f); } \ No newline at end of file diff --git a/Assets/Shaders/Particle_VS.shshaderb b/Assets/Shaders/Particle_VS.shshaderb index 7afc020263359dad7b8472dd42cf88966eaeb831..c863fca2de80928a25a643004b41c3211faca429 100644 GIT binary patch delta 1793 zcmZ9LOHUI~7=~x)1yO2DOxi^gqp;D17(-$t-Xf5I3nPj#!G&f50~suBQ$|1*6ujRR z>J=2Rc)_J<-1f;q%Su>D>z(Ye-1Pysbj2_)14S(}mZL6a_Eu z4|=nTL(v>WHif>PoLB7iCVeMA?1sL|Ts(Vj8L3u6zpC~=H}96b;a2X|{t-W{ ziH2%!&M8j1BbU92Fk7{9Es?dWmDxnLye@x3p6;8Yqi#uDQZ?|gMkt__P?uk|k8Rbh z>*?v6d_B&DTXKSylp`5%#1;#ap6?a%oXL$=z4cgA#q*B(t&@yk%5$e-jW8yzSSpOe zQD{T+9fAoaIb3VRt!rn&u_y>fY@gCG;s`0aATag#6UwF-1fMbiQ}degrKXJLL+AaxhXo5aWkH>O<t4o2lgxcy>?3CKM~pdP2ljaMQ38kQ?2|?Wro&eRRt7Zw9^b68L$~Y z91%22^mGG=`z{*|e&Vn!nBEpy3CTcggs&ow z-~s(FDE3+)0ebx5BZtksk5vi@--N%TdYtzVT#5FeZ kNgVO$@ta20bp9;x7hy^?f{p&4u6JBGrb)Ean$n&2e*#_6OaK4? delta 1978 zcmZ9M=}S~$6vp4{EZU+7kwHRK5@eJSeTp{Hz`jJ5QQ()j>8);!&M@Az`p_-Q_RXf< zHf`U_p}(f@LH|Vb{ATXap*J4ibDp!G_fF^6{p@J*)-G|Cld5a0cg}P3U85^cwDfw< ze;l7owU5hK%tw9{IG1r*_f-1P+@YSJcpxZ7!6{<1@THFQl1*5>#3LULMZMt}#o zR2?bo_M;k(Y9nDV3Tu8TafM?3I2?7Rr1w|r9Ih0C{3fzH7z&DEf2DfXr7N6hH=qg( zj1NVFoL?9Y2KI-8)luNBa3Noe4u%8KF>$QmTj_7Q)%#vrnrU70T^whiQk9|W-Hi03 zb9FmU9yt;eUHMmL+KX8&XF>IHyA)yThNBnbs1L`m#v#L{g>G4h#SgnJwoN)`m%QM} znW^ZRc$UDaxk}D*`f?Jk8c5 zlTyi>6PD@Q;5D`+95%3A?$2~n68q*v=Vt;(9J3QQS_9%jLW1j~}yuo3e^Hwl@SBIq-v-;I;rczLYpPb$thUzDEC4Ga87vsG@S zJSV{KP;z|E3#WzE0)E?63htb+L+^&qm_QzOW_d0oyydwlojlD#jshft#1VO1_gTRb zT#|f3Sg1y5?6TkqO#(Jcd_^*`wGG1IZ@I2YuFbXTnh26L3K%Wfb;*`2SDIe5KE~sQ z5GVV&CHbac5w|51!CbZq9m%!jC#2gb*eusw$(D;akJ15Ql%PS_||r|%O^ z*DUuT;c6%Pm~gcNeG*4J{@594Ld6-j{j>hi08UK7&+)6kZ=EM#O7zd=ZHv3Sf6UBegin(frameIndex); auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex); + particleSubSystem->ResetInstanceCounts(cmdBuffer, frameIndex); particleSubSystem->Run(cmdBuffer, frameIndex); renderGraph->Execute(frameIndex, descPool, MESH_DATA); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp index 8e1ce707..7e1e9455 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp @@ -14,6 +14,8 @@ #include "Graphics/Pipeline/SHVkPipeline.h" #include "Graphics/RenderGraph/SHSubpass.h" #include "Graphics/SHVkUtil.h" +#include "Graphics/Synchronization/SHVkFence.h" + namespace SHADE { @@ -68,7 +70,7 @@ namespace SHADE } // buffer to store draw call data. Non-indexed, host-visible mapped, triple buffered. - comp.drawCallData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, 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); + comp.drawCallData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndirectBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT); } @@ -151,12 +153,6 @@ namespace SHADE { auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING); - uint32_t instanceCountOffset = sizeof (vk::DrawIndirectCommand) * frameIndex + offsetof(vk::DrawIndirectCommand, instanceCount); - uint32_t ZERO = 0; - - // reset instance count to 0 - comp.drawCallData->WriteToMemory (&ZERO, sizeof(uint32_t), 0, instanceCountOffset); - // bind the descriptor sets required for emitting particles cmdBuffer->BindDescriptorSet(comp.particleDescriptorSet, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), comp.dynamicOffsets[frameIndex]); @@ -170,7 +166,7 @@ namespace SHADE //cmdBuffer->DrawArrays(4, 1, 0, 0); } - void SHParticleSubSystem::PreparePrePostUpdateBarriers(std::vector& preUpdateBarriers, std::vector& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept + void SHParticleSubSystem::PreparePrePostUpdateBarriers(std::vector& preUpdateBarriers, std::vector& postUpdateBarriers, std::vector& preDrawBarriers, 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 @@ -219,18 +215,17 @@ namespace SHADE // make new barrier on stack... vk::BufferMemoryBarrier drawDataBarrier { - .srcAccessMask = vk::AccessFlagBits::eShaderWrite, - .dstAccessMask = vk::AccessFlagBits::eShaderRead, + .srcAccessMask = vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eMemoryWrite, + .dstAccessMask = vk::AccessFlagBits::eIndirectCommandRead, .buffer = emitter.drawCallData->GetVkBuffer(), .offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_DRAW_DATA], .size = static_cast(sizeof(vk::DrawIndirectCommand)) }; // ...copy assign barriers on heap - postUpdateBarriers[EMITTER_INDEX * 3] = particleDataBarrierPost; - postUpdateBarriers[(EMITTER_INDEX * 3) + 1] = indicesDataBarrier; - postUpdateBarriers[(EMITTER_INDEX * 3) + 2] = drawDataBarrier; - + postUpdateBarriers[EMITTER_INDEX * 2] = particleDataBarrierPost; + postUpdateBarriers[(EMITTER_INDEX * 2) + 1] = indicesDataBarrier; + preDrawBarriers[EMITTER_INDEX] = drawDataBarrier; } void SHParticleSubSystem::Init(Handle device, Handle inDescPool, Handle compatibleRenderpass, Handle subpass, Handle VS, Handle FS, Handle emitCS, Handle defaultUpdateCS) noexcept @@ -310,7 +305,7 @@ namespace SHADE SHComponentManager::CreateComponentSparseSet(); } - void SHParticleSubSystem::Run(Handle cmdBuffer, uint32_t frameIndex) noexcept + void SHParticleSubSystem::Run(Handle cmdBuffer, uint32_t frameIndex, Handle waitFence) noexcept { float dt = static_cast(SHFrameRateController::GetRawDeltaTime()); @@ -332,7 +327,11 @@ namespace SHADE // 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() * 3); + postUpdateBarriers.resize(emitters.size() * 2); + + std::vector preDrawBarriers{}; + preDrawBarriers.resize(emitters.size()); + // 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. @@ -350,6 +349,10 @@ namespace SHADE SHGlobalDescriptorSets::BindGenericAndTextureData(logicalDevice, cmdBuffer, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::STATIC_DATA), frameIndex); uint32_t i = 0; + + if (waitFence) + waitFence->Wait(true); + for (auto& emitter : emitters) { if (!emitter.initialized) @@ -382,7 +385,7 @@ namespace SHADE } // prepare barriers - PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, emitter, i, frameIndex); + PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, preDrawBarriers, emitter, i, frameIndex); // Emitter will emit once and stop emitting next frame (unless specified before reaching here to do so). emitter.toEmit = false; @@ -398,6 +401,7 @@ namespace SHADE /* EMITTING PARTICLES DONE, BEGIN UPDATES.... */ /*-----------------------------------------------------------------------*/ + // bind the pipeline for updating cmdBuffer->BindPipeline(defaultUpdatePipelineData.pipeline); @@ -411,9 +415,53 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // 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, {}); + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eDrawIndirect, {}, {}, preDrawBarriers, {}); } + void SHParticleSubSystem::ResetInstanceCounts(Handle cmdBuffer, uint32_t frameIndex) noexcept + { + auto& emitters = SHComponentManager::GetDense(); + std::vector preResetBarriers{}; + preResetBarriers.resize(emitters.size()); + + uint32_t i = 0; + for (auto& emitter : emitters) + { + if (emitter.initialized) + { + // 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 drawDataHostWriteBarrier + { + .srcAccessMask = vk::AccessFlagBits::eIndirectCommandRead | vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite, + .dstAccessMask = vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eHostWrite, + .buffer = emitter.drawCallData->GetVkBuffer(), + .offset = emitter.dynamicOffsets[frameIndex][DYOFF_INDEX_DRAW_DATA], + .size = static_cast(sizeof(vk::DrawIndirectCommand)) + }; + + preResetBarriers[i] = drawDataHostWriteBarrier; + } + ++i; + } + + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eDrawIndirect, vk::PipelineStageFlagBits::eHost, {}, {}, preResetBarriers, {}); + + + for (auto& emitter : emitters) + { + if (emitter.initialized) + { + //uint32_t instanceCountOffset = 20; + uint32_t instanceCountOffset = sizeof(vk::DrawIndirectCommand) * frameIndex + offsetof(vk::DrawIndirectCommand, instanceCount); + uint32_t ZERO = 0; + + // reset instance count to 0 + emitter.drawCallData->WriteToMemory(&ZERO, sizeof(uint32_t), 0, instanceCountOffset); + } + } + } + void SHParticleSubSystem::Render(Handle cmdBuffer, Handle renderer, uint32_t frameIndex) noexcept { auto& emitters = SHComponentManager::GetDense(); @@ -432,6 +480,7 @@ namespace SHADE } } + void SHParticleSubSystem::Exit(void) noexcept { diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h index 73404e3d..bb8f570d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h @@ -20,6 +20,7 @@ namespace SHADE class SHVkShaderModule; class SHRenderer; class SHParticleEmitterComponent; + class SHVkFence; @@ -81,12 +82,13 @@ 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; + void PreparePrePostUpdateBarriers (std::vector& preUpdateBarriers, std::vector& postUpdateBarriers, std::vector& preDrawBarriers, 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; - void Run(Handle cmdBuffer, uint32_t frameIndex) noexcept; + void Run(Handle cmdBuffer, uint32_t frameIndex, Handle waitFence = {}) noexcept; + void ResetInstanceCounts (Handle cmdBuffer, uint32_t frameIndex) noexcept; void Render(Handle cmdBuffer, Handle renderer, uint32_t frameIndex) noexcept; void Exit(void) noexcept; diff --git a/SHADE_Engine/src/Graphics/Synchronization/SHVkFence.h b/SHADE_Engine/src/Graphics/Synchronization/SHVkFence.h index 7c48a5f6..9e552a85 100644 --- a/SHADE_Engine/src/Graphics/Synchronization/SHVkFence.h +++ b/SHADE_Engine/src/Graphics/Synchronization/SHVkFence.h @@ -30,7 +30,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - bool Wait (bool waitAll, uint64_t timer) noexcept; + bool Wait (bool waitAll, uint64_t timer = std::numeric_limits::max()) noexcept; void Reset (void) noexcept; /*-----------------------------------------------------------------------*/ From 32ef4d8c554e818d805323adc9004ed66d247832 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Wed, 15 Mar 2023 21:09:55 +0800 Subject: [PATCH 07/16] Updated particle interfaces and added more barriers --- Assets/Scenes/Scene2.shade | 19 ++-- Assets/Shaders/ParticleEmit_CS.glsl | 26 ++++-- Assets/Shaders/ParticleEmit_CS.shshaderb | Bin 7685 -> 9957 bytes Assets/Shaders/ParticleUpdate_CS.glsl | 10 +-- Assets/Shaders/ParticleUpdate_CS.shshaderb | Bin 6229 -> 6541 bytes Assets/Shaders/Particle_VS.glsl | 24 +++-- Assets/Shaders/Particle_VS.shshaderb | Bin 5761 -> 6357 bytes .../Inspector/SHEditorComponentView.hpp | 37 +++----- .../Particles/SHParticleEmitterComponent.cpp | 34 +++---- .../Particles/SHParticleEmitterComponent.h | 55 ++++++------ .../Particles/SHParticleSubSystem.cpp | 84 +++++++----------- .../MiddleEnd/Particles/SHParticleSubSystem.h | 4 +- .../src/Serialization/SHYAMLConverters.h | 32 +++---- 13 files changed, 145 insertions(+), 180 deletions(-) diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index 2cfa3fb7..76595523 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -158,15 +158,14 @@ IsActive: true classSHADE::SHParticleEmitterComponent: Emission Count: 1 - Is Passive: false - Emission Interval: 3 - Min Life: 7 - Max Life: 20 - Angular Min: {x: 2.29999995, y: 1.70000005, z: 2.9000001} - Angular Max: {x: 0, y: 0, z: 0} - Minimum Velocity: {x: 1, y: 1, z: 0} - Maximum Velocity: {x: 2, y: 2, z: 0} - Minimum Size: 1 - Maximum Size: 3 + Is Passive: true + Emission Interval: 0.200000003 + Min Life: 2 + Max Life: 3 + Minimum Speed: 3 + Maximum Speed: 6 + Minimum Size: 0 + Maximum Size: 0.5 + Angular Ranges And Offset: {x: 0, y: 0, z: 0, w: 0} IsActive: true Scripts: ~ \ No newline at end of file diff --git a/Assets/Shaders/ParticleEmit_CS.glsl b/Assets/Shaders/ParticleEmit_CS.glsl index 6c65ff83..1e2a0882 100644 --- a/Assets/Shaders/ParticleEmit_CS.glsl +++ b/Assets/Shaders/ParticleEmit_CS.glsl @@ -4,10 +4,10 @@ layout(local_size_x = 128) in; struct EmitterParameters { - vec4 angularMin; - vec4 angularMax; - vec4 minVel; - vec4 maxVel; + vec4 angularRangesAndOffsets; + float minSpeed; + float maxSpeed; + float padding[2]; vec4 lifeAndSizeRange; // min life, max life, min size, max size }; @@ -107,6 +107,9 @@ void main() { uint emitterInvocationIndex = gl_GlobalInvocationID.x; vec4 emitterPosition = emitterPushConstant.emitterPosition; + vec4 angularRangesAndOffsets = emitterParams.data.angularRangesAndOffsets; + float minSpeed = emitterParams.data.minSpeed; + float maxSpeed = emitterParams.data.maxSpeed; if (emitterInvocationIndex >= emitterPushConstant.emissionCount) return; @@ -127,15 +130,24 @@ void main() // emit particle from emitter position particle.position = vec4 (emitterPosition.xyz, 1.0f); + vec2 eulerAngles = vec2 (rand(seed) * angularRangesAndOffsets.x + angularRangesAndOffsets.z, + rand(seed) * angularRangesAndOffsets.y + angularRangesAndOffsets.w); + // Set its velocity - particle.velocity = emitterParams.data.minVel; + particle.velocity.xyz = vec3 (cos(eulerAngles.x) * cos(eulerAngles.y), + sin(eulerAngles.x) * cos(eulerAngles.y), + sin(eulerAngles.y)); + + particle.velocity *= map (rand (seed), 0.0f, 1.0f, minSpeed.x, maxSpeed.x); // randomize life value that ranges from minLife to maxLife particle.life = map (rand(seed), 0.0f, 1.0f, emitterParams.data.lifeAndSizeRange.x, emitterParams.data.lifeAndSizeRange.y); + float particleSize = map (rand(seed), 0.0f, 1.0f, emitterParams.data.lifeAndSizeRange.z, emitterParams.data.lifeAndSizeRange.w); + // Set size of particle - particle.scaleAndDecay.x = emitterParams.data.lifeAndSizeRange.z; - particle.scaleAndDecay.z = emitterParams.data.lifeAndSizeRange.z; + particle.scaleAndDecay.x = particleSize; + particle.scaleAndDecay.z = particleSize; particle.rotation = vec4 (5.0f); particle.acceleration = vec4 (0.01f); diff --git a/Assets/Shaders/ParticleEmit_CS.shshaderb b/Assets/Shaders/ParticleEmit_CS.shshaderb index 898baf45d9f8cfbeb4c6f34f99c06f4751117f51..125d56214d9838b6209164686b53572e48083b69 100644 GIT binary patch literal 9957 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 bANXBqJr_tP7q-h%u2(wa!p2;Jnak$@c})kQ literal 7685 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 0.0f) { // update position from velocity - // particle.position += particle.velocity * genericDataBuffer.data.dt; - // particle.life -= genericDataBuffer.data.dt; + particle.position += particle.velocity * genericDataBuffer.data.dt; + particle.life -= genericDataBuffer.data.dt; if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f) { particle.life = 0.0f; - particle.position.x = 99999.0f; + particle.position.x = 9999.0f; outputParticles.data[index] = particle; freelist.freeIndices[atomicAdd(freelist.freeCount, 1)] = int (index); return; } - outputParticles.data[index] = particle; uint drawIndex = atomicAdd (indirectArgs.instanceCount, 1); indices[drawIndex] = index; - // indirectArgs.instanceCount = 1; } + + outputParticles.data[index] = particle; } \ No newline at end of file diff --git a/Assets/Shaders/ParticleUpdate_CS.shshaderb b/Assets/Shaders/ParticleUpdate_CS.shshaderb index 53c89d01ec7756fe8677723c7f5996f0278f6b8d..8f0de701474344fe7efab5fe56b8a95f552c3305 100644 GIT binary patch literal 6541 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 Icj!Un|Hf)=G5`Po 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 diff --git a/Assets/Shaders/Particle_VS.glsl b/Assets/Shaders/Particle_VS.glsl index 2645fe87..d74acdd9 100644 --- a/Assets/Shaders/Particle_VS.glsl +++ b/Assets/Shaders/Particle_VS.glsl @@ -74,24 +74,22 @@ void main() ParticleData particle = outputParticles.data[indices[gl_InstanceIndex]]; vec3 normalized = normalize (particle.velocity.xyz); - float angle = atan (normalized.y, normalized.x); + float angle = 1.1f; + // float angle = atan (normalized.y, normalized.x); vec2 particleScaleData = particle.scaleAndDecay.xz; // x and y - mat4 localModel = mat4 (1.0f); - localModel[0][0] = 1.0f; - localModel[1][1] = 1.0f; - - // localModel[0][0] = particleScaleData.x; - // localModel[1][1] = particleScaleData.y; - - mat4 rotate = mat4(1.0f); + mat3 rotate = mat3 (1.0f); rotate[0][0] = cos(angle); rotate[0][1] = sin(angle); rotate[1][0] = -sin(angle); rotate[1][1] = cos(angle); - // localModel = rotate * localModel; - localModel[3] = vec4 (particle.position.xyz, 1.0f); - // gl_Position = cameraData.vpMat * localModel * vec4(vertexPos, 1.0f); - gl_Position = vec4(vertexPos, 1.0f); + vec3 particlePos = rotate * vertexPos; + + vec3 viewRight = normalize (vec3 (cameraData.viewMat[0][0], cameraData.viewMat[1][0], cameraData.viewMat[2][0])); + vec3 viewUp = normalize(vec3 (cameraData.viewMat[0][1], cameraData.viewMat[1][1], cameraData.viewMat[2][1])); + + particlePos = particle.position.xyz + (viewRight * particlePos.x * particleScaleData.x) + (viewUp * particlePos.y * particleScaleData.y); + + gl_Position = cameraData.vpMat * vec4(particlePos, 1.0f); } \ No newline at end of file diff --git a/Assets/Shaders/Particle_VS.shshaderb b/Assets/Shaders/Particle_VS.shshaderb index c863fca2de80928a25a643004b41c3211faca429..d79ee1d1cd5d1d3e5d7635143926837c84ac367b 100644 GIT binary patch literal 6357 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 }, [comp = component](float val) {comp->SetMinLife(val); }); SHEditorWidgets::DragFloat("Max Life", [comp = component]() {return comp->GetMaxLife(); }, [comp = component](float val) {comp->SetMaxLife(val); }); SHEditorWidgets::DragFloat("Min Size", [comp = component]() {return comp->GetMinSize(); }, [comp = component](float val) {comp->SetMinSize(val); }); - SHEditorWidgets::DragFloat("Man Size", [comp = component]() {return comp->GetMaxSize(); }, [comp = component](float val) {comp->SetMaxSize(val); }); + SHEditorWidgets::DragFloat("Max Size", [comp = component]() {return comp->GetMaxSize(); }, [comp = component](float val) {comp->SetMaxSize(val); }); - SHEditorWidgets::DragVec3("Angular Min", {"x", "y", "z"}, + SHEditorWidgets::DragVec4("Angles and Offsets", {"yaw", "pitch", "yaw off", "pitch off"}, [comp = component]() { - return comp->GetAngularMin(); + return comp->GetAngularRangesAndOffsets(); }, - [comp = component](SHVec3 const& val) + [comp = component](SHVec4 const& val) { - comp->SetAngularMin(val); + comp->SetAngularRangesAndOffsets(val); }); - SHEditorWidgets::DragVec3("Angular Max", { "x", "y", "z" }, + + SHEditorWidgets::DragFloat("Min Speed", [comp = component]() { - return comp->GetAngularMax(); + return comp->GetMinSpeed(); }, - [comp = component](SHVec3 const& val) + [comp = component](float val) { - comp->SetAngularMax(val); + comp->SetMinSpeed(val); }); - SHEditorWidgets::DragVec3("Min Vel", { "x", "y", "z" }, + SHEditorWidgets::DragFloat("Max Speed", [comp = component]() { - return comp->GetMinVelocity(); + return comp->GetMaxSpeed(); }, - [comp = component](SHVec3 const& val) + [comp = component](float val) { - comp->SetMinVelocity(val); - }); - - SHEditorWidgets::DragVec3("Max Vel", { "x", "y", "z" }, - [comp = component]() - { - return comp->GetMaxVelocity(); - }, - [comp = component](SHVec3 const& val) - { - comp->SetMaxVelocity(val); + comp->SetMaxSpeed(val); }); SHEditorWidgets::CheckBox("Is Passive", [comp = component]() {return comp->GetPassive(); }, [comp = component](bool flag) {comp->SetPassive(flag); }); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp index d2c0e05a..b095f26b 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp @@ -46,24 +46,20 @@ namespace SHADE cpuEmitterData.lifeAndSizeRange.y = val; } - void SHParticleEmitterComponent::SetAngularMin(SHVec3 const& min) noexcept + void SHParticleEmitterComponent::SetAngularRangesAndOffsets(SHVec4 const& ranges) noexcept { - cpuEmitterData.angularMin = SHVec4 (min); + cpuEmitterData.angularRangesAndOffsets = SHVec4 (ranges); } - void SHParticleEmitterComponent::SetAngularMax(SHVec3 const& max) noexcept + + void SHParticleEmitterComponent::SetMinSpeed(float speed) noexcept { - cpuEmitterData.angularMax = SHVec4(max); + cpuEmitterData.minSpeed = speed; } - void SHParticleEmitterComponent::SetMinVelocity(SHVec3 const& vel) noexcept + void SHParticleEmitterComponent::SetMaxSpeed(float speed) noexcept { - cpuEmitterData.minVel = vel; - } - - void SHParticleEmitterComponent::SetMaxVelocity(SHVec3 const& vel) noexcept - { - cpuEmitterData.maxVel = vel; + cpuEmitterData.maxSpeed = speed; } void SHParticleEmitterComponent::SetMinSize(float size) noexcept @@ -102,19 +98,19 @@ namespace SHADE } - SHVec3 SHParticleEmitterComponent::GetAngularMin(void) const noexcept + SHVec4 const& SHParticleEmitterComponent::GetAngularRangesAndOffsets(void) const noexcept { - return SHVec3 (cpuEmitterData.angularMin.x, cpuEmitterData.angularMin.y, cpuEmitterData.angularMin.z); + return cpuEmitterData.angularRangesAndOffsets; } - SHVec3 SHParticleEmitterComponent::GetMinVelocity(void) const noexcept + float SHParticleEmitterComponent::GetMinSpeed(void) const noexcept { - return SHVec3(cpuEmitterData.minVel.x, cpuEmitterData.minVel.y, cpuEmitterData.minVel.z); + return cpuEmitterData.minSpeed; } - SHVec3 SHParticleEmitterComponent::GetMaxVelocity(void) const noexcept + float SHParticleEmitterComponent::GetMaxSpeed(void) const noexcept { - return SHVec3(cpuEmitterData.maxVel.x, cpuEmitterData.maxVel.y, cpuEmitterData.maxVel.z); + return cpuEmitterData.maxSpeed; } float SHParticleEmitterComponent::GetMinSize(void) const noexcept @@ -127,9 +123,5 @@ namespace SHADE return cpuEmitterData.lifeAndSizeRange.w; } - SHVec3 SHParticleEmitterComponent::GetAngularMax(void) const noexcept - { - return SHVec3(cpuEmitterData.angularMax.x, cpuEmitterData.angularMax.y, cpuEmitterData.angularMax.z); - } } \ 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 7781c29f..e345c24d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h @@ -16,17 +16,16 @@ namespace SHADE private: struct GPUEmitterStruct { - //! Minimum emitting angular range - SHVec4 angularMin; - - //! Maximum emitting angular range - SHVec4 angularMax; + //! Angular ranges of emission + SHVec4 angularRangesAndOffsets; //! minimum starting velocity - SHVec4 minVel; + float minSpeed; //! Maximum starting velocity - SHVec4 maxVel; + float maxSpeed; + + float padding[2]; //! Spawn lifetime and size range (min and max) SHVec4 lifeAndSizeRange; @@ -111,30 +110,28 @@ namespace SHADE void Emit (void) noexcept; - void SetEmissionCount (uint32_t count) noexcept; - void SetPassive (bool flag) noexcept; - void SetEmissionInterval (float interval) noexcept; - void SetMinLife (float val) noexcept; - void SetMaxLife (float val) noexcept; - void SetAngularMin (SHVec3 const& min) noexcept; - void SetAngularMax (SHVec3 const& max) noexcept; - void SetMinVelocity (SHVec3 const& vel) noexcept; - void SetMaxVelocity (SHVec3 const& vel) noexcept; - void SetMinSize (float size) noexcept; - void SetMaxSize (float size) noexcept; + void SetEmissionCount (uint32_t count) noexcept; + void SetPassive (bool flag) noexcept; + void SetEmissionInterval (float interval) noexcept; + void SetMinLife (float val) noexcept; + void SetMaxLife (float val) noexcept; + void SetAngularRangesAndOffsets (SHVec4 const& ranges) noexcept; + void SetMinSpeed (float speed) noexcept; + void SetMaxSpeed (float speed) noexcept; + void SetMinSize (float size) noexcept; + void SetMaxSize (float size) noexcept; - uint32_t GetEmissionCount (void) const noexcept; - bool GetPassive (void) const noexcept; - float GetEmissionInterval (void) const noexcept; - float GetMinLife (void) const noexcept; - float GetMaxLife (void) const noexcept; - SHVec3 GetAngularMax (void) const noexcept; - SHVec3 GetAngularMin (void) const noexcept; - SHVec3 GetMinVelocity (void) const noexcept; - SHVec3 GetMaxVelocity (void) const noexcept; - float GetMinSize (void) const noexcept; - float GetMaxSize (void) const noexcept; + uint32_t GetEmissionCount (void) const noexcept; + bool GetPassive (void) const noexcept; + float GetEmissionInterval (void) const noexcept; + float GetMinLife (void) const noexcept; + float GetMaxLife (void) const noexcept; + SHVec4 const& GetAngularRangesAndOffsets (void) const noexcept; + float GetMinSpeed (void) const noexcept; + float GetMaxSpeed (void) const noexcept; + float GetMinSize (void) const noexcept; + float GetMaxSize (void) const 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 7e1e9455..665f43aa 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp @@ -23,7 +23,7 @@ namespace SHADE void SHParticleSubSystem::InitializeComponent(SHParticleEmitterComponent& comp) noexcept { // TODO: temporary only. - static constexpr uint32_t NUM_PARTICLES = 5; + static constexpr uint32_t NUM_PARTICLES = 2000; comp.maxParticles = NUM_PARTICLES; uint32_t sizeofUint = static_cast(sizeof(uint32_t)); @@ -166,34 +166,46 @@ namespace SHADE //cmdBuffer->DrawArrays(4, 1, 0, 0); } - void SHParticleSubSystem::PreparePrePostUpdateBarriers(std::vector& preUpdateBarriers, std::vector& postUpdateBarriers, std::vector& preDrawBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept + 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 + vk::BufferMemoryBarrier inputParticleDataBarrierPreUpdate { - .srcAccessMask = vk::AccessFlagBits::eShaderWrite, + .srcAccessMask = vk::AccessFlagBits::eShaderRead | 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 + // pre-update free list data barrier. + vk::BufferMemoryBarrier freelistDataBarrierPreUpdate { - .srcAccessMask = vk::AccessFlagBits::eShaderWrite, - .dstAccessMask = vk::AccessFlagBits::eShaderRead, + .srcAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite, + .dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite, .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) }; + // pre update indices data barrier. + vk::BufferMemoryBarrier indicesDataBarrierPreUpdate + { + + .srcAccessMask = vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead, + .dstAccessMask = vk::AccessFlagBits::eShaderWrite, + .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 - preUpdateBarriers[EMITTER_INDEX * 2] = particleDataBarrier; - preUpdateBarriers[(EMITTER_INDEX * 2) + 1] = freelistDataBarrier; + preUpdateBarriers[EMITTER_INDEX * 3] = inputParticleDataBarrierPreUpdate; + preUpdateBarriers[(EMITTER_INDEX * 3) + 1] = freelistDataBarrierPreUpdate; + preUpdateBarriers[(EMITTER_INDEX * 3) + 2] = indicesDataBarrierPreUpdate; // make new barrier on stack... - vk::BufferMemoryBarrier particleDataBarrierPost + vk::BufferMemoryBarrier outputParticleDataBarrierPostUpdate { .srcAccessMask = vk::AccessFlagBits::eShaderWrite, .dstAccessMask = vk::AccessFlagBits::eShaderRead, @@ -203,7 +215,7 @@ namespace SHADE }; // make new barrier on stack... - vk::BufferMemoryBarrier indicesDataBarrier + vk::BufferMemoryBarrier indicesDataBarrierPostUpdate { .srcAccessMask = vk::AccessFlagBits::eShaderWrite, .dstAccessMask = vk::AccessFlagBits::eShaderRead, @@ -213,9 +225,9 @@ namespace SHADE }; // make new barrier on stack... - vk::BufferMemoryBarrier drawDataBarrier + vk::BufferMemoryBarrier drawDataBarrierPostUpdate { - .srcAccessMask = vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eMemoryWrite, + .srcAccessMask = vk::AccessFlagBits::eShaderWrite, .dstAccessMask = vk::AccessFlagBits::eIndirectCommandRead, .buffer = emitter.drawCallData->GetVkBuffer(), .offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_DRAW_DATA], @@ -223,9 +235,9 @@ namespace SHADE }; // ...copy assign barriers on heap - postUpdateBarriers[EMITTER_INDEX * 2] = particleDataBarrierPost; - postUpdateBarriers[(EMITTER_INDEX * 2) + 1] = indicesDataBarrier; - preDrawBarriers[EMITTER_INDEX] = drawDataBarrier; + postUpdateBarriers[EMITTER_INDEX * 3] = outputParticleDataBarrierPostUpdate; + postUpdateBarriers[(EMITTER_INDEX * 3) + 1] = indicesDataBarrierPostUpdate; + postUpdateBarriers[(EMITTER_INDEX * 3) + 2] = drawDataBarrierPostUpdate; } void SHParticleSubSystem::Init(Handle device, Handle inDescPool, Handle compatibleRenderpass, Handle subpass, Handle VS, Handle FS, Handle emitCS, Handle defaultUpdateCS) noexcept @@ -322,12 +334,12 @@ namespace SHADE // 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() * 2); + preUpdateBarriers.resize(emitters.size() * 3); // 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); + postUpdateBarriers.resize(emitters.size() * 3); std::vector preDrawBarriers{}; preDrawBarriers.resize(emitters.size()); @@ -340,8 +352,6 @@ namespace SHADE /* BEGIN EMITTING PARTICES */ /*-----------------------------------------------------------------------*/ - // TODO: Might need to issue a barrier here for input particle data - // bind the pipeline for emitting particles cmdBuffer->BindPipeline(emittingPipelineData.pipeline); @@ -385,7 +395,7 @@ namespace SHADE } // prepare barriers - PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, preDrawBarriers, emitter, i, frameIndex); + 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; @@ -393,7 +403,7 @@ namespace SHADE } // issue the barrier to wait - cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {}); + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eDrawIndirect, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {}); @@ -414,39 +424,13 @@ namespace SHADE /* 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, {}); - cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eDrawIndirect, {}, {}, preDrawBarriers, {}); + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eDrawIndirect | vk::PipelineStageFlagBits::eVertexShader, {}, {}, postUpdateBarriers, {}); } void SHParticleSubSystem::ResetInstanceCounts(Handle cmdBuffer, uint32_t frameIndex) noexcept { auto& emitters = SHComponentManager::GetDense(); - std::vector preResetBarriers{}; - preResetBarriers.resize(emitters.size()); - - uint32_t i = 0; - for (auto& emitter : emitters) - { - if (emitter.initialized) - { - // 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 drawDataHostWriteBarrier - { - .srcAccessMask = vk::AccessFlagBits::eIndirectCommandRead | vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite, - .dstAccessMask = vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eHostWrite, - .buffer = emitter.drawCallData->GetVkBuffer(), - .offset = emitter.dynamicOffsets[frameIndex][DYOFF_INDEX_DRAW_DATA], - .size = static_cast(sizeof(vk::DrawIndirectCommand)) - }; - - preResetBarriers[i] = drawDataHostWriteBarrier; - } - ++i; - } - - cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eDrawIndirect, vk::PipelineStageFlagBits::eHost, {}, {}, preResetBarriers, {}); - for (auto& emitter : emitters) { diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h index bb8f570d..ec7418cd 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h @@ -73,7 +73,7 @@ namespace SHADE //! Pipeline data for updating particles PipelineData defaultUpdatePipelineData; - //! Desc pool for particle component desc set allocation + //! Desc pool for particle component desc set allocation Handle descPool; @@ -82,7 +82,7 @@ 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, std::vector& preDrawBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) 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/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 6826efa7..b5f0ffdf 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -509,12 +509,11 @@ namespace YAML static constexpr std::string_view EMISSION_INTERVAL_TAG = "Emission Interval"; static constexpr std::string_view MIN_LIFE_TAG = "Min Life"; static constexpr std::string_view MAX_LIFE_TAG = "Max Life"; - static constexpr std::string_view ANGULAR_MIN_TAG = "Angular Min"; - static constexpr std::string_view ANGULAR_MAX_TAG = "Angular Max"; - static constexpr std::string_view MIN_VEL_TAG = "Minimum Velocity"; - static constexpr std::string_view MAX_VEL_TAG = "Maximum Velocity"; + static constexpr std::string_view ANGULAR_RANGES_OFFSET_TAG = "Angular Ranges And Offset"; static constexpr std::string_view MIN_SIZE_TAG = "Minimum Size"; static constexpr std::string_view MAX_SIZE_TAG = "Maximum Size"; + static constexpr std::string_view MIN_SPEED_TAG = "Minimum Speed"; + static constexpr std::string_view MAX_SPEED_TAG = "Maximum Speed"; static YAML::Node encode(SHParticleEmitterComponent const& rhs) { @@ -524,12 +523,11 @@ namespace YAML node[EMISSION_INTERVAL_TAG.data()] = rhs.GetEmissionInterval(); node[MIN_LIFE_TAG.data()] = rhs.GetMinLife(); node[MAX_LIFE_TAG.data()] = rhs.GetMaxLife(); - node[ANGULAR_MIN_TAG.data()] = rhs.GetAngularMin(); - node[ANGULAR_MAX_TAG.data()] = rhs.GetAngularMax(); - node[MIN_VEL_TAG.data()] = rhs.GetMinVelocity(); - node[MAX_VEL_TAG.data()] = rhs.GetMaxVelocity(); + node[MIN_SPEED_TAG.data()] = rhs.GetMinSpeed(); + node[MAX_SPEED_TAG.data()] = rhs.GetMaxSpeed(); node[MIN_SIZE_TAG.data()] = rhs.GetMinSize(); node[MAX_SIZE_TAG.data()] = rhs.GetMaxSize(); + node[ANGULAR_RANGES_OFFSET_TAG.data()] = rhs.GetAngularRangesAndOffsets(); return node; } @@ -550,20 +548,14 @@ namespace YAML if (node[MAX_LIFE_TAG.data()].IsDefined()) rhs.SetMaxLife(node[MAX_LIFE_TAG.data()].as()); - if (node[ANGULAR_MIN_TAG.data()].IsDefined()) - rhs.SetAngularMin(node[ANGULAR_MIN_TAG.data()].as()); + if (node[ANGULAR_RANGES_OFFSET_TAG.data()].IsDefined()) + rhs.SetAngularRangesAndOffsets(node[ANGULAR_RANGES_OFFSET_TAG.data()].as()); - if (node[ANGULAR_MAX_TAG.data()].IsDefined()) - rhs.SetAngularMax(node[ANGULAR_MAX_TAG.data()].as()); + if (node[MIN_SPEED_TAG.data()].IsDefined()) + rhs.SetMinSpeed(node[MIN_SPEED_TAG.data()].as()); - if (node[MIN_VEL_TAG.data()].IsDefined()) - rhs.SetMinVelocity(node[MIN_VEL_TAG.data()].as()); - - if (node[MAX_VEL_TAG.data()].IsDefined()) - rhs.SetMaxVelocity(node[MAX_VEL_TAG.data()].as()); - - if (node[MIN_SIZE_TAG.data()].IsDefined()) - rhs.SetMinSize(node[MIN_SIZE_TAG.data()].as()); + if (node[MAX_SPEED_TAG.data()].IsDefined()) + rhs.SetMaxSpeed (node[MAX_SPEED_TAG.data()].as()); if (node[MAX_SIZE_TAG.data()].IsDefined()) rhs.SetMaxSize(node[MAX_SIZE_TAG.data()].as()); From a08e5388954ef4273f24406cd48f12b0e8e0f940 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Thu, 16 Mar 2023 09:34:42 +0800 Subject: [PATCH 08/16] Added Texture support for particles --- Assets/Scenes/Scene2.shade | 8 +- Assets/Shaders/ParticleEmit_CS.glsl | 19 +++- Assets/Shaders/ParticleEmit_CS.shshaderb | Bin 9957 -> 10437 bytes Assets/Shaders/ParticleUpdate_CS.glsl | 2 +- Assets/Shaders/ParticleUpdate_CS.shshaderb | Bin 6541 -> 6565 bytes Assets/Shaders/Particle_FS.glsl | 15 ++- Assets/Shaders/Particle_FS.shshaderb | Bin 537 -> 1401 bytes Assets/Shaders/Particle_VS.glsl | 10 +- Assets/Shaders/Particle_VS.shshaderb | Bin 6357 -> 6585 bytes .../Inspector/SHEditorComponentView.hpp | 43 ++++++++ .../Particles/SHParticleEmitterComponent.cpp | 30 ++++++ .../Particles/SHParticleEmitterComponent.h | 16 ++- .../Particles/SHParticleSubSystem.cpp | 96 ++++++++++-------- .../src/Serialization/SHYAMLConverters.h | 20 ++++ 14 files changed, 205 insertions(+), 54 deletions(-) diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index 76595523..4b3d5118 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -157,15 +157,17 @@ Scale: {x: 1, y: 1, z: 1} IsActive: true classSHADE::SHParticleEmitterComponent: - Emission Count: 1 + Emission Count: 7 Is Passive: true - Emission Interval: 0.200000003 + Emission Interval: 0.0939999968 Min Life: 2 Max Life: 3 Minimum Speed: 3 Maximum Speed: 6 Minimum Size: 0 Maximum Size: 0.5 - Angular Ranges And Offset: {x: 0, y: 0, z: 0, w: 0} + Angular Ranges And Offset: {x: 0.699999988, y: 0.469999999, z: 0, w: 0} + Rotation Speed: 0 + Texture Asset ID: 63456868 IsActive: true Scripts: ~ \ No newline at end of file diff --git a/Assets/Shaders/ParticleEmit_CS.glsl b/Assets/Shaders/ParticleEmit_CS.glsl index 1e2a0882..c9e6cc8b 100644 --- a/Assets/Shaders/ParticleEmit_CS.glsl +++ b/Assets/Shaders/ParticleEmit_CS.glsl @@ -1,5 +1,7 @@ #version 450 +#define PI 3.14159265f + layout(local_size_x = 128) in; struct EmitterParameters @@ -7,14 +9,15 @@ struct EmitterParameters vec4 angularRangesAndOffsets; float minSpeed; float maxSpeed; - float padding[2]; + float rotationSpeed; + uint textureIndex; vec4 lifeAndSizeRange; // min life, max life, min size, max size }; struct ParticleData { vec4 position; - vec4 rotation; + vec4 orientationSpeedDecay; vec4 velocity; vec4 acceleration; vec4 scaleAndDecay; @@ -149,8 +152,18 @@ void main() particle.scaleAndDecay.x = particleSize; particle.scaleAndDecay.z = particleSize; - particle.rotation = vec4 (5.0f); + // Set the texture for the particle + particle.textureIndex = emitterParams.data.textureIndex; + + // Set orientation and rotation speed + if (emitterParams.data.rotationSpeed != 0.0f) + particle.orientationSpeedDecay = vec4 (rand(seed) * PI, emitterParams.data.rotationSpeed, 0.0f, 0.0f); + else + particle.orientationSpeedDecay = vec4 (0.0f); + + particle.acceleration = vec4 (0.01f); + inputParticles.data[index] = particle; } \ No newline at end of file diff --git a/Assets/Shaders/ParticleEmit_CS.shshaderb b/Assets/Shaders/ParticleEmit_CS.shshaderb index 125d56214d9838b6209164686b53572e48083b69..6f340a2754899af3f2b9aae9ffd0985b96894bd1 100644 GIT binary patch literal 10437 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 Pg6l_jUE1uW*k1k*2f#)` literal 9957 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 bANXBqJr_tP7q-h%u2(wa!p2;Jnak$@c})kQ diff --git a/Assets/Shaders/ParticleUpdate_CS.glsl b/Assets/Shaders/ParticleUpdate_CS.glsl index 56b0470c..762ff01a 100644 --- a/Assets/Shaders/ParticleUpdate_CS.glsl +++ b/Assets/Shaders/ParticleUpdate_CS.glsl @@ -13,7 +13,7 @@ struct DrawArraysIndirectArgs struct ParticleData { vec4 position; - vec4 rotation; + vec4 orientationSpeedDecay; vec4 velocity; vec4 acceleration; vec4 scaleAndDecay; diff --git a/Assets/Shaders/ParticleUpdate_CS.shshaderb b/Assets/Shaders/ParticleUpdate_CS.shshaderb index 8f0de701474344fe7efab5fe56b8a95f552c3305..d36fa560d123b200e78dbced03f98c10e3627961 100644 GIT binary patch delta 84 zcmeA*UTVywFlQr^Eu%aqgAfA)10xXU7iFgAl_ZvA=H~?$q^730q$Vd;P7Y!`2~;DB LPt9gMrg(7xt#cR8 delta 60 zcmZ2#+-uCF(6W)qmQk3EL5P8Yff0y{@=Fp+GV}8oCdVip` diff --git a/Assets/Shaders/Particle_FS.glsl b/Assets/Shaders/Particle_FS.glsl index d365b110..243baa2e 100644 --- a/Assets/Shaders/Particle_FS.glsl +++ b/Assets/Shaders/Particle_FS.glsl @@ -1,15 +1,26 @@ #version 460 core +#extension GL_EXT_nonuniform_qualifier : require layout (location = 0) out vec4 fragColor; +layout (set = 0, binding = 1) uniform sampler2D textures[]; // for textures (global) + // between shader stages layout(location = 0) in struct { vec2 uv; // location = 0 - } In; +// material stuff +layout(location = 1) flat in struct +{ + uint textureIndex; +} InFlat; + + void main () { - fragColor = vec4 (1.0f); + fragColor = vec4 (texture(textures [nonuniformEXT(InFlat.textureIndex)], In.uv)); + if (fragColor.a < 0.01f) + discard; } diff --git a/Assets/Shaders/Particle_FS.shshaderb b/Assets/Shaders/Particle_FS.shshaderb index 19e503b2eeedd6e8d92ec7b00034a41a3fd84484..edd2dd6b7d9b403787f621ed464e8e07afc8316e 100644 GIT binary patch literal 1401 zcmZ9LYikox5Qa~iO{}TCXm8fqcGGyT#)=mNFCbDwAka!g{kDW;Qx>+HxY?BYzf=VO zg5UiqiYWL#yJti2z+`6LxzB7C2St;xH%NhS-`8V;h znK7-yx8DByH(u8tcH&@=^kXlGy8dYp9hq5EO5^LzRQNGyJoTP#}GUmGi9mUm~Y3ZmRjiR8}kB_|%qjnhd0za0$jJ;kmsxn_-#r)Cyq|;IdL8sxzU-G zw<3K(+(psbQY`n#Fh}2aRuha^boN7CVwc2StM6J}t4bfWSFA11w{C6p#vU$7RC%$MBuy}yDAxMY681vG3Lwtu3L;b4^@F0H$>zl2Qm0O*CzP>u+cBO+!cYb rV`ie4+amC<@?oEMEykXID#tx>-f#J1+Y^DYW8^>T7#ZxZ delta 292 zcmXv}I|{-;6dZSBg7K4B1q*|qV4+xw5YSRQgEp3e+G(p-2v#;;%!_CtII~IKGVH#Y zdA!+g`1D3`Y~ae8VF1(+qK&wq(1js`d^b)4cqE0>{&1GwAfo)$&)>()a;PYup6Y$M z0(DqKls24MQ`1yhdeujdnc3bZeEDQUr`%Ul1Ux{q5&GOY!y#Sf3z=%KZvvvN&o-= diff --git a/Assets/Shaders/Particle_VS.glsl b/Assets/Shaders/Particle_VS.glsl index d74acdd9..211bb4de 100644 --- a/Assets/Shaders/Particle_VS.glsl +++ b/Assets/Shaders/Particle_VS.glsl @@ -19,7 +19,7 @@ struct GenericData struct ParticleData { vec4 position; - vec4 rotation; + vec4 orientationSpeedDecay; vec4 velocity; vec4 acceleration; vec4 scaleAndDecay; @@ -56,9 +56,14 @@ layout (std430, set = 2, binding = 4) coherent restrict buffer IndicesData layout(location = 0) out struct { vec2 uv; // location = 0 - } Out; +// material stuff +layout(location = 1) out struct +{ + uint textureIndex; // location = 1 +} OutFlat; + vec2 CreateQuad (in uint vertexID) { uint b = 1 << vertexID; @@ -90,6 +95,7 @@ void main() vec3 viewUp = normalize(vec3 (cameraData.viewMat[0][1], cameraData.viewMat[1][1], cameraData.viewMat[2][1])); particlePos = particle.position.xyz + (viewRight * particlePos.x * particleScaleData.x) + (viewUp * particlePos.y * particleScaleData.y); + OutFlat.textureIndex = particle.textureIndex; gl_Position = cameraData.vpMat * vec4(particlePos, 1.0f); } \ No newline at end of file diff --git a/Assets/Shaders/Particle_VS.shshaderb b/Assets/Shaders/Particle_VS.shshaderb index d79ee1d1cd5d1d3e5d7635143926837c84ac367b..492a926c869f280ed8059f362d67f99a3df754f2 100644 GIT binary patch delta 1161 zcmaKrOKTHh6o$V^GD%x62x5yw1@zmxhlz zsfpvLT#t-OP!5a1LmOvgx|NAoJ6{T_`Jf(pcH|_?{qyJt%r z<}*O%O7FD(y3Z4hLT~k)XhvL=$a2`W*bO*zxZym;!zG1&EoZotP>@1D^3dDz*ktS) z1CpkY6!jA+f*Tp)Xb!i%$MtuE!x#uhEz5P}4+~g7J`{&$w`tW!)2T*IHM}Qj;h<{X z$}44voIPpzvSrw#}ML9E4OoHq@i!lycbRjzAz)17E1#BS^Yumwj!|a zQQ?%@6O)6!F8@h*ChQXE!F4|i@WfN{UxdfPRn>6auf{aGq|O8Ko6aOUL)`Zs#}2c4 nQQ7^6pazC~^sLZSW3&x{;pA{Zp4m@O zv)))-y>cd%Xkem18RSdxyRfsW!e8_vn!Y};?B#y=fVjjR3FSEvS@J`fC7c}->OtNg zI~?h-|FiH`7#9{L<8>&&Q_m=W5#9)o_0D*Gb)3>U*LNK6?fbqt4*NCz6*%{iz`XkB j4GmSHtHp@N0_I1;LvdXAyTGH|6_#{2>f?N8YB~4^7Kex3 diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 0e1f4fd4..a46d76c4 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -811,6 +811,8 @@ namespace SHADE if (!component) return; + auto gfxSystem = SHSystemManager::GetSystem(); + ImGui::PushID(SHFamilyID::GetID()); const auto componentType = rttr::type::get(*component); @@ -860,6 +862,47 @@ namespace SHADE comp->SetMaxSpeed(val); }); + SHEditorWidgets::DragFloat("Rotation Speed", + [comp = component]() + { + return comp->GetMaxSpeed(); + }, + [comp = component](float val) + { + comp->SetMaxSpeed(val); + }); + + SHEditorWidgets::DragInt("Texture Index", + [comp = component]() + { + return comp->GetTextureAssetID(); + }, + [comp = component](AssetID val) + { + comp->SetTextureAssetID(val); + }); + if (SHDragDrop::BeginTarget()) + { + if (AssetID* payload = SHDragDrop::AcceptPayload(SHDragDrop::DRAG_RESOURCE)) + { + Handle texture = SHResourceManager::LoadOrGet(*payload); + gfxSystem->BuildTextures(); + + if (texture) + { + component->SetTextureIndex(texture->TextureArrayIndex); + component->SetTextureAssetID(*payload); + } + else + { + SHLOG_WARNING("[] Attempted to load invalid texture! Texture for particle not set. "); + } + + SHDragDrop::EndTarget(); + } + } + + SHEditorWidgets::CheckBox("Is Passive", [comp = component]() {return comp->GetPassive(); }, [comp = component](bool flag) {comp->SetPassive(flag); }); } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp index b095f26b..2427ade9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp @@ -62,6 +62,21 @@ namespace SHADE cpuEmitterData.maxSpeed = speed; } + void SHParticleEmitterComponent::SetRotationSpeed(float speed) noexcept + { + cpuEmitterData.rotationSpeed = speed; + } + + void SHParticleEmitterComponent::SetTextureIndex(uint32_t index) noexcept + { + cpuEmitterData.textureIndex = index; + } + + void SHParticleEmitterComponent::SetTextureAssetID(AssetID id) + { + textureAssetID = id; + } + void SHParticleEmitterComponent::SetMinSize(float size) noexcept { cpuEmitterData.lifeAndSizeRange.z = size; @@ -113,6 +128,21 @@ namespace SHADE return cpuEmitterData.maxSpeed; } + float SHParticleEmitterComponent::GetRotationSpeed(void) const noexcept + { + return cpuEmitterData.rotationSpeed; + } + + uint32_t SHParticleEmitterComponent::GetTextureIndex(void) const noexcept + { + return cpuEmitterData.textureIndex; + } + + AssetID SHParticleEmitterComponent::GetTextureAssetID(void) const noexcept + { + return textureAssetID; + } + float SHParticleEmitterComponent::GetMinSize(void) const noexcept { return cpuEmitterData.lifeAndSizeRange.z; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h index e345c24d..dea510f2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h @@ -4,6 +4,7 @@ #include "Math/Vector/SHVec4.h" #include "ECS_Base/Components/SHComponent.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" +#include namespace SHADE { @@ -25,7 +26,11 @@ namespace SHADE //! Maximum starting velocity float maxSpeed; - float padding[2]; + //! Rotational speed of the quad + float rotationSpeed; + + //! Texture used by the particle + uint32_t textureIndex; //! Spawn lifetime and size range (min and max) SHVec4 lifeAndSizeRange; @@ -104,6 +109,9 @@ namespace SHADE //! For all the dynamic SSBOs in the descriptor set std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> dynamicOffsets{}; + //! For the emitter to use to give particles their texture + AssetID textureAssetID; + public: void OnCreate(void) override final; void OnDestroy(void) override final; @@ -118,6 +126,9 @@ namespace SHADE void SetAngularRangesAndOffsets (SHVec4 const& ranges) noexcept; void SetMinSpeed (float speed) noexcept; void SetMaxSpeed (float speed) noexcept; + void SetRotationSpeed (float speed) noexcept; + void SetTextureIndex (uint32_t index) noexcept; + void SetTextureAssetID (AssetID id); void SetMinSize (float size) noexcept; void SetMaxSize (float size) noexcept; @@ -130,6 +141,9 @@ namespace SHADE SHVec4 const& GetAngularRangesAndOffsets (void) const noexcept; float GetMinSpeed (void) const noexcept; float GetMaxSpeed (void) const noexcept; + float GetRotationSpeed (void) const noexcept; + uint32_t GetTextureIndex (void) const noexcept; + AssetID GetTextureAssetID (void) const noexcept; float GetMinSize (void) const noexcept; float GetMaxSize (void) const noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp index 665f43aa..bd08b48f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp @@ -200,9 +200,9 @@ namespace SHADE }; // ...copy assign barriers on heap - preUpdateBarriers[EMITTER_INDEX * 3] = inputParticleDataBarrierPreUpdate; - preUpdateBarriers[(EMITTER_INDEX * 3) + 1] = freelistDataBarrierPreUpdate; - preUpdateBarriers[(EMITTER_INDEX * 3) + 2] = indicesDataBarrierPreUpdate; + preUpdateBarriers.push_back(inputParticleDataBarrierPreUpdate); + preUpdateBarriers.push_back(freelistDataBarrierPreUpdate); + preUpdateBarriers.push_back(indicesDataBarrierPreUpdate); // make new barrier on stack... vk::BufferMemoryBarrier outputParticleDataBarrierPostUpdate @@ -235,9 +235,9 @@ namespace SHADE }; // ...copy assign barriers on heap - postUpdateBarriers[EMITTER_INDEX * 3] = outputParticleDataBarrierPostUpdate; - postUpdateBarriers[(EMITTER_INDEX * 3) + 1] = indicesDataBarrierPostUpdate; - postUpdateBarriers[(EMITTER_INDEX * 3) + 2] = drawDataBarrierPostUpdate; + postUpdateBarriers.push_back(outputParticleDataBarrierPostUpdate); + postUpdateBarriers.push_back(indicesDataBarrierPostUpdate); + postUpdateBarriers.push_back(drawDataBarrierPostUpdate); } void SHParticleSubSystem::Init(Handle device, Handle inDescPool, Handle compatibleRenderpass, Handle subpass, Handle VS, Handle FS, Handle emitCS, Handle defaultUpdateCS) noexcept @@ -334,15 +334,15 @@ namespace SHADE // 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() * 3); + preUpdateBarriers.reserve(emitters.size() * 3); // 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() * 3); + postUpdateBarriers.reserve(emitters.size() * 3); std::vector preDrawBarriers{}; - preDrawBarriers.resize(emitters.size()); + preDrawBarriers.reserve(emitters.size()); // If we wanted to be VERY safe, a barrier would be good here to make sure output particles have finish reading input particles in @@ -365,45 +365,51 @@ namespace SHADE for (auto& emitter : emitters) { - if (!emitter.initialized) - InitializeComponent(emitter); - - // Set emitter emit flag to true here if there are ready to be emitted - if (emitter.isPassive) + if (emitter.isActive) { - // decrement emission timer - emitter.timeBeforeEmission -= dt; + if (!emitter.initialized) + InitializeComponent(emitter); - // Check if time to emit - if (emitter.timeBeforeEmission <= 0.0f) + // Set emitter emit flag to true here if there are ready to be emitted + if (emitter.isPassive) { - // reset timer - emitter.timeBeforeEmission = emitter.emissionInterval; + // decrement emission timer + emitter.timeBeforeEmission -= dt; - // Emit later - emitter.toEmit = true; + // Check if time to emit + if (emitter.timeBeforeEmission <= 0.0f) + { + // reset timer + emitter.timeBeforeEmission = emitter.emissionInterval; + + // Emit later + emitter.toEmit = true; + } } + + if (emitter.toEmit) // take note that if emitter is not passive, this can also be set to true outside of this function + { + // Copy data to host visible buffer of emitter + emitter.emitterData->WriteToMemory (&emitter.cpuEmitterData, sizeof (SHParticleEmitterComponent::GPUEmitterStruct), 0, emitterDataOffset); + + // Call emit function here + EmitComponent(cmdBuffer, emitter, frameIndex); + } + + // 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; } - if (emitter.toEmit) // take note that if emitter is not passive, this can also be set to true outside of this function - { - // Copy data to host visible buffer of emitter - emitter.emitterData->WriteToMemory (&emitter.cpuEmitterData, sizeof (SHParticleEmitterComponent::GPUEmitterStruct), 0, emitterDataOffset); - - // Call emit function here - EmitComponent(cmdBuffer, emitter, frameIndex); - } - - // 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; } + // issue the barrier to wait - cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eDrawIndirect, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {}); + if (!preUpdateBarriers.empty()) + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eDrawIndirect, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {}); @@ -417,14 +423,17 @@ namespace SHADE for (auto& emitter : emitters) { - UpdateCompoennt(cmdBuffer, emitter, frameIndex); + if (emitter.isActive) + 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::eVertexShader | vk::PipelineStageFlagBits::eDrawIndirect | vk::PipelineStageFlagBits::eVertexShader, {}, {}, postUpdateBarriers, {}); + if (!postUpdateBarriers.empty()) + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eDrawIndirect | vk::PipelineStageFlagBits::eVertexShader, {}, {}, postUpdateBarriers, {}); } @@ -457,10 +466,13 @@ namespace SHADE // TODO: Issue barrier for output particle data. Semaphore should also be issued outside in SHGraphicsSystem for (auto& emitter : emitters) { - // bind the descriptor sets required for emitting particles - cmdBuffer->BindDescriptorSet(emitter.particleDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), emitter.dynamicOffsets[frameIndex]); + if (emitter.isActive) + { + // bind the descriptor sets required for emitting particles + cmdBuffer->BindDescriptorSet(emitter.particleDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), emitter.dynamicOffsets[frameIndex]); - RenderComponent(cmdBuffer, emitter, frameIndex); + RenderComponent(cmdBuffer, emitter, frameIndex); + } } } diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index b5f0ffdf..daf3d4ca 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -514,6 +514,8 @@ namespace YAML static constexpr std::string_view MAX_SIZE_TAG = "Maximum Size"; static constexpr std::string_view MIN_SPEED_TAG = "Minimum Speed"; static constexpr std::string_view MAX_SPEED_TAG = "Maximum Speed"; + static constexpr std::string_view ROTATION_SPEED_TAG = "Rotation Speed"; + static constexpr std::string_view TEXTURE_ASSET_ID_TAG = "Texture Asset ID"; static YAML::Node encode(SHParticleEmitterComponent const& rhs) { @@ -528,11 +530,15 @@ namespace YAML node[MIN_SIZE_TAG.data()] = rhs.GetMinSize(); node[MAX_SIZE_TAG.data()] = rhs.GetMaxSize(); node[ANGULAR_RANGES_OFFSET_TAG.data()] = rhs.GetAngularRangesAndOffsets(); + node[ROTATION_SPEED_TAG.data()] = rhs.GetRotationSpeed(); + node[TEXTURE_ASSET_ID_TAG.data()] = rhs.GetTextureAssetID(); return node; } static bool decode(YAML::Node const& node, SHParticleEmitterComponent& rhs) { + auto gfxSystem = SHSystemManager::GetSystem(); + if (node[EMISSION_COUNT_TAG.data()].IsDefined()) rhs.SetEmissionCount(node[EMISSION_COUNT_TAG.data()].as()); @@ -560,6 +566,20 @@ namespace YAML if (node[MAX_SIZE_TAG.data()].IsDefined()) rhs.SetMaxSize(node[MAX_SIZE_TAG.data()].as()); + if (node[ROTATION_SPEED_TAG.data()].IsDefined()) + rhs.SetRotationSpeed(node[ROTATION_SPEED_TAG.data()].as()); + + if (node[TEXTURE_ASSET_ID_TAG.data()].IsDefined()) + { + AssetID id = node[TEXTURE_ASSET_ID_TAG.data()].as(); + + Handle texture = SHResourceManager::LoadOrGet(id); + gfxSystem->BuildTextures(); + + rhs.SetTextureIndex(texture->TextureArrayIndex); + rhs.SetTextureAssetID(id); + } + return true; } }; From 2eed7428d8472f1343ed5ebdba35a2804d848e09 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Thu, 16 Mar 2023 10:44:03 +0800 Subject: [PATCH 09/16] Fixed emitting angles for particles --- Assets/Scenes/Scene2.shade | 2 +- Assets/Shaders/ParticleEmit_CS.glsl | 23 +++++++++++++++--- Assets/Shaders/ParticleEmit_CS.shshaderb | Bin 10437 -> 11661 bytes Assets/Shaders/ParticleUpdate_CS.glsl | 1 + Assets/Shaders/ParticleUpdate_CS.shshaderb | Bin 6565 -> 6689 bytes .../Inspector/SHEditorComponentView.hpp | 2 +- 6 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index 4b3d5118..564c78c4 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -166,7 +166,7 @@ Maximum Speed: 6 Minimum Size: 0 Maximum Size: 0.5 - Angular Ranges And Offset: {x: 0.699999988, y: 0.469999999, z: 0, w: 0} + Angular Ranges And Offset: {x: 6.19999981, y: 1.10000002, z: 0, w: 0.100000001} Rotation Speed: 0 Texture Asset ID: 63456868 IsActive: true diff --git a/Assets/Shaders/ParticleEmit_CS.glsl b/Assets/Shaders/ParticleEmit_CS.glsl index c9e6cc8b..444af6db 100644 --- a/Assets/Shaders/ParticleEmit_CS.glsl +++ b/Assets/Shaders/ParticleEmit_CS.glsl @@ -137,9 +137,24 @@ void main() rand(seed) * angularRangesAndOffsets.y + angularRangesAndOffsets.w); // Set its velocity - particle.velocity.xyz = vec3 (cos(eulerAngles.x) * cos(eulerAngles.y), - sin(eulerAngles.x) * cos(eulerAngles.y), - sin(eulerAngles.y)); + // particle.velocity.xyz = vec3 (cos(eulerAngles.x) * cos(eulerAngles.y), + // sin(eulerAngles.x) * cos(eulerAngles.y), + // sin(eulerAngles.y)); + + float bank = eulerAngles.y; + float cb = cos(bank); + float sb = sin(bank); + float ch = cos (eulerAngles.x); + float sh = sin (eulerAngles.x); + float cp = cos (0.0f); + float sp = sin (0.0f); + + particle.velocity.xyz = mat3 ( + (ch * cb + sh * sp * sb), (sb * cp), (-sh * cb + ch * sp * sb), + (-ch * sb + sh * sp * cb), (cb * cp), ( sb * sh + ch * sp * cb), + (sh * cp), (-sp), (ch * cp) + ) * vec3 (1.0f, 0.0f, 0.0f); + particle.velocity *= map (rand (seed), 0.0f, 1.0f, minSpeed.x, maxSpeed.x); @@ -162,7 +177,7 @@ void main() particle.orientationSpeedDecay = vec4 (0.0f); - particle.acceleration = vec4 (0.01f); + particle.acceleration = vec4 (0.0f, -0.058f, 0.0f, 0.0f); inputParticles.data[index] = particle; diff --git a/Assets/Shaders/ParticleEmit_CS.shshaderb b/Assets/Shaders/ParticleEmit_CS.shshaderb index 6f340a2754899af3f2b9aae9ffd0985b96894bd1..f0d782403695ba43b8271f8a3103ba6fa2c4ac7b 100644 GIT binary patch literal 11661 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 Y&a$4(VEfXyv($#c&P$(bDR(XZ4@-RRB>(^b delta 3708 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 N#JyG5&pY%W_#b0#hU@?U literal 6565 zcmai$`*&1V6~`}0CZPpdO6kK|Fgz4(3sR-ET3VA32xux)(E4mT%-p~&lbLa55R_nXIU$xdp{mJEz{yF~c^0Ag{`T5*?cXFFWmxr}Edwc2MBz-A+G~P~bP@{_dyK%hL8Bk9D$}rp@WJQNIWtT=%+^ zwmOY$APhd1bM0Wg(MVfqFDF;m+)KYvZ>5v%O1xUmv)8R`p02FM8bu$Z7Y2*H^jNuN z_FPN0f_KY3>0cxJZOqr(r?_M7KE?mvKJ~fYKE>Z?pRT>pK3!Y8PqFLobA56LYq6*P zv37THFts>8pZ0*^)be%pW_hmm!Rw#txAPm@?MHL zUjJRz5^?vt)P1a8^u55`r*}-$^VZLOc6*(t#XN^UU^gmx-18s74liVbLE1a9*gt!y zllR0J#Tv^=TCT@a7;E{ru#olpypM4YjQLuHQ;j*pH?@H^x5D3P0Z$v55-iyCQa?g88n9okFbbc4o1skfYeXFAnFbed`+g&fH#o zZ;a`f;RNIk=lV$g_UuG=ALjEd+JU%NYmfIP_<=<)+*e@H3xDqdGmqSjB{sqAh(RCzhj#IXt@b0{kmyI)ML$;Gm})+Ktjl=kn9Vm-vCS9u7trm0vCol} zcP8>Jv*w6=%el3>KhH?aepNZzRgShbn#Z0jGe?b=(5p3STchjt+4sXC-w{|fW?=41 zzc?eg#t|#dXe57gFjwlms=f2MTSKE5M@2o+o+L;T^=w*O-HV$0izIP~Ad?3(!PWVYYqh_U^f zUE8zVPQ)$DVrxa8qRx^0o?4&2a(vI%`bS(j+sNrVtKW8X@1eG}`HtELG54bFJ&NAk zg+7j0zkAbuGvbiHjk)kG>>b$FX8!Qsjb7#N!Il&2_n_O`u=k?dkFfWndymX_KeO@e zN30(}cc0qg4a(wr}~?iY&5h}AG(~qh#YPGLgNXl?7`{L6D>2`te-h&$v*SPbyY?_5=KWHSJwAeNY

J&-T$= z*Jm_;kEXGw5YJVK8V;koc8wb39YN%ZNBkLd;|EW_qlox(CGS{?$q(KK(1T}BwDpUc zK8Sw3nr6XWGmhu+7_zo^A1d+7_}I(ih?v~qoj?zs`L*?n^~Wpg(T@* z%rkkJ-in<<#66>rGCMpY@sA*4o{_qHbq`M<*5W)u8CsE^n@V%>g|EyVXw zdkgadBF7lpnA^xX#2EU<`_Vzy*I_+f=FcGd>uWA;{esg&mlN-yoIWCFHzG${zu*ke z3|e!*EnmlN-ydCntp;yu*XFE|&_<%}Sa=OVhCy@+|V^^>!i`Ll?e z8Y1Tq^XCvb`w=* z+1kH2(=VfYrq8e&eZPW;d8WquDq=i2#xbXue*fikyk|{x{jKjC$Th_La;(AnpGRDa z8k~)FrCf`8zKtyw_IJ>&FXDd}{YAw1`Wiz_KfmjP%+}-_F}{ax3~lf2_mQng+}j_Z z$Gz1z&iRMv`a0sAUqaX4{N~oyFE~F!ms7pBKgO10KjdiZ7o4A<%c-oA`3C+@Abe%_&nkpBV5ICypd diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index a46d76c4..4e150e10 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -831,7 +831,7 @@ namespace SHADE SHEditorWidgets::DragFloat("Min Size", [comp = component]() {return comp->GetMinSize(); }, [comp = component](float val) {comp->SetMinSize(val); }); SHEditorWidgets::DragFloat("Max Size", [comp = component]() {return comp->GetMaxSize(); }, [comp = component](float val) {comp->SetMaxSize(val); }); - SHEditorWidgets::DragVec4("Angles and Offsets", {"yaw", "pitch", "yaw off", "pitch off"}, + SHEditorWidgets::DragVec4("Angles and Offsets", {"yaw", "bank", "yaw off", "bank off"}, [comp = component]() { return comp->GetAngularRangesAndOffsets(); From f787f2b7824c9d7fecd64243c741abe9a6f50800 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Sun, 19 Mar 2023 20:11:29 +0800 Subject: [PATCH 10/16] particles WIP --- Assets/Scenes/Scene2.shade | 4 +- .../Particles/SHParticleEmitterComponent.cpp | 10 ++++ .../Particles/SHParticleEmitterComponent.h | 38 ++++++++++----- .../Particles/SHParticleSubSystem.cpp | 47 +++++++++++++++++-- .../MiddleEnd/Particles/SHParticleSubSystem.h | 10 ++++ .../src/Serialization/SHYAMLConverters.h | 5 +- 6 files changed, 92 insertions(+), 22 deletions(-) diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index 564c78c4..e14f32cb 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -152,8 +152,8 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 0, z: 0} - Rotate: {x: 0, y: 0, z: 0} + Translate: {x: 0, y: 0.823412895, z: -4.31447983} + Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true classSHADE::SHParticleEmitterComponent: diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp index 2427ade9..9541a47b 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp @@ -87,6 +87,11 @@ namespace SHADE cpuEmitterData.lifeAndSizeRange.w = size; } + void SHParticleEmitterComponent::SetCustomShader(Handle shaderModule) noexcept + { + customUpdateShader = shaderModule; + } + uint32_t SHParticleEmitterComponent::GetEmissionCount(void) const noexcept { return emissionCount; @@ -154,4 +159,9 @@ namespace SHADE } + Handle SHParticleEmitterComponent::GetCustomShader(void) const noexcept + { + return customUpdateShader; + } + } \ 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 dea510f2..d99f8403 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h @@ -11,10 +11,13 @@ namespace SHADE class SHVkBuffer; class SHVkDescriptorSetGroup; class SHVkDescriptorSetLayout; + class SHVkShaderModule; + class SHVkPipeline; class SHParticleEmitterComponent : public SHComponent { private: + struct GPUEmitterStruct { //! Angular ranges of emission @@ -94,6 +97,12 @@ namespace SHADE //! will contain 2 bindings that point to 2 buffers (input and output). Handle particleDescriptorSet; + //! Custom update shader for the particles in this component + Handle customUpdateShader; + + //! Internally the system will bind this pipeline when it detects that this is not a null handle + Handle customUpdatePipeline; + //! Emitter's data on the CPU side. To be copied to GPU. GPUEmitterStruct cpuEmitterData; @@ -131,21 +140,24 @@ namespace SHADE void SetTextureAssetID (AssetID id); void SetMinSize (float size) noexcept; void SetMaxSize (float size) noexcept; + void SetCustomShader (Handle shaderModule) noexcept; - uint32_t GetEmissionCount (void) const noexcept; - bool GetPassive (void) const noexcept; - float GetEmissionInterval (void) const noexcept; - float GetMinLife (void) const noexcept; - float GetMaxLife (void) const noexcept; - SHVec4 const& GetAngularRangesAndOffsets (void) const noexcept; - float GetMinSpeed (void) const noexcept; - float GetMaxSpeed (void) const noexcept; - float GetRotationSpeed (void) const noexcept; - uint32_t GetTextureIndex (void) const noexcept; - AssetID GetTextureAssetID (void) const noexcept; - float GetMinSize (void) const noexcept; - float GetMaxSize (void) const noexcept; + uint32_t GetEmissionCount (void) const noexcept; + bool GetPassive (void) const noexcept; + float GetEmissionInterval (void) const noexcept; + float GetMinLife (void) const noexcept; + float GetMaxLife (void) const noexcept; + SHVec4 const& GetAngularRangesAndOffsets (void) const noexcept; + float GetMinSpeed (void) const noexcept; + float GetMaxSpeed (void) const noexcept; + float GetRotationSpeed (void) const noexcept; + uint32_t GetTextureIndex (void) const noexcept; + AssetID GetTextureAssetID (void) const noexcept; + float GetMinSize (void) const noexcept; + float GetMaxSize (void) const noexcept; + Handle GetCustomShader (void) const 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 bd08b48f..05295fd0 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp @@ -240,6 +240,34 @@ namespace SHADE postUpdateBarriers.push_back(drawDataBarrierPostUpdate); } + Handle SHParticleSubSystem::GetCustomUpdatePipeline(Handle customUpdateShader) noexcept + { + if (!customUpdateShader) + return {}; + + if (!customUpdatePipelineCache.contains(customUpdateShader)) + { + SHPipelineLayoutParams plParams + { + .shaderModules = {customUpdateShader}, + .predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING).descSetLayouts + }; + + auto pipelineLayout = logicalDevice->CreatePipelineLayout(plParams); + auto newPipeline = logicalDevice->CreateComputePipeline(pipelineLayout); + newPipeline->ConstructPipeline(); + + if (!newPipeline) + return {}; + + auto customUpdateShaderData = CustomPipeline{ newPipeline, pipelineLayout }; + + customUpdatePipelineCache.emplace (customUpdateShader, customUpdateShaderData); + } + + return customUpdatePipelineCache.at (customUpdateShader).customPipeline; + } + void SHParticleSubSystem::Init(Handle device, Handle inDescPool, Handle compatibleRenderpass, Handle subpass, Handle VS, Handle FS, Handle emitCS, Handle defaultUpdateCS) noexcept { descPool = inDescPool; @@ -416,13 +444,22 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* EMITTING PARTICLES DONE, BEGIN UPDATES.... */ /*-----------------------------------------------------------------------*/ - - - // bind the pipeline for updating - cmdBuffer->BindPipeline(defaultUpdatePipelineData.pipeline); - for (auto& emitter : emitters) { + if (emitter.customUpdateShader) + { + if (!emitter.customUpdatePipeline) + emitter.customUpdatePipeline = GetCustomUpdatePipeline(emitter.customUpdateShader); + + // bind the custom pipeline for updating + cmdBuffer->BindPipeline(emitter.customUpdatePipeline); + } + else + { + // bind the pipeline for updating + cmdBuffer->BindPipeline(defaultUpdatePipelineData.pipeline); + } + if (emitter.isActive) UpdateCompoennt(cmdBuffer, emitter, frameIndex); } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h index ec7418cd..a0675da6 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h @@ -34,6 +34,12 @@ namespace SHADE static constexpr uint32_t DYOFF_INDEX_INDICES_DATA = 3; static constexpr uint32_t DYOFF_INDEX_DRAW_DATA = 4; + struct CustomPipeline + { + Handle customPipeline; + Handle customPipelineLayout; + }; + // To hold data for a pipeline and pipeline layout. // We want this here because particles require 3 pipeline sets: @@ -76,6 +82,8 @@ namespace SHADE //! Desc pool for particle component desc set allocation Handle descPool; + std::unordered_map, CustomPipeline> customUpdatePipelineCache; + void InitializeComponent (SHParticleEmitterComponent& comp) noexcept; void EmitComponent (Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept; @@ -84,6 +92,8 @@ namespace SHADE void PreparePrePostUpdateBarriers (std::vector& preUpdateBarriers, std::vector& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept; + Handle GetCustomUpdatePipeline (Handle customUpdateShader) 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/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index daf3d4ca..0a879146 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -574,12 +574,13 @@ namespace YAML AssetID id = node[TEXTURE_ASSET_ID_TAG.data()].as(); Handle texture = SHResourceManager::LoadOrGet(id); - gfxSystem->BuildTextures(); + SHResourceManager::FinaliseChanges(); + //gfxSystem->BuildTextures(); rhs.SetTextureIndex(texture->TextureArrayIndex); rhs.SetTextureAssetID(id); } - + return true; } }; From 6a1ae5fac8b34750eed4bf9335abd66227219b14 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 20 Mar 2023 00:37:46 +0800 Subject: [PATCH 11/16] SSAO shader looks better on racoon now It still looks a little off but its better than before --- Assets/Shaders/SSAO_CS.glsl | 2 +- Assets/Shaders/SSAO_CS.shshaderb | Bin 6141 -> 6141 bytes .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 8 ++--- .../MiddleEnd/PostProcessing/SHSSAO.cpp | 33 +++++++++--------- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Assets/Shaders/SSAO_CS.glsl b/Assets/Shaders/SSAO_CS.glsl index 42ab220c..7e818141 100644 --- a/Assets/Shaders/SSAO_CS.glsl +++ b/Assets/Shaders/SSAO_CS.glsl @@ -8,7 +8,7 @@ const int ROTATION_KERNEL_W = 4; const int ROTATION_KERNEL_H = 4; // can perhaps pass in as push constant. -const float RADIUS = 0.2f; +const float RADIUS = 0.35f; const float BIAS = 0.0025f; layout(local_size_x = 16, local_size_y = 16) in; diff --git a/Assets/Shaders/SSAO_CS.shshaderb b/Assets/Shaders/SSAO_CS.shshaderb index 36e627d6a0b8e6d8cca6f1d3a8ad43f81b987952..06438d5813d4d91106485135a01770dc3da1d9f3 100644 GIT binary patch delta 16 YcmeyX|5ty*UUp_<(VS_DEFAULT); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/PostProcessing/SHSSAO.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/PostProcessing/SHSSAO.cpp index db5b08c3..f71c3f93 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/PostProcessing/SHSSAO.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/PostProcessing/SHSSAO.cpp @@ -19,15 +19,16 @@ namespace SHADE // generate samples for (uint32_t i = 0; i < NUM_SAMPLES; ++i) { - //SHVec3 temp - //{ - // distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f - // distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f - // distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere - //}; + SHVec3 temp + { + distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f + distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f + distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere + }; - //temp = SHVec3::Normalise(temp); - //temp *= distrib(generator); + temp = SHVec3::Normalise(temp); + temp *= distrib(generator); + samples[i] = SHVec4 (temp.x, temp.y, temp.z, 0.0f); //// This makes sure that most points are closer to fragment's position //float scale = 1.0f / static_cast(NUM_SAMPLES); @@ -36,16 +37,16 @@ namespace SHADE //samples[i] = SHVec4 (temp.x, temp.y, temp.z, 0.0f); - samples[i] = SHVec4 - { - distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f - distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f - distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere - 0.0f - }; + //samples[i] = SHVec4 + //{ + // distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f + // distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f + // distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere + // 0.0f + //}; // This makes sure that most points are closer to fragment's position - float scale = 1.0f / static_cast(NUM_SAMPLES); + float scale = static_cast(i) / static_cast(NUM_SAMPLES); scale = std::lerp(0.1f, 1.0f, scale * scale); samples[i] *= scale; } From 565126c4bacbe5404aaf9bb0befdf60f2eafad32 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 20 Mar 2023 09:33:04 +0800 Subject: [PATCH 12/16] Enabled custom update shaders for particles --- .../Inspector/SHEditorComponentView.hpp | 45 ++++++++++++++++++- .../Particles/SHParticleEmitterComponent.cpp | 16 +++++-- .../Particles/SHParticleEmitterComponent.h | 19 +++++--- .../Particles/SHParticleSubSystem.cpp | 4 +- .../src/Serialization/SHYAMLConverters.h | 14 ++++++ 5 files changed, 88 insertions(+), 10 deletions(-) diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 4e150e10..4aa03a4b 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -886,7 +886,7 @@ namespace SHADE if (AssetID* payload = SHDragDrop::AcceptPayload(SHDragDrop::DRAG_RESOURCE)) { Handle texture = SHResourceManager::LoadOrGet(*payload); - gfxSystem->BuildTextures(); + gfxSystem->BuildTextures(); if (texture) { @@ -901,6 +901,49 @@ namespace SHADE SHDragDrop::EndTarget(); } } + SHEditorWidgets::InputText("Custom Update Shader", + [comp = component]() + { + auto customShader = comp->GetCustomUpdateShader(); + + if (customShader) + return customShader->GetName(); + else + return std::string{}; + + }, + [comp = component](std::string const& text) + { + }, {}, ImGuiSliderFlags_ReadOnly); + + if (SHDragDrop::BeginTarget()) + { + if (AssetID* payload = SHDragDrop::AcceptPayload(SHDragDrop::DRAG_RESOURCE)) + { + Handle shaderModule = SHResourceManager::LoadOrGet(*payload); + + if (shaderModule) + { + component->SetCustomUpdateShader(shaderModule); + component->SetCustomUpdateShaderAssetID(*payload); + } + else + { + SHLOG_WARNING("[] Attempted to load invalid shader! Custom update shader for particles not set. "); + } + + SHDragDrop::EndTarget(); + } + } + ImGui::SameLine(); + if (ImGui::Button("Reset")) + { + component->SetCustomUpdateShader({}); + component->SetCustomUpdateShaderAssetID(INVALID_ASSET_ID); + + } + + SHEditorWidgets::CheckBox("Is Passive", [comp = component]() {return comp->GetPassive(); }, [comp = component](bool flag) {comp->SetPassive(flag); }); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp index 9541a47b..8293604c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp @@ -72,11 +72,16 @@ namespace SHADE cpuEmitterData.textureIndex = index; } - void SHParticleEmitterComponent::SetTextureAssetID(AssetID id) + void SHParticleEmitterComponent::SetTextureAssetID(AssetID id) noexcept { textureAssetID = id; } + void SHParticleEmitterComponent::SetCustomUpdateShaderAssetID(AssetID id) noexcept + { + customUpdateShaderID = id; + } + void SHParticleEmitterComponent::SetMinSize(float size) noexcept { cpuEmitterData.lifeAndSizeRange.z = size; @@ -87,7 +92,7 @@ namespace SHADE cpuEmitterData.lifeAndSizeRange.w = size; } - void SHParticleEmitterComponent::SetCustomShader(Handle shaderModule) noexcept + void SHParticleEmitterComponent::SetCustomUpdateShader(Handle shaderModule) noexcept { customUpdateShader = shaderModule; } @@ -148,6 +153,11 @@ namespace SHADE return textureAssetID; } + AssetID SHParticleEmitterComponent::GetCustomUpdateShaderAssetID(void) const noexcept + { + return customUpdateShaderID; + } + float SHParticleEmitterComponent::GetMinSize(void) const noexcept { return cpuEmitterData.lifeAndSizeRange.z; @@ -159,7 +169,7 @@ namespace SHADE } - Handle SHParticleEmitterComponent::GetCustomShader(void) const noexcept + Handle SHParticleEmitterComponent::GetCustomUpdateShader(void) const noexcept { return customUpdateShader; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h index d99f8403..616410cd 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h @@ -121,6 +121,9 @@ namespace SHADE //! For the emitter to use to give particles their texture AssetID textureAssetID; + //! Custom update shaders, similarly with textures, will be identified through their AssetID + AssetID customUpdateShaderID; + public: void OnCreate(void) override final; void OnDestroy(void) override final; @@ -137,11 +140,9 @@ namespace SHADE void SetMaxSpeed (float speed) noexcept; void SetRotationSpeed (float speed) noexcept; void SetTextureIndex (uint32_t index) noexcept; - void SetTextureAssetID (AssetID id); void SetMinSize (float size) noexcept; void SetMaxSize (float size) noexcept; - void SetCustomShader (Handle shaderModule) noexcept; - + void SetCustomUpdateShader (Handle shaderModule) noexcept; uint32_t GetEmissionCount (void) const noexcept; bool GetPassive (void) const noexcept; @@ -153,11 +154,19 @@ namespace SHADE float GetMaxSpeed (void) const noexcept; float GetRotationSpeed (void) const noexcept; uint32_t GetTextureIndex (void) const noexcept; - AssetID GetTextureAssetID (void) const noexcept; float GetMinSize (void) const noexcept; float GetMaxSize (void) const noexcept; - Handle GetCustomShader (void) const noexcept; + Handle GetCustomUpdateShader (void) const noexcept; + /*-----------------------------------------------------------------------*/ + /* NON-INTERFACE FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + void SetTextureAssetID(AssetID id) noexcept; + void SetCustomUpdateShaderAssetID(AssetID id) noexcept; + + AssetID GetTextureAssetID(void) const noexcept; + AssetID GetCustomUpdateShaderAssetID(void) const 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 05295fd0..d99832a5 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp @@ -446,8 +446,10 @@ namespace SHADE /*-----------------------------------------------------------------------*/ for (auto& emitter : emitters) { + // If custom update shader is a valid handle in the component if (emitter.customUpdateShader) { + // Check if pipeline associated with shader is valid, if not create or get one from the cache if (!emitter.customUpdatePipeline) emitter.customUpdatePipeline = GetCustomUpdatePipeline(emitter.customUpdateShader); @@ -456,7 +458,7 @@ namespace SHADE } else { - // bind the pipeline for updating + // bind the default upddate pipeline for updating cmdBuffer->BindPipeline(defaultUpdatePipelineData.pipeline); } diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 0a879146..c1fa8548 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -516,6 +516,7 @@ namespace YAML static constexpr std::string_view MAX_SPEED_TAG = "Maximum Speed"; static constexpr std::string_view ROTATION_SPEED_TAG = "Rotation Speed"; static constexpr std::string_view TEXTURE_ASSET_ID_TAG = "Texture Asset ID"; + static constexpr std::string_view CUSTOM_UPDATE_SHADER_ASSET_ID_TAG = "Custom Update Shader Asset ID"; static YAML::Node encode(SHParticleEmitterComponent const& rhs) { @@ -532,6 +533,7 @@ namespace YAML node[ANGULAR_RANGES_OFFSET_TAG.data()] = rhs.GetAngularRangesAndOffsets(); node[ROTATION_SPEED_TAG.data()] = rhs.GetRotationSpeed(); node[TEXTURE_ASSET_ID_TAG.data()] = rhs.GetTextureAssetID(); + node[CUSTOM_UPDATE_SHADER_ASSET_ID_TAG.data()] = rhs.GetCustomUpdateShaderAssetID(); return node; } @@ -580,6 +582,18 @@ namespace YAML rhs.SetTextureIndex(texture->TextureArrayIndex); rhs.SetTextureAssetID(id); } + + if (node[CUSTOM_UPDATE_SHADER_ASSET_ID_TAG.data()].IsDefined()) + { + AssetID id = node[CUSTOM_UPDATE_SHADER_ASSET_ID_TAG.data()].as(); + + Handle shaderModule = SHResourceManager::LoadOrGet(id); + SHResourceManager::FinaliseChanges(); + //gfxSystem->BuildTextures(); + + rhs.SetCustomUpdateShader(shaderModule); + rhs.SetTextureAssetID(id); + } return true; } From aa0c9d08e0e59667efde72c900e7749709c33ba4 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 20 Mar 2023 10:50:18 +0800 Subject: [PATCH 13/16] Updated particle shaders to include rotation - Fixed compute shader hot reloading - Vertex/Fragment shader hot reloading still broken :/ --- .../Shaders/ParticleUpdateRandomAcc_CS.glsl | 146 ++++++++++++++++++ .../ParticleUpdateRandomAcc_CS.shshaderb | Bin 0 -> 9093 bytes ...articleUpdateRandomAcc_CS.shshaderb.shmeta | 3 + Assets/Shaders/ParticleUpdate_CS.glsl | 2 + Assets/Shaders/ParticleUpdate_CS.shshaderb | Bin 6689 -> 7037 bytes Assets/Shaders/Particle_VS.glsl | 2 +- Assets/Shaders/Particle_VS.shshaderb | Bin 6585 -> 6609 bytes Assets/Shaders/ShinyHighlight_VS.shshaderb | Bin 6141 -> 5913 bytes .../Inspector/SHEditorComponentView.hpp | 4 +- .../src/Graphics/Pipeline/SHVkPipeline.cpp | 2 + .../src/Graphics/Shaders/SHVkShaderModule.cpp | 4 +- 11 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 Assets/Shaders/ParticleUpdateRandomAcc_CS.glsl create mode 100644 Assets/Shaders/ParticleUpdateRandomAcc_CS.shshaderb create mode 100644 Assets/Shaders/ParticleUpdateRandomAcc_CS.shshaderb.shmeta diff --git a/Assets/Shaders/ParticleUpdateRandomAcc_CS.glsl b/Assets/Shaders/ParticleUpdateRandomAcc_CS.glsl new file mode 100644 index 00000000..bf500255 --- /dev/null +++ b/Assets/Shaders/ParticleUpdateRandomAcc_CS.glsl @@ -0,0 +1,146 @@ +#version 450 + +layout(local_size_x = 128) in; + +struct DrawArraysIndirectArgs +{ + uint count; + uint instanceCount; + uint first; + uint baseInstance; +}; + +struct ParticleData +{ + vec4 position; + vec4 orientationSpeedDecay; + vec4 velocity; + vec4 acceleration; + vec4 scaleAndDecay; + float life; + uint textureIndex; +}; + +struct GenericData +{ + //! Delta time + float dt; + + //! Elapsed time of the application + float elapsedTime; + + //! Viewport width of the scene (excluding imgui, that means smaller than window) + uint viewportWidth; + + //! Ditto but for height + uint viewportHeight; +}; + +layout(set = 1, binding = 0) uniform CameraData +{ + vec4 position; + mat4 vpMat; + mat4 viewMat; + mat4 projMat; +} cameraData; + + +layout (set = 0, binding = 0) uniform GenericDataBuffer +{ + GenericData data; +} genericDataBuffer; + +layout (std430, set = 2, binding = 1) coherent restrict readonly buffer ParticlesInputBuffer +{ + ParticleData data[]; +} inputParticles; + +// output buffer not needed +layout (std430, set = 2, binding = 2) coherent restrict buffer ParticlesOutputBuffer +{ + ParticleData data[]; +} outputParticles; + +layout (std430, set = 2, binding = 3) coherent restrict buffer ParticlesFreelistBuffer +{ + int freeCount; + int freeIndices[]; + +} freelist; + +layout (std430, set = 2, binding = 4) coherent restrict buffer IndicesData +{ + uint indices[]; +}; + +layout (std140, set = 2, binding = 5) coherent restrict buffer IndirectDrawArgs +{ + DrawArraysIndirectArgs indirectArgs; +}; + +// push constants +layout(std140, push_constant) uniform EmitterPushConstant +{ + vec4 emitterPosition; + uint emissionCount; + +} emitterPushConstant; + +uint pcg_hash(uint seed) +{ + uint state = seed * 747796405u + 2891336453u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +// Used to advance the PCG state. +uint rand_pcg(inout uint rng_state) +{ + uint state = rng_state; + rng_state = rng_state * 747796405u + 2891336453u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +// Advances the prng state and returns the corresponding random float. +float rand(inout uint state) +{ + uint x = rand_pcg(state); + state = x; + return float(x)*uintBitsToFloat(0x2f800004u); +} + +void main() +{ + uint index = gl_GlobalInvocationID.x; + + ParticleData particle = inputParticles.data[index]; + + // Get seed for randomization + uint pixel_index = uint (particle.position.x + particle.position.y + floatBitsToUint(genericDataBuffer.data.elapsedTime) * (gl_GlobalInvocationID.x + 1)); + uint seed = pcg_hash (pixel_index); + + if (particle.life > 0.0f) + { + // update position from velocity + particle.position += particle.velocity * genericDataBuffer.data.dt; + particle.velocity += vec4 (rand(seed) * particle.acceleration.x, rand(seed) * particle.acceleration.y, rand(seed) * particle.acceleration.z, 1.0f); + particle.life -= genericDataBuffer.data.dt; + + if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f) + { + particle.life = 0.0f; + particle.position.x = 9999.0f; + + outputParticles.data[index] = particle; + freelist.freeIndices[atomicAdd(freelist.freeCount, 1)] = int (index); + return; + } + + uint drawIndex = atomicAdd (indirectArgs.instanceCount, 1); + indices[drawIndex] = index; + + } + + outputParticles.data[index] = particle; +} \ No newline at end of file diff --git a/Assets/Shaders/ParticleUpdateRandomAcc_CS.shshaderb b/Assets/Shaders/ParticleUpdateRandomAcc_CS.shshaderb new file mode 100644 index 0000000000000000000000000000000000000000..370f996537732a4324d4303ed533ffecc20b12fd GIT binary patch literal 9093 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 N#JyG5&pY%W_#b0#hU@?U diff --git a/Assets/Shaders/Particle_VS.glsl b/Assets/Shaders/Particle_VS.glsl index 211bb4de..02830753 100644 --- a/Assets/Shaders/Particle_VS.glsl +++ b/Assets/Shaders/Particle_VS.glsl @@ -79,7 +79,7 @@ void main() ParticleData particle = outputParticles.data[indices[gl_InstanceIndex]]; vec3 normalized = normalize (particle.velocity.xyz); - float angle = 1.1f; + float angle = particle.orientationSpeedDecay.x; // float angle = atan (normalized.y, normalized.x); vec2 particleScaleData = particle.scaleAndDecay.xz; // x and y diff --git a/Assets/Shaders/Particle_VS.shshaderb b/Assets/Shaders/Particle_VS.shshaderb index 492a926c869f280ed8059f362d67f99a3df754f2..58000df23b9a92eb4eb81c7b532248e60458f5f2 100644 GIT binary patch literal 6609 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 literal 6585 zcmai%`D`lBhmYG=pPQTRC=d<@-!)C&#cb@gEwZ7}}uC?BG@3W`t`Ad^*b1diR+i9hf?w+jFR!&~KE=hX%n+<*>ZFkb6JGLN#bkj$Y z+*8O`39|ag81m$i+|Pb?O?HUs%lbOh7`-b`)vTpQ_325j#-~+jSH|G(cRf7cZ)AKT z!}^l-@R3TpQ?EACEtO6Mm5e#A+!~*#ck1KW4EvHc zDb~3jNgLzUdPkUy{aLK1RH;_eM%vDT%QojWQLQx6p=K#xZx+{!tx-S737pN*QfZK^{MU6`qVbPPqFj&IWyUW zEqa>ZGPEW;nO=Qv1r zvOR~8`?F_>d$*%G(Wx}6=bphq{F>wKu}Y)|Lp0t?73Z|qb1yES zz8!4saV{9n-reIRUvID239uve^!`2dLx=Sj`!sxWWsKXEC-W|gxz0V~+}ATc(z?B3 zygloiohf-m1M@sv?eTlX+~*W}wX}~lKMiI*cebphJNXs5%ex=)|K8W0?0v-XZEIw? z`;r%lVXh--JAb6}967G6EgnmA>u(l_BN zHf`?j%(QJ!^MmwmoB=QGdCtAo=BiEI>;B{)=!eeMIORXgx%jSJY5+^!-+|eXd^`OO z!d+M9YzngB~y`R%G|HUh{8*yJEl4W53YL`-#PVz8}i_ zsk@)~?a$v|XTJ(^R`F~`K5G!`f}B_QsOuAF5kCD>SRQAevsiaPOwg=v`Nh^1`icTG)*4qrF8$vQw?1+G z)qNj{X@4i&eD388u7z8lnD*=7_Aef_-h|BBxSBIFZY?Axnd4TtIXwTRc&vwuO(%Vv zk^5|byN|xc48o`TM_yx=P~i|` zQ{P@-F}oe;U6B5_6*hCJ-%;p;g}w)FPu3l0vme<#Lcbf?S%>}sWak$80pwoD{1v$Q zoLksy$nLK$-hkdXb8@5pW61h@MvKw?Uh^E|Z2dOZF20&9+9o0IqW4n@oPP&0J#2yB zU-H!^Za)4s$Z{E{kM&vSLr@oFJtyJLCch{7_mjGKkbOLX?#z4-dJgKR3QW82PVM&Z znfeVBXYy-g`xP@*{d9pD`$8e>e+ByQ;pVZ4|U&xVmEOsE-b7cuWaHfBF$jJkdi^Il|Qyqgj8K4fF=hKy0yFJj)0Y>f9hVm^p$jPFKc)b%rF zCVUh!#=CEfclRF1m;;b8>iQYuysMBg%EovvQ^=SaWQ@9gQO6-`G`6WG*rNBiDn-@H`j%bw#fA` za^!jl*<51!N3KVZ%efv!k6hXwF6w^_SzF|O9NFCSp{P?#zsUVjX!bjb6{UqeG{}gvg{Zo)W;`VvGz=k-pCy}3mPC?$Km~GVgnZh2v zpDp=Df8qN%Y}&*3^Ce$%JB#rB07mt0uj9jkY zImJF-LDn9=UoH7sf7$nI=-R{g>m^_7FZ+H2U3=9346=KfLtE7UP2{Nm8D#5!8ZI8s z)whs0LeAd0Z-svw5|3y3I|U~0GUp6Pf6w^4kaIC-1^zwAb1u*P`vv|)aW8&=Zk%|; zJ&WwKT8{f6x_HDrhit6)qeZSCAzP!isOiVZ_8Pf=f^1FYIsOz~JaRveY@B$+{S4Wf z%5gtO7mv7KAR8+lHT@FVy0pc;7c*}^{5OzuuR+$_2mdW3uFnhb-$AD#&&C|;`e=U{ z{zu5W=Up<#N%)^2@tDJ(k?lKvBVIuka|QMnWHHY*u)h|V=R88i-iucutlVd!T%1u1V#Po`u&@oZif7Jn}t3Ha$NwerBCNG8}d8OcV~RZ%|+H0^STIG zzgNgJ5B?U&S%}BC)Pe$ce#Wau{Kd#(uM+S4FM$?9;?IFChF=PadncbQej~0ZaQnXu pihN6v%lY1lz627Fd;`eh<$TM~#UtNHF_-0F?xp=d%tGC{{TGG6hUWkP diff --git a/Assets/Shaders/ShinyHighlight_VS.shshaderb b/Assets/Shaders/ShinyHighlight_VS.shshaderb index 95eac304277d9591e76c296a0c74bea47b4eb2ad..3b7e8d728a411274e97343f18c285a4b3359b2c5 100644 GIT binary patch delta 54 zcmeyXKT}VPQ9zsl449de*%=rZ8MqjD8BR?UGiBtT=wrEYq6o|8w=5}4n;Y2!ST-B- HoZ$ul3;zrM delta 271 zcmbQK_g7zx@ryVE7%(#_vokO-GH@~QGF+G_X38iu(Z`bW3{dVI5TD=JB+lZ-%D~0| z5=nH*&r9{pOUX=5Ee2@@iGx&u#lurG(=$ro;^%?lX_-aEB~U%76`QBCq%rBbGq8Zo zk^{~QlVvx8sln-(u eNDL%@7RpwF%7geIYe4cK^%6k({AM@q%iI9e-7ZQ1 diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 4aa03a4b..0fc66afb 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -865,11 +865,11 @@ namespace SHADE SHEditorWidgets::DragFloat("Rotation Speed", [comp = component]() { - return comp->GetMaxSpeed(); + return comp->GetRotationSpeed(); }, [comp = component](float val) { - comp->SetMaxSpeed(val); + comp->SetRotationSpeed(val); }); SHEditorWidgets::DragInt("Texture Index", diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp index 38944882..f2f8db7a 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp @@ -299,6 +299,8 @@ namespace SHADE , created{ false } { + if (pipelineLayout) + pipelineLayout->AddCallback([this]() {ConstructPipeline(); }); } diff --git a/SHADE_Engine/src/Graphics/Shaders/SHVkShaderModule.cpp b/SHADE_Engine/src/Graphics/Shaders/SHVkShaderModule.cpp index 49188181..8f41d24a 100644 --- a/SHADE_Engine/src/Graphics/Shaders/SHVkShaderModule.cpp +++ b/SHADE_Engine/src/Graphics/Shaders/SHVkShaderModule.cpp @@ -94,8 +94,8 @@ namespace SHADE Recompile(); - //for (auto& callback : onChangeCallbacks) - // callback(); + for (auto& callback : onChangeCallbacks) + callback(); } void SHVkShaderModule::AddCallback(ChangeCallback&& callback) noexcept From b8a2e206f776e6c612dffb89fe9edf956327b89b Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 20 Mar 2023 12:19:27 +0800 Subject: [PATCH 14/16] Added rotation and size decay support for particles --- Assets/Scenes/Scene2.shade | 9 +++++--- Assets/Shaders/ParticleEmit_CS.glsl | 11 +++++++--- Assets/Shaders/ParticleEmit_CS.shshaderb | Bin 11661 -> 12045 bytes Assets/Shaders/ParticleUpdate_CS.glsl | 10 ++++++++- Assets/Shaders/ParticleUpdate_CS.shshaderb | Bin 7037 -> 7585 bytes Assets/Shaders/Particle_VS.glsl | 2 +- Assets/Shaders/Particle_VS.shshaderb | Bin 6609 -> 6609 bytes .../Inspector/SHEditorComponentView.hpp | 11 ++++++++++ .../Particles/SHParticleEmitterComponent.cpp | 20 ++++++++++++++++++ .../Particles/SHParticleEmitterComponent.h | 19 +++++++++++++++-- .../src/Serialization/SHYAMLConverters.h | 11 ++++++++++ 11 files changed, 83 insertions(+), 10 deletions(-) diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index e14f32cb..11078394 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -157,7 +157,7 @@ Scale: {x: 1, y: 1, z: 1} IsActive: true classSHADE::SHParticleEmitterComponent: - Emission Count: 7 + Emission Count: 15 Is Passive: true Emission Interval: 0.0939999968 Min Life: 2 @@ -166,8 +166,11 @@ Maximum Speed: 6 Minimum Size: 0 Maximum Size: 0.5 + Size Decay: 0.990999997 Angular Ranges And Offset: {x: 6.19999981, y: 1.10000002, z: 0, w: 0.100000001} - Rotation Speed: 0 - Texture Asset ID: 63456868 + Rotation Speed: 0.0309999995 + Rotation Decay: 0.0199999996 + Texture Asset ID: 0 + Custom Update Shader Asset ID: 0 IsActive: true Scripts: ~ \ No newline at end of file diff --git a/Assets/Shaders/ParticleEmit_CS.glsl b/Assets/Shaders/ParticleEmit_CS.glsl index 444af6db..45cea313 100644 --- a/Assets/Shaders/ParticleEmit_CS.glsl +++ b/Assets/Shaders/ParticleEmit_CS.glsl @@ -10,8 +10,11 @@ struct EmitterParameters float minSpeed; float maxSpeed; float rotationSpeed; - uint textureIndex; + float rotationDecay; vec4 lifeAndSizeRange; // min life, max life, min size, max size + float sizeDecay; + uint textureIndex; + float padding[2]; }; struct ParticleData @@ -165,14 +168,16 @@ void main() // Set size of particle particle.scaleAndDecay.x = particleSize; - particle.scaleAndDecay.z = particleSize; + particle.scaleAndDecay.y = particleSize; + particle.scaleAndDecay.z = emitterParams.data.sizeDecay; + particle.scaleAndDecay.w = emitterParams.data.sizeDecay; // Set the texture for the particle particle.textureIndex = emitterParams.data.textureIndex; // Set orientation and rotation speed if (emitterParams.data.rotationSpeed != 0.0f) - particle.orientationSpeedDecay = vec4 (rand(seed) * PI, emitterParams.data.rotationSpeed, 0.0f, 0.0f); + particle.orientationSpeedDecay = vec4 (rand(seed) * PI, emitterParams.data.rotationSpeed, emitterParams.data.rotationDecay, 0.0f); else particle.orientationSpeedDecay = vec4 (0.0f); diff --git a/Assets/Shaders/ParticleEmit_CS.shshaderb b/Assets/Shaders/ParticleEmit_CS.shshaderb index f0d782403695ba43b8271f8a3103ba6fa2c4ac7b..b003ba77861961ed5ed03983caec5948612b5c10 100644 GIT binary patch literal 12045 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 literal 11661 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 Y&a$4(VEfXyv($#c&P$(bDR(XZ4@-RRB>(^b diff --git a/Assets/Shaders/ParticleUpdate_CS.glsl b/Assets/Shaders/ParticleUpdate_CS.glsl index 5882a561..43d4893d 100644 --- a/Assets/Shaders/ParticleUpdate_CS.glsl +++ b/Assets/Shaders/ParticleUpdate_CS.glsl @@ -123,7 +123,15 @@ void main() particle.velocity += particle.acceleration; particle.life -= genericDataBuffer.data.dt; particle.orientationSpeedDecay.x += particle.orientationSpeedDecay.y; - particle.orientationSpeedDecay.y -= particle.orientationSpeedDecay.z * genericDataBuffer.data.dt; + particle.scaleAndDecay.x *= particle.scaleAndDecay.z; + particle.scaleAndDecay.y *= particle.scaleAndDecay.w; + + if (particle.orientationSpeedDecay.y > 0.0f) + { + particle.orientationSpeedDecay.y -= particle.orientationSpeedDecay.z * genericDataBuffer.data.dt; + if (particle.orientationSpeedDecay.y < 0.0f) + particle.orientationSpeedDecay.y = 0.0f; + } if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f) { diff --git a/Assets/Shaders/ParticleUpdate_CS.shshaderb b/Assets/Shaders/ParticleUpdate_CS.shshaderb index 963f2ec9bbd9fa88371947916c2f77ed7179a781..63a79d5af3edef985bc8cb8bc9652dfe2032f10b 100644 GIT binary patch literal 7585 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 literal 7037 zcmai%`D`p% zqrY#}P?9W4E={gT{#HQA)kz;nl3bPy=JWXOeY@9ndz0%n-o9R!E0g}*Q=hBwsWA^A zN9tM2h0Bn|;9^%JClGy=e*WuYK94a#*74mF<9qgu@7_Mqn4X^K_Kr8xiDuSHCnmE_ z+URAoseZ#1zpT}0&P-MvYIs!hYY&qnYfYxdm}^+pbf`Ho-fSPNH+QvW+l_iJYqxf7 z%hv~!Ynb=eJH4#YOt;m0bxd|p;Of)uZYH6?FUkGgPrH+)tzI5$-*lQzZc7{Wn3(^lHa8u>Nw7K=G1d&V2g zZF`b7>(kwIa({Lt1s%%qyboD=bh_Q?-Iq=F4&xVV_F}eN+nHvE4im2iZwq)O=UnmD z?wVu1_Mv1e_M!P2=ls3rA7gE9OM7N|)n*vab;o?X!Q>=%J9nL9;yIjr6?_ia(Mi*0 z){WNM2iF}_ERD5iT5Jcj!0nGX7cy(4UEl@2PwaUZ!}B;;?^0vI!K9|4 zM|y}U=YM9d+#=t+O_OabMb^XOysBfJPX zCGVw}-q;0lEFTK9IjXE79GD`Fx93Anw)LipJyayzp5PVDo0z6dF+XtsL{8oTBEi#x^AD(FgxaR7FacA__;6r z;*8`PN31xbf&9(EoU8Y&1|#YXJMvktm~rgsIp&o}U&Xdw@4M?yF;{yUZ&CCo?8p~( zHJ@1I^WCcE(>7nx%Yo#1biZ%!wtYCy?1*@tk(m9m#_-YBC%*Ua;g8f3D|mg_Ri3uI z_^#!NE#z5$m8UK5F(hgb3!Z(BSoZM(Ybz1!4BLG>`O{rj_a2)n?rn4Y1@CXTe0PN*Bts^!R(s&QZn1`5yaU3 z&93cPE+?XY8;dOzeTq5<@_TB1`pWS=U+5ok@qk9jvt<87TK8U#&ZSPU^ z=0@}p#QNQvcKN?EIe!^;;akL8fo*N(5C7HZRsI@mIkA2Vy1fm1ExP>(dp)}M$a*(0 z8{dA!`bKp3sV#md;#fkKH!&|~)py=CMPJ2UY+-iI*rUwWwFR*k+FKDZ*T+gdavS45 zWD#O+?fVh^qn3xzlg&5p@CXVsv9*0)BleS}UhoI=x7N5-u}^2g&LGD8PRS87ruMlKv!18W<;(LO z)0X#rX7h^4)AlVBi~juy{RDCw5&XWMN5t&2as#|SGuw*+#IrqL+TtPR`wO-`4@=yQeW@nFygH3+rFe?i=Qs-QCPkS zS0cU}z7==Dv5u<{@w>@jJndNX?>DhgJpJyLBYvxXkFM$G{dy(h+P&l{?o5FJ!L8-L z9V^kTPp-MNN08vGLO0GLBsi}^m$Mp?qpe?XUX3otJ_YAB=yKK|aG?G zY

J&-U(I*Jm()pSEFdMLbs}YS@nM+N0DUZwDe*JmQa|8$WpZ?L@>+mb_ghCO>#@ zMGu}m(bg~4-&U@Bo>BL1bn)=Hr}U}r?d@RVk$VrinB3s)MUS4CTU)>A$Gzwm>&H95 zT{F%G=6#59ybIB@{U!b|KAz({5iz;Jdl!1}%&)DV`HlPTa@}vn_bXz*r(6ra_g4Ha zulT(W-8Fk)4ev+9t|J%g*THh_k+O~k z_5nmZa!jH}j_O`haMz-bQ|MyG2<{>DD%U-T=^MR1T>4bcC<7CJmb(159zewWww~r2 z5&Iw_?zeV?+2OY)-bBRw*3_e(7P|GUMXKk~#&#|8O{0sM@886TSkC|8#W4Se5c6+B z^fyn`)S$5hWTMcjxm-o ze*!s)7(?Iq9e4y?Ux)RaV*VtezrN$kEm>IG;n8(~kt_^XPJJLF8!b7o11Yk@*{lxOdRAU5&(< zeiPj@eTd!Y`z=JwGd13~5#z}*jyc8j`!A>CJ$n#cf9v}$at<-S9BZ)t?;);54bH|o z&Fos#^8<9Tuz!edeG&gh=+7X=*VhGetMaxLife(); }, [comp = component](float val) {comp->SetMaxLife(val); }); SHEditorWidgets::DragFloat("Min Size", [comp = component]() {return comp->GetMinSize(); }, [comp = component](float val) {comp->SetMinSize(val); }); SHEditorWidgets::DragFloat("Max Size", [comp = component]() {return comp->GetMaxSize(); }, [comp = component](float val) {comp->SetMaxSize(val); }); + SHEditorWidgets::DragFloat("Size Decay", [comp = component]() {return comp->GetSizeDecayMult(); }, [comp = component](float val) {comp->SetSizeDecayMult(val); }, {}, 0.0001f); SHEditorWidgets::DragVec4("Angles and Offsets", {"yaw", "bank", "yaw off", "bank off"}, [comp = component]() @@ -872,6 +873,16 @@ namespace SHADE comp->SetRotationSpeed(val); }); + SHEditorWidgets::DragFloat("Rotation Decay", + [comp = component]() + { + return comp->GetRotationDecay(); + }, + [comp = component](float val) + { + comp->SetRotationDecay(val); + }); + SHEditorWidgets::DragInt("Texture Index", [comp = component]() { diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp index 8293604c..5454cf31 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp @@ -67,6 +67,11 @@ namespace SHADE cpuEmitterData.rotationSpeed = speed; } + void SHParticleEmitterComponent::SetRotationDecay(float decay) noexcept + { + cpuEmitterData.rotationDecay = decay; + } + void SHParticleEmitterComponent::SetTextureIndex(uint32_t index) noexcept { cpuEmitterData.textureIndex = index; @@ -92,6 +97,11 @@ namespace SHADE cpuEmitterData.lifeAndSizeRange.w = size; } + void SHParticleEmitterComponent::SetSizeDecayMult(float decay) noexcept + { + cpuEmitterData.sizeDecayMult = decay; + } + void SHParticleEmitterComponent::SetCustomUpdateShader(Handle shaderModule) noexcept { customUpdateShader = shaderModule; @@ -143,6 +153,11 @@ namespace SHADE return cpuEmitterData.rotationSpeed; } + float SHParticleEmitterComponent::GetRotationDecay(void) const noexcept + { + return cpuEmitterData.rotationDecay; + } + uint32_t SHParticleEmitterComponent::GetTextureIndex(void) const noexcept { return cpuEmitterData.textureIndex; @@ -169,6 +184,11 @@ namespace SHADE } + float SHParticleEmitterComponent::GetSizeDecayMult(void) const noexcept + { + return cpuEmitterData.sizeDecayMult; + } + Handle SHParticleEmitterComponent::GetCustomUpdateShader(void) const noexcept { return customUpdateShader; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h index 616410cd..d9c26666 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h @@ -1,6 +1,7 @@ #pragma once #include "Resource/SHHandle.h" +#include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec4.h" #include "ECS_Base/Components/SHComponent.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" @@ -32,11 +33,21 @@ namespace SHADE //! Rotational speed of the quad float rotationSpeed; - //! Texture used by the particle - uint32_t textureIndex; + //! Rotation decay rate + float rotationDecay; //! Spawn lifetime and size range (min and max) SHVec4 lifeAndSizeRange; + + //! Size decay for particles + float sizeDecayMult; + + //! Texture used by the particle + uint32_t textureIndex; + + //! Padding for the shader struct + float padding[2]; + }; struct GPUParticleStruct @@ -139,9 +150,11 @@ namespace SHADE void SetMinSpeed (float speed) noexcept; void SetMaxSpeed (float speed) noexcept; void SetRotationSpeed (float speed) noexcept; + void SetRotationDecay (float decay) noexcept; void SetTextureIndex (uint32_t index) noexcept; void SetMinSize (float size) noexcept; void SetMaxSize (float size) noexcept; + void SetSizeDecayMult (float decay) noexcept; void SetCustomUpdateShader (Handle shaderModule) noexcept; uint32_t GetEmissionCount (void) const noexcept; @@ -153,9 +166,11 @@ namespace SHADE float GetMinSpeed (void) const noexcept; float GetMaxSpeed (void) const noexcept; float GetRotationSpeed (void) const noexcept; + float GetRotationDecay (void) const noexcept; uint32_t GetTextureIndex (void) const noexcept; float GetMinSize (void) const noexcept; float GetMaxSize (void) const noexcept; + float GetSizeDecayMult (void) const noexcept; Handle GetCustomUpdateShader (void) const noexcept; /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index c1fa8548..44ed0888 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -512,9 +512,11 @@ namespace YAML static constexpr std::string_view ANGULAR_RANGES_OFFSET_TAG = "Angular Ranges And Offset"; static constexpr std::string_view MIN_SIZE_TAG = "Minimum Size"; static constexpr std::string_view MAX_SIZE_TAG = "Maximum Size"; + static constexpr std::string_view SIZE_DECAY_TAG = "Size Decay"; static constexpr std::string_view MIN_SPEED_TAG = "Minimum Speed"; static constexpr std::string_view MAX_SPEED_TAG = "Maximum Speed"; static constexpr std::string_view ROTATION_SPEED_TAG = "Rotation Speed"; + static constexpr std::string_view ROTATION_DECAY_TAG = "Rotation Decay"; static constexpr std::string_view TEXTURE_ASSET_ID_TAG = "Texture Asset ID"; static constexpr std::string_view CUSTOM_UPDATE_SHADER_ASSET_ID_TAG = "Custom Update Shader Asset ID"; @@ -530,8 +532,10 @@ namespace YAML node[MAX_SPEED_TAG.data()] = rhs.GetMaxSpeed(); node[MIN_SIZE_TAG.data()] = rhs.GetMinSize(); node[MAX_SIZE_TAG.data()] = rhs.GetMaxSize(); + node[SIZE_DECAY_TAG.data()] = rhs.GetSizeDecayMult(); node[ANGULAR_RANGES_OFFSET_TAG.data()] = rhs.GetAngularRangesAndOffsets(); node[ROTATION_SPEED_TAG.data()] = rhs.GetRotationSpeed(); + node[ROTATION_DECAY_TAG.data()] = rhs.GetRotationDecay(); node[TEXTURE_ASSET_ID_TAG.data()] = rhs.GetTextureAssetID(); node[CUSTOM_UPDATE_SHADER_ASSET_ID_TAG.data()] = rhs.GetCustomUpdateShaderAssetID(); @@ -556,6 +560,9 @@ namespace YAML if (node[MAX_LIFE_TAG.data()].IsDefined()) rhs.SetMaxLife(node[MAX_LIFE_TAG.data()].as()); + if (node[SIZE_DECAY_TAG.data()].IsDefined()) + rhs.SetSizeDecayMult(node[SIZE_DECAY_TAG.data()].as()); + if (node[ANGULAR_RANGES_OFFSET_TAG.data()].IsDefined()) rhs.SetAngularRangesAndOffsets(node[ANGULAR_RANGES_OFFSET_TAG.data()].as()); @@ -571,6 +578,10 @@ namespace YAML if (node[ROTATION_SPEED_TAG.data()].IsDefined()) rhs.SetRotationSpeed(node[ROTATION_SPEED_TAG.data()].as()); + if (node[ROTATION_DECAY_TAG.data()].IsDefined()) + rhs.SetRotationDecay(node[ROTATION_DECAY_TAG.data()].as()); + + if (node[TEXTURE_ASSET_ID_TAG.data()].IsDefined()) { AssetID id = node[TEXTURE_ASSET_ID_TAG.data()].as(); From 9ead2b6b12f7cf4584b7a4763ea96c95309f22c2 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 20 Mar 2023 15:03:18 +0800 Subject: [PATCH 15/16] Added if statement for particle texture check --- Assets/Scenes/Scene2.shade | 2 +- SHADE_Engine/src/Serialization/SHYAMLConverters.h | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index 11078394..b4d7abbd 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -170,7 +170,7 @@ Angular Ranges And Offset: {x: 6.19999981, y: 1.10000002, z: 0, w: 0.100000001} Rotation Speed: 0.0309999995 Rotation Decay: 0.0199999996 - Texture Asset ID: 0 + Texture Asset ID: 63456868 Custom Update Shader Asset ID: 0 IsActive: true Scripts: ~ \ No newline at end of file diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 44ed0888..2550388e 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -590,8 +590,15 @@ namespace YAML SHResourceManager::FinaliseChanges(); //gfxSystem->BuildTextures(); - rhs.SetTextureIndex(texture->TextureArrayIndex); - rhs.SetTextureAssetID(id); + if (texture) + { + rhs.SetTextureIndex(texture->TextureArrayIndex); + rhs.SetTextureAssetID(id); + } + else + { + SHLOG_WARNING ("Texture not set for particle emitter component: texture handle is null. "); + } } if (node[CUSTOM_UPDATE_SHADER_ASSET_ID_TAG.data()].IsDefined()) From ba732ea64ca00d53a69c9265d274585dcc9fbde2 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 20 Mar 2023 16:38:15 +0800 Subject: [PATCH 16/16] Fixed trajectory renderable --- .../SHTrajectoryRenderableComponent.cpp | 9 ++++++++- .../SHTrajectoryRenderableComponent.h | 6 +++++- .../SHTrajectoryRenderingSubSystem.cpp | 12 ++++++++++-- .../{ => src/Physics/System}/SHGhostBody.cpp | 12 ++++++------ SHADE_Engine/{ => src/Physics/System}/SHGhostBody.h | 0 SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp | 2 +- .../src/Components/TrajectoryRenderable.cxx | 4 ++-- .../src/Components/TrajectoryRenderable.hxx | 2 +- 8 files changed, 33 insertions(+), 14 deletions(-) rename SHADE_Engine/{ => src/Physics/System}/SHGhostBody.cpp (82%) rename SHADE_Engine/{ => src/Physics/System}/SHGhostBody.h (100%) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.cpp index 41678935..b7ef5e35 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.cpp @@ -14,6 +14,7 @@ namespace SHADE /***************************************************************************/ void SHTrajectoryRenderableComponent::OnCreate(void) { + ResetSimulationInfo(); } void SHTrajectoryRenderableComponent::OnDestroy(void) @@ -22,12 +23,13 @@ namespace SHADE } - void SHTrajectoryRenderableComponent::SimulateTrajectory(EntityID eid, SHVec3 force, float timestep, uint32_t maxSteps) noexcept + void SHTrajectoryRenderableComponent::SimulateTrajectory(EntityID eid, float mass, SHVec3 force, float timestep, uint32_t maxSteps) noexcept { entityToSimulate = eid; simulationForce = force; simulationTimestep = timestep; simulationMaxSteps = maxSteps; + objectMass = mass; } float SHTrajectoryRenderableComponent::GetSimulationTimestep(void) const noexcept @@ -35,6 +37,11 @@ namespace SHADE return simulationTimestep; } + float SHTrajectoryRenderableComponent::GetObjectMass(void) const noexcept + { + return objectMass; + } + void SHTrajectoryRenderableComponent::ResetSimulationInfo(void) noexcept { entityToSimulate = MAX_EID; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h index 95d40af1..51536107 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h @@ -36,6 +36,9 @@ namespace SHADE //! plotting a point in the simulation float simulationTimestep; + //! mass of the object to simulate + float objectMass; + //! Entity to simulate trajectory of EntityID entityToSimulate; @@ -68,12 +71,13 @@ namespace SHADE SHVec3 GetSimulationForce (void) const noexcept; uint32_t GetSimulationMaxSteps (void) const noexcept; float GetSimulationTimestep (void) const noexcept; + float GetObjectMass (void) const noexcept; void ResetSimulationInfo (void) noexcept; void OnCreate(void) override final; void OnDestroy(void) override final; - void SimulateTrajectory (EntityID eid, SHVec3 force, float timestep, uint32_t maxSteps) noexcept; + void SimulateTrajectory (EntityID eid, float mass, SHVec3 force, float timestep, uint32_t maxSteps) noexcept; RTTR_ENABLE() diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderingSubSystem.cpp index 5f211929..dab94c5d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderingSubSystem.cpp @@ -1,7 +1,6 @@ #include "SHpch.h" #include "SHTrajectoryRenderingSubSystem.h" -#include "../../../../SHGhostBody.h" #include "ECS_Base/Managers/SHComponentManager.h" #include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h" #include "Graphics/Devices/SHVkLogicalDevice.h" @@ -15,6 +14,7 @@ #include "Graphics/MiddleEnd/Interface/SHRenderer.h" #include "Physics/System/SHPhysicsSystem.h" #include "ECS_Base/Managers/SHSystemManager.h" +#include namespace SHADE { @@ -88,7 +88,13 @@ namespace SHADE std::vector positions{}; std::vector quats{}; - SHGhostBody defaultGhostBody{}; + auto* rigidBodyComp = SHComponentManager::GetComponent_s(entityToSimulate); + if (!rigidBodyComp) + continue; + + SHGhostBody defaultGhostBody{*rigidBodyComp}; + + defaultGhostBody.mass = comp.GetObjectMass(); SHPhysicsSystem::SimulateBodyInfo simulateInfo { @@ -109,6 +115,8 @@ namespace SHADE comp.ResetSimulationInfo(); + std::cout << positions.size() << std::endl; + // If has positions, feed data to buffer. if (!positions.empty()) { diff --git a/SHADE_Engine/SHGhostBody.cpp b/SHADE_Engine/src/Physics/System/SHGhostBody.cpp similarity index 82% rename from SHADE_Engine/SHGhostBody.cpp rename to SHADE_Engine/src/Physics/System/SHGhostBody.cpp index ef260521..2a5cff3a 100644 --- a/SHADE_Engine/SHGhostBody.cpp +++ b/SHADE_Engine/src/Physics/System/SHGhostBody.cpp @@ -38,13 +38,13 @@ namespace SHADE localInvInertia.y = 1.0f / LOCAL_INERTIA.y; localInvInertia.z = 1.0f / LOCAL_INERTIA.z; - linearLock.x = rigidBody.GetFreezePositionX() ? 1.0f : 0.0f; - linearLock.y = rigidBody.GetFreezePositionY() ? 1.0f : 0.0f; - linearLock.z = rigidBody.GetFreezePositionZ() ? 1.0f : 0.0f; + linearLock.x = rigidBody.GetFreezePositionX() ? 0.0f : 1.0f; + linearLock.y = rigidBody.GetFreezePositionY() ? 0.0f : 1.0f; + linearLock.z = rigidBody.GetFreezePositionZ() ? 0.0f : 1.0f; - angularLock.x = rigidBody.GetFreezeRotationX() ? 1.0f : 0.0f; - angularLock.y = rigidBody.GetFreezeRotationY() ? 1.0f : 0.0f; - angularLock.z = rigidBody.GetFreezeRotationZ() ? 1.0f : 0.0f; + angularLock.x = rigidBody.GetFreezeRotationX() ? 0.0f : 1.0f; + angularLock.y = rigidBody.GetFreezeRotationY() ? 0.0f : 1.0f; + angularLock.z = rigidBody.GetFreezeRotationZ() ? 0.0f : 1.0f; } diff --git a/SHADE_Engine/SHGhostBody.h b/SHADE_Engine/src/Physics/System/SHGhostBody.h similarity index 100% rename from SHADE_Engine/SHGhostBody.h rename to SHADE_Engine/src/Physics/System/SHGhostBody.h diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index 75ed50f4..32d6f03e 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -14,7 +14,6 @@ #include "SHPhysicsSystem.h" // Project Headers -#include "../../../SHGhostBody.h" #include "Assets/SHAssetMacros.h" #include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHEntityManager.h" @@ -25,6 +24,7 @@ #include "Physics/Interface/SHColliderComponent.h" #include "Scene/SHSceneManager.h" #include "Scripting/SHScriptEngine.h" +#include "SHGhostBody.h" namespace SHADE { diff --git a/SHADE_Managed/src/Components/TrajectoryRenderable.cxx b/SHADE_Managed/src/Components/TrajectoryRenderable.cxx index 9eace4ab..7234147c 100644 --- a/SHADE_Managed/src/Components/TrajectoryRenderable.cxx +++ b/SHADE_Managed/src/Components/TrajectoryRenderable.cxx @@ -13,9 +13,9 @@ namespace SHADE } - void TrajectoryRenderable::SimulateTrajectory(EntityID eid, Vector3 force, float timestep, uint32_t maxSteps) + void TrajectoryRenderable::SimulateTrajectory(EntityID eid, float mass, Vector3 force, float timestep, uint32_t maxSteps) { - GetNativeComponent()->SimulateTrajectory(eid, Convert::ToNative(force), timestep, maxSteps); + GetNativeComponent()->SimulateTrajectory(eid, mass, Convert::ToNative(force), timestep, maxSteps); } MeshAsset TrajectoryRenderable::Mesh::get() diff --git a/SHADE_Managed/src/Components/TrajectoryRenderable.hxx b/SHADE_Managed/src/Components/TrajectoryRenderable.hxx index 78e3c0f1..e6f71788 100644 --- a/SHADE_Managed/src/Components/TrajectoryRenderable.hxx +++ b/SHADE_Managed/src/Components/TrajectoryRenderable.hxx @@ -83,7 +83,7 @@ namespace SHADE void set(float val); } - void SimulateTrajectory(EntityID eid, Vector3 force, float timestep, uint32_t maxSteps); + void SimulateTrajectory(EntityID eid, float mass, Vector3 force, float timestep, uint32_t maxSteps); }; }