From a2d5a1fd4421110deae48b1261b03c0308fcd787 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sun, 6 Oct 2024 15:17:11 +0200 Subject: [PATCH] Simplify descriptor setup Refs #1157 --- .../shadowmappingcascade.cpp | 79 ++++++------------ .../debugshadowmap.frag.spv | Bin 1020 -> 1020 bytes .../debugshadowmap.vert.spv | Bin 1304 -> 1304 bytes .../shadowmappingcascade/depthpass.frag.spv | Bin 696 -> 696 bytes .../glsl/shadowmappingcascade/depthpass.vert | 6 +- .../shadowmappingcascade/depthpass.vert.spv | Bin 1592 -> 1780 bytes shaders/glsl/shadowmappingcascade/scene.frag | 7 +- .../glsl/shadowmappingcascade/scene.frag.spv | Bin 8564 -> 9240 bytes shaders/glsl/shadowmappingcascade/scene.vert | 4 - .../glsl/shadowmappingcascade/scene.vert.spv | Bin 2400 -> 2588 bytes .../debugshadowmap.frag.spv | Bin 1608 -> 1068 bytes .../debugshadowmap.vert.spv | Bin 1780 -> 1148 bytes .../shadowmappingcascade/depthpass.frag.spv | Bin 1072 -> 792 bytes .../hlsl/shadowmappingcascade/depthpass.vert | 4 +- .../shadowmappingcascade/depthpass.vert.spv | Bin 2152 -> 1500 bytes shaders/hlsl/shadowmappingcascade/scene.frag | 9 +- .../hlsl/shadowmappingcascade/scene.frag.spv | Bin 9912 -> 6780 bytes .../hlsl/shadowmappingcascade/scene.vert.spv | Bin 3544 -> 2200 bytes 18 files changed, 41 insertions(+), 68 deletions(-) diff --git a/examples/shadowmappingcascade/shadowmappingcascade.cpp b/examples/shadowmappingcascade/shadowmappingcascade.cpp index 7aaf347b..9133a03c 100644 --- a/examples/shadowmappingcascade/shadowmappingcascade.cpp +++ b/examples/shadowmappingcascade/shadowmappingcascade.cpp @@ -62,7 +62,6 @@ public: struct UBOFS { float cascadeSplits[4]; - glm::mat4 cascadeViewProjMat[4]; glm::mat4 inverseViewMat; glm::vec3 lightDir; float _pad; @@ -76,9 +75,7 @@ public: VkPipeline sceneShadowPCF; } pipelines; - struct DescriptorSetLayouts { - VkDescriptorSetLayout base; - } descriptorSetLayouts; + VkDescriptorSetLayout descriptorSetLayout; VkDescriptorSet descriptorSet; // For simplicity all pipelines use the same push constant block layout @@ -92,12 +89,6 @@ public: VkRenderPass renderPass; VkPipelineLayout pipelineLayout; VkPipeline pipeline; - vks::Buffer uniformBuffer; - - struct UniformBlock { - std::array cascadeViewProjMat; - } ubo; - } depthPass; // Layered depth image containing the shadow cascade depths @@ -117,18 +108,17 @@ public: // Contains all resources required for a single shadow map cascade struct Cascade { VkFramebuffer frameBuffer; - VkDescriptorSet descriptorSet; VkImageView view; - float splitDepth; glm::mat4 viewProjMatrix; - void destroy(VkDevice device) { vkDestroyImageView(device, view, nullptr); vkDestroyFramebuffer(device, frameBuffer, nullptr); } }; std::array cascades; + // Per-cascade matrices will be passed to the shaders as a linear array + vks::Buffer cascadeViewProjMatricesBuffer; VulkanExample() : VulkanExampleBase() { @@ -159,9 +149,9 @@ public: vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyPipelineLayout(device, depthPass.pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.base, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - depthPass.uniformBuffer.destroy(); + cascadeViewProjMatricesBuffer.destroy(); uniformBuffers.VS.destroy(); uniformBuffers.FS.destroy(); } @@ -174,10 +164,10 @@ public: } /* - Render the example scene with given command buffer, pipeline layout and descriptor set + Render the example scene to acommand buffer using the supplied pipeline layout and for the selected shadow cascade index Used by the scene rendering and depth pass generation command buffer */ - void renderScene(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VkDescriptorSet descriptorSet, uint32_t cascadeIndex = 0) { + void renderScene(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, uint32_t cascadeIndex = 0) { // We use push constants for passing shadow cascade info to the shaders PushConstBlock pushConstBlock = { glm::vec4(0.0f), cascadeIndex }; @@ -197,10 +187,10 @@ public: glm::vec3(-1.25f, -0.25f, -1.25f), }; - for (auto position : positions) { + for (auto& position : positions) { pushConstBlock.position = glm::vec4(position, 0.0f); vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstBlock), &pushConstBlock); - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); + // This will also bind the texture images to set 1 models.tree.draw(commandBuffer, vkglTF::RenderFlags::BindImages, pipelineLayout); } } @@ -377,12 +367,11 @@ public: vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); // One pass per cascade - // The layer that this pass renders to is defined by the cascade's image view (selected via the cascade's descriptor set) for (uint32_t j = 0; j < SHADOW_MAP_CASCADE_COUNT; j++) { renderPassBeginInfo.framebuffer = cascades[j].frameBuffer; vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, depthPass.pipeline); - renderScene(drawCmdBuffers[i], depthPass.pipelineLayout, cascades[j].descriptorSet, j); + renderScene(drawCmdBuffers[i], depthPass.pipelineLayout, j); vkCmdEndRenderPass(drawCmdBuffers[i]); } } @@ -430,7 +419,7 @@ public: // Render shadowed scene vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, (filterPCF) ? pipelines.sceneShadowPCF : pipelines.sceneShadow); - renderScene(drawCmdBuffers[i], pipelineLayout, descriptorSet); + renderScene(drawCmdBuffers[i], pipelineLayout); drawUI(drawCmdBuffers[i]); @@ -470,44 +459,31 @@ public: vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1), vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, 2), + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 3), }; - VkDescriptorSetLayoutCreateInfo descriptorLayout = - vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayouts.base)); + VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); /* Descriptor sets */ - std::vector writeDescriptorSets; - VkDescriptorImageInfo depthMapDescriptor = vks::initializers::descriptorImageInfo(depth.sampler, depth.view, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); VkDescriptorSetAllocateInfo allocInfo = - vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.base, 1); + vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); // Scene rendering / debug display VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); - writeDescriptorSets = { + const std::vector writeDescriptorSets = { vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.VS.descriptor), vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &depthMapDescriptor), vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &uniformBuffers.FS.descriptor), + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3, &cascadeViewProjMatricesBuffer.descriptor), }; vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); - // Per-cascade descriptor sets - // Each descriptor set represents a single layer of the array texture - for (uint32_t i = 0; i < SHADOW_MAP_CASCADE_COUNT; i++) { - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &cascades[i].descriptorSet)); - VkDescriptorImageInfo cascadeImageInfo = vks::initializers::descriptorImageInfo(depth.sampler, depth.view, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); - writeDescriptorSets = { - vks::initializers::writeDescriptorSet(cascades[i].descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &depthPass.uniformBuffer.descriptor), - vks::initializers::writeDescriptorSet(cascades[i].descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &cascadeImageInfo) - }; - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); - } - /* Pipeline layouts */ @@ -515,7 +491,7 @@ public: // Shared pipeline layout (scene and depth map debug display) { VkPushConstantRange pushConstantRange = vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstBlock), 0); - std::array setLayouts = { descriptorSetLayouts.base, vkglTF::descriptorSetLayoutImage }; + std::array setLayouts = { descriptorSetLayout, vkglTF::descriptorSetLayoutImage }; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast(setLayouts.size())); pipelineLayoutCreateInfo.pushConstantRangeCount = 1; pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange; @@ -525,7 +501,7 @@ public: // Depth pass pipeline layout { VkPushConstantRange pushConstantRange = vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstBlock), 0); - std::array setLayouts = { descriptorSetLayouts.base, vkglTF::descriptorSetLayoutImage }; + std::array setLayouts = { descriptorSetLayout, vkglTF::descriptorSetLayoutImage }; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast(setLayouts.size())); pipelineLayoutCreateInfo.pushConstantRangeCount = 1; pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange; @@ -599,12 +575,12 @@ public: void prepareUniformBuffers() { - // Shadow map generation buffer blocks + // Cascade matrices VK_CHECK_RESULT(vulkanDevice->createBuffer( VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &depthPass.uniformBuffer, - sizeof(depthPass.ubo))); + &cascadeViewProjMatricesBuffer, + sizeof(glm::mat4) * SHADOW_MAP_CASCADE_COUNT)); // Scene uniform buffer blocks VK_CHECK_RESULT(vulkanDevice->createBuffer( @@ -619,7 +595,7 @@ public: sizeof(uboFS))); // Map persistent - VK_CHECK_RESULT(depthPass.uniformBuffer.map()); + VK_CHECK_RESULT(cascadeViewProjMatricesBuffer.map()); VK_CHECK_RESULT(uniformBuffers.VS.map()); VK_CHECK_RESULT(uniformBuffers.FS.map()); @@ -725,10 +701,11 @@ public: /* Depth rendering */ + std::vector cascadeViewProjMatrices(SHADOW_MAP_CASCADE_COUNT); for (uint32_t i = 0; i < SHADOW_MAP_CASCADE_COUNT; i++) { - depthPass.ubo.cascadeViewProjMat[i] = cascades[i].viewProjMatrix; + cascadeViewProjMatrices[i] = cascades[i].viewProjMatrix; } - memcpy(depthPass.uniformBuffer.mapped, &depthPass.ubo, sizeof(depthPass.ubo)); + memcpy(cascadeViewProjMatricesBuffer.mapped, cascadeViewProjMatrices.data(), sizeof(glm::mat4) * SHADOW_MAP_CASCADE_COUNT); /* Scene rendering @@ -736,14 +713,10 @@ public: uboVS.projection = camera.matrices.perspective; uboVS.view = camera.matrices.view; uboVS.model = glm::mat4(1.0f); - uboVS.lightDir = normalize(-lightPos); - memcpy(uniformBuffers.VS.mapped, &uboVS, sizeof(uboVS)); - for (uint32_t i = 0; i < SHADOW_MAP_CASCADE_COUNT; i++) { uboFS.cascadeSplits[i] = cascades[i].splitDepth; - uboFS.cascadeViewProjMat[i] = cascades[i].viewProjMatrix; } uboFS.inverseViewMat = glm::inverse(camera.matrices.view); uboFS.lightDir = normalize(-lightPos); diff --git a/shaders/glsl/shadowmappingcascade/debugshadowmap.frag.spv b/shaders/glsl/shadowmappingcascade/debugshadowmap.frag.spv index caa073abe89f3cf331bf5971f2698271eaee9c62..bd866c7a807e6cec89fb245de62e91b554531e8c 100644 GIT binary patch delta 18 Zcmeyv{)e5DnMs+Qfq{{Mdn4y(W&kPl1N#5~ delta 18 Zcmeyv{)e5DnMs+Qfq{{MeIw^*W&kPR1NQ&` diff --git a/shaders/glsl/shadowmappingcascade/debugshadowmap.vert.spv b/shaders/glsl/shadowmappingcascade/debugshadowmap.vert.spv index d9dad4eb6df11fb680657d56cc844bf50ca7c1c3..3892ce4361dd46521903c5ed8adbd38765c5df9a 100644 GIT binary patch delta 18 ZcmbQiHG_+jnMs+Qfq{{Mdm|@5D*zit0#^V4 delta 18 ZcmbQiHG_+jnMs+Qfq{{MeIqA7D*ziZ0#g70 diff --git a/shaders/glsl/shadowmappingcascade/depthpass.frag.spv b/shaders/glsl/shadowmappingcascade/depthpass.frag.spv index 8863bb9f4a09d302dd66a1b444aec856a9f39521..655cbbf3235cb1f8e1bc310858a76a6e735e8b76 100644 GIT binary patch delta 18 ZcmdnNx`UOInMs+Qfq{{Mdn4z1CIBEK11bOj delta 18 ZcmdnNx`UOInMs+Qfq{{MeIw_3CIBE01110f diff --git a/shaders/glsl/shadowmappingcascade/depthpass.vert b/shaders/glsl/shadowmappingcascade/depthpass.vert index 0abfbda0..c4a0f7fd 100644 --- a/shaders/glsl/shadowmappingcascade/depthpass.vert +++ b/shaders/glsl/shadowmappingcascade/depthpass.vert @@ -11,16 +11,12 @@ layout(push_constant) uniform PushConsts { uint cascadeIndex; } pushConsts; -layout (binding = 0) uniform UBO { +layout (set = 0, binding = 3) uniform UBO { mat4[SHADOW_MAP_CASCADE_COUNT] cascadeViewProjMat; } ubo; layout (location = 0) out vec2 outUV; -out gl_PerVertex { - vec4 gl_Position; -}; - void main() { outUV = inUV; diff --git a/shaders/glsl/shadowmappingcascade/depthpass.vert.spv b/shaders/glsl/shadowmappingcascade/depthpass.vert.spv index 87255aea5e6524ebe424ab9e63b89b74771d5f9b..2c6c5daf797548c335186e529319e97d3127172f 100644 GIT binary patch literal 1780 zcmYk6*-jKu5QY!T0*V_Vf{HkZ;({V7AZlC?6EMLrhQO^EVWMru8N&2LeOFXKRpmaUl=HFX*za^R zpE;9u9ZPN{jH2tk?x)pGyPE=5`4RIFlcY%}>!}(BGTfeb8{OT;Uh_?RulY@$dB)@) z$x|WE6xhes`+D2^u-e97dL-~C+&1A`QDTleeM9?YAe})opjSid$)P$ zbEEott=6H>+1;PV`wjH=t4(4Cv%7dP%TCh#T0iJ~e%nZM?k#-151p`9>~~T!N89~s z+pD%ajsA5i#r?(F5tA==CW|X&JZIAH>>hJ_B4&)3I%39%IdjCki}`J=;W3{)`

