diff --git a/shaders/bilateral_cleanup_pass.comp b/shaders/bilateral_cleanup_pass.comp new file mode 100644 index 0000000..4dae106 --- /dev/null +++ b/shaders/bilateral_cleanup_pass.comp @@ -0,0 +1,236 @@ + +#version 460 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_EXT_nonuniform_qualifier : enable +#extension GL_GOOGLE_include_directive : enable +#extension GL_EXT_scalar_block_layout : enable +#extension GL_EXT_ray_tracing : enable +#extension GL_EXT_ray_query : enable +#extension GL_ARB_shader_clock : enable // Using clockARB +#extension GL_EXT_shader_image_load_formatted : enable // The folowing extension allow to pass images as function parameters + +#extension GL_NV_shader_sm_builtins : require // Debug - gl_WarpIDNV, gl_SMIDNV +#extension GL_ARB_gpu_shader_int64 : enable // Debug - heatmap value +#extension GL_EXT_shader_realtime_clock : enable // Debug - heatmap timing + +#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require +#extension GL_EXT_buffer_reference2 : require +#extension GL_EXT_debug_printf : enable +#extension GL_KHR_vulkan_glsl : enable + +#include "host_device.h" + +layout(push_constant) uniform _RtxState +{ + RtxState rtxState; +}; + +#include "globals.glsl" + +layout(set = 0, binding = 0) uniform image2D reflectionColor; +layout(set = 0, binding = 1) uniform image2D reflectionDirection; +layout(set = 0, binding = 2) uniform image2D reflectionPointBrdf; +layout(set = 0, binding = 3) uniform image2D filteredReflectionColor; +layout(set = 5, binding = 4) uniform image2D bilateralCleanupColor; + +const ivec2 samplePattern[4][16] = ivec2[4][16]( + ivec2[16]( + ivec2(-4, 0), + ivec2(-4, 1), + ivec2(-3, -2), + ivec2(-3, 3), + ivec2(-2, 2), + ivec2(-1, -4), + ivec2(-1, -2), + ivec2(-1, 4), + ivec2(0, -1), + ivec2(0, 1), + ivec2(1, -2), + ivec2(1, 2), + ivec2(2, -2), + ivec2(3, -1), + ivec2(3, 1), + ivec2(3, 3)), + ivec2[16]( + ivec2(-3, -3), + ivec2(-3, 0), + ivec2(-3, 2), + ivec2(-2, -1), + ivec2(-2, 0), + ivec2(-1, -3), + ivec2(-1, 2), + ivec2(0, 0), + ivec2(0, 2), + ivec2(1, -1), + ivec2(2, -3), + ivec2(2, 2), + ivec2(2, 3), + ivec2(3, -3), + ivec2(3, 0), + ivec2(4, 0)), + ivec2[16]( + ivec2(-4, -1), + ivec2(-4, 2), + ivec2(-3, 1), + ivec2(-2, -3), + ivec2(-2, -2), + ivec2(-1, -1), + ivec2(-1, 1), + ivec2(-1, 3), + ivec2(1, -4), + ivec2(1, -3), + ivec2(1, 0), + ivec2(1, 3), + ivec2(1, 4), + ivec2(2, 0), + ivec2(2, 1), + ivec2(3, -2)), + ivec2[16]( + ivec2(-4, -2), + ivec2(-3, -1), + ivec2(-2, 1), + ivec2(-2, 3), + ivec2(-1, 0), + ivec2(0, -4), + ivec2(0, -3), + ivec2(0, -2), + ivec2(0, 3), + ivec2(0, 4), + ivec2(1, 1), + ivec2(2, -1), + ivec2(2, 4), + ivec2(3, 2), + ivec2(4, -1), + ivec2(4, 1)) + ); + +const vec2 poissonDisk[8] = vec2[]( + vec2(-0.5, -0.5), + vec2( 0.5, -0.5), + vec2(-0.5, 0.5), + vec2( 0.5, 0.5), + vec2(-0.25, -0.75), + vec2( 0.25, -0.75), + vec2(-0.75, 0.25), + vec2( 0.75, 0.25) +); + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +void main() +{ + ivec2 imageRes = rtxState.size; + ivec2 imageCoords = ivec2(gl_GlobalInvocationID.xy); + + if (imageCoords.x >= imageRes.x || imageCoords.y >= imageRes.y) + return; + + // STAGE 1; Spatial reconstruction filtering + ivec2 halfImageCoords = imageCoords / 2; + + vec3 result = vec3(0.0); + float weightSum = 0.0; + + // Base sampling radius + float radius = min(imageRes.x, imageRes.y) * 0.003; + + // Get center pixel values as reference + vec4 centerColor = imageLoad(reflectionColor, halfImageCoords); + if (centerColor.a == 0.0) + { + imageStore(filteredReflectionColor, imageCoords, vec4(0.0)); + return; + } + + vec4 centerDirection = imageLoad(reflectionDirection, halfImageCoords); + vec4 centerBrdf = imageLoad(reflectionPointBrdf, halfImageCoords); + + // Add center sample contribution + float centerPdfInv = max(centerDirection.a, 0.001); + float centerWeight = max(centerColor.a * centerPdfInv, 0.0); + vec3 centerContrib = centerColor.rgb * centerWeight; + result += centerContrib; + weightSum += centerWeight; + + uint quadID = (imageCoords.y & 0x1) << 1 + (imageCoords.x & 0x1); + float variance = 0.0; + + for (int i = 0; i < 16; ++i) + { + ivec2 offset = samplePattern[quadID][i]; + ivec2 neighborCoords = halfImageCoords + offset; + + vec4 neighborColor = imageLoad(reflectionColor, neighborCoords); + if (neighborColor.a == 0.0) + continue; + + float brdfWeight = neighborColor.a; + float pdfInv = max(imageLoad(reflectionDirection, neighborCoords).a, 1e-5); + + // Combine BRDF weight with distance weight + float weight = max(brdfWeight * pdfInv, 0.0); + vec3 contrib = neighborColor.rgb * weight; + vec3 diff = contrib - centerContrib; + variance += dot(diff, diff); + + result += contrib; + weightSum += weight; + } + + // Normalize result + if (weightSum > 1e-5) { + result /= weightSum; + } else { + result = centerColor.rgb; + } + + // temporal accumulation + //float ratio = 1.0 / min(64.0, (1.0 + float(rtxState.frame))); + //vec3 colPrev = imageLoad(filteredReflectionColor, imageCoords).rgb; + //result = mix(colPrev, result, ratio); + + imageStore(filteredReflectionColor, imageCoords, vec4(result, sqrt(variance))); + //barriering is fine for now, if we need to optimize, maybe spliting different stage into seperate shader will be good + memoryBarrier(); + barrier(); + + // STAGE 2: bilateral filter + if(sqrt(variance) > 2.0 && !(length (centerColor.rgb ) < 0.001) ){ + result = vec3(0.0); + weightSum = 0.0; + // Define sigma values + float sigmaS = clamp (sqrt(variance) , 2.0, 6.0); + float sigmaR = 0.5; + // Define a kernel radius for the spatial domain + int kernelRadius = int(0.25 * sigmaS); + for (int y = -kernelRadius; y <= kernelRadius; ++y) { + for (int x = -kernelRadius; x <= kernelRadius; ++x) { + ivec2 neighborCoords = imageCoords + ivec2(x, y); + // Boundary check + if (neighborCoords.x < 0 || neighborCoords.y < 0 || + neighborCoords.x >= imageRes.x || neighborCoords.y >= imageRes.y) + continue; + vec4 neighborColor = imageLoad(filteredReflectionColor, neighborCoords); + if(length (neighborColor.rgb) < 0.001) continue; + // Spatial weight + float dist2 = float(x * x + y * y); + float spatialWeight = exp(-dist2 / (2.0 * sigmaS * sigmaS)); + // Range weight + float colorDiff = length(neighborColor.rgb - centerColor.rgb); + float rangeWeight = exp(-colorDiff * colorDiff / (2.0 * sigmaR * sigmaR)); + // Combined weight + float weight = spatialWeight * rangeWeight; + result += neighborColor.rgb * weight; + weightSum += weight; + } + } + // Normalize result + if (weightSum > 1e-5) { + result /= weightSum; + } else { + result = centerColor.rgb; + } + } + + imageStore(filteredReflectionColor, imageCoords, vec4(result, 1.0)); +} \ No newline at end of file diff --git a/shaders/lightPass.frag b/shaders/lightPass.frag index ddf51c0..68e77a4 100644 --- a/shaders/lightPass.frag +++ b/shaders/lightPass.frag @@ -73,10 +73,11 @@ layout(set = 4, binding = 2) uniform sampler2D gbufferDepth; layout(set = 5, binding = eSampler) uniform sampler2D indirectLightMap; -layout(set = 6, binding = 4) uniform sampler2D reflectionColor; -layout(set = 6, binding = 5) uniform sampler2D reflectionDirection; -layout(set = 6, binding = 6) uniform sampler2D reflectionPointBrdf; -layout(set = 6, binding = 7) uniform sampler2D filteredReflectionColor; +layout(set = 6, binding = 5) uniform sampler2D reflectionColor; +layout(set = 6, binding = 6) uniform sampler2D reflectionDirection; +layout(set = 6, binding = 7) uniform sampler2D reflectionPointBrdf; +layout(set = 6, binding = 8) uniform sampler2D filteredReflectionColor; +layout(set = 6, binding = 9) uniform sampler2D bilateralCleanupColor; vec3 hsv2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); diff --git a/shaders/reflection_generation.comp b/shaders/reflection_generation.comp index 55b2ef7..322f866 100644 --- a/shaders/reflection_generation.comp +++ b/shaders/reflection_generation.comp @@ -50,6 +50,7 @@ layout(set = 5, binding = 0) uniform image2D reflectionColor; layout(set = 5, binding = 1) uniform image2D reflectionDirection; layout(set = 5, binding = 2) uniform image2D reflectionPointBrdf; layout(set = 5, binding = 3) uniform image2D filteredReflectionColor; +layout(set = 5, binding = 4) uniform image2D bilateralCleanupColor; float brdfWeight(vec3 V, vec3 N, vec3 L, float roughness) { diff --git a/shaders/temporal_spatial_pass.comp b/shaders/temporal_spatial_pass.comp index 03191a8..c7529fc 100644 --- a/shaders/temporal_spatial_pass.comp +++ b/shaders/temporal_spatial_pass.comp @@ -30,6 +30,7 @@ layout(set = 0, binding = 0) uniform image2D reflectionColor; layout(set = 0, binding = 1) uniform image2D reflectionDirection; layout(set = 0, binding = 2) uniform image2D reflectionPointBrdf; layout(set = 0, binding = 3) uniform image2D filteredReflectionColor; +layout(set = 5, binding = 4) uniform image2D bilateralCleanupColor; const ivec2 samplePattern[4][16] = ivec2[4][16]( ivec2[16]( @@ -175,25 +176,6 @@ void main() weightSum += weight; } - // Sample with distance-based weights -// for (int i = 0; i < 8; i++) { -// ivec2 offset = ivec2(poissonDisk[i] * radius); -// ivec2 neighborCoords = halfImageCoords + offset; -// -// vec4 neighborColor = imageLoad(reflectionColor, neighborCoords); -// if (neighborColor.a == 0.0) -// continue; -// -// float brdfWeight = neighborColor.a; -// float pdfInv = max(imageLoad(reflectionDirection, neighborCoords).a, 1e-5); -// -// // Combine BRDF weight with distance weight -// float weight = max(brdfWeight * pdfInv, 0.0); -// -// result += neighborColor.rgb * weight; -// weightSum += weight; -// } - // Normalize result if (weightSum > 1e-5) { result /= weightSum; diff --git a/src/bilateral_cleanup_pass.cpp b/src/bilateral_cleanup_pass.cpp new file mode 100644 index 0000000..59312ae --- /dev/null +++ b/src/bilateral_cleanup_pass.cpp @@ -0,0 +1,77 @@ +#include "bilateral_cleanup_pass.h" + +#include "nvvk/images_vk.hpp" +#include "nvh/alignment.hpp" +#include "nvh/fileoperations.hpp" +#include "nvvk/shaders_vk.hpp" +#include "scene.hpp" +#include "tools.hpp" +#include "nvvk/commands_vk.hpp" +#include "shaders/host_device.h" + +#include "autogen/temporal_spatial_pass.comp.h" + +void BilateralCleanupPass::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t familyIndex, nvvk::ResourceAllocator* allocator) +{ + m_device = device; + m_pAlloc = allocator; + m_queueIndex = familyIndex; + m_debug.setup(device); +} + +void BilateralCleanupPass::destroy() +{ + vkDestroyPipeline(m_device, m_pipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + + m_pipelineLayout = VK_NULL_HANDLE; + m_pipeline = VK_NULL_HANDLE; +} + +void BilateralCleanupPass::run(const VkCommandBuffer& cmdBuf, const VkExtent2D& size, nvvk::ProfilerVK& profiler, const std::vector& descSets) +{ + LABEL_SCOPE_VK(cmdBuf); + const int GROUP_SIZE = 8; + // Preparing for the compute shader + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_pipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelineLayout, 0, + static_cast(descSets.size()), descSets.data(), 0, nullptr); + + // Sending the push constant information + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(RtxState), &m_state); + + // Dispatching the shader + vkCmdDispatch(cmdBuf, (size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1); +} + +void BilateralCleanupPass::create(const VkExtent2D& fullSize, const std::vector& extraDescSetsLayout, Scene* _scene) +{ + VkExtent2D size = { fullSize.width, fullSize.height}; + + std::vector push_constants; + push_constants.push_back({ VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(RtxState) }); + + VkPipelineLayoutCreateInfo layout_info{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; + layout_info.pushConstantRangeCount = static_cast(push_constants.size()); + layout_info.pPushConstantRanges = push_constants.data(); + layout_info.setLayoutCount = static_cast(extraDescSetsLayout.size()); + layout_info.pSetLayouts = extraDescSetsLayout.data(); + vkCreatePipelineLayout(m_device, &layout_info, nullptr, &m_pipelineLayout); + + VkComputePipelineCreateInfo computePipelineCreateInfo{ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; + computePipelineCreateInfo.layout = m_pipelineLayout; + computePipelineCreateInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + computePipelineCreateInfo.stage.module = nvvk::createShaderModule(m_device, temporal_spatial_pass_comp, sizeof(temporal_spatial_pass_comp)); + computePipelineCreateInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; + computePipelineCreateInfo.stage.pName = "main"; + + vkCreateComputePipelines(m_device, {}, 1, &computePipelineCreateInfo, nullptr, &m_pipeline); + + m_debug.setObjectName(m_pipeline, "Temporal Spatial Denoise Compute Pass"); + vkDestroyShaderModule(m_device, computePipelineCreateInfo.stage.module, nullptr); +} + +const std::string BilateralCleanupPass::name() +{ + return "Reflection Compute Pass"; +} \ No newline at end of file diff --git a/src/bilateral_cleanup_pass.h b/src/bilateral_cleanup_pass.h new file mode 100644 index 0000000..9666410 --- /dev/null +++ b/src/bilateral_cleanup_pass.h @@ -0,0 +1,46 @@ +#pragma once + +#include "nvvk/resourceallocator_vk.hpp" +#include "nvvk/debug_util_vk.hpp" +#include "nvvk/descriptorsets_vk.hpp" +#include "nvh/gltfscene.hpp" +#include "nvh/fileoperations.hpp" +#include "queue.hpp" +#include "nvvk/profiler_vk.hpp" +#include "renderer.h" +#include "shaders/host_device.h" + +class BilateralCleanupPass : Renderer +{ + enum Queues + { + eGraphics, + eLoading, + eCompute, + eTransfer + }; +public: + void setup(const VkDevice& device, + const VkPhysicalDevice& physicalDevice, + uint32_t familyIndex, + nvvk::ResourceAllocator* allocator); + void destroy(); + void run(const VkCommandBuffer& cmdBuf, + const VkExtent2D& size, + nvvk::ProfilerVK& profiler, + const std::vector& descSets); + void create(const VkExtent2D& size, const std::vector& descSetsLayout, Scene* _scene = nullptr); + const std::string name(); + void setPushContants(const RtxState& state) { m_state = state; } + +private: + // Setup + nvvk::ResourceAllocator* m_pAlloc{ nullptr }; // Allocator for buffer, images, acceleration structures + nvvk::DebugUtil m_debug; // Utility to name objects + VkDevice m_device{ VK_NULL_HANDLE }; + uint32_t m_queueIndex{ 0 }; + + VkPipelineLayout m_pipelineLayout{ VK_NULL_HANDLE }; + VkPipeline m_pipeline{ VK_NULL_HANDLE }; +}; + diff --git a/src/reflection_compute_pass.cpp b/src/reflection_compute_pass.cpp index ca78a8d..485aff0 100644 --- a/src/reflection_compute_pass.cpp +++ b/src/reflection_compute_pass.cpp @@ -119,6 +119,10 @@ void ReflectionComputePass::createReflectionPassDescriptorSet(const VkExtent2D& fullSize, VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, true); + auto bilateralCleanupCreateInfo = nvvk::makeImage2DCreateInfo( + fullSize, VK_FORMAT_R16G16B16A16_SFLOAT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, + true); // create image nvvk::Image reflectColor = m_pAlloc->createImage(reflectColorCreateInfo); @@ -129,12 +133,15 @@ void ReflectionComputePass::createReflectionPassDescriptorSet(const VkExtent2D& NAME_VK(reflectBrdf.image); nvvk::Image filteredReflection = m_pAlloc->createImage(filteredReflectionCreateInfo); NAME_VK(filteredReflection.image); + nvvk::Image bilateralCleanup = m_pAlloc->createImage(bilateralCleanupCreateInfo); + NAME_VK(bilateralCleanup.image); // create image view VkImageViewCreateInfo reflectColorvInfo = nvvk::makeImageViewCreateInfo(reflectColor.image, reflectColorCreateInfo); VkImageViewCreateInfo reflectDirectionvInfo = nvvk::makeImageViewCreateInfo(reflectDirection.image, reflectDirectionCreateInfo); VkImageViewCreateInfo reflectBrdfvInfo = nvvk::makeImageViewCreateInfo(reflectBrdf.image, reflectBrdfCreateInfo); VkImageViewCreateInfo filteredReflectionvInfo = nvvk::makeImageViewCreateInfo(filteredReflection.image, filteredReflectionCreateInfo); + VkImageViewCreateInfo bilateralCleanupvInfo = nvvk::makeImageViewCreateInfo(bilateralCleanup.image, bilateralCleanupCreateInfo); // create sampler VkSamplerCreateInfo reflectColorSampler{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; @@ -153,6 +160,10 @@ void ReflectionComputePass::createReflectionPassDescriptorSet(const VkExtent2D& filteredReflectionSampler.magFilter = VK_FILTER_LINEAR; filteredReflectionSampler.minFilter = VK_FILTER_LINEAR; + VkSamplerCreateInfo bilateralCleanupSampler{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; + bilateralCleanupSampler.magFilter = VK_FILTER_LINEAR; + bilateralCleanupSampler.minFilter = VK_FILTER_LINEAR; + // create texture nvvk::Texture reflectColorTex = m_pAlloc->createTexture(reflectColor, reflectColorvInfo, reflectColorSampler); reflectColorTex.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; @@ -162,6 +173,8 @@ void ReflectionComputePass::createReflectionPassDescriptorSet(const VkExtent2D& reflectBrdfTex.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; nvvk::Texture filteredReflectionTex = m_pAlloc->createTexture(filteredReflection, filteredReflectionvInfo, filteredReflectionSampler); filteredReflectionTex.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + nvvk::Texture bilateralCleanupTex = m_pAlloc->createTexture(bilateralCleanup, bilateralCleanupvInfo, bilateralCleanupSampler); + bilateralCleanupTex.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; nvvk::CommandPool cmdBufGet(m_device, queue.familyIndex, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queue.queue); @@ -171,6 +184,7 @@ void ReflectionComputePass::createReflectionPassDescriptorSet(const VkExtent2D& nvvk::cmdBarrierImageLayout(cmdBuf, reflectDirection.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); nvvk::cmdBarrierImageLayout(cmdBuf, reflectBrdf.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); nvvk::cmdBarrierImageLayout(cmdBuf, filteredReflection.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, bilateralCleanup.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); cmdBufGet.submitAndWait(cmdBuf); @@ -178,6 +192,7 @@ void ReflectionComputePass::createReflectionPassDescriptorSet(const VkExtent2D& m_images.push_back(reflectDirectionTex); m_images.push_back(reflectBrdfTex); m_images.push_back(filteredReflectionTex); + m_images.push_back(bilateralCleanupTex); } // reflection description set @@ -188,11 +203,13 @@ void ReflectionComputePass::createReflectionPassDescriptorSet(const VkExtent2D& bind.addBinding({ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT }); bind.addBinding({ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT }); bind.addBinding({ 3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT }); + bind.addBinding({ 4, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT }); - bind.addBinding({ 4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT }); bind.addBinding({ 5, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT }); bind.addBinding({ 6, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT }); bind.addBinding({ 7, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT }); + bind.addBinding({ 8, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT }); + bind.addBinding({ 9, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT }); // allocate the descriptor set m_samplerDescSetLayout = bind.createLayout(m_device); @@ -202,21 +219,24 @@ void ReflectionComputePass::createReflectionPassDescriptorSet(const VkExtent2D& // update the descriptor set std::vector writes; - VkDescriptorImageInfo descImg[4] = { + VkDescriptorImageInfo descImg[5] = { m_images[0].descriptor, m_images[1].descriptor, m_images[2].descriptor, - m_images[3].descriptor + m_images[3].descriptor, + m_images[4].descriptor }; writes.emplace_back(bind.makeWrite(m_samplerDescSet, 0, &descImg[0])); writes.emplace_back(bind.makeWrite(m_samplerDescSet, 1, &descImg[1])); writes.emplace_back(bind.makeWrite(m_samplerDescSet, 2, &descImg[2])); writes.emplace_back(bind.makeWrite(m_samplerDescSet, 3, &descImg[3])); - writes.emplace_back(bind.makeWrite(m_samplerDescSet, 4, &descImg[0])); - writes.emplace_back(bind.makeWrite(m_samplerDescSet, 5, &descImg[1])); - writes.emplace_back(bind.makeWrite(m_samplerDescSet, 6, &descImg[2])); - writes.emplace_back(bind.makeWrite(m_samplerDescSet, 7, &descImg[3])); + writes.emplace_back(bind.makeWrite(m_samplerDescSet, 4, &descImg[4])); + writes.emplace_back(bind.makeWrite(m_samplerDescSet, 5, &descImg[0])); + writes.emplace_back(bind.makeWrite(m_samplerDescSet, 6, &descImg[1])); + writes.emplace_back(bind.makeWrite(m_samplerDescSet, 7, &descImg[2])); + writes.emplace_back(bind.makeWrite(m_samplerDescSet, 8, &descImg[3])); + writes.emplace_back(bind.makeWrite(m_samplerDescSet, 9, &descImg[4])); vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); }