diff --git a/.gitmodules b/.gitmodules index cc3bf1fcd2e1eb8117cbcc7222b04f7041fea520..e270bddb0a91069af1eff869560e8b817f7cc844 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,12 @@ [submodule "modules/upscaling/lib/FidelityFX-FSR"] path = modules/upscaling/lib/FidelityFX-FSR url = https://github.com/GPUOpen-Effects/FidelityFX-FSR.git +[submodule "lib/Vulkan-Headers"] + path = lib/Vulkan-Headers + url = https://github.com/KhronosGroup/Vulkan-Headers.git +[submodule "lib/Vulkan-Hpp"] + path = lib/Vulkan-Hpp + url = https://github.com/KhronosGroup/Vulkan-Hpp +[submodule "modules/upscaling/lib/NVIDIAImageScaling"] + path = modules/upscaling/lib/NVIDIAImageScaling + url = https://github.com/NVIDIAGameWorks/NVIDIAImageScaling.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 121d499fb2cd337c28524b89ecf1ab9d12607bdf..d47706415b6274a135a4c85aa1010fde2e959105 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,7 @@ endif() include(${vkcv_config}/Sources.cmake) message(STATUS "Framework:") +message(" - Includes: [ ${vkcv_includes} ]") message(" - Libraries: [ ${vkcv_libraries} ]") message(" - Flags: [ ${vkcv_flags} ]") diff --git a/Doxyfile b/Doxyfile index 1bc2863556f9d9de0c0a54d590c4a58c9f9ca2e3..728050856484c09c072b16c96116fabe2125917f 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.9.2 +# Doxyfile 1.9.3 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -463,7 +463,7 @@ LOOKUP_CACHE_SIZE = 0 # DOT_NUM_THREADS setting. # Minimum value: 0, maximum value: 32, default value: 1. -NUM_PROC_THREADS = 1 +NUM_PROC_THREADS = 0 #--------------------------------------------------------------------------- # Build related configuration options @@ -857,7 +857,10 @@ WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = @@ -983,7 +986,7 @@ EXCLUDE_PATTERNS = */lib/* # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test +# ANamespace::AClass, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* @@ -1360,6 +1363,13 @@ GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. @@ -1564,7 +1574,7 @@ GENERATE_TREEVIEW = YES # area (value NO) or if it should extend to the full height of the window (value # YES). Setting this to YES gives a layout similar to # https://docs.readthedocs.io with more room for contents, but less room for the -# project logo, title, and description. If either GENERATOR_TREEVIEW or +# project logo, title, and description. If either GENERATE_TREEVIEW or # DISABLE_INDEX is set to NO, this option has no effect. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1595,6 +1605,13 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + # If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for @@ -2308,15 +2325,6 @@ EXTERNAL_PAGES = YES # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = NO - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. @@ -2373,11 +2381,14 @@ DOT_FONTSIZE = 10 DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a +# graph for each documented class showing the direct and indirect inheritance +# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, +# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set +# to TEXT the direct and indirect inheritance relations will be shown as texts / +# links. +# Possible values are: NO, YES, TEXT and GRAPH. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES @@ -2506,6 +2517,13 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: @@ -2559,10 +2577,10 @@ MSCFILE_DIRS = DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = @@ -2624,6 +2642,8 @@ DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. diff --git a/README.md b/README.md index 62efc4df4a929963f8581c1c2cc66796f4c6a80d..fa0d833ea8ba66c6851296a4e12b5d06d7ab0406 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ The following modules will be provided in this repository and they will automati - [Asset-Loader](modules/asset_loader/README.md) - [Camera](modules/asset_loader/README.md) - [GUI](modules/gui/README.md) + - [Effects](modules/effects/README.md) - [Material](modules/material/README.md) - [Meshlet](modules/meshlet/README.md) - [Scene](modules/scene/README.md) diff --git a/config/lib/Vulkan.cmake b/config/lib/Vulkan.cmake index e8fe4aee3a949fa7bf9906558f8a0c558eb47cf2..5100d1b78986a7a4b4b6180b1862046cb8b4fc8c 100644 --- a/config/lib/Vulkan.cmake +++ b/config/lib/Vulkan.cmake @@ -2,7 +2,26 @@ find_package(Vulkan REQUIRED) if (Vulkan_FOUND) - list(APPEND vkcv_includes ${Vulkan_INCLUDE_DIR}) + if (NOT EXISTS ${Vulkan_INCLUDE_DIR}/vulkan/vulkan.h) + use_git_submodule("${vkcv_lib_path}/Vulkan-Headers" vulkan_headers_status) + + if (${vulkan_headers_status}) + list(APPEND vkcv_includes ${vkcv_lib}/Vulkan-Headers/include) + endif() + else() + list(APPEND vkcv_includes ${Vulkan_INCLUDE_DIR}) + endif() + + if (NOT EXISTS ${Vulkan_INCLUDE_DIR}/vulkan/vulkan.hpp) + use_git_submodule("${vkcv_lib_path}/Vulkan-Hpp" vulkan_hpp_status) + + if (${vulkan_hpp_status}) + list(APPEND vkcv_includes ${vkcv_lib}/Vulkan-Hpp) + endif() + else() + list(APPEND vkcv_includes ${Vulkan_INCLUDE_DIR}) + endif() + list(APPEND vkcv_libraries ${Vulkan_LIBRARIES}) message(${vkcv_config_msg} " Vulkan - ") diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 6343bf070fbc1003c4813d30cca30e4d32e19864..35c4756f0a32fc7ea789abbf872125437b208810 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -269,7 +269,7 @@ namespace vkcv * @return swapchain */ [[nodiscard]] - Swapchain& getSwapchain(const SwapchainHandle& handle); + Swapchain& getSwapchain(const SwapchainHandle &handle); /** * Gets the swapchain handle from the window @@ -277,7 +277,7 @@ namespace vkcv * @return the swapchain from getSwapchain( SwapchainHandle ) */ [[nodiscard]] - Swapchain& getSwapchain(const WindowHandle& handle); + Swapchain& getSwapchain(const WindowHandle &handle); /** * Returns the image width @@ -285,7 +285,7 @@ namespace vkcv * @return imageWidth */ [[nodiscard]] - uint32_t getImageWidth(const ImageHandle& image); + uint32_t getImageWidth(const ImageHandle &image); /** * Returns the image height @@ -293,7 +293,7 @@ namespace vkcv * @return imageHeight */ [[nodiscard]] - uint32_t getImageHeight(const ImageHandle& image); + uint32_t getImageHeight(const ImageHandle &image); /** * Returns the image format of the image @@ -301,7 +301,16 @@ namespace vkcv * @return imageFormat */ [[nodiscard]] - vk::Format getImageFormat(const ImageHandle& image); + vk::Format getImageFormat(const ImageHandle &image); + + /** + * @brief Returns the images amount of mip levels. + * + * @param image Image handle + * @return Amount of mip levels + */ + [[nodiscard]] + uint32_t getImageMipLevels(const ImageHandle &image); /** * @brief Creates a descriptor set layout handle by a set of descriptor bindings. diff --git a/lib/Vulkan-Headers b/lib/Vulkan-Headers new file mode 160000 index 0000000000000000000000000000000000000000..8ba8294c86d0e99fcb457bedbd573dd678ccc9b3 --- /dev/null +++ b/lib/Vulkan-Headers @@ -0,0 +1 @@ +Subproject commit 8ba8294c86d0e99fcb457bedbd573dd678ccc9b3 diff --git a/lib/Vulkan-Hpp b/lib/Vulkan-Hpp new file mode 160000 index 0000000000000000000000000000000000000000..ae1b0c36df0943795cd621a37e7f7bfd00ac958a --- /dev/null +++ b/lib/Vulkan-Hpp @@ -0,0 +1 @@ +Subproject commit ae1b0c36df0943795cd621a37e7f7bfd00ac958a diff --git a/lib/VulkanMemoryAllocator-Hpp b/lib/VulkanMemoryAllocator-Hpp index c6c3c665b6a29ae546bdec60606a3ef0757ea108..da6ea76eecf12a1decc76f58a3e096bcc555bd94 160000 --- a/lib/VulkanMemoryAllocator-Hpp +++ b/lib/VulkanMemoryAllocator-Hpp @@ -1 +1 @@ -Subproject commit c6c3c665b6a29ae546bdec60606a3ef0757ea108 +Subproject commit da6ea76eecf12a1decc76f58a3e096bcc555bd94 diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 4d89c52a039e9d5de9efb276396158e987f52118..0a7f0f0ab1b71f78c6a548caf3d82442a05dcb2b 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -5,6 +5,7 @@ set(vkcv_modules_libraries) # Add new modules here: add_subdirectory(asset_loader) add_subdirectory(camera) +add_subdirectory(effects) add_subdirectory(gui) add_subdirectory(material) add_subdirectory(meshlet) diff --git a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp index f3f55f6514a58e776abf226fd80805fbf656a809..110a941ff6703e989174eaf311118b10b41491d4 100644 --- a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp +++ b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp @@ -171,7 +171,7 @@ namespace vkcv::asset { static std::array<float, 16> calculateModelMatrix(const std::array<float, 3>& translation, const std::array<float, 3>& scale, const std::array<float, 4>& rotation, - const std::array<float, 16>& matrix){ + const std::array<float, 16>& matrix) { std::array<float, 16> modelMatrix = { 1,0,0,0, 0,1,0,0, @@ -185,32 +185,55 @@ namespace vkcv::asset { // translation modelMatrix[3] = translation[0]; modelMatrix[7] = translation[1]; - modelMatrix[11] = translation[2]; + modelMatrix[11] = -translation[2]; // flip Z to convert from GLTF to Vulkan // rotation and scale - auto a = rotation[0]; - auto q1 = rotation[1]; - auto q2 = rotation[2]; - auto q3 = rotation[3]; - - modelMatrix[0] = (2 * (a * a + q1 * q1) - 1) * scale[0]; - modelMatrix[1] = (2 * (q1 * q2 - a * q3)) * scale[1]; - modelMatrix[2] = (2 * (q1 * q3 + a * q2)) * scale[2]; - - modelMatrix[4] = (2 * (q1 * q2 + a * q3)) * scale[0]; - modelMatrix[5] = (2 * (a * a + q2 * q2) - 1) * scale[1]; - modelMatrix[6] = (2 * (q2 * q3 - a * q1)) * scale[2]; - - modelMatrix[8] = (2 * (q1 * q3 - a * q2)) * scale[0]; - modelMatrix[9] = (2 * (q2 * q3 + a * q1)) * scale[1]; - modelMatrix[10] = (2 * (a * a + q3 * q3) - 1) * scale[2]; - - // flip y, because GLTF uses y up, but vulkan -y up - modelMatrix[5] *= -1; + auto a = rotation[3]; + auto q1 = rotation[0]; + auto q2 = rotation[1]; + auto q3 = rotation[2]; + + auto s = 2 / (a * a + q1 * q1 + q2 * q2 + q3 * q3); + + auto s1 = scale[0]; + auto s2 = scale[1]; + auto s3 = -scale[2]; // flip Z to convert from GLTF to Vulkan + + modelMatrix[0] = (1 - s * (q2 * q2 + q3 * q3)) * s1; + modelMatrix[1] = ( s * (q1 * q2 - q3 * a)) * s2; + modelMatrix[2] = ( s * (q1 * q3 + q2 * a)) * s3; + + modelMatrix[4] = ( s * (q1 * q2 + q3 * a)) * s1; + modelMatrix[5] = (1 - s * (q1 * q1 + q3 * q3)) * s2; + modelMatrix[6] = ( s * (q2 * q3 - q1 * a)) * s3; + + modelMatrix[8] = ( s * (q1 * q3 - q2 * a)) * s1; + modelMatrix[9] = ( s * (q2 * q3 + q1 * a)) * s2; + modelMatrix[10] = (1 - s * (q1 * q1 + q2 * q2)) * s3; return modelMatrix; } } + + static std::array<float, 16> multiplyMatrix(const std::array<float, 16>& matrix, + const std::array<float, 16>& other) { + std::array<float, 16> result; + size_t i, j, k; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + float sum = 0.0f; + + for (k = 0; k < 4; k++) { + sum += matrix[i * 4 + k] * other[k * 4 + j]; + } + + result[i * 4 + j] = sum; + } + } + + return result; + } bool Material::hasTexture(const PBRTextureTarget target) const { return textureMask & bitflag(target); @@ -496,9 +519,23 @@ namespace vkcv::asset { try { if (path.extension() == ".glb") { - sceneObjects = fx::gltf::LoadFromBinary(path.string()); + sceneObjects = fx::gltf::LoadFromBinary( + path.string(), + { + fx::gltf::detail::DefaultMaxBufferCount, + fx::gltf::detail::DefaultMaxMemoryAllocation * 16, + fx::gltf::detail::DefaultMaxMemoryAllocation * 8 + } + ); } else { - sceneObjects = fx::gltf::LoadFromText(path.string()); + sceneObjects = fx::gltf::LoadFromText( + path.string(), + { + fx::gltf::detail::DefaultMaxBufferCount, + fx::gltf::detail::DefaultMaxMemoryAllocation, + fx::gltf::detail::DefaultMaxMemoryAllocation * 8 + } + ); } } catch (const std::system_error& err) { recurseExceptionPrint(err, path.string()); @@ -536,15 +573,54 @@ namespace vkcv::asset { scene.meshes.push_back(mesh); } - // This only works if the node has a mesh and it only loads the meshes and ignores cameras and lights - for (const auto& node : sceneObjects.nodes) { + std::vector< std::array<float, 16> > matrices; + std::vector< int32_t > parents; + + matrices.reserve(sceneObjects.nodes.size()); + parents.resize(sceneObjects.nodes.size(), -1); + + for (size_t i = 0; i < sceneObjects.nodes.size(); i++) { + const auto &node = sceneObjects.nodes[i]; + + matrices.push_back(calculateModelMatrix( + node.translation, + node.scale, + node.rotation, + node.matrix + )); + + for (int32_t child : node.children) + if ((child >= 0) && (child < parents.size())) + parents[child] = static_cast<int32_t>(i); + } + + std::vector< std::array<float, 16> > final_matrices; + final_matrices.reserve(matrices.size()); + + for (size_t i = 0; i < matrices.size(); i++) { + std::vector<int> order; + order.push_back(static_cast<int32_t>(i)); + + while (parents[ order[order.size() - 1] ] >= 0) + order.push_back(parents[ order[order.size() - 1] ]); + + std::array<float, 16> matrix = matrices[ order[order.size() - 1] ]; + + for (size_t j = order.size() - 1; j > 0; j--) { + const auto id = order[j - 1]; + const std::array<float, 16> matrix_other = matrices[ id ]; + + matrix = multiplyMatrix(matrix, matrix_other); + } + + final_matrices.push_back(matrix); + } + + for (size_t i = 0; i < sceneObjects.nodes.size(); i++) { + const auto &node = sceneObjects.nodes[i]; + if ((node.mesh >= 0) && (node.mesh < scene.meshes.size())) { - scene.meshes[node.mesh].modelMatrix = calculateModelMatrix( - node.translation, - node.scale, - node.rotation, - node.matrix - ); + scene.meshes[node.mesh].modelMatrix = final_matrices[i]; } } } diff --git a/modules/effects/CMakeLists.txt b/modules/effects/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8de9ea539cfbe9c22607a9b6deb07f683a56bbdd --- /dev/null +++ b/modules/effects/CMakeLists.txt @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 3.16) +project(vkcv_effects) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(vkcv_effects_source ${PROJECT_SOURCE_DIR}/src) +set(vkcv_effects_include ${PROJECT_SOURCE_DIR}/include) + +set(vkcv_effects_sources + ${vkcv_effects_include}/vkcv/effects/Effect.hpp + ${vkcv_effects_source}/vkcv/effects/Effect.cpp + + ${vkcv_effects_include}/vkcv/effects/BloomAndFlaresEffect.hpp + ${vkcv_effects_source}/vkcv/effects/BloomAndFlaresEffect.cpp +) + +set(vkcv_effects_shaders ${PROJECT_SOURCE_DIR}/shaders) + +include_shader(${vkcv_effects_shaders}/bloomDownsample.comp ${vkcv_effects_include} ${vkcv_effects_source}) +include_shader(${vkcv_effects_shaders}/bloomFlaresComposite.comp ${vkcv_effects_include} ${vkcv_effects_source}) +include_shader(${vkcv_effects_shaders}/bloomUpsample.comp ${vkcv_effects_include} ${vkcv_effects_source}) +include_shader(${vkcv_effects_shaders}/lensFlares.comp ${vkcv_effects_include} ${vkcv_effects_source}) + +list(APPEND vkcv_effects_sources ${vkcv_effects_source}/bloomDownsample.comp.cxx) +list(APPEND vkcv_effects_sources ${vkcv_effects_source}/bloomFlaresComposite.comp.cxx) +list(APPEND vkcv_effects_sources ${vkcv_effects_source}/bloomUpsample.comp.cxx) +list(APPEND vkcv_effects_sources ${vkcv_effects_source}/lensFlares.comp.cxx) + +list(APPEND vkcv_effects_sources ${vkcv_effects_include}/bloomDownsample.comp.hxx) +list(APPEND vkcv_effects_sources ${vkcv_effects_include}/bloomFlaresComposite.comp.hxx) +list(APPEND vkcv_effects_sources ${vkcv_effects_include}/bloomUpsample.comp.hxx) +list(APPEND vkcv_effects_sources ${vkcv_effects_include}/lensFlares.comp.hxx) + +# adding source files to the project +add_library(vkcv_effects ${vkcv_build_attribute} ${vkcv_effects_sources}) + +# link the required libraries to the module +target_link_libraries(vkcv_effects ${vkcv_effects_libraries} vkcv vkcv_shader_compiler vkcv_camera vkcv_asset_loader) + +# including headers of dependencies and the VkCV framework +target_include_directories(vkcv_effects SYSTEM BEFORE PRIVATE ${vkcv_effects_includes} ${vkcv_include} ${vkcv_shader_compiler_include} ${vkcv_camera_include} {vkcv_asset_loader_include}) + +# add the own include directory for public headers +target_include_directories(vkcv_effects BEFORE PUBLIC ${vkcv_effects_include}) + +if (vkcv_parent_scope) + list(APPEND vkcv_modules_includes ${vkcv_effects_include}) + list(APPEND vkcv_modules_libraries vkcv_effects) + + set(vkcv_modules_includes ${vkcv_modules_includes} PARENT_SCOPE) + set(vkcv_modules_libraries ${vkcv_modules_libraries} PARENT_SCOPE) +endif() diff --git a/modules/effects/README.md b/modules/effects/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4e035831381f50a66cf405c06fadbb63f4273bc0 --- /dev/null +++ b/modules/effects/README.md @@ -0,0 +1,15 @@ +# Effects + +A VkCV module to add post-processing effects to images in realtime after rendering + +## Build + +### Dependencies (required): + +| Name of dependency | Used as submodule | +|--------------------|-------------------| +| | | + +## Docs + +Here is a [link](https://vkcv.de/develop/group__vkcv__effects.html) to this module. diff --git a/modules/effects/include/vkcv/effects/BloomAndFlaresEffect.hpp b/modules/effects/include/vkcv/effects/BloomAndFlaresEffect.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f4a9d03d8afcaf3532570a0807b246a0d641e02d --- /dev/null +++ b/modules/effects/include/vkcv/effects/BloomAndFlaresEffect.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include <vector> +#include <vkcv/camera/Camera.hpp> + +#include "Effect.hpp" + +namespace vkcv::effects { + + class BloomAndFlaresEffect : public Effect { + private: + bool m_advanced; + + ComputePipelineHandle m_downsamplePipeline; + ComputePipelineHandle m_upsamplePipeline; + ComputePipelineHandle m_lensFlaresPipeline; + ComputePipelineHandle m_compositePipeline; + + DescriptorSetLayoutHandle m_downsampleDescriptorSetLayout; + std::vector<DescriptorSetHandle> m_downsampleDescriptorSets; + + DescriptorSetLayoutHandle m_upsampleDescriptorSetLayout; + std::vector<DescriptorSetHandle> m_upsampleDescriptorSets; + std::vector<DescriptorSetHandle> m_flaresDescriptorSets; + + DescriptorSetLayoutHandle m_lensFlaresDescriptorSetLayout; + DescriptorSetHandle m_lensFlaresDescriptorSet; + + DescriptorSetLayoutHandle m_compositeDescriptorSetLayout; + DescriptorSetHandle m_compositeDescriptorSet; + + ImageHandle m_blurImage; + ImageHandle m_flaresImage; + + SamplerHandle m_linearSampler; + SamplerHandle m_radialLutSampler; + + ImageHandle m_radialLut; + ImageHandle m_lensDirt; + + glm::vec3 m_cameraDirection; + uint32_t m_upsampleLimit; + + void recordDownsampling(const CommandStreamHandle &cmdStream, + const ImageHandle &input, + const ImageHandle &sample, + const std::vector<DescriptorSetHandle> &mipDescriptorSets); + + void recordUpsampling(const CommandStreamHandle &cmdStream, + const ImageHandle &sample, + const std::vector<DescriptorSetHandle> &mipDescriptorSets); + + void recordLensFlares(const CommandStreamHandle &cmdStream, + uint32_t mipLevel); + + void recordComposition(const CommandStreamHandle &cmdStream, + const ImageHandle &output); + + public: + BloomAndFlaresEffect(Core& core, + bool advanced = false); + + void recordEffect(const CommandStreamHandle &cmdStream, + const ImageHandle &input, + const ImageHandle &output) override; + + void updateCameraDirection(const camera::Camera &camera); + + void setUpsamplingLimit(uint32_t limit); + + }; + +} diff --git a/modules/effects/include/vkcv/effects/Effect.hpp b/modules/effects/include/vkcv/effects/Effect.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d068fb59404080aa421e49f6a183844e731c1c5e --- /dev/null +++ b/modules/effects/include/vkcv/effects/Effect.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include <vkcv/Core.hpp> +#include <vkcv/Handles.hpp> + +namespace vkcv::effects { + + class Effect { + protected: + Core& m_core; + + public: + explicit Effect(Core& core); + + ~Effect() = default; + + virtual void recordEffect(const CommandStreamHandle& cmdStream, + const ImageHandle& input, + const ImageHandle& output) = 0; + + }; + +} diff --git a/projects/voxelization/assets/shaders/bloomDownsample.comp b/modules/effects/shaders/bloomDownsample.comp similarity index 100% rename from projects/voxelization/assets/shaders/bloomDownsample.comp rename to modules/effects/shaders/bloomDownsample.comp diff --git a/projects/voxelization/assets/shaders/bloomFlaresComposite.comp b/modules/effects/shaders/bloomFlaresComposite.comp similarity index 97% rename from projects/voxelization/assets/shaders/bloomFlaresComposite.comp rename to modules/effects/shaders/bloomFlaresComposite.comp index 57174b73ae3b58023d01defd26f636e13cb4709c..21d67393b634c8e639c0b81669e96070c380e6f6 100644 --- a/projects/voxelization/assets/shaders/bloomFlaresComposite.comp +++ b/modules/effects/shaders/bloomFlaresComposite.comp @@ -5,12 +5,17 @@ layout(set=0, binding=0) uniform texture2D blurImage; layout(set=0, binding=1) uniform texture2D lensImage; layout(set=0, binding=2) uniform sampler linearSampler; layout(set=0, binding=3, r11f_g11f_b10f) uniform image2D colorBuffer; + +#ifdef ADVANCED_FEATURES layout(set=0, binding=4) uniform texture2D radialLUT; layout(set=0, binding=5) uniform sampler radialLUTSampler; layout(set=0, binding=6) uniform texture2D dirtTexture; +#endif layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; +#ifdef ADVANCED_FEATURES + layout( push_constant ) uniform constants{ vec3 cameraForward; }; @@ -52,6 +57,8 @@ float getLensDirtWeight(vec2 uv){ return mix(1, dirt, dirtStrength); } +#endif + void main() { if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(colorBuffer)))){ @@ -73,17 +80,17 @@ void main() float lens_weight = 0.02f; float main_weight = 1 - (bloom_weight + lens_weight); +#ifdef ADVANCED_FEATURES lens_color *= starburst(UV); float lensDirtWeight = getLensDirtWeight(UV); bloom_weight *= lensDirtWeight; lens_weight *= lensDirtWeight; +#endif composite_color.rgb = blur_color * bloom_weight + lens_color * lens_weight + main_color * main_weight; - - //composite_color.rgb = vec3(1) * starburst(UV); imageStore(colorBuffer, pixel_coord, composite_color); } \ No newline at end of file diff --git a/projects/voxelization/assets/shaders/bloomUpsample.comp b/modules/effects/shaders/bloomUpsample.comp similarity index 100% rename from projects/voxelization/assets/shaders/bloomUpsample.comp rename to modules/effects/shaders/bloomUpsample.comp diff --git a/projects/voxelization/assets/shaders/lensFlares.comp b/modules/effects/shaders/lensFlares.comp similarity index 100% rename from projects/voxelization/assets/shaders/lensFlares.comp rename to modules/effects/shaders/lensFlares.comp diff --git a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78456da209233c67735b3fb1abe1a11ad8be5736 --- /dev/null +++ b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp @@ -0,0 +1,558 @@ + +#include "vkcv/effects/BloomAndFlaresEffect.hpp" + +#include <vkcv/DrawcallRecording.hpp> +#include <vkcv/PushConstants.hpp> + +#include <vkcv/shader/GLSLCompiler.hpp> +#include <vkcv/asset/asset_loader.hpp> + +#include "bloomDownsample.comp.hxx" +#include "bloomFlaresComposite.comp.hxx" +#include "bloomUpsample.comp.hxx" +#include "lensFlares.comp.hxx" + +namespace vkcv::effects { + + static DescriptorBindings getDescriptorBindings() { + DescriptorBindings descriptorBindings = {}; + + auto binding_0 = DescriptorBinding { + 0, + DescriptorType::IMAGE_SAMPLED, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_1 = DescriptorBinding { + 1, + DescriptorType::SAMPLER, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_2 = DescriptorBinding{ + 2, + DescriptorType::IMAGE_STORAGE, + 1, + ShaderStage::COMPUTE, + false + }; + + descriptorBindings.insert(std::make_pair(0, binding_0)); + descriptorBindings.insert(std::make_pair(1, binding_1)); + descriptorBindings.insert(std::make_pair(2, binding_2)); + + return descriptorBindings; + } + + static DescriptorBindings getCompositeDescriptorBindings(bool advanced) { + DescriptorBindings descriptorBindings = {}; + + auto binding_0 = DescriptorBinding { + 0, + DescriptorType::IMAGE_SAMPLED, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_1 = DescriptorBinding { + 1, + DescriptorType::IMAGE_SAMPLED, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_2 = DescriptorBinding{ + 2, + DescriptorType::SAMPLER, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_3 = DescriptorBinding{ + 3, + DescriptorType::IMAGE_STORAGE, + 1, + ShaderStage::COMPUTE, + false + }; + + descriptorBindings.insert(std::make_pair(0, binding_0)); + descriptorBindings.insert(std::make_pair(1, binding_1)); + descriptorBindings.insert(std::make_pair(2, binding_2)); + descriptorBindings.insert(std::make_pair(3, binding_3)); + + if (advanced) { + auto binding_4 = DescriptorBinding{ + 4, + DescriptorType::IMAGE_SAMPLED, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_5 = DescriptorBinding{ + 5, + DescriptorType::SAMPLER, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_6 = DescriptorBinding{ + 6, + DescriptorType::IMAGE_SAMPLED, + 1, + ShaderStage::COMPUTE, + false + }; + + descriptorBindings.insert(std::make_pair(4, binding_4)); + descriptorBindings.insert(std::make_pair(5, binding_5)); + descriptorBindings.insert(std::make_pair(6, binding_6)); + } + + return descriptorBindings; + } + + static ImageHandle loadTexture(Core &core, + const std::string &texturePath) { + const auto texture = vkcv::asset::loadTexture(texturePath); + + Image image = core.createImage( + vk::Format::eR8G8B8A8Unorm, + texture.width, + texture.height + ); + + image.fill(texture.data.data(), texture.data.size()); + return image.getHandle(); + } + + static ComputePipelineHandle compilePipeline(Core &core, + const std::string &shaderSource, + const DescriptorSetLayoutHandle &descriptorSetLayout, + bool advanced = false) { + vkcv::shader::GLSLCompiler compiler; + + if (advanced) { + compiler.setDefine("ADVANCED_FEATURES", "1"); + } + + ShaderProgram program; + compiler.compileSource( + vkcv::ShaderStage::COMPUTE, + shaderSource.c_str(), + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + program.addShader(shaderStage, path); + }, + "" + ); + + ComputePipelineHandle pipeline = core.createComputePipeline({ + program, { descriptorSetLayout } + }); + + return pipeline; + } + + BloomAndFlaresEffect::BloomAndFlaresEffect(Core &core, + bool advanced) : + Effect(core), + m_advanced(advanced), + + m_downsamplePipeline(), + m_upsamplePipeline(), + m_lensFlaresPipeline(), + m_compositePipeline(), + + m_downsampleDescriptorSetLayout(m_core.createDescriptorSetLayout(getDescriptorBindings())), + m_downsampleDescriptorSets({}), + + m_upsampleDescriptorSetLayout(m_core.createDescriptorSetLayout(getDescriptorBindings())), + m_upsampleDescriptorSets({}), + m_flaresDescriptorSets({}), + + m_lensFlaresDescriptorSetLayout(m_core.createDescriptorSetLayout(getDescriptorBindings())), + m_lensFlaresDescriptorSet(m_core.createDescriptorSet(m_lensFlaresDescriptorSetLayout)), + + m_compositeDescriptorSetLayout(), + m_compositeDescriptorSet(), + + m_blurImage(), + m_flaresImage(), + + m_linearSampler(m_core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::CLAMP_TO_EDGE + )), + + m_radialLutSampler(), + + m_radialLut(), + m_lensDirt(), + + m_cameraDirection(), + m_upsampleLimit(5) { + m_downsamplePipeline = compilePipeline( + m_core, + BLOOMDOWNSAMPLE_COMP_SHADER, + m_downsampleDescriptorSetLayout + ); + + m_upsamplePipeline = compilePipeline( + m_core, + BLOOMUPSAMPLE_COMP_SHADER, + m_upsampleDescriptorSetLayout + ); + + m_lensFlaresPipeline = compilePipeline( + m_core, + LENSFLARES_COMP_SHADER, + m_lensFlaresDescriptorSetLayout + ); + + m_compositeDescriptorSetLayout = m_core.createDescriptorSetLayout( + getCompositeDescriptorBindings(m_advanced) + ); + + m_compositeDescriptorSet = m_core.createDescriptorSet( + m_compositeDescriptorSetLayout + ); + + m_compositePipeline = compilePipeline( + m_core, + BLOOMFLARESCOMPOSITE_COMP_SHADER, + m_compositeDescriptorSetLayout, + m_advanced + ); + + if (m_advanced) { + m_radialLutSampler = m_core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::REPEAT + ); + + m_radialLut = loadTexture(m_core, "assets/RadialLUT.png"); + m_lensDirt = loadTexture(m_core, "assets/lensDirt.jpg"); + } + } + + static uint32_t calcDispatchSize(float sampleSizeDim, uint32_t threadGroupWorkRegionDim) { + return std::max<uint32_t>( + static_cast<uint32_t>(std::ceil( + sampleSizeDim / static_cast<float>(threadGroupWorkRegionDim) + )), + 1 + ); + } + + void BloomAndFlaresEffect::recordDownsampling(const CommandStreamHandle &cmdStream, + const ImageHandle &input, + const ImageHandle &sample, + const std::vector<DescriptorSetHandle> &mipDescriptorSets) { + const uint32_t sampleWidth = m_core.getImageWidth(sample); + const uint32_t sampleHeight = m_core.getImageHeight(sample); + + m_core.prepareImageForSampling(cmdStream, input); + m_core.prepareImageForStorage(cmdStream, m_blurImage); + + for (uint32_t mipLevel = 0; mipLevel < mipDescriptorSets.size(); mipLevel++) { + // mip descriptor writes + DescriptorWrites mipDownsampleWrites; + + if (mipLevel > 0) { + mipDownsampleWrites.sampledImageWrites = {SampledImageDescriptorWrite(0, sample, mipLevel - 1, true)}; + } else { + mipDownsampleWrites.sampledImageWrites = {SampledImageDescriptorWrite(0, input)}; + } + + mipDownsampleWrites.samplerWrites = {SamplerDescriptorWrite(1, m_linearSampler)}; + mipDownsampleWrites.storageImageWrites = {StorageImageDescriptorWrite(2, sample, mipLevel) }; + + m_core.writeDescriptorSet(mipDescriptorSets[mipLevel], mipDownsampleWrites); + + float mipDivisor = 1.0f; + + for (uint32_t i = 0; i < mipLevel; i++) { + mipDivisor *= 2.0f; + } + + const auto downsampleSizeX = static_cast<float>(sampleWidth) / mipDivisor; + const auto downsampleSizeY = static_cast<float>(sampleHeight) / mipDivisor; + + static const uint32_t threadGroupWorkRegionDim = 8; + + uint32_t dispatch[3]; + dispatch[0] = calcDispatchSize(downsampleSizeX, threadGroupWorkRegionDim); + dispatch[1] = calcDispatchSize(downsampleSizeY, threadGroupWorkRegionDim); + dispatch[2] = 1; + + // mip blur dispatch + m_core.recordComputeDispatchToCmdStream( + cmdStream, + m_downsamplePipeline, + dispatch, + { DescriptorSetUsage(0, mipDescriptorSets[mipLevel]) }, + PushConstants(0) + ); + + // image barrier between mips + m_core.recordImageMemoryBarrier(cmdStream, sample); + } + } + + void BloomAndFlaresEffect::recordUpsampling(const CommandStreamHandle &cmdStream, + const ImageHandle &sample, + const std::vector<DescriptorSetHandle> &mipDescriptorSets) { + // upsample dispatch + m_core.prepareImageForStorage(cmdStream, sample); + + const uint32_t sampleWidth = m_core.getImageWidth(sample); + const uint32_t sampleHeight = m_core.getImageHeight(sample); + + // upsample dispatch for each mip map + for(uint32_t mipLevel = mipDescriptorSets.size(); mipLevel > 0; mipLevel--) { + // mip descriptor writes + DescriptorWrites mipUpsampleWrites; + mipUpsampleWrites.sampledImageWrites = {SampledImageDescriptorWrite(0, sample, mipLevel, true)}; + mipUpsampleWrites.samplerWrites = {SamplerDescriptorWrite(1, m_linearSampler)}; + mipUpsampleWrites.storageImageWrites = {StorageImageDescriptorWrite(2, sample, mipLevel - 1) }; + + m_core.writeDescriptorSet(mipDescriptorSets[mipLevel - 1], mipUpsampleWrites); + + float mipDivisor = 1.0f; + + for (uint32_t i = 0; i < mipLevel - 1; i++) { + mipDivisor *= 2.0f; + } + + const auto upsampleSizeX = static_cast<float>(sampleWidth) / mipDivisor; + const auto upsampleSizeY = static_cast<float>(sampleHeight) / mipDivisor; + + static const uint32_t threadGroupWorkRegionDim = 8; + + uint32_t dispatch[3]; + dispatch[0] = calcDispatchSize(upsampleSizeX, threadGroupWorkRegionDim); + dispatch[1] = calcDispatchSize(upsampleSizeY, threadGroupWorkRegionDim); + dispatch[2] = 1; + + m_core.recordComputeDispatchToCmdStream( + cmdStream, + m_upsamplePipeline, + dispatch, + { DescriptorSetUsage(0, mipDescriptorSets[mipLevel - 1]) }, + PushConstants(0) + ); + + // image barrier between mips + m_core.recordImageMemoryBarrier(cmdStream, sample); + } + } + + void BloomAndFlaresEffect::recordLensFlares(const CommandStreamHandle &cmdStream, + uint32_t mipLevel) { + // lens feature generation descriptor writes + m_core.prepareImageForSampling(cmdStream, m_blurImage); + m_core.prepareImageForStorage(cmdStream, m_flaresImage); + + const uint32_t flaresWidth = m_core.getImageWidth(m_flaresImage); + const uint32_t flaresHeight = m_core.getImageHeight(m_flaresImage); + + DescriptorWrites lensFlaresWrites; + lensFlaresWrites.sampledImageWrites = {SampledImageDescriptorWrite(0, m_blurImage, 0)}; + lensFlaresWrites.samplerWrites = {SamplerDescriptorWrite(1, m_linearSampler)}; + lensFlaresWrites.storageImageWrites = {StorageImageDescriptorWrite(2, m_flaresImage, mipLevel)}; + + m_core.writeDescriptorSet(m_lensFlaresDescriptorSet, lensFlaresWrites); + + const auto sampleSizeX = static_cast<float>(flaresWidth); + const auto sampleSizeY = static_cast<float>(flaresHeight); + + float mipDivisor = 1.0f; + + for (uint32_t i = 0; i < mipLevel - 1; i++) { + mipDivisor *= 2.0f; + } + + static const uint32_t threadGroupWorkRegionDim = 8.0f; + + // lens feature generation dispatch + uint32_t dispatch[3]; + dispatch[0] = calcDispatchSize(sampleSizeX / mipDivisor, threadGroupWorkRegionDim); + dispatch[1] = calcDispatchSize(sampleSizeY / mipDivisor, threadGroupWorkRegionDim); + dispatch[2] = 1; + + m_core.recordComputeDispatchToCmdStream( + cmdStream, + m_lensFlaresPipeline, + dispatch, + { DescriptorSetUsage(0, m_lensFlaresDescriptorSet) }, + PushConstants(0) + ); + } + + void BloomAndFlaresEffect::recordComposition(const CommandStreamHandle &cmdStream, + const ImageHandle &output) { + const uint32_t outputWidth = m_core.getImageWidth(output); + const uint32_t outputHeight = m_core.getImageHeight(output); + + m_core.prepareImageForSampling(cmdStream, m_blurImage); + m_core.prepareImageForSampling(cmdStream, m_flaresImage); + m_core.prepareImageForStorage(cmdStream, output); + + // bloom composite descriptor write + vkcv::DescriptorWrites compositeWrites; + + if (m_advanced) { + compositeWrites.sampledImageWrites = { + SampledImageDescriptorWrite(0, m_blurImage), + SampledImageDescriptorWrite(1, m_flaresImage), + SampledImageDescriptorWrite(4, m_radialLut), + SampledImageDescriptorWrite(6, m_lensDirt) + }; + + compositeWrites.samplerWrites = { + SamplerDescriptorWrite(2, m_linearSampler), + SamplerDescriptorWrite(5, m_radialLutSampler) + }; + + compositeWrites.storageImageWrites = { + StorageImageDescriptorWrite(3, output) + }; + } else { + compositeWrites.sampledImageWrites = { + SampledImageDescriptorWrite(0, m_blurImage), + SampledImageDescriptorWrite(1, m_flaresImage) + }; + + compositeWrites.samplerWrites = { + SamplerDescriptorWrite(2, m_linearSampler) + }; + + compositeWrites.storageImageWrites = { + StorageImageDescriptorWrite(3, output) + }; + } + + m_core.writeDescriptorSet(m_compositeDescriptorSet, compositeWrites); + + const auto sampleWidth = static_cast<float>(outputWidth); + const auto sampleHeight = static_cast<float>(outputHeight); + + static const uint32_t threadGroupWorkRegionDim = 8; + + uint32_t dispatch[3]; + dispatch[0] = calcDispatchSize(sampleWidth, threadGroupWorkRegionDim); + dispatch[1] = calcDispatchSize(sampleHeight, threadGroupWorkRegionDim); + dispatch[2] = 1; + + PushConstants pushConstants (sizeof(m_cameraDirection)); + pushConstants.appendDrawcall(m_cameraDirection); + + // bloom composite dispatch + m_core.recordComputeDispatchToCmdStream( + cmdStream, + m_compositePipeline, + dispatch, + { DescriptorSetUsage(0, m_compositeDescriptorSet) }, + m_advanced? pushConstants : PushConstants(0) + ); + } + + void BloomAndFlaresEffect::recordEffect(const CommandStreamHandle &cmdStream, + const ImageHandle &input, + const ImageHandle &output) { + m_core.recordBeginDebugLabel(cmdStream, "vkcv::post_processing::BloomAndFlaresEffect", { + 0.0f, 1.0f, 1.0f, 1.0f + }); + + const uint32_t halfWidth = static_cast<uint32_t>(std::ceil( + static_cast<float>(m_core.getImageWidth(output)) * 0.5f + )); + + const uint32_t halfHeight = static_cast<uint32_t>(std::ceil( + static_cast<float>(m_core.getImageHeight(output)) * 0.5f + )); + + if ((!m_blurImage) || + (halfWidth != m_core.getImageWidth(m_blurImage)) || + (halfHeight != m_core.getImageHeight(m_blurImage))) { + m_blurImage = m_core.createImage( + m_core.getImageFormat(output), + halfWidth, + halfHeight, + 1, + true, + true + ).getHandle(); + + m_downsampleDescriptorSets.clear(); + m_upsampleDescriptorSets.clear(); + + const uint32_t mipLevels = m_core.getImageMipLevels(m_blurImage); + + for (uint32_t i = 0; i < mipLevels; i++) { + m_downsampleDescriptorSets.push_back(m_core.createDescriptorSet( + m_downsampleDescriptorSetLayout + )); + } + + for (uint32_t i = 0; i < std::min<uint32_t>(m_upsampleLimit, mipLevels); i++) { + m_upsampleDescriptorSets.push_back(m_core.createDescriptorSet( + m_upsampleDescriptorSetLayout + )); + } + } + + if ((!m_flaresImage) || + (halfWidth != m_core.getImageWidth(m_flaresImage)) || + (halfHeight != m_core.getImageHeight(m_flaresImage))) { + m_flaresImage = m_core.createImage( + m_core.getImageFormat(output), + halfWidth, + halfHeight, + 1, + true, + true + ).getHandle(); + + m_flaresDescriptorSets.clear(); + + const uint32_t mipLevels = m_core.getImageMipLevels(m_flaresImage); + + for (uint32_t i = 0; i < std::min<uint32_t>(2, mipLevels); i++) { + m_flaresDescriptorSets.push_back(m_core.createDescriptorSet( + m_upsampleDescriptorSetLayout + )); + } + } + + recordDownsampling(cmdStream, input, m_blurImage, m_downsampleDescriptorSets); + recordUpsampling(cmdStream, m_blurImage, m_upsampleDescriptorSets); + recordLensFlares(cmdStream, m_flaresDescriptorSets.size()); + recordUpsampling(cmdStream, m_flaresImage, m_flaresDescriptorSets); + recordComposition(cmdStream, output); + + m_core.recordEndDebugLabel(cmdStream); + } + + void BloomAndFlaresEffect::updateCameraDirection(const camera::Camera &camera) { + m_cameraDirection = camera.getFront(); + } + + void BloomAndFlaresEffect::setUpsamplingLimit(uint32_t limit) { + m_upsampleLimit = limit; + } + +} diff --git a/modules/effects/src/vkcv/effects/Effect.cpp b/modules/effects/src/vkcv/effects/Effect.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3246db15144bcafcc253df34f358594c85868647 --- /dev/null +++ b/modules/effects/src/vkcv/effects/Effect.cpp @@ -0,0 +1,8 @@ + +#include "vkcv/effects/Effect.hpp" + +namespace vkcv::effects { + + Effect::Effect(Core &core) : m_core(core) {} + +} diff --git a/modules/scene/src/vkcv/scene/MeshPart.cpp b/modules/scene/src/vkcv/scene/MeshPart.cpp index f9c87f0a0587bd8a897e42d5b8536fe07c61c749..50d14ed49d43496ada3853034be1455b044bd902 100644 --- a/modules/scene/src/vkcv/scene/MeshPart.cpp +++ b/modules/scene/src/vkcv/scene/MeshPart.cpp @@ -71,8 +71,23 @@ namespace vkcv::scene { if (*this) { const auto& material = getMaterial(); + IndexBitCount indexBitCount; + + switch (vertexGroup.indexBuffer.type) { + case asset::IndexType::UINT16: + indexBitCount = IndexBitCount::Bit16; + break; + case asset::IndexType::UINT32: + indexBitCount = IndexBitCount::Bit32; + break; + default: + indexBitCount = IndexBitCount::Bit16; + vkcv_log(LogLevel::WARNING, "Unsupported index type!"); + break; + } + drawcalls.push_back(DrawcallInfo( - vkcv::Mesh(m_vertexBindings, indexBuffer.getVulkanHandle(), m_indexCount), + vkcv::Mesh(m_vertexBindings, indexBuffer.getVulkanHandle(), m_indexCount, indexBitCount), { DescriptorSetUsage(0, material.getDescriptorSet()) } )); } diff --git a/modules/shader_compiler/include/vkcv/shader/Compiler.hpp b/modules/shader_compiler/include/vkcv/shader/Compiler.hpp index 937c43ef58227d6c2ed29a7ac66681f9afadd025..f62190753ec440c7d732551b6229276c5a42cfc1 100644 --- a/modules/shader_compiler/include/vkcv/shader/Compiler.hpp +++ b/modules/shader_compiler/include/vkcv/shader/Compiler.hpp @@ -93,6 +93,7 @@ namespace vkcv::shader { * @param[in] value Macro definition value */ void setDefine(const std::string& name, const std::string& value); + }; /** @} */ diff --git a/modules/upscaling/CMakeLists.txt b/modules/upscaling/CMakeLists.txt index dec392573d31a7348f8440162410b4fc91757b51..6d6e7b987e2e7e448f1e8c5925dc731aafc4f3d0 100644 --- a/modules/upscaling/CMakeLists.txt +++ b/modules/upscaling/CMakeLists.txt @@ -17,6 +17,9 @@ set(vkcv_upscaling_sources ${vkcv_upscaling_include}/vkcv/upscaling/FSRUpscaling.hpp ${vkcv_upscaling_source}/vkcv/upscaling/FSRUpscaling.cpp + + ${vkcv_upscaling_include}/vkcv/upscaling/NISUpscaling.hpp + ${vkcv_upscaling_source}/vkcv/upscaling/NISUpscaling.cpp ) # Setup some path variables to load libraries @@ -26,6 +29,9 @@ set(vkcv_upscaling_lib_path ${PROJECT_SOURCE_DIR}/${vkcv_upscaling_lib}) # Check and load FidelityFX_FSR include(config/FidelityFX_FSR.cmake) +# Check and load NVIDIAImageScaling +include(config/NVIDIAImageScaling.cmake) + # adding source files to the project add_library(vkcv_upscaling ${vkcv_build_attribute} ${vkcv_upscaling_sources}) diff --git a/modules/upscaling/config/NVIDIAImageScaling.cmake b/modules/upscaling/config/NVIDIAImageScaling.cmake new file mode 100644 index 0000000000000000000000000000000000000000..083891c67e369dc783c79f5ac4386ae15e6e3261 --- /dev/null +++ b/modules/upscaling/config/NVIDIAImageScaling.cmake @@ -0,0 +1,15 @@ + +use_git_submodule("${vkcv_upscaling_lib_path}/NVIDIAImageScaling" nvidia_nis_status) + +if (${nvidia_nis_status}) + include_shader(${vkcv_upscaling_lib_path}/NVIDIAImageScaling/NIS/NIS_Scaler.h ${vkcv_upscaling_include} ${vkcv_upscaling_source}) + include_shader(${vkcv_upscaling_lib_path}/NVIDIAImageScaling/NIS/NIS_Main.glsl ${vkcv_upscaling_include} ${vkcv_upscaling_source}) + + list(APPEND vkcv_upscaling_includes ${vkcv_upscaling_lib}/NVIDIAImageScaling/NIS) + + list(APPEND vkcv_upscaling_sources ${vkcv_upscaling_source}/NIS_Scaler.h.cxx) + list(APPEND vkcv_upscaling_sources ${vkcv_upscaling_source}/NIS_Main.glsl.cxx) + + list(APPEND vkcv_upscaling_sources ${vkcv_upscaling_include}/NIS_Scaler.h.hxx) + list(APPEND vkcv_upscaling_sources ${vkcv_upscaling_include}/NIS_Main.glsl.hxx) +endif () diff --git a/modules/upscaling/include/vkcv/upscaling/NISUpscaling.hpp b/modules/upscaling/include/vkcv/upscaling/NISUpscaling.hpp new file mode 100644 index 0000000000000000000000000000000000000000..efab311d4fb452285bb3d88262ddbf3fbd04a810 --- /dev/null +++ b/modules/upscaling/include/vkcv/upscaling/NISUpscaling.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include "Upscaling.hpp" + +#include <vkcv/ShaderProgram.hpp> + +namespace vkcv::upscaling { + + class NISUpscaling : public Upscaling { + private: + ComputePipelineHandle m_scalerPipeline; + + DescriptorSetLayoutHandle m_scalerDescriptorSetLayout; + DescriptorSetHandle m_scalerDescriptorSet; + + Buffer<uint8_t> m_scalerConstants; + SamplerHandle m_sampler; + ImageHandle m_coefScaleImage; + ImageHandle m_coefUsmImage; + + uint32_t m_blockWidth; + uint32_t m_blockHeight; + + bool m_hdr; + float m_sharpness; + + public: + explicit NISUpscaling(Core &core); + + void recordUpscaling(const CommandStreamHandle &cmdStream, + const ImageHandle &input, + const ImageHandle &output) override; + + [[nodiscard]] + bool isHdrEnabled() const; + + void setHdrEnabled(bool enabled); + + [[nodiscard]] + float getSharpness() const; + + void setSharpness(float sharpness); + + }; + +} diff --git a/modules/upscaling/lib/NVIDIAImageScaling b/modules/upscaling/lib/NVIDIAImageScaling new file mode 160000 index 0000000000000000000000000000000000000000..7a468267104585ce5cd683aebd8e4cb74f826807 --- /dev/null +++ b/modules/upscaling/lib/NVIDIAImageScaling @@ -0,0 +1 @@ +Subproject commit 7a468267104585ce5cd683aebd8e4cb74f826807 diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp index 752d81e65eeb1fc901abf498b8330b7ae6102c80..5a2c96419ce2415737216a31ea26ce3d67012ee9 100644 --- a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp @@ -1,3 +1,4 @@ + #include "vkcv/upscaling/FSRUpscaling.hpp" #include <cstdint> @@ -104,7 +105,6 @@ namespace vkcv::upscaling { descriptorBindings.insert(std::make_pair(3, binding_3)); return descriptorBindings; - } template<typename T> @@ -159,10 +159,11 @@ namespace vkcv::upscaling { return false; } - return compiler.compileSource(vkcv::ShaderStage::COMPUTE, - FSR_PASS_GLSL_SHADER.c_str(), - [&directory, &compiled] (vkcv::ShaderStage shaderStage, - const std::filesystem::path& path) { + return compiler.compileSource( + vkcv::ShaderStage::COMPUTE, + FSR_PASS_GLSL_SHADER.c_str(), + [&directory, &compiled] (vkcv::ShaderStage shaderStage, + const std::filesystem::path& path) { if (compiled) { compiled(shaderStage, path); } @@ -198,6 +199,7 @@ namespace vkcv::upscaling { SamplerMipmapMode::NEAREST, SamplerAddressMode::CLAMP_TO_EDGE )), + m_hdr(false), m_sharpness(0.875f) { vkcv::shader::GLSLCompiler easuCompiler; diff --git a/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp new file mode 100644 index 0000000000000000000000000000000000000000..998d7f83e7a05d456dfe544a87953769181eada4 --- /dev/null +++ b/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp @@ -0,0 +1,278 @@ + +#include "vkcv/upscaling/NISUpscaling.hpp" + +#include <NIS_Config.h> + +#include "NIS_Main.glsl.hxx" +#include "NIS_Scaler.h.hxx" + +#include <vkcv/File.hpp> +#include <vkcv/Logger.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> + +namespace vkcv::upscaling { + + static DescriptorBindings getDescriptorBindings() { + DescriptorBindings descriptorBindings = {}; + + auto binding_0 = DescriptorBinding { + 0, + DescriptorType::UNIFORM_BUFFER_DYNAMIC, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_1 = DescriptorBinding{ + 1, + DescriptorType::SAMPLER, + 1, + ShaderStage::COMPUTE + }; + + auto binding_2 = DescriptorBinding { + 2, + DescriptorType::IMAGE_SAMPLED, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_3 = DescriptorBinding{ + 3, + DescriptorType::IMAGE_STORAGE, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_4 = DescriptorBinding { + 4, + DescriptorType::IMAGE_SAMPLED, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_5 = DescriptorBinding { + 5, + DescriptorType::IMAGE_SAMPLED, + 1, + ShaderStage::COMPUTE, + false + }; + + descriptorBindings.insert(std::make_pair(0, binding_0)); + descriptorBindings.insert(std::make_pair(1, binding_1)); + descriptorBindings.insert(std::make_pair(2, binding_2)); + descriptorBindings.insert(std::make_pair(3, binding_3)); + descriptorBindings.insert(std::make_pair(4, binding_4)); + descriptorBindings.insert(std::make_pair(5, binding_5)); + + return descriptorBindings; + } + + static ImageHandle createFilterImage(Core &core, + const void* data) { + const size_t rowPitch = kFilterSize * 2; + const size_t imageSize = rowPitch * kPhaseCount; + + Image image = core.createImage( + vk::Format::eR16G16B16A16Sfloat, + kFilterSize / 4, + kPhaseCount + ); + + image.fill(data, imageSize); + + return image.getHandle(); + } + + static bool writeShaderCode(const std::filesystem::path &shaderPath, const std::string& code) { + std::ofstream file (shaderPath.string(), std::ios::out); + + if (!file.is_open()) { + vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", shaderPath.string().c_str()); + return false; + } + + file.seekp(0); + file.write(code.c_str(), static_cast<std::streamsize>(code.length())); + file.close(); + + return true; + } + + static bool compileNISShader(vkcv::shader::GLSLCompiler& compiler, + const shader::ShaderCompiledFunction& compiled) { + std::filesystem::path directory = generateTemporaryDirectoryPath(); + + if (!std::filesystem::create_directory(directory)) { + vkcv_log(LogLevel::ERROR, "The directory could not be created (%s)", directory.string().c_str()); + return false; + } + + if (!writeShaderCode(directory / "NIS_Scaler.h", NIS_SCALER_H_SHADER)) { + return false; + } + + return compiler.compileSource( + vkcv::ShaderStage::COMPUTE, + NIS_MAIN_GLSL_SHADER.c_str(), + [&directory, &compiled] (vkcv::ShaderStage shaderStage, + const std::filesystem::path& path) { + if (compiled) { + compiled(shaderStage, path); + } + + std::filesystem::remove_all(directory); + }, directory + ); + } + + NISUpscaling::NISUpscaling(Core &core) : + Upscaling(core), + m_scalerPipeline(), + + m_scalerDescriptorSetLayout(m_core.createDescriptorSetLayout(getDescriptorBindings())), + m_scalerDescriptorSet(m_core.createDescriptorSet(m_scalerDescriptorSetLayout)), + + m_scalerConstants(m_core.createBuffer<uint8_t>( + BufferType::UNIFORM, sizeof(NISConfig), + BufferMemoryType::HOST_VISIBLE + )), + m_sampler(m_core.createSampler( + SamplerFilterType::LINEAR, + SamplerFilterType::LINEAR, + SamplerMipmapMode::NEAREST, + SamplerAddressMode::CLAMP_TO_EDGE + )), + + m_coefScaleImage(createFilterImage(m_core, coef_scale_fp16)), + m_coefUsmImage(createFilterImage(m_core, coef_usm_fp16)), + + m_blockWidth(0), + m_blockHeight(0), + + m_hdr(false), + m_sharpness(0.875f) { + vkcv::shader::GLSLCompiler scalerCompiler; + + scalerCompiler.setDefine("NIS_SCALER", "1"); + scalerCompiler.setDefine("NIS_GLSL", "1"); + + NISOptimizer optimizer (true, NISGPUArchitecture::NVIDIA_Generic); + + m_blockWidth = optimizer.GetOptimalBlockWidth(); + m_blockHeight = optimizer.GetOptimalBlockHeight(); + + scalerCompiler.setDefine("NIS_BLOCK_WIDTH", std::to_string(m_blockWidth)); + scalerCompiler.setDefine("NIS_BLOCK_HEIGHT", std::to_string(m_blockHeight)); + + const uint32_t threadGroupSize = optimizer.GetOptimalThreadGroupSize(); + + scalerCompiler.setDefine("NIS_THREAD_GROUP_SIZE", std::to_string(threadGroupSize)); + + { + ShaderProgram program; + compileNISShader(scalerCompiler, [&program](vkcv::ShaderStage shaderStage, + const std::filesystem::path& path) { + program.addShader(shaderStage, path); + }); + + m_scalerPipeline = m_core.createComputePipeline({program,{ + m_scalerDescriptorSetLayout + }}); + + + DescriptorWrites writes; + writes.uniformBufferWrites.emplace_back( + 0, m_scalerConstants.getHandle(), true + ); + + writes.samplerWrites.emplace_back(1, m_sampler); + writes.sampledImageWrites.emplace_back(4, m_coefScaleImage); + writes.sampledImageWrites.emplace_back(5, m_coefUsmImage); + + m_core.writeDescriptorSet(m_scalerDescriptorSet, writes); + } + } + + void NISUpscaling::recordUpscaling(const CommandStreamHandle &cmdStream, + const ImageHandle &input, + const ImageHandle &output) { + m_core.recordBeginDebugLabel(cmdStream, "vkcv::upscaling::NISUpscaling", { + 0.0f, 1.0f, 0.0f, 1.0f + }); + + const uint32_t inputWidth = m_core.getImageWidth(input); + const uint32_t inputHeight = m_core.getImageHeight(input); + + const uint32_t outputWidth = m_core.getImageWidth(output); + const uint32_t outputHeight = m_core.getImageHeight(output); + + NISConfig config {}; + NVScalerUpdateConfig( + config, + m_sharpness, + 0, 0, + inputWidth, + inputHeight, + inputWidth, + inputHeight, + 0, 0, + outputWidth, + outputHeight, + outputWidth, + outputHeight, + m_hdr? NISHDRMode::PQ : NISHDRMode::None + ); + + m_scalerConstants.fill( + reinterpret_cast<uint8_t*>(&config), + sizeof(config) + ); + + uint32_t dispatch[3]; + dispatch[0] = (outputWidth + (m_blockWidth - 1)) / m_blockWidth; + dispatch[1] = (outputHeight + (m_blockHeight - 1)) / m_blockHeight; + dispatch[2] = 1; + + m_core.recordBufferMemoryBarrier(cmdStream, m_scalerConstants.getHandle()); + + { + DescriptorWrites writes; + writes.sampledImageWrites.emplace_back(2, input); + writes.storageImageWrites.emplace_back(3, output); + + m_core.writeDescriptorSet(m_scalerDescriptorSet, writes); + } + + m_core.recordComputeDispatchToCmdStream( + cmdStream, + m_scalerPipeline, + dispatch, + {DescriptorSetUsage(0, m_scalerDescriptorSet, { 0 })}, + PushConstants(0) + ); + + m_core.recordEndDebugLabel(cmdStream); + } + + bool NISUpscaling::isHdrEnabled() const { + return m_hdr; + } + + void NISUpscaling::setHdrEnabled(bool enabled) { + m_hdr = enabled; + } + + float NISUpscaling::getSharpness() const { + return m_sharpness; + } + + void NISUpscaling::setSharpness(float sharpness) { + m_sharpness = (sharpness < 0.0f ? 0.0f : (sharpness > 1.0f ? 1.0f : sharpness)); + } + +} diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt index ffe8546c961697869354993539697b118fa8d6be..997c907fb26db2344f028ff5eaec8de3f69038b7 100644 --- a/projects/CMakeLists.txt +++ b/projects/CMakeLists.txt @@ -5,6 +5,7 @@ include(${vkcv_config_ext}/ProjectFix.cmake) add_subdirectory(first_triangle) add_subdirectory(first_mesh) add_subdirectory(first_scene) +add_subdirectory(head_demo) add_subdirectory(particle_simulation) add_subdirectory(rtx_ambient_occlusion) add_subdirectory(sph) diff --git a/projects/bindless_textures/src/main.cpp b/projects/bindless_textures/src/main.cpp index 6aa0a9d6106dd06c08dd5219c9570430b49ce229..f8fa8db91fb9566771862b59ad9314c9fae2e288 100644 --- a/projects/bindless_textures/src/main.cpp +++ b/projects/bindless_textures/src/main.cpp @@ -7,10 +7,7 @@ #include <vkcv/shader/GLSLCompiler.hpp> int main(int argc, const char** argv) { - const char* applicationName = "First Mesh"; - - uint32_t windowWidth = 800; - uint32_t windowHeight = 600; + const char* applicationName = "Bindless Textures"; vkcv::Features features; features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); @@ -48,7 +45,7 @@ int main(int argc, const char** argv) { features ); - vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth,windowHeight,false); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 800, 600, true); vkcv::asset::Scene mesh; @@ -206,7 +203,7 @@ int main(int argc, const char** argv) { core.writeDescriptorSet(descriptorSet, setWrites); - vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight, 1, false).getHandle(); + vkcv::ImageHandle depthBuffer; const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); @@ -234,11 +231,14 @@ int main(int argc, const char** argv) { continue; } - if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) { - depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); - - windowWidth = swapchainWidth; - windowHeight = swapchainHeight; + if ((!depthBuffer) || + (swapchainWidth != core.getImageWidth(depthBuffer)) || + (swapchainHeight != core.getImageHeight(depthBuffer))) { + depthBuffer = core.createImage( + vk::Format::eD32Sfloat, + swapchainWidth, + swapchainHeight + ).getHandle(); } auto end = std::chrono::system_clock::now(); diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 3f4378a6a2187ba33b7965fd6d008577541f7351..c8da98abd87579c2b91b2422dda544dd257b03af 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -8,9 +8,6 @@ int main(int argc, const char** argv) { const char* applicationName = "First Mesh"; - uint32_t windowWidth = 800; - uint32_t windowHeight = 600; - vkcv::Core core = vkcv::Core::create( applicationName, VK_MAKE_VERSION(0, 0, 1), @@ -18,7 +15,7 @@ int main(int argc, const char** argv) { { VK_KHR_SWAPCHAIN_EXTENSION_NAME } ); - vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, false); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 800, 600, true); vkcv::asset::Scene mesh; @@ -148,14 +145,7 @@ int main(int argc, const char** argv) { core.writeDescriptorSet(descriptorSet, setWrites); - auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); - - vkcv::ImageHandle depthBuffer = core.createImage( - vk::Format::eD32Sfloat, - swapchainExtent.width, - swapchainExtent.height, - 1, false - ).getHandle(); + vkcv::ImageHandle depthBuffer; const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); @@ -182,11 +172,14 @@ int main(int argc, const char** argv) { continue; } - if ((swapchainWidth != swapchainExtent.width) || ((swapchainHeight != swapchainExtent.height))) { - depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); - - swapchainExtent.width = swapchainWidth; - swapchainExtent.height = swapchainHeight; + if ((!depthBuffer) || + (swapchainWidth != core.getImageWidth(depthBuffer)) || + (swapchainHeight != core.getImageHeight(depthBuffer))) { + depthBuffer = core.createImage( + vk::Format::eD32Sfloat, + swapchainWidth, + swapchainHeight + ).getHandle(); } auto end = std::chrono::system_clock::now(); diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp index 3dd6fc40d516c6f1ae3358d60c02fc4ed219245a..3e424919d2289c45e129c6b476ff026455403982 100644 --- a/projects/first_scene/src/main.cpp +++ b/projects/first_scene/src/main.cpp @@ -20,7 +20,7 @@ int main(int argc, const char** argv) { {vk::QueueFlagBits::eTransfer, vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute}, { VK_KHR_SWAPCHAIN_EXTENSION_NAME } ); - vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, false); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, true); vkcv::Window& window = core.getWindow(windowHandle); vkcv::camera::CameraManager cameraManager(window); @@ -92,13 +92,7 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } - auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); - - vkcv::ImageHandle depthBuffer = core.createImage( - vk::Format::eD32Sfloat, - swapchainExtent.width, - swapchainExtent.height - ).getHandle(); + vkcv::ImageHandle depthBuffer; const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); @@ -114,11 +108,14 @@ int main(int argc, const char** argv) { continue; } - if ((swapchainWidth != swapchainExtent.width) || ((swapchainHeight != swapchainExtent.height))) { - depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); - - swapchainExtent.width = swapchainWidth; - swapchainExtent.height = swapchainHeight; + if ((!depthBuffer) || + (swapchainWidth != core.getImageWidth(depthBuffer)) || + (swapchainHeight != core.getImageHeight(depthBuffer))) { + depthBuffer = core.createImage( + vk::Format::eD32Sfloat, + swapchainWidth, + swapchainHeight + ).getHandle(); } auto end = std::chrono::system_clock::now(); diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index b4ba9046e07ecd3534844b493642098aa5847307..3bdefe3ae55fc89879461ed37025f8fe00e39a8a 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -56,12 +56,12 @@ int main(int argc, const char** argv) { const vkcv::GraphicsPipelineConfig trianglePipelineDefinition { triangleShaderProgram, - swapchainExtent.width, - swapchainExtent.height, + UINT32_MAX, + UINT32_MAX, trianglePass, {}, {}, - false + true }; vkcv::GraphicsPipelineHandle trianglePipeline = core.createGraphicsPipeline(trianglePipelineDefinition); diff --git a/projects/head_demo/.gitignore b/projects/head_demo/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..151f56c5bb7098a3beb7b8e049c0ade02914cd91 --- /dev/null +++ b/projects/head_demo/.gitignore @@ -0,0 +1 @@ +head_demo \ No newline at end of file diff --git a/projects/head_demo/CMakeLists.txt b/projects/head_demo/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bd7e48000320d4c1304a3b9f3b26fe54421f818c --- /dev/null +++ b/projects/head_demo/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.16) +project(head_demo) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# this should fix the execution path to load local files from the project +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +# adding source files to the project +add_executable(head_demo src/main.cpp) +fix_project(head_demo) + +# including headers of dependencies and the VkCV framework +target_include_directories(head_demo SYSTEM BEFORE PRIVATE + ${vkcv_include} + ${vkcv_includes} + ${vkcv_asset_loader_include} + ${vkcv_camera_include} + ${vkcv_scene_include} + ${vkcv_shader_compiler_include} + ${vkcv_gui_include} + ${vkcv_effects_include} + ${vkcv_upscaling_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(head_demo + vkcv + ${vkcv_libraries} + vkcv_asset_loader + ${vkcv_asset_loader_libraries} + vkcv_camera vkcv_scene + vkcv_shader_compiler + vkcv_gui + vkcv_effects + vkcv_upscaling) diff --git a/projects/head_demo/assets/shaders/clip.inc b/projects/head_demo/assets/shaders/clip.inc new file mode 100644 index 0000000000000000000000000000000000000000..edb5ac3ccfe5d7f6ad1e59dd88bee4446b85118f --- /dev/null +++ b/projects/head_demo/assets/shaders/clip.inc @@ -0,0 +1,19 @@ + +#define CLIP_SCALE 10000.0f + +vec4 clipPosition(vec4 pos) { + return vec4( + max(clipX, pos.x), + max(clipY, pos.y), + max(clipZ, pos.z), + 1.0f / CLIP_SCALE + ); +} + +vec4 clipByLimit(vec4 pos) { + if (pos.x / pos.w < clipLimit) { + return vec4(pos.xyz / pos.w, 1.0f); + } else { + return vec4(clipLimit, pos.y / pos.w, pos.z / pos.w, 1.0f); + } +} diff --git a/projects/head_demo/assets/shaders/red.frag b/projects/head_demo/assets/shaders/red.frag new file mode 100644 index 0000000000000000000000000000000000000000..35735be779edd0bf88890638329dc53f6b691f57 --- /dev/null +++ b/projects/head_demo/assets/shaders/red.frag @@ -0,0 +1,11 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 passNormal; +layout(location = 1) in vec3 passEdge; + +layout(location = 0) out vec3 outColor; + +void main() { + outColor = (0.1f + max(dot(passNormal, vec3(1.0f, -1.0f, 0.5f)), 0.0f) * 0.9f) * (passEdge + 0.5f); +} \ No newline at end of file diff --git a/projects/head_demo/assets/shaders/shader.frag b/projects/head_demo/assets/shaders/shader.frag new file mode 100644 index 0000000000000000000000000000000000000000..b8756a6b84af4e93f9ac932ec01d28e4f2e9638b --- /dev/null +++ b/projects/head_demo/assets/shaders/shader.frag @@ -0,0 +1,10 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 passNormal; + +layout(location = 0) out vec3 outColor; + +void main() { + outColor = (vec3(0.3f) + max(dot(passNormal, vec3(1.0f, -1.0f, 0.5f)), 0.0f) * vec3(0.7f)); +} \ No newline at end of file diff --git a/projects/head_demo/assets/shaders/shader.geom b/projects/head_demo/assets/shaders/shader.geom new file mode 100644 index 0000000000000000000000000000000000000000..275b300ee3466e117876aa46a6ea1cde11f6f17d --- /dev/null +++ b/projects/head_demo/assets/shaders/shader.geom @@ -0,0 +1,53 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +layout(triangles) in; +layout(triangle_strip, max_vertices = 3) out; + +layout(location = 0) in vec3 geomNormal[]; + +layout(location = 0) out vec3 passNormal; + +layout(set=1, binding=0) uniform clipBuffer { + float clipLimit; + float clipX; + float clipY; + float clipZ; +}; + +layout( push_constant ) uniform constants{ + mat4 mvp; +}; + +#include "clip.inc" + +void main() { + vec4 v0 = gl_in[0].gl_Position; + vec4 v1 = gl_in[1].gl_Position; + vec4 v2 = gl_in[2].gl_Position; + + v0 = clipPosition(v0 / CLIP_SCALE); + v1 = clipPosition(v1 / CLIP_SCALE); + v2 = clipPosition(v2 / CLIP_SCALE); + + float dx = abs(v0.x - clipX) + abs(v1.x - clipX) + abs(v2.x - clipX); + float dy = abs(v0.y - clipY) + abs(v1.y - clipY) + abs(v2.y - clipY); + float dz = abs(v0.z - clipZ) + abs(v1.z - clipZ) + abs(v2.z - clipZ); + + if (dx * dy * dz > 0.0f) { + gl_Position = mvp * (v0 * CLIP_SCALE); + passNormal = geomNormal[0]; + EmitVertex(); + + gl_Position = mvp * (v1 * CLIP_SCALE); + passNormal = geomNormal[1]; + EmitVertex(); + + gl_Position = mvp * (v2 * CLIP_SCALE); + passNormal = geomNormal[2]; + EmitVertex(); + + EndPrimitive(); + } +} diff --git a/projects/head_demo/assets/shaders/shader.vert b/projects/head_demo/assets/shaders/shader.vert new file mode 100644 index 0000000000000000000000000000000000000000..26e43e9c89dc2ffb2355d60be8288fa9832f8baa --- /dev/null +++ b/projects/head_demo/assets/shaders/shader.vert @@ -0,0 +1,12 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNormal; + +layout(location = 0) out vec3 geomNormal; + +void main() { + gl_Position = vec4(inPosition, 1.0); + geomNormal = inNormal; +} \ No newline at end of file diff --git a/projects/head_demo/assets/shaders/wired.geom b/projects/head_demo/assets/shaders/wired.geom new file mode 100644 index 0000000000000000000000000000000000000000..689e073dde7fd993d164cfea0b7ca777d79f8508 --- /dev/null +++ b/projects/head_demo/assets/shaders/wired.geom @@ -0,0 +1,53 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +layout(triangles) in; +layout(points, max_vertices = 1) out; + +layout(location = 0) in vec3 geomNormal[]; + +layout(location = 0) out vec3 passNormal; +layout(location = 1) out vec3 passEdge; + +layout(set=1, binding=0) uniform clipBuffer { + float clipLimit; + float clipX; + float clipY; + float clipZ; +}; + +layout( push_constant ) uniform constants{ + mat4 mvp; +}; + +#include "clip.inc" + +void main() { + vec4 v0 = gl_in[0].gl_Position; + vec4 v1 = gl_in[1].gl_Position; + vec4 v2 = gl_in[2].gl_Position; + + v0 = clipPosition(v0 / CLIP_SCALE); + v1 = clipPosition(v1 / CLIP_SCALE); + v2 = clipPosition(v2 / CLIP_SCALE); + + float dx = abs(v0.x - clipX) + abs(v1.x - clipX) + abs(v2.x - clipX); + float dy = abs(v0.y - clipY) + abs(v1.y - clipY) + abs(v2.y - clipY); + float dz = abs(v0.z - clipZ) + abs(v1.z - clipZ) + abs(v2.z - clipZ); + + if (dx * dy * dz <= 0.0f) { + v0 = clipByLimit(mvp * gl_in[0].gl_Position); + v1 = clipByLimit(mvp * gl_in[1].gl_Position); + v2 = clipByLimit(mvp * gl_in[2].gl_Position); + + if ((v0.x < clipLimit) || (v1.x < clipLimit) || (v2.x < clipLimit)) { + gl_Position = (v0 + v1 + v2) / 3; + passNormal = (geomNormal[0] + geomNormal[1] + geomNormal[2]) / 3; + passEdge = vec3(dx, dy, dz); + EmitVertex(); + + EndPrimitive(); + } + } +} diff --git a/projects/head_demo/assets/skull/license.txt b/projects/head_demo/assets/skull/license.txt new file mode 100644 index 0000000000000000000000000000000000000000..6816d6d659087b54dfc6b8e0c2c0e158daa001f0 --- /dev/null +++ b/projects/head_demo/assets/skull/license.txt @@ -0,0 +1,11 @@ +Model Information: +* title: The Anatomy of the Human Skull +* source: https://sketchfab.com/3d-models/the-anatomy-of-the-human-skull-baf6ac7b781a46218dca2b59dee58817 +* author: HannahNewey (https://sketchfab.com/HannahNewey) + +Model License: +* license type: CC-BY-NC-SA-4.0 (http://creativecommons.org/licenses/by-nc-sa/4.0/) +* requirements: Author must be credited. No commercial use. Modified versions must have the same license. + +If you use this 3D model in your project be sure to copy paste this credit wherever you share it: +This work is based on "The Anatomy of the Human Skull" (https://sketchfab.com/3d-models/the-anatomy-of-the-human-skull-baf6ac7b781a46218dca2b59dee58817) by HannahNewey (https://sketchfab.com/HannahNewey) licensed under CC-BY-NC-SA-4.0 (http://creativecommons.org/licenses/by-nc-sa/4.0/) \ No newline at end of file diff --git a/projects/head_demo/assets/skull/scene.bin b/projects/head_demo/assets/skull/scene.bin new file mode 100644 index 0000000000000000000000000000000000000000..e995091c9d2f10b15959a65d3b0e0de3c9edb0e4 --- /dev/null +++ b/projects/head_demo/assets/skull/scene.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:df3cb5e715426a8e7a3c4883eb7c53022e09011ded9ae385cd6bc59824129ed8 +size 78176672 diff --git a/projects/head_demo/assets/skull/scene.gltf b/projects/head_demo/assets/skull/scene.gltf new file mode 100644 index 0000000000000000000000000000000000000000..6a2b75fa5af1e826bf3851db576dd3051e7b77c3 --- /dev/null +++ b/projects/head_demo/assets/skull/scene.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8cd4f673e0a555dc138b96e07be60546a799f9ef11837870eae27b16ffd5c1c7 +size 36442 diff --git a/projects/head_demo/assets/skull_scaled/scene.bin b/projects/head_demo/assets/skull_scaled/scene.bin new file mode 100644 index 0000000000000000000000000000000000000000..3edc8865ed5465c33cb8c9d2f2b0eb83b1a5b599 --- /dev/null +++ b/projects/head_demo/assets/skull_scaled/scene.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:685e971ce4e99be286464c56a373e528dc507ce18b5bfdff45f90db27e49176b +size 56596296 diff --git a/projects/head_demo/assets/skull_scaled/scene.gltf b/projects/head_demo/assets/skull_scaled/scene.gltf new file mode 100644 index 0000000000000000000000000000000000000000..72087f182e4cd1ce1a73f7af9db1d36608df2029 --- /dev/null +++ b/projects/head_demo/assets/skull_scaled/scene.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f05a4c8f979dab2793540bafe2b392133d64af028a0ff97f0159dbc52fc20230 +size 4843 diff --git a/projects/head_demo/src/main.cpp b/projects/head_demo/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3eeec03a47d8051385523e8f3e3e146e0829aeda --- /dev/null +++ b/projects/head_demo/src/main.cpp @@ -0,0 +1,287 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <vkcv/gui/GUI.hpp> +#include <chrono> +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> +#include <vkcv/scene/Scene.hpp> +#include <vkcv/effects/BloomAndFlaresEffect.hpp> +#include <vkcv/upscaling/FSRUpscaling.hpp> + +int main(int argc, const char** argv) { + const char* applicationName = "First Scene"; + + uint32_t windowWidth = 800; + uint32_t windowHeight = 600; + + vkcv::Core core = vkcv::Core::create( + applicationName, + VK_MAKE_VERSION(0, 0, 1), + {vk::QueueFlagBits::eTransfer, vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute}, + { VK_KHR_SWAPCHAIN_EXTENSION_NAME } + ); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, true); + vkcv::Window& window = core.getWindow(windowHandle); + vkcv::camera::CameraManager cameraManager(window); + + vkcv::gui::GUI gui (core, windowHandle); + + uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camIndex0).setPosition(glm::vec3(15.5f, 0, 0)); + cameraManager.getCamera(camIndex0).setNearFar(0.1f, 30.0f); + + cameraManager.getCamera(camIndex1).setNearFar(0.1f, 30.0f); + + vkcv::scene::Scene scene = vkcv::scene::Scene::load(core, std::filesystem::path( + argc > 1 ? argv[1] : "assets/skull_scaled/scene.gltf" + )); + + vk::Format colorFormat = vk::Format::eR16G16B16A16Sfloat; + + const vkcv::AttachmentDescription color_attachment0( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + colorFormat + ); + + const vkcv::AttachmentDescription depth_attachment0( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + vk::Format::eD32Sfloat + ); + + const vkcv::AttachmentDescription color_attachment1( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::LOAD, + colorFormat + ); + + const vkcv::AttachmentDescription depth_attachment1( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::LOAD, + vk::Format::eD32Sfloat + ); + + vkcv::PassConfig linePassDefinition({ color_attachment0, depth_attachment0 }); + vkcv::PassHandle linePass = core.createPass(linePassDefinition); + + vkcv::PassConfig scenePassDefinition({ color_attachment1, depth_attachment1 }); + vkcv::PassHandle scenePass = core.createPass(scenePassDefinition); + + if ((!scenePass) || (!linePass)) { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; + } + + vkcv::ShaderProgram sceneShaderProgram; + vkcv::ShaderProgram lineShaderProgram; + vkcv::shader::GLSLCompiler compiler; + + compiler.compileProgram(sceneShaderProgram, { + { vkcv::ShaderStage::VERTEX, "assets/shaders/shader.vert" }, + { vkcv::ShaderStage::GEOMETRY, "assets/shaders/shader.geom" }, + { vkcv::ShaderStage::FRAGMENT, "assets/shaders/shader.frag" } + }, nullptr); + + compiler.compileProgram(lineShaderProgram, { + { vkcv::ShaderStage::VERTEX, "assets/shaders/shader.vert" }, + { vkcv::ShaderStage::GEOMETRY, "assets/shaders/wired.geom" }, + { vkcv::ShaderStage::FRAGMENT, "assets/shaders/red.frag" } + }, nullptr); + + const std::vector<vkcv::VertexAttachment> vertexAttachments = sceneShaderProgram.getVertexAttachments(); + std::vector<vkcv::VertexBinding> bindings; + for (size_t i = 0; i < vertexAttachments.size(); i++) { + bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + } + + const auto& clipBindings = sceneShaderProgram.getReflectedDescriptors().at(1); + + auto clipDescriptorSetLayout = core.createDescriptorSetLayout(clipBindings); + auto clipDescriptorSet = core.createDescriptorSet(clipDescriptorSetLayout); + + float clipLimit = 1.0f; + float clipX = 0.0f; + float clipY = 0.0f; + float clipZ = 0.0f; + + auto clipBuffer = core.createBuffer<float>(vkcv::BufferType::UNIFORM, 4); + clipBuffer.fill({ clipLimit, -clipX, -clipY, -clipZ }); + + vkcv::DescriptorWrites clipWrites; + clipWrites.uniformBufferWrites = { + vkcv::BufferDescriptorWrite(0, clipBuffer.getHandle()) + }; + + core.writeDescriptorSet(clipDescriptorSet, clipWrites); + + float mouseX = -0.0f; + bool dragLimit = false; + + window.e_mouseMove.add([&](double x, double y) { + double cx = (x - window.getWidth() * 0.5); + double dx = cx / window.getWidth(); + + mouseX = 2.0f * static_cast<float>(dx); + + if (dragLimit) { + clipLimit = mouseX; + } + }); + + window.e_mouseButton.add([&](int button, int action, int mods) { + if ((std::abs(mouseX - clipLimit) < 0.1f) && (action == GLFW_PRESS)) { + dragLimit = true; + } else { + dragLimit = false; + } + }); + + const vkcv::VertexLayout sceneLayout(bindings); + + const auto& material0 = scene.getMaterial(0); + + const vkcv::GraphicsPipelineConfig scenePipelineDefinition{ + sceneShaderProgram, + UINT32_MAX, + UINT32_MAX, + scenePass, + {sceneLayout}, + { material0.getDescriptorSetLayout(), clipDescriptorSetLayout }, + true + }; + + const vkcv::GraphicsPipelineConfig linePipelineDefinition{ + lineShaderProgram, + UINT32_MAX, + UINT32_MAX, + linePass, + {sceneLayout}, + { material0.getDescriptorSetLayout(), clipDescriptorSetLayout }, + true + }; + + vkcv::GraphicsPipelineHandle scenePipeline = core.createGraphicsPipeline(scenePipelineDefinition); + vkcv::GraphicsPipelineHandle linePipeline = core.createGraphicsPipeline(linePipelineDefinition); + + if ((!scenePipeline) || (!linePipeline)) { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); + + vkcv::ImageHandle depthBuffer = core.createImage( + vk::Format::eD32Sfloat, + swapchainExtent.width, + swapchainExtent.height + ).getHandle(); + + vkcv::ImageHandle colorBuffer = core.createImage( + colorFormat, + swapchainExtent.width, + swapchainExtent.height, + 1, false, true, true + ).getHandle(); + + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + vkcv::effects::BloomAndFlaresEffect bloomAndFlares (core); + vkcv::upscaling::FSRUpscaling upscaling (core); + + auto start = std::chrono::system_clock::now(); + while (vkcv::Window::hasOpenWindow()) { + vkcv::Window::pollEvents(); + + if(window.getHeight() == 0 || window.getWidth() == 0) + continue; + + uint32_t swapchainWidth, swapchainHeight; + if (!core.beginFrame(swapchainWidth, swapchainHeight,windowHandle)) { + continue; + } + + if ((swapchainWidth != swapchainExtent.width) || ((swapchainHeight != swapchainExtent.height))) { + depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); + + colorBuffer = core.createImage( + colorFormat, + swapchainExtent.width, + swapchainExtent.height, + 1, false, true, true + ).getHandle(); + + swapchainExtent.width = swapchainWidth; + swapchainExtent.height = swapchainHeight; + } + + auto end = std::chrono::system_clock::now(); + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + + start = end; + cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + + clipBuffer.fill({ clipLimit, -clipX, -clipY, -clipZ }); + + const std::vector<vkcv::ImageHandle> renderTargets = { colorBuffer, depthBuffer }; + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + auto recordMesh = [&](const glm::mat4& MVP, const glm::mat4& M, + vkcv::PushConstants &pushConstants, + vkcv::DrawcallInfo& drawcallInfo) { + pushConstants.appendDrawcall(MVP); + drawcallInfo.descriptorSets.push_back( + vkcv::DescriptorSetUsage(1, clipDescriptorSet) + ); + }; + + scene.recordDrawcalls(cmdStream, + cameraManager.getActiveCamera(), + linePass, + linePipeline, + sizeof(glm::mat4), + recordMesh, + renderTargets, + windowHandle); + + bloomAndFlares.recordEffect(cmdStream, colorBuffer, colorBuffer); + + scene.recordDrawcalls(cmdStream, + cameraManager.getActiveCamera(), + scenePass, + scenePipeline, + sizeof(glm::mat4), + recordMesh, + renderTargets, + windowHandle); + + core.prepareImageForSampling(cmdStream, colorBuffer); + core.prepareImageForStorage(cmdStream, swapchainInput); + upscaling.recordUpscaling(cmdStream, colorBuffer, swapchainInput); + + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + + auto stop = std::chrono::system_clock::now(); + auto kektime = std::chrono::duration_cast<std::chrono::microseconds>(stop - start); + + gui.beginGUI(); + + ImGui::Begin("Settings"); + ImGui::SliderFloat("Clip X", &clipX, -1.0f, 1.0f); + ImGui::SliderFloat("Clip Y", &clipY, -1.0f, 1.0f); + ImGui::SliderFloat("Clip Z", &clipZ, -1.0f, 1.0f); + ImGui::Text("Mesh by HannahNewey (https://sketchfab.com/HannahNewey)"); + ImGui::End(); + + gui.endGUI(); + + core.endFrame(windowHandle); + } + + return 0; +} diff --git a/projects/indirect_draw/src/main.cpp b/projects/indirect_draw/src/main.cpp index 9b062ab56245c44e5021f164b9e06fed8edd15c3..2a213a2ad7b8ecdaf4b4a51cf4327addc7a881a5 100644 --- a/projects/indirect_draw/src/main.cpp +++ b/projects/indirect_draw/src/main.cpp @@ -259,9 +259,6 @@ void compileMeshForIndirectDraw(vkcv::Core &core, int main(int argc, const char** argv) { const char* applicationName = "Indirect draw"; - uint32_t windowWidth = 800; - uint32_t windowHeight = 600; - vkcv::Features features; features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); features.requireFeature([](vk::PhysicalDeviceFeatures &features){ @@ -305,7 +302,7 @@ int main(int argc, const char** argv) { features ); - vkcv::WindowHandle windowHandle = core.createWindow(applicationName,windowWidth,windowHeight,false); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName,800,600,true); vkcv::gui::GUI gui (core, windowHandle); @@ -526,7 +523,8 @@ int main(int argc, const char** argv) { cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -3)); cameraManager.getCamera(camIndex0).setNearFar(0.1f, 20.f); - vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight, 1, false).getHandle(); + vkcv::ImageHandle depthBuffer; + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); auto start = std::chrono::system_clock::now(); @@ -552,11 +550,10 @@ int main(int argc, const char** argv) { continue; } - if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) { + if ((!depthBuffer) || + (swapchainWidth != core.getImageWidth(depthBuffer)) || + (swapchainHeight != core.getImageHeight(depthBuffer))) { depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); - - windowWidth = swapchainWidth; - windowHeight = swapchainHeight; } auto end = std::chrono::system_clock::now(); diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp index 0a9914abf0a28f82eee06c5d2a67067faaff4109..afaec1a8ba5dded5f16bad65c68f25f442029091 100644 --- a/projects/mesh_shader/src/main.cpp +++ b/projects/mesh_shader/src/main.cpp @@ -77,9 +77,6 @@ CameraPlanes computeCameraPlanes(const vkcv::camera::Camera& camera) { int main(int argc, const char** argv) { const char* applicationName = "Mesh shader"; - - const int windowWidth = 1280; - const int windowHeight = 720; vkcv::Features features; features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); @@ -95,7 +92,7 @@ int main(int argc, const char** argv) { { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, features ); - vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, false); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 1280, 720, true); vkcv::Window &window = core.getWindow(windowHandle); vkcv::gui::GUI gui (core, windowHandle); @@ -202,17 +199,15 @@ int main(int argc, const char** argv) { vkcv::DescriptorSetLayoutHandle vertexShaderDescriptorSetLayout = core.createDescriptorSetLayout(bunnyShaderProgram.getReflectedDescriptors().at(0)); vkcv::DescriptorSetHandle vertexShaderDescriptorSet = core.createDescriptorSet(vertexShaderDescriptorSetLayout); - - auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); const vkcv::GraphicsPipelineConfig bunnyPipelineDefinition { bunnyShaderProgram, - swapchainExtent.width, - swapchainExtent.height, + UINT32_MAX, + UINT32_MAX, renderPass, { bunnyLayout }, { vertexShaderDescriptorSetLayout }, - false + true }; struct ObjectMatrices { @@ -257,12 +252,12 @@ int main(int argc, const char** argv) { const vkcv::GraphicsPipelineConfig meshShaderPipelineDefinition{ meshShaderProgram, - swapchainExtent.width, - swapchainExtent.height, + UINT32_MAX, + UINT32_MAX, renderPass, {meshShaderLayout}, {meshShaderDescriptorSetLayout}, - false + true }; vkcv::GraphicsPipelineHandle meshShaderPipeline = core.createGraphicsPipeline(meshShaderPipelineDefinition); @@ -289,12 +284,7 @@ int main(int argc, const char** argv) { core.writeDescriptorSet( meshShaderDescriptorSet, meshShaderWrites); - vkcv::ImageHandle depthBuffer = core.createImage( - vk::Format::eD32Sfloat, - swapchainExtent.width, - swapchainExtent.height, - 1, false - ).getHandle(); + vkcv::ImageHandle depthBuffer; auto start = std::chrono::system_clock::now(); @@ -321,6 +311,16 @@ int main(int argc, const char** argv) { continue; } + if ((!depthBuffer) || + (swapchainWidth != core.getImageWidth(depthBuffer)) || + (swapchainHeight != core.getImageHeight(depthBuffer))) { + depthBuffer = core.createImage( + vk::Format::eD32Sfloat, + swapchainWidth, + swapchainHeight + ).getHandle(); + } + auto end = std::chrono::system_clock::now(); auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); start = end; diff --git a/projects/particle_simulation/CMakeLists.txt b/projects/particle_simulation/CMakeLists.txt index 2ff6aaf62c6a9842c3d1b9669286becfd79d92ca..3adede6e25f88208824144b63a866ccabdfc5be9 100644 --- a/projects/particle_simulation/CMakeLists.txt +++ b/projects/particle_simulation/CMakeLists.txt @@ -14,14 +14,23 @@ add_executable(particle_simulation src/ParticleSystem.hpp src/ParticleSystem.cpp src/Particle.hpp - src/Particle.cpp - src/BloomAndFlares.hpp - src/BloomAndFlares.cpp) + src/Particle.cpp) fix_project(particle_simulation) # including headers of dependencies and the VkCV framework -target_include_directories(particle_simulation SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include}) +target_include_directories(particle_simulation SYSTEM BEFORE PRIVATE + ${vkcv_include} + ${vkcv_includes} + ${vkcv_testing_include} + ${vkcv_camera_include} + ${vkcv_shader_compiler_include} + ${vkcv_effects_include}) # linking with libraries from all dependencies and the VkCV framework -target_link_libraries(particle_simulation vkcv vkcv_testing vkcv_camera vkcv_shader_compiler) +target_link_libraries(particle_simulation + vkcv + vkcv_testing + vkcv_camera + vkcv_shader_compiler + vkcv_effects) diff --git a/projects/particle_simulation/shaders/bloom/composite.comp b/projects/particle_simulation/shaders/bloom/composite.comp deleted file mode 100644 index 87b5ddb975106232d1cd3b6e5b8dc7e623dd0b59..0000000000000000000000000000000000000000 --- a/projects/particle_simulation/shaders/bloom/composite.comp +++ /dev/null @@ -1,38 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(set=0, binding=0) uniform texture2D blurImage; -layout(set=0, binding=1) uniform texture2D lensImage; -layout(set=0, binding=2) uniform sampler linearSampler; -layout(set=0, binding=3, r11f_g11f_b10f) uniform image2D colorBuffer; - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - - -void main() -{ - if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(colorBuffer)))){ - return; - } - - ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); - vec2 pixel_size = vec2(1.0f) / textureSize(sampler2D(blurImage, linearSampler), 0); - vec2 UV = pixel_coord.xy * pixel_size; - - vec4 composite_color = vec4(0.0f); - - vec3 blur_color = texture(sampler2D(blurImage, linearSampler), UV).rgb; - vec3 lens_color = texture(sampler2D(lensImage, linearSampler), UV).rgb; - vec3 main_color = imageLoad(colorBuffer, pixel_coord).rgb; - - // composite blur and lens features - float bloom_weight = 0.01f; - float lens_weight = 0.f; - float main_weight = 1 - (bloom_weight + lens_weight); - - composite_color.rgb = blur_color * bloom_weight + - lens_color * lens_weight + - main_color * main_weight; - - imageStore(colorBuffer, pixel_coord, composite_color); -} \ No newline at end of file diff --git a/projects/particle_simulation/shaders/bloom/downsample.comp b/projects/particle_simulation/shaders/bloom/downsample.comp deleted file mode 100644 index 2ab00c7c92798769153634f3479c5b7f3fb61d94..0000000000000000000000000000000000000000 --- a/projects/particle_simulation/shaders/bloom/downsample.comp +++ /dev/null @@ -1,76 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(set=0, binding=0) uniform texture2D inBlurImage; -layout(set=0, binding=1) uniform sampler inImageSampler; -layout(set=0, binding=2, r11f_g11f_b10f) uniform writeonly image2D outBlurImage; - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - - -void main() -{ - if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outBlurImage)))){ - return; - } - - ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); - vec2 pixel_size = vec2(1.0f) / imageSize(outBlurImage); - vec2 UV = pixel_coord.xy * pixel_size; - vec2 UV_offset = UV + 0.5f * pixel_size; - - vec2 color_fetches[13] = { - // center neighbourhood (RED) - vec2(-1, 1), // LT - vec2(-1, -1), // LB - vec2( 1, -1), // RB - vec2( 1, 1), // RT - - vec2(-2, 2), // LT - vec2( 0, 2), // CT - vec2( 2, 2), // RT - - vec2(0 ,-2), // LC - vec2(0 , 0), // CC - vec2(2, 0), // CR - - vec2(-2, -2), // LB - vec2(0 , -2), // CB - vec2(2 , -2) // RB - }; - - float color_weights[13] = { - // 0.5f - 1.f/8.f, - 1.f/8.f, - 1.f/8.f, - 1.f/8.f, - - // 0.125f - 1.f/32.f, - 1.f/16.f, - 1.f/32.f, - - // 0.25f - 1.f/16.f, - 1.f/8.f, - 1.f/16.f, - - // 0.125f - 1.f/32.f, - 1.f/16.f, - 1.f/32.f - }; - - vec3 sampled_color = vec3(0.0f); - - for(uint i = 0; i < 13; i++) - { - vec2 color_fetch = UV_offset + color_fetches[i] * pixel_size; - vec3 color = texture(sampler2D(inBlurImage, inImageSampler), color_fetch).rgb; - color *= color_weights[i]; - sampled_color += color; - } - - imageStore(outBlurImage, pixel_coord, vec4(sampled_color, 1.f)); -} \ No newline at end of file diff --git a/projects/particle_simulation/shaders/bloom/lensFlares.comp b/projects/particle_simulation/shaders/bloom/lensFlares.comp deleted file mode 100644 index ce27d8850b709f61332d467914ddc944dc63109f..0000000000000000000000000000000000000000 --- a/projects/particle_simulation/shaders/bloom/lensFlares.comp +++ /dev/null @@ -1,109 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(set=0, binding=0) uniform texture2D blurBuffer; -layout(set=0, binding=1) uniform sampler linearSampler; -layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D lensBuffer; - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -vec3 sampleColorChromaticAberration(vec2 _uv) -{ - vec2 toCenter = (vec2(0.5) - _uv); - - vec3 colorScales = vec3(-1, 0, 1); - float aberrationScale = 0.1; - vec3 scaleFactors = colorScales * aberrationScale; - - float r = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.r).r; - float g = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.g).g; - float b = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.b).b; - return vec3(r, g, b); -} - -// _uv assumed to be flipped UV coordinates! -vec3 ghost_vectors(vec2 _uv) -{ - vec2 ghost_vec = (vec2(0.5f) - _uv); - - const uint c_ghost_count = 64; - const float c_ghost_spacing = length(ghost_vec) / c_ghost_count; - - ghost_vec *= c_ghost_spacing; - - vec3 ret_color = vec3(0.0f); - - for (uint i = 0; i < c_ghost_count; ++i) - { - // sample scene color - vec2 s_uv = fract(_uv + ghost_vec * vec2(i)); - vec3 s = sampleColorChromaticAberration(s_uv); - - // tint/weight - float d = distance(s_uv, vec2(0.5)); - float weight = 1.0f - smoothstep(0.0f, 0.75f, d); - s *= weight; - - ret_color += s; - } - - ret_color /= c_ghost_count; - return ret_color; -} - -vec3 halo(vec2 _uv) -{ - const float c_aspect_ratio = float(imageSize(lensBuffer).x) / float(imageSize(lensBuffer).y); - const float c_radius = 0.6f; - const float c_halo_thickness = 0.1f; - - vec2 halo_vec = vec2(0.5) - _uv; - //halo_vec.x /= c_aspect_ratio; - halo_vec = normalize(halo_vec); - //halo_vec.x *= c_aspect_ratio; - - - //vec2 w_uv = (_uv - vec2(0.5, 0.0)) * vec2(c_aspect_ratio, 1.0) + vec2(0.5, 0.0); - vec2 w_uv = _uv; - float d = distance(w_uv, vec2(0.5)); // distance to center - - float distance_to_halo = abs(d - c_radius); - - float halo_weight = 0.0f; - if(abs(d - c_radius) <= c_halo_thickness) - { - float distance_to_border = c_halo_thickness - distance_to_halo; - halo_weight = distance_to_border / c_halo_thickness; - - //halo_weight = clamp((halo_weight / 0.4f), 0.0f, 1.0f); - halo_weight = pow(halo_weight, 2.0f); - - - //halo_weight = 1.0f; - } - - return sampleColorChromaticAberration(_uv + halo_vec) * halo_weight; -} - - - -void main() -{ - if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(lensBuffer)))){ - return; - } - - ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); - vec2 pixel_size = vec2(1.0f) / imageSize(lensBuffer); - vec2 UV = pixel_coord.xy * pixel_size; - - vec2 flipped_UV = vec2(1.0f) - UV; - - vec3 color = vec3(0.0f); - - color += ghost_vectors(flipped_UV); - color += halo(UV); - color *= 0.5f; - - imageStore(lensBuffer, pixel_coord, vec4(color, 0.0f)); -} \ No newline at end of file diff --git a/projects/particle_simulation/shaders/bloom/upsample.comp b/projects/particle_simulation/shaders/bloom/upsample.comp deleted file mode 100644 index 0ddeedb5b5af9e476dc19012fed6430544006c0e..0000000000000000000000000000000000000000 --- a/projects/particle_simulation/shaders/bloom/upsample.comp +++ /dev/null @@ -1,45 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(set=0, binding=0) uniform texture2D inUpsampleImage; -layout(set=0, binding=1) uniform sampler inImageSampler; -layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D outUpsampleImage; - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -void main() -{ - if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outUpsampleImage)))){ - return; - } - - - ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); - vec2 pixel_size = vec2(1.0f) / imageSize(outUpsampleImage); - vec2 UV = pixel_coord.xy * pixel_size; - - const float gauss_kernel[3] = {1.f, 2.f, 1.f}; - const float gauss_weight = 16.f; - - vec3 sampled_color = vec3(0.f); - - for(int i = -1; i <= 1; i++) - { - for(int j = -1; j <= 1; j++) - { - vec2 sample_location = UV + vec2(j, i) * pixel_size; - vec3 color = texture(sampler2D(inUpsampleImage, inImageSampler), sample_location).rgb; - color *= gauss_kernel[j+1]; - color *= gauss_kernel[i+1]; - color /= gauss_weight; - - sampled_color += color; - } - } - - //vec3 prev_color = imageLoad(outUpsampleImage, pixel_coord).rgb; - //float bloomRimStrength = 0.75f; // adjust this to change strength of bloom - //sampled_color = mix(prev_color, sampled_color, bloomRimStrength); - - imageStore(outUpsampleImage, pixel_coord, vec4(sampled_color, 1.f)); -} \ No newline at end of file diff --git a/projects/particle_simulation/src/BloomAndFlares.cpp b/projects/particle_simulation/src/BloomAndFlares.cpp deleted file mode 100644 index 6ab0a8deff3d5fe906567562cb86d75a1cc2c09b..0000000000000000000000000000000000000000 --- a/projects/particle_simulation/src/BloomAndFlares.cpp +++ /dev/null @@ -1,293 +0,0 @@ -#include "BloomAndFlares.hpp" -#include <vkcv/shader/GLSLCompiler.hpp> - -BloomAndFlares::BloomAndFlares( - vkcv::Core *p_Core, - vk::Format colorBufferFormat, - uint32_t width, - uint32_t height) : - - p_Core(p_Core), - m_ColorBufferFormat(colorBufferFormat), - m_Width(width), - m_Height(height), - m_LinearSampler(p_Core->createSampler(vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::CLAMP_TO_EDGE)), - m_Blur(p_Core->createImage(colorBufferFormat, width, height, 1, true, true, false)), - m_LensFeatures(p_Core->createImage(colorBufferFormat, width, height, 1, false, true, false)) -{ - vkcv::shader::GLSLCompiler compiler; - - // DOWNSAMPLE - vkcv::ShaderProgram dsProg; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "shaders/bloom/downsample.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - dsProg.addShader(shaderStage, path); - }); - for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++) - { - m_DownsampleDescSetLayouts.push_back( - p_Core->createDescriptorSetLayout(dsProg.getReflectedDescriptors().at(0))); - - m_DownsampleDescSets.push_back( - p_Core->createDescriptorSet(m_DownsampleDescSetLayouts.back())); - } - - m_DownsamplePipe = p_Core->createComputePipeline({ - dsProg, m_DownsampleDescSetLayouts - }); - - // UPSAMPLE - vkcv::ShaderProgram usProg; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "shaders/bloom/upsample.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - usProg.addShader(shaderStage, path); - }); - for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++) - { - m_UpsampleDescSetLayouts.push_back( - p_Core->createDescriptorSetLayout(usProg.getReflectedDescriptors().at(0))); - m_UpsampleDescSets.push_back( - p_Core->createDescriptorSet(m_UpsampleDescSetLayouts.back())); - } - - m_UpsamplePipe = p_Core->createComputePipeline({ - usProg, m_UpsampleDescSetLayouts - }); - - // LENS FEATURES - vkcv::ShaderProgram lensProg; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "shaders/bloom/lensFlares.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - lensProg.addShader(shaderStage, path); - }); - - m_LensFlareDescSetLayout = p_Core->createDescriptorSetLayout(lensProg.getReflectedDescriptors().at(0)); - m_LensFlareDescSet = p_Core->createDescriptorSet(m_LensFlareDescSetLayout); - m_LensFlarePipe = p_Core->createComputePipeline({ - lensProg, { m_LensFlareDescSetLayout } - }); - - // COMPOSITE - vkcv::ShaderProgram compProg; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "shaders/bloom/composite.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - compProg.addShader(shaderStage, path); - }); - - m_CompositeDescSetLayout = p_Core->createDescriptorSetLayout(compProg.getReflectedDescriptors().at(0)); - m_CompositeDescSet = p_Core->createDescriptorSet(m_CompositeDescSetLayout); - m_CompositePipe = p_Core->createComputePipeline({ - compProg, { m_CompositeDescSetLayout } - }); -} - -void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, - const vkcv::ImageHandle &colorAttachment) -{ - auto dispatchCountX = static_cast<float>(m_Width) / 8.0f; - auto dispatchCountY = static_cast<float>(m_Height) / 8.0f; - // blur dispatch - uint32_t initialDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(dispatchCountX)), - static_cast<uint32_t>(glm::ceil(dispatchCountY)), - 1 - }; - - // downsample dispatch of original color attachment - p_Core->prepareImageForSampling(cmdStream, colorAttachment); - p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); - - vkcv::DescriptorWrites initialDownsampleWrites; - initialDownsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, colorAttachment)}; - initialDownsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; - initialDownsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), 0) }; - p_Core->writeDescriptorSet(m_DownsampleDescSets[0], initialDownsampleWrites); - - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_DownsamplePipe, - initialDispatchCount, - {vkcv::DescriptorSetUsage(0, m_DownsampleDescSets[0])}, - vkcv::PushConstants(0)); - - // downsample dispatches of blur buffer's mip maps - float mipDispatchCountX = dispatchCountX; - float mipDispatchCountY = dispatchCountY; - for(uint32_t mipLevel = 1; mipLevel < std::min((uint32_t)m_DownsampleDescSets.size(), m_Blur.getMipCount()); mipLevel++) - { - // mip descriptor writes - vkcv::DescriptorWrites mipDescriptorWrites; - mipDescriptorWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel - 1, true)}; - mipDescriptorWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; - mipDescriptorWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel) }; - p_Core->writeDescriptorSet(m_DownsampleDescSets[mipLevel], mipDescriptorWrites); - - // mip dispatch calculation - mipDispatchCountX /= 2.0f; - mipDispatchCountY /= 2.0f; - - uint32_t mipDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(mipDispatchCountX)), - static_cast<uint32_t>(glm::ceil(mipDispatchCountY)), - 1 - }; - - if(mipDispatchCount[0] == 0) - mipDispatchCount[0] = 1; - if(mipDispatchCount[1] == 0) - mipDispatchCount[1] = 1; - - // mip blur dispatch - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_DownsamplePipe, - mipDispatchCount, - {vkcv::DescriptorSetUsage(0, m_DownsampleDescSets[mipLevel])}, - vkcv::PushConstants(0)); - - // image barrier between mips - p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); - } -} - -void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream) -{ - // upsample dispatch - p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); - - const uint32_t upsampleMipLevels = std::min( - static_cast<uint32_t>(m_UpsampleDescSets.size() - 1), - static_cast<uint32_t>(3) - ); - - // upsample dispatch for each mip map - for(uint32_t mipLevel = upsampleMipLevels; mipLevel > 0; mipLevel--) - { - // mip descriptor writes - vkcv::DescriptorWrites mipUpsampleWrites; - mipUpsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel, true)}; - mipUpsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; - mipUpsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel - 1) }; - p_Core->writeDescriptorSet(m_UpsampleDescSets[mipLevel], mipUpsampleWrites); - - auto mipDivisor = glm::pow(2.0f, static_cast<float>(mipLevel) - 1.0f); - - auto upsampleDispatchX = static_cast<float>(m_Width) / mipDivisor; - auto upsampleDispatchY = static_cast<float>(m_Height) / mipDivisor; - upsampleDispatchX /= 8.0f; - upsampleDispatchY /= 8.0f; - - const uint32_t upsampleDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(upsampleDispatchX)), - static_cast<uint32_t>(glm::ceil(upsampleDispatchY)), - 1 - }; - - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_UpsamplePipe, - upsampleDispatchCount, - {vkcv::DescriptorSetUsage(0, m_UpsampleDescSets[mipLevel])}, - vkcv::PushConstants(0) - ); - // image barrier between mips - p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); - } -} - -void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream) -{ - // lens feature generation descriptor writes - p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); - p_Core->prepareImageForStorage(cmdStream, m_LensFeatures.getHandle()); - - vkcv::DescriptorWrites lensFeatureWrites; - lensFeatureWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), 0)}; - lensFeatureWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; - lensFeatureWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_LensFeatures.getHandle(), 0)}; - p_Core->writeDescriptorSet(m_LensFlareDescSet, lensFeatureWrites); - - auto dispatchCountX = static_cast<float>(m_Width) / 8.0f; - auto dispatchCountY = static_cast<float>(m_Height) / 8.0f; - // lens feature generation dispatch - uint32_t lensFeatureDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(dispatchCountX)), - static_cast<uint32_t>(glm::ceil(dispatchCountY)), - 1 - }; - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_LensFlarePipe, - lensFeatureDispatchCount, - {vkcv::DescriptorSetUsage(0, m_LensFlareDescSet)}, - vkcv::PushConstants(0)); -} - -void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, - const vkcv::ImageHandle &colorAttachment) -{ - p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); - p_Core->prepareImageForSampling(cmdStream, m_LensFeatures.getHandle()); - p_Core->prepareImageForStorage(cmdStream, colorAttachment); - - // bloom composite descriptor write - vkcv::DescriptorWrites compositeWrites; - compositeWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle()), - vkcv::SampledImageDescriptorWrite(1, m_LensFeatures.getHandle())}; - compositeWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(2, m_LinearSampler)}; - compositeWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(3, colorAttachment)}; - p_Core->writeDescriptorSet(m_CompositeDescSet, compositeWrites); - - float dispatchCountX = static_cast<float>(m_Width) / 8.0f; - float dispatchCountY = static_cast<float>(m_Height) / 8.0f; - - uint32_t compositeDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(dispatchCountX)), - static_cast<uint32_t>(glm::ceil(dispatchCountY)), - 1 - }; - - // bloom composite dispatch - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_CompositePipe, - compositeDispatchCount, - {vkcv::DescriptorSetUsage(0, m_CompositeDescSet)}, - vkcv::PushConstants(0)); -} - -void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, - const vkcv::ImageHandle &colorAttachment) -{ - execDownsamplePipe(cmdStream, colorAttachment); - execUpsamplePipe(cmdStream); - execLensFeaturePipe(cmdStream); - execCompositePipe(cmdStream, colorAttachment); -} - -void BloomAndFlares::updateImageDimensions(uint32_t width, uint32_t height) -{ - if ((width == m_Width) && (height == m_Height)) { - return; - } - - m_Width = width; - m_Height = height; - - p_Core->getContext().getDevice().waitIdle(); - m_Blur = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, true, true, false); - m_LensFeatures = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, false, true, false); -} - - diff --git a/projects/particle_simulation/src/BloomAndFlares.hpp b/projects/particle_simulation/src/BloomAndFlares.hpp deleted file mode 100644 index 2692034db51cf341e7ede2a26f5724c92dccbfed..0000000000000000000000000000000000000000 --- a/projects/particle_simulation/src/BloomAndFlares.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include <vkcv/Core.hpp> -#include <glm/glm.hpp> - -class BloomAndFlares{ -public: - BloomAndFlares(vkcv::Core *p_Core, - vk::Format colorBufferFormat, - uint32_t width, - uint32_t height); - - void execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); - - void updateImageDimensions(uint32_t width, uint32_t height); - -private: - vkcv::Core *p_Core; - - vk::Format m_ColorBufferFormat; - uint32_t m_Width; - uint32_t m_Height; - - vkcv::SamplerHandle m_LinearSampler; - vkcv::Image m_Blur; - vkcv::Image m_LensFeatures; - - vkcv::ComputePipelineHandle m_DownsamplePipe; - std::vector<vkcv::DescriptorSetLayoutHandle> m_DownsampleDescSetLayouts; - std::vector<vkcv::DescriptorSetHandle> m_DownsampleDescSets; // per mip desc set - - vkcv::ComputePipelineHandle m_UpsamplePipe; - std::vector<vkcv::DescriptorSetLayoutHandle> m_UpsampleDescSetLayouts; - std::vector<vkcv::DescriptorSetHandle> m_UpsampleDescSets; // per mip desc set - - vkcv::ComputePipelineHandle m_LensFlarePipe; - vkcv::DescriptorSetLayoutHandle m_LensFlareDescSetLayout; - vkcv::DescriptorSetHandle m_LensFlareDescSet; - - vkcv::ComputePipelineHandle m_CompositePipe; - vkcv::DescriptorSetLayoutHandle m_CompositeDescSetLayout; - vkcv::DescriptorSetHandle m_CompositeDescSet; - - void execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); - void execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream); - void execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream); - void execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); -}; - - - diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp index 6637041e5ea9c8f1dd3dadf0303049d2a3b749e9..f1490e6f035b1a378afcb59436814986b3aca51f 100644 --- a/projects/particle_simulation/src/main.cpp +++ b/projects/particle_simulation/src/main.cpp @@ -8,7 +8,7 @@ #include <glm/gtc/matrix_access.hpp> #include <ctime> #include <vkcv/shader/GLSLCompiler.hpp> -#include "BloomAndFlares.hpp" +#include <vkcv/effects/BloomAndFlaresEffect.hpp> int main(int argc, const char **argv) { const char *applicationName = "Particlesystem"; @@ -22,7 +22,7 @@ int main(int argc, const char **argv) { {vk::QueueFlagBits::eTransfer, vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute}, { VK_KHR_SWAPCHAIN_EXTENSION_NAME } ); - vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, false); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, true); vkcv::Window& window = core.getWindow(windowHandle); vkcv::camera::CameraManager cameraManager(window); @@ -212,7 +212,7 @@ int main(int argc, const char **argv) { cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, -2.0f)); cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, 0.0f)); - auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); + const auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); vkcv::ImageHandle colorBuffer = core.createImage( colorFormat, @@ -220,17 +220,9 @@ int main(int argc, const char **argv) { swapchainExtent.height, 1, false, true, true ).getHandle(); - BloomAndFlares bloomAndFlares(&core, colorFormat, swapchainExtent.width, swapchainExtent.height); - window.e_resize.add([&](int width, int height) { - swapchainExtent = core.getSwapchain(windowHandle).getExtent(); - colorBuffer = core.createImage( - colorFormat, - swapchainExtent.width, - swapchainExtent.height, - 1, false, true, true - ).getHandle(); - bloomAndFlares.updateImageDimensions(width, height); - }); + + vkcv::effects::BloomAndFlaresEffect bloomAndFlares (core); + bloomAndFlares.setUpsamplingLimit(3); vkcv::ShaderProgram tonemappingShader; compiler.compile(vkcv::ShaderStage::COMPUTE, "shaders/tonemapping.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { @@ -253,6 +245,16 @@ int main(int argc, const char **argv) { if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { continue; } + + if ((core.getImageWidth(colorBuffer) != swapchainWidth) || + (core.getImageHeight(colorBuffer) != swapchainHeight)) { + colorBuffer = core.createImage( + colorFormat, + swapchainWidth, + swapchainHeight, + 1, false, true, true + ).getHandle(); + } color.fill(&colorData); position.fill(&pos); @@ -299,8 +301,8 @@ int main(int argc, const char **argv) { {drawcalls}, { colorBuffer }, windowHandle); - - bloomAndFlares.execWholePipeline(cmdStream, colorBuffer); + + bloomAndFlares.recordEffect(cmdStream, colorBuffer, colorBuffer); core.prepareImageForStorage(cmdStream, colorBuffer); core.prepareImageForStorage(cmdStream, swapchainInput); @@ -313,8 +315,8 @@ int main(int argc, const char **argv) { core.writeDescriptorSet(tonemappingDescriptor, tonemappingDescriptorWrites); uint32_t tonemappingDispatchCount[3]; - tonemappingDispatchCount[0] = std::ceil(swapchainExtent.width / 8.f); - tonemappingDispatchCount[1] = std::ceil(swapchainExtent.height / 8.f); + tonemappingDispatchCount[0] = std::ceil(swapchainWidth / 8.f); + tonemappingDispatchCount[1] = std::ceil(swapchainHeight / 8.f); tonemappingDispatchCount[2] = 1; core.recordComputeDispatchToCmdStream( diff --git a/projects/rtx_ambient_occlusion/src/main.cpp b/projects/rtx_ambient_occlusion/src/main.cpp index d4c8ec2cac8e26f70da346738da04de16a766a26..becd80c4e4478da38a8e3722cbf30d39fd159ca6 100644 --- a/projects/rtx_ambient_occlusion/src/main.cpp +++ b/projects/rtx_ambient_occlusion/src/main.cpp @@ -13,9 +13,6 @@ int main(int argc, const char** argv) { const char* applicationName = "RTX Ambient Occlusion"; - uint32_t windowWidth = 800; - uint32_t windowHeight = 600; - // prepare raytracing extensions. IMPORTANT: configure compiler to build in 64 bit mode vkcv::rtx::RTXExtensions rtxExtensions; std::vector<const char*> raytracingInstanceExtensions = rtxExtensions.getInstanceExtensions(); @@ -35,7 +32,7 @@ int main(int argc, const char** argv) { vkcv::rtx::ASManager asManager(&core); - vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, false); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 800, 600, true); vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle)); uint32_t camIndex = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); @@ -91,7 +88,7 @@ int main(int argc, const char** argv) { vkcv::rtx::ShaderBindingTableRegions rtxRegions = rtxModule.createRegions(); - vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight).getHandle(); + vkcv::ImageHandle depthBuffer; const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); @@ -109,11 +106,14 @@ int main(int argc, const char** argv) { continue; } - if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) { - depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); - - windowWidth = swapchainWidth; - windowHeight = swapchainHeight; + if ((!depthBuffer) || + (swapchainWidth != core.getImageWidth(depthBuffer)) || + ((swapchainHeight != core.getImageHeight(depthBuffer)))) { + depthBuffer = core.createImage( + vk::Format::eD32Sfloat, + swapchainWidth, + swapchainHeight + ).getHandle(); } auto end = std::chrono::system_clock::now(); diff --git a/projects/saf_r/src/main.cpp b/projects/saf_r/src/main.cpp index ea5378406b092a92a1f8ee8149630f72059ca391..85420cfd859010c10355dde77be22fc6b5a5f54a 100644 --- a/projects/saf_r/src/main.cpp +++ b/projects/saf_r/src/main.cpp @@ -38,7 +38,7 @@ int main(int argc, const char** argv) { { "VK_KHR_swapchain" } ); - vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, false); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, true); //configuring the compute Shader vkcv::PassConfig computePassDefinition({}); @@ -171,12 +171,12 @@ int main(int argc, const char** argv) { //create the render pipeline + compute pipeline const vkcv::GraphicsPipelineConfig safrPipelineDefinition{ safrShaderProgram, - (uint32_t)windowWidth, - (uint32_t)windowHeight, + UINT32_MAX, + UINT32_MAX, safrPass, {}, { descriptorSetLayout }, - false + true }; vkcv::GraphicsPipelineHandle safrPipeline = core.createGraphicsPipeline(safrPipelineDefinition); @@ -273,7 +273,7 @@ int main(int argc, const char** argv) { pushConstantsCompute.appendDrawcall(raytracingPushData); //dispatch compute shader - uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil( swapchainWidth/16.f)), + uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil(swapchainWidth/16.f)), static_cast<uint32_t> (std::ceil(swapchainHeight/16.f)), 1 }; // Anzahl workgroups core.recordComputeDispatchToCmdStream(cmdStream, diff --git a/projects/sph/CMakeLists.txt b/projects/sph/CMakeLists.txt index 8be89e0891d697bc22088e54dbeea5541d7f2065..985a33938b02202d05ac84a03dd505a35dd6b8a6 100644 --- a/projects/sph/CMakeLists.txt +++ b/projects/sph/CMakeLists.txt @@ -13,23 +13,24 @@ add_executable(sph src/main.cpp src/Particle.hpp src/Particle.cpp - src/BloomAndFlares.hpp - src/BloomAndFlares.cpp src/PipelineInit.hpp src/PipelineInit.cpp) -# this should fix the execution path to load local files from the project (for MSVC) -if(MSVC) - set_target_properties(sph PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) - set_target_properties(sph PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) - - # in addition to setting the output directory, the working directory has to be set - # by default visual studio sets the working directory to the build directory, when using the debugger - set_target_properties(sph PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) -endif() +fix_project(sph) # including headers of dependencies and the VkCV framework -target_include_directories(sph SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include}) +target_include_directories(sph SYSTEM BEFORE PRIVATE + ${vkcv_include} + ${vkcv_includes} + ${vkcv_testing_include} + ${vkcv_camera_include} + ${vkcv_shader_compiler_include} + ${vkcv_effects_include}) # linking with libraries from all dependencies and the VkCV framework -target_link_libraries(sph vkcv vkcv_testing vkcv_camera vkcv_shader_compiler) +target_link_libraries(sph + vkcv + vkcv_testing + vkcv_camera + vkcv_shader_compiler + vkcv_effects) diff --git a/projects/sph/shaders/bloom/composite.comp b/projects/sph/shaders/bloom/composite.comp deleted file mode 100644 index 87b5ddb975106232d1cd3b6e5b8dc7e623dd0b59..0000000000000000000000000000000000000000 --- a/projects/sph/shaders/bloom/composite.comp +++ /dev/null @@ -1,38 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(set=0, binding=0) uniform texture2D blurImage; -layout(set=0, binding=1) uniform texture2D lensImage; -layout(set=0, binding=2) uniform sampler linearSampler; -layout(set=0, binding=3, r11f_g11f_b10f) uniform image2D colorBuffer; - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - - -void main() -{ - if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(colorBuffer)))){ - return; - } - - ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); - vec2 pixel_size = vec2(1.0f) / textureSize(sampler2D(blurImage, linearSampler), 0); - vec2 UV = pixel_coord.xy * pixel_size; - - vec4 composite_color = vec4(0.0f); - - vec3 blur_color = texture(sampler2D(blurImage, linearSampler), UV).rgb; - vec3 lens_color = texture(sampler2D(lensImage, linearSampler), UV).rgb; - vec3 main_color = imageLoad(colorBuffer, pixel_coord).rgb; - - // composite blur and lens features - float bloom_weight = 0.01f; - float lens_weight = 0.f; - float main_weight = 1 - (bloom_weight + lens_weight); - - composite_color.rgb = blur_color * bloom_weight + - lens_color * lens_weight + - main_color * main_weight; - - imageStore(colorBuffer, pixel_coord, composite_color); -} \ No newline at end of file diff --git a/projects/sph/shaders/bloom/downsample.comp b/projects/sph/shaders/bloom/downsample.comp deleted file mode 100644 index 2ab00c7c92798769153634f3479c5b7f3fb61d94..0000000000000000000000000000000000000000 --- a/projects/sph/shaders/bloom/downsample.comp +++ /dev/null @@ -1,76 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(set=0, binding=0) uniform texture2D inBlurImage; -layout(set=0, binding=1) uniform sampler inImageSampler; -layout(set=0, binding=2, r11f_g11f_b10f) uniform writeonly image2D outBlurImage; - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - - -void main() -{ - if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outBlurImage)))){ - return; - } - - ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); - vec2 pixel_size = vec2(1.0f) / imageSize(outBlurImage); - vec2 UV = pixel_coord.xy * pixel_size; - vec2 UV_offset = UV + 0.5f * pixel_size; - - vec2 color_fetches[13] = { - // center neighbourhood (RED) - vec2(-1, 1), // LT - vec2(-1, -1), // LB - vec2( 1, -1), // RB - vec2( 1, 1), // RT - - vec2(-2, 2), // LT - vec2( 0, 2), // CT - vec2( 2, 2), // RT - - vec2(0 ,-2), // LC - vec2(0 , 0), // CC - vec2(2, 0), // CR - - vec2(-2, -2), // LB - vec2(0 , -2), // CB - vec2(2 , -2) // RB - }; - - float color_weights[13] = { - // 0.5f - 1.f/8.f, - 1.f/8.f, - 1.f/8.f, - 1.f/8.f, - - // 0.125f - 1.f/32.f, - 1.f/16.f, - 1.f/32.f, - - // 0.25f - 1.f/16.f, - 1.f/8.f, - 1.f/16.f, - - // 0.125f - 1.f/32.f, - 1.f/16.f, - 1.f/32.f - }; - - vec3 sampled_color = vec3(0.0f); - - for(uint i = 0; i < 13; i++) - { - vec2 color_fetch = UV_offset + color_fetches[i] * pixel_size; - vec3 color = texture(sampler2D(inBlurImage, inImageSampler), color_fetch).rgb; - color *= color_weights[i]; - sampled_color += color; - } - - imageStore(outBlurImage, pixel_coord, vec4(sampled_color, 1.f)); -} \ No newline at end of file diff --git a/projects/sph/shaders/bloom/lensFlares.comp b/projects/sph/shaders/bloom/lensFlares.comp deleted file mode 100644 index ce27d8850b709f61332d467914ddc944dc63109f..0000000000000000000000000000000000000000 --- a/projects/sph/shaders/bloom/lensFlares.comp +++ /dev/null @@ -1,109 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(set=0, binding=0) uniform texture2D blurBuffer; -layout(set=0, binding=1) uniform sampler linearSampler; -layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D lensBuffer; - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -vec3 sampleColorChromaticAberration(vec2 _uv) -{ - vec2 toCenter = (vec2(0.5) - _uv); - - vec3 colorScales = vec3(-1, 0, 1); - float aberrationScale = 0.1; - vec3 scaleFactors = colorScales * aberrationScale; - - float r = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.r).r; - float g = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.g).g; - float b = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.b).b; - return vec3(r, g, b); -} - -// _uv assumed to be flipped UV coordinates! -vec3 ghost_vectors(vec2 _uv) -{ - vec2 ghost_vec = (vec2(0.5f) - _uv); - - const uint c_ghost_count = 64; - const float c_ghost_spacing = length(ghost_vec) / c_ghost_count; - - ghost_vec *= c_ghost_spacing; - - vec3 ret_color = vec3(0.0f); - - for (uint i = 0; i < c_ghost_count; ++i) - { - // sample scene color - vec2 s_uv = fract(_uv + ghost_vec * vec2(i)); - vec3 s = sampleColorChromaticAberration(s_uv); - - // tint/weight - float d = distance(s_uv, vec2(0.5)); - float weight = 1.0f - smoothstep(0.0f, 0.75f, d); - s *= weight; - - ret_color += s; - } - - ret_color /= c_ghost_count; - return ret_color; -} - -vec3 halo(vec2 _uv) -{ - const float c_aspect_ratio = float(imageSize(lensBuffer).x) / float(imageSize(lensBuffer).y); - const float c_radius = 0.6f; - const float c_halo_thickness = 0.1f; - - vec2 halo_vec = vec2(0.5) - _uv; - //halo_vec.x /= c_aspect_ratio; - halo_vec = normalize(halo_vec); - //halo_vec.x *= c_aspect_ratio; - - - //vec2 w_uv = (_uv - vec2(0.5, 0.0)) * vec2(c_aspect_ratio, 1.0) + vec2(0.5, 0.0); - vec2 w_uv = _uv; - float d = distance(w_uv, vec2(0.5)); // distance to center - - float distance_to_halo = abs(d - c_radius); - - float halo_weight = 0.0f; - if(abs(d - c_radius) <= c_halo_thickness) - { - float distance_to_border = c_halo_thickness - distance_to_halo; - halo_weight = distance_to_border / c_halo_thickness; - - //halo_weight = clamp((halo_weight / 0.4f), 0.0f, 1.0f); - halo_weight = pow(halo_weight, 2.0f); - - - //halo_weight = 1.0f; - } - - return sampleColorChromaticAberration(_uv + halo_vec) * halo_weight; -} - - - -void main() -{ - if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(lensBuffer)))){ - return; - } - - ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); - vec2 pixel_size = vec2(1.0f) / imageSize(lensBuffer); - vec2 UV = pixel_coord.xy * pixel_size; - - vec2 flipped_UV = vec2(1.0f) - UV; - - vec3 color = vec3(0.0f); - - color += ghost_vectors(flipped_UV); - color += halo(UV); - color *= 0.5f; - - imageStore(lensBuffer, pixel_coord, vec4(color, 0.0f)); -} \ No newline at end of file diff --git a/projects/sph/shaders/bloom/upsample.comp b/projects/sph/shaders/bloom/upsample.comp deleted file mode 100644 index 0ddeedb5b5af9e476dc19012fed6430544006c0e..0000000000000000000000000000000000000000 --- a/projects/sph/shaders/bloom/upsample.comp +++ /dev/null @@ -1,45 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(set=0, binding=0) uniform texture2D inUpsampleImage; -layout(set=0, binding=1) uniform sampler inImageSampler; -layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D outUpsampleImage; - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -void main() -{ - if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outUpsampleImage)))){ - return; - } - - - ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); - vec2 pixel_size = vec2(1.0f) / imageSize(outUpsampleImage); - vec2 UV = pixel_coord.xy * pixel_size; - - const float gauss_kernel[3] = {1.f, 2.f, 1.f}; - const float gauss_weight = 16.f; - - vec3 sampled_color = vec3(0.f); - - for(int i = -1; i <= 1; i++) - { - for(int j = -1; j <= 1; j++) - { - vec2 sample_location = UV + vec2(j, i) * pixel_size; - vec3 color = texture(sampler2D(inUpsampleImage, inImageSampler), sample_location).rgb; - color *= gauss_kernel[j+1]; - color *= gauss_kernel[i+1]; - color /= gauss_weight; - - sampled_color += color; - } - } - - //vec3 prev_color = imageLoad(outUpsampleImage, pixel_coord).rgb; - //float bloomRimStrength = 0.75f; // adjust this to change strength of bloom - //sampled_color = mix(prev_color, sampled_color, bloomRimStrength); - - imageStore(outUpsampleImage, pixel_coord, vec4(sampled_color, 1.f)); -} \ No newline at end of file diff --git a/projects/sph/src/BloomAndFlares.cpp b/projects/sph/src/BloomAndFlares.cpp deleted file mode 100644 index 200c0dea16a0b1483a8b20786902b38a43b5f825..0000000000000000000000000000000000000000 --- a/projects/sph/src/BloomAndFlares.cpp +++ /dev/null @@ -1,289 +0,0 @@ -#include "BloomAndFlares.hpp" -#include <vkcv/shader/GLSLCompiler.hpp> - -BloomAndFlares::BloomAndFlares( - vkcv::Core *p_Core, - vk::Format colorBufferFormat, - uint32_t width, - uint32_t height) : - - p_Core(p_Core), - m_ColorBufferFormat(colorBufferFormat), - m_Width(width), - m_Height(height), - m_LinearSampler(p_Core->createSampler(vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::CLAMP_TO_EDGE)), - m_Blur(p_Core->createImage(colorBufferFormat, width, height, 1, true, true, false)), - m_LensFeatures(p_Core->createImage(colorBufferFormat, width, height, 1, false, true, false)) -{ - vkcv::shader::GLSLCompiler compiler; - - // DOWNSAMPLE - vkcv::ShaderProgram dsProg; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "shaders/bloom/downsample.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - dsProg.addShader(shaderStage, path); - }); - for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++) - { - m_DownsampleDescSetLayouts.push_back( - p_Core->createDescriptorSetLayout(dsProg.getReflectedDescriptors().at(0))); - - m_DownsampleDescSets.push_back( - p_Core->createDescriptorSet(m_DownsampleDescSetLayouts.back())); - } - m_DownsamplePipe = p_Core->createComputePipeline({ - dsProg, m_DownsampleDescSetLayouts - }); - - // UPSAMPLE - vkcv::ShaderProgram usProg; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "shaders/bloom/upsample.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - usProg.addShader(shaderStage, path); - }); - for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++) - { - m_UpsampleDescSetLayouts.push_back( - p_Core->createDescriptorSetLayout(usProg.getReflectedDescriptors().at(0))); - m_UpsampleDescSets.push_back( - p_Core->createDescriptorSet(m_UpsampleDescSetLayouts.back())); - } - m_UpsamplePipe = p_Core->createComputePipeline({ - usProg, m_UpsampleDescSetLayouts - }); - - // LENS FEATURES - vkcv::ShaderProgram lensProg; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "shaders/bloom/lensFlares.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - lensProg.addShader(shaderStage, path); - }); - m_LensFlareDescSetLayout = p_Core->createDescriptorSetLayout(lensProg.getReflectedDescriptors().at(0)); - m_LensFlareDescSet = p_Core->createDescriptorSet(m_LensFlareDescSetLayout); - m_LensFlarePipe = p_Core->createComputePipeline({ - lensProg, { m_LensFlareDescSetLayout } - }); - - // COMPOSITE - vkcv::ShaderProgram compProg; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "shaders/bloom/composite.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - compProg.addShader(shaderStage, path); - }); - m_CompositeDescSetLayout = p_Core->createDescriptorSetLayout(compProg.getReflectedDescriptors().at(0)); - m_CompositeDescSet = p_Core->createDescriptorSet(m_CompositeDescSetLayout); - m_CompositePipe = p_Core->createComputePipeline({ - compProg, { m_CompositeDescSetLayout } - }); -} - -void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, - const vkcv::ImageHandle &colorAttachment) -{ - auto dispatchCountX = static_cast<float>(m_Width) / 8.0f; - auto dispatchCountY = static_cast<float>(m_Height) / 8.0f; - // blur dispatch - uint32_t initialDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(dispatchCountX)), - static_cast<uint32_t>(glm::ceil(dispatchCountY)), - 1 - }; - - // downsample dispatch of original color attachment - p_Core->prepareImageForSampling(cmdStream, colorAttachment); - p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); - - vkcv::DescriptorWrites initialDownsampleWrites; - initialDownsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, colorAttachment)}; - initialDownsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; - initialDownsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), 0) }; - p_Core->writeDescriptorSet(m_DownsampleDescSets[0], initialDownsampleWrites); - - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_DownsamplePipe, - initialDispatchCount, - {vkcv::DescriptorSetUsage(0, m_DownsampleDescSets[0])}, - vkcv::PushConstants(0)); - - // downsample dispatches of blur buffer's mip maps - float mipDispatchCountX = dispatchCountX; - float mipDispatchCountY = dispatchCountY; - for(uint32_t mipLevel = 1; mipLevel < std::min((uint32_t)m_DownsampleDescSets.size(), m_Blur.getMipCount()); mipLevel++) - { - // mip descriptor writes - vkcv::DescriptorWrites mipDescriptorWrites; - mipDescriptorWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel - 1, true)}; - mipDescriptorWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; - mipDescriptorWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel) }; - p_Core->writeDescriptorSet(m_DownsampleDescSets[mipLevel], mipDescriptorWrites); - - // mip dispatch calculation - mipDispatchCountX /= 2.0f; - mipDispatchCountY /= 2.0f; - - uint32_t mipDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(mipDispatchCountX)), - static_cast<uint32_t>(glm::ceil(mipDispatchCountY)), - 1 - }; - - if(mipDispatchCount[0] == 0) - mipDispatchCount[0] = 1; - if(mipDispatchCount[1] == 0) - mipDispatchCount[1] = 1; - - // mip blur dispatch - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_DownsamplePipe, - mipDispatchCount, - {vkcv::DescriptorSetUsage(0, m_DownsampleDescSets[mipLevel])}, - vkcv::PushConstants(0)); - - // image barrier between mips - p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); - } -} - -void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream) -{ - // upsample dispatch - p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); - - const uint32_t upsampleMipLevels = std::min( - static_cast<uint32_t>(m_UpsampleDescSets.size() - 1), - static_cast<uint32_t>(3) - ); - - // upsample dispatch for each mip map - for(uint32_t mipLevel = upsampleMipLevels; mipLevel > 0; mipLevel--) - { - // mip descriptor writes - vkcv::DescriptorWrites mipUpsampleWrites; - mipUpsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel, true)}; - mipUpsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; - mipUpsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel - 1) }; - p_Core->writeDescriptorSet(m_UpsampleDescSets[mipLevel], mipUpsampleWrites); - - auto mipDivisor = glm::pow(2.0f, static_cast<float>(mipLevel) - 1.0f); - - auto upsampleDispatchX = static_cast<float>(m_Width) / mipDivisor; - auto upsampleDispatchY = static_cast<float>(m_Height) / mipDivisor; - upsampleDispatchX /= 8.0f; - upsampleDispatchY /= 8.0f; - - const uint32_t upsampleDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(upsampleDispatchX)), - static_cast<uint32_t>(glm::ceil(upsampleDispatchY)), - 1 - }; - - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_UpsamplePipe, - upsampleDispatchCount, - {vkcv::DescriptorSetUsage(0, m_UpsampleDescSets[mipLevel])}, - vkcv::PushConstants(0) - ); - // image barrier between mips - p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); - } -} - -void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream) -{ - // lens feature generation descriptor writes - p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); - p_Core->prepareImageForStorage(cmdStream, m_LensFeatures.getHandle()); - - vkcv::DescriptorWrites lensFeatureWrites; - lensFeatureWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), 0)}; - lensFeatureWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; - lensFeatureWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_LensFeatures.getHandle(), 0)}; - p_Core->writeDescriptorSet(m_LensFlareDescSet, lensFeatureWrites); - - auto dispatchCountX = static_cast<float>(m_Width) / 8.0f; - auto dispatchCountY = static_cast<float>(m_Height) / 8.0f; - // lens feature generation dispatch - uint32_t lensFeatureDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(dispatchCountX)), - static_cast<uint32_t>(glm::ceil(dispatchCountY)), - 1 - }; - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_LensFlarePipe, - lensFeatureDispatchCount, - {vkcv::DescriptorSetUsage(0, m_LensFlareDescSet)}, - vkcv::PushConstants(0)); -} - -void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, - const vkcv::ImageHandle &colorAttachment) -{ - p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); - p_Core->prepareImageForSampling(cmdStream, m_LensFeatures.getHandle()); - p_Core->prepareImageForStorage(cmdStream, colorAttachment); - - // bloom composite descriptor write - vkcv::DescriptorWrites compositeWrites; - compositeWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle()), - vkcv::SampledImageDescriptorWrite(1, m_LensFeatures.getHandle())}; - compositeWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(2, m_LinearSampler)}; - compositeWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(3, colorAttachment)}; - p_Core->writeDescriptorSet(m_CompositeDescSet, compositeWrites); - - float dispatchCountX = static_cast<float>(m_Width) / 8.0f; - float dispatchCountY = static_cast<float>(m_Height) / 8.0f; - - uint32_t compositeDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(dispatchCountX)), - static_cast<uint32_t>(glm::ceil(dispatchCountY)), - 1 - }; - - // bloom composite dispatch - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_CompositePipe, - compositeDispatchCount, - {vkcv::DescriptorSetUsage(0, m_CompositeDescSet)}, - vkcv::PushConstants(0)); -} - -void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, - const vkcv::ImageHandle &colorAttachment) -{ - execDownsamplePipe(cmdStream, colorAttachment); - execUpsamplePipe(cmdStream); - execLensFeaturePipe(cmdStream); - execCompositePipe(cmdStream, colorAttachment); -} - -void BloomAndFlares::updateImageDimensions(uint32_t width, uint32_t height) -{ - if ((width == m_Width) && (height == m_Height)) { - return; - } - - m_Width = width; - m_Height = height; - - p_Core->getContext().getDevice().waitIdle(); - m_Blur = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, true, true, false); - m_LensFeatures = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, false, true, false); -} - - diff --git a/projects/sph/src/BloomAndFlares.hpp b/projects/sph/src/BloomAndFlares.hpp deleted file mode 100644 index 1644d38e9c98c7a0bf74d48b173f0e627214f1e1..0000000000000000000000000000000000000000 --- a/projects/sph/src/BloomAndFlares.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -#include <vkcv/Core.hpp> -#include <glm/glm.hpp> - -class BloomAndFlares{ -public: - BloomAndFlares(vkcv::Core *p_Core, - vk::Format colorBufferFormat, - uint32_t width, - uint32_t height); - - void execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); - - void updateImageDimensions(uint32_t width, uint32_t height); - -private: - vkcv::Core *p_Core; - - vk::Format m_ColorBufferFormat; - uint32_t m_Width; - uint32_t m_Height; - - vkcv::SamplerHandle m_LinearSampler; - vkcv::Image m_Blur; - vkcv::Image m_LensFeatures; - - - vkcv::ComputePipelineHandle m_DownsamplePipe; - std::vector<vkcv::DescriptorSetLayoutHandle> m_DownsampleDescSetLayouts; - std::vector<vkcv::DescriptorSetHandle> m_DownsampleDescSets; // per mip desc set - - vkcv::ComputePipelineHandle m_UpsamplePipe; - std::vector<vkcv::DescriptorSetLayoutHandle> m_UpsampleDescSetLayouts; - std::vector<vkcv::DescriptorSetHandle> m_UpsampleDescSets; // per mip desc set - - vkcv::ComputePipelineHandle m_LensFlarePipe; - vkcv::DescriptorSetLayoutHandle m_LensFlareDescSetLayout; - vkcv::DescriptorSetHandle m_LensFlareDescSet; - - vkcv::ComputePipelineHandle m_CompositePipe; - vkcv::DescriptorSetLayoutHandle m_CompositeDescSetLayout; - vkcv::DescriptorSetHandle m_CompositeDescSet; - - void execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); - void execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream); - void execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream); - void execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); -}; - - - diff --git a/projects/sph/src/main.cpp b/projects/sph/src/main.cpp index c3305fdd335115ef108ca87a8065da3f5302e7a0..e7a1c89474374fbd5c72b6cbbb17ccf6b61e398b 100644 --- a/projects/sph/src/main.cpp +++ b/projects/sph/src/main.cpp @@ -5,7 +5,7 @@ #include <random> #include <ctime> #include <vkcv/shader/GLSLCompiler.hpp> -#include "BloomAndFlares.hpp" +#include <vkcv/effects/BloomAndFlaresEffect.hpp> #include "PipelineInit.hpp" #include "Particle.hpp" @@ -20,8 +20,7 @@ int main(int argc, const char **argv) { { VK_KHR_SWAPCHAIN_EXTENSION_NAME } ); - // creating window - vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 1920, 1080, false); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 1280, 720, true); vkcv::Window& window = core.getWindow(windowHandle); vkcv::camera::CameraManager cameraManager(window); @@ -229,7 +228,7 @@ int main(int argc, const char **argv) { cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, -2.5f)); cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, 0.0f)); - auto swapchainExtent = core.getSwapchain(window.getSwapchainHandle()).getExtent(); + const auto swapchainExtent = core.getSwapchain(window.getSwapchainHandle()).getExtent(); vkcv::ImageHandle colorBuffer = core.createImage( colorFormat, @@ -237,13 +236,18 @@ int main(int argc, const char **argv) { swapchainExtent.height, 1, false, true, true ).getHandle(); - BloomAndFlares bloomAndFlares(&core, colorFormat, swapchainExtent.width, swapchainExtent.height); + + vkcv::effects::BloomAndFlaresEffect bloomAndFlares (core); + bloomAndFlares.setUpsamplingLimit(3); //tone mapping shader & pipeline vkcv::ComputePipelineHandle tonemappingPipe; - vkcv::DescriptorSetHandle tonemappingDescriptor = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, - "shaders/tonemapping.comp", tonemappingPipe); - + vkcv::DescriptorSetHandle tonemappingDescriptor = PipelineInit::ComputePipelineInit( + &core, + vkcv::ShaderStage::COMPUTE, + "shaders/tonemapping.comp", + tonemappingPipe + ); while (vkcv::Window::hasOpenWindow()) { vkcv::Window::pollEvents(); @@ -252,6 +256,16 @@ int main(int argc, const char **argv) { if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { continue; } + + if ((core.getImageWidth(colorBuffer) != swapchainWidth) || + (core.getImageHeight(colorBuffer) != swapchainHeight)) { + colorBuffer = core.createImage( + colorFormat, + swapchainWidth, + swapchainHeight, + 1, false, true, true + ).getHandle(); + } color.fill(&colorData); position.fill(&pos); @@ -381,9 +395,10 @@ int main(int argc, const char **argv) { pushConstantsDraw, {drawcalls}, { colorBuffer }, - windowHandle); - - bloomAndFlares.execWholePipeline(cmdStream, colorBuffer); + windowHandle + ); + + bloomAndFlares.recordEffect(cmdStream, colorBuffer, colorBuffer); core.prepareImageForStorage(cmdStream, colorBuffer); core.prepareImageForStorage(cmdStream, swapchainInput); @@ -396,8 +411,8 @@ int main(int argc, const char **argv) { core.writeDescriptorSet(tonemappingDescriptor, tonemappingDescriptorWrites); uint32_t tonemappingDispatchCount[3]; - tonemappingDispatchCount[0] = std::ceil(swapchainExtent.width / 8.f); - tonemappingDispatchCount[1] = std::ceil(swapchainExtent.height / 8.f); + tonemappingDispatchCount[0] = std::ceil(swapchainWidth / 8.f); + tonemappingDispatchCount[1] = std::ceil(swapchainHeight / 8.f); tonemappingDispatchCount[2] = 1; core.recordComputeDispatchToCmdStream( diff --git a/projects/voxelization/CMakeLists.txt b/projects/voxelization/CMakeLists.txt index ba3c467766377d22925ac9c90acffee7fe324332..0f0585d9d5d9a26cb2daec486f3df8c417a01527 100644 --- a/projects/voxelization/CMakeLists.txt +++ b/projects/voxelization/CMakeLists.txt @@ -15,14 +15,29 @@ target_sources(voxelization PRIVATE src/Voxelization.hpp src/Voxelization.cpp src/ShadowMapping.hpp - src/ShadowMapping.cpp - src/BloomAndFlares.hpp - src/BloomAndFlares.cpp) + src/ShadowMapping.cpp) fix_project(voxelization) # including headers of dependencies and the VkCV framework -target_include_directories(voxelization SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include} ${vkcv_upscaling_include}) +target_include_directories(voxelization SYSTEM BEFORE PRIVATE + ${vkcv_include} + ${vkcv_includes} + ${vkcv_asset_loader_include} + ${vkcv_camera_include} + ${vkcv_shader_compiler_include} + ${vkcv_gui_include} + ${vkcv_upscaling_include} + ${vkcv_effects_include}) # linking with libraries from all dependencies and the VkCV framework -target_link_libraries(voxelization vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_shader_compiler vkcv_gui vkcv_upscaling) +target_link_libraries(voxelization + vkcv + ${vkcv_libraries} + vkcv_asset_loader + ${vkcv_asset_loader_libraries} + vkcv_camera + vkcv_shader_compiler + vkcv_gui + vkcv_upscaling + vkcv_effects) diff --git a/projects/voxelization/src/BloomAndFlares.cpp b/projects/voxelization/src/BloomAndFlares.cpp deleted file mode 100644 index ddb1326ae83c8bd596ce61dc1c47b81b5ddb17be..0000000000000000000000000000000000000000 --- a/projects/voxelization/src/BloomAndFlares.cpp +++ /dev/null @@ -1,374 +0,0 @@ -#include "BloomAndFlares.hpp" -#include <vkcv/shader/GLSLCompiler.hpp> -#include <vkcv/asset/asset_loader.hpp> - -vkcv::Image loadLenseDirtTexture(vkcv::Core* corePtr) { - const auto texture = vkcv::asset::loadTexture("assets/lensDirt.jpg"); - vkcv::Image image = corePtr->createImage(vk::Format::eR8G8B8A8Unorm, texture.width, texture.height); - image.fill((void*)texture.data.data(), texture.data.size()); - return image; -} - -BloomAndFlares::BloomAndFlares( - vkcv::Core *p_Core, - vk::Format colorBufferFormat, - uint32_t width, - uint32_t height) : - - p_Core(p_Core), - m_ColorBufferFormat(colorBufferFormat), - m_Width(width / 2), - m_Height(height / 2), - m_LinearSampler(p_Core->createSampler(vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::CLAMP_TO_EDGE)), - m_RadialLutSampler(p_Core->createSampler(vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT)), - m_Blur(p_Core->createImage(colorBufferFormat, m_Width, m_Height, 1, true, true, false)), - m_LensFeatures(p_Core->createImage(colorBufferFormat, m_Width, m_Height, 1, true, true, false)), - m_radialLut(p_Core->createImage(vk::Format::eR8G8B8A8Unorm, 128, 10, 1)), - m_lensDirt(loadLenseDirtTexture(p_Core)) -{ - vkcv::shader::GLSLCompiler compiler; - - // DOWNSAMPLE - vkcv::ShaderProgram dsProg; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "assets/shaders/bloomDownsample.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - dsProg.addShader(shaderStage, path); - }); - for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++) - { - m_DownsampleDescSetLayouts.push_back( - p_Core->createDescriptorSetLayout(dsProg.getReflectedDescriptors().at(0)) - ); - m_DownsampleDescSets.push_back(p_Core->createDescriptorSet(m_DownsampleDescSetLayouts.back())); - } - - m_DownsamplePipe = p_Core->createComputePipeline({ - dsProg, m_DownsampleDescSetLayouts - }); - - // UPSAMPLE - vkcv::ShaderProgram usProg; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "assets/shaders/bloomUpsample.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - usProg.addShader(shaderStage, path); - }); - for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++) - { - m_UpsampleDescSetLayouts.push_back( - p_Core->createDescriptorSetLayout(usProg.getReflectedDescriptors().at(0))); - m_UpsampleDescSets.push_back( - p_Core->createDescriptorSet(m_UpsampleDescSetLayouts.back())); - } - for (uint32_t mipLevel = 0; mipLevel < m_LensFeatures.getMipCount(); mipLevel++) { - m_UpsampleLensFlareDescSetLayouts.push_back( - p_Core->createDescriptorSetLayout(usProg.getReflectedDescriptors().at(0))); - m_UpsampleLensFlareDescSets.push_back( - p_Core->createDescriptorSet(m_UpsampleLensFlareDescSetLayouts.back())); - } - - m_UpsamplePipe = p_Core->createComputePipeline({ - usProg, m_UpsampleDescSetLayouts - }); - - // LENS FEATURES - vkcv::ShaderProgram lensProg; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "assets/shaders/lensFlares.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - lensProg.addShader(shaderStage, path); - }); - - m_LensFlareDescSetLayout = p_Core->createDescriptorSetLayout(lensProg.getReflectedDescriptors().at(0)); - m_LensFlareDescSet = p_Core->createDescriptorSet(m_LensFlareDescSetLayout); - m_LensFlarePipe = p_Core->createComputePipeline( - { lensProg, { m_LensFlareDescSetLayout } - }); - - - // COMPOSITE - vkcv::ShaderProgram compProg; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "assets/shaders/bloomFlaresComposite.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - compProg.addShader(shaderStage, path); - }); - - m_CompositeDescSetLayout = p_Core->createDescriptorSetLayout(compProg.getReflectedDescriptors().at(0)); - m_CompositeDescSet = p_Core->createDescriptorSet(m_CompositeDescSetLayout); - m_CompositePipe = p_Core->createComputePipeline( - { compProg, { m_CompositeDescSetLayout } - }); - - // radial LUT - const auto texture = vkcv::asset::loadTexture("assets/RadialLUT.png"); - - m_radialLut.fill((void*)texture.data.data(), texture.data.size()); -} - -void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, - const vkcv::ImageHandle &colorAttachment) -{ - auto dispatchCountX = static_cast<float>(m_Width) / 8.0f; - auto dispatchCountY = static_cast<float>(m_Height) / 8.0f; - // blur dispatch - uint32_t initialDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(dispatchCountX)), - static_cast<uint32_t>(glm::ceil(dispatchCountY)), - 1 - }; - - p_Core->recordBeginDebugLabel(cmdStream, "Bloom downsample", { 1, 1, 1, 1 }); - - // downsample dispatch of original color attachment - p_Core->prepareImageForSampling(cmdStream, colorAttachment); - p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); - - vkcv::DescriptorWrites initialDownsampleWrites; - initialDownsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, colorAttachment)}; - initialDownsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; - initialDownsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), 0) }; - p_Core->writeDescriptorSet(m_DownsampleDescSets[0], initialDownsampleWrites); - - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_DownsamplePipe, - initialDispatchCount, - {vkcv::DescriptorSetUsage(0, m_DownsampleDescSets[0])}, - vkcv::PushConstants(0)); - - // downsample dispatches of blur buffer's mip maps - float mipDispatchCountX = dispatchCountX; - float mipDispatchCountY = dispatchCountY; - for(uint32_t mipLevel = 1; mipLevel < std::min((uint32_t)m_DownsampleDescSets.size(), m_Blur.getMipCount()); mipLevel++) - { - // mip descriptor writes - vkcv::DescriptorWrites mipDescriptorWrites; - mipDescriptorWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel - 1, true)}; - mipDescriptorWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; - mipDescriptorWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel) }; - p_Core->writeDescriptorSet(m_DownsampleDescSets[mipLevel], mipDescriptorWrites); - - // mip dispatch calculation - mipDispatchCountX /= 2.0f; - mipDispatchCountY /= 2.0f; - - uint32_t mipDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(mipDispatchCountX)), - static_cast<uint32_t>(glm::ceil(mipDispatchCountY)), - 1 - }; - - if(mipDispatchCount[0] == 0) - mipDispatchCount[0] = 1; - if(mipDispatchCount[1] == 0) - mipDispatchCount[1] = 1; - - // mip blur dispatch - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_DownsamplePipe, - mipDispatchCount, - {vkcv::DescriptorSetUsage(0, m_DownsampleDescSets[mipLevel])}, - vkcv::PushConstants(0)); - - // image barrier between mips - p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); - } - - p_Core->recordEndDebugLabel(cmdStream); -} - -void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream) -{ - p_Core->recordBeginDebugLabel(cmdStream, "Bloom upsample", { 1, 1, 1, 1 }); - - // upsample dispatch - p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); - - const uint32_t upsampleMipLevels = std::min( - static_cast<uint32_t>(m_UpsampleDescSets.size() - 1), - static_cast<uint32_t>(5) - ); - - // upsample dispatch for each mip map - for(uint32_t mipLevel = upsampleMipLevels; mipLevel > 0; mipLevel--) - { - // mip descriptor writes - vkcv::DescriptorWrites mipUpsampleWrites; - mipUpsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel, true)}; - mipUpsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; - mipUpsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel - 1) }; - p_Core->writeDescriptorSet(m_UpsampleDescSets[mipLevel], mipUpsampleWrites); - - auto mipDivisor = glm::pow(2.0f, static_cast<float>(mipLevel) - 1.0f); - - auto upsampleDispatchX = static_cast<float>(m_Width) / mipDivisor; - auto upsampleDispatchY = static_cast<float>(m_Height) / mipDivisor; - upsampleDispatchX /= 8.0f; - upsampleDispatchY /= 8.0f; - - const uint32_t upsampleDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(upsampleDispatchX)), - static_cast<uint32_t>(glm::ceil(upsampleDispatchY)), - 1 - }; - - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_UpsamplePipe, - upsampleDispatchCount, - {vkcv::DescriptorSetUsage(0, m_UpsampleDescSets[mipLevel])}, - vkcv::PushConstants(0) - ); - // image barrier between mips - p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); - } - - p_Core->recordEndDebugLabel(cmdStream); -} - -void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream) -{ - p_Core->recordBeginDebugLabel(cmdStream, "Lense flare generation", { 1, 1, 1, 1 }); - - // lens feature generation descriptor writes - p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); - p_Core->prepareImageForStorage(cmdStream, m_LensFeatures.getHandle()); - - const uint32_t targetMip = 2; - const uint32_t mipLevel = std::min(targetMip, m_LensFeatures.getMipCount()); - - vkcv::DescriptorWrites lensFeatureWrites; - lensFeatureWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), 0)}; - lensFeatureWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; - lensFeatureWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_LensFeatures.getHandle(), mipLevel)}; - p_Core->writeDescriptorSet(m_LensFlareDescSet, lensFeatureWrites); - - auto dispatchCountX = static_cast<float>(m_Width) / 8.0f; - auto dispatchCountY = static_cast<float>(m_Height) / 8.0f; - // lens feature generation dispatch - uint32_t lensFeatureDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(dispatchCountX / std::exp2(mipLevel))), - static_cast<uint32_t>(glm::ceil(dispatchCountY / std::exp2(mipLevel))), - 1 - }; - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_LensFlarePipe, - lensFeatureDispatchCount, - {vkcv::DescriptorSetUsage(0, m_LensFlareDescSet)}, - vkcv::PushConstants(0)); - - // upsample dispatch - p_Core->prepareImageForStorage(cmdStream, m_LensFeatures.getHandle()); - - // upsample dispatch for each mip map - for (uint32_t i = mipLevel; i > 0; i--) - { - // mip descriptor writes - vkcv::DescriptorWrites mipUpsampleWrites; - mipUpsampleWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, m_LensFeatures.getHandle(), i, true) }; - mipUpsampleWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, m_LinearSampler) }; - mipUpsampleWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, m_LensFeatures.getHandle(), i - 1) }; - p_Core->writeDescriptorSet(m_UpsampleLensFlareDescSets[i], mipUpsampleWrites); - - auto mipDivisor = glm::pow(2.0f, static_cast<float>(i) - 1.0f); - - auto upsampleDispatchX = static_cast<float>(m_Width) / mipDivisor; - auto upsampleDispatchY = static_cast<float>(m_Height) / mipDivisor; - upsampleDispatchX /= 8.0f; - upsampleDispatchY /= 8.0f; - - const uint32_t upsampleDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(upsampleDispatchX)), - static_cast<uint32_t>(glm::ceil(upsampleDispatchY)), - 1 - }; - - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_UpsamplePipe, - upsampleDispatchCount, - { vkcv::DescriptorSetUsage(0, m_UpsampleLensFlareDescSets[i]) }, - vkcv::PushConstants(0) - ); - // image barrier between mips - p_Core->recordImageMemoryBarrier(cmdStream, m_LensFeatures.getHandle()); - } - - p_Core->recordEndDebugLabel(cmdStream); -} - -void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle& colorAttachment, - const uint32_t attachmentWidth, const uint32_t attachmentHeight, const glm::vec3& cameraForward) -{ - p_Core->recordBeginDebugLabel(cmdStream, "Bloom/lense flare composition", { 1, 1, 1, 1 }); - - p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); - p_Core->prepareImageForSampling(cmdStream, m_LensFeatures.getHandle()); - p_Core->prepareImageForStorage(cmdStream, colorAttachment); - - // bloom composite descriptor write - vkcv::DescriptorWrites compositeWrites; - compositeWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle()), - vkcv::SampledImageDescriptorWrite(1, m_LensFeatures.getHandle()), - vkcv::SampledImageDescriptorWrite(4, m_radialLut.getHandle()), - vkcv::SampledImageDescriptorWrite(6, m_lensDirt.getHandle()) }; - compositeWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(2, m_LinearSampler), - vkcv::SamplerDescriptorWrite(5, m_RadialLutSampler) }; - compositeWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(3, colorAttachment)}; - p_Core->writeDescriptorSet(m_CompositeDescSet, compositeWrites); - - float dispatchCountX = static_cast<float>(attachmentWidth) / 8.0f; - float dispatchCountY = static_cast<float>(attachmentHeight) / 8.0f; - - uint32_t compositeDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(dispatchCountX)), - static_cast<uint32_t>(glm::ceil(dispatchCountY)), - 1 - }; - - vkcv::PushConstants pushConstants(sizeof(cameraForward)); - pushConstants.appendDrawcall(cameraForward); - - // bloom composite dispatch - p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_CompositePipe, - compositeDispatchCount, - {vkcv::DescriptorSetUsage(0, m_CompositeDescSet)}, - pushConstants); - - p_Core->recordEndDebugLabel(cmdStream); -} - -void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment, - const uint32_t attachmentWidth, const uint32_t attachmentHeight, const glm::vec3& cameraForward) -{ - execDownsamplePipe(cmdStream, colorAttachment); - execUpsamplePipe(cmdStream); - execLensFeaturePipe(cmdStream); - execCompositePipe(cmdStream, colorAttachment, attachmentWidth, attachmentHeight, cameraForward); -} - -void BloomAndFlares::updateImageDimensions(uint32_t width, uint32_t height) -{ - m_Width = width / 2; - m_Height = height / 2; - - p_Core->getContext().getDevice().waitIdle(); - m_Blur = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, true, true, false); - m_LensFeatures = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, true, true, false); -} \ No newline at end of file diff --git a/projects/voxelization/src/BloomAndFlares.hpp b/projects/voxelization/src/BloomAndFlares.hpp deleted file mode 100644 index 3d63d9f37b4733eaea170a3e4561774c0d53208b..0000000000000000000000000000000000000000 --- a/projects/voxelization/src/BloomAndFlares.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once -#include <vkcv/Core.hpp> -#include <glm/glm.hpp> - -class BloomAndFlares{ -public: - BloomAndFlares(vkcv::Core *p_Core, - vk::Format colorBufferFormat, - uint32_t width, - uint32_t height); - - void execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment, - const uint32_t attachmentWidth, const uint32_t attachmentHeight, const glm::vec3& cameraForward); - - void updateImageDimensions(uint32_t width, uint32_t height); - -private: - vkcv::Core *p_Core; - - vk::Format m_ColorBufferFormat; - uint32_t m_Width; - uint32_t m_Height; - - vkcv::SamplerHandle m_LinearSampler; - vkcv::SamplerHandle m_RadialLutSampler; - vkcv::Image m_Blur; - vkcv::Image m_LensFeatures; - - vkcv::Image m_radialLut; - vkcv::Image m_lensDirt; - - vkcv::ComputePipelineHandle m_DownsamplePipe; - std::vector<vkcv::DescriptorSetLayoutHandle> m_DownsampleDescSetLayouts; - std::vector<vkcv::DescriptorSetHandle> m_DownsampleDescSets; // per mip desc set - - std::vector<vkcv::DescriptorSetLayoutHandle> m_UpsampleLensFlareDescSetLayouts; - std::vector<vkcv::DescriptorSetHandle> m_UpsampleLensFlareDescSets; // per mip desc set - - vkcv::ComputePipelineHandle m_UpsamplePipe; - std::vector<vkcv::DescriptorSetLayoutHandle> m_UpsampleDescSetLayouts; - std::vector<vkcv::DescriptorSetHandle> m_UpsampleDescSets; // per mip desc set - - vkcv::ComputePipelineHandle m_LensFlarePipe; - vkcv::DescriptorSetLayoutHandle m_LensFlareDescSetLayout; - vkcv::DescriptorSetHandle m_LensFlareDescSet; - - vkcv::ComputePipelineHandle m_CompositePipe; - vkcv::DescriptorSetLayoutHandle m_CompositeDescSetLayout; - vkcv::DescriptorSetHandle m_CompositeDescSet; - - void execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); - void execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream); - void execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream); - void execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment, - const uint32_t attachmentWidth, const uint32_t attachmentHeight, const glm::vec3& cameraForward); -}; - - - diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index 2245419f87d196e913ba27e8e78ffff73aab04b6..f01b87a79b287609822635ecc67f7541e1a8e3b6 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -8,9 +8,10 @@ #include "Voxelization.hpp" #include "vkcv/gui/GUI.hpp" #include "ShadowMapping.hpp" -#include "BloomAndFlares.hpp" #include <vkcv/upscaling/FSRUpscaling.hpp> #include <vkcv/upscaling/BilinearUpscaling.hpp> +#include <vkcv/upscaling/NISUpscaling.hpp> +#include <vkcv/effects/BloomAndFlaresEffect.hpp> int main(int argc, const char** argv) { const char* applicationName = "Voxelization"; @@ -556,14 +557,7 @@ int main(int argc, const char** argv) { voxelSampler, msaa); - BloomAndFlares bloomFlares(&core, colorBufferFormat, swapchainExtent.width, swapchainExtent.height); - - window.e_key.add([&](int key, int scancode, int action, int mods) { - if (key == GLFW_KEY_R && action == GLFW_PRESS) { - bloomFlares = BloomAndFlares(&core, colorBufferFormat, swapchainExtent.width, swapchainExtent.height); - } - }); - + vkcv::effects::BloomAndFlaresEffect bloomFlares (core, true); vkcv::Buffer<glm::vec3> cameraPosBuffer = core.createBuffer<glm::vec3>(vkcv::BufferType::UNIFORM, 1); struct VolumetricSettings { @@ -607,8 +601,15 @@ int main(int argc, const char** argv) { bool fsrMipLoadBiasFlagBackup = fsrMipLoadBiasFlag; vkcv::upscaling::BilinearUpscaling upscaling1 (core); + vkcv::upscaling::NISUpscaling upscaling2 (core); - bool bilinearUpscaling = false; + const std::vector<const char*> modeNames = { + "Bilinear Upscaling", + "FSR Upscaling", + "NIS Upscaling" + }; + + int upscalingMode = 0; vkcv::gui::GUI gui(core, windowHandle); @@ -701,8 +702,6 @@ int main(int argc, const char** argv) { swapchainWidth, swapchainHeight, 1, false, true ).getHandle(); - - bloomFlares.updateImageDimensions(swapchainWidth, swapchainHeight); } auto end = std::chrono::system_clock::now(); @@ -869,10 +868,9 @@ int main(int argc, const char** argv) { } core.recordEndDebugLabel(cmdStream); } - - bloomFlares.execWholePipeline(cmdStream, resolvedColorBuffer, fsrWidth, fsrHeight, - glm::normalize(cameraManager.getActiveCamera().getFront()) - ); + + bloomFlares.updateCameraDirection(cameraManager.getActiveCamera()); + bloomFlares.recordEffect(cmdStream, resolvedColorBuffer, resolvedColorBuffer); core.prepareImageForStorage(cmdStream, swapBuffer); core.prepareImageForSampling(cmdStream, resolvedColorBuffer); @@ -890,10 +888,18 @@ int main(int argc, const char** argv) { core.prepareImageForSampling(cmdStream, swapBuffer); core.recordEndDebugLabel(cmdStream); - if (bilinearUpscaling) { - upscaling1.recordUpscaling(cmdStream, swapBuffer, swapBuffer2); - } else { - upscaling.recordUpscaling(cmdStream, swapBuffer, swapBuffer2); + switch (upscalingMode) { + case 0: + upscaling1.recordUpscaling(cmdStream, swapBuffer, swapBuffer2); + break; + case 1: + upscaling.recordUpscaling(cmdStream, swapBuffer, swapBuffer2); + break; + case 2: + upscaling2.recordUpscaling(cmdStream, swapBuffer, swapBuffer2); + break; + default: + break; } core.prepareImageForStorage(cmdStream, swapchainInput); @@ -956,18 +962,19 @@ int main(int argc, const char** argv) { ImGui::DragFloat("Absorption density", &absorptionDensity, 0.0001); ImGui::DragFloat("Volumetric ambient", &volumetricAmbient, 0.002); - float fsrSharpness = upscaling.getSharpness(); + float sharpness = upscaling.getSharpness(); ImGui::Combo("FSR Quality Mode", &fsrModeIndex, fsrModeNames.data(), fsrModeNames.size()); - ImGui::DragFloat("FSR Sharpness", &fsrSharpness, 0.001, 0.0f, 1.0f); + ImGui::DragFloat("FSR Sharpness", &sharpness, 0.001, 0.0f, 1.0f); ImGui::Checkbox("FSR Mip Lod Bias", &fsrMipLoadBiasFlag); - ImGui::Checkbox("Bilinear Upscaling", &bilinearUpscaling); + ImGui::Combo("Upscaling Mode", &upscalingMode, modeNames.data(), modeNames.size()); if ((fsrModeIndex >= 0) && (fsrModeIndex <= 4)) { fsrMode = static_cast<vkcv::upscaling::FSRQualityMode>(fsrModeIndex); } - upscaling.setSharpness(fsrSharpness); + upscaling.setSharpness(sharpness); + upscaling2.setSharpness(sharpness); if (ImGui::Button("Reload forward pass")) { diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp index f7cd67eb756f353d9eb98c4768e2b0d74bbc1ab6..8988e479f0f57693c49ab3dbfc40f056a4cc4d8c 100644 --- a/src/vkcv/Context.cpp +++ b/src/vkcv/Context.cpp @@ -341,25 +341,16 @@ namespace vkcv vma::AllocatorCreateFlags vmaFlags; const vma::AllocatorCreateInfo allocatorCreateInfo ( - vma::AllocatorCreateFlags(), + vmaFlags, physicalDevice, device, 0, nullptr, nullptr, - 0, - nullptr, nullptr, nullptr, instance, - - /* Uses default version when set to 0 (currently VK_VERSION_1_0): - * - * The reason for this is that the allocator restricts the allowed version - * to be at maximum VK_VERSION_1_1 which is already less than - * VK_HEADER_VERSION_COMPLETE at most platforms. - * */ - 0 + VK_HEADER_VERSION_COMPLETE ); vma::Allocator allocator = vma::createAllocator(allocatorCreateInfo); diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index cd24d9e0991b1401aa2443166ba638c017c6a6f9..42e96b515c8844fed9c2e0d5ca0d326ca64bdf9c 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -875,6 +875,10 @@ namespace vkcv vk::Format Core::getImageFormat(const ImageHandle& image) { return m_ImageManager->getImageFormat(image); } + + uint32_t Core::getImageMipLevels(const ImageHandle &image) { + return m_ImageManager->getImageMipCount(image); + } Swapchain& Core::getSwapchainOfCurrentWindow() { return m_SwapchainManager->getSwapchain(Window::getFocusedWindow().getSwapchainHandle());