From 3ae4f269014c07bb155df2e8ac3397eb34b8c6c0 Mon Sep 17 00:00:00 2001 From: saschawillems Date: Sat, 14 May 2016 23:09:17 +0200 Subject: [PATCH] Updated compute shader particle system with point sprites and gradient coloring --- android/computeparticles/build.bat | 1 + computeparticles/computeparticles.cpp | 185 +++++++++++------- data/shaders/computeparticles/particle.comp | 4 + .../computeparticles/particle.comp.spv | Bin 4684 -> 5212 bytes data/shaders/computeparticles/particle.frag | 7 +- .../computeparticles/particle.frag.spv | Bin 452 -> 1184 bytes data/shaders/computeparticles/particle.vert | 11 +- .../computeparticles/particle.vert.spv | Bin 1068 -> 1148 bytes data/textures/particle_gradient_rgba.ktx | Bin 0 -> 1124 bytes 9 files changed, 131 insertions(+), 77 deletions(-) create mode 100644 data/textures/particle_gradient_rgba.ktx diff --git a/android/computeparticles/build.bat b/android/computeparticles/build.bat index 88059925..a70cfac6 100644 --- a/android/computeparticles/build.bat +++ b/android/computeparticles/build.bat @@ -9,6 +9,7 @@ if %ERRORLEVEL% EQU 0 ( mkdir "assets\textures" xcopy "..\..\data\textures\particle01_rgba.ktx" "assets\textures" /Y + xcopy "..\..\data\textures\particle_gradient_rgba.ktx" "assets\textures" /Y mkdir "res\drawable" xcopy "..\..\android\images\icon.png" "res\drawable" /Y diff --git a/computeparticles/computeparticles.cpp b/computeparticles/computeparticles.cpp index 960833ca..73378494 100644 --- a/computeparticles/computeparticles.cpp +++ b/computeparticles/computeparticles.cpp @@ -1,6 +1,8 @@ /* * Vulkan Example - Attraction based compute shader particle system * +* Updated compute shader by Lukas Bergdoll (https://github.com/Voultapher) +* * Copyright (C) 2016 by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) @@ -25,20 +27,23 @@ #define ENABLE_VALIDATION false #if defined(__ANDROID__) // Lower particle count on Android for performance reasons -#define PARTICLE_COUNT 512 * 1024 +#define PARTICLE_COUNT 64 * 1024 #else -#define PARTICLE_COUNT 2048 * 1024 +#define PARTICLE_COUNT 256 * 1024 #endif class VulkanExample : public VulkanExampleBase { -private: - vkTools::VulkanTexture textureColorMap; public: float timer = 0.f; float animStart = 20.0f; bool animate = true; + struct { + vkTools::VulkanTexture particle; + vkTools::VulkanTexture gradient; + } textures; + struct { VkPipelineVertexInputStateCreateInfo inputState; std::vector bindingDescriptions; @@ -76,9 +81,11 @@ public: struct Particle { glm::vec2 pos; glm::vec2 vel; + glm::vec4 gradientPos; }; VkPipelineLayout pipelineLayout; + VkDescriptorSet descriptorSetPostCompute; VkDescriptorSetLayout descriptorSetLayout; VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) @@ -105,6 +112,15 @@ public: vkDestroyPipelineLayout(device, computePipelineLayout, nullptr); vkDestroyDescriptorSetLayout(device, computeDescriptorSetLayout, nullptr); vkDestroyPipeline(device, pipelines.compute, nullptr); + + textureLoader->destroyTexture(textures.particle); + textureLoader->destroyTexture(textures.gradient); + } + + void loadTextures() + { + textureLoader->loadTexture(getAssetPath() + "textures/particle01_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM, &textures.particle, false); + textureLoader->loadTexture(getAssetPath() + "textures/particle_gradient_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM, &textures.gradient, false); } void buildCommandBuffers() @@ -131,15 +147,12 @@ public: renderPassBeginInfo.clearValueCount = 2; renderPassBeginInfo.pClearValues = clearValues; - VkResult err; - for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) { // Set target frame buffer renderPassBeginInfo.framebuffer = frameBuffers[i]; - err = vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo); - assert(!err); + VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); // Buffer memory barrier to make sure that compute shader // writes are finished before using the storage buffer @@ -166,23 +179,15 @@ public: vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - VkViewport viewport = vkTools::initializers::viewport( - (float)width, - (float)height, - 0.0f, - 1.0f + VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f ); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); - VkRect2D scissor = vkTools::initializers::rect2D( - width, - height, - 0, - 0 - ); + VkRect2D scissor = vkTools::initializers::rect2D(width, height, 0, 0); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.postCompute); + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSetPostCompute, 0, NULL); VkDeviceSize offsets[1] = { 0 }; vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &computeStorageBuffer.buffer, offsets); @@ -190,8 +195,7 @@ public: vkCmdEndRenderPass(drawCmdBuffers[i]); - err = vkEndCommandBuffer(drawCmdBuffers[i]); - assert(!err); + VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); } } @@ -212,11 +216,8 @@ public: void draw() { - VkResult err; - // Get next image in the swap chain (back/front buffer) - err = swapChain.acquireNextImage(semaphores.presentComplete, ¤tBuffer); - assert(!err); + VK_CHECK_RESULT(swapChain.acquireNextImage(semaphores.presentComplete, ¤tBuffer)); submitPostPresentBarrier(swapChain.buffers[currentBuffer].image); @@ -225,27 +226,22 @@ public: submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; // Submit to queue - err = vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); - assert(!err); + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); submitPrePresentBarrier(swapChain.buffers[currentBuffer].image); - err = swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete); - assert(!err); + VK_CHECK_RESULT(swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete)); // Compute VkSubmitInfo computeSubmitInfo = vkTools::initializers::submitInfo(); computeSubmitInfo.commandBufferCount = 1; computeSubmitInfo.pCommandBuffers = &computeCmdBuffer; - err = vkQueueSubmit(computeQueue, 1, &computeSubmitInfo, VK_NULL_HANDLE); - assert(!err); + VK_CHECK_RESULT(vkQueueSubmit(computeQueue, 1, &computeSubmitInfo, VK_NULL_HANDLE)); - err = vkQueueWaitIdle(queue); - assert(!err); + VK_CHECK_RESULT(vkQueueWaitIdle(queue)); - err = vkQueueWaitIdle(computeQueue); - assert(!err); + VK_CHECK_RESULT(vkQueueWaitIdle(computeQueue)); } // Setup and fill the compute shader storage buffers for @@ -262,6 +258,7 @@ public: { particle.pos = glm::vec2(rDistribution(rGenerator), rDistribution(rGenerator)); particle.vel = glm::vec2(0.0f); + particle.gradientPos.x = particle.pos.x / 2.0f; } uint32_t storageBufferSize = particleBuffer.size() * sizeof(Particle); @@ -319,7 +316,7 @@ public: // Attribute descriptions // Describes memory layout and shader positions - vertices.attributeDescriptions.resize(1); + vertices.attributeDescriptions.resize(2); // Location 0 : Position vertices.attributeDescriptions[0] = vkTools::initializers::vertexInputAttributeDescription( @@ -327,6 +324,13 @@ public: 0, VK_FORMAT_R32G32_SFLOAT, 0); + // Location 1 : Gradient position + vertices.attributeDescriptions[1] = + vkTools::initializers::vertexInputAttributeDescription( + VERTEX_BUFFER_BIND_ID, + 1, + VK_FORMAT_R32G32B32A32_SFLOAT, + 4 * sizeof(float)); // Assign to vertex buffer vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo(); @@ -341,7 +345,8 @@ public: std::vector poolSizes = { vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), - vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1) + vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1), + vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2) }; VkDescriptorPoolCreateInfo descriptorPoolInfo = @@ -350,30 +355,74 @@ public: poolSizes.data(), 2); - VkResult vkRes = vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool); - assert(!vkRes); + VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); } void setupDescriptorSetLayout() { + std::vector setLayoutBindings; + // Binding 0 : Particle color map + setLayoutBindings.push_back(vkTools::initializers::descriptorSetLayoutBinding( + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + VK_SHADER_STAGE_FRAGMENT_BIT, + 0)); + // Binding 1 : Particle gradient ramp + setLayoutBindings.push_back(vkTools::initializers::descriptorSetLayoutBinding( + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + VK_SHADER_STAGE_FRAGMENT_BIT, + 1)); - VkDescriptorSetLayoutCreateInfo descriptorLayoutInfo; - descriptorLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorLayoutInfo.pNext = NULL; - descriptorLayoutInfo.flags = 0; - descriptorLayoutInfo.bindingCount = 0; - descriptorLayoutInfo.pBindings = nullptr; + VkDescriptorSetLayoutCreateInfo descriptorLayout = + vkTools::initializers::descriptorSetLayoutCreateInfo( + setLayoutBindings.data(), + setLayoutBindings.size()); - VkResult err = vkCreateDescriptorSetLayout(device, &descriptorLayoutInfo, nullptr, &descriptorSetLayout); - assert(!err); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); - VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vkTools::initializers::pipelineLayoutCreateInfo( &descriptorSetLayout, - 0); + 1); - err = vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout); - assert(!err); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + } + + void setupDescriptorSet() + { + VkDescriptorSetAllocateInfo allocInfo = + vkTools::initializers::descriptorSetAllocateInfo( + descriptorPool, + &descriptorSetLayout, + 1); + + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSetPostCompute)); + + // Image descriptor for the color map texture + std::vector texDescriptors; + texDescriptors.push_back(vkTools::initializers::descriptorImageInfo( + textures.particle.sampler, + textures.particle.view, + VK_IMAGE_LAYOUT_GENERAL)); + texDescriptors.push_back(vkTools::initializers::descriptorImageInfo( + textures.gradient.sampler, + textures.gradient.view, + VK_IMAGE_LAYOUT_GENERAL)); + + std::vector writeDescriptorSets; + // Binding 0 : Particle color map + writeDescriptorSets.push_back(vkTools::initializers::writeDescriptorSet( + descriptorSetPostCompute, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 0, + &texDescriptors[0])); + // Binding 1 : Particle gradient ramp + writeDescriptorSets.push_back(vkTools::initializers::writeDescriptorSet( + descriptorSetPostCompute, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 1, + &texDescriptors[1])); + + vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); } // Create a separate command buffer for compute commands @@ -385,14 +434,11 @@ public: VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); - VkResult vkRes = vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &computeCmdBuffer); - assert(!vkRes); + VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &computeCmdBuffer)); } void preparePipelines() { - VkResult err; - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vkTools::initializers::pipelineInputAssemblyStateCreateInfo( VK_PRIMITIVE_TOPOLOGY_POINT_LIST, @@ -475,8 +521,7 @@ public: blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_DST_ALPHA; - err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.postCompute); - assert(!err); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.postCompute)); } void prepareCompute() @@ -503,12 +548,7 @@ public: setLayoutBindings.data(), setLayoutBindings.size()); - VkResult err = vkCreateDescriptorSetLayout( - device, - &descriptorLayout, - nullptr, - &computeDescriptorSetLayout); - assert(!err); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &computeDescriptorSetLayout)); VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = @@ -516,12 +556,7 @@ public: &computeDescriptorSetLayout, 1); - err = vkCreatePipelineLayout( - device, - &pPipelineLayoutCreateInfo, - nullptr, - &computePipelineLayout); - assert(!err); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &computePipelineLayout)); VkDescriptorSetAllocateInfo allocInfo = vkTools::initializers::descriptorSetAllocateInfo( @@ -529,8 +564,7 @@ public: &computeDescriptorSetLayout, 1); - err = vkAllocateDescriptorSets(device, &allocInfo, &computeDescriptorSet); - assert(!err); + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &computeDescriptorSet)); std::vector computeWriteDescriptorSets = { @@ -556,8 +590,7 @@ public: computePipelineLayout, 0); computePipelineCreateInfo.stage = loadShader(getAssetPath() + "shaders/computeparticles/particle.comp.spv", VK_SHADER_STAGE_COMPUTE_BIT); - err = vkCreateComputePipelines(device, pipelineCache, 1, &computePipelineCreateInfo, nullptr, &pipelines.compute); - assert(!err); + VK_CHECK_RESULT(vkCreateComputePipelines(device, pipelineCache, 1, &computePipelineCreateInfo, nullptr, &pipelines.compute)); } // Prepare and initialize uniform buffer containing shader uniforms @@ -580,7 +613,7 @@ public: void updateUniformBuffers() { - computeUbo.deltaT = frameTimer * 4.0f; + computeUbo.deltaT = frameTimer * 2.5f; if (animate) { computeUbo.destX = sin(glm::radians(timer*360.0)) * 0.75f; @@ -627,6 +660,7 @@ public: void prepare() { VulkanExampleBase::prepare(); + loadTextures(); getComputeQueue(); createComputeCommandBuffer(); prepareStorageBuffers(); @@ -634,8 +668,9 @@ public: setupDescriptorSetLayout(); preparePipelines(); setupDescriptorPool(); + setupDescriptorSet(); prepareCompute(); - buildCommandBuffers(); + buildCommandBuffers(); buildComputeCommandBuffer(); prepared = true; } diff --git a/data/shaders/computeparticles/particle.comp b/data/shaders/computeparticles/particle.comp index 7209c481..b9848140 100644 --- a/data/shaders/computeparticles/particle.comp +++ b/data/shaders/computeparticles/particle.comp @@ -7,6 +7,7 @@ struct Particle { vec2 pos; vec2 vel; + vec4 gradientPos; }; // Binding 0 : Position storage buffer @@ -71,5 +72,8 @@ void main() // Write back particles[index].vel.xy = vVel; + particles[index].gradientPos.x += 0.02 * ubo.deltaT; + if (particles[index].gradientPos.x > 1.0) + particles[index].gradientPos.x -= 1.0; } diff --git a/data/shaders/computeparticles/particle.comp.spv b/data/shaders/computeparticles/particle.comp.spv index ca56a5e57cbfbbb5b2e4559fc326ff2f1e5195d0..7a800bfa3968ef584efddcbc30369bd1db95761c 100644 GIT binary patch literal 5212 zcmZve`FCAa6~}K$`qGx#31~rRNT>r^7SvKEOQ9*Tp*2b^f`UuZo0r=VNZ*SuFL6TK zGAK@niUWgM#Q_yc6~T%!h_j|D@PmJei(xHXem?h|U0$EPS$pmM{qBAC-shZs-%ZyE zYkIP59)An67qiy0JUaoLWhZ8pQV$JZJ$&wTbL`v=7pya4N!C>c8ncv``RHzBPd-u8 zu?<-UFSoq3#a78!*+up&dk)Z@EzE|7M+SCo8JRAo@Cee|ZH+MGT% z2G>Mwd}K1OjnCxc#mI*B>!$MR&D8HcrvCh_CtFO7yxDBz)#gOKcJ}P<^&1spyRt?2 zrs~t!^V#FkxE)Y1J!P+rVrph``k1BV+9hpkm;T?{?ra6zSTWhm(dJ(z9?bVl6=Q?- zrd)Tn8g8OCJ2)}j1Xr@NUdLC=j22_SGVVO|>$xh~`QT>W7%!SG&1==76}J_BqBd51 ztX#LCJpb{@k)g@@Xg;~EHe0Xe9>TW4(%+TsKwq=vs`BQveabrT&yI55)mSmz{2Y5YP$>NIoOpPrP-IeV`&y3c~eS8>u_S#|+1)iUcpm(G-a!!hz zkM|PT9%flq;ZMKy#~TbmQEPfx*72ORjnVdrez?vurdqPCv$_d;w!G;Uc3|C8D_?gu zTjIFCO7;ox@y>iNyd%2@?VaxLzy~|fG~^_1+`aa*+V$Eiv7+88;`#9^vA#aAy~-*5^s_M8@`^Dl z6K9^aVD;$;&*g!8OStbSUJKr`tJoO+&ES{jRvbQs^}bhqh>!W-g|@!DJq{(?J?Os@ zJr9xJn6UF8XMWdhM|_NbH(H;(^{y)U7S~Jn-nDxOY5BXe_rZBC`mG~&7UZmB+|@|* z#p_@Cea z`*r;|+V$2F*Aup%h;JlLEPp$4WNvs<;Jd+Dw(l9SXZQeO{_sDHePnL#X#8W~EZaN~ z{-;5U{{7&kvHp3m^M4N2hS1KeoMP?^IU{@aynH<0mtp))dIrwNR>VDtolAcs+p)h> z?bzR`cI@v|VCUK2slevj+ky9YV1J+5;}0b~K$p(jFyc%)hnv#5y(jUPu_OBzhwr`E za;|rdu0fnN=gSyp>RLqpmXz-Ui95&|XU*@5dE{TB#)r^8uM)5CdPL5%)P9Xy)Rv1r z_#~!2ddk_k5$wDJ;KRMBNJZM-m?~ey5CSAm%j2@2LC^^4RMP;yQWjI1h5s!$+~@0{g#!z1)`8e;nHw zdDlBXauNSYY`MU>ywN4JF(^B{6B~7`Ny5Q zx6dQ;QTGeju9J^EU&MBAQTI#Oa>iO$pPY4kNAE)9wj<`S&X*DS!^HRwd?j&rqaPwh z?yHISowx_v$9F>hYlxihfp*mTI(BERZ@|evnQDC#Tdo&*h4qm~{U2_@+TTL#$#=|n zYeZl7V(YiB`_Vr3C4V0xXJ6XU*SE3l%iqa3gYRI=#~FMVTh24EugIg0z7Akp+g^>g zM)dVP>;s5>J&5+PFZu5ya`vSiefm`6KU>*zI|L18%*`t-QYlM_yxhBj%MiHu5}$Z65F6-|1(NorrxH zQ$atA$lpPX_;<+D$g{`*Uv1YtheSPdHjwQ|}L0MPlurv16^i&ia3WGbU#Euh??Vuygr$w2yPC?{A2l_o*Fq=dj!B9sx&PeVujx z0cVWgp9=b)h@5q!_kUp@FNgcq=NjiA`ceDMzZmgGcz>rO(<8~9{wYsRPcsFA2=6{w=1MdI; literal 4684 zcmZvd_j6QL6vrQINI;RMfQ=Bujw6Uz5hWOjXjJTNG}$DN7!12H*~G3v#NK=Fy#`d_)SfIPU_F>WHLNS_D!0z zv9s&auH#2*{l~93X_+1~l2YcV&rE!#Fg9VE%7Yar)?u^I)n;c{ZkB|VC88(EuaKr> zTGH9o-G0fM?$LC(JW{Tu-J>^@`_qx`YVXFhuQs~34^xAcf$pJlWnip4kan+FzHGSM zcO&_m_R2pcX-TG&qg<2If)ymQ18M)56%3RGVY1hoSX=+l}85BnoG--zO?SQ7JabNpWc$Ko0^^fz)*MRP_?%_w5~E< z?JIi->pHUeQnH@$@--J_Hz)SV@?4he*1W6!bhLIAqc^Od_ojArrnO|6oxs)A2K$E6 zv#VnjwupBrxrA}7x0>zaI`H@v=@0{aN^(8p`h1O=oucOBy#%+0ah4gc2kZqk^Ar0- zUal?k>CM#onGAx*vm34RO>k>h@(#u_9{1Fo+zS7{v%L%5)^xq=CK~vs4SZXHcjE86 zV2>S&olAr`@5OMR(A=wT-U?s6YI>|1219vd+x=&a`XB){}ZEUa1gdXT{M|-5vyG|nU-U9O`mzWW}GE($3rllvx2u~bYeGO0$aidGpAIZ;)pIhrs%&d=j~K!FLhz|n?1HFKc@?F{Y-Xb z{qmT*5Ul2Ud*pJ=KC*Z8v0tvh)bGgSU72g2vBo~~f515EzmwxyMxVd%ckUWY&9fB$ z&8>;mqKu2v|*D^E#(y9^cVNF}3qBW0>bLOno~(z5`F>n%}4o z@KJj**L^3R2K)FUsriT`yyC2CstE;|yK{t9b_26>%J+uGhilwpRVk z5p}%*cHX+)V)U`DHyGc<)T~P!b-fL4tm_>#^*FD0!D?|{5yvs=dJk-FYt`Qz*6{(O zk9FwtKK2b}9pdPz55e~4-T1XIeuSw-AAXW+A2Y_9&%oAh&wa`$kGapm@s4c+%i|sU z0z4gajdPLXE3k84Vw>}K>T9sMor`x$&HHh0?!*0c5nMJ#((u3uxsV>80RxY`1Hk5tZ}nWTKI+zPKDF>a5Udvb zpq$6I`e3*|>fT>7>!F`H-FasVvF%xVb%w~)}SPCxo!HGGKI+wv+7yJaUG2@<>gY{8&pT<)Q{}o`h z;3wrg?)hZ6KI(CAr-0+$oHwp@sYjes!4cQyi1=mkK ddgV;8z2aQl!&zYSI~Q6zSba6--N?P0e*ujbzYYKZ diff --git a/data/shaders/computeparticles/particle.frag b/data/shaders/computeparticles/particle.frag index 9e1869d8..7f0281e8 100644 --- a/data/shaders/computeparticles/particle.frag +++ b/data/shaders/computeparticles/particle.frag @@ -3,11 +3,16 @@ #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable +layout (binding = 0) uniform sampler2D samplerColorMap; +layout (binding = 1) uniform sampler2D samplerGradientRamp; + layout (location = 0) in vec4 inColor; +layout (location = 1) in float inGradientPos; layout (location = 0) out vec4 outFragColor; void main () { - outFragColor = inColor; + vec3 color = texture(samplerGradientRamp, vec2(inGradientPos, 0.0)).rgb; + outFragColor.rgb = texture(samplerColorMap, gl_PointCoord).rgb * color; } diff --git a/data/shaders/computeparticles/particle.frag.spv b/data/shaders/computeparticles/particle.frag.spv index c4bb6a705657ed0b86184be008b50ab89181b9e3..dcc76dacbe478ae36b513f586468d33d786b7e64 100644 GIT binary patch literal 1184 zcmY+CT~8BH5Qazk0f>TtfQTP0pBE;C5HKc26D6@XH8gnP<>uIK)`ha$>@GjSKjyFU z#>DqI-4p6GlR57@bKaRV+s549yx9Z&7VOBTwrX?2W=q!gvDg3BKQ61$@!9za70cG} zh19IrqBRxqTbE`ep2)Z5FXe|GH+)`=bh9CKv){Vh)ZJb``gHXBL!eC8%86&zoj}9^`84dESuURbL91T+~vYe}1p!`LAxO!+Vo)G|1Dey2$fl2(`A%TIaz}VU5f0zhW*;h&XWm&0ct`FP=37^U;~n6Q8uK4O@0lXA!=ndghj5`kJHx1dp-3-u$%EM;9QlL#9Q444 zHTPEk2) zMQ=+Ek7LZsEFU!mJ;{fjJ38}bFg^G`@W!D3T4!qDgMLS6cpMA*Xwbhar_V3V2;P-< j2@U=8Ji ubb!P_@?1cg5r|>(AU^kGOJ-#iTc9jRlm{dN#CAYEAe|uoU!WcfAO--ploYlA diff --git a/data/shaders/computeparticles/particle.vert b/data/shaders/computeparticles/particle.vert index 7b6acb4b..1ed16c13 100644 --- a/data/shaders/computeparticles/particle.vert +++ b/data/shaders/computeparticles/particle.vert @@ -4,12 +4,21 @@ #extension GL_ARB_shading_language_420pack : enable layout (location = 0) in vec2 inPos; +layout (location = 1) in vec4 inGradientPos; layout (location = 0) out vec4 outColor; +layout (location = 1) out float outGradientPos; + +out gl_PerVertex +{ + vec4 gl_Position; + float gl_PointSize; +}; void main () { - gl_PointSize = 1.0; + gl_PointSize = 8.0; outColor = vec4(0.035); + outGradientPos = inGradientPos.x; gl_Position = vec4(inPos.xy, 1.0, 1.0); } \ No newline at end of file diff --git a/data/shaders/computeparticles/particle.vert.spv b/data/shaders/computeparticles/particle.vert.spv index 70c3b3ad9e96a3f833c3376f2a8eb6b7f6436a8f..572d49b795e7b1cd512167b0462bac4921b59380 100644 GIT binary patch literal 1148 zcmY+CUu)Dr6vc0MlWl9YYprelTeDULQA&|2f>c?3h!6WvE%ZqUu^ravnv^63@yXBT zr}9Pc{3eNPXE{4_&YZb(@168}JBwxu`YqWbYsQ-O#LZT0;OBU9G}*1{)7|~&dpK6D z?~QndcFC^;{eMrh9D=eYTo*QldqQ8op61^=6xg!GlVtqyZBn_jv`lN4RA16lS0=^h zukNI-E_$?;<XQ9uduQp%HwzVM{@zgeF6oZxEID-Lu`6r$LsV*`vu3ZT zvN|hrsf*rE9bV7!`Y8M9@P*2^sf=~#>nYCbcg3tIoBe^WPg-0mKbO~vi+A8_&hiVg z^uYHa%e~FsOCeXrN;Cb}n%?s&X0h_XNAF_Aps(8k15S_OjW_Uj&vSa;`PUVNI3xcW zP0UTL2ht*8OY!tEcurrp#ksrFBJpK$ULXBc%jpx^hB&oE0{J{?`QTmb*4IlUElT&i9E%?pvB8 zfx%ty8=f`iZ)%N~9J<=>wEOh#Zo5a1xvzT%bn=1o9>nNs8EI|y>&**&51ga#408S> zCDc6DKeY@6dQCrH%K@jCtmzSbz)POD1ZpGy14Sk0+X6a%`T}Q<{33zeKIlB&`$8lz mI&DYmNLUaK+ulFW8ZUdJ7UaOYJru~79&sle|6fITDf|P07gX>7 literal 1068 zcmY+CT}vBL5Qa~atRK~ys#V)+ZKPL45fLjwv0^Qx7rF2QdR17~?n{7*En zS(sj4*?y5f&r!%F!!VAL;W!%FaBp{K6!ou7ph{2q0`)l~j$s_0+U%Fj3VS10XoX`F zOLJGaG!Z&k<}-7NyQH{q|15bvM$d|!#BTJ%+Ym_HpC zCuy8!71k>E;S#kW;HPrvnd7y`=nD+(G5P_6+hf>Z?4qj(HhEnk@UKfa_`HSp7nMcc zhVD=Uds)_mbVstHeEmsEpV~|EdF76TvswGovgvV6{!3}@gRRS=7hi)I(ox>5wD0?C z?Xx#9c;?EysxCbEZ3#U1aJ-fn^Z$r?^Rl>G_1-dzwGTJ-@!17A{{E8e&%fJ;Tk4R! zWeM0*@!TuIIqc-EG(7AJ?swAk1r8TJdj{Lr`;y20IPl*I38atpOWz9;W@o-{%D`tf zYuKqkPQa^X+0ZnPA)NOBk;4Aj}rKq5l(#a?^WSI@&J7{ BQd9r{ diff --git a/data/textures/particle_gradient_rgba.ktx b/data/textures/particle_gradient_rgba.ktx new file mode 100644 index 0000000000000000000000000000000000000000..d8ec3d60549bc3702472631c48c48a5e47d786da GIT binary patch literal 1124 zcmXxjdrZ}J7zXfjxG98%#twJ6D5Am_&fyMnfKZNdmCGq)rj8`-qytA}TGEJOqUU!G z;)D_v3ACf4>C}uOWk!x+jx?Bffk2D&^v%k$d+q75*1LW7ZqK{Dd;fX6a*WG@bh@5t zZoY162S+Ehr%I((sZ>*aRH|jQ|MhBkvO-m?uZl40 z%Oi^PCJvqG@B~zc#-X--0rkN#I2;&-L&r@xw%>qb+ch}t9f4EpRXD#j4Cj_1IPbaw zm!{9)(m04ImP?qj{UW9|48XO%AFg#5;8xoQx0>^KKnY@%YN4@O-)pn$pAYdddcG<3acocEUHm1OB<~2*_?j;NpD< z%G`sHg{_#Kz8j&bZz3$E1@n@d5uUUQB4H<@;+ha0+l1KY9Z1kMB1vmSN~9HO!h(zl z3o^qMWX)HQJ5NEuTm{8pW|Yh^V|l0_+@>hiJTIGv*RsmI%jUh1QMy69!aAYGwhFAGNK z290SHOwetO8IzjrxTDzyJAI>RfYfZIdU}Iir`M>KUZom(g*MYB+DO$@MH{Gs*3clV(t8P{kAW6J`es1-r9=9sLI&s|XD)yYOo9wf zgbay?oD~Nd8Uq;?4LMf_IbRDI5d|3;38@wMHiqH_?j=%+z;|f^-)9K?U=X;UCGcaO zz)yt&51thGxm4hnl>)y#Bk=ngfj`y>{8=gRcQtLM8mgnMq|gp(rdDdBPO{NaIzjKz z2XvOs(*+u!OLUor=qg>OQ5vUP^d(Kw9l9&pock&s-M15PY9bNG#*<(hOUBzb7huoz6f}?M(KwunhR@Sb zcR3wf2A{yjPcyJ#U?EKXi?I5WOsx3WfRbJV3ePS^PR|k;y0egeCL778a}akj7uw@_ r2tSsGIbHb(KC%@4hYH~RP60d*6vCsk2<{z4aBVM!%l=~iw-NsUd#HC5 literal 0 HcmV?d00001