m zk(bCiwtMhY5aXkLwBLvgz={2e#hmWvD&nz*wl(cz1eUxhEN$=Sx!FSv8G~J6J@!ICs_T9vcA3+=M{zmzI4qZb$ zli0qgoE$GRPyTl*Za!`Q2JG4RadZta|7>Aj;O?=Xi)gv#)NkG^i2Moc8rpuuCb>NNoyFoz zx4HKr@@LV`6n8YoU9S1%JI@0ogdZ>DFLSd``&;5Wlxv?J@joDbqt^C4{XgdWKf_j^ zK>P-t!?v!rKHvB(;`^?U!ChZMd>`LHjx{F`@lC!yV=fn%xW~Ed=_fh#`!{Z0dDgTa zF>5&c9mE>$#2W75E+W3d^zP#x;tuUYpFH<7kLZj2-{)@rcjR_&4-qj>#1^=V*=NKS r3(UUjY$@Mu9xq?NZ}5w}`W_+HUP7G1H+hWs4cVh}YRmgerDfzF{~vCJ delta 675 zcmY+C%Su8~6o%LK+U<0~K!eI#W@R_COb9ER=qw`|N23rb2Q{}>kn;pRLzALM=m~m{ zra|9tN1+YhS$q9^?SCyc=i7Um^1`8f+{{_r#;n%&E?u^N^WoC|l1rA;_P1{DuG`(m z&QquRU{MQOHqf;%u)jJxw;1;e{<}-NqW|T(z2V)-pteb^v=B5cVk^WLoI;CSK3Y*| z@g3&*f%;!#V4DSbs&436WS;}p^q`4^!LYA$;fgCS2Qws)GxW?5!=Sm2f?Va&Qsg=R zC6efAf(R_~)zs=BO>XKgO>V11O(IQh$~Azr5_yWa1`breP8^5%Am1daR{pBj>+G6M z5S~wTq3YM8pFLgMfF#JS&WS8aAicpwS#5#ZFM!TeC+ls{nR1V~12b^JqpM{(&6egRru BE7kx2 diff --git a/shaders/glsl/shadowmappingcascade/scene.frag b/shaders/glsl/shadowmappingcascade/scene.frag index 73c3721c..9f33bed4 100644 --- a/shaders/glsl/shadowmappingcascade/scene.frag +++ b/shaders/glsl/shadowmappingcascade/scene.frag @@ -19,13 +19,16 @@ layout (location = 0) out vec4 outFragColor; layout (set = 0, binding = 2) uniform UBO { vec4 cascadeSplits; - mat4 cascadeViewProjMat[SHADOW_MAP_CASCADE_COUNT]; mat4 inverseViewMat; vec3 lightDir; float _pad; int colorCascades; } ubo; +layout (set = 0, binding = 3) uniform CVPM { + mat4 matrices[SHADOW_MAP_CASCADE_COUNT]; +} cascadeViewProjMatrices; + const mat4 biasMat = mat4( 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, @@ -84,7 +87,7 @@ void main() } // Depth compare for shadowing - vec4 shadowCoord = (biasMat * ubo.cascadeViewProjMat[cascadeIndex]) * vec4(inPos, 1.0); + vec4 shadowCoord = (biasMat * cascadeViewProjMatrices.matrices[cascadeIndex]) * vec4(inPos, 1.0); float shadow = 0; if (enablePCF == 1) { diff --git a/shaders/glsl/shadowmappingcascade/scene.frag.spv b/shaders/glsl/shadowmappingcascade/scene.frag.spv index 13cb1ce193100f3c282d8791ba62a2b5e05b5153..86a6d312a7dd162776ada2e6aeee952e059ad974 100644 GIT binary patch literal 9240 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 AY5)KL delta 446 zcmYL`%}T>i5Ju;wwGC)D{!pr*1viS~!j&;?ZTzcRh57_8r6_ixF1ix&32L_Pd;-Y} z=@a+_0nev5SUAj`Gn2{9^lkogwpI#Ot7gus7TU$6cH`oY@r!d&n!9=PY3FKm*$KGv_uW(Kv0QL8? zyz=cDEz-?jW!6Tob8bT`{R-#OwQ%NXkE{c)Tujw2s6#%%Z4viDQ}lvj%7ORAbBE+z zkXH{&u_LI%C37moWA6xs8(Ysy_b=_lJAKW7QQE>OXn^`v--Zc;RXYP+Ks~y2pLh=1 QP!l@rPPzJW{;VDN0dWH=F#rGn diff --git a/shaders/hlsl/shadowmappingcascade/debugshadowmap.frag.spv b/shaders/hlsl/shadowmappingcascade/debugshadowmap.frag.spv index 25a86e551c87d0e47ee27118d3c913457bd3d14b..9af8e1605965ffd96420dafa11f1f1effa7f3196 100644 GIT binary patch literal 1068 zcmZ9KO-~d-5Qf|R0P%xG5fD(>1#c!3;b2Gz8iItA0bzsQ$Rtc)6BjnaqH^PBdol5O zdbg92N@}X>eXFXgs;6FCn+)MW2w^(B<*PgkwJ}nUzHBQz3=OR3e%`y3sG&xP&v25X z7^iw@V($oOf_NU@4vK8!EbI02^CHX3GQW-71l;vSes=ZiOFrlpzlS$v0R%S@YsI|l zyg&F+lp}nSPAWOa|8w@#yUc#(W!ByMzI$+R^!a_tv)6mvdg7en>Sh=dk55j!J4gF_ zU9cw8RcCgdDey{PkCVGe&yBdBH=GrH@7K4UzIRr6cd?2p^7aKE@ ZQx56Q*fmr> literal 1608 zcmZ9L-A_|N5XF~%P!K;r1OyaY@xg?o5lM`R0a8n?sL;~Z;+t9RjW)66=Jr^d4XXc!l*_qkfY-YP)%#1PSrs?RHvt%+J$vPkQmYFj-Y3zaR4*2+ z-pCH(Z&5PA3u2~n+W&I&)E}0=+oas7eW*4Xt)nL)k6!=db_2%@7vt0=w!0rYl~%pR zKJuDwdgi>44dLB(W1Pn0l>Ax6fN|b;@e9r;uWCo1Z7(_=_M%I8=Gv5wZDI%Rw*HVZ z>}gN9+tXxTzbs?wZlk;qcFyg6OEw3ex$wCUpIN4PcKlGnfyXaNLOlDN=J5l+qIll4 zC?S5w`*X56!Jn56zp8GoNf#w>*b5S4ejcuydG{@V5zAYlIYAedbA1B2*bPPT9e^`G z2Y*fek~Fob1HULu9dPobyd0~WK9}-OEJ7N z^(VD+W?eS>0WXO!Ns|vw%}3Jk+=Ktv`_#bS@qXxOS3a@yv8mrZY5qSi6w6+CI}Sek z;H^0L%pZ1&&%D%`@jUY}D;RelNYfkrK2v38B$mU>zf|q6G_{yxUqU=Sxrb9e^YUH8 z?~7-?dlLG=XTJLq?r!QX_Qf|!4ETW<^1+B_=8A-Q@pcx zV%hII2{<{NQ1?VO9ETmSV=#K9ms4l|y|dvla3s`e%7)_v>`XQoJqN7iG2W%A*P^$! dvxzYVenCPnye}NR5cfa=2AA{xZ&iOT`2$)XZ=V1F diff --git a/shaders/hlsl/shadowmappingcascade/debugshadowmap.vert.spv b/shaders/hlsl/shadowmappingcascade/debugshadowmap.vert.spv index 6d67026bc7025bfdc425983556ec3fc845c1a34c..c4178cc53515ae84a5c2234f4749465b176dec0e 100644 GIT binary patch literal 1148 zcmZXSNlODk5QW=hV%%fgcgKAt=tTr^Lq$Cq#e>&T1Lj~7oQdd7@b0e?{7YU0-`D9@ z!3veG_o}+Ko^)y^YfO_drpv78AIY1PW6~Dm&6(C8`#vgH04XUEfiz?7v^}ro$e1?M zEG~Jjl?ugre0NZ-#7R_1enBj^V)!+rR*lO^xoUGao2=!jeG|nu(QWCpa$9;LGNYfG zHZ`ACnPBLnT2Bg((L>?#=<49??Ba0E#%JaK?_0ONz|QJtI#w3uYL_lc!ORFoj)ln8 zW$nP$oWLO=79W_tPlWtzGs1}H@WXXW$w?e_2V}SC45fq0$JW8j25xhh*nVO93Z=-3 z!yU58?{TMWA5Y(*)ce7?KbTtdB-!IWIB((0?yBaYevjkeeN3;7VfMhzLf?(v0@EiO z%#5M@{W_`d{R6VuF){cD9i|p|$YJ7pHOa8fDcu;+iA~I?PG56Nn3{YeaA0b(1L}f( zP3nTF$&NjyX5*VSW$I&MKWJa2j~j-D2! q@QCM@WW%w8qAIc1Wht@vcz?c!9c_>u;=^XA)Wl|=^z@}Ho6>LoOG6O= literal 1780 zcmZXU+fNfw5XKMfE+8t12;Q*;;*~V|;w8pgiYely+~|Y!jb3jYwh#^lYg_0KH_!qmXmZR*=;;&?Kbv_kKLF% zrDyh~(8EnLm1apR`wLRyhV>(k)oG{Atl9Rpk{h1AcK*v9yVJy5T4jnAPhag` zR{ETDOB;{3%hl@I(sglY^!u-N!)uY>!_Fvnqi#-oC+Q}8K2yEX%^LgGSVgRFJTR6Y%Z$Mg>7 z*3pTb79P{HAY;vHKkk@!h(jwW9~|{x3-L$fv%le^@-GZvdb9i!@(VJH2UGJPo)jjY zeAISaruES9l!sp*EUG^0Iw6C@EM{6h3(Ouf9??_e&xW4*y+%5Ret(=aH&%4xGk=fqh+qBN`Z=Jj{~Ct;k3JsTz3isf_tzrhWwOnSA2VEbh5{cxJ7mJ(-&q zGI+~fl|PufCJZcYcle{KN82itjnmIxupj%ap>IBhK##Fx4kz5PYmay ze}_H?vrY~$F}BB6&@BhGY|G%khuU5Sj_>1J;9kjx=bKm+$2q)~!Ly8eBOi|WsOcuT z%eOLO(fEG&o~Vaednco3z9Z@d6HkB4?0XqH8nXa4Z9zU9d$Z3)861mvW)KdYJ}=48 ZsSP~}96B>`S%z-&#N5LD)*H8Fe*l}Oa;5+P diff --git a/shaders/hlsl/shadowmappingcascade/depthpass.frag.spv b/shaders/hlsl/shadowmappingcascade/depthpass.frag.spv index ac6f294189f7616b4e8102c89a9eed883cbfa45e..fb4495e53014bc111613718790d9e72be68b5aa8 100644 GIT binary patch literal 792 zcmY+BOH0F05QVQvA3poAwY9BCTbDu*7b1wbP;n(iE$TLCkV4azSVedKEdQAz3ZCz# zkvMQVbI#12N9sCTd1K~`F$J@sU#x7Lnc`YbwrFxDBTpRqgAoZwC>hskYNE(BS@}05 zva09x^mP(=yZ7E8^dACobo$(lhvVqnpY(&5=~EO~owv6B(GMrXAQH8DE>(XuOJz;o z&L51tXFu}#r?>`k*{>^bYr;Er>fP`9syl zyTtWy?ym~;hjYuCK>uqo_Nxihpx-FNo^=7eB48J)W%qS~9DU!VaYI8u=evI>)0D@) VG>=?MKx0qhZ*5PE_M>=T_yv6jIRgLy literal 1072 zcmY+C+iy%!6vmgCPDfpO(MF>ZI>Zw>D5})u0r4aa+VXmEB9nBclcR(;f0j3YmP<(d ze*2s)>}1Va-?uLN+iOm@bG{#OC?aO#4!@p-=(J2XVY72F9aDJYQ8^r&=wS2FO&mjr zy3xbGBGIG%2=T$ENmZ=9DTbr+Z3UKh>g)Zz{rX8c*{(hwysxXoAItUc%F$%6s)333 z-dz8@P4%Lm?jMee4`p3!KYICKYwOv=D^1VTe>%N$k;J5|%TX#Hj(2vQ-H)^INn>;8 zU!jkAt?xVIK#o}5=P-AW@qpMPR_DKYan7G?ce4t2kxKV8jdAX0><%M7f6e%C!V#xp zChgK5?^ahnV$UiwXPPk8u2AJZ<&UIs<~A@n`;33FO=Gzq_&ifD-fV02zp358{s6ivQ0V{w diff --git a/shaders/hlsl/shadowmappingcascade/depthpass.vert b/shaders/hlsl/shadowmappingcascade/depthpass.vert index 78e70e5b..b2e848a0 100644 --- a/shaders/hlsl/shadowmappingcascade/depthpass.vert +++ b/shaders/hlsl/shadowmappingcascade/depthpass.vert @@ -1,4 +1,5 @@ // Copyright 2020 Google LLC +// Copyright 2024 Sascha Willems struct VSInput { @@ -17,8 +18,7 @@ struct PushConsts { struct UBO { float4x4 cascadeViewProjMat[SHADOW_MAP_CASCADE_COUNT]; }; - -cbuffer ubo : register(b0) { UBO ubo; } +cbuffer ubo : register(b3) { UBO ubo; } struct VSOutput { diff --git a/shaders/hlsl/shadowmappingcascade/depthpass.vert.spv b/shaders/hlsl/shadowmappingcascade/depthpass.vert.spv index de1756812400e08f17bf234787e2ff2a7dc96c67..bb2028353ca029d79c92203289aeaacc4410679f 100644 GIT binary patch literal 1500 zcmY+E*-sNu6vi)Yrv(=lkwrzEQd|(M=z}paE{F#DAX5;DuLCr3Oqgkysmq)G2mZOf znE3tf+*|7SGxKbHUWb72o^4c6X3}+RoCvh|}U9$Yquff92_Cc~T^q&0RMQ%TxO#&QIdgUMD^6 zeZw=*pPDv(pH`XR#>LrsgX0Xpx;lg7Kn3cSDL%Z8WE*!A4f7u*y|3N#?DM<0AYWAz z__&6hHA&lF;`4Sldfz$hM0=a$r4x4GY=>_@Zb#94t8);Lfo#r{hnLG9M6#tZd$SnC&$4DA z7LGeJflb&Y#MG{how6 z_>ni1UXzfQ?})tY=e`7fOO~eex`bU&8^Mk*Z@(eIzOQ_|=>rLMIG$_k4o5$pd+0d& n>#7d(Y)Xj7A3NXfFXhGdNP?YuFSHqU4ac25v#&p@@Ko{_KzUlm literal 2152 zcmZ9MYfn=_5QY~@3!;LGTvUV>@DedqV`4N$v{nO6)N`;<@y?;Ga!lxH=&6@)`VaiM zelhWVw!5Wqo9XQP&Sht2x6KSMj~X*%jF~X8zFDWuuwyb7W1Td|`ul?@ZUKfRc#KH0 zcAv3&Pll{MN^EM?pqsY4skSC3PdHYXbo!Y5+cjdwb+$3-k9M;dc02p!q}55IR(b?F z#OCzDkJU~(aT+JKo}9A7ldm3i>QSRvX*HVP@uQw8>9$X+OmNfU?0Mb21V3toV?kxr z;f(g%j|17p>>iuTUyGaH!o%dt^GF@yo9oAo+WEw-;@9Y~7zWkKRwa0GlUOFh+?;Le z=}tKaUOwsDm}SyUZQ!6WtJ>(z&mX)jT&q@EjF{TNEI(iH(R_1eMYtUuMh7-~Y~$7y z#~mJ*u)y5yf<-+{y4GOO4zX)v+iafk6;5at|w;ERd{ zGq-8kPDtk^^t9^m$^Y<#Fbg~9Oj`8wA@OIl&s*F(i&=11j~}u95d%*={G5bZ=k$F} z8h`M-zL_5!J`1Xqxxlffe{f!YXQk;6j-D?_b52Hr{k$|i!Gq@=W(MGk()e;Vn0Eoj zKBdfy(giVjY4*&KyC9#>v7|k-gfGZ`-C=lg-f$Qn@GXaZO}8EP`R)nRgRg1LVL!`~ zFg^PjlpSVX~AIH#g96e8ysiwCf-Rn!}r4bc<*?8O4@&raM#pP(ylE1 zQ34N#KRxhvb|u(+Pm%VVxv5;dojnO0%X4+@;f4mdhU4fZ)Xmd-Q$jrc*e4~wl^5G5 z3HDtHb@P5dOSl7Sq<1iW)HW);FTswD_XGB}tJ=d+Bl)jM;8^&NNW)?0J*`Tx(*yRb K(D}VrjfQFA5^H%8;+9f#ad^16 zGqW{d8`)ay8@y6bFX-OT!iYghC_C_@1u3t-kQo*b}*s zjWr3{JJ>%soJ*tr;G8}}*~cLfXZz+sSUhVpoxG|#`aTr?{G}b(CS<&}-r`7av9HuM z)L$MQK@OXzQ{J|tG(1x3DVJz=R9k(v&sp}Dw`?6M zR!L+IYdH*BsjH!IID9tmRE!BbhX*et>2SHX3l{=T=A0M__O3>0GU!^(wmt zaS8@Bi8}^g*ogG~(yH|FsInDUmyjM@MWp`Ga zcQM(zm#=T@=vcdK+~&O;+&-Em>+0Fq-MY4Yd3P4G_6c{}I7gw+W>vXk>4H}BPu`EM zovOX(o~cXOvznGk71_R&JzMSeqO6~?^(*VAY|Z)ozKa>arCoVCFsHI_Aa7UB+r97F z!(Umu%l+Q_yj?kO_dez0D{HR??)SX&c4h7McP`y}e_b;xWL#I3biS|fQ&;(}sH@HP zs&h8sV_su*=5*##cR^0)9(9|N&O9!4u68O^7kwNJ?^!GX=8F3r{&`)##_)?8eRHnZ zXC8ItIg(DMK%0PlwIta)i@jnsX9%8@zN#KTEyB2Go zlkDc3$Mluw0(%UY$9*S*LSbxi_{~GIcl9FlrzAOSp>NLlY770T@XFyI`R1eJHjK~R zk5R+DH!nJZZd%~yG9~E(FokcZzirm(EbLe63fe>;3oEMRTb=!`sXsmG{hc$Gzg_uQ z$^3*^XC$S*&hpH($9s4*@>x)I%F}pNzC&g8G55-Ssk{U2*77u{_4_vBjGqo~oT>cn zJ28g3Y0SX;uTI{3u56q|P~)gmeg@Q8m|OYmBzs4c7el=V)_6EO&w)-yvji%CEWF=n z`_;b{YJBIUyfn$ywvfBz*|dS(!1v|7)NdKoeNo5qBs&Y|xB}V)ti_y@p`Ps`Y@VOr zUzf7y=J(d6?3ws|b%ovUsY}_}`u#M&vNQ5~8L~4nZxzt4?A-IRzaJqxL%&%eJ43%s zl^8YIEZdRip>?k30>3Bmw&cUMGU>yfw>>kr$9LlX*!QfQO}%z)p2I3&PGcKGU+tXU~ zdoECCU-FM~dh+TXf?kkp(tXUa3AzDH2l_k@Yy@H31Ru6yvfY_#*^I1x2DqR6y-@eM ztVeqvP;U+L(OW6wD`(M49j(aE2j1UV37eqK@fhe9pgrcW72X)?okJPwGOxA^fjaZb zk5O|I^aWrOH~~11@R3H(&cK;ium0}W*WQdLjd;#v6Nq>*UwgK%rOzR-;%z3<2wjzV3| zunoE$>;U#Gje0JEcW(`d+!w>E&*RFJdnbDR^@$iSf>&?-cc=UGVtDn(1M9g2>aref zF9GVTM?UVtOX1yTzn)Y0NIlaQ=%ru*un+y+Z;mmj%N+V#2F8FnS!} z2aR9|yZ7_uU;~K$u7I~cSLj{=ug-Jqhp+u`Nrh0Pn`3c;63Lp^u7Z6W}t2sFi#V77f|oIgxO7j-T>5x&s*U2@vOt=t?=px z)17%6y!))jUf&Mp1NGta4tV#4&yDc?z>*osH7va?zE53tYg4b7@G2%P;Wq9A8b;Wn^EAZ;wJ;&PG1IgWrO8{`v3Vw~@`O%`=I8(m0dv zz&q^`HiDS*u(!VfYx+BI zzcl9Y4|r=Au9%14U}yPHpwFow=J79h{k1)L9^O6cFpqg7&%fahl;=O#^=Z!bROY@f z?a_9iJoXuR?oWI6*Utmk^*JTmQ_1sS+N142d7NwHc_{7KU!I4t>oYIgQ_1s4+N142 zd7R%q{-^7`dNl3v%-wGd)@#qs#~FJbo~g5sJ0kVn8{;uxoqh|9XZ*$7hzU?_k8$c} Gf&T$%Y}FC~ literal 9912 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 HqT|TFW(N!a