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 caa073ab..bd866c7a 100644 Binary files a/shaders/glsl/shadowmappingcascade/debugshadowmap.frag.spv and b/shaders/glsl/shadowmappingcascade/debugshadowmap.frag.spv differ diff --git a/shaders/glsl/shadowmappingcascade/debugshadowmap.vert.spv b/shaders/glsl/shadowmappingcascade/debugshadowmap.vert.spv index d9dad4eb..3892ce43 100644 Binary files a/shaders/glsl/shadowmappingcascade/debugshadowmap.vert.spv and b/shaders/glsl/shadowmappingcascade/debugshadowmap.vert.spv differ diff --git a/shaders/glsl/shadowmappingcascade/depthpass.frag.spv b/shaders/glsl/shadowmappingcascade/depthpass.frag.spv index 8863bb9f..655cbbf3 100644 Binary files a/shaders/glsl/shadowmappingcascade/depthpass.frag.spv and b/shaders/glsl/shadowmappingcascade/depthpass.frag.spv differ 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 87255aea..2c6c5daf 100644 Binary files a/shaders/glsl/shadowmappingcascade/depthpass.vert.spv and b/shaders/glsl/shadowmappingcascade/depthpass.vert.spv differ 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 13cb1ce1..86a6d312 100644 Binary files a/shaders/glsl/shadowmappingcascade/scene.frag.spv and b/shaders/glsl/shadowmappingcascade/scene.frag.spv differ diff --git a/shaders/glsl/shadowmappingcascade/scene.vert b/shaders/glsl/shadowmappingcascade/scene.vert index 4ef0b3a9..4d0649f7 100644 --- a/shaders/glsl/shadowmappingcascade/scene.vert +++ b/shaders/glsl/shadowmappingcascade/scene.vert @@ -22,10 +22,6 @@ layout(push_constant) uniform PushConsts { uint cascadeIndex; } pushConsts; -out gl_PerVertex { - vec4 gl_Position; -}; - void main() { outColor = inColor; diff --git a/shaders/glsl/shadowmappingcascade/scene.vert.spv b/shaders/glsl/shadowmappingcascade/scene.vert.spv index 9f5c7a6d..e085b16a 100644 Binary files a/shaders/glsl/shadowmappingcascade/scene.vert.spv and b/shaders/glsl/shadowmappingcascade/scene.vert.spv differ diff --git a/shaders/hlsl/shadowmappingcascade/debugshadowmap.frag.spv b/shaders/hlsl/shadowmappingcascade/debugshadowmap.frag.spv index 25a86e55..9af8e160 100644 Binary files a/shaders/hlsl/shadowmappingcascade/debugshadowmap.frag.spv and b/shaders/hlsl/shadowmappingcascade/debugshadowmap.frag.spv differ diff --git a/shaders/hlsl/shadowmappingcascade/debugshadowmap.vert.spv b/shaders/hlsl/shadowmappingcascade/debugshadowmap.vert.spv index 6d67026b..c4178cc5 100644 Binary files a/shaders/hlsl/shadowmappingcascade/debugshadowmap.vert.spv and b/shaders/hlsl/shadowmappingcascade/debugshadowmap.vert.spv differ diff --git a/shaders/hlsl/shadowmappingcascade/depthpass.frag.spv b/shaders/hlsl/shadowmappingcascade/depthpass.frag.spv index ac6f2941..fb4495e5 100644 Binary files a/shaders/hlsl/shadowmappingcascade/depthpass.frag.spv and b/shaders/hlsl/shadowmappingcascade/depthpass.frag.spv differ 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 de175681..bb202835 100644 Binary files a/shaders/hlsl/shadowmappingcascade/depthpass.vert.spv and b/shaders/hlsl/shadowmappingcascade/depthpass.vert.spv differ diff --git a/shaders/hlsl/shadowmappingcascade/scene.frag b/shaders/hlsl/shadowmappingcascade/scene.frag index 6a7388f4..b02919ca 100644 --- a/shaders/hlsl/shadowmappingcascade/scene.frag +++ b/shaders/hlsl/shadowmappingcascade/scene.frag @@ -1,4 +1,5 @@ // Copyright 2020 Google LLC +// Copyright 2024 Sascha Willems #define SHADOW_MAP_CASCADE_COUNT 4 @@ -22,7 +23,6 @@ struct VSOutput struct UBO { float4 cascadeSplits; - float4x4 cascadeViewProjMat[SHADOW_MAP_CASCADE_COUNT]; float4x4 inverseViewMat; float3 lightDir; float _pad; @@ -30,6 +30,11 @@ struct UBO { }; cbuffer ubo : register(b2) { UBO ubo; }; +struct CVPM { + float4x4 matrices[SHADOW_MAP_CASCADE_COUNT]; +}; +cbuffer cascadeViewProjMatrices : register(b3) { CVPM cascadeViewProjMatrices; } + static const float4x4 biasMat = float4x4( 0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, @@ -90,7 +95,7 @@ float4 main(VSOutput input) : SV_TARGET } // Depth compare for shadowing - float4 shadowCoord = mul(biasMat, mul(ubo.cascadeViewProjMat[cascadeIndex], float4(input.Pos, 1.0))); + float4 shadowCoord = mul(biasMat, mul(cascadeViewProjMatrices.matrices[cascadeIndex], float4(input.Pos, 1.0))); float shadow = 0; if (enablePCF == 1) { diff --git a/shaders/hlsl/shadowmappingcascade/scene.frag.spv b/shaders/hlsl/shadowmappingcascade/scene.frag.spv index 38cb207c..100717b3 100644 Binary files a/shaders/hlsl/shadowmappingcascade/scene.frag.spv and b/shaders/hlsl/shadowmappingcascade/scene.frag.spv differ diff --git a/shaders/hlsl/shadowmappingcascade/scene.vert.spv b/shaders/hlsl/shadowmappingcascade/scene.vert.spv index d3fdc479..7875e028 100644 Binary files a/shaders/hlsl/shadowmappingcascade/scene.vert.spv and b/shaders/hlsl/shadowmappingcascade/scene.vert.spv differ