diff --git a/projects/voxelization/resources/shaders/msaa4XResolve.comp b/projects/voxelization/resources/shaders/msaa4XResolve.comp new file mode 100644 index 0000000000000000000000000000000000000000..746e0b1e15a064efb2c089555f373d0466099bb4 --- /dev/null +++ b/projects/voxelization/resources/shaders/msaa4XResolve.comp @@ -0,0 +1,85 @@ +#version 450 +#extension GL_ARB_texture_multisample : enable + +layout(set=0, binding=0) uniform texture2DMS srcTexture; +layout(set=0, binding=1) uniform sampler MSAASampler; +layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D outImage; + + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +float computeLuma(vec3 c){ + return dot(c, vec3(0.21, 0.72, 0.07)); +} + +vec3 tonemap(vec3 c){ + return c / (1 + computeLuma(c)); +} + +vec3 tonemapReverse(vec3 c){ + return c / (1 - computeLuma(c)); +} + +float reconstructionFilter(float d){ + // gauß filter, tuned so that distance of one has weight around 20% + float a = 1.6; + return exp(-a * d*d); +} + +void main(){ + + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outImage)))){ + return; + } + ivec2 uv = ivec2(gl_GlobalInvocationID.xy); + + vec2 samplePositions[4] = { + vec2(0.375, 0.125), + vec2(0.875, 0.375), + vec2(0.125, 0.625), + vec2(0.625, 0.875)}; + + vec3 color = vec3(0); + float wTotal = 0; + + // four samples from main pixel + for(int i = 0; i < 4; i++){ + vec3 msaaSample = texelFetch(sampler2DMS(srcTexture, MSAASampler), uv, i).rgb; + float d = distance(vec2(0.5), samplePositions[i]); + float w = reconstructionFilter(d); + color += tonemap(msaaSample) * w; + wTotal += w; + } + + ivec2 neighbourOffsets[4] = { + ivec2( 1, 0), // right + ivec2(-1, 0), // left + ivec2( 0, 1), // top + ivec2( 0, -1) // bot + }; + + int neighbourSampleIndices[8] = { + 0, 2, // left samples of right neighbour + 1, 3, // right samples of left neighbour + 2, 3, // bot samples of top neighbour + 0, 1 // top samples of bot neighbour + }; + + // two additional samples from each neighbour + for(int neighbour = 0; neighbour < 4; neighbour++){ + for(int i = 0; i < 2; i++){ + int sampleIndex = neighbourSampleIndices[neighbour * 2 + i]; + ivec2 pixelOffset = neighbourOffsets[neighbour]; + ivec2 pixelUV = uv + pixelOffset; + vec3 msaaSample = texelFetch(sampler2DMS(srcTexture, MSAASampler), pixelUV, sampleIndex).rgb; + float d = distance(vec2(0.5), samplePositions[sampleIndex] + pixelOffset); + float w = reconstructionFilter(d); + color += tonemap(msaaSample) * w; + wTotal += w; + } + } + color /= wTotal; + color = tonemapReverse(color); + + imageStore(outImage, uv, vec4(color, 0.f)); +} \ No newline at end of file diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index f5095e42ef8c7bfdd1c12097d7ba062c0c8e5ad8..6c1167389fe13a849ffd2f6afefacb4ef6496abf 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -276,6 +276,24 @@ int main(int argc, const char** argv) { tonemappingProgram, { core.getDescriptorSet(tonemappingDescriptorSet).layout }); + // resolve compute shader + vkcv::ShaderProgram resolveProgram; + compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/msaa4XResolve.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + resolveProgram.addShader(shaderStage, path); + }); + vkcv::DescriptorSetHandle resolveDescriptorSet = core.createDescriptorSet( + resolveProgram.getReflectedDescriptors()[0]); + vkcv::PipelineHandle resolvePipeline = core.createComputePipeline( + resolveProgram, + { core.getDescriptorSet(resolveDescriptorSet).layout }); + + vkcv::SamplerHandle resolveSampler = core.createSampler( + vkcv::SamplerFilterType::NEAREST, + vkcv::SamplerFilterType::NEAREST, + vkcv::SamplerMipmapMode::NEAREST, + vkcv::SamplerAddressMode::CLAMP_TO_EDGE); + // model matrices per mesh std::vector<glm::mat4> modelMatrices; modelMatrices.resize(scene.vertexGroups.size(), glm::mat4(1.f)); @@ -349,6 +367,8 @@ int main(int argc, const char** argv) { int voxelVisualisationMip = 0; float voxelizationExtent = 30.f; + bool msaaCustomResolve = true; + auto start = std::chrono::system_clock::now(); const auto appStartTime = start; while (window.isWindowOpen()) { @@ -384,6 +404,13 @@ int main(int argc, const char** argv) { vkcv::StorageImageDescriptorWrite(1, swapchainInput) }; core.writeDescriptorSet(tonemappingDescriptorSet, tonemappingDescriptorWrites); + // update resolve descriptor, color images could be changed + vkcv::DescriptorWrites resolveDescriptorWrites; + resolveDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, colorBuffer) }; + resolveDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, resolveSampler) }; + resolveDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, resolvedColorBuffer) }; + core.writeDescriptorSet(resolveDescriptorSet, resolveDescriptorWrites); + start = end; cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); cameraPosBuffer.fill({ cameraManager.getActiveCamera().getPosition() }); @@ -439,24 +466,41 @@ int main(int argc, const char** argv) { voxelization.renderVoxelVisualisation(cmdStream, viewProjectionCamera, renderTargets, voxelVisualisationMip); } - if (usingMsaa) { - core.resolveMSAAImage(cmdStream, colorBuffer, resolvedColorBuffer); - } - - const uint32_t tonemappingLocalGroupSize = 8; - const uint32_t tonemappingDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(windowWidth / static_cast<float>(tonemappingLocalGroupSize))), - static_cast<uint32_t>(glm::ceil(windowHeight / static_cast<float>(tonemappingLocalGroupSize))), + const uint32_t fullscreenLocalGroupSize = 8; + const uint32_t fulsscreenDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(windowWidth / static_cast<float>(fullscreenLocalGroupSize))), + static_cast<uint32_t>(glm::ceil(windowHeight / static_cast<float>(fullscreenLocalGroupSize))), 1 }; + if (usingMsaa) { + if (msaaCustomResolve) { + + core.prepareImageForSampling(cmdStream, colorBuffer); + core.prepareImageForStorage(cmdStream, resolvedColorBuffer); + + assert(msaa == vkcv::Multisampling::MSAA4X); // shaders is written for msaa 4x + core.recordComputeDispatchToCmdStream( + cmdStream, + resolvePipeline, + fulsscreenDispatchCount, + { vkcv::DescriptorSetUsage(0, core.getDescriptorSet(resolveDescriptorSet).vulkanHandle) }, + vkcv::PushConstantData(nullptr, 0)); + + core.recordImageMemoryBarrier(cmdStream, resolvedColorBuffer); + } + else { + core.resolveMSAAImage(cmdStream, colorBuffer, resolvedColorBuffer); + } + } + core.prepareImageForStorage(cmdStream, swapchainInput); core.prepareImageForStorage(cmdStream, resolvedColorBuffer); core.recordComputeDispatchToCmdStream( cmdStream, tonemappingPipeline, - tonemappingDispatchCount, + fulsscreenDispatchCount, { vkcv::DescriptorSetUsage(0, core.getDescriptorSet(tonemappingDescriptorSet).vulkanHandle) }, vkcv::PushConstantData(nullptr, 0)); @@ -468,6 +512,9 @@ int main(int argc, const char** argv) { gui.beginGUI(); ImGui::Begin("Settings"); + + ImGui::Checkbox("MSAA custom resolve", &msaaCustomResolve); + ImGui::DragFloat2("Light angles", &lightAnglesDegree.x); ImGui::ColorEdit3("Sun color", &lightColor.x); ImGui::DragFloat("Sun strength", &lightStrength);