diff --git a/Doxyfile b/Doxyfile index a657ede81c43b3cae1fc5c17f071aa7dc65add04..249fed47d3c09ceca1e570b3be4f1a20cb1b13c3 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.9.1 +# Doxyfile 1.9.3 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -93,14 +93,6 @@ ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English -# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all generated output in the proper direction. -# Possible values are: None, LTR, RTL and Context. -# The default value is: None. - -OUTPUT_TEXT_DIRECTION = None - # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -258,16 +250,16 @@ TAB_SIZE = 4 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines (in the resulting output). You can put ^^ in the value part of an -# alias to insert a newline as if a physical newline was in the original file. -# When you need a literal { or } or , in the value part of an alias you have to -# escape them by means of a backslash (\), this can lead to conflicts with the -# commands \{ and \} for these it is advised to use the version @{ and @} or use -# a double escape (\\{ and \\}) +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) ALIASES = @@ -312,8 +304,8 @@ OPTIMIZE_OUTPUT_SLICE = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, -# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the # default for Fortran type files). For instance to make doxygen treat .inc files @@ -466,12 +458,12 @@ LOOKUP_CACHE_SIZE = 0 # than 0 to get more control over the balance between CPU load and processing # speed. At this moment only the input processing can be done using multiple # threads. Since this is still an experimental feature the default is set to 1, -# which efficively disables parallel processing. Please report any issues you +# which effectively disables parallel processing. Please report any issues you # encounter. Generating dot graphs in parallel is controlled by the # 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 @@ -610,6 +602,12 @@ HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -767,7 +765,8 @@ FILE_VERSION_FILTER = # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE @@ -813,18 +812,26 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. If -# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO @@ -850,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 = @@ -890,10 +900,10 @@ INPUT_ENCODING = UTF-8 # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), -# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, -# *.ucf, *.qsf and *.ice. +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.cc \ @@ -976,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/* @@ -1261,7 +1271,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see +# this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. @@ -1271,7 +1281,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1353,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. @@ -1378,8 +1395,12 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: -# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1538,16 +1559,28 @@ DISABLE_INDEX = NO # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = YES +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# 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 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. + +FULL_SIDEBAR = NO + # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # @@ -1572,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 @@ -1620,11 +1660,29 @@ FORMULA_MACROFILE = USE_MATHJAX = NO +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1637,15 +1695,21 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = @@ -1825,29 +1889,31 @@ PAPER_TYPE = a4 EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empty -# string, for the replacement values of the other commands the user is referred -# to HTML_HEADER. +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. See +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what -# special commands can be used inside the footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = @@ -1892,8 +1958,7 @@ USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode # command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# if errors occur, instead of asking the user for help. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1906,16 +1971,6 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO -# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source -# code with syntax highlighting in the LaTeX output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_SOURCE_CODE = NO - # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See # https://en.wikipedia.org/wiki/BibTeX and \cite for more info. @@ -1996,16 +2051,6 @@ RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = -# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code -# with syntax highlighting in the RTF output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_RTF is set to YES. - -RTF_SOURCE_CODE = NO - #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- @@ -2102,15 +2147,6 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook -# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the -# program listings (including syntax highlighting and cross-referencing -# information) to the DOCBOOK output. Note that enabling this will significantly -# increase the size of the DOCBOOK output. -# The default value is: NO. -# This tag requires that the tag GENERATE_DOCBOOK is set to YES. - -DOCBOOK_PROGRAMLISTING = NO - #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- @@ -2293,15 +2329,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. @@ -2358,11 +2385,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 @@ -2491,6 +2521,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: @@ -2544,10 +2581,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 = @@ -2609,6 +2646,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. @@ -2617,8 +2656,8 @@ GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. # -# Note: This setting is not only used for dot files but also for msc and -# plantuml temporary files. +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. DOT_CLEANUP = YES diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 77370fb39b1a5a300614fe9cfb0b505e5ef2dd67..cac5bdf5d6e4d1cb182d8b9036695378165a5e65 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -265,7 +265,7 @@ namespace vkcv * @return swapchain */ [[nodiscard]] - Swapchain& getSwapchain(const SwapchainHandle& handle); + Swapchain& getSwapchain(const SwapchainHandle &handle); /** * gets the swapchain handle from the window @@ -273,7 +273,7 @@ namespace vkcv * @return the swapchain from getSwapchain( SwapchainHandle ) */ [[nodiscard]] - Swapchain& getSwapchain(const WindowHandle& handle); + Swapchain& getSwapchain(const WindowHandle &handle); /** * returns the image width @@ -281,7 +281,7 @@ namespace vkcv * @return imageWidth */ [[nodiscard]] - uint32_t getImageWidth(const ImageHandle& image); + uint32_t getImageWidth(const ImageHandle &image); /** * returns the image height @@ -289,7 +289,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 @@ -297,7 +297,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); /** TODO: * @param bindings 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/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/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..db17621eb6ee46a2a4e6e0564323c59045915c57 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"; @@ -220,7 +220,10 @@ 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); + window.e_resize.add([&](int width, int height) { swapchainExtent = core.getSwapchain(windowHandle).getExtent(); colorBuffer = core.createImage( @@ -229,7 +232,6 @@ int main(int argc, const char **argv) { swapchainExtent.height, 1, false, true, true ).getHandle(); - bloomAndFlares.updateImageDimensions(width, height); }); vkcv::ShaderProgram tonemappingShader; @@ -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); 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 44d38850a134327e1bd4733d45e9e2aed295f8b3..4e98a3013484c75da7c39c711ff4312535a71ef6 100644 --- a/projects/sph/src/main.cpp +++ b/projects/sph/src/main.cpp @@ -9,7 +9,7 @@ #include <glm/gtc/matrix_transform.hpp> #include <time.h> #include <vkcv/shader/GLSLCompiler.hpp> -#include "BloomAndFlares.hpp" +#include <vkcv/effects/BloomAndFlaresEffect.hpp> #include "PipelineInit.hpp" #include "Particle.hpp" @@ -234,7 +234,9 @@ 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; @@ -375,8 +377,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); 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..dd4e0374e7e18477f69fde79e090e3d4c5689aa5 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -8,9 +8,9 @@ #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/effects/BloomAndFlaresEffect.hpp> int main(int argc, const char** argv) { const char* applicationName = "Voxelization"; @@ -556,14 +556,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 { @@ -701,8 +694,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 +860,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); diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index ba69cab5fcd2a1ce78e5a3491e24ab7f273e0474..a44ee97821e4fbf6241e74b9f010fcf46970e91f 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());