├── .gitattributes
├── .gitignore
├── CMakeLists.txt
├── CONTRIBUTING
├── LICENSE
├── README.md
├── comp_depth_minmax.hpp
├── doc
├── depth.png
├── normal.png
├── nrm_depth.png
├── nrm_depth_without.png
├── obj_contour.png
├── obj_contour_fxaa.png
├── object_id.png
└── vk_toon_shader.png
├── example.cpp
├── example.hpp
├── main.cpp
├── post_compositing.hpp
├── post_effect.hpp
├── post_kuwahara.hpp
├── post_kuwahara_aniso.hpp
├── post_nrmdepth.hpp
├── post_objcontour.hpp
├── post_tonemapper.hpp
├── rasterizer.cpp
├── rasterizer.hpp
├── raypick.hpp
├── raytracer.cpp
├── raytracer.hpp
├── shaders
├── binding.glsl
├── compositing.frag
├── contour_normaldepth.frag
├── contour_objects.frag
├── depthminmax.comp
├── final.frag
├── fxaa.frag
├── gltf.glsl
├── kuwa_aniso.frag
├── kuwa_gauss.frag
├── kuwa_sst.frag
├── kuwa_tfm.frag
├── kuwahara.frag
├── passthrough.vert
├── pick.rchit
├── pick.rgen
├── pick.rmiss
├── rasterizer.frag
├── rasterizer.vert
├── raytrace.rchit
├── raytrace.rgen
├── raytrace.rmiss
├── raytraceShadow.rmiss
├── share.glsl
├── tonemap.frag
└── tonemapping.glsl
├── tiny_gltf.cpp
└── vk_util.hpp
/.gitattributes:
--------------------------------------------------------------------------------
1 |
2 | #
3 | # Git LFS (see https://git-lfs.github.com/)
4 | *.bin filter=lfs diff=lfs merge=lfs -text
5 | *.csf filter=lfs diff=lfs merge=lfs -text
6 | *.dds filter=lfs diff=lfs merge=lfs -text
7 | *.dll filter=lfs diff=lfs merge=lfs -text
8 | *.exe filter=lfs diff=lfs merge=lfs -text
9 | *.gz filter=lfs diff=lfs merge=lfs -text
10 | *.hdr filter=lfs diff=lfs merge=lfs -text
11 | *.jpg filter=lfs diff=lfs merge=lfs -text
12 | *.lib filter=lfs diff=lfs merge=lfs -text
13 | *.obj filter=lfs diff=lfs merge=lfs -text
14 | *.pdb filter=lfs diff=lfs merge=lfs -text
15 | *.png filter=lfs diff=lfs merge=lfs -text
16 | *.so filter=lfs diff=lfs merge=lfs -text
17 | *.vks filter=lfs diff=lfs merge=lfs -text
18 | *.zip filter=lfs diff=lfs merge=lfs -text
19 | * !text !filter !merge !diff
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | **/spv/*
2 | build
3 | cmake_build
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.5)
2 |
3 | get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
4 | Project(${PROJNAME})
5 | Message(STATUS "-------------------------------")
6 | Message(STATUS "Processing Project ${PROJNAME}:")
7 |
8 | #####################################################################################
9 | # look for nvpro_core 1) as a sub-folder 2) at some other locations
10 | # this cannot be put anywhere else since we still didn't find setup.cmake yet
11 | #
12 | if(NOT BASE_DIRECTORY)
13 |
14 | find_path(BASE_DIRECTORY
15 | NAMES nvpro_core/cmake/setup.cmake
16 | PATHS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../..
17 | REQUIRED
18 | DOC "Directory containing nvpro_core"
19 | )
20 | endif()
21 | if(EXISTS ${BASE_DIRECTORY}/nvpro_core/cmake/setup.cmake)
22 | include(${BASE_DIRECTORY}/nvpro_core/cmake/setup.cmake)
23 | include(${BASE_DIRECTORY}/nvpro_core/cmake/utilities.cmake)
24 | else()
25 | message(FATAL_ERROR "could not find base directory, please set BASE_DIRECTORY to folder containing nvpro_core")
26 | endif()
27 |
28 | _add_project_definitions(${PROJNAME})
29 |
30 | set(CMAKE_CXX_STANDARD 20)
31 |
32 | #####################################################################################
33 | # additions from packages needed for this sample
34 | # add refs in LIBRARIES_OPTIMIZED
35 | # add refs in LIBRARIES_DEBUG
36 | # add files in PACKAGE_SOURCE_FILES
37 |
38 | set( EXENAME ${PROJNAME} )
39 | _add_package_VulkanSDK()
40 | _add_package_IMGUI()
41 |
42 | #####################################################################################
43 | # process the rest of some cmake code that needs to be done *after* the packages add
44 | _add_nvpro_core_lib()
45 |
46 | #####################################################################################
47 | # Source files for this project
48 | #
49 | file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
50 | file(GLOB GLSL_FILES *.glsl)
51 |
52 | #--------------------------------------------------------------------------------------------------
53 | # GLSL to SPIR-V custom build
54 | compile_glsl_directory(
55 | SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
56 | DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
57 | VULKAN_TARGET "vulkan1.2"
58 | )
59 |
60 |
61 |
62 | #--------------------------------------------------------------------------------------------------
63 | # Resources
64 | #
65 | download_files(FILENAMES robot.zip EXTRACT)
66 |
67 |
68 | source_group(Shader_Files FILES ${GLSL_SOURCES})
69 |
70 | #####################################################################################
71 | # Executable
72 | #
73 | if(WIN32 AND NOT GLUT_FOUND)
74 | add_definitions(/wd4996) #remove printf warning
75 | add_definitions(/wd4244) #remove double to float conversion warning
76 | add_definitions(/wd4305) #remove double to float truncation warning
77 | else()
78 | add_definitions(-fpermissive)
79 | endif()
80 | add_executable(${EXENAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES})
81 |
82 | #_set_subsystem_console(${EXENAME})
83 |
84 | #####################################################################################
85 | # common source code needed for this sample
86 | #
87 | source_group(common FILES
88 | ${COMMON_SOURCE_FILES}
89 | ${PACKAGE_SOURCE_FILES}
90 | )
91 | source_group("Source Files" FILES ${SOURCE_FILES})
92 |
93 | if(UNIX)
94 | set(UNIXLINKLIBS dl pthread)
95 | else()
96 | set(UNIXLINKLIBS)
97 | endif()
98 |
99 | #####################################################################################
100 | # Linkage
101 | #
102 | target_link_libraries(${EXENAME} ${PLATFORM_LIBRARIES} nvpro_core)
103 |
104 | foreach(DEBUGLIB ${LIBRARIES_DEBUG})
105 | target_link_libraries(${EXENAME} debug ${DEBUGLIB})
106 | endforeach(DEBUGLIB)
107 |
108 | foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
109 | target_link_libraries(${EXENAME} optimized ${RELEASELIB})
110 | endforeach(RELEASELIB)
111 |
112 | #####################################################################################
113 | # copies binaries that need to be put next to the exe files (ZLib, etc.)
114 | #
115 | _finalize_target( ${EXENAME} )
116 |
117 |
118 | #####################################################################################
119 | # Extra elements for INSTALL
120 | #
121 | install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
122 | install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
123 |
--------------------------------------------------------------------------------
/CONTRIBUTING:
--------------------------------------------------------------------------------
1 | https://developercertificate.org/
2 |
3 | Developer Certificate of Origin
4 | Version 1.1
5 |
6 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
7 |
8 | Everyone is permitted to copy and distribute verbatim copies of this
9 | license document, but changing it is not allowed.
10 |
11 |
12 | Developer's Certificate of Origin 1.1
13 |
14 | By making a contribution to this project, I certify that:
15 |
16 | (a) The contribution was created in whole or in part by me and I
17 | have the right to submit it under the open source license
18 | indicated in the file; or
19 |
20 | (b) The contribution is based upon previous work that, to the best
21 | of my knowledge, is covered under an appropriate open source
22 | license and I have the right under that license to submit that
23 | work with modifications, whether created in whole or in part
24 | by me, under the same open source license (unless I am
25 | permitted to submit under a different license), as indicated
26 | in the file; or
27 |
28 | (c) The contribution was provided directly to me by some other
29 | person who certified (a), (b) or (c) and I have not modified
30 | it.
31 |
32 | (d) I understand and agree that this project and the contribution
33 | are public and that a record of the contribution (including all
34 | personal information I submit with it, including my sign-off) is
35 | maintained indefinitely and may be redistributed consistent with
36 | this project or the open source license(s) involved.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Silhouette and toon shading
2 |
3 | This sample is loading a glTF scene and extracting lines for object contours and details, like when there is a sharp curvature on the object.
4 |
5 | This is only post-processing, no line/edge drawing.
6 |
7 | 
8 |
9 |
10 | ## Line extractions
11 |
12 | Either we are using the raster or the ray tracer, the renderer must provide 3 data information: normal, depth, object id.
13 |
14 | 
15 | 
16 | 
17 |
18 | In the fragment shader, or in the closest hit shader, these data will be stored in a single RGBA32F buffer, where the first XY will have the normal data encoded, Z, the depth and W the object ID, an integer we cast to float.
19 |
20 | ## Contour Extraction
21 |
22 | To extract the contour, we are using a post-processing pipeline, mainly using a fragment shader. There is a case where we are using a compute shader to find the min and max value of the depth buffer.
23 |
24 | The extraction of the object contour is done by comparing the actual pixel with the neighbors. We compare each immediate neighbor if the value is greather, smaller or different from the current one. This has for effect to create a line on the current object, outside of it or both, which makes a thicker line.
25 |
26 | ~~~~
27 | +---+---+---+
28 | | A | B | C |
29 | +---+---+---+
30 | | D | X | E |
31 | +---+---+---+
32 | | F | G | H |
33 | +---+---+---+
34 | ~~~~
35 |
36 | Comparing X against any A-H, if one value is (< , >, !=) then we set 1 to the result.
37 |
38 | The GLSL shader is a fragment shader, but to use the `unsigned int` from Iray, we cast the image pixels data to a single `GL_R32F` and in the fragment shader, we reinteprete the
39 | value as an integer using `floatBitsToInt`.
40 |
41 | This will result to something like this
42 |
43 | 
44 |
45 | ### FXAA
46 |
47 | The result is jaggy and one method to remove this, is to apply a FXAA pass on the image, which is resulting to smoother lines.
48 |
49 | 
50 |
51 |
52 | ## Normal and depth
53 |
54 | In some cases, the contour of individual object is not enough as we might want to see details that are part of the same object, like crease and valleys.
55 |
56 | This is without
57 |
58 | 
59 |
60 |
61 | With depth and normal extraction
62 |
63 | 
64 |
65 | ### Normal extraction
66 |
67 | To extract the normal gradient to create and create additional contour, we are using the
68 | following function. See above for the position of the surrounding pixels.
69 |
70 | `N = (|X-B|∙|X-B|) + (|X-G|∙|X-G|) + (|X-E|∙|X-E|) + (|X-D|∙|X-D|)`
71 |
72 | ### Depth extraction
73 |
74 | For depth extraction, we are normalizing the depth value by finding the nearest depth
75 | position (d1) and the farthest value (d2).
76 |
77 | Since we want to clearly emphasis the elements closer to the camera to avoid too many
78 | contour created in the background, we will give more priority to the closest elements as you can see with the blue line.
79 |
80 |
81 |
82 |
83 | The extraction of the depth contour is done using Sobel eqn. [linear1] for the first order of differential and eqn. [linear2]
84 | See: [Comprehensible Rendering of 3-D Shapes](https://www.cs.princeton.edu/courses/archive/fall00/cs597b/papers/saito90.pdf)
85 |
86 | linear1: `g = (|A +2B +C -F-2G-H| + C|C+2E+H-A-2D-F|)/8`
87 |
88 | linear2: `l = (8X -A-B-C-D-E-F-G-H)/3`
89 |
90 | ## References
91 |
92 | * https://graphics.pixar.com/library/ToonRendering/paper.pdf
93 | * https://en.wikipedia.org/wiki/Cel_shading
94 | * https://gfx.cs.princeton.edu/gfx/pubs/DeCarlo_2003_SCF/DeCarlo2003.pdf
95 | * http://www.markmark.net/npar/npar2000_lake_et_al.pdf
96 | * https://hpi.de/fileadmin/user_upload/hpi/navigation/10_forschung/30_publikationen/15_dissertationen/Diss_Nienhaus.pdf
97 | * https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter15.html
98 | * https://www.ijstr.org/final-print/apr2018/Edge-Detection-In-Images-Using-Haar-Wavelets-Sobel-Gabor-And-Laplacian-Filters.pdf
99 | * https://en.wikipedia.org/wiki/Canny_edge_detector
100 | * https://www.cs.princeton.edu/courses/archive/fall00/cs597b/papers/saito90.pdf
101 | * https://adempsey.github.io/edgey/
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/comp_depth_minmax.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | #include "vk_util.hpp"
25 |
26 | #include "nvh/fileoperations.hpp"
27 | #include "nvvk/debug_util_vk.hpp"
28 | #include "nvvk/descriptorsets_vk.hpp"
29 | #include "nvvk/shaders_vk.hpp"
30 |
31 |
32 | extern std::vector defaultSearchPaths;
33 |
34 |
35 | // Find the min/max value of the depth value stored in the output data buffer
36 | class CompDepthMinMax
37 | {
38 | public:
39 | void setup(const vk::Device& device, const vk::PhysicalDevice& physicalDevice, uint32_t queueIndex, nvvkpp::ResourceAllocator* allocator)
40 | {
41 | m_device = device;
42 | m_queueIndex = queueIndex;
43 | m_alloc = allocator;
44 | m_debug.setup(device);
45 |
46 | // Create the buffer, no value in
47 | m_values = m_alloc->createBuffer(2 * sizeof(uint32_t), vkBU::eTransferSrc | vkBU::eTransferDst | vkBU::eStorageBuffer,
48 | vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
49 | createCompDescriptors();
50 | createCompPipelines();
51 | }
52 |
53 | void setInput(const nvvk::Texture& dataImage)
54 | {
55 | std::vector writes;
56 | writes.emplace_back(m_descSetBind.nvvk::DescriptorSetBindings::makeWrite(m_descSet, 0, &dataImage.descriptor)); // ray tracing
57 | vk::DescriptorBufferInfo bi{m_values.buffer, 0, VK_WHOLE_SIZE};
58 | writes.emplace_back(m_descSetBind.makeWrite(m_descSet, 1, &bi)); // ray tracing
59 | m_device.updateDescriptorSets(writes, nullptr);
60 | }
61 |
62 | void execute(const vk::CommandBuffer& cmdBuf, const vk::Extent2D& size)
63 | {
64 | float big{10000.f};
65 | m_minmax = {*reinterpret_cast(&big), 0}; // Resetting zNear and zFar values (floatBitsToInt)
66 | cmdBuf.updateBuffer(m_values.buffer, 0, m_minmax);
67 | cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_pipeline);
68 | cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_pipelineLayout, 0, {m_descSet}, {});
69 | cmdBuf.dispatch(size.width / 32 + 1, size.height / 32 + 1, 1);
70 |
71 | // Adding a barrier to make sure the compute is done before one of the fragment
72 | // shader picks up the values computed here.
73 | vk::BufferMemoryBarrier bmb;
74 | bmb.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
75 | bmb.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
76 | bmb.setOffset(0);
77 | bmb.setSize(VK_WHOLE_SIZE);
78 | bmb.setSize(VK_WHOLE_SIZE);
79 | bmb.setBuffer(m_values.buffer);
80 | cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eFragmentShader,
81 | vk::DependencyFlagBits::eDeviceGroup, 0, nullptr, 1, &bmb, 0, nullptr);
82 | }
83 |
84 | void getNearFar(float& near_, float& far_)
85 | {
86 | {
87 | m_device.waitIdle(); // Must wait to be sure to get synchronization (use only for debug)
88 | void* mapped = m_alloc->map(m_values);
89 | memcpy(m_minmax.data(), mapped, 2 * sizeof(float));
90 | m_alloc->unmap(m_values);
91 | }
92 |
93 | near_ = *reinterpret_cast(&m_minmax[0]); // intBitsToFloat
94 | far_ = *reinterpret_cast(&m_minmax[1]);
95 | }
96 | const nvvk::Buffer& getBuffer() { return m_values; } // zNear - zFar
97 |
98 | void destroy()
99 | {
100 | m_alloc->destroy(m_values);
101 | m_device.destroyDescriptorSetLayout(m_descSetLayout);
102 | m_device.destroyPipeline(m_pipeline);
103 | m_device.destroyPipelineLayout(m_pipelineLayout);
104 | m_device.destroyDescriptorPool(m_descPool);
105 | }
106 |
107 |
108 | private:
109 | void createCompDescriptors()
110 | {
111 | m_descSetBind.addBinding(vkDS(0, vkDT::eStorageImage, 1, vkSS::eCompute)); // Input - image
112 | m_descSetBind.addBinding(vkDS(1, vkDT::eStorageBuffer, 1, vkSS::eCompute)); // Output - values
113 |
114 | m_descSetLayout = m_descSetBind.createLayout(m_device);
115 | m_descPool = m_descSetBind.createPool(m_device, 1);
116 | m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout);
117 | }
118 |
119 | void createCompPipelines()
120 | {
121 | vk::PipelineLayoutCreateInfo layout_info{{}, 1, &m_descSetLayout};
122 | m_pipelineLayout = m_device.createPipelineLayout(layout_info);
123 | m_debug.setObjectName(m_pipelineLayout, "minmax");
124 | vk::ComputePipelineCreateInfo createInfo{{}, {}, m_pipelineLayout};
125 |
126 | createInfo.stage = nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/depthminmax.comp.spv", true, defaultSearchPaths),
127 | VK_SHADER_STAGE_COMPUTE_BIT);
128 | m_pipeline = m_device.createComputePipeline({}, createInfo, nullptr).value;
129 | m_device.destroy(createInfo.stage.module);
130 | }
131 |
132 | vk::Device m_device;
133 | uint32_t m_queueIndex;
134 | nvvkpp::ResourceAllocator* m_alloc{nullptr};
135 | nvvk::DebugUtil m_debug;
136 |
137 | std::array m_minmax;
138 | nvvk::Buffer m_values; // min/max
139 |
140 | nvvkpp::DescriptorSetBindings m_descSetBind;
141 | vk::DescriptorPool m_descPool;
142 | vk::DescriptorSetLayout m_descSetLayout;
143 | vk::DescriptorSet m_descSet;
144 | vk::Pipeline m_pipeline;
145 | vk::PipelineLayout m_pipelineLayout;
146 | };
147 |
--------------------------------------------------------------------------------
/doc/depth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvpro-samples/vk_toon_shader/7b99bd8970d753180ece5d43a00f45fea0a64f6a/doc/depth.png
--------------------------------------------------------------------------------
/doc/normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvpro-samples/vk_toon_shader/7b99bd8970d753180ece5d43a00f45fea0a64f6a/doc/normal.png
--------------------------------------------------------------------------------
/doc/nrm_depth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvpro-samples/vk_toon_shader/7b99bd8970d753180ece5d43a00f45fea0a64f6a/doc/nrm_depth.png
--------------------------------------------------------------------------------
/doc/nrm_depth_without.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvpro-samples/vk_toon_shader/7b99bd8970d753180ece5d43a00f45fea0a64f6a/doc/nrm_depth_without.png
--------------------------------------------------------------------------------
/doc/obj_contour.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvpro-samples/vk_toon_shader/7b99bd8970d753180ece5d43a00f45fea0a64f6a/doc/obj_contour.png
--------------------------------------------------------------------------------
/doc/obj_contour_fxaa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvpro-samples/vk_toon_shader/7b99bd8970d753180ece5d43a00f45fea0a64f6a/doc/obj_contour_fxaa.png
--------------------------------------------------------------------------------
/doc/object_id.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvpro-samples/vk_toon_shader/7b99bd8970d753180ece5d43a00f45fea0a64f6a/doc/object_id.png
--------------------------------------------------------------------------------
/doc/vk_toon_shader.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvpro-samples/vk_toon_shader/7b99bd8970d753180ece5d43a00f45fea0a64f6a/doc/vk_toon_shader.png
--------------------------------------------------------------------------------
/example.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | #include
22 |
23 | #include "vk_util.hpp"
24 |
25 | #include
26 |
27 | #include "comp_depth_minmax.hpp"
28 | #include "nvh/gltfscene.hpp"
29 | #include "nvvkhl/appbase_vkpp.hpp"
30 | #include "nvvk/gizmos_vk.hpp"
31 | #include "nvvk/images_vk.hpp"
32 | #include "post_compositing.hpp"
33 | #include "post_kuwahara.hpp"
34 | #include "post_kuwahara_aniso.hpp"
35 | #include "post_nrmdepth.hpp"
36 | #include "post_objcontour.hpp"
37 | #include "post_tonemapper.hpp"
38 | #include "rasterizer.hpp"
39 | #include "raypick.hpp"
40 | #include "raytracer.hpp"
41 |
42 |
43 | //--------------------------------------------------------------------------------------------------
44 | // Loading a glTF scene, raytrace and tonemap result
45 | //
46 | class VkToonExample : public nvvkhl::AppBase
47 | {
48 | public:
49 | VkToonExample() = default;
50 |
51 | void loadScene(const std::string& filename);
52 | void createPostProcess();
53 | void display();
54 |
55 | void setup(const vk::Instance& instance, const vk::Device& device, const vk::PhysicalDevice& physicalDevice, uint32_t graphicsQueueIndex) override;
56 |
57 | void destroy() override;
58 | void onResize(int w, int h) override;
59 | void createRenderPass() override;
60 | void createAxis();
61 | void createDescriptorFinal();
62 | void createFinalPipeline();
63 | void onKeyboard(int key, int scancode, int action, int mods) override;
64 | void onFileDrop(const char* filename) override;
65 |
66 | private:
67 | struct SceneUBO
68 | {
69 | glm::mat4 projection;
70 | glm::mat4 model;
71 | glm::vec4 cameraPosition{0.f, 0.f, 0.f, 1.f};
72 | };
73 |
74 | void createDescriptorMaterial();
75 | void createDescriptorRaytrace();
76 | void createPipeline();
77 | void createSceneBuffers();
78 | void createSceneDescriptors();
79 | void drawUI();
80 | void importImages(tinygltf::Model& gltfModel);
81 | void prepareUniformBuffers();
82 | void resetFrame();
83 | void settingPostPipeline();
84 | void updateCameraBuffer(const vk::CommandBuffer& cmdBuffer);
85 | void updateDescriptor(const vk::DescriptorImageInfo& descriptor);
86 | void updateFrame();
87 |
88 | vk::GeometryNV primitiveToGeometry(const nvh::GltfPrimMesh& prim);
89 |
90 |
91 | vk::RenderPass m_renderPassUI;
92 | vk::PipelineLayout m_pipelineLayout;
93 | vk::Pipeline m_pipeline;
94 |
95 | // Descriptors
96 | enum Dset
97 | {
98 | eFinal, // For the tonemapper
99 | eScene, // All scene data
100 | Total
101 | };
102 | std::vector m_descSetLayout{Dset::Total};
103 | std::vector m_descPool{Dset::Total};
104 | std::vector m_descSet{Dset::Total};
105 | std::vector m_descSetLayoutBind{Dset::Total};
106 |
107 | // GLTF scene model
108 | nvh::GltfScene m_gltfScene; // The scene
109 | nvh::GltfStats m_sceneStats; // The scene stats
110 | SceneUBO m_sceneUbo; // Camera, light and more
111 |
112 | int m_frameNumber{0};
113 |
114 | nvvk::AxisVK m_axis; // To display the axis in the lower left corner
115 | Raytracer m_raytracer; // The raytracer
116 | RayPicker m_rayPicker; // Picking under mouse using raytracer
117 | Rasterizer m_rasterizer; // Rasterizer
118 |
119 | // Post effect
120 | Tonemapper m_tonemapper; //
121 | PostNrmDepth m_nrmDepth;
122 | PostObjContour m_objContour;
123 | PostCompositing m_compositing;
124 | PostKuwahara m_kuwahara;
125 | PostKuwaharaAniso m_kuwaharaAniso;
126 | CompDepthMinMax m_depthMinMax;
127 |
128 | // All buffers on the Device
129 | nvvk::Buffer m_sceneBuffer;
130 | nvvk::Buffer m_vertexBuffer;
131 | nvvk::Buffer m_normalBuffer;
132 | nvvk::Buffer m_uvBuffer;
133 | nvvk::Buffer m_indexBuffer;
134 | nvvk::Buffer m_materialBuffer;
135 | nvvk::Buffer m_matrixBuffer;
136 |
137 | // All textures
138 | std::vector m_textures;
139 |
140 | bool m_useRaytracer{true};
141 | glm::vec3 m_backgroundColor{1.f}; // clear color and miss
142 | int m_toonNbStep{5}; // Toon shading steps
143 | glm::vec3 m_toonLightDir{-1, -1, -1}; // Toon light
144 |
145 | // Allocator for buffers and images
146 | Allocator m_alloc;
147 |
148 | nvvk::DebugUtil m_debug;
149 | };
150 |
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | //--------------------------------------------------------------------------------------------------
22 | // This example is creating a scene with many similar objects and a plane. There are a few materials
23 | // and a light direction.
24 | // More details in simple.cpp
25 | //
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 | VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
32 |
33 | #define IMGUI_DEFINE_MATH_OPERATORS
34 | #include "backends/imgui_impl_glfw.h"
35 | #include "backends/imgui_impl_vulkan.h"
36 | #include "example.hpp"
37 | #include "GLFW/glfw3.h"
38 | #include "nvh/fileoperations.hpp"
39 | #include "nvh/inputparser.h"
40 | #include "nvpsystem.hpp"
41 | #include "nvvk/context_vk.hpp"
42 | #include "nvvk/extensions_vk.hpp"
43 |
44 | int const SAMPLE_SIZE_WIDTH = 1600;
45 | int const SAMPLE_SIZE_HEIGHT = 1000;
46 |
47 | // Default search path for shaders
48 | std::vector defaultSearchPaths;
49 |
50 |
51 | //--------------------------------------------------------------------------------------------------
52 | //
53 | //
54 | int main(int argc, char** argv)
55 | {
56 | // setup some basic things for the sample, logging file for example
57 | NVPSystem system(PROJECT_NAME);
58 |
59 | // Default search path for shaders
60 | defaultSearchPaths = {
61 | NVPSystem::exePath() + PROJECT_NAME,
62 | NVPSystem::exePath() + R"(media)",
63 | NVPSystem::exePath() + PROJECT_RELDIRECTORY,
64 | NVPSystem::exePath() + PROJECT_DOWNLOAD_RELDIRECTORY,
65 | };
66 |
67 | // Parsing the command line: mandatory '-f' for the filename of the scene
68 | InputParser parser(argc, argv);
69 | std::string filename = parser.getString("-f");
70 | if(parser.exist("-f"))
71 | {
72 | filename = parser.getString("-f");
73 | }
74 | else if(argc == 2 && nvh::endsWith(argv[1], ".gltf")) // Drag&Drop on .exe
75 | {
76 | filename = argv[1];
77 | }
78 | else
79 | {
80 | filename = nvh::findFile("robot/robot.gltf", defaultSearchPaths, true);
81 | }
82 |
83 | // Setup GLFW window
84 | if(!glfwInit())
85 | {
86 | return 1;
87 | }
88 | glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
89 | GLFWwindow* window = glfwCreateWindow(SAMPLE_SIZE_WIDTH, SAMPLE_SIZE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
90 |
91 | // Enabling the extension
92 | vk::PhysicalDeviceDescriptorIndexingFeaturesEXT feature;
93 |
94 | // Vulkan required extensions
95 | assert(glfwVulkanSupported() == 1);
96 | uint32_t count{0};
97 | auto reqExtensions = glfwGetRequiredInstanceExtensions(&count);
98 |
99 | // Requesting Vulkan extensions and layers
100 | nvvk::ContextCreateInfo contextInfo;
101 | contextInfo.setVersion(1, 2); // Using Vulkan 1.2
102 | for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..)
103 | contextInfo.addInstanceExtension(reqExtensions[ext_id]);
104 | contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar
105 | contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names
106 | contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering
107 |
108 | // #VKRay: Activate the ray tracing extension
109 | contextInfo.addDeviceExtension(VK_NV_RAY_TRACING_EXTENSION_NAME, true /*optional*/);
110 |
111 |
112 | // Creating the Vulkan instance and device
113 | nvvk::Context vkctx;
114 | vkctx.initInstance(contextInfo);
115 |
116 | // Find all compatible devices
117 | auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo);
118 | assert(!compatibleDevices.empty());
119 |
120 | // Use first compatible device
121 | vkctx.initDevice(compatibleDevices[0], contextInfo);
122 |
123 | VkToonExample example;
124 |
125 | // Window need to be opened to get the surface on which to draw
126 | vk::SurfaceKHR surface = example.getVkSurface(vkctx.m_instance, window);
127 | vkctx.setGCTQueueWithPresent(surface);
128 |
129 | example.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
130 | LOGI("Using %s \n", example.getPhysicalDevice().getProperties().deviceName.data());
131 |
132 | example.createSwapchain(surface, SAMPLE_SIZE_WIDTH, SAMPLE_SIZE_HEIGHT);
133 | example.createDepthBuffer();
134 | example.createRenderPass();
135 | example.createFrameBuffers();
136 | //example.createTonemapper();
137 | example.createAxis();
138 | example.createDescriptorFinal();
139 | example.createFinalPipeline(); // How the quad will be rendered
140 |
141 | example.loadScene(filename); // Now build the example
142 | example.createPostProcess(); // Adding all post-effects, line extractions, ..
143 | example.initGUI(0); // Using sub-pass 0
144 |
145 |
146 | // GLFW Callback
147 | example.setupGlfwCallbacks(window);
148 | ImGui_ImplGlfw_InitForVulkan(window, true);
149 |
150 | // Main loop
151 | while(!glfwWindowShouldClose(window))
152 | {
153 | glfwPollEvents();
154 | if(example.isMinimized())
155 | continue;
156 |
157 | CameraManip.updateAnim();
158 | example.display(); // infinitely drawing
159 | }
160 |
161 |
162 | glfwDestroyWindow(window);
163 | glfwTerminate();
164 |
165 | example.destroy();
166 | vkctx.deinit();
167 |
168 |
169 | return 0;
170 | }
171 |
--------------------------------------------------------------------------------
/post_compositing.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | #pragma once
22 |
23 | #include "post_effect.hpp"
24 | #include "nvvk/resourceallocator_vk.hpp"
25 |
26 | // Merge the final frame and add the contour of the normal/depth and object
27 | class PostCompositing : public PostEffect
28 | {
29 | public:
30 | const std::string getShaderName() override { return R"(spv/compositing.frag.spv)"; }
31 |
32 | // Attaching the 3 input images
33 | void setInputs(const std::vector& inputs) override
34 | {
35 | std::vector writes;
36 | writes.emplace_back(m_descSetBind.makeWrite(m_descSet, 0, &inputs[0].descriptor)); // ray tracing
37 | writes.emplace_back(m_descSetBind.makeWrite(m_descSet, 1, &inputs[1].descriptor)); // normal depth
38 | writes.emplace_back(m_descSetBind.makeWrite(m_descSet, 2, &inputs[2].descriptor)); // object
39 | m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr);
40 | }
41 |
42 | void execute(const vk::CommandBuffer& cmdBuf) override
43 | {
44 | if(!m_active)
45 | return;
46 |
47 | cmdBuf.pushConstants(m_pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, m_pushCnt);
48 | PostEffect::execute(cmdBuf);
49 | }
50 |
51 | bool uiSetup() override
52 | {
53 | bool changed{false};
54 | // changed |= ImGui::Checkbox("Color Background", (bool*)&m_pushCnt.setBackground);
55 | // changed |= ImGui::ColorEdit3("Background Color", &m_pushCnt.backgroundColor.x);
56 | changed |= ImGui::ColorEdit3("Contour Color", &m_pushCnt.lineColor.x);
57 | return changed;
58 | }
59 |
60 | private:
61 | // One input image and push constant to control the effect
62 | void createDescriptorSet() override
63 | {
64 | vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(PushConstant)};
65 |
66 | m_descSetBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); // ray tracing
67 | m_descSetBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); // Normal/depth
68 | m_descSetBind.addBinding(vkDS(2, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); // Object contour
69 | m_descSetLayout = m_descSetBind.createLayout(m_device);
70 | m_descPool = m_descSetBind.createPool(m_device);
71 | m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout);
72 | m_pipelineLayout = m_device.createPipelineLayout({{}, 1, &m_descSetLayout, 1, &push_constants});
73 | m_debug.setObjectName(m_pipelineLayout, "compositing");
74 | }
75 |
76 | struct PushConstant
77 | {
78 | glm::vec3 backgroundColor{1.f};
79 | int setBackground{0};
80 | glm::vec3 lineColor{0.3f};
81 | };
82 | PushConstant m_pushCnt;
83 | };
84 |
--------------------------------------------------------------------------------
/post_effect.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | #pragma once
22 |
23 | #include "imgui.h"
24 | #include "nvh/fileoperations.hpp"
25 | #include "nvvk/commands_vk.hpp"
26 | #include "nvvk/debug_util_vk.hpp"
27 | #include "nvvk/descriptorsets_vk.hpp"
28 | #include "nvvk/images_vk.hpp"
29 | #include "nvvk/pipeline_vk.hpp"
30 | #include "nvvk/vulkanhppsupport.hpp"
31 |
32 | #include "vk_util.hpp"
33 |
34 | #include
35 |
36 |
37 | extern std::vector defaultSearchPaths;
38 |
39 | // Base Class to create effect on incoming images and output one image
40 | //
41 | // Usage:
42 | // - setup(...)
43 | // - initialize( size of window/image )
44 | // - setInput( image.descriptor )
45 | // - run
46 | // - getOutput
47 | class PostEffect
48 | {
49 |
50 |
51 | public:
52 | PostEffect() = default;
53 |
54 | virtual void setup(const vk::Device& device, const vk::PhysicalDevice& physicalDevice, uint32_t queueIndex, nvvkpp::ResourceAllocator* allocator)
55 | {
56 | m_device = device;
57 | m_queueIndex = queueIndex;
58 | m_alloc = allocator;
59 | m_debug.setup(device);
60 | }
61 |
62 | virtual void initialize(const vk::Extent2D& size)
63 | {
64 | createRenderPass();
65 | createDescriptorSet();
66 | createPipeline();
67 | updateRenderTarget(size);
68 | }
69 |
70 | // Attaching the input image
71 | virtual void setInputs(const std::vector& inputs)
72 | {
73 | std::vector writes;
74 | writes.emplace_back(m_descSetBind.makeWrite(m_descSet, 0, &inputs[0].descriptor)); // ray tracing
75 | m_device.updateDescriptorSets(writes, nullptr);
76 | }
77 |
78 | // Internal image format
79 | virtual vk::Format getOutputFormat() { return vk::Format::eR8G8B8A8Unorm; }
80 | // Display controls for the post-process
81 | virtual bool uiSetup() { return false; } // return true when something changed
82 | virtual const std::string getShaderName() = 0;
83 |
84 |
85 | void setActive(bool active_) { m_active = active_; }
86 | bool isActive() { return m_active; }
87 |
88 | // Updating the output framebuffer when the image size is changing
89 | virtual void updateRenderTarget(const vk::Extent2D& size)
90 | {
91 | m_size = size;
92 |
93 | // Create new output image
94 | m_alloc->destroy(m_output);
95 | vk::SamplerCreateInfo samplerCreateInfo; // default values
96 | vk::ImageCreateInfo imageCreateInfo =
97 | nvvkpp::makeImage2DCreateInfo(m_size, getOutputFormat(),
98 | vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled);
99 |
100 | nvvk::Image image = m_alloc->createImage(imageCreateInfo);
101 | vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
102 | m_output = m_alloc->createTexture(image, ivInfo, samplerCreateInfo);
103 |
104 | {
105 | nvvk::CommandPool scb(m_device, m_queueIndex);
106 | auto cmdBuf = scb.createCommandBuffer();
107 | nvvkpp::cmdBarrierImageLayout(cmdBuf, m_output.image, vk::ImageLayout::eUndefined, vk::ImageLayout::eShaderReadOnlyOptimal);
108 | m_alloc->finalizeAndReleaseStaging();
109 | }
110 |
111 |
112 | // Create the Framebuffer and attach the texture
113 | m_device.destroy(m_framebuffer);
114 | vk::FramebufferCreateInfo info;
115 | info.setRenderPass(m_renderPass);
116 | info.setAttachmentCount(1);
117 | info.setPAttachments(reinterpret_cast(&m_output.descriptor.imageView));
118 | info.setWidth(m_size.width);
119 | info.setHeight(m_size.height);
120 | info.setLayers(1);
121 | m_framebuffer = m_device.createFramebuffer(info);
122 | }
123 |
124 | virtual void destroy()
125 | {
126 | m_alloc->destroy(m_output);
127 | m_device.destroyFramebuffer(m_framebuffer);
128 | m_device.destroyDescriptorSetLayout(m_descSetLayout);
129 | m_device.destroyRenderPass(m_renderPass);
130 | m_device.destroyPipeline(m_pipeline);
131 | m_device.destroyPipelineLayout(m_pipelineLayout);
132 | m_device.destroyDescriptorPool(m_descPool);
133 | }
134 |
135 | virtual const nvvk::Texture getOutput() { return m_output; }
136 |
137 |
138 | // Executing the the post-process
139 | virtual void execute(const vk::CommandBuffer& cmdBuf)
140 | {
141 | vk::ClearValue clearValues; // default is 0,0,0,0
142 | //clearValues[0].setColor(std::array({0.f, 0.f, 0.f, 0.f}));
143 |
144 | vk::RenderPassBeginInfo renderPassBeginInfo = {m_renderPass, m_framebuffer, {{}, m_size}, 1, &clearValues};
145 | cmdBuf.beginRenderPass(renderPassBeginInfo, vk::SubpassContents::eInline);
146 | if(m_active)
147 | {
148 | cmdBuf.setViewport(0, {vk::Viewport(0, 0, m_size.width, m_size.height, 0, 1)});
149 | cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
150 | cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_pipeline);
151 | cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_pipelineLayout, 0, m_descSet, {});
152 | cmdBuf.draw(3, 1, 0, 0);
153 | }
154 | cmdBuf.endRenderPass();
155 | }
156 |
157 | protected:
158 | // Render pass, one clear, no depth
159 | void createRenderPass()
160 | {
161 | if(m_renderPass)
162 | m_device.destroyRenderPass(m_renderPass);
163 |
164 | // Color attachment
165 | vk::AttachmentDescription attachments;
166 | attachments.setFormat(getOutputFormat()); // image format of the output image
167 | attachments.setLoadOp(vk::AttachmentLoadOp::eClear);
168 | attachments.setFinalLayout(vk::ImageLayout::eShaderReadOnlyOptimal);
169 |
170 | vk::AttachmentReference colorReference{0, vk::ImageLayout::eColorAttachmentOptimal};
171 | vk::SubpassDescription subpassDescription;
172 | subpassDescription.setColorAttachmentCount(1);
173 | subpassDescription.setPColorAttachments(&colorReference);
174 |
175 | vk::RenderPassCreateInfo renderPassInfo{{}, 1, &attachments, 1, &subpassDescription};
176 | m_renderPass = m_device.createRenderPass(renderPassInfo);
177 |
178 | std::string rp_name = getShaderName();
179 | rp_name = rp_name.substr(rp_name.find_first_of("/") + 1, rp_name.find_first_of(".") - rp_name.find_first_of("/") - 1);
180 | m_debug.setObjectName(m_renderPass, rp_name.c_str());
181 | }
182 |
183 | // One input image and push constant to control the effect
184 | virtual void createDescriptorSet()
185 | {
186 | m_descSetBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); // Normal/depth from ray tracing
187 | m_descSetLayout = m_descSetBind.createLayout(m_device);
188 | m_descPool = m_descSetBind.createPool(m_device);
189 | m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout);
190 | m_pipelineLayout = m_device.createPipelineLayout({{}, 1, &m_descSetLayout, 0, nullptr});
191 | m_debug.setObjectName(m_pipelineLayout, "post_effect");
192 | }
193 |
194 |
195 | // Creating the shading pipeline
196 | void createPipeline()
197 | {
198 | const std::string& fragProg = getShaderName();
199 | // Pipeline: completely generic, no vertices
200 | nvvkpp::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_pipelineLayout, m_renderPass);
201 | pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths), vk::ShaderStageFlagBits::eVertex);
202 | pipelineGenerator.addShader(nvh::loadFile(fragProg, true, defaultSearchPaths), vk::ShaderStageFlagBits::eFragment);
203 | pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
204 | m_pipeline = pipelineGenerator.createPipeline();
205 | }
206 |
207 | //
208 | bool m_active{true};
209 | vk::RenderPass m_renderPass;
210 | vk::Pipeline m_pipeline;
211 | vk::PipelineLayout m_pipelineLayout;
212 | nvvkpp::DescriptorSetBindings m_descSetBind;
213 | vk::DescriptorPool m_descPool;
214 | vk::DescriptorSetLayout m_descSetLayout;
215 | vk::DescriptorSet m_descSet;
216 | vk::Extent2D m_size{0, 0};
217 | vk::Framebuffer m_framebuffer;
218 | nvvk::Texture m_output;
219 | vk::Device m_device;
220 | uint32_t m_queueIndex;
221 | nvvkpp::ResourceAllocator* m_alloc{nullptr};
222 | nvvk::DebugUtil m_debug;
223 | };
224 |
--------------------------------------------------------------------------------
/post_kuwahara.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | #pragma once
22 |
23 | #include "post_effect.hpp"
24 |
25 | // Create a smoothing effect on the image https://en.wikipedia.org/wiki/Kuwahara_filter
26 | class PostKuwahara : public PostEffect
27 | {
28 | public:
29 | PostKuwahara() { m_active = false; }
30 |
31 | const std::string getShaderName() override { return R"(spv/kuwahara.frag.spv)"; }
32 |
33 | void execute(const vk::CommandBuffer& cmdBuf) override
34 | {
35 | if(!m_active)
36 | return;
37 |
38 | cmdBuf.pushConstants(m_pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, m_pushCnt);
39 | PostEffect::execute(cmdBuf);
40 | }
41 |
42 | bool uiSetup() override { return ImGui::SliderInt("radius", &m_pushCnt.radius, 1, 8); }
43 |
44 | private:
45 | // One input image and push constant to control the effect
46 | void createDescriptorSet() override
47 | {
48 | vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(PushConstant)};
49 |
50 | m_descSetBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); // Normal/depth from ray tracing
51 | m_descSetLayout = m_descSetBind.createLayout(m_device);
52 | m_descPool = m_descSetBind.createPool(m_device);
53 | m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout);
54 | m_pipelineLayout = m_device.createPipelineLayout({{}, 1, &m_descSetLayout, 1, &push_constants});
55 | m_debug.setObjectName(m_pipelineLayout, "kuwahara");
56 | }
57 |
58 | struct PushConstant
59 | {
60 | int radius{3};
61 | };
62 | PushConstant m_pushCnt;
63 | };
64 |
--------------------------------------------------------------------------------
/post_kuwahara_aniso.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | #pragma once
22 |
23 | #include "post_effect.hpp"
24 |
25 | // This is the implementation of the anisotropic Kuwahara filter (https://hpi.de/en/doellner/rendering/akf.html)
26 | // Paper : http://www.kyprianidis.com/p/pg2009/jkyprian-pg2009.pdf
27 | // Preview App' : https://code.google.com/archive/p/gpuakf/downloads
28 | // Code : https://code.google.com/archive/p/gpuakf/source/default/source
29 |
30 | // Apply anisotropic Kuwahara filter (https://hpi.de/en/doellner/rendering/akf.html)
31 | class PostKuwaharaAniso : public PostEffect
32 | {
33 | public:
34 | const std::string getShaderName() override { return R"(spv/kuwa_aniso.frag.spv)"; }
35 |
36 | void setup(const vk::Device& device, const vk::PhysicalDevice& physicalDevice, uint32_t queueIndex, nvvkpp::ResourceAllocator* allocator) override
37 | {
38 | m_sst.setup(device, physicalDevice, queueIndex, allocator);
39 | m_gauss.setup(device, physicalDevice, queueIndex, allocator);
40 | m_tfm.setup(device, physicalDevice, queueIndex, allocator);
41 | PostEffect::setup(device, physicalDevice, queueIndex, allocator);
42 | }
43 |
44 | void initialize(const vk::Extent2D& size) override
45 | {
46 | m_sst.initialize(size);
47 | m_gauss.initialize(size);
48 | m_tfm.initialize(size);
49 | PostEffect::initialize(size);
50 | updateKernel();
51 | }
52 |
53 | void setInputs(const std::vector& inputs) override
54 | {
55 | m_sst.setInputs(inputs);
56 | m_gauss.setInputs({m_sst.getOutput()});
57 | m_tfm.setInputs({m_gauss.getOutput()});
58 |
59 | const nvvk::Texture& outTfm = m_tfm.getOutput();
60 |
61 | std::vector writes;
62 | writes.emplace_back(m_descSetBind.makeWrite(m_descSet, 0, &inputs[0].descriptor)); // ray tracing
63 | writes.emplace_back(m_descSetBind.makeWrite(m_descSet, 1, &m_kernel.descriptor)); // kernel
64 | writes.emplace_back(m_descSetBind.makeWrite(m_descSet, 2, &outTfm.descriptor)); // kuwahara info
65 | m_device.updateDescriptorSets(writes, nullptr);
66 | }
67 |
68 | void updateRenderTarget(const vk::Extent2D& size) override
69 | {
70 | m_sst.updateRenderTarget(size);
71 | m_gauss.updateRenderTarget(size);
72 | m_tfm.updateRenderTarget(size);
73 | PostEffect::updateRenderTarget(size);
74 | }
75 |
76 | // Executing the effect
77 | void execute(const vk::CommandBuffer& cmdBuf) override
78 | {
79 | if(!m_active)
80 | return;
81 |
82 | m_sst.execute(cmdBuf);
83 | m_gauss.execute(cmdBuf);
84 | m_tfm.execute(cmdBuf);
85 | cmdBuf.pushConstants(m_pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, m_pushCnt);
86 | PostEffect::execute(cmdBuf);
87 | }
88 |
89 | void destroy() override
90 | {
91 | m_sst.destroy();
92 | m_gauss.destroy();
93 | m_tfm.destroy();
94 | m_alloc->destroy(m_kernel);
95 | PostEffect::destroy();
96 | }
97 |
98 | // UI Control
99 | bool uiSetup() override
100 | {
101 | bool changed{false};
102 | // changed |= ImGui::InputFloat("alpha", &m_pushCnt.alpha);
103 | changed |= ImGui::SliderFloat("radius", &m_pushCnt.radius, 1, 20);
104 | changed |= ImGui::SliderInt("N", &m_Nsectors, 1, 16);
105 | if(changed)
106 | updateKernel();
107 | return changed;
108 | }
109 |
110 | private:
111 | // One input image and push constant to control the effect
112 | void createDescriptorSet() override
113 | {
114 | vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(PushConstant)};
115 |
116 | m_descSetBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); // ray tracing image
117 | m_descSetBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); // kernel
118 | m_descSetBind.addBinding(vkDS(2, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); // from tfm
119 | m_descSetLayout = m_descSetBind.createLayout(m_device);
120 | m_descPool = m_descSetBind.createPool(m_device);
121 | m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout);
122 | m_pipelineLayout = m_device.createPipelineLayout({{}, 1, &m_descSetLayout, 1, &push_constants});
123 | m_debug.setObjectName(m_pipelineLayout, "kuwahara_aniso");
124 | }
125 |
126 |
127 | void updateKernel()
128 | {
129 | int N = m_Nsectors;
130 | float smoothing = m_smoothing / 100.0f; // in %
131 |
132 | const int krnl_size = 32;
133 | const float sigma = 0.25f * (krnl_size - 1);
134 |
135 | float* krnl[4];
136 | for(int k = 0; k < 4; ++k)
137 | {
138 | krnl[k] = new float[krnl_size * krnl_size];
139 | make_sector(krnl[k], k, N, krnl_size, sigma, smoothing * sigma);
140 | }
141 |
142 | m_device.waitIdle();
143 | m_alloc->destroy(m_kernel);
144 | {
145 | nvvkpp::ScopeCommandBuffer cmdBuf(m_device, m_queueIndex);
146 | vk::SamplerCreateInfo samplerCreateInfo; // default values
147 | vk::Extent2D size(krnl_size, krnl_size);
148 | vk::ImageCreateInfo imageCreateInfo = nvvkpp::makeImage2DCreateInfo(size, vk::Format::eR32Sfloat);
149 |
150 | nvvk::Image image = m_alloc->createImage(cmdBuf, krnl_size * krnl_size * sizeof(float), krnl[0], imageCreateInfo);
151 | vk::ImageViewCreateInfo ivInfo = nvvkpp::makeImageViewCreateInfo(image.image, imageCreateInfo);
152 | m_kernel = m_alloc->createTexture(image, ivInfo, samplerCreateInfo);
153 |
154 |
155 | nvvkpp::cmdBarrierImageLayout(cmdBuf, m_kernel.image, vk::ImageLayout::eUndefined, vk::ImageLayout::eShaderReadOnlyOptimal);
156 | }
157 | m_alloc->finalizeAndReleaseStaging();
158 | m_debug.setObjectName(m_kernel.image, "Kernel");
159 |
160 | for(auto& k : krnl)
161 | {
162 | delete k;
163 | }
164 | }
165 |
166 |
167 | static void gauss_filter(float* data, int width, int height, float sigma)
168 | {
169 | float twoSigma2 = 2.0f * sigma * sigma;
170 | int halfWidth = (int)ceil(2.0 * sigma);
171 |
172 | //float* src_data = new float[width * height];
173 | std::vector srcData(width * height);
174 |
175 | memcpy(srcData.data(), data, width * height * sizeof(float));
176 |
177 | for(int y = 0; y < height; ++y)
178 | {
179 | for(int x = 0; x < width; ++x)
180 | {
181 | float sum = 0;
182 | float w = 0;
183 |
184 | for(int i = -halfWidth; i <= halfWidth; ++i)
185 | {
186 | for(int j = -halfWidth; j <= halfWidth; ++j)
187 | {
188 | int xi = x + i;
189 | int yj = y + j;
190 | if((xi >= 0) && (xi < width) && (yj >= 0) && (yj < height))
191 | {
192 | float r = sqrt((float)(i * i + j * j));
193 | float k = exp(-r * r / twoSigma2);
194 | w += k;
195 | sum += k * srcData[xi + yj * width];
196 | }
197 | }
198 | }
199 |
200 | data[x + y * width] = sum / w;
201 | }
202 | }
203 |
204 | // delete[] src_data;
205 | }
206 |
207 |
208 | void make_sector(float* krnl, int k, int N, int size, float sigma_r, float sigma_s)
209 | {
210 | float* p = krnl;
211 | for(int j = 0; j < size; ++j)
212 | {
213 | for(int i = 0; i < size; ++i)
214 | {
215 | float x = i - 0.5f * size + 0.5f;
216 | float y = j - 0.5f * size + 0.5f;
217 | float r = sqrtf((x * x + y * y));
218 |
219 | float a = 0.5f * atan2(y, x) / glm::pi() + k * 1.0f / N;
220 | if(a > 0.5f)
221 | a -= 1.0f;
222 | if(a < -0.5f)
223 | a += 1.0f;
224 |
225 | if((fabs(a) <= 0.5f / N) && (r < 0.5f * size))
226 | {
227 | *p = 1;
228 | }
229 | else
230 | {
231 | *p = 0;
232 | }
233 | ++p;
234 | }
235 | }
236 |
237 | gauss_filter(krnl, size, size, sigma_s);
238 |
239 | p = krnl;
240 | float mx = 0.0f;
241 | for(int j = 0; j < size; ++j)
242 | {
243 | for(int i = 0; i < size; ++i)
244 | {
245 | float x = i - 0.5f * size + 0.5f;
246 | float y = j - 0.5f * size + 0.5f;
247 | float r = sqrtf(x * x + y * y);
248 | *p *= exp(-0.5f * r * r / sigma_r / sigma_r);
249 | if(*p > mx)
250 | mx = *p;
251 | ++p;
252 | }
253 | }
254 |
255 | p = krnl;
256 | for(int j = 0; j < size; ++j)
257 | {
258 | for(int i = 0; i < size; ++i)
259 | {
260 | *p /= mx;
261 | ++p;
262 | }
263 | }
264 | }
265 |
266 |
267 | struct PushConstant
268 | {
269 | float radius{3.f};
270 | float q{8.f};
271 | float alpha{1.f};
272 | };
273 | PushConstant m_pushCnt;
274 |
275 | nvvk::Texture m_kernel;
276 | int m_Nsectors = 8;
277 | float m_smoothing = 33.33f;
278 | float m_sigma_t{2.0f};
279 |
280 |
281 | struct PostKSst : public PostEffect
282 | {
283 | const std::string getShaderName() override { return R"(spv/kuwa_sst.frag.spv)"; }
284 | };
285 |
286 | struct PostKTfm : public PostEffect
287 | {
288 | const std::string getShaderName() override { return R"(spv/kuwa_tfm.frag.spv)"; }
289 | };
290 |
291 | struct PostGauss : public PostEffect
292 | {
293 | const std::string getShaderName() override { return R"(spv/kuwa_gauss.frag.spv)"; }
294 | };
295 |
296 | PostKSst m_sst;
297 | PostKTfm m_tfm;
298 | PostGauss m_gauss;
299 | };
300 |
--------------------------------------------------------------------------------
/post_nrmdepth.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | #pragma once
22 |
23 | #include "post_effect.hpp"
24 |
25 | // Extract the contour from the normal and depth buffer
26 | // And does a second post effect (FXAA) on the contour
27 | class PostNrmDepth : public PostEffect
28 | {
29 | public:
30 | const std::string getShaderName() override { return R"(spv/contour_normaldepth.frag.spv)"; }
31 |
32 | void setup(const vk::Device& device, const vk::PhysicalDevice& physicalDevice, uint32_t queueIndex, nvvkpp::ResourceAllocator* allocator) override
33 | {
34 | m_fxaa.setup(device, physicalDevice, queueIndex, allocator);
35 | PostEffect::setup(device, physicalDevice, queueIndex, allocator);
36 | }
37 |
38 | void initialize(const vk::Extent2D& size) override
39 | {
40 | m_fxaa.initialize(size);
41 | PostEffect::initialize(size);
42 | }
43 |
44 | void setInputs(const std::vector& inputs, const nvvk::Buffer& minMaxBuffer)
45 | {
46 | m_fxaa.setInputs({m_output});
47 |
48 | std::vector writes;
49 | writes.emplace_back(m_descSetBind.makeWrite(m_descSet, 0, &inputs[0].descriptor)); // ray tracing
50 | vk::DescriptorBufferInfo bufInfo{minMaxBuffer.buffer, 0, VK_WHOLE_SIZE};
51 | writes.emplace_back(m_descSetBind.makeWrite(m_descSet, 1, &bufInfo)); // zNear - zFar from compute shader
52 | m_device.updateDescriptorSets(writes, nullptr);
53 | }
54 |
55 | void updateRenderTarget(const vk::Extent2D& size) override
56 | {
57 | m_fxaa.updateRenderTarget(size);
58 | PostEffect::updateRenderTarget(size);
59 | }
60 |
61 | void execute(const vk::CommandBuffer& cmdBuf) override
62 | {
63 | cmdBuf.pushConstants(m_pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, m_pushCnt);
64 | PostEffect::execute(cmdBuf);
65 | if(m_useFxaa)
66 | m_fxaa.execute(cmdBuf);
67 | }
68 |
69 | const nvvk::Texture getOutput() override
70 | {
71 | if(m_useFxaa)
72 | return m_fxaa.getOutput();
73 |
74 | return m_output;
75 | }
76 |
77 | void destroy() override
78 | {
79 | m_fxaa.destroy();
80 | PostEffect::destroy();
81 | }
82 |
83 | bool uiSetup() override
84 | {
85 | bool changed{false};
86 | changed |= ImGui::SliderFloat("Normal Threshold", &m_pushCnt.normalDiffCoeff, 0.0f, 1.f, "%.3f", ImGuiSliderFlags_Logarithmic);
87 | changed |= ImGui::SliderFloat("Depth Threshold", &m_pushCnt.depthDiffCoeff, 0.00f, 10.f, "%.3f", ImGuiSliderFlags_Logarithmic);
88 | changed |= ImGui::Checkbox("FXAA on Inside Details", &m_useFxaa);
89 |
90 | return changed;
91 | }
92 |
93 | private:
94 | // One input image and push constant to control the effect
95 | void createDescriptorSet() override
96 | {
97 | vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(PushConstant)};
98 |
99 | m_descSetBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); // Normal/depth from ray tracing
100 | m_descSetBind.addBinding(vkDS(1, vkDT::eStorageBuffer, 1, vkSS::eFragment)); // Min/Max
101 |
102 | m_descSetLayout = m_descSetBind.createLayout(m_device);
103 | m_descPool = m_descSetBind.createPool(m_device);
104 | m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout);
105 | m_pipelineLayout = m_device.createPipelineLayout({{}, 1, &m_descSetLayout, 1, &push_constants});
106 | m_debug.setObjectName(m_pipelineLayout, "nrmdepth");
107 | }
108 |
109 | struct PushConstant
110 | {
111 | float normalDiffCoeff{0.5f};
112 | float depthDiffCoeff{1.f};
113 | };
114 | PushConstant m_pushCnt;
115 |
116 | // Second post effect to anti-alias lines
117 | struct PostFxaa : public PostEffect
118 | {
119 | const std::string getShaderName() override { return R"(spv/fxaa.frag.spv)"; }
120 | };
121 |
122 | PostFxaa m_fxaa;
123 | bool m_useFxaa{true};
124 | };
125 |
--------------------------------------------------------------------------------
/post_objcontour.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | #pragma once
22 |
23 | #include "post_effect.hpp"
24 |
25 | // Extract the contour of the different objects and can apply a FXAA to this contour
26 | class PostObjContour : public PostEffect
27 | {
28 | public:
29 | const std::string getShaderName() override { return R"(spv/contour_objects.frag.spv)"; }
30 |
31 |
32 | void setup(const vk::Device& device, const vk::PhysicalDevice& physicalDevice, uint32_t queueIndex, nvvkpp::ResourceAllocator* allocator) override
33 | {
34 | m_fxaa.setup(device, physicalDevice, queueIndex, allocator);
35 | PostEffect::setup(device, physicalDevice, queueIndex, allocator);
36 | }
37 |
38 | void initialize(const vk::Extent2D& size) override
39 | {
40 | m_fxaa.initialize(size);
41 | PostEffect::initialize(size);
42 | }
43 |
44 | void setInputs(const std::vector& inputs) override
45 | {
46 | m_fxaa.setInputs({m_output});
47 | PostEffect::setInputs(inputs);
48 | }
49 |
50 | void updateRenderTarget(const vk::Extent2D& size) override
51 | {
52 | m_fxaa.updateRenderTarget(size);
53 | PostEffect::updateRenderTarget(size);
54 | }
55 |
56 | void execute(const vk::CommandBuffer& cmdBuf) override
57 | {
58 | cmdBuf.pushConstants(m_pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, m_pushCnt);
59 | PostEffect::execute(cmdBuf);
60 | if(m_useFxaa)
61 | m_fxaa.execute(cmdBuf);
62 | }
63 |
64 | const nvvk::Texture getOutput() override
65 | {
66 | if(m_useFxaa)
67 | return m_fxaa.getOutput();
68 |
69 | return m_output;
70 | }
71 |
72 | void destroy() override
73 | {
74 | m_fxaa.destroy();
75 | PostEffect::destroy();
76 | }
77 |
78 | bool uiSetup() override
79 | {
80 | static const std::vector dbgItem1 = {"greater", "smaller", "thicker", "different"};
81 | bool changed{false};
82 | changed |= ImGui::Combo("Line Type", &m_pushCnt.method, dbgItem1.data(), int(dbgItem1.size()));
83 | changed |= ImGui::Checkbox("FXAA on Object Contour", &m_useFxaa);
84 | return changed;
85 | }
86 |
87 | private:
88 | // One input image and push constant to control the effect
89 | void createDescriptorSet() override
90 | {
91 | vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(PushConstant)};
92 |
93 | m_descSetBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); // Normal/depth from ray tracing
94 | m_descSetLayout = m_descSetBind.createLayout(m_device);
95 | m_descPool = m_descSetBind.createPool(m_device);
96 | m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout);
97 | m_pipelineLayout = m_device.createPipelineLayout({{}, 1, &m_descSetLayout, 1, &push_constants});
98 | m_debug.setObjectName(m_pipelineLayout, "objcontour");
99 | }
100 |
101 | struct PushConstant
102 | {
103 | int method{2};
104 | };
105 | PushConstant m_pushCnt;
106 |
107 | // Second post effect to anti-alias lines
108 | struct PostFxaa : public PostEffect
109 | {
110 | const std::string getShaderName() override { return R"(spv/fxaa.frag.spv)"; }
111 | };
112 |
113 | PostFxaa m_fxaa;
114 | bool m_useFxaa{true};
115 | };
116 |
--------------------------------------------------------------------------------
/post_tonemapper.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | #pragma once
22 |
23 | #include "post_effect.hpp"
24 |
25 | // Take as an input an image (RGB32F) and apply a tonemapper
26 | class Tonemapper : public PostEffect
27 | {
28 | public:
29 | const std::string getShaderName() override { return "spv/tonemap.frag.spv"; }
30 |
31 | // Executing the the tonemapper
32 | void execute(const vk::CommandBuffer& cmdBuf) override
33 | {
34 | if(!m_active)
35 | return;
36 |
37 | cmdBuf.pushConstants(m_pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, m_pushCnt);
38 | PostEffect::execute(cmdBuf);
39 | }
40 |
41 | // Controlling the tonemapper
42 | bool uiSetup() override
43 | {
44 | static const std::vector tmItem = {"Linear", "Uncharted 2", "Hejl Richard", "ACES"};
45 | bool changed{false};
46 | changed |= ImGui::Combo("Tonemapper", &m_pushCnt.tonemapper, tmItem.data(), static_cast(tmItem.size()));
47 | changed |= ImGui::InputFloat("Exposure", &m_pushCnt.exposure, 0.1f, 1.f);
48 | changed |= ImGui::InputFloat("Gamma", &m_pushCnt.gamma, .1f, 1.f);
49 | m_pushCnt.exposure = std::max(0.1f, std::min(m_pushCnt.exposure, 100.0f));
50 | m_pushCnt.gamma = std::max(0.1f, std::min(m_pushCnt.gamma, 3.0f));
51 | return changed;
52 | }
53 |
54 | private:
55 | // One input image and push constant to control the effect
56 | void createDescriptorSet() override
57 | {
58 | vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(PushConstant)};
59 | m_descSetBind.clear();
60 | m_descSetBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); // Normal/depth from ray tracing
61 | m_descSetLayout = m_descSetBind.createLayout(m_device);
62 | m_descPool = m_descSetBind.createPool(m_device);
63 | m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout);
64 | m_pipelineLayout = m_device.createPipelineLayout({{}, 1, &m_descSetLayout, 1, &push_constants});
65 | m_debug.setObjectName(m_pipelineLayout, "tonemap");
66 | }
67 |
68 | struct PushConstant
69 | {
70 | int tonemapper{1};
71 | float gamma{2.2f};
72 | float exposure{3.0f};
73 | };
74 | PushConstant m_pushCnt;
75 | };
76 |
--------------------------------------------------------------------------------
/rasterizer.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | //--------------------------------------------------------------------------------------------------
22 | // This example is loading a glTF scene and renders it with a very simple material
23 | //
24 |
25 | #include
26 | #include
27 |
28 | #include "nvh/fileoperations.hpp"
29 | #include "nvvk/images_vk.hpp"
30 | #include "nvvk/pipeline_vk.hpp"
31 | #include "nvvk/renderpasses_vk.hpp"
32 | #include "nvvk/shaders_vk.hpp"
33 | #include "rasterizer.hpp"
34 |
35 |
36 | extern std::vector defaultSearchPaths;
37 |
38 | void Rasterizer::setup(const vk::Device& device, const vk::PhysicalDevice& physicalDevice, uint32_t queueIndex, nvvkpp::ResourceAllocator* allocator)
39 | {
40 | m_device = device;
41 | m_queueIndex = queueIndex;
42 | m_debug.setup(device);
43 | m_alloc = allocator;
44 | }
45 |
46 | //--------------------------------------------------------------------------------------------------
47 | // Overridden function called on shutdown
48 | //
49 | void Rasterizer::destroy()
50 | {
51 | m_device.waitIdle();
52 |
53 | m_alloc->destroy(m_depthImage);
54 | for(auto& t : m_rasterizerOutput)
55 | m_alloc->destroy(t);
56 |
57 | m_device.destroy(m_renderPass);
58 | m_device.destroy(m_framebuffer);
59 | m_device.destroy(m_drawPipeline);
60 | m_device.destroy(m_pipelineLayout);
61 | m_device.destroy(m_depthImageView);
62 |
63 | m_framebuffer = vk::Framebuffer();
64 | m_depthImageView = vk::ImageView();
65 | }
66 |
67 |
68 | //--------------------------------------------------------------------------------
69 | // Called at each frame, as fast as possible
70 | //
71 | void Rasterizer::run(const vk::CommandBuffer& cmdBuf, const vk::DescriptorSet& dsetScene, int frame /*= 0*/)
72 | {
73 | auto dbgLabel = m_debug.scopeLabel(cmdBuf, "Start rendering");
74 |
75 | vk::ClearValue clearValues[3];
76 | clearValues[0].setColor(makeClearColor(m_clearColor)); // Color buffer
77 | clearValues[1].setColor(std::array({0.0f, 0.0f, -1.0f, 0.f})); // Data buffer
78 | clearValues[2].setDepthStencil({1.0f, 0});
79 |
80 |
81 | // Pre-recorded scene
82 | {
83 | auto dbgLabel = m_debug.scopeLabel(cmdBuf, "Recorded Scene");
84 |
85 | vk::RenderPassBeginInfo renderPassBeginInfo{m_renderPass, m_framebuffer, {{}, m_outputSize}, 3, clearValues};
86 | // Recorded
87 | //cmdBuf.beginRenderPass(renderPassBeginInfo, vk::SubpassContents::eSecondaryCommandBuffers);
88 | //cmdBuf.executeCommands(m_recordedCmdBuffer);
89 | // Immediate
90 | cmdBuf.beginRenderPass(renderPassBeginInfo, vk::SubpassContents::eInline);
91 | setViewport(cmdBuf);
92 | render(cmdBuf, dsetScene);
93 | cmdBuf.endRenderPass();
94 | }
95 | }
96 |
97 | //--------------------------------------------------------------------------------------------------
98 | // When the pipeline is set for using dynamic, this becomes useful
99 | //
100 | void Rasterizer::setViewport(const vk::CommandBuffer& cmdBuf)
101 | {
102 | cmdBuf.setViewport(0, {vk::Viewport(0.0f, 0.0f, static_cast(m_outputSize.width),
103 | static_cast(m_outputSize.height), 0.0f, 1.0f)});
104 | cmdBuf.setScissor(0, {{{0, 0}, {m_outputSize.width, m_outputSize.height}}});
105 | }
106 |
107 |
108 | //--------------------------------------------------------------------------------------------------
109 | // Building the command buffer, is in fact, recording all the calls needed to draw the frame in a
110 | // command buffer.This need to be call only if the number of objects in the scene is changing or
111 | // if the viewport is changing
112 | //
113 | void Rasterizer::recordCommandBuffer(const vk::CommandPool& cmdPool, const vk::DescriptorSet& dsetScene)
114 | {
115 | m_device.freeCommandBuffers(cmdPool, {m_recordedCmdBuffer});
116 | m_recordedCmdBuffer = m_device.allocateCommandBuffers({cmdPool, vk::CommandBufferLevel::eSecondary, 1})[0];
117 |
118 | vk::CommandBufferInheritanceInfo inheritance_info{m_renderPass};
119 | vk::CommandBufferBeginInfo begin_info{vkCB::eSimultaneousUse | vkCB::eRenderPassContinue, &inheritance_info};
120 |
121 | m_recordedCmdBuffer.begin(begin_info);
122 | {
123 | setViewport(m_recordedCmdBuffer);
124 | render(m_recordedCmdBuffer, dsetScene);
125 | }
126 | m_recordedCmdBuffer.end();
127 | }
128 |
129 |
130 | //--------------------------------------------------------------------------------------------------
131 | // The pipeline is how things are rendered, which shaders, type of primitives, depth test and more
132 | //
133 | void Rasterizer::createPipeline(const vk::DescriptorSetLayout& sceneDescSetLayout)
134 | {
135 | vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0,
136 | sizeof(PushC)};
137 |
138 | // Creating the pipeline layout
139 | vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
140 | pipelineLayoutCreateInfo.setSetLayoutCount(1);
141 | pipelineLayoutCreateInfo.setPSetLayouts(&sceneDescSetLayout);
142 | pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
143 | pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
144 | m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
145 |
146 | // Pipeline
147 | std::vector paths = defaultSearchPaths;
148 | nvvkpp::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_renderPass);
149 | gpb.depthStencilState.depthTestEnable = true;
150 |
151 | gpb.addBlendAttachmentState(nvvk::GraphicsPipelineState::makePipelineColorBlendAttachmentState());
152 | gpb.addShader(nvh::loadFile("spv/rasterizer.vert.spv", true, paths), vk::ShaderStageFlagBits::eVertex);
153 | gpb.addShader(nvh::loadFile("spv/rasterizer.frag.spv", true, paths), vk::ShaderStageFlagBits::eFragment);
154 | gpb.addBindingDescriptions({{0, sizeof(glm::vec3)}, {1, sizeof(glm::vec3)}, {2, sizeof(glm::vec2)}});
155 | gpb.addAttributeDescriptions({
156 | {0, 0, vk::Format::eR32G32B32Sfloat, 0}, // Position
157 | {1, 1, vk::Format::eR32G32B32Sfloat, 0}, // Normal
158 | {2, 2, vk::Format::eR32G32Sfloat, 0}, // Texcoord0
159 | });
160 | gpb.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
161 | m_drawPipeline = gpb.createPipeline();
162 |
163 | m_debug.setObjectName(m_drawPipeline, "ShadingPipeline");
164 | m_debug.setObjectName(gpb.getShaderModule(0), "VertexShader");
165 | m_debug.setObjectName(gpb.getShaderModule(1), "FragmentShader");
166 | }
167 |
168 |
169 | //--------------------------------------------------------------------------------------------------
170 | // Rendering all glTF nodes
171 | //
172 | void Rasterizer::render(const vk::CommandBuffer& cmdBuff, const vk::DescriptorSet& dsetScene)
173 | {
174 | if(!m_drawPipeline)
175 | {
176 | return;
177 | }
178 |
179 | m_debug.setObjectName(cmdBuff, "Recored");
180 | auto dgbLabel = m_debug.scopeLabel(cmdBuff, "Recording Scene");
181 |
182 | // Pipeline to use for rendering the current scene
183 | cmdBuff.bindPipeline(vk::PipelineBindPoint::eGraphics, m_drawPipeline);
184 |
185 | // Offsets for the descriptor set and vertex buffer
186 | std::vector offsets = {0, 0, 0};
187 |
188 | // Keeping track of the last material to avoid binding them again
189 | uint32_t lastMaterial = -1;
190 |
191 | std::vector vertexBuffers = {m_vertexBuffer->buffer, m_normalBuffer->buffer, m_uvBuffer->buffer};
192 | cmdBuff.bindVertexBuffers(0, static_cast(vertexBuffers.size()), vertexBuffers.data(), offsets.data());
193 | cmdBuff.bindIndexBuffer(m_indexBuffer->buffer, 0, vk::IndexType::eUint32);
194 |
195 | std::vector descriptorSets = {dsetScene};
196 |
197 | // The pipeline uses four descriptor set, one for the scene information, one for the matrix of the instance, one for the textures and for the environment
198 | cmdBuff.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_pipelineLayout, 0, descriptorSets, {});
199 |
200 | uint32_t idxNode = 0;
201 | for(auto& node : m_gltfScene->m_nodes)
202 | {
203 | auto dgbLabel = m_debug.scopeLabel(cmdBuff, std::string("Draw Mesh: " + std::to_string(node.primMesh)));
204 | auto& primitive = m_gltfScene->m_primMeshes[node.primMesh];
205 |
206 | m_pushC.instID = idxNode++;
207 | m_pushC.matID = primitive.materialIndex;
208 | cmdBuff.pushConstants(m_pipelineLayout, vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0, m_pushC);
209 | cmdBuff.drawIndexed(primitive.indexCount, 1, primitive.firstIndex, primitive.vertexOffset, 0);
210 | }
211 | }
212 |
213 |
214 | void Rasterizer::setToonSteps(int nbStep)
215 | {
216 | m_pushC.nbSteps = nbStep;
217 | }
218 |
219 | void Rasterizer::setToonLightDir(glm::vec3 lightDir)
220 | {
221 | m_pushC.lightDir = lightDir;
222 | }
223 |
224 | // Return all outputs
225 | const std::vector& Rasterizer::outputImages() const
226 | {
227 | return m_rasterizerOutput;
228 | }
229 |
230 | //--------------------------------------------------------------------------------------------------
231 | // The display will render the recorded command buffer, then in a sub-pass, render the UI
232 | //
233 | void Rasterizer::createRenderPass()
234 | {
235 | m_renderPass = nvvkpp::createRenderPass(m_device, {vk::Format::eR32G32B32A32Sfloat, vk::Format::eR32G32B32A32Sfloat}, // color attachment
236 | m_depthFormat, // depth attachment
237 | 1, // Nb sub-passes
238 | true, // clearColor
239 | true, // clearDepth
240 | vk::ImageLayout::eUndefined, // initialLayout
241 | vk::ImageLayout::eGeneral); // finalLayout
242 |
243 | m_debug.setObjectName(m_renderPass, "General Render Pass");
244 | }
245 |
246 |
247 | //--------------------------------------------------------------------------------------------------
248 | // Making the two output images: color, data(normal, depth, ID)
249 | //
250 | void Rasterizer::createOutputImages(vk::Extent2D size)
251 | {
252 | for(auto& t : m_rasterizerOutput)
253 | m_alloc->destroy(t);
254 | m_rasterizerOutput.clear();
255 |
256 | m_outputSize = size;
257 | auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eStorage
258 | | vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eColorAttachment;
259 | vk::DeviceSize imgSize = size.width * size.height * 4 * sizeof(float);
260 | vk::Format format = vk::Format::eR32G32B32A32Sfloat;
261 |
262 | // Create two output image, the color and the data
263 | for(int i = 0; i < 2; i++)
264 | {
265 | nvvkpp::ScopeCommandBuffer cmdBuf(m_device, m_queueIndex);
266 | vk::SamplerCreateInfo samplerCreateInfo; // default values
267 | vk::ImageCreateInfo imageCreateInfo = nvvkpp::makeImage2DCreateInfo(size, format, usage);
268 |
269 | nvvk::Image image = m_alloc->createImage(cmdBuf, imgSize, nullptr, imageCreateInfo, vk::ImageLayout::eGeneral);
270 | vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
271 | nvvk::Texture txt = m_alloc->createTexture(image, ivInfo, samplerCreateInfo);
272 | txt.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
273 |
274 | m_rasterizerOutput.push_back(txt);
275 | }
276 | {
277 | nvvkpp::ScopeCommandBuffer cmdBuf(m_device, m_queueIndex);
278 | createDepthBuffer(cmdBuf, size);
279 | }
280 | createFrameBuffer();
281 | }
282 |
283 | //--------------------------------------------------------------------------------------------------
284 | // Create the framebuffers in which the images will be rendered
285 | // - Swapchain need to be created before calling this
286 | //
287 | void Rasterizer::createFrameBuffer()
288 | {
289 | // Recreate the frame buffers
290 | m_device.destroy(m_framebuffer);
291 |
292 | // Array of attachment (color, depth)
293 | std::array attachments;
294 |
295 | // Create frame buffers for every swap chain image
296 | vk::FramebufferCreateInfo framebufferCreateInfo;
297 | framebufferCreateInfo.renderPass = m_renderPass;
298 | framebufferCreateInfo.attachmentCount = 3;
299 | framebufferCreateInfo.width = m_outputSize.width;
300 | framebufferCreateInfo.height = m_outputSize.height;
301 | framebufferCreateInfo.layers = 1;
302 | framebufferCreateInfo.pAttachments = attachments.data();
303 |
304 | // Create frame buffers for every swap chain image
305 | attachments[0] = m_rasterizerOutput[0].descriptor.imageView; // Color
306 | attachments[1] = m_rasterizerOutput[1].descriptor.imageView; // Data
307 | attachments[2] = m_depthImageView; // Depth
308 | m_framebuffer = m_device.createFramebuffer(framebufferCreateInfo);
309 |
310 | std::string name = std::string("Rasterizer_Framebuffer");
311 | #if DEBUG
312 | m_device.setDebugUtilsObjectNameEXT(
313 | {vk::ObjectType::eFramebuffer, reinterpret_cast(m_framebuffer), name.c_str()});
314 | #endif
315 | }
316 |
317 |
318 | //--------------------------------------------------------------------------------------------------
319 | // Creating an image to be used as depth buffer
320 | //
321 | void Rasterizer::createDepthBuffer(vk::CommandBuffer commandBuffer, vk::Extent2D imageSize)
322 | {
323 | m_alloc->destroy(m_depthImage);
324 | m_device.destroy(m_depthImageView);
325 |
326 | vk::ImageCreateInfo imageInfo =
327 | nvvkpp::makeImage2DCreateInfo(imageSize, m_depthFormat, vk::ImageUsageFlagBits::eDepthStencilAttachment);
328 | m_depthImage = m_alloc->createImage(imageInfo);
329 | m_debug.setObjectName(m_depthImage.image, "m_depthImage");
330 |
331 | vk::ImageViewCreateInfo viewInfo =
332 | nvvkpp::makeImage2DViewCreateInfo(m_depthImage.image, m_depthFormat, vk::ImageAspectFlagBits::eDepth);
333 | m_depthImageView = m_device.createImageView(viewInfo);
334 | m_debug.setObjectName(m_depthImageView, "m_depthImageView");
335 |
336 | // Set layout to VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
337 | nvvkpp::cmdBarrierImageLayout(commandBuffer, // Command buffer
338 | m_depthImage.image, // Image
339 | vk::ImageLayout::eUndefined, // Old layout
340 | vk::ImageLayout::eDepthStencilAttachmentOptimal, // New layout
341 | vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil);
342 | }
343 |
344 |
345 | void Rasterizer::setObjectPointers(nvh::GltfScene* gltfScene,
346 | nvvk::Buffer* vertexBuffer,
347 | nvvk::Buffer* normalBuffer,
348 | nvvk::Buffer* uvBuffer,
349 | nvvk::Buffer* indexBuffer)
350 | {
351 | m_gltfScene = gltfScene;
352 | m_vertexBuffer = vertexBuffer;
353 | m_normalBuffer = normalBuffer;
354 | m_uvBuffer = uvBuffer;
355 | m_indexBuffer = indexBuffer;
356 | }
357 |
--------------------------------------------------------------------------------
/rasterizer.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | #include
22 |
23 | #include "nvvk/vulkanhppsupport.hpp"
24 | #include "nvh/gltfscene.hpp"
25 | #include "nvvk/commands_vk.hpp"
26 | #include "nvvk/debug_util_vk.hpp"
27 | #include "nvvk/descriptorsets_vk.hpp"
28 |
29 | #include "vk_util.hpp"
30 |
31 | //--------------------------------------------------------------------------------------------------
32 | // Simple example showing a cube, camera movement and post-process
33 | //
34 | class Rasterizer
35 | {
36 | public:
37 | Rasterizer() = default;
38 |
39 | void setup(const vk::Device& device, const vk::PhysicalDevice& physicalDevice, uint32_t queueIndex, nvvkpp::ResourceAllocator* allocator);
40 | void setObjectPointers(nvh::GltfScene* gltfScene,
41 | nvvk::Buffer* vertexBuffer,
42 | nvvk::Buffer* normalBuffer,
43 | nvvk::Buffer* uvBuffer,
44 | nvvk::Buffer* indexBuffer);
45 |
46 | // Executing the rasterizer
47 | void run(const vk::CommandBuffer& cmdBuf, const vk::DescriptorSet& dsetScene, int frame = 0);
48 |
49 | // Return the rendered image
50 | const std::vector& outputImages() const;
51 |
52 | void destroy();
53 | void recordCommandBuffer(const vk::CommandPool& cmdPool, const vk::DescriptorSet& dsetScene);
54 | void createOutputImages(vk::Extent2D size);
55 | void createFrameBuffer();
56 | void createRenderPass();
57 | void createPipeline(const vk::DescriptorSetLayout& sceneDescSetLayout);
58 |
59 | void setClearColor(glm::vec3& _color) { m_clearColor = _color; }
60 | void setToonSteps(int nbStep);
61 | void setToonLightDir(glm::vec3 lightDir);
62 |
63 | private:
64 | void createDepthBuffer(vk::CommandBuffer commandBuffer, vk::Extent2D imageSize);
65 | void setViewport(const vk::CommandBuffer& cmdBuf);
66 | void render(const vk::CommandBuffer& cmdBuff, const vk::DescriptorSet& dsetScene);
67 |
68 |
69 | struct PushC
70 | {
71 | glm::vec3 lightDir{-1, -1, -1};
72 | int nbSteps{5};
73 | int instID{0};
74 | int matID{0};
75 | } m_pushC;
76 |
77 | glm::vec3 m_clearColor{0, 0, 0};
78 |
79 | // Rasterizer
80 | vk::PipelineLayout m_pipelineLayout;
81 | vk::Pipeline m_drawPipeline;
82 | vk::CommandBuffer m_recordedCmdBuffer;
83 | std::vector m_rasterizerOutput; // many outputs (2)
84 | nvvk::Image m_depthImage;
85 | vk::ImageView m_depthImageView;
86 | vk::Extent2D m_outputSize;
87 | vk::RenderPass m_renderPass;
88 | vk::Framebuffer m_framebuffer;
89 | vk::Format m_depthFormat{vk::Format::eD24UnormS8Uint};
90 |
91 | // Scene data
92 | nvh::GltfScene* m_gltfScene{nullptr}; // The scene
93 | nvvk::Buffer* m_vertexBuffer{nullptr};
94 | nvvk::Buffer* m_normalBuffer{nullptr};
95 | nvvk::Buffer* m_uvBuffer{nullptr};
96 | nvvk::Buffer* m_indexBuffer{nullptr};
97 |
98 | // Vulkan core
99 | vk::Device m_device;
100 | nvvk::DebugUtil m_debug;
101 | uint32_t m_queueIndex;
102 | nvvkpp::ResourceAllocator* m_alloc{nullptr};
103 | };
104 |
--------------------------------------------------------------------------------
/raypick.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | #pragma once
22 |
23 | //////////////////////////////////////////////////////////////////////////
24 | // Raytracing implementation for the Vulkan Interop (G-Buffers)
25 | //////////////////////////////////////////////////////////////////////////
26 |
27 |
28 | #include "nvh/fileoperations.hpp"
29 | #include "nvvk/debug_util_vk.hpp"
30 | #include "nvvk/descriptorsets_vk.hpp"
31 | #include "nvvk/shaders_vk.hpp"
32 | #include "nvvk/vulkanhppsupport.hpp"
33 | #include "vk_util.hpp"
34 |
35 |
36 | extern std::vector defaultSearchPaths;
37 |
38 |
39 | struct RayPicker
40 | {
41 | private:
42 | std::vector m_groups;
43 |
44 | public:
45 | struct PushConstant
46 | {
47 | float pickX{0};
48 | float pickY{0};
49 | } m_pushC;
50 |
51 | struct PickResult
52 | {
53 | glm::vec4 worldPos{0, 0, 0, 0};
54 | glm::vec4 barycentrics{0, 0, 0, 0};
55 | uint32_t intanceID{0};
56 | uint32_t intanceCustomID{0};
57 | uint32_t primitiveID{0};
58 | };
59 |
60 | nvvk::Buffer m_pickResult;
61 | nvvk::Buffer m_sbtBuffer;
62 |
63 | nvvkpp::DescriptorSetBindings m_binding;
64 |
65 | vk::DescriptorPool m_descPool;
66 | vk::DescriptorSetLayout m_descSetLayout;
67 | vk::DescriptorSet m_descSet;
68 | vk::PipelineLayout m_pipelineLayout;
69 | vk::Pipeline m_pipeline;
70 | vk::PhysicalDeviceRayTracingPropertiesNV m_raytracingProperties;
71 | vk::AccelerationStructureNV m_tlas;
72 | vk::PhysicalDevice m_physicalDevice;
73 | vk::Device m_device;
74 | uint32_t m_queueIndex;
75 | nvvkpp::ResourceAllocator* m_alloc{nullptr};
76 | nvvk::DebugUtil m_debug;
77 |
78 | RayPicker() = default;
79 |
80 |
81 | void setup(const vk::Device& device, const vk::PhysicalDevice& physicalDevice, uint32_t queueIndex, nvvkpp::ResourceAllocator* allocator)
82 | {
83 | m_physicalDevice = physicalDevice;
84 | m_device = device;
85 | m_queueIndex = queueIndex;
86 | m_debug.setup(device);
87 | m_alloc = allocator;
88 | }
89 |
90 |
91 | VkBuffer outputResult() const { return m_pickResult.buffer; }
92 |
93 | void destroy()
94 | {
95 | m_alloc->destroy(m_pickResult);
96 | m_alloc->destroy(m_sbtBuffer);
97 | m_device.destroyDescriptorSetLayout(m_descSetLayout);
98 | m_device.destroyPipelineLayout(m_pipelineLayout);
99 | m_device.destroyPipeline(m_pipeline);
100 | m_device.destroyDescriptorPool(m_descPool);
101 | }
102 |
103 | void initialize(const vk::AccelerationStructureNV& tlas, const vk::DescriptorBufferInfo& sceneUbo)
104 | {
105 |
106 | m_tlas = tlas;
107 |
108 | // Query the values of shaderHeaderSize and maxRecursionDepth in current implementation
109 | m_raytracingProperties =
110 | m_physicalDevice.getProperties2()
111 | .get();
112 |
113 |
114 | createOutputResult();
115 | createDescriptorSet(sceneUbo);
116 | createPipeline();
117 | createShadingBindingTable();
118 | }
119 |
120 | void createOutputResult()
121 | {
122 | m_alloc->destroy(m_pickResult);
123 | m_pickResult =
124 | m_alloc->createBuffer(sizeof(PickResult), vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eStorageBuffer,
125 | vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
126 | m_debug.setObjectName(m_pickResult.buffer, "PickResult");
127 | }
128 |
129 | void createDescriptorSet(const vk::DescriptorBufferInfo& sceneUbo)
130 | {
131 | m_binding.clear();
132 | m_binding.addBinding(vkDS(0, vkDT::eAccelerationStructureNV, 1, vkSS::eRaygenNV | vkSS::eClosestHitNV));
133 | m_binding.addBinding(vkDS(1, vkDT::eStorageBuffer, 1, vkSS::eRaygenNV));
134 | m_binding.addBinding(vkDS(2, vkDT::eUniformBuffer, 1, vkSS::eRaygenNV | vkSS::eClosestHitNV));
135 |
136 | m_descPool = m_binding.createPool(m_device);
137 | m_descSetLayout = m_binding.createLayout(m_device);
138 | m_descSet = m_device.allocateDescriptorSets({m_descPool, 1, &m_descSetLayout})[0];
139 |
140 | vk::WriteDescriptorSetAccelerationStructureNV descAsInfo{1, &m_tlas};
141 |
142 | vk::DescriptorBufferInfo pickDesc{m_pickResult.buffer, 0, VK_WHOLE_SIZE};
143 | std::vector writes;
144 | writes.emplace_back(m_binding.makeWrite(m_descSet, 0, &descAsInfo));
145 | writes.emplace_back(m_binding.makeWrite(m_descSet, 1, &pickDesc));
146 | writes.emplace_back(m_binding.makeWrite(m_descSet, 2, &sceneUbo));
147 | m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr);
148 | }
149 |
150 |
151 | void createPipeline()
152 | {
153 | vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, nvh::loadFile("spv/pick.rgen.spv", true, defaultSearchPaths));
154 | vk::ShaderModule missSM = nvvk::createShaderModule(m_device, nvh::loadFile("spv/pick.rmiss.spv", true, defaultSearchPaths));
155 | vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, nvh::loadFile("spv/pick.rchit.spv", true, defaultSearchPaths));
156 |
157 | std::vector stages;
158 |
159 | // Raygen
160 | stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenNV, raygenSM, "main"});
161 | vk::RayTracingShaderGroupCreateInfoNV rg{vk::RayTracingShaderGroupTypeNV::eGeneral, VK_SHADER_UNUSED_NV,
162 | VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV};
163 | rg.setGeneralShader(static_cast(stages.size() - 1));
164 | m_groups.push_back(rg);
165 | // Miss - TODO remove
166 | stages.push_back({{}, vk::ShaderStageFlagBits::eMissNV, missSM, "main"});
167 | vk::RayTracingShaderGroupCreateInfoNV mg{vk::RayTracingShaderGroupTypeNV::eGeneral, VK_SHADER_UNUSED_NV,
168 | VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV};
169 | mg.setGeneralShader(static_cast(stages.size() - 1));
170 | m_groups.push_back(mg);
171 | // Hit
172 | stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitNV, chitSM, "main"});
173 | vk::RayTracingShaderGroupCreateInfoNV hg{vk::RayTracingShaderGroupTypeNV::eTrianglesHitGroup, VK_SHADER_UNUSED_NV,
174 | VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV};
175 | hg.setClosestHitShader(static_cast(stages.size() - 1));
176 | m_groups.push_back(hg);
177 |
178 | vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenNV, 0, sizeof(PushConstant)};
179 | vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
180 | pipelineLayoutCreateInfo.setSetLayoutCount(1);
181 | pipelineLayoutCreateInfo.setPSetLayouts(&m_descSetLayout);
182 | pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
183 | pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant);
184 | m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
185 | m_debug.setObjectName(m_pipelineLayout, "raypick");
186 |
187 | // Assemble the shader stages and recursion depth info into the raytracing pipeline
188 | vk::RayTracingPipelineCreateInfoNV rayPipelineInfo;
189 | rayPipelineInfo.setStageCount(static_cast(stages.size()));
190 | rayPipelineInfo.setPStages(stages.data());
191 | rayPipelineInfo.setGroupCount(static_cast(m_groups.size()));
192 | rayPipelineInfo.setPGroups(m_groups.data());
193 | rayPipelineInfo.setMaxRecursionDepth(2);
194 | rayPipelineInfo.setLayout(m_pipelineLayout);
195 | m_pipeline = m_device.createRayTracingPipelineNV({}, rayPipelineInfo).value;
196 |
197 | m_device.destroyShaderModule(raygenSM);
198 | m_device.destroyShaderModule(missSM);
199 | m_device.destroyShaderModule(chitSM);
200 | }
201 |
202 |
203 | void createShadingBindingTable()
204 | {
205 | auto groupCount = static_cast(m_groups.size()); // 3 shaders: raygen, miss, chit
206 | uint32_t groupHandleSize = m_raytracingProperties.shaderGroupHandleSize; // Size of a program identifier
207 | uint32_t alignSize = m_raytracingProperties.shaderGroupBaseAlignment; // Size of a program identifier
208 |
209 |
210 | // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
211 | uint32_t sbtSize = groupCount * alignSize;
212 | std::vector shaderHandleStorage(sbtSize);
213 | auto res = m_device.getRayTracingShaderGroupHandlesNV(m_pipeline, 0, groupCount, sbtSize, shaderHandleStorage.data());
214 | assert(res == vk::Result::eSuccess);
215 |
216 | m_sbtBuffer = m_alloc->createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc,
217 | vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
218 | m_debug.setObjectName(m_sbtBuffer.buffer, std::string("PickSBT").c_str());
219 |
220 | // Write the handles in the SBT
221 | void* mapped = m_alloc->map(m_sbtBuffer);
222 | auto* pData = reinterpret_cast(mapped);
223 | for(uint32_t g = 0; g < groupCount; g++)
224 | {
225 | memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
226 | pData += alignSize;
227 | }
228 | m_alloc->unmap(m_sbtBuffer);
229 | }
230 |
231 | void run(const vk::CommandBuffer& cmdBuf, float x, float y)
232 | {
233 | m_pushC.pickX = x;
234 | m_pushC.pickY = y;
235 |
236 | uint32_t progSize = m_raytracingProperties.shaderGroupBaseAlignment; // Size of a program identifier
237 | cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingNV, m_pipeline);
238 | cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingNV, m_pipelineLayout, 0, {m_descSet}, {});
239 | cmdBuf.pushConstants(m_pipelineLayout, vk::ShaderStageFlagBits::eRaygenNV, 0, m_pushC);
240 |
241 | vk::DeviceSize rayGenOffset = 0 * progSize;
242 | vk::DeviceSize missOffset = 1 * progSize;
243 | vk::DeviceSize missStride = progSize;
244 | vk::DeviceSize hitGroupOffset = 2 * progSize; // Jump over the miss
245 | vk::DeviceSize hitGroupStride = progSize;
246 |
247 | cmdBuf.traceRaysNV(m_sbtBuffer.buffer, rayGenOffset, //
248 | m_sbtBuffer.buffer, missOffset, missStride, //
249 | m_sbtBuffer.buffer, hitGroupOffset, hitGroupStride, //
250 | m_sbtBuffer.buffer, 0, 0, //
251 | 1, 1, //
252 | 1 /*, NVVKPP_DISPATCHER*/);
253 |
254 | vk::BufferMemoryBarrier bmb{vk::AccessFlagBits::eMemoryWrite,
255 | vk::AccessFlagBits::eMemoryRead,
256 | VK_QUEUE_FAMILY_IGNORED,
257 | VK_QUEUE_FAMILY_IGNORED,
258 | m_pickResult.buffer,
259 | 0,
260 | VK_WHOLE_SIZE};
261 | cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTopOfPipe,
262 | vk::DependencyFlagBits::eDeviceGroup, 0, nullptr, 1, &bmb, 0, nullptr);
263 | }
264 |
265 | PickResult getResult()
266 | {
267 | PickResult pr;
268 | void* mapped = m_alloc->map(m_pickResult);
269 | memcpy(&pr, mapped, sizeof(PickResult));
270 | m_alloc->unmap(m_pickResult);
271 | return pr;
272 | }
273 | };
274 |
--------------------------------------------------------------------------------
/raytracer.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | #include "raytracer.hpp"
22 | #include "imgui.h"
23 | #include "nvh/fileoperations.hpp"
24 | #include "nvvk/images_vk.hpp"
25 | #include "nvvk/shaders_vk.hpp"
26 |
27 | extern std::vector defaultSearchPaths;
28 |
29 | Raytracer::Raytracer() = default;
30 |
31 | //--------------------------------------------------------------------------------------------------
32 | // Initializing the allocator and querying the raytracing properties
33 | //
34 | void Raytracer::setup(const vk::Device& device, const vk::PhysicalDevice& physicalDevice, uint32_t queueIndex, nvvkpp::ResourceAllocator* allocator)
35 | {
36 | m_device = device;
37 | m_queueIndex = queueIndex;
38 | m_debug.setup(device);
39 | m_alloc = allocator;
40 |
41 | // Requesting raytracing properties
42 | auto properties = physicalDevice.getProperties2();
43 | m_rtProperties = properties.get();
44 |
45 | if(m_rtProperties.shaderGroupHandleSize != 0)
46 | m_bValid = true;
47 | else
48 | {
49 | m_bValid = false;
50 | return;
51 | }
52 | m_rtBuilder.setup(device, allocator, queueIndex);
53 | }
54 |
55 | const std::vector& Raytracer::outputImages() const
56 | {
57 | return m_raytracingOutput;
58 | }
59 |
60 | int Raytracer::maxFrames() const
61 | {
62 | return m_maxFrames;
63 | }
64 |
65 | void Raytracer::destroy()
66 | {
67 | for(auto& t : m_raytracingOutput)
68 | m_alloc->destroy(t);
69 | m_rtBuilder.destroy();
70 | m_device.destroy(m_descPool);
71 | m_device.destroy(m_descSetLayout);
72 | m_device.destroy(m_pipeline);
73 | m_device.destroy(m_pipelineLayout);
74 | m_alloc->destroy(m_sbtBuffer);
75 | m_alloc->destroy(m_rtPrimLookup);
76 | m_binding.clear();
77 | }
78 |
79 | //--------------------------------------------------------------------------------------------------
80 | // Making all output images: color, normal, ...
81 | //
82 | void Raytracer::createOutputImages(vk::Extent2D size)
83 | {
84 | for(auto& t : m_raytracingOutput)
85 | m_alloc->destroy(t);
86 | m_raytracingOutput.clear();
87 |
88 | m_outputSize = size;
89 | auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferSrc;
90 | vk::DeviceSize imgSize = size.width * size.height * 4 * sizeof(float);
91 | vk::Format format = vk::Format::eR32G32B32A32Sfloat;
92 |
93 | // Create two output image, the color and the data
94 | for(int i = 0; i < 2; i++)
95 | {
96 | nvvkpp::ScopeCommandBuffer cmdBuf(m_device, m_queueIndex);
97 | vk::SamplerCreateInfo samplerCreateInfo; // default values
98 | vk::ImageCreateInfo imageCreateInfo = nvvkpp::makeImage2DCreateInfo(size, format, usage);
99 |
100 | nvvk::Image image = m_alloc->createImage(cmdBuf, imgSize, nullptr, imageCreateInfo, vk::ImageLayout::eGeneral);
101 | vk::ImageViewCreateInfo ivInfo = nvvkpp::makeImageViewCreateInfo(image.image, imageCreateInfo);
102 | nvvk::Texture txt = m_alloc->createTexture(image, ivInfo, samplerCreateInfo);
103 | txt.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
104 |
105 | m_raytracingOutput.push_back(txt);
106 | }
107 | m_alloc->finalizeAndReleaseStaging();
108 | }
109 |
110 | void Raytracer::createDescriptorSet()
111 | {
112 | using vkDS = vk::DescriptorSetLayoutBinding;
113 | using vkDT = vk::DescriptorType;
114 | using vkSS = vk::ShaderStageFlagBits;
115 |
116 | uint32_t nbOutput = static_cast(m_raytracingOutput.size());
117 |
118 | m_binding.addBinding(vkDS(0, vkDT::eAccelerationStructureNV, 1, vkSS::eRaygenNV | vkSS::eClosestHitNV));
119 | m_binding.addBinding(vkDS(1, vkDT::eStorageImage, nbOutput, vkSS::eRaygenNV)); // Output image
120 | m_binding.addBinding(vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eClosestHitNV | vkSS::eAnyHitNV)); // Primitive info
121 |
122 | m_descPool = m_binding.createPool(m_device);
123 | m_descSetLayout = m_binding.createLayout(m_device);
124 | m_descSet = m_device.allocateDescriptorSets({m_descPool, 1, &m_descSetLayout})[0];
125 |
126 | std::vector writes;
127 |
128 | vk::AccelerationStructureNV tlas = m_rtBuilder.getAccelerationStructure();
129 | vk::WriteDescriptorSetAccelerationStructureNV descAsInfo{1, &tlas};
130 | vk::DescriptorBufferInfo primitiveInfoDesc{m_rtPrimLookup.buffer, 0, VK_WHOLE_SIZE};
131 | writes.emplace_back(m_binding.makeWrite(m_descSet, 0, &descAsInfo));
132 |
133 | std::vector descImgInfo;
134 | for(auto& i : m_raytracingOutput)
135 | {
136 | descImgInfo.push_back(i.descriptor);
137 | }
138 | writes.emplace_back(m_binding.makeWriteArray(m_descSet, 1, descImgInfo.data()));
139 |
140 | writes.emplace_back(m_binding.makeWrite(m_descSet, 2, &primitiveInfoDesc));
141 | m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr);
142 |
143 | updateDescriptorSet();
144 | }
145 |
146 | void Raytracer::updateDescriptorSet()
147 | {
148 | // (1) Output buffer
149 | {
150 | std::vector descImgInfo;
151 | for(auto& i : m_raytracingOutput)
152 | {
153 | descImgInfo.push_back(i.descriptor);
154 | }
155 | vk::WriteDescriptorSet wds = m_binding.makeWriteArray(m_descSet, 1, descImgInfo.data());
156 |
157 | //vk::DescriptorImageInfo imageInfo{{}, m_raytracingOutput.descriptor.imageView, vk::ImageLayout::eGeneral};
158 | //vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo};
159 | m_device.updateDescriptorSets(wds, nullptr);
160 | }
161 | }
162 |
163 | void Raytracer::createPipeline(const vk::DescriptorSetLayout& sceneDescSetLayout)
164 | {
165 | vk::ShaderModule raygenSM =
166 | nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths));
167 | vk::ShaderModule missSM = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths));
168 | vk::ShaderModule shadowmissSM =
169 | nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths));
170 | vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths));
171 |
172 | std::vector stages;
173 |
174 | // Raygen
175 | vk::RayTracingShaderGroupCreateInfoNV rg{vk::RayTracingShaderGroupTypeNV::eGeneral, VK_SHADER_UNUSED_NV,
176 | VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV};
177 | stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenNV, raygenSM, "main"});
178 | rg.setGeneralShader(static_cast(stages.size() - 1));
179 | m_groups.push_back(rg);
180 | // Miss
181 | vk::RayTracingShaderGroupCreateInfoNV mg{vk::RayTracingShaderGroupTypeNV::eGeneral, VK_SHADER_UNUSED_NV,
182 | VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV};
183 | stages.push_back({{}, vk::ShaderStageFlagBits::eMissNV, missSM, "main"});
184 | mg.setGeneralShader(static_cast(stages.size() - 1));
185 | m_groups.push_back(mg);
186 | // Shadow Miss
187 | stages.push_back({{}, vk::ShaderStageFlagBits::eMissNV, shadowmissSM, "main"});
188 | mg.setGeneralShader(static_cast(stages.size() - 1));
189 | m_groups.push_back(mg);
190 | // Hit Group - Closest Hit + AnyHit
191 | vk::RayTracingShaderGroupCreateInfoNV hg{vk::RayTracingShaderGroupTypeNV::eTrianglesHitGroup, VK_SHADER_UNUSED_NV,
192 | VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV};
193 | stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitNV, chitSM, "main"});
194 | hg.setClosestHitShader(static_cast(stages.size() - 1));
195 | m_groups.push_back(hg);
196 |
197 | // Push constant: ray depth, ...
198 | vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenNV | vk::ShaderStageFlagBits::eClosestHitNV
199 | | vk::ShaderStageFlagBits::eMissNV,
200 | 0, sizeof(PushConstant)};
201 |
202 | // All 3 descriptors
203 | std::vector allLayouts = {m_descSetLayout, sceneDescSetLayout};
204 | vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
205 | pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(allLayouts.size()));
206 | pipelineLayoutCreateInfo.setPSetLayouts(allLayouts.data());
207 | pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
208 | pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant);
209 | m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
210 | m_debug.setObjectName(m_pipelineLayout, "raytracer");
211 |
212 | // Assemble the shader stages and recursion depth info into the raytracing pipeline
213 | vk::RayTracingPipelineCreateInfoNV rayPipelineInfo;
214 | rayPipelineInfo.setStageCount(static_cast(stages.size()));
215 | rayPipelineInfo.setPStages(stages.data());
216 | rayPipelineInfo.setGroupCount(static_cast(m_groups.size()));
217 | rayPipelineInfo.setPGroups(m_groups.data());
218 | rayPipelineInfo.setMaxRecursionDepth(10);
219 | rayPipelineInfo.setLayout(m_pipelineLayout);
220 | m_pipeline = m_device.createRayTracingPipelineNV({}, rayPipelineInfo).value;
221 |
222 | m_device.destroyShaderModule(raygenSM);
223 | m_device.destroyShaderModule(missSM);
224 | m_device.destroyShaderModule(shadowmissSM);
225 | m_device.destroyShaderModule(chitSM);
226 | }
227 |
228 | //--------------------------------------------------------------------------------------------------
229 | //
230 | //
231 | void Raytracer::createShadingBindingTable()
232 | {
233 | auto groupCount = static_cast(m_groups.size()); // 3 shaders: raygen, miss, chit
234 | uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier
235 | uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier
236 |
237 |
238 | // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
239 | uint32_t sbtSize = groupCount * baseAlignment;
240 | std::vector shaderHandleStorage(sbtSize);
241 | auto result = m_device.getRayTracingShaderGroupHandlesNV(m_pipeline, 0, groupCount, sbtSize, shaderHandleStorage.data());
242 | assert(result == vk::Result::eSuccess);
243 |
244 | m_sbtBuffer = m_alloc->createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc,
245 | vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
246 | m_debug.setObjectName(m_sbtBuffer.buffer, std::string("SBT").c_str());
247 |
248 | // Write the handles in the SBT
249 | void* mapped = m_alloc->map(m_sbtBuffer);
250 | auto* pData = reinterpret_cast(mapped);
251 | for(uint32_t g = 0; g < groupCount; g++)
252 | {
253 | memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
254 | pData += baseAlignment;
255 | }
256 | m_alloc->unmap(m_sbtBuffer);
257 | }
258 |
259 | //--------------------------------------------------------------------------------------------------
260 | //
261 | //
262 | void Raytracer::run(const vk::CommandBuffer& cmdBuf, const vk::DescriptorSet& sceneDescSet, int frame /*= 0*/)
263 | {
264 | m_pushC.frame = frame;
265 |
266 | uint32_t progSize = m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier
267 | cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingNV, m_pipeline);
268 | cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingNV, m_pipelineLayout, 0, {m_descSet, sceneDescSet}, {});
269 | cmdBuf.pushConstants(m_pipelineLayout,
270 | vk::ShaderStageFlagBits::eRaygenNV | vk::ShaderStageFlagBits::eClosestHitNV
271 | | vk::ShaderStageFlagBits::eMissNV,
272 | 0, m_pushC);
273 |
274 | vk::DeviceSize rayGenOffset = 0 * progSize;
275 | vk::DeviceSize missOffset = 1 * progSize;
276 | vk::DeviceSize missStride = progSize;
277 | vk::DeviceSize hitGroupOffset = 3 * progSize; // Jump over the 2 miss
278 | vk::DeviceSize hitGroupStride = progSize;
279 |
280 | cmdBuf.traceRaysNV(m_sbtBuffer.buffer, rayGenOffset, //
281 | m_sbtBuffer.buffer, missOffset, missStride, //
282 | m_sbtBuffer.buffer, hitGroupOffset, hitGroupStride, //
283 | m_sbtBuffer.buffer, 0, 0, //
284 | m_outputSize.width, m_outputSize.height, //
285 | 1 /*, NVVKPP_DISPATCHER*/);
286 | }
287 |
288 | bool Raytracer::uiSetup()
289 | {
290 | bool modified = false;
291 | if(ImGui::CollapsingHeader("Ray Tracing"))
292 | {
293 | modified = false;
294 | modified |= ImGui::SliderFloat("Max Ray Length", &m_pushC.maxRayLenght, 1, 1000000, "%.1f");
295 | modified |= ImGui::SliderInt("Samples Per Frame", &m_pushC.samples, 1, 100);
296 | modified |= ImGui::SliderInt("Max Iteration ", &m_maxFrames, 1, 1000);
297 | }
298 | return modified;
299 | }
300 |
301 | void Raytracer::setClearColor(glm::vec3& _color)
302 | {
303 | m_pushC.backgroundColor = _color;
304 | }
305 |
306 | void Raytracer::setToonSteps(int nbStep)
307 | {
308 | m_pushC.nbSteps = nbStep;
309 | }
310 |
311 | void Raytracer::setToonLightDir(glm::vec3 lightDir)
312 | {
313 | m_pushC.lightDir = lightDir;
314 | }
315 |
--------------------------------------------------------------------------------
/raytracer.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 |
21 | #pragma once
22 |
23 | //////////////////////////////////////////////////////////////////////////
24 | // Raytracing implementation
25 | //
26 | // There are 2 descriptor sets
27 | // (0) - Acceleration structure and result image
28 | // (1) - Various buffers: vertices, indices, matrices, Material and Textures
29 | //
30 | //////////////////////////////////////////////////////////////////////////
31 |
32 | #include
33 |
34 | #include "vk_util.hpp"
35 |
36 | #include "nvvk/commands_vk.hpp"
37 | #include "nvvk/descriptorsets_vk.hpp"
38 | #include "nvvk/raytraceNV_vk.hpp"
39 |
40 | // Structure used for retrieving the primitive information in the closest hit
41 | // The gl_InstanceCustomIndexNV
42 | struct RtPrimitiveLookup
43 | {
44 | uint32_t indexOffset;
45 | uint32_t vertexOffset;
46 | int materialIndex;
47 | };
48 |
49 | class Raytracer
50 | {
51 | public:
52 | Raytracer();
53 |
54 | // Initializing the allocator and querying the raytracing properties
55 | void setup(const vk::Device& device, const vk::PhysicalDevice& physicalDevice, uint32_t queueIndex, nvvkpp::ResourceAllocator* allocator);
56 |
57 | bool isValid() { return m_bValid; }
58 |
59 | // Return the rendered image
60 | const std::vector& outputImages() const;
61 | int maxFrames() const;
62 |
63 | void destroy();
64 |
65 | // Creating the two images where the result is stored
66 | void createOutputImages(vk::Extent2D size);
67 |
68 | // Create a descriptor set holding the acceleration structure and the output image
69 | void createDescriptorSet();
70 |
71 | // Will be called when resizing the window
72 | void updateDescriptorSet();
73 |
74 | // Pipeline with all shaders, including the 3 descriptor layouts.
75 | void createPipeline(const vk::DescriptorSetLayout& sceneDescSetLayout);
76 |
77 | // The SBT, storing in a buffer the calling handles of each shader group
78 | void createShadingBindingTable();
79 |
80 | // Executing the raytracing
81 | void run(const vk::CommandBuffer& cmdBuf, const vk::DescriptorSet& sceneDescSet, int frame = 0);
82 |
83 | // To control the raytracer
84 | bool uiSetup();
85 |
86 | nvvkpp::RaytracingBuilderNV& builder() { return m_rtBuilder; }
87 |
88 | void setPrimitiveLookup(const std::vector& primitiveLookup)
89 | {
90 | nvvkpp::ScopeCommandBuffer cmdBuf(m_device, m_queueIndex);
91 | m_rtPrimLookup = m_alloc->createBuffer(cmdBuf, primitiveLookup, vk::BufferUsageFlagBits::eStorageBuffer);
92 | m_debug.setObjectName(m_rtPrimLookup.buffer, "PrimitiveInfo");
93 | }
94 |
95 | void setClearColor(glm::vec3& _color);
96 | void setToonSteps(int nbStep);
97 | void setToonLightDir(glm::vec3 lightDir);
98 |
99 | private:
100 | struct PushConstant
101 | {
102 | glm::vec3 backgroundColor{1, 1, 1};
103 | int frame{0}; // Current frame number
104 | glm::vec3 lightDir{-1, -1, -1};
105 | float maxRayLenght{100000};
106 | int samples{1}; // samples per frame
107 | int nbSteps{3}; // Dither
108 | } m_pushC;
109 |
110 | int m_maxFrames{50}; // Max iterations
111 |
112 | vk::PhysicalDeviceRayTracingPropertiesNV m_rtProperties;
113 | std::vector m_raytracingOutput; // many outputs
114 |
115 | // Raytracer
116 | nvvk::Buffer m_sbtBuffer;
117 | nvvkpp::RaytracingBuilderNV m_rtBuilder;
118 | nvvkpp::DescriptorSetBindings m_descSetLayoutBind;
119 | vk::DescriptorPool m_descPool;
120 | vk::DescriptorSetLayout m_descSetLayout;
121 | vk::DescriptorSet m_descSet;
122 | vk::PipelineLayout m_pipelineLayout;
123 | vk::Pipeline m_pipeline;
124 | vk::Extent2D m_outputSize;
125 | nvvkpp::DescriptorSetBindings m_binding;
126 | nvvk::Buffer m_rtPrimLookup;
127 | std::vector m_groups;
128 |
129 |
130 | // Vulkan
131 | bool m_bValid{false};
132 | vk::Device m_device;
133 | nvvk::DebugUtil m_debug;
134 | uint32_t m_queueIndex;
135 | nvvkpp::ResourceAllocator* m_alloc{nullptr};
136 | };
137 |
--------------------------------------------------------------------------------
/shaders/binding.glsl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #define B_SCENE 0
21 | #define B_MATRIX 1
22 | #define B_VERTICES 2
23 | #define B_INDICES 3
24 | #define B_NORMALS 4
25 | #define B_TEXCOORDS 5
26 | #define B_TANGENTS 6
27 | #define B_MATERIAL 8
28 | #define B_TEXTURES 9
29 |
30 | #define B_HDR 10
31 | #define B_FILTER_DIFFUSE 11
32 | #define B_LUT_BRDF 12
33 | #define B_FILTER_GLOSSY 13
34 | #define B_IMPORT_SMPL 14
35 |
--------------------------------------------------------------------------------
/shaders/compositing.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 450
21 | //layout(set = 0, binding = 0) uniform sampler2D inTxt;
22 |
23 | layout(set = 0, binding = 0) uniform sampler2D iChannel0; // Ray tracer out
24 | layout(set = 0, binding = 1) uniform sampler2D iChannel1; // Normal & depth Contour
25 | layout(set = 0, binding = 2) uniform sampler2D iChannel2; // Object Contour
26 |
27 | layout(push_constant) uniform params_
28 | {
29 | vec3 backgroundColor;
30 | int setBackground;
31 | vec3 lineColor;
32 | };
33 |
34 | layout(location = 0) in vec2 fragCoord;
35 | layout(location = 0) out vec4 fragColor;
36 |
37 | void main()
38 | {
39 | vec4 color = texture(iChannel0, fragCoord.st);
40 |
41 | // White backgound
42 | if(setBackground > 0)
43 | color.xyz = mix(color.xyz, backgroundColor, 1.0 - texture(iChannel0, fragCoord.st).a);
44 | //
45 | vec4 ct1 = texture(iChannel1, fragCoord.st);
46 | vec4 ct2 = texture(iChannel2, fragCoord.st);
47 |
48 | color.xyz = mix(color.xyz, lineColor, ct1.r);
49 | color.xyz = mix(color.xyz, lineColor, ct2.r); // outline contour over inline
50 |
51 | fragColor = color;
52 | }
53 |
--------------------------------------------------------------------------------
/shaders/contour_normaldepth.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 450
21 |
22 | // https://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection
23 | // https://aras-p.info/texts/CompactNormalStorage.html
24 | vec2 encode(vec3 n)
25 | {
26 | float p = sqrt(n.z * 8 + 8);
27 | return vec2(n.xy / p + 0.5);
28 | }
29 |
30 | vec3 decode(vec2 enc)
31 | {
32 | vec2 fenc = enc * 4 - 2;
33 | float f = dot(fenc, fenc);
34 | float g = sqrt(1 - f / 4);
35 | vec3 n;
36 | n.xy = fenc * g;
37 | n.z = 1 - f / 2;
38 | return n;
39 | }
40 |
41 |
42 | layout(set = 0, binding = 0) uniform sampler2D iChannel0; // Normal + depth
43 |
44 | layout(set = 0, binding = 1) buffer zValues
45 | {
46 | int minmax[2]; // zNear and zFar, from the compute shader deapthminmax.comp
47 | };
48 |
49 | layout(push_constant) uniform params_
50 | {
51 | float NormalDiffCoeff;
52 | float DepthDiffCoeff;
53 | };
54 |
55 |
56 | layout(location = 0) in vec2 fragCoord;
57 | layout(location = 0) out float fragColor;
58 |
59 |
60 | float Fdepth(in float Z, in float zNear, in float zFar)
61 | {
62 | return abs((1. / Z - 1. / zNear) / ((1. / zFar) - (1. / zNear)));
63 | }
64 |
65 | float FNdepth(in float Z, in float zNear, in float zFar)
66 | {
67 | return (Z - zNear) / (zFar - zNear);
68 | }
69 |
70 | float Gradient(ivec2 texelCoord, float zNear, float zFar)
71 | {
72 | vec4 A = texelFetchOffset(iChannel0, texelCoord, 0, ivec2(-1.0, +1.0)); // +---+---+---+
73 | vec4 B = texelFetchOffset(iChannel0, texelCoord, 0, ivec2(+0.0, +1.0)); // | A | B | C |
74 | vec4 C = texelFetchOffset(iChannel0, texelCoord, 0, ivec2(+1.0, +1.0)); // +---+---+---+
75 | vec4 D = texelFetchOffset(iChannel0, texelCoord, 0, ivec2(-1.0, +0.0)); // | D | X | E |
76 | vec4 X = texelFetchOffset(iChannel0, texelCoord, 0, ivec2(+0.0, +0.0)); // +---+---+---+
77 | vec4 E = texelFetchOffset(iChannel0, texelCoord, 0, ivec2(+1.0, +0.0)); // | F | G | H |
78 | vec4 F = texelFetchOffset(iChannel0, texelCoord, 0, ivec2(-1.0, -1.0)); // +---+---+---+
79 | vec4 G = texelFetchOffset(iChannel0, texelCoord, 0, ivec2(+0.0, -1.0));
80 | vec4 H = texelFetchOffset(iChannel0, texelCoord, 0, ivec2(+1.0, -1.0));
81 |
82 | // Don't sample background
83 | int objId = floatBitsToInt(X.w);
84 | if(X.z < 0.0001 || objId == 0)
85 | return 0;
86 |
87 | vec3 An = decode(A.xy);
88 | vec3 Bn = decode(B.xy);
89 | vec3 Cn = decode(C.xy);
90 | vec3 Dn = decode(D.xy);
91 | vec3 Xn = decode(X.xy);
92 | vec3 En = decode(E.xy);
93 | vec3 Fn = decode(F.xy);
94 | vec3 Gn = decode(G.xy);
95 | vec3 Hn = decode(H.xy);
96 |
97 | // Normal Gradient
98 | float Ngrad = 0;
99 | {
100 | // compute length of gradient using Sobel/Kroon operator
101 | const float k0 = 17. / 23.75;
102 | const float k1 = 61. / 23.75;
103 | const vec3 grad_y = k0 * An + k1 * Bn + k0 * Cn - k0 * Fn - k1 * Gn - k0 * Hn;
104 | const vec3 grad_x = k0 * Cn + k1 * En + k0 * Hn - k0 * An - k1 * Dn - k0 * Fn;
105 | const float g = length(grad_x) + length(grad_y);
106 |
107 | Ngrad = smoothstep(2.f, 3.f, g * NormalDiffCoeff); //!! magic
108 | }
109 |
110 | // Depth Gradient
111 | float Dgrad = 0;
112 | {
113 | // https://www.cs.princeton.edu/courses/archive/fall00/cs597b/papers/saito90.pdf
114 | A.z = Fdepth(A.z, zNear, zFar);
115 | B.z = Fdepth(B.z, zNear, zFar);
116 | C.z = Fdepth(C.z, zNear, zFar);
117 | D.z = Fdepth(D.z, zNear, zFar);
118 | E.z = Fdepth(E.z, zNear, zFar);
119 | F.z = Fdepth(F.z, zNear, zFar);
120 | G.z = Fdepth(G.z, zNear, zFar);
121 | H.z = Fdepth(H.z, zNear, zFar);
122 | X.z = Fdepth(X.z, zNear, zFar);
123 |
124 | float g = (abs(A.z + 2 * B.z + C.z - F.z - 2 * G.z - H.z) + abs(C.z + 2 * E.z + H.z - A.z - 2 * D.z - F.z)) / 8.0;
125 | float l = (8 * X.z - A.z - B.z - C.z - D.z - E.z - F.z - G.z - H.z) / 3.0;
126 |
127 | Dgrad = (l + g) * DepthDiffCoeff;
128 | Dgrad = smoothstep(0.03f, 0.1f, Dgrad); // !magic values
129 | }
130 |
131 |
132 | return Ngrad + Dgrad;
133 | }
134 |
135 | void main()
136 | {
137 | ivec2 size = textureSize(iChannel0, 0);
138 | ivec2 texelCoord = ivec2(vec2(size) * fragCoord.st);
139 |
140 | float zNear = intBitsToFloat(minmax[0]);
141 | float zFar = intBitsToFloat(minmax[1]);
142 |
143 | fragColor = Gradient(texelCoord, zNear, zFar);
144 | }
145 |
--------------------------------------------------------------------------------
/shaders/contour_objects.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 450
21 |
22 | // clang-format off
23 | layout(set = 0, binding = 0) uniform sampler2D iChannel0; // Object ID in Z
24 | // clang-format on
25 |
26 | layout(push_constant) uniform params_
27 | {
28 | int contourMethod;
29 | };
30 |
31 |
32 | layout(location = 0) in vec2 fragCoord;
33 | layout(location = 0) out vec4 fragColor;
34 |
35 |
36 | vec4 objectContour()
37 | {
38 | ivec2 size = textureSize(iChannel0, 0);
39 | ivec2 texelCoord = ivec2(vec2(size) * fragCoord.st);
40 |
41 | int A = floatBitsToInt(texelFetchOffset(iChannel0, texelCoord, 0, ivec2(-1.0, +1.0)).w); // +---+---+---+
42 | int B = floatBitsToInt(texelFetchOffset(iChannel0, texelCoord, 0, ivec2(+0.0, +1.0)).w); // | A | B | C |
43 | int C = floatBitsToInt(texelFetchOffset(iChannel0, texelCoord, 0, ivec2(+1.0, +1.0)).w); // +---+---+---+
44 | int D = floatBitsToInt(texelFetchOffset(iChannel0, texelCoord, 0, ivec2(-1.0, +0.0)).w); // | D | X | E |
45 | int X = floatBitsToInt(texelFetchOffset(iChannel0, texelCoord, 0, ivec2(+0.0, +0.0)).w); // +---+---+---+
46 | int E = floatBitsToInt(texelFetchOffset(iChannel0, texelCoord, 0, ivec2(+1.0, +0.0)).w); // | F | G | H |
47 | int F = floatBitsToInt(texelFetchOffset(iChannel0, texelCoord, 0, ivec2(-1.0, -1.0)).w); // +---+---+---+
48 | int G = floatBitsToInt(texelFetchOffset(iChannel0, texelCoord, 0, ivec2(+0.0, -1.0)).w);
49 | int H = floatBitsToInt(texelFetchOffset(iChannel0, texelCoord, 0, ivec2(+1.0, -1.0)).w);
50 |
51 |
52 | switch(contourMethod)
53 | {
54 | case 0: // smaller
55 | if(X < A || X < B || X < C || X < D || X < E || X < F || X < G || X < H)
56 | {
57 | return vec4(1);
58 | }
59 | break;
60 | case 1: // bigger
61 | if(X > A || X > B || X > C || X > D || X > E || X > F || X > G || X > H)
62 | {
63 | return vec4(1);
64 | }
65 | break;
66 | case 2: // thicker
67 | if(X != A || X != B || X != C || X != D || X != E || X != F || X != G || X != H)
68 | {
69 | return vec4(1);
70 | }
71 | case 3: // different
72 | return vec4((int(X != A) + int(X != C) + int(X != F) + int(X != H)) * (1. / 6.)
73 | + (int(X != B) + int(X != D) + int(X != E) + int(X != G)) * (1. / 3.));
74 |
75 | break;
76 | }
77 |
78 | return vec4(0);
79 | }
80 |
81 | void main()
82 | {
83 | fragColor = objectContour();
84 | }
85 |
--------------------------------------------------------------------------------
/shaders/depthminmax.comp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 450
21 |
22 |
23 | layout(local_size_x = 32, local_size_y = 32) in;
24 | layout(binding = 0, rgba8) uniform image2D inImage;
25 | layout(binding = 1) buffer outValue
26 | {
27 | uint minmax[2];
28 | };
29 |
30 | // Extracting the zNear and zFar of the image, storing the value in outValue.
31 |
32 | void main()
33 | {
34 | ivec2 size = imageSize(inImage);
35 | if(gl_GlobalInvocationID.x >= size.x || gl_GlobalInvocationID.y >= size.y)
36 | return;
37 |
38 | vec4 fragColor = imageLoad(inImage, ivec2(gl_GlobalInvocationID.xy));
39 |
40 | if(fragColor.z > 0)
41 | {
42 | atomicMin(minmax[0], floatBitsToInt(fragColor.z));
43 | atomicMax(minmax[1], floatBitsToInt(fragColor.z));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/shaders/final.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 450
21 | layout(location = 0) in vec2 inUV;
22 | layout(location = 0) out vec4 outFragColor;
23 |
24 | layout(set = 0, binding = 0) uniform sampler2D inTxt;
25 |
26 | void main()
27 | {
28 | outFragColor = texture(inTxt, inUV).rgba;
29 | }
30 |
--------------------------------------------------------------------------------
/shaders/fxaa.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 450
21 |
22 | /**
23 | Basic FXAA implementation based on the code on geeks3d.com with the
24 | modification that the texture2DLod stuff was removed since it's
25 | unsupported by WebGL.
26 |
27 | --
28 |
29 | From:
30 | https://github.com/mitsuhiko/webgl-meincraft
31 |
32 | Copyright (c) 2011 by Armin Ronacher.
33 |
34 | Some rights reserved.
35 |
36 | Redistribution and use in source and binary forms, with or without
37 | modification, are permitted provided that the following conditions are
38 | met:
39 |
40 | * Redistributions of source code must retain the above copyright
41 | notice, this list of conditions and the following disclaimer.
42 |
43 | * Redistributions in binary form must reproduce the above
44 | copyright notice, this list of conditions and the following
45 | disclaimer in the documentation and/or other materials provided
46 | with the distribution.
47 |
48 | * The names of the contributors may not be used to endorse or
49 | promote products derived from this software without specific
50 | prior written permission.
51 |
52 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
53 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
54 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
55 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
56 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
57 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
58 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
59 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
60 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
61 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
62 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63 | */
64 |
65 |
66 | // clang-format off
67 | layout(set = 0, binding = 0) uniform sampler2D iChannel0; // Normal + depth
68 | // clang-format on
69 |
70 | layout(location = 0) in vec2 fragCoord;
71 | layout(location = 0) out vec4 fragColor;
72 |
73 |
74 | #ifndef FXAA_REDUCE_MIN
75 | #define FXAA_REDUCE_MIN (1.0 / 128.0)
76 | #endif
77 | #ifndef FXAA_REDUCE_MUL
78 | #define FXAA_REDUCE_MUL (1.0 / 8.0)
79 | #endif
80 | #ifndef FXAA_SPAN_MAX
81 | #define FXAA_SPAN_MAX 8.0
82 | #endif
83 |
84 | // optimized version for mobile, where dependent
85 | // texture reads can be a bottleneck
86 | vec4 fxaa(sampler2D tex,
87 | vec2 fragCoord,
88 | vec2 resolution, //
89 | vec2 v_rgbNW,
90 | vec2 v_rgbNE,
91 | vec2 v_rgbSW,
92 | vec2 v_rgbSE,
93 | vec2 v_rgbM)
94 | {
95 | vec4 color;
96 | vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y);
97 | vec3 rgbNW = texture(tex, v_rgbNW).xyz;
98 | vec3 rgbNE = texture(tex, v_rgbNE).xyz;
99 | vec3 rgbSW = texture(tex, v_rgbSW).xyz;
100 | vec3 rgbSE = texture(tex, v_rgbSE).xyz;
101 | vec4 texColor = texture(tex, v_rgbM);
102 | vec3 rgbM = texColor.xyz;
103 | vec3 luma = vec3(0.299, 0.587, 0.114);
104 | float lumaNW = dot(rgbNW, luma);
105 | float lumaNE = dot(rgbNE, luma);
106 | float lumaSW = dot(rgbSW, luma);
107 | float lumaSE = dot(rgbSE, luma);
108 | float lumaM = dot(rgbM, luma);
109 | float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
110 | float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
111 |
112 | vec2 dir;
113 | dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
114 | dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
115 |
116 | float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);
117 |
118 | float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
119 | dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir * rcpDirMin)) * inverseVP;
120 |
121 | vec3 rgbA = 0.5
122 | * (texture(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz
123 | + texture(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);
124 | vec3 rgbB =
125 | rgbA * 0.5
126 | + 0.25 * (texture(tex, fragCoord * inverseVP + dir * -0.5).xyz + texture(tex, fragCoord * inverseVP + dir * 0.5).xyz);
127 |
128 | float lumaB = dot(rgbB, luma);
129 | if((lumaB < lumaMin) || (lumaB > lumaMax))
130 | color = vec4(rgbA, texColor.a);
131 | else
132 | color = vec4(rgbB, texColor.a);
133 | return color;
134 | }
135 |
136 | void main()
137 | {
138 | vec2 resolution = vec2(textureSize(iChannel0, 0));
139 | vec2 fragCoord = gl_FragCoord.xy;
140 |
141 | vec2 inverseVP = 1.0 / resolution.xy;
142 | vec2 v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP;
143 | vec2 v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP;
144 | vec2 v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP;
145 | vec2 v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP;
146 | vec2 v_rgbM = vec2(fragCoord * inverseVP);
147 |
148 |
149 | vec4 result = fxaa(iChannel0, fragCoord, resolution, //
150 | v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);
151 |
152 | fragColor = result;
153 | }
154 |
--------------------------------------------------------------------------------
/shaders/gltf.glsl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | //--------------------------------
21 | // glTF material representation
22 |
23 | #ifdef __cplusplus
24 | // GLSL Type
25 | using vec4 = glm::vec4;
26 | #endif
27 |
28 | struct GltfShadeMaterial
29 | {
30 | vec4 pbrBaseColorFactor;
31 | int pbrBaseColorTexture;
32 | };
33 |
--------------------------------------------------------------------------------
/shaders/kuwa_aniso.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | // by Jan Eric Kyprianidis
21 | // https://github.com/MzHub/gpuakf
22 |
23 | #version 450
24 |
25 | // clang-format off
26 | layout(set = 0, binding = 0) uniform sampler2D src;
27 | layout(set = 0, binding = 1) uniform sampler2D K0;
28 | layout(set = 0, binding = 2) uniform sampler2D tfm;
29 | // clang-format on
30 |
31 | layout(push_constant) uniform params_
32 | {
33 | float radius;
34 | float q;
35 | float alpha;
36 | };
37 |
38 |
39 | layout(location = 0) in vec2 fragCoord;
40 | layout(location = 0) out vec4 fragColor;
41 |
42 |
43 | const float PI = 3.14159265358979323846;
44 | const int N = 8;
45 |
46 | void main(void)
47 | {
48 | vec2 src_size = vec2(textureSize(src, 0));
49 | vec2 uv = gl_FragCoord.xy / src_size;
50 |
51 | vec4 m[8];
52 | vec3 s[8];
53 | for(int k = 0; k < N; ++k)
54 | {
55 | m[k] = vec4(0.0);
56 | s[k] = vec3(0.0);
57 | }
58 |
59 | float piN = 2.0 * PI / float(N);
60 | mat2 X = mat2(cos(piN), sin(piN), -sin(piN), cos(piN));
61 |
62 | vec4 t = texture(tfm, uv);
63 | float a = radius * clamp((alpha + t.w) / alpha, 0.1, 2.0);
64 | float b = radius * clamp(alpha / (alpha + t.w), 0.1, 2.0);
65 |
66 | float cos_phi = cos(t.z);
67 | float sin_phi = sin(t.z);
68 |
69 | mat2 R = mat2(cos_phi, -sin_phi, sin_phi, cos_phi);
70 | mat2 S = mat2(0.5 / a, 0.0, 0.0, 0.5 / b);
71 | mat2 SR = S * R;
72 |
73 | int max_x = int(sqrt(a * a * cos_phi * cos_phi + b * b * sin_phi * sin_phi));
74 | int max_y = int(sqrt(a * a * sin_phi * sin_phi + b * b * cos_phi * cos_phi));
75 |
76 | for(int j = -max_y; j <= max_y; ++j)
77 | {
78 | for(int i = -max_x; i <= max_x; ++i)
79 | {
80 | vec2 v = SR * vec2(i, j);
81 | if(dot(v, v) <= 0.25)
82 | {
83 | vec4 c_fix = texture(src, uv + vec2(i, j) / src_size);
84 | vec3 c = c_fix.rgb;
85 | for(int k = 0; k < N; ++k)
86 | {
87 | float w = texture(K0, vec2(0.5, 0.5) + v).x;
88 |
89 | m[k] += vec4(c * w, w);
90 | s[k] += c * c * w;
91 |
92 | v *= X;
93 | }
94 | }
95 | }
96 | }
97 |
98 | vec4 o = vec4(0.0);
99 | for(int k = 0; k < N; ++k)
100 | {
101 | m[k].rgb /= m[k].w;
102 | s[k] = abs(s[k] / m[k].w - m[k].rgb * m[k].rgb);
103 |
104 | float sigma2 = s[k].r + s[k].g + s[k].b;
105 | float w = 1.0 / (1.0 + pow(255.0 * sigma2, 0.5 * q));
106 |
107 | o += vec4(m[k].rgb * w, w);
108 | }
109 |
110 | float alpha = texture(src, uv).a;
111 | fragColor = vec4(o.rgb / o.w, alpha);
112 | }
113 |
--------------------------------------------------------------------------------
/shaders/kuwa_gauss.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | // by Jan Eric Kyprianidis
21 |
22 | #version 450
23 |
24 | layout(set = 0, binding = 0) uniform sampler2D src;
25 | //layout(push_constant) uniform params_
26 | //{
27 | // float sigma;
28 | //};
29 |
30 | layout(location = 0) out vec4 dst;
31 | layout(location = 0) in vec2 fragCoord;
32 |
33 | const float sigma = 2.;
34 |
35 | void main(void)
36 | {
37 | vec2 src_size = vec2(textureSize(src, 0));
38 | vec2 uv = gl_FragCoord.xy / src_size;
39 | float twoSigma2 = 2.0 * sigma * sigma;
40 | int halfWidth = int(ceil(2.0 * sigma));
41 |
42 | vec3 sum = vec3(0.0);
43 | float norm = 0.0;
44 | if(halfWidth > 0)
45 | {
46 | for(int i = -halfWidth; i <= halfWidth; ++i)
47 | {
48 | for(int j = -halfWidth; j <= halfWidth; ++j)
49 | {
50 | float d = length(vec2(i, j));
51 | float kernel = exp(-d * d / twoSigma2);
52 | vec3 c = texture(src, uv + vec2(i, j) / src_size).rgb;
53 | sum += kernel * c;
54 | norm += kernel;
55 | }
56 | }
57 | }
58 | else
59 | {
60 | sum = texture(src, uv).rgb;
61 | norm = 1.0;
62 | }
63 | dst = vec4(sum / norm, 0);
64 | }
65 |
--------------------------------------------------------------------------------
/shaders/kuwa_sst.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | // by Jan Eric Kyprianidis
21 | #version 450
22 |
23 | layout(set = 0, binding = 0) uniform sampler2D src;
24 | layout(location = 0) out vec4 fragColor;
25 | layout(location = 0) in vec2 fragCoord;
26 |
27 |
28 | void main(void)
29 | {
30 | vec2 src_size = vec2(textureSize(src, 0));
31 | vec2 uv = gl_FragCoord.xy / src_size;
32 | vec2 d = 1.0 / src_size;
33 |
34 | vec3 c = texture(src, uv).xyz;
35 | vec3 u = (-1.0 * texture(src, uv + vec2(-d.x, -d.y)).xyz + -2.0 * texture(src, uv + vec2(-d.x, 0.0)).xyz
36 | + -1.0 * texture(src, uv + vec2(-d.x, d.y)).xyz + +1.0 * texture(src, uv + vec2(d.x, -d.y)).xyz
37 | + +2.0 * texture(src, uv + vec2(d.x, 0.0)).xyz + +1.0 * texture(src, uv + vec2(d.x, d.y)).xyz)
38 | / 4.0;
39 |
40 | vec3 v = (-1.0 * texture(src, uv + vec2(-d.x, -d.y)).xyz + -2.0 * texture(src, uv + vec2(0.0, -d.y)).xyz
41 | + -1.0 * texture(src, uv + vec2(d.x, -d.y)).xyz + +1.0 * texture(src, uv + vec2(-d.x, d.y)).xyz
42 | + +2.0 * texture(src, uv + vec2(0.0, d.y)).xyz + +1.0 * texture(src, uv + vec2(d.x, d.y)).xyz)
43 | / 4.0;
44 |
45 | fragColor = vec4(dot(u, u), dot(v, v), dot(u, v), 1.0);
46 | }
47 |
--------------------------------------------------------------------------------
/shaders/kuwa_tfm.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | // by Jan Eric Kyprianidis
21 | #version 450
22 |
23 | layout(set = 0, binding = 0) uniform sampler2D src;
24 | layout(location = 0) out vec4 fragColor;
25 | layout(location = 0) in vec2 fragCoord;
26 |
27 | void main(void)
28 | {
29 | vec2 uv = gl_FragCoord.xy / vec2(textureSize(src, 0));
30 | vec3 g = texture(src, uv).xyz;
31 |
32 | float lambda1 = 0.5 * (g.y + g.x + sqrt(g.y * g.y - 2.0 * g.x * g.y + g.x * g.x + 4.0 * g.z * g.z));
33 | float lambda2 = 0.5 * (g.y + g.x - sqrt(g.y * g.y - 2.0 * g.x * g.y + g.x * g.x + 4.0 * g.z * g.z));
34 |
35 | vec2 v = vec2(lambda1 - g.x, -g.z);
36 | vec2 t;
37 | if(length(v) > 0.0)
38 | {
39 | t = normalize(v);
40 | }
41 | else
42 | {
43 | t = vec2(0.0, 1.0);
44 | }
45 |
46 | float phi = atan(t.y, t.x);
47 |
48 | float A = (lambda1 + lambda2 > 0.0) ? (lambda1 - lambda2) / (lambda1 + lambda2) : 0.0;
49 |
50 | fragColor = vec4(t, phi, A);
51 | }
52 |
--------------------------------------------------------------------------------
/shaders/kuwahara.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | // by Jan Eric Kyprianidis
21 |
22 | #version 450
23 |
24 | // clang-format off
25 | layout(set = 0, binding = 0) uniform sampler2D iChannel0; // Normal + depth
26 | layout(push_constant) uniform params_ {int radius;};
27 | // clang-format on
28 |
29 | layout(location = 0) in vec2 fragCoord;
30 | layout(location = 0) out vec4 fragColor;
31 |
32 |
33 | void main(void)
34 | {
35 | vec2 src_size = vec2(textureSize(iChannel0, 0));
36 | vec2 uv = gl_FragCoord.xy / src_size;
37 | float n = float((radius + 1) * (radius + 1));
38 |
39 | float alpha = texture(iChannel0, uv).a;
40 |
41 | vec3 m[4];
42 | vec3 s[4];
43 | for(int k = 0; k < 4; ++k)
44 | {
45 | m[k] = vec3(0.0);
46 | s[k] = vec3(0.0);
47 | }
48 |
49 | for(int j = -radius; j <= 0; ++j)
50 | {
51 | for(int i = -radius; i <= 0; ++i)
52 | {
53 | vec3 c = texture(iChannel0, uv + vec2(i, j) / src_size).rgb;
54 | m[0] += c;
55 | s[0] += c * c;
56 | }
57 | }
58 |
59 | for(int j = -radius; j <= 0; ++j)
60 | {
61 | for(int i = 0; i <= radius; ++i)
62 | {
63 | vec3 c = texture(iChannel0, uv + vec2(i, j) / src_size).rgb;
64 | m[1] += c;
65 | s[1] += c * c;
66 | }
67 | }
68 |
69 | for(int j = 0; j <= radius; ++j)
70 | {
71 | for(int i = 0; i <= radius; ++i)
72 | {
73 | vec3 c = texture(iChannel0, uv + vec2(i, j) / src_size).rgb;
74 | m[2] += c;
75 | s[2] += c * c;
76 | }
77 | }
78 |
79 | for(int j = 0; j <= radius; ++j)
80 | {
81 | for(int i = -radius; i <= 0; ++i)
82 | {
83 | vec3 c = texture(iChannel0, uv + vec2(i, j) / src_size).rgb;
84 | m[3] += c;
85 | s[3] += c * c;
86 | }
87 | }
88 |
89 |
90 | float min_sigma2 = 1e+2;
91 | for(int k = 0; k < 4; ++k)
92 | {
93 | m[k] /= n;
94 | s[k] = abs(s[k] / n - m[k] * m[k]);
95 |
96 | float sigma2 = s[k].r + s[k].g + s[k].b;
97 | if(sigma2 < min_sigma2)
98 | {
99 | min_sigma2 = sigma2;
100 | fragColor = vec4(m[k], alpha);
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/shaders/passthrough.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 450
21 | layout(location = 0) out vec2 outUV;
22 |
23 |
24 | out gl_PerVertex
25 | {
26 | vec4 gl_Position;
27 | };
28 |
29 |
30 | void main()
31 | {
32 | outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
33 | gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f);
34 | }
35 |
--------------------------------------------------------------------------------
/shaders/pick.rchit:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 460
21 | #extension GL_NV_ray_tracing : require
22 | #extension GL_GOOGLE_include_directive : enable
23 |
24 | #include "share.glsl"
25 |
26 | // Payload information of the ray returning: 0 hit, 2 shadow
27 | layout(location = 0) rayPayloadInNV PerRayData_pick prd;
28 |
29 | // Raytracing hit attributes: barycentrics
30 | hitAttributeNV vec2 attribs;
31 |
32 | void main()
33 | {
34 | prd.worldPos = vec4(gl_WorldRayOriginNV + gl_WorldRayDirectionNV * gl_HitTNV, 0);
35 | prd.barycentrics = vec4(1.0 - attribs.x - attribs.y, attribs.x, attribs.y, 0);
36 | prd.instanceID = gl_InstanceID;
37 | prd.instanceCustomID = gl_InstanceCustomIndexNV;
38 | prd.primitiveID = gl_PrimitiveID;
39 | }
40 |
--------------------------------------------------------------------------------
/shaders/pick.rgen:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 460
21 | #extension GL_NV_ray_tracing : require
22 | #extension GL_GOOGLE_include_directive : enable
23 |
24 | //-------------------------------------------------------------------------------------------------
25 | // Default raygen for picking objects in the scene
26 | // -
27 | //-------------------------------------------------------------------------------------------------
28 |
29 |
30 | #include "share.glsl"
31 |
32 | layout(binding = 0, set = 0) uniform accelerationStructureNV topLevelAS;
33 | layout(binding = 1, set = 0) buffer _resultPick
34 | {
35 | PerRayData_pick resultPick;
36 | };
37 | layout(binding = 2, set = 0) uniform UBOscene
38 | {
39 | Scene s;
40 | }
41 | ubo;
42 |
43 | layout(push_constant) uniform Constants
44 | {
45 | float pickX;
46 | float pickY;
47 | };
48 |
49 | layout(location = 0) rayPayloadNV PerRayData_pick prd;
50 |
51 |
52 | void main()
53 | {
54 | const vec2 pixelCenter = vec2(pickX, pickY);
55 | const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeNV.xy);
56 | vec2 d = inUV * 2.0 - 1.0;
57 |
58 | mat4 viewInverse = inverse(ubo.s.modelView);
59 | mat4 projInverse = inverse(ubo.s.projection);
60 | vec4 origin = viewInverse * vec4(0, 0, 0, 1);
61 | vec4 target = projInverse * vec4(d.x, d.y, 1, 1);
62 | vec4 direction = viewInverse * vec4(normalize(target.xyz), 0);
63 | uint rayFlags = gl_RayFlagsOpaqueNV;
64 | uint cullMask = 0xff;
65 | float tmin = 0.001;
66 | float tmax = 10000.0;
67 |
68 | prd.worldPos = vec4(0.f);
69 | prd.barycentrics = vec4(0.f);
70 | prd.instanceID = 0;
71 | prd.primitiveID = 0;
72 |
73 | traceNV(topLevelAS, rayFlags, cullMask, 0 /*sbtRecordOffset*/, 0 /*sbtRecordStride*/, 0 /*missIndex*/, origin.xyz,
74 | tmin, direction.xyz, tmax, 0 /*payload*/);
75 |
76 | resultPick.worldPos = prd.worldPos;
77 | resultPick.barycentrics = prd.barycentrics;
78 | resultPick.instanceID = prd.instanceID;
79 | resultPick.primitiveID = prd.primitiveID;
80 | }
81 |
--------------------------------------------------------------------------------
/shaders/pick.rmiss:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 460
21 | #extension GL_NV_ray_tracing : require
22 | #extension GL_GOOGLE_include_directive : enable
23 |
24 | //-------------------------------------------------------------------------------------------------
25 | // Default miss for picking. Return non-valid object ID
26 | //-------------------------------------------------------------------------------------------------
27 |
28 | #include "share.glsl"
29 | layout(location = 0) rayPayloadInNV PerRayData_pick prd;
30 |
31 | void main()
32 | {
33 | prd.instanceID = ~0;
34 | }
35 |
--------------------------------------------------------------------------------
/shaders/rasterizer.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 450
21 | #extension GL_ARB_separate_shader_objects : enable
22 | #extension GL_GOOGLE_include_directive : enable
23 | #extension GL_EXT_nonuniform_qualifier : enable
24 | #extension GL_EXT_scalar_block_layout : enable
25 |
26 | #include "binding.glsl"
27 | #include "share.glsl"
28 |
29 | // clang-format off
30 | layout(set = 0, binding = B_SCENE) uniform _Scene {Scene sceneInfo; };
31 | layout(set = 0, binding = B_MATERIAL, scalar) readonly buffer _Material {GltfShadeMaterial materials[];};
32 | layout(set = 0, binding = B_TEXTURES) uniform sampler2D texturesMap[]; // all textures
33 | // clang-format on
34 |
35 | layout(push_constant) uniform _Push
36 | {
37 | vec3 c_lightDir;
38 | int c_nbSteps;
39 | int c_instID;
40 | int c_matID;
41 | };
42 |
43 | // Incoming
44 | layout(location = 0) in vec3 in_worldPos;
45 | layout(location = 1) in vec3 in_normal;
46 | layout(location = 2) in vec2 in_texcoord0;
47 |
48 | // Outgoing
49 | layout(location = 0) out vec4 out_color;
50 | layout(location = 1) out vec4 out_bufferEncoded; // xy: normal, z, object ID
51 |
52 |
53 | // Debug utility
54 | vec3 integerToColor(int val)
55 | {
56 | const vec3 freq = vec3(1.33333f, 2.33333f, 3.33333f);
57 | return vec3(sin(freq * val) * .5 + .5);
58 | }
59 |
60 | void main()
61 | {
62 | // Retrieve the material on this hit
63 | GltfShadeMaterial material = materials[c_matID];
64 |
65 | // Albedo
66 | vec3 baseColor = material.pbrBaseColorFactor.rgb;
67 | if(material.pbrBaseColorTexture > -1)
68 | baseColor *= texture(texturesMap[nonuniformEXT(material.pbrBaseColorTexture)], in_texcoord0).rgb;
69 |
70 | // Color Result
71 | vec3 toLight = normalize(-c_lightDir);
72 | float intensity = toonShading(toLight, in_normal, c_nbSteps);
73 |
74 | out_color.xyz = max(0.1f, intensity) * baseColor.xyz; // keeping ambient
75 | out_color.a = 1;
76 |
77 | // Encoding data buffer
78 | vec2 encodedNormal = encode(normalize(in_normal));
79 | float depth = length(in_worldPos - sceneInfo.camPos.xyz);
80 | float fInstanceID = intBitsToFloat(c_instID + 1);
81 | out_bufferEncoded = vec4(encodedNormal, depth, fInstanceID);
82 | }
83 |
--------------------------------------------------------------------------------
/shaders/rasterizer.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 450
21 | #extension GL_ARB_separate_shader_objects : enable
22 | #extension GL_GOOGLE_include_directive : enable
23 | #extension GL_EXT_nonuniform_qualifier : enable
24 | #extension GL_EXT_scalar_block_layout : enable
25 |
26 | #include "binding.glsl"
27 | #include "share.glsl"
28 |
29 | // clang-format off
30 | layout(set = 0, binding = B_SCENE) uniform _Scene {Scene sceneInfo; } ;
31 | layout(set = 0, binding = B_MATRIX) readonly buffer _Matrix {InstancesMatrices matrices[]; };
32 | // clang-format on
33 |
34 | layout(push_constant) uniform _Push
35 | {
36 | vec3 c_lightDir;
37 | int c_nbSteps;
38 | int c_instID;
39 | int c_matID;
40 | };
41 |
42 |
43 | // Input
44 | layout(location = 0) in vec3 in_pos;
45 | layout(location = 1) in vec3 in_normal;
46 | layout(location = 2) in vec2 in_texcoord0;
47 |
48 |
49 | // Output
50 | layout(location = 0) out vec3 out_worldPos;
51 | layout(location = 1) out vec3 out_normal;
52 | layout(location = 2) out vec2 out_texcoord0;
53 |
54 |
55 | out gl_PerVertex
56 | {
57 | vec4 gl_Position;
58 | };
59 |
60 |
61 | void main()
62 | {
63 | vec4 worldPos = matrices[c_instID].world * vec4(in_pos, 1.0);
64 |
65 | out_normal = vec3(matrices[c_instID].worldIT * vec4(in_normal, 0.0));
66 | out_worldPos = worldPos.xyz;
67 | out_texcoord0 = in_texcoord0;
68 |
69 | gl_Position = sceneInfo.projection * sceneInfo.modelView * worldPos;
70 | }
71 |
--------------------------------------------------------------------------------
/shaders/raytrace.rchit:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 460
21 | #extension GL_NV_ray_tracing : require
22 | #extension GL_GOOGLE_include_directive : enable
23 | #extension GL_EXT_nonuniform_qualifier : enable
24 | #extension GL_EXT_scalar_block_layout : enable
25 |
26 | #include "binding.glsl"
27 | #include "share.glsl"
28 |
29 |
30 | layout(location = 0) rayPayloadInNV PerRayData_raytrace prd; // incoming from raygen
31 | layout(location = 1) rayPayloadNV bool payload_isHit; // shadow
32 |
33 | layout(push_constant) uniform _Push
34 | {
35 | vec3 c_backgroundColor;
36 | int c_frame; // Current frame
37 | vec3 c_lightDir;
38 | float c_maxRayLenght; // Trace depth
39 | int c_samples; // Number of samples per pixel
40 | int c_nbSteps;
41 | };
42 |
43 |
44 | // Raytracing hit attributes: barycentrics
45 | hitAttributeNV vec2 attribs;
46 |
47 | // clang-format off
48 | layout(set = 0, binding = 0) uniform accelerationStructureNV topLevelAS;
49 | layout(set = 0, binding = 2) readonly buffer _InstanceInfo {PrimMeshInfo primInfo[];};
50 |
51 | layout(set = 1, binding = B_VERTICES) readonly buffer _VertexBuf {float vertices[];};
52 | layout(set = 1, binding = B_INDICES) readonly buffer _Indices {uint indices[];};
53 | layout(set = 1, binding = B_NORMALS) readonly buffer _NormalBuf {float normals[];};
54 | layout(set = 1, binding = B_TEXCOORDS) readonly buffer _TexCoordBuf {float texcoord0[];};
55 | layout(set = 1, binding = B_MATERIAL, scalar) readonly buffer _MaterialBuffer {GltfShadeMaterial materials[];};
56 | layout(set = 1, binding = B_TEXTURES) uniform sampler2D texturesMap[]; // all textures
57 | // clang-format on
58 |
59 |
60 | // Return the vertex position
61 | vec3 getVertex(uint index)
62 | {
63 | vec3 vp;
64 | vp.x = vertices[3 * index + 0];
65 | vp.y = vertices[3 * index + 1];
66 | vp.z = vertices[3 * index + 2];
67 | return vp;
68 | }
69 |
70 | vec3 getNormal(uint index)
71 | {
72 | vec3 vp;
73 | vp.x = normals[3 * index + 0];
74 | vp.y = normals[3 * index + 1];
75 | vp.z = normals[3 * index + 2];
76 | return vp;
77 | }
78 |
79 | vec2 getTexCoord(uint index)
80 | {
81 | vec2 vp;
82 | vp.x = texcoord0[2 * index + 0];
83 | vp.y = texcoord0[2 * index + 1];
84 | return vp;
85 | }
86 |
87 | // Structure of what a vertex is
88 | struct ShadingState
89 | {
90 | vec3 pos;
91 | vec3 normal;
92 | vec3 geom_normal;
93 | vec2 texcoord0;
94 | uint matIndex;
95 | };
96 |
97 | //--------------------------------------------------------------
98 | // Getting the interpolated vertex
99 | // gl_InstanceID gives the Instance Info
100 | // gl_PrimitiveID gives the triangle for this instance
101 | //
102 | ShadingState getShadingState()
103 | {
104 | // Retrieve the Primitive mesh buffer information
105 | PrimMeshInfo pinfo = primInfo[gl_InstanceCustomIndexNV];
106 |
107 | // Getting the 'first index' for this mesh (offset of the mesh + offset of the triangle)
108 | uint indexOffset = pinfo.indexOffset + (3 * gl_PrimitiveID);
109 | uint vertexOffset = pinfo.vertexOffset; // Vertex offset as defined in glTF
110 | uint matIndex = max(0, pinfo.materialIndex); // material of primitive mesh
111 |
112 | // Getting the 3 indices of the triangle (local)
113 | ivec3 triangleIndex = ivec3(indices[indexOffset + 0], indices[indexOffset + 1], indices[indexOffset + 2]);
114 | triangleIndex += ivec3(vertexOffset); // (global)
115 |
116 | const vec3 barycentric = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);
117 |
118 | // Position
119 | const vec3 pos0 = getVertex(triangleIndex.x);
120 | const vec3 pos1 = getVertex(triangleIndex.y);
121 | const vec3 pos2 = getVertex(triangleIndex.z);
122 | const vec3 position = pos0 * barycentric.x + pos1 * barycentric.y + pos2 * barycentric.z;
123 | const vec3 world_position = vec3(gl_ObjectToWorldNV * vec4(position, 1.0));
124 |
125 | // Normal
126 | const vec3 nrm0 = getNormal(triangleIndex.x);
127 | const vec3 nrm1 = getNormal(triangleIndex.y);
128 | const vec3 nrm2 = getNormal(triangleIndex.z);
129 | vec3 normal = normalize(nrm0 * barycentric.x + nrm1 * barycentric.y + nrm2 * barycentric.z);
130 | const vec3 world_normal = normalize(vec3(normal * gl_WorldToObjectNV));
131 | const vec3 geom_normal = normalize(cross(pos1 - pos0, pos2 - pos0));
132 |
133 | // Move normal to same side as geometric normal
134 | if(dot(normal, geom_normal) <= 0)
135 | {
136 | normal *= -1.0f;
137 | }
138 |
139 | // Texture coord
140 | const vec2 uv0 = getTexCoord(triangleIndex.x);
141 | const vec2 uv1 = getTexCoord(triangleIndex.y);
142 | const vec2 uv2 = getTexCoord(triangleIndex.z);
143 | const vec2 texcoord0 = uv0 * barycentric.x + uv1 * barycentric.y + uv2 * barycentric.z;
144 |
145 | // Final shading state
146 | ShadingState state;
147 | state.pos = world_position;
148 | state.normal = world_normal;
149 | state.geom_normal = geom_normal;
150 | state.texcoord0 = texcoord0;
151 | state.matIndex = matIndex;
152 |
153 | return state;
154 | }
155 |
156 |
157 | void main()
158 | {
159 | // Get the shading information
160 | ShadingState state = getShadingState(); //ind, vertexOffset, barycentrics);
161 |
162 | // cast a shadow ray; assuming light is always outside
163 | vec3 origin = state.pos;
164 | vec3 toLight = normalize(-c_lightDir);
165 |
166 | payload_isHit = true; // Assuming the ray has hit something
167 | uint rayFlags = gl_RayFlagsTerminateOnFirstHitNV | gl_RayFlagsSkipClosestHitShaderNV;
168 | traceNV(topLevelAS, // acceleration structure
169 | rayFlags, // rayFlags
170 | 0xFF, // cullMask
171 | 0, // sbtRecordOffset
172 | 0, // sbtRecordStride
173 | 1, // missIndex
174 | origin, // ray origin
175 | 0.01, // ray min range
176 | toLight, // ray direction
177 | c_maxRayLenght, // ray max range
178 | 1 // payload layout(location = 1)
179 | );
180 |
181 | // Retrieve the material on this hit
182 | GltfShadeMaterial material = materials[state.matIndex];
183 |
184 | // The albedo may be defined from a base texture or a flat color
185 | vec3 baseColor = material.pbrBaseColorFactor.rgb;
186 | if(material.pbrBaseColorTexture > -1)
187 | baseColor *= texture(texturesMap[nonuniformEXT(material.pbrBaseColorTexture)], state.texcoord0).rgb;
188 |
189 | // If isHit is ture, means the ray hit an object, therefore cannot see the light and it is under shadow
190 | float intensity;
191 | if(payload_isHit)
192 | intensity = 0.0f;
193 | else
194 | intensity = toonShading(toLight, state.normal, c_nbSteps);
195 |
196 | // Result color
197 | prd.result.xyz = max(0.1f, intensity) * baseColor.xyz; // keeping ambient
198 | prd.result.a = 1;
199 |
200 | // Result data
201 | prd.normal = state.normal;
202 | prd.depth = gl_HitTNV;
203 | prd.objId = gl_InstanceID + 1;
204 | }
205 |
--------------------------------------------------------------------------------
/shaders/raytrace.rgen:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 460
21 | #extension GL_NV_ray_tracing : require
22 | #extension GL_GOOGLE_include_directive : enable
23 |
24 | //-------------------------------------------------------------------------------------------------
25 | // Default ray generation
26 | // - Will sample the pixel n-number of time: samples
27 | // - Will jitter the camera in sub-pixel to do anitaliasing
28 | //-------------------------------------------------------------------------------------------------
29 |
30 |
31 | #include "binding.glsl"
32 | #include "share.glsl"
33 |
34 | // clang-format off
35 | layout(set = 0, binding = 0) uniform accelerationStructureNV topLevelAS; // Scene BVH
36 | layout(set = 0, binding = 1, rgba32f) uniform image2D image[]; // In/Out rendering images 0: color, 1: data
37 |
38 | layout(set = 1, binding = B_SCENE) uniform _Scene {Scene sceneInfo;};
39 | // clang-format on
40 |
41 | //------------------------------------
42 | // Push constant from the application
43 | //------------------------------------
44 | layout(push_constant) uniform Constants
45 | {
46 | vec3 c_backgroundColor;
47 | int c_frame; // Current frame
48 | vec3 c_lightDir;
49 | float c_maxRayLenght; // Trace depth
50 | int c_samples; // Number of samples per pixel
51 | int c_nbSteps;
52 | };
53 |
54 | // Payload
55 | layout(location = 0) rayPayloadNV PerRayData_raytrace prd;
56 |
57 |
58 | //-------------------------------
59 | // Ray generation
60 | //-------------------------------
61 | void main()
62 | {
63 | vec4 hitValue = vec4(0);
64 | vec4 bufferEncoded = vec4(0); // xy: normal, z, object ID, w, depth
65 |
66 | for(int smpl = 0; smpl < c_samples; ++smpl)
67 | {
68 | // Initialize the random number
69 | uint seed = tea(gl_LaunchIDNV.y * gl_LaunchSizeNV.x + gl_LaunchIDNV.x, c_frame * c_samples + smpl);
70 | float r1 = rnd(seed);
71 | float r2 = rnd(seed);
72 |
73 | bool first_frame = c_frame == 0 && smpl == 0;
74 |
75 | // Subpixel jitter: send the ray through a different position inside the pixel each time, to provide antialiasing.
76 | vec2 subpixel_jitter = first_frame ? vec2(0.5f, 0.5f) : vec2(r1, r2);
77 |
78 | const vec2 pixelCenter = vec2(gl_LaunchIDNV.xy) + subpixel_jitter;
79 |
80 | const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeNV.xy);
81 | vec2 d = inUV * 2.0 - 1.0;
82 |
83 | // Initialize ray information
84 | mat4 viewInverse = inverse(sceneInfo.modelView);
85 | mat4 projInverse = inverse(sceneInfo.projection);
86 | vec4 origin = viewInverse * vec4(0, 0, 0, 1);
87 | vec4 target = projInverse * vec4(d.x, d.y, 1, 1);
88 | vec4 direction = viewInverse * vec4(normalize(target.xyz), 0);
89 | float Tmin = 0.001;
90 | float Tmax = 100000.0;
91 |
92 | // Payload
93 | prd.result = vec4(0.f);
94 | prd.importance = vec3(1.f);
95 | prd.seed = seed;
96 | prd.rayDepth = 0;
97 | prd.roughness = 0;
98 | prd.normal = vec3(0.f);
99 | prd.depth = -1;
100 | prd.objId = 0;
101 |
102 | traceNV(topLevelAS, // acceleration structure
103 | gl_RayFlagsNoneNV, // rayFlags
104 | 0xFF, // cullMask
105 | 0, // sbtRecordOffset
106 | 0, // sbtRecordStride
107 | 0, // missIndex
108 | origin.xyz, // ray origin
109 | Tmin, // ray min range
110 | direction.xyz, // ray direction
111 | Tmax, // ray max range
112 | 0 // payload layout(location = 0)
113 | );
114 |
115 | // Accumulating the result for this sample
116 | hitValue += prd.result;
117 |
118 | vec2 n = encode(prd.normal);
119 | bufferEncoded = vec4(n, prd.depth, intBitsToFloat(prd.objId));
120 | }
121 |
122 | // Average result
123 | hitValue = hitValue / c_samples;
124 |
125 | // Do accumulation over time
126 | if(c_frame > 0)
127 | {
128 | float a = 1.0f / float(c_frame);
129 | vec3 old_color = imageLoad(image[0], ivec2(gl_LaunchIDNV.xy)).xyz;
130 | imageStore(image[0], ivec2(gl_LaunchIDNV.xy), vec4(mix(old_color, hitValue.xyz, a), hitValue.a));
131 | }
132 | else
133 | {
134 | // First frame, replace value in the buffer
135 | imageStore(image[0], ivec2(gl_LaunchIDNV.xy), hitValue);
136 | imageStore(image[1], ivec2(gl_LaunchIDNV.xy), bufferEncoded);
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/shaders/raytrace.rmiss:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 460
21 | #extension GL_NV_ray_tracing : require
22 | #extension GL_GOOGLE_include_directive : enable
23 |
24 | //-------------------------------------------------------------------------------------------------
25 | // Default miss shader for the raytracer
26 | // - Return the background color
27 | //-------------------------------------------------------------------------------------------------
28 |
29 | #include "binding.glsl"
30 | #include "share.glsl"
31 |
32 | layout(location = 0) rayPayloadInNV PerRayData_raytrace payload;
33 |
34 | layout(push_constant) uniform _Push
35 | {
36 | vec3 c_backgroundColor; // Miss color
37 | int c_frame; // Current frame
38 | vec3 c_lightDir; //
39 | float c_maxRayLenght; // Trace depth
40 | int c_samples; // Number of samples per pixel
41 | int c_nbSteps; // Toon shading steps
42 | };
43 |
44 | void main()
45 | {
46 | payload.result = vec4(c_backgroundColor, 0);
47 | payload.depth = -1; // Will stop rendering
48 | }
49 |
--------------------------------------------------------------------------------
/shaders/raytraceShadow.rmiss:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 460
21 | #extension GL_NV_ray_tracing : require
22 |
23 | layout(location = 1) rayPayloadInNV bool payload_isHit;
24 |
25 | //-------------------------------------------------------------------------------------------------
26 | // This will be executed when sending shadow rays and missing all geometries
27 | // - There are no hit shader for the shadow ray, therefore
28 | // - Before calling Trace, set payload_isHit=true
29 | // - The default anyhit, closesthit won't change isShadowed, but if nothing is hit, it will be
30 | // set to false.
31 | //-------------------------------------------------------------------------------------------------
32 |
33 | void main()
34 | {
35 | payload_isHit = false;
36 | }
37 |
--------------------------------------------------------------------------------
/shaders/share.glsl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #include "gltf.glsl"
21 |
22 | const highp float M_PI = 3.14159265358979323846f; // pi
23 | const highp float M_PI_2 = 1.57079632679489661923f; // pi/2
24 | const highp float M_PI_4 = 0.785398163397448309616; // pi/4
25 | const highp float M_1_PI = 0.318309886183790671538; // 1/pi
26 | const highp float M_2_PI = 0.636619772367581343076; // 2/pi
27 |
28 | //-------------------------------------------------------------------------------------------------
29 | // random number generator based on the Optix SDK
30 | //-------------------------------------------------------------------------------------------------
31 |
32 | uint tea(uint val0, uint val1)
33 | {
34 | uint v0 = val0;
35 | uint v1 = val1;
36 | uint s0 = 0u;
37 |
38 | for(uint n = 0u; n < 16u; n++)
39 | {
40 | s0 += 0x9e3779b9u;
41 | v0 += ((v1 << 4u) + 0xa341316cu) ^ (v1 + s0) ^ ((v1 >> 5u) + 0xc8013ea4u);
42 | v1 += ((v0 << 4u) + 0xad90777du) ^ (v0 + s0) ^ ((v0 >> 5u) + 0x7e95761eu);
43 | }
44 |
45 | return v0;
46 | }
47 |
48 | // Generate random unsigned int in [0, 2^24)
49 | uint lcg(inout uint prev)
50 | {
51 | uint LCG_A = 1664525u;
52 | uint LCG_C = 1013904223u;
53 | prev = (LCG_A * prev + LCG_C);
54 | return prev & 0x00FFFFFF;
55 | }
56 |
57 | uint lcg2(inout uint prev)
58 | {
59 | prev = (prev * 8121 + 28411) % 134456;
60 | return prev;
61 | }
62 |
63 | // Generate random float in [0, 1)
64 | float rnd(inout uint prev)
65 | {
66 | return (float(lcg(prev)) / float(0x01000000));
67 | }
68 |
69 |
70 | vec2 rnd2(inout uint prev)
71 | {
72 | return vec2(rnd(prev), rnd(prev));
73 | }
74 |
75 |
76 | //-------------------------------------------------------------------------------------------------
77 | // Avoiding self intersections (see Ray Tracing Gems, Ch. 6)
78 | //-------------------------------------------------------------------------------------------------
79 |
80 | vec3 offsetRay(in vec3 p, in vec3 n)
81 | {
82 | const float intScale = 256.0f;
83 | const float floatScale = 1.0f / 65536.0f;
84 | const float origin = 1.0f / 32.0f;
85 |
86 | ivec3 of_i = ivec3(intScale * n.x, intScale * n.y, intScale * n.z);
87 |
88 | vec3 p_i = vec3(intBitsToFloat(floatBitsToInt(p.x) + ((p.x < 0) ? -of_i.x : of_i.x)),
89 | intBitsToFloat(floatBitsToInt(p.y) + ((p.y < 0) ? -of_i.y : of_i.y)),
90 | intBitsToFloat(floatBitsToInt(p.z) + ((p.z < 0) ? -of_i.z : of_i.z)));
91 |
92 | return vec3(abs(p.x) < origin ? p.x + floatScale * n.x : p_i.x, //
93 | abs(p.y) < origin ? p.y + floatScale * n.y : p_i.y, //
94 | abs(p.z) < origin ? p.z + floatScale * n.z : p_i.z);
95 | }
96 |
97 |
98 | //-------------------------------------------------------------------------------------------------
99 | // Toon Shading : apply quatization on lambertian when nbSteps > 0
100 | //-------------------------------------------------------------------------------------------------
101 |
102 | float toonShading(in vec3 L, // Vector to light
103 | in vec3 N, // Normal
104 | in float nbSteps // Quatization steps
105 | )
106 | {
107 | float NdotL = dot(N, L);
108 | if(nbSteps > 0.f)
109 | {
110 | const float inv = 1.f / nbSteps;
111 | NdotL = floor(NdotL * (1.f + inv * 0.5f) * nbSteps) * inv;
112 | }
113 | return NdotL;
114 | }
115 |
116 | //-------------------------------------------------------------------------------------------------
117 | // Ray tracer Payloads
118 | //-------------------------------------------------------------------------------------------------
119 |
120 | // Payload for raytracing
121 | struct PerRayData_raytrace
122 | {
123 | vec4 result;
124 | vec3 importance;
125 | float roughness;
126 | uint seed;
127 | int rayDepth;
128 | vec3 normal;
129 | float depth;
130 | int objId;
131 | };
132 |
133 | // Payload for ray picking
134 | struct PerRayData_pick
135 | {
136 | vec4 worldPos;
137 | vec4 barycentrics;
138 | uint instanceID;
139 | uint instanceCustomID;
140 | uint primitiveID;
141 | };
142 |
143 |
144 | //-------------------------------------------------------------------------------------------------
145 | // Structures in buffers
146 | //-------------------------------------------------------------------------------------------------
147 |
148 | // Primitive Mesh information, use for finding geometry data
149 | struct PrimMeshInfo
150 | {
151 | uint indexOffset;
152 | uint vertexOffset;
153 | int materialIndex;
154 | };
155 |
156 | // Matrices buffer for all instances
157 | struct InstancesMatrices
158 | {
159 | mat4 world;
160 | mat4 worldIT;
161 | };
162 |
163 | // Scene information
164 | struct Scene
165 | {
166 | mat4 projection;
167 | mat4 modelView;
168 | vec4 camPos;
169 | };
170 |
171 |
172 | //-------------------------------------------------------------------------------------------------
173 | // sRGB to linear approximation
174 | // see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
175 | //-------------------------------------------------------------------------------------------------
176 | vec4 SRGBtoLINEAR(vec4 srgbIn, float gamma)
177 | {
178 | return vec4(pow(srgbIn.xyz, vec3(gamma)), srgbIn.w);
179 | }
180 |
181 | //-------------------------------------------------------------------------------------------------
182 | // Normal Encoding: Lambert azimuthal equal-area projection
183 | // see Method #4 https://aras-p.info/texts/CompactNormalStorage.html
184 | //-------------------------------------------------------------------------------------------------
185 | vec2 encode(vec3 n)
186 | {
187 | float p = sqrt(n.z * 8 + 8);
188 | return vec2(n.xy / p + 0.5);
189 | }
190 | // Normal Decoding
191 | vec3 decode(vec2 enc)
192 | {
193 | vec2 fenc = enc * 4 - 2;
194 | float f = dot(fenc, fenc);
195 | float g = sqrt(1 - f / 4);
196 | vec3 n;
197 | n.xy = fenc * g;
198 | n.z = 1 - f / 2;
199 | return n;
200 | }
201 |
--------------------------------------------------------------------------------
/shaders/tonemap.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #version 450
21 | #extension GL_GOOGLE_include_directive : enable
22 |
23 | //----------------------------------------------------------------------------
24 | // Use for tonemapping the incoming image (full screen quad)
25 | //
26 |
27 |
28 | // Tonemapping functions
29 | #include "tonemapping.glsl"
30 |
31 | layout(location = 0) in vec2 outUV;
32 | layout(location = 0) out vec4 fragColor;
33 |
34 | layout(set = 0, binding = 0) uniform sampler2D inImage;
35 |
36 | layout(push_constant) uniform shaderInformation
37 | {
38 | int tonemapper; // tonemapper to use
39 | float gamma; // Default 2.2
40 | float exposure; // Overal exposure
41 | }
42 | pushc;
43 |
44 | void main()
45 | {
46 | vec2 uv = outUV;
47 | vec4 color = texture(inImage, uv);
48 |
49 | fragColor = vec4(toneMap(color.rgb, pushc.tonemapper, pushc.gamma, pushc.exposure), color.a);
50 | }
51 |
--------------------------------------------------------------------------------
/shaders/tonemapping.glsl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #define NO_DEBUG_OUTPUT 0
21 | #define DEBUG_METALLIC 1
22 | #define DEBUG_NORMAL 2
23 | #define DEBUG_BASECOLOR 3
24 | #define DEBUG_OCCLUSION 4
25 | #define DEBUG_EMISSIVE 5
26 | #define DEBUG_UV 6
27 | #define DEBUG_ALPHA 7
28 | #define DEBUG_ROUGHNESS 8
29 |
30 | // Gamma Correction in Computer Graphics
31 | // see https://www.teamten.com/lawrence/graphics/gamma/
32 | vec3 gammaCorrection(vec3 color, float gamma)
33 | {
34 | return pow(color, vec3(1.0 / gamma));
35 | }
36 |
37 | // sRGB to linear approximation
38 | // see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
39 | vec4 SRGBtoLINEAR(vec4 srgbIn, float gamma)
40 | {
41 | return vec4(pow(srgbIn.xyz, vec3(gamma)), srgbIn.w);
42 | }
43 |
44 | // Uncharted 2 tone map
45 | // see: http://filmicworlds.com/blog/filmic-tonemapping-operators/
46 | vec3 toneMapUncharted2Impl(vec3 color)
47 | {
48 | const float A = 0.15;
49 | const float B = 0.50;
50 | const float C = 0.10;
51 | const float D = 0.20;
52 | const float E = 0.02;
53 | const float F = 0.30;
54 | return ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
55 | }
56 |
57 | vec3 toneMapUncharted(vec3 color, float gamma)
58 | {
59 | const float W = 11.2;
60 | const float ExposureBias = 2.0f;
61 | color = toneMapUncharted2Impl(color * ExposureBias);
62 | vec3 whiteScale = 1.0 / toneMapUncharted2Impl(vec3(W));
63 | return gammaCorrection(color * whiteScale, gamma);
64 | }
65 |
66 | // Hejl Richard tone map
67 | // see: http://filmicworlds.com/blog/filmic-tonemapping-operators/
68 | vec3 toneMapHejlRichard(vec3 color)
69 | {
70 | color = max(vec3(0.0), color - vec3(0.004));
71 | return (color * (6.2 * color + .5)) / (color * (6.2 * color + 1.7) + 0.06);
72 | }
73 |
74 | // ACES tone map
75 | // see: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
76 | vec3 toneMapACES(vec3 color, float gamma)
77 | {
78 | const float A = 2.51;
79 | const float B = 0.03;
80 | const float C = 2.43;
81 | const float D = 0.59;
82 | const float E = 0.14;
83 | return gammaCorrection(clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0), gamma);
84 | }
85 |
86 | #define TONEMAP_DEFAULT 0
87 | #define TONEMAP_UNCHARTED 1
88 | #define TONEMAP_HEJLRICHARD 2
89 | #define TONEMAP_ACES 3
90 |
91 | vec3 toneMap(vec3 color, int tonemap, float gamma, float exposure)
92 | {
93 | color *= exposure;
94 |
95 | switch(tonemap)
96 | {
97 | case TONEMAP_UNCHARTED:
98 | return toneMapUncharted(color, gamma);
99 | case TONEMAP_HEJLRICHARD:
100 | return toneMapHejlRichard(color);
101 | case TONEMAP_ACES:
102 | return toneMapACES(color, gamma);
103 | default:
104 | return gammaCorrection(color, gamma);
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/tiny_gltf.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | // Visual Studio warnings
21 | #ifdef _MSC_VER
22 | #pragma warning(disable : 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
23 | #endif
24 |
25 | #define TINYGLTF_IMPLEMENTATION
26 | #define STB_IMAGE_IMPLEMENTATION
27 | #define STB_IMAGE_WRITE_IMPLEMENTATION
28 | #include "tiny_gltf.h"
29 |
--------------------------------------------------------------------------------
/vk_util.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
17 | * SPDX-License-Identifier: Apache-2.0
18 | */
19 |
20 | #pragma once
21 |
22 | #include "nvvk/vulkanhppsupport.hpp"
23 |
24 | // Choosing the allocator to use
25 | // #define ALLOC_DMA
26 | #define ALLOC_DEDICATED
27 | // #define ALLOC_VMA
28 | #include
29 |
30 | #if defined(ALLOC_DMA)
31 | #include
32 | typedef nvvkpp::ResourceAllocatorDma Allocator;
33 | #elif defined(ALLOC_VMA)
34 | #include
35 | typedef nvvkpp::ResourceAllocatorVma Allocator;
36 | #else
37 | typedef nvvkpp::ResourceAllocatorDedicated Allocator;
38 | #endif
39 |
40 | using vkDT = vk::DescriptorType;
41 | using vkDS = vk::DescriptorSetLayoutBinding;
42 | using vkSS = vk::ShaderStageFlagBits;
43 | using vkCB = vk::CommandBufferUsageFlagBits;
44 | using vkBU = vk::BufferUsageFlagBits;
45 | using vkIU = vk::ImageUsageFlagBits;
46 | using vkMP = vk::MemoryPropertyFlagBits;
47 |
48 |
49 | // Utility to time the execution of something resetting the timer
50 | // on each elapse call
51 | // Usage:
52 | // {
53 | // MilliTimer timer;
54 | // ... stuff ...
55 | // double time_elapse = timer.elapse();
56 | // }
57 | #include
58 |
59 | struct MilliTimer
60 | {
61 | MilliTimer() { reset(); }
62 | void reset() { startTime = std::chrono::high_resolution_clock::now(); }
63 | double elapse()
64 | {
65 | auto now = std::chrono::high_resolution_clock::now();
66 | auto t = std::chrono::duration_cast(now - startTime).count() / 1000.0;
67 | startTime = now;
68 | return t;
69 | }
70 | std::chrono::high_resolution_clock::time_point startTime;
71 | };
72 |
73 | inline vk::ClearColorValue makeClearColor(glm::vec3& _c)
74 | {
75 | vk::ClearColorValue cc;
76 | cc.float32[0] = _c.x;
77 | cc.float32[1] = _c.y;
78 | cc.float32[2] = _c.z;
79 | cc.float32[3] = 0;
80 | return cc;
81 | }
82 |
--------------------------------------------------------------------------------