├── .gitignore ├── .vscode ├── launch.json └── settings.json ├── CMakeLists.txt ├── CONTRIBUTING ├── LICENSE ├── README.md ├── doc ├── 2cylinder.png ├── Anisotropy.png ├── AntiqueCamera.png ├── BoomBox.png ├── Corset.png ├── Damagedhelmet.png ├── FlightHelmet.png ├── MetalRoughness.png ├── SciFiHelmet.png ├── SpecGlossVsMetalRough.png ├── Unlit.png ├── VertexColor.png ├── alpha_blend.png ├── carbon_fiber.png ├── clear_coat.png ├── punctual_light.png ├── transmission.png └── vk_raytrace.png ├── images ├── bistro_ext.jpg ├── bistro_int.png ├── com.jpg ├── com_d.jpg ├── demov.png ├── dir.jpg ├── dir_d.jpg ├── gbuffer.jpg ├── ind.jpg ├── ind_d.jpg ├── ind_none.jpg ├── ind_restir.jpg ├── pipeline_direct.png ├── pipeline_indirect.png ├── pipeline_overview.png ├── render_time.jpg └── teaser.png ├── log_nvprosample.txt ├── shaders ├── common.glsl ├── compose.comp ├── compress.glsl ├── denoise_common.glsl ├── denoise_direct.comp ├── denoise_indirect.comp ├── direct_gen.comp ├── direct_reuse.comp ├── direct_stage.comp ├── env_sampling.glsl ├── gbuffer.comp ├── globals.glsl ├── gltf_material.glsl ├── host_device.h ├── indirect_stage.comp ├── layouts.glsl ├── passthrough.vert ├── pathtrace.glsl ├── pbr_metallicworkflow.glsl ├── post.frag ├── punctual.glsl ├── random.glsl ├── reservoir.glsl ├── shade_state.glsl ├── sun_and_sky.glsl ├── tonemapping.glsl └── traceray_rq.glsl └── src ├── accelstruct.cpp ├── accelstruct.hpp ├── alias_table.hpp ├── hdr_sampling.cpp ├── hdr_sampling.hpp ├── main.cpp ├── nvml_monitor.hpp ├── queue.hpp ├── render_output.cpp ├── render_output.hpp ├── renderer.cpp ├── renderer.hpp ├── sample_example.cpp ├── sample_example.hpp ├── sample_gui.cpp ├── sample_gui.hpp ├── scene.cpp ├── scene.hpp ├── tiny_gltf.cpp └── tools.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | /autogen/*.h 2 | /build/* 3 | /bin_x64/* 4 | /downloaded_resources/* 5 | /nvpro_core/* 6 | /nvpro_core -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | 8 | { 9 | "name": "(Windows) Launch", 10 | "type": "cppvsdbg", 11 | "request": "launch", 12 | "program": "F:\\GitLab\\nvp\\bin_x64\\Debug\\vk_raytrace.exe", 13 | "args": [], 14 | "stopAtEntry": false, 15 | "cwd": "${workspaceFolder}", 16 | "environment": [], 17 | "console": "externalTerminal" 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "algorithm": "cpp", 4 | "array": "cpp", 5 | "atomic": "cpp", 6 | "bit": "cpp", 7 | "bitset": "cpp", 8 | "cctype": "cpp", 9 | "charconv": "cpp", 10 | "chrono": "cpp", 11 | "cinttypes": "cpp", 12 | "clocale": "cpp", 13 | "cmath": "cpp", 14 | "codecvt": "cpp", 15 | "compare": "cpp", 16 | "concepts": "cpp", 17 | "condition_variable": "cpp", 18 | "csignal": "cpp", 19 | "cstdarg": "cpp", 20 | "cstddef": "cpp", 21 | "cstdint": "cpp", 22 | "cstdio": "cpp", 23 | "cstdlib": "cpp", 24 | "cstring": "cpp", 25 | "ctime": "cpp", 26 | "cwchar": "cpp", 27 | "deque": "cpp", 28 | "exception": "cpp", 29 | "filesystem": "cpp", 30 | "format": "cpp", 31 | "forward_list": "cpp", 32 | "fstream": "cpp", 33 | "functional": "cpp", 34 | "initializer_list": "cpp", 35 | "iomanip": "cpp", 36 | "ios": "cpp", 37 | "iosfwd": "cpp", 38 | "iostream": "cpp", 39 | "istream": "cpp", 40 | "iterator": "cpp", 41 | "limits": "cpp", 42 | "list": "cpp", 43 | "locale": "cpp", 44 | "map": "cpp", 45 | "memory": "cpp", 46 | "mutex": "cpp", 47 | "new": "cpp", 48 | "numeric": "cpp", 49 | "optional": "cpp", 50 | "ostream": "cpp", 51 | "queue": "cpp", 52 | "random": "cpp", 53 | "ratio": "cpp", 54 | "regex": "cpp", 55 | "set": "cpp", 56 | "shared_mutex": "cpp", 57 | "sstream": "cpp", 58 | "stdexcept": "cpp", 59 | "stop_token": "cpp", 60 | "streambuf": "cpp", 61 | "string": "cpp", 62 | "system_error": "cpp", 63 | "thread": "cpp", 64 | "tuple": "cpp", 65 | "type_traits": "cpp", 66 | "typeinfo": "cpp", 67 | "unordered_map": "cpp", 68 | "unordered_set": "cpp", 69 | "utility": "cpp", 70 | "valarray": "cpp", 71 | "vector": "cpp", 72 | "xfacet": "cpp", 73 | "xhash": "cpp", 74 | "xiosbase": "cpp", 75 | "xlocale": "cpp", 76 | "xlocbuf": "cpp", 77 | "xlocinfo": "cpp", 78 | "xlocmes": "cpp", 79 | "xlocmon": "cpp", 80 | "xlocnum": "cpp", 81 | "xloctime": "cpp", 82 | "xmemory": "cpp", 83 | "xstddef": "cpp", 84 | "xstring": "cpp", 85 | "xtr1common": "cpp", 86 | "xtree": "cpp", 87 | "xutility": "cpp" 88 | } 89 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #***************************************************************************** 2 | # Copyright 2020 NVIDIA Corporation. All rights reserved. 3 | #***************************************************************************** 4 | 5 | cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) 6 | 7 | #-------------------------------------------------------------------------------------------------- 8 | # Project setting 9 | get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) 10 | set(PROJNAME ${PROJNAME}) 11 | project(${PROJNAME} LANGUAGES C CXX) 12 | message(STATUS "-------------------------------") 13 | message(STATUS "Processing Project ${PROJNAME}:") 14 | 15 | #-------------------------------------------------------------------------------------------------- 16 | # C++ target and defines 17 | set(CMAKE_CXX_STANDARD 17) 18 | add_executable(${PROJNAME}) 19 | 20 | if(MSVC) 21 | add_definitions(/wd26812) # 'enum class' over 'enum' 22 | add_definitions(/wd26451) # Arithmetic overflow, casting 4 byte value to 8 byte value 23 | endif() 24 | 25 | 26 | #-------------------------------------------------------------------------------------------------- 27 | # look for nvpro_core 1) as a sub-folder 2) at some other locations 28 | # this cannot be put anywhere else since we still didn't find setup.cmake yet 29 | if(NOT BASE_DIRECTORY) 30 | find_path(BASE_DIRECTORY 31 | NAMES nvpro_core/cmake/setup.cmake 32 | PATHS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../.. 33 | REQUIRED 34 | DOC "Directory containing nvpro_core" 35 | ) 36 | endif() 37 | 38 | ## Various functions and macros REQUIRED 39 | if(EXISTS ${BASE_DIRECTORY}/nvpro_core/cmake/setup.cmake) 40 | include(${BASE_DIRECTORY}/nvpro_core/cmake/setup.cmake) 41 | include(${BASE_DIRECTORY}/nvpro_core/cmake/utilities.cmake) 42 | else() 43 | message(FATAL_ERROR "could not find base directory, please set BASE_DIRECTORY to folder containing nvpro_core") 44 | endif() 45 | 46 | 47 | 48 | #-------------------------------------------------------------------------------------------------- 49 | # Resources 50 | # 51 | download_files(FILENAMES robot_toon.zip EXTRACT) 52 | download_files(FILENAMES daytime.hdr std_env.hdr) 53 | 54 | 55 | 56 | #-------------------------------------------------------------------------------------------------- 57 | # Packages 58 | _add_package_VulkanSDK() 59 | _add_package_ImGUI() 60 | _add_package_FreeImage() 61 | # Add the following for GPU load and memory 62 | _add_package_NVML() 63 | # This should be added after all packages 64 | _add_nvpro_core_lib() 65 | 66 | #-------------------------------------------------------------------------------------------------- 67 | # Memory Allocation 68 | # Forcing to use our memory allocator DMA (similar to Vulkan Memory Allocator (VMA)) 69 | # target_compile_definitions(${PROJNAME} PUBLIC ALLOC_VMA) 70 | target_compile_definitions(${PROJNAME} PUBLIC ALLOC_DMA) 71 | # target_compile_definitions(${PROJNAME} PUBLIC ALLOC_DEDICATED) 72 | 73 | 74 | #-------------------------------------------------------------------------------------------------- 75 | # Default definitions: PROJECT_RELDIRECTORY, ... 76 | _add_project_definitions(${PROJNAME}) 77 | 78 | 79 | 80 | #-------------------------------------------------------------------------------------------------- 81 | # For NVML, the DLL is loaded by the application 82 | if(MSVC) 83 | set_target_properties(${PROJNAME} PROPERTIES LINK_FLAGS "/DELAYLOAD:nvml.dll") 84 | endif() 85 | 86 | #-------------------------------------------------------------------------------------------------- 87 | # Source files for this project 88 | file(GLOB SOURCE_FILES src/*.cpp src/*.c) 89 | file(GLOB HEADER_FILES src/*.hpp src/*.h ) 90 | 91 | 92 | #-------------------------------------------------------------------------------------------------- 93 | # GLSL to SPIR-V custom build 94 | compile_glsl_directory( 95 | SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" 96 | DST "${CMAKE_CURRENT_SOURCE_DIR}/autogen" 97 | VULKAN_TARGET "vulkan1.2" 98 | HEADER ON 99 | DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} 100 | ) 101 | 102 | 103 | 104 | #-------------------------------------------------------------------------------------------------- 105 | # Sources 106 | target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) 107 | target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) 108 | target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) 109 | target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) 110 | target_sources(${PROJNAME} PUBLIC ${GLSL_HEADERS}) 111 | 112 | 113 | #-------------------------------------------------------------------------------------------------- 114 | # Sub-folders in Visual Studio 115 | # 116 | source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) 117 | source_group("Sources" FILES ${SOURCE_FILES}) 118 | source_group("Header Files" FILES ${HEADER_FILES}) 119 | source_group("Shader Sources" FILES ${GLSL_SOURCES}) 120 | source_group("Shader Headers" FILES ${GLSL_HEADERS}) 121 | 122 | 123 | 124 | ##################################################################################### 125 | # Linkage 126 | # 127 | target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) 128 | 129 | foreach(DEBUGLIB ${LIBRARIES_DEBUG}) 130 | target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) 131 | endforeach(DEBUGLIB) 132 | 133 | foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) 134 | target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) 135 | endforeach(RELEASELIB) 136 | 137 | ##################################################################################### 138 | # copies binaries that need to be put next to the exe files (ZLib, etc.) 139 | # 140 | _finalize_target( ${PROJNAME} ) 141 | 142 | 143 | ##################################################################################### 144 | # Copy the default scene and images 145 | # 146 | #install(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") 147 | #install(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /doc/2cylinder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/2cylinder.png -------------------------------------------------------------------------------- /doc/Anisotropy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/Anisotropy.png -------------------------------------------------------------------------------- /doc/AntiqueCamera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/AntiqueCamera.png -------------------------------------------------------------------------------- /doc/BoomBox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/BoomBox.png -------------------------------------------------------------------------------- /doc/Corset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/Corset.png -------------------------------------------------------------------------------- /doc/Damagedhelmet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/Damagedhelmet.png -------------------------------------------------------------------------------- /doc/FlightHelmet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/FlightHelmet.png -------------------------------------------------------------------------------- /doc/MetalRoughness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/MetalRoughness.png -------------------------------------------------------------------------------- /doc/SciFiHelmet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/SciFiHelmet.png -------------------------------------------------------------------------------- /doc/SpecGlossVsMetalRough.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/SpecGlossVsMetalRough.png -------------------------------------------------------------------------------- /doc/Unlit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/Unlit.png -------------------------------------------------------------------------------- /doc/VertexColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/VertexColor.png -------------------------------------------------------------------------------- /doc/alpha_blend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/alpha_blend.png -------------------------------------------------------------------------------- /doc/carbon_fiber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/carbon_fiber.png -------------------------------------------------------------------------------- /doc/clear_coat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/clear_coat.png -------------------------------------------------------------------------------- /doc/punctual_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/punctual_light.png -------------------------------------------------------------------------------- /doc/transmission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/transmission.png -------------------------------------------------------------------------------- /doc/vk_raytrace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/doc/vk_raytrace.png -------------------------------------------------------------------------------- /images/bistro_ext.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/bistro_ext.jpg -------------------------------------------------------------------------------- /images/bistro_int.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/bistro_int.png -------------------------------------------------------------------------------- /images/com.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/com.jpg -------------------------------------------------------------------------------- /images/com_d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/com_d.jpg -------------------------------------------------------------------------------- /images/demov.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/demov.png -------------------------------------------------------------------------------- /images/dir.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/dir.jpg -------------------------------------------------------------------------------- /images/dir_d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/dir_d.jpg -------------------------------------------------------------------------------- /images/gbuffer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/gbuffer.jpg -------------------------------------------------------------------------------- /images/ind.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/ind.jpg -------------------------------------------------------------------------------- /images/ind_d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/ind_d.jpg -------------------------------------------------------------------------------- /images/ind_none.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/ind_none.jpg -------------------------------------------------------------------------------- /images/ind_restir.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/ind_restir.jpg -------------------------------------------------------------------------------- /images/pipeline_direct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/pipeline_direct.png -------------------------------------------------------------------------------- /images/pipeline_indirect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/pipeline_indirect.png -------------------------------------------------------------------------------- /images/pipeline_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/pipeline_overview.png -------------------------------------------------------------------------------- /images/render_time.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/render_time.jpg -------------------------------------------------------------------------------- /images/teaser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/images/teaser.png -------------------------------------------------------------------------------- /log_nvprosample.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IwakuraRein/CIS-565-Final-VR-Raytracer/5285429fd3c21652eda8cd5f62db2c8f09ea409b/log_nvprosample.txt -------------------------------------------------------------------------------- /shaders/common.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | //------------------------------------------------------------------------------------------------- 22 | // Various common functions. 23 | 24 | 25 | #ifndef RAYCOMMON_GLSL 26 | #define RAYCOMMON_GLSL 27 | 28 | const float InvalidPdf = -1.0; 29 | 30 | //----------------------------------------------------------------------- 31 | // Debugging 32 | //----------------------------------------------------------------------- 33 | vec3 IntegerToColor(uint val) 34 | { 35 | const vec3 freq = vec3(1.33333f, 2.33333f, 3.33333f); 36 | return vec3(sin(freq * val) * .5 + .5); 37 | } 38 | 39 | // utility for temperature 40 | float fade(float low, float high, float value) 41 | { 42 | float mid = (low + high) * 0.5; 43 | float range = (high - low) * 0.5; 44 | float x = 1.0 - clamp(abs(mid - value) / range, 0.0, 1.0); 45 | return smoothstep(0.0, 1.0, x); 46 | } 47 | 48 | // Return a cold-hot color based on intensity [0-1] 49 | vec3 temperature(float intensity) 50 | { 51 | const vec3 blue = vec3(0.0, 0.0, 1.0); 52 | const vec3 cyan = vec3(0.0, 1.0, 1.0); 53 | const vec3 green = vec3(0.0, 1.0, 0.0); 54 | const vec3 yellow = vec3(1.0, 1.0, 0.0); 55 | const vec3 red = vec3(1.0, 0.0, 0.0); 56 | 57 | vec3 color = (fade(-0.25, 0.25, intensity) * blue // 58 | + fade(0.0, 0.5, intensity) * cyan // 59 | + fade(0.25, 0.75, intensity) * green // 60 | + fade(0.5, 1.0, intensity) * yellow // 61 | + smoothstep(0.75, 1.0, intensity) * red); 62 | return color; 63 | } 64 | 65 | //----------------------------------------------------------------------- 66 | // Return the UV in a lat-long HDR map 67 | //----------------------------------------------------------------------- 68 | vec2 GetSphericalUv(vec3 v) 69 | { 70 | float gamma = asin(-v.y); 71 | float theta = atan(v.z, v.x); 72 | 73 | vec2 uv = vec2(theta * M_1_OVER_PI * 0.5, gamma * M_1_OVER_PI) + 0.5; 74 | return uv; 75 | } 76 | 77 | //----------------------------------------------------------------------- 78 | // Return the tangent and binormal from the incoming normal 79 | //----------------------------------------------------------------------- 80 | void CreateCoordinateSystem(in vec3 N, out vec3 Nt, out vec3 Nb) 81 | { 82 | // http://www.pbr-book.org/3ed-2018/Geometry_and_Transformations/Vectors.html#CoordinateSystemfromaVector 83 | //if(abs(N.x) > abs(N.y)) 84 | // Nt = vec3(-N.z, 0, N.x) / sqrt(N.x * N.x + N.z * N.z); 85 | //else 86 | // Nt = vec3(0, N.z, -N.y) / sqrt(N.y * N.y + N.z * N.z); 87 | //Nb = cross(N, Nt); 88 | 89 | Nt = normalize(((abs(N.z) > 0.99999f) ? vec3(-N.x * N.y, 1.0f - N.y * N.y, -N.y * N.z) : 90 | vec3(-N.x * N.z, -N.y * N.z, 1.0f - N.z * N.z))); 91 | Nb = cross(Nt, N); 92 | } 93 | 94 | 95 | //------------------------------------------------------------------------------------------------- 96 | // Avoiding self intersections (see Ray Tracing Gems, Ch. 6) 97 | //----------------------------------------------------------------------- 98 | vec3 OffsetRay(in vec3 p, in vec3 n) 99 | { 100 | const float intScale = 256.0f; 101 | const float floatScale = 1.0f / 65536.0f; 102 | const float origin = 1.0f / 32.0f; 103 | 104 | ivec3 of_i = ivec3(intScale * n.x, intScale * n.y, intScale * n.z); 105 | 106 | vec3 p_i = vec3(intBitsToFloat(floatBitsToInt(p.x) + ((p.x < 0) ? -of_i.x : of_i.x)), 107 | intBitsToFloat(floatBitsToInt(p.y) + ((p.y < 0) ? -of_i.y : of_i.y)), 108 | intBitsToFloat(floatBitsToInt(p.z) + ((p.z < 0) ? -of_i.z : of_i.z))); 109 | 110 | return vec3(abs(p.x) < origin ? p.x + floatScale * n.x : p_i.x, // 111 | abs(p.y) < origin ? p.y + floatScale * n.y : p_i.y, // 112 | abs(p.z) < origin ? p.z + floatScale * n.z : p_i.z); 113 | } 114 | 115 | // compact hdr color to 32bit 116 | // TODO: change tone mapping 117 | uint packYCbCr(in vec3 c) { 118 | // c = pow(c, vec3(0.5, 0.5, 0.5)); 119 | c = c / (1.0 + c); 120 | float y = 0.299 * c.r + 0.587 * c.g + 0.114 * c.b; 121 | float cb = -0.16873589 * c.r -0.33126411 * c.g + 0.5 * c.b + 0.5; 122 | float cr = 0.5 * c.r -0.41868759 * c.g -0.08131241 * c.b + 0.5; 123 | uint outVal = uint(y * 65535.0) << 16; 124 | outVal += uint(cb * 255.0) << 8; 125 | outVal += uint(cr * 255.0); 126 | return outVal; 127 | } 128 | vec3 unpackYCbCr(in uint c) { 129 | float y = (c >> 16) / 65535.0; 130 | float cb = ((c << 16) >> 24) / 255.0 - 0.5; 131 | float cr = ((c << 24) >> 24) / 255.0 - 0.5; 132 | 133 | float b = cb * 1.772 + y; 134 | float r = y + 1.402 * cr; 135 | float g = (y - 0.299 * r - 0.114 * b) / 0.587; 136 | vec3 rgb = vec3(r, g, b); 137 | // return pow(rgb / (1.0 - rgb), vec3(2,2,2)); 138 | return rgb / (1.0 - rgb); 139 | } 140 | 141 | uint hash8bit(uint a) { 142 | return (a ^ (a >> 8)) << 24; 143 | } 144 | 145 | float getDepth(float z) { // untested 146 | // return 2.0 * CAMERA_NEAR * CAMERA_FAR / (CAMERA_FAR + CAMERA_NEAR - z_n * (CAMERA_FAR - CAMERA_NEAR)); 147 | float A = CAMERA_FAR / (CAMERA_NEAR - CAMERA_FAR); 148 | float B = CAMERA_NEAR * CAMERA_FAR / (CAMERA_NEAR - CAMERA_FAR); 149 | return (z - B) / A; 150 | } 151 | float getZ(float depth) { // untested 152 | return (CAMERA_FAR + CAMERA_NEAR) / (CAMERA_NEAR * CAMERA_FAR) * 0.5 + 0.5 - (CAMERA_FAR * CAMERA_NEAR / depth); 153 | } 154 | 155 | uint packTangent(vec3 n, vec3 t){ 156 | vec3 T, B; 157 | CreateCoordinateSystem(n, T, B); 158 | float theta = acos(dot(t, T)) / M_PI; 159 | float phi = acos(dot(t, B)); 160 | if (phi > M_PI_2) theta = -theta; 161 | 162 | return uint((theta + 1.0) * 32767.499); 163 | } 164 | vec3 unpackTangent(vec3 n, uint val){ 165 | vec3 T, B; 166 | CreateCoordinateSystem(n, T, B); 167 | float theta = (float(val & 0xFFFF) / 32767.499 - 1.0) * M_PI; 168 | return normalize(cos(theta) * T + sin(theta) * B); 169 | } 170 | 171 | vec2 toConcentricDisk(vec2 r) { 172 | float rx = sqrt(r.x); 173 | float theta = r.y * 2.0 * M_PI; 174 | return vec2(cos(theta), sin(theta)) * rx; 175 | } 176 | 177 | float powerHeuristic(float f, float g) { 178 | float f2 = f * f; 179 | return f2 / (f2 + g * g); 180 | } 181 | 182 | bool hasNan(vec3 v) { 183 | return isnan(v.x) || isnan(v.y) || isnan(v.z); 184 | } 185 | 186 | bool inBound(ivec2 p, ivec2 pMin, ivec2 pMax) { 187 | return p.x >= pMin.x && p.x < pMax.x && p.y >= pMin.y && p.y < pMax.y; 188 | } 189 | 190 | bool inBound(ivec2 p, ivec2 bound) { 191 | return inBound(p, ivec2(0, 0), bound); 192 | } 193 | 194 | vec3 HDRToLDR(vec3 color) { 195 | return color / (color + 1.0); 196 | } 197 | 198 | vec3 LDRToHDR(vec3 color) { 199 | return color / (1.01 - color); 200 | } 201 | 202 | vec3 colorWheel(float x) 203 | { 204 | const float Div = 1.0 / 4.0; 205 | if (x < Div) 206 | return vec3(0.0, x / Div, 1.0); 207 | else if (x < Div * 2) 208 | return vec3(0.0, 1.0, 2.0 - x / Div); 209 | else if (x < Div * 3) 210 | return vec3(x / Div - 2.0, 1.0, 0.0); 211 | else 212 | return vec3(1.0, 4.0 - x / Div, 0.0); 213 | } 214 | 215 | #endif // RAYCOMMON_GLSL 216 | -------------------------------------------------------------------------------- /shaders/compose.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_EXT_scalar_block_layout : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | #extension GL_EXT_ray_query : enable 7 | #extension GL_ARB_shader_clock : enable 8 | #extension GL_EXT_shader_image_load_formatted : enable 9 | #extension GL_ARB_shading_language_420pack : enable 10 | #extension GL_GOOGLE_include_directive : enable 11 | 12 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 13 | #extension GL_EXT_buffer_reference2 : require 14 | 15 | #include "layouts.glsl" 16 | 17 | layout(local_size_x = ComposeBlockSizeX, local_size_y = ComposeBlockSizeY) in; 18 | 19 | layout(push_constant) uniform _RtxState{ 20 | RtxState rtxState; 21 | }; 22 | 23 | void main() { 24 | ivec2 coord = ivec2(gl_GlobalInvocationID.xy); 25 | if (coord.x >= rtxState.size.x || coord.y >= rtxState.size.y) { 26 | return; 27 | } 28 | 29 | if (rtxState.modulate == 0) { 30 | vec4 indirect = (rtxState.denoise > 0) ? imageLoad(denoiseIndTempB, coord / 2) : 31 | imageLoad(denoiseIndTempA, coord / 2); 32 | imageStore(thisIndirectResultImage, coord, indirect); 33 | } 34 | else { 35 | vec3 albedo = unpackUnorm4x8(imageLoad(thisGbuffer, coord).w).rgb; 36 | vec3 direct = imageLoad(thisDirectResultImage, coord).rgb * albedo; 37 | vec3 indirect = ((rtxState.denoise > 0) ? imageLoad(denoiseIndTempB, coord / 2) : 38 | imageLoad(denoiseIndTempA, coord / 2)).rgb * albedo; 39 | 40 | imageStore(thisDirectResultImage, coord, vec4(direct, 1.0)); 41 | imageStore(thisIndirectResultImage, coord, vec4(indirect, 1.0)); 42 | } 43 | } -------------------------------------------------------------------------------- /shaders/compress.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | //------------------------------------------------------------------------------------------------- 21 | // This file can compress normal or tangent to a single uint 22 | // all oct functions derived from: 23 | // "A Survey of Efficient Representations for Independent Unit Vectors" 24 | // http://jcgt.org/published/0003/02/01/paper.pdf 25 | 26 | 27 | #ifndef COMPRESS_GLSL 28 | #define COMPRESS_GLSL 29 | 30 | 31 | #ifdef __cplusplus 32 | #define INLINE inline 33 | 34 | INLINE float uintBitsToFloat(uint32_t const& v) 35 | { 36 | union 37 | { 38 | uint in; 39 | float out; 40 | } u; 41 | 42 | u.in = v; 43 | 44 | return u.out; 45 | }; 46 | 47 | INLINE uint32_t floatBitsToUint(float v) 48 | { 49 | union 50 | { 51 | float in; 52 | uint out; 53 | } u; 54 | 55 | u.in = v; 56 | 57 | return u.out; 58 | }; 59 | 60 | INLINE uint packUnorm4x8(vec4 const& v) 61 | { 62 | union 63 | { 64 | unsigned char in[4]; 65 | uint out; 66 | } u; 67 | 68 | u.in[0] = (unsigned char)std::round(std::min(std::max(v.x, 0.0f), 1.0f) * 255.f); 69 | u.in[1] = (unsigned char)std::round(std::min(std::max(v.y, 0.0f), 1.0f) * 255.f); 70 | u.in[2] = (unsigned char)std::round(std::min(std::max(v.z, 0.0f), 1.0f) * 255.f); 71 | u.in[3] = (unsigned char)std::round(std::min(std::max(v.w, 0.0f), 1.0f) * 255.f); 72 | 73 | return u.out; 74 | } 75 | 76 | INLINE float roundEven(float x) 77 | { 78 | int Integer = static_cast(x); 79 | float IntegerPart = static_cast(Integer); 80 | float FractionalPart = (x - floor(x)); 81 | 82 | if(FractionalPart > 0.5f || FractionalPart < 0.5f) 83 | { 84 | return std::round(x); 85 | } 86 | else if((Integer % 2) == 0) 87 | { 88 | return IntegerPart; 89 | } 90 | else if(x <= 0) // Work around... 91 | { 92 | return IntegerPart - 1; 93 | } 94 | else 95 | { 96 | return IntegerPart + 1; 97 | } 98 | } 99 | 100 | #else 101 | #define INLINE 102 | #endif 103 | 104 | 105 | //----------------------------------------------------------------------- 106 | // Compression - can be done on host or device 107 | //----------------------------------------------------------------------- 108 | 109 | ////////////////////////////////////////////////////////////////////////// 110 | #define C_Stack_Max 3.402823466e+38f 111 | INLINE uint compress_unit_vec(vec3 nv) 112 | { 113 | // map to octahedron and then flatten to 2D (see 'Octahedron Environment Maps' by Engelhardt & Dachsbacher) 114 | if((nv.x < C_Stack_Max) && !isinf(nv.x)) 115 | { 116 | const float d = 32767.0f / (abs(nv.x) + abs(nv.y) + abs(nv.z)); 117 | int x = int(roundEven(nv.x * d)); 118 | int y = int(roundEven(nv.y * d)); 119 | 120 | if(nv.z < 0.0f) 121 | { 122 | const int maskx = x >> 31; 123 | const int masky = y >> 31; 124 | const int tmp = 32767 + maskx + masky; 125 | const int tmpx = x; 126 | x = (tmp - (y ^ masky)) ^ maskx; 127 | y = (tmp - (tmpx ^ maskx)) ^ masky; 128 | } 129 | 130 | uint packed = (uint(y + 32767) << 16) | uint(x + 32767); 131 | if(packed == ~0u) 132 | return ~0x1u; 133 | return packed; 134 | } 135 | else 136 | { 137 | return ~0u; 138 | } 139 | } 140 | 141 | 142 | /// 143 | float short_to_floatm11(const int v) // linearly maps a short 32767-32768 to a float -1-+1 //!! opt.? 144 | { 145 | return (v >= 0) ? (uintBitsToFloat(0x3F800000u | (uint(v) << 8)) - 1.0f) : 146 | (uintBitsToFloat((0x80000000u | 0x3F800000u) | (uint(-v) << 8)) + 1.0f); 147 | } 148 | 149 | vec3 decompress_unit_vec(uint packed) 150 | { 151 | if(packed != ~0u) // sanity check, not needed as isvalid_unit_vec is called earlier 152 | { 153 | int x = int(packed & 0xFFFFu) - 32767; 154 | int y = int(packed >> 16) - 32767; 155 | 156 | const int maskx = x >> 31; 157 | const int masky = y >> 31; 158 | const int tmp0 = 32767 + maskx + masky; 159 | const int ymask = y ^ masky; 160 | const int tmp1 = tmp0 - (x ^ maskx); 161 | const int z = tmp1 - ymask; 162 | float zf; 163 | if(z < 0) 164 | { 165 | x = (tmp0 - ymask) ^ maskx; 166 | y = tmp1 ^ masky; 167 | zf = uintBitsToFloat((0x80000000u | 0x3F800000u) | (uint(-z) << 8)) + 1.0f; 168 | } 169 | else 170 | { 171 | zf = uintBitsToFloat(0x3F800000u | (uint(z) << 8)) - 1.0f; 172 | } 173 | 174 | return normalize(vec3(short_to_floatm11(x), short_to_floatm11(y), zf)); 175 | } 176 | else 177 | { 178 | return vec3(C_Stack_Max); 179 | } 180 | } 181 | 182 | 183 | #endif // COMPRESS_GLSL 184 | -------------------------------------------------------------------------------- /shaders/denoise_common.glsl: -------------------------------------------------------------------------------- 1 | #ifndef DENOISE_COMMON_GLSL 2 | #define DENOISE_COMMON_GLSL 3 | 4 | #include "host_device.h" 5 | #include "globals.glsl" 6 | #include "layouts.glsl" 7 | #include "random.glsl" 8 | #include "common.glsl" 9 | #include "compress.glsl" 10 | 11 | layout(push_constant) uniform _RtxState{ 12 | RtxState rtxState; 13 | }; 14 | 15 | const float Gaussian5x5[5][5] = { 16 | { .0030f, .0133f, .0219f, .0133f, .0030f }, 17 | { .0133f, .0596f, .0983f, .0596f, .0133f }, 18 | { .0219f, .0983f, .1621f, .0983f, .0219f }, 19 | { .0133f, .0596f, .0983f, .0596f, .0133f }, 20 | { .0030f, .0133f, .0219f, .0133f, .0030f } 21 | }; 22 | 23 | float luminance(vec3 rgb) { 24 | return 0.2126f * rgb.x + 0.7152f * rgb.y + 0.0722f * rgb.z; 25 | } 26 | 27 | Ray raySpawn(ivec2 coord, ivec2 sizeImage) { 28 | const vec2 pixelCenter = vec2(coord) + 0.5; 29 | const vec2 inUV = pixelCenter / vec2(sizeImage.xy); 30 | vec2 d = inUV * 2.0 - 1.0; 31 | vec4 origin = sceneCamera.viewInverse * vec4(0, 0, 0, 1); 32 | vec4 target = sceneCamera.projInverse * vec4(d.x, d.y, 1, 1); 33 | vec4 direction = sceneCamera.viewInverse * vec4(normalize(target.xyz), 0); 34 | return Ray(origin.xyz, direction.xyz); 35 | } 36 | 37 | vec3 getCameraPos(ivec2 coord, float dist, ivec2 imageSize) { 38 | Ray ray = raySpawn(coord, imageSize); 39 | return ray.origin + ray.direction * dist; 40 | } 41 | 42 | void loadThisGeometry(ivec2 coord, out vec3 normal, out vec3 pos, out uint matHash, ivec2 imageSize) { 43 | uvec4 gInfo = imageLoad(thisGbuffer, coord); 44 | normal = decompress_unit_vec(gInfo.y); 45 | pos = getCameraPos(coord, uintBitsToFloat(gInfo.x), imageSize); 46 | matHash = gInfo.w & 0xFF000000; 47 | } 48 | 49 | void loadThisGeometry(ivec2 coord, out vec3 albedo, out vec3 normal, out vec3 pos, out uint matHash, ivec2 imageSize) { 50 | uvec4 gInfo = imageLoad(thisGbuffer, coord); 51 | albedo = unpackUnorm4x8(gInfo.w).rgb; 52 | normal = decompress_unit_vec(gInfo.y); 53 | pos = getCameraPos(coord, uintBitsToFloat(gInfo.x), imageSize); 54 | matHash = gInfo.w & 0xFF000000; 55 | } 56 | 57 | #endif -------------------------------------------------------------------------------- /shaders/denoise_direct.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_EXT_scalar_block_layout : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | #extension GL_EXT_ray_query : enable 7 | #extension GL_ARB_shader_clock : enable 8 | #extension GL_EXT_shader_image_load_formatted : enable 9 | #extension GL_ARB_shading_language_420pack : enable 10 | #extension GL_GOOGLE_include_directive : enable 11 | 12 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 13 | #extension GL_EXT_buffer_reference2 : require 14 | 15 | #include "denoise_common.glsl" 16 | 17 | layout(local_size_x = DenoiseBlockSizeX, local_size_y = DenoiseBlockSizeY) in; 18 | 19 | vec3 waveletFilter(image2D inImage, ivec2 coord, vec3 norm, vec3 pos, uint matHash, 20 | float sigLumin, float sigNormal, float sigDepth, int level 21 | ) { 22 | if (matHash == InvalidMatId) { 23 | return vec3(0.0); 24 | } 25 | int step = 1 << level; 26 | 27 | vec3 sum = vec3(0.0); 28 | float sumWeight = 0.0; 29 | 30 | vec3 color = imageLoad(inImage, coord).rgb; 31 | 32 | for (int j = -2; j <= 2; j++) { 33 | for (int i = -2; i <= 2; i++) { 34 | ivec2 q = coord + ivec2(i, j) * step; 35 | if (q.x >= rtxState.size.x || q.y >= rtxState.size.y || 36 | q.x < 0 || q.y < 0) { 37 | continue; 38 | } 39 | 40 | vec3 normQ; vec3 posQ; uint matHashQ; 41 | loadThisGeometry(q, normQ, posQ, matHashQ, rtxState.size); 42 | vec3 colorQ = imageLoad(inImage, q).rgb; 43 | 44 | if (matHash != matHashQ || matHashQ == InvalidMatId) { 45 | continue; 46 | } 47 | 48 | float var = sigLumin; 49 | float distColor = abs(luminance(color) - luminance(colorQ)); 50 | float wColor = exp(-distColor / var) + 1e-2; 51 | //float distColor = dot(color - colorQ, color - colorQ); 52 | //float wColor = exp(-distColor / rtxState.sigLumin) + 1e-3; 53 | 54 | float distNorm2 = dot(norm - normQ, norm - normQ); 55 | float wNorm = min(1.0, exp(-distNorm2 / sigNormal)); 56 | 57 | float distPos2 = dot(pos - posQ, pos - posQ); 58 | float wDepth = exp(-distPos2 / sigDepth) + 1e-2; 59 | 60 | float weight = wColor * wNorm * wDepth * Gaussian5x5[i + 2][j + 2]; 61 | sum += colorQ * weight; 62 | sumWeight += weight; 63 | } 64 | } 65 | vec3 res = (sumWeight < 1e-5) ? vec3(0.0) : sum / sumWeight; 66 | if (hasNan(res) || res.x < 0 || res.y < 0 || res.z < 0 || 67 | res.x > 1e8 || res.y > 1e8 || res.z > 1e8) { 68 | res = vec3(0.0); 69 | } 70 | return res; 71 | } 72 | 73 | #if DENOISER_DIRECT_BILATERAL 74 | const int Radius = 4; 75 | 76 | shared vec3 sharedColor[DenoiseBlockSizeX + Radius * 2][DenoiseBlockSizeY + Radius * 2]; 77 | 78 | vec3 bilateralFilter(image2D inImage, ivec2 coord, vec3 norm, vec3 pos, uint matHash, 79 | float sigLumin, float sigNormal, float sigDepth 80 | ) { 81 | if (matHash == InvalidMatId) { 82 | //return vec3(0.0); 83 | } 84 | vec3 sum = vec3(0.0); 85 | float sumWeight = 0.0; 86 | 87 | vec3 color = imageLoad(inImage, coord).rgb; 88 | 89 | ivec2 localId = ivec2(gl_LocalInvocationID.xy); 90 | ivec2 globalId = ivec2(gl_GlobalInvocationID.xy); 91 | 92 | sharedColor[localId.x][localId.y] = imageLoad(inImage, globalId).rgb; 93 | 94 | for (int j = -Radius; j <= Radius; j++) { 95 | for (int i = -Radius; i <= Radius; i++) { 96 | ivec2 q = coord + ivec2(i, j); 97 | if (q.x >= rtxState.size.x || q.y >= rtxState.size.y || 98 | q.x < 0 || q.y < 0) { 99 | continue; 100 | } 101 | 102 | vec3 normQ; vec3 posQ; uint matHashQ; 103 | loadThisGeometry(q, normQ, posQ, matHashQ, rtxState.size); 104 | vec3 colorQ = imageLoad(inImage, q).rgb; 105 | 106 | if (matHash != matHashQ || matHashQ == InvalidMatId) { 107 | continue; 108 | } 109 | 110 | float var = sigLumin; 111 | //float distColor = abs(luminance(color) - luminance(colorQ)); 112 | float distColor = dot(color - colorQ, color - colorQ); 113 | float wColor = exp(-distColor / var) + 1e-2; 114 | //float wColor = exp(-distColor / rtxState.sigLumin) + 1e-3; 115 | 116 | float distNorm2 = dot(norm - normQ, norm - normQ); 117 | float wNorm = min(1.0, exp(-distNorm2 / sigNormal)); 118 | 119 | float distPos2 = dot(pos - posQ, pos - posQ); 120 | float wDepth = exp(-distPos2 / sigDepth) + 1e-2; 121 | 122 | float dist2 = float(i * i + j * j); 123 | float wDist = exp(-dist2 / 10) + 1e-2; 124 | 125 | float weight = wColor * wNorm * wDepth * wDist; 126 | sum += colorQ * weight; 127 | sumWeight += weight; 128 | } 129 | } 130 | vec3 res = (sumWeight < 1e-5) ? vec3(0.0) : sum / sumWeight; 131 | if (hasNan(res) || res.x < 0 || res.y < 0 || res.z < 0 || 132 | res.x > 1e8 || res.y > 1e8 || res.z > 1e8) { 133 | res = vec3(0.0); 134 | } 135 | return res; 136 | } 137 | #endif 138 | 139 | void main() { 140 | ivec2 coord = ivec2(gl_GlobalInvocationID.xy); 141 | if (!inBound(coord, rtxState.size)) { 142 | return; 143 | } 144 | vec3 albedo; vec3 norm; vec3 pos; uint matHash; 145 | loadThisGeometry(coord, albedo, norm, pos, matHash, rtxState.size); 146 | 147 | #if DENOISER_DIRECT_BILATERAL 148 | { 149 | vec3 res = bilateralFilter(denoiseDirTempA, coord, norm, pos, matHash, 150 | rtxState.sigLuminDirect, rtxState.sigNormalDirect, rtxState.sigDepthDirect); 151 | #else 152 | if (rtxState.denoiseLevel == 0) { 153 | vec3 res = waveletFilter(thisDirectResultImage, coord, norm, pos, matHash, 154 | rtxState.sigLuminDirect, rtxState.sigNormalDirect, rtxState.sigDepthDirect, 0); 155 | imageStore(denoiseDirTempA, coord, vec4(res, 1.0)); 156 | } 157 | else if (rtxState.denoiseLevel == 1) { 158 | vec3 res = waveletFilter(denoiseDirTempA, coord, norm, pos, matHash, 159 | rtxState.sigLuminDirect, rtxState.sigNormalDirect, rtxState.sigDepthDirect, 1); 160 | imageStore(denoiseDirTempB, coord, vec4(res, 1.0)); 161 | } 162 | else if (rtxState.denoiseLevel == 2) { 163 | vec3 res = waveletFilter(denoiseDirTempB, coord, norm, pos, matHash, 164 | rtxState.sigLuminDirect, rtxState.sigNormalDirect, rtxState.sigDepthDirect, 2); 165 | imageStore(denoiseDirTempA, coord, vec4(res, 1.0)); 166 | } 167 | else if (rtxState.denoiseLevel == 3) { 168 | vec3 res = waveletFilter(denoiseDirTempA, coord, norm, pos, matHash, 169 | rtxState.sigLuminDirect, rtxState.sigNormalDirect, rtxState.sigDepthDirect, 3); 170 | #endif 171 | res = LDRToHDR(res); 172 | imageStore(thisDirectResultImage, coord, vec4(res, 1.0)); 173 | } 174 | } -------------------------------------------------------------------------------- /shaders/denoise_indirect.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_EXT_scalar_block_layout : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | #extension GL_EXT_ray_query : enable 7 | #extension GL_ARB_shader_clock : enable 8 | #extension GL_EXT_shader_image_load_formatted : enable 9 | #extension GL_ARB_shading_language_420pack : enable 10 | #extension GL_GOOGLE_include_directive : enable 11 | 12 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 13 | #extension GL_EXT_buffer_reference2 : require 14 | 15 | #include "denoise_common.glsl" 16 | 17 | layout(local_size_x = DenoiseBlockSizeX, local_size_y = DenoiseBlockSizeY) in; 18 | 19 | ivec2 indSize() { 20 | return rtxState.size / 2; 21 | } 22 | 23 | vec3 waveletFilter(image2D inImage, ivec2 coord, vec3 norm, vec3 pos, uint matHash, 24 | float sigLumin, float sigNormal, float sigDepth, int level 25 | ) { 26 | if (matHash == InvalidMatId) { 27 | return vec3(0.0); 28 | } 29 | int step = 1 << level; 30 | 31 | vec3 sum = vec3(0.0); 32 | float sumWeight = 0.0; 33 | 34 | vec3 color = imageLoad(inImage, coord).rgb; 35 | 36 | for (int j = -2; j <= 2; j++) { 37 | for (int i = -2; i <= 2; i++) { 38 | ivec2 q = coord + ivec2(i, j) * step; 39 | if (q.x >= indSize().x || q.y >= indSize().y || 40 | q.x < 0 || q.y < 0) { 41 | continue; 42 | } 43 | 44 | vec3 normQ; vec3 posQ; uint matHashQ; 45 | loadThisGeometry(q * 2, normQ, posQ, matHashQ, indSize()); 46 | vec3 colorQ = imageLoad(inImage, q).rgb; 47 | 48 | if (matHash != matHashQ || matHashQ == InvalidMatId) { 49 | continue; 50 | } 51 | 52 | float var = sigLumin; 53 | //float distColor = abs(luminance(color) - luminance(colorQ)); 54 | float distColor = dot(color - colorQ, color - colorQ); 55 | float wColor = exp(-distColor / var) + 1e-2; 56 | //float wColor = exp(-distColor / rtxState.sigLumin) + 1e-3; 57 | 58 | float distNorm2 = dot(norm - normQ, norm - normQ); 59 | float wNorm = min(1.0, exp(-distNorm2 / sigNormal)); 60 | 61 | float distPos2 = dot(pos - posQ, pos - posQ); 62 | float wDepth = exp(-distPos2 / sigDepth) + 1e-2; 63 | 64 | float weight = wColor * wNorm * wDepth * Gaussian5x5[i + 2][j + 2]; 65 | sum += colorQ * weight; 66 | sumWeight += weight; 67 | } 68 | } 69 | vec3 res = (sumWeight < 1e-5) ? vec3(0.0) : sum / sumWeight; 70 | if (hasNan(res) || res.x < 0 || res.y < 0 || res.z < 0 || 71 | res.x > 1e8 || res.y > 1e8 || res.z > 1e8) { 72 | res = vec3(0.0); 73 | } 74 | return res; 75 | } 76 | 77 | vec3 bilateralFilter(image2D inImage, ivec2 coord, vec3 norm, vec3 pos, uint matHash, 78 | float sigLumin, float sigNormal, float sigDepth 79 | ) { 80 | const int Radius = 5; 81 | 82 | if (matHash == InvalidMatId) { 83 | return vec3(0.0); 84 | } 85 | 86 | vec3 sum = vec3(0.0); 87 | float sumWeight = 0.0; 88 | 89 | vec3 color = imageLoad(inImage, coord).rgb; 90 | 91 | for (int j = -Radius; j <= Radius; j++) { 92 | for (int i = -Radius; i <= Radius; i++) { 93 | ivec2 q = coord + ivec2(i, j); 94 | if (q.x >= indSize().x || q.y >= indSize().y || 95 | q.x < 0 || q.y < 0) { 96 | continue; 97 | } 98 | 99 | vec3 normQ; vec3 posQ; uint matHashQ; 100 | loadThisGeometry(q * 2, normQ, posQ, matHashQ, indSize()); 101 | vec3 colorQ = imageLoad(inImage, q).rgb; 102 | 103 | if (matHash != matHashQ || matHashQ == InvalidMatId) { 104 | continue; 105 | } 106 | 107 | float var = sigLumin; 108 | //float distColor = abs(luminance(color) - luminance(colorQ)); 109 | float distColor = dot(color - colorQ, color - colorQ); 110 | float wColor = exp(-distColor / var) + 1e-2; 111 | //float wColor = exp(-distColor / rtxState.sigLumin) + 1e-3; 112 | 113 | float distNorm2 = dot(norm - normQ, norm - normQ); 114 | float wNorm = min(1.0, exp(-distNorm2 / sigNormal)); 115 | 116 | float distPos2 = dot(pos - posQ, pos - posQ); 117 | float wDepth = exp(-distPos2 / sigDepth) + 1e-2; 118 | 119 | float weight = wColor * wNorm * wDepth; 120 | sum += colorQ * weight; 121 | sumWeight += weight; 122 | } 123 | } 124 | vec3 res = (sumWeight < 1e-5) ? vec3(0.0) : sum / sumWeight; 125 | if (hasNan(res) || res.x < 0 || res.y < 0 || res.z < 0 || 126 | res.x > 1e8 || res.y > 1e8 || res.z > 1e8) { 127 | res = vec3(0.0); 128 | } 129 | return res; 130 | } 131 | 132 | void main() { 133 | ivec2 coord = ivec2(gl_GlobalInvocationID.xy); 134 | if (coord.x >= indSize().x || coord.y >= indSize().y || rtxState.denoise == 0) { 135 | return; 136 | } 137 | 138 | vec3 albedo; vec3 norm; vec3 pos; uint matHash; 139 | loadThisGeometry(coord * 2, norm, pos, matHash, indSize()); 140 | 141 | #if DENOISER_INDIRECT_BILATERAL 142 | { 143 | vec3 res = bilateralFilter(denoiseIndTempA, coord, norm, pos, matHash, 144 | rtxState.sigLuminIndirect, rtxState.sigNormalIndirect, rtxState.sigDepthIndirect); 145 | #else 146 | if (rtxState.denoiseLevel == 0) { 147 | vec3 res = waveletFilter(denoiseIndTempA, coord, norm, pos, matHash, 148 | rtxState.sigLuminIndirect, rtxState.sigNormalIndirect, rtxState.sigDepthIndirect, 0); 149 | imageStore(denoiseIndTempB, coord, vec4(res, 1.0)); 150 | } 151 | else if (rtxState.denoiseLevel == 1) { 152 | vec3 res = waveletFilter(denoiseIndTempB, coord, norm, pos, matHash, 153 | rtxState.sigLuminIndirect, rtxState.sigNormalIndirect, rtxState.sigDepthIndirect, 1); 154 | imageStore(denoiseIndTempA, coord, vec4(res, 1.0)); 155 | } 156 | else if (rtxState.denoiseLevel == 2) { 157 | vec3 res = waveletFilter(denoiseIndTempA, coord, norm, pos, matHash, 158 | rtxState.sigLuminIndirect, rtxState.sigNormalIndirect, rtxState.sigDepthIndirect, 2); 159 | imageStore(thisIndirectResultImage, coord, vec4(res, 1.0)); 160 | } 161 | else if (rtxState.denoiseLevel == 3) { 162 | vec3 res = waveletFilter(thisIndirectResultImage, coord, norm, pos, matHash, 163 | rtxState.sigLuminIndirect, rtxState.sigNormalIndirect, rtxState.sigDepthIndirect, 3); 164 | imageStore(denoiseIndTempA, coord, vec4(res, 1.0)); 165 | } 166 | else if (rtxState.denoiseLevel == 4) { 167 | vec3 res = waveletFilter(denoiseIndTempA, coord, norm, pos, matHash, 168 | rtxState.sigLuminIndirect, rtxState.sigNormalIndirect, rtxState.sigDepthIndirect, 4); 169 | #endif 170 | res = LDRToHDR(res); 171 | imageStore(denoiseIndTempB, coord, vec4(res, 1.0)); 172 | } 173 | } -------------------------------------------------------------------------------- /shaders/direct_gen.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_GOOGLE_include_directive : enable 5 | #extension GL_EXT_scalar_block_layout : enable 6 | #extension GL_EXT_ray_tracing : enable 7 | #extension GL_EXT_ray_query : enable 8 | #extension GL_ARB_shader_clock : enable // Using clockARB 9 | #extension GL_EXT_shader_image_load_formatted : enable // The folowing extension allow to pass images as function parameters 10 | 11 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 12 | #extension GL_EXT_buffer_reference2 : require 13 | 14 | #include "host_device.h" 15 | 16 | layout(push_constant) uniform _RtxState { 17 | RtxState rtxState; 18 | }; 19 | 20 | #include "globals.glsl" 21 | 22 | PtPayload prd; 23 | ShadowHitPayload shadow_payload; 24 | ivec2 imageCoords; 25 | 26 | #include "layouts.glsl" 27 | #include "random.glsl" 28 | #include "common.glsl" 29 | #include "traceray_rq.glsl" 30 | 31 | #include "pathtrace.glsl" 32 | 33 | #define FIREFLIES 1 34 | 35 | #ifndef SWIZZLED 36 | layout(local_size_x = 8, local_size_y = 8) in; 37 | #else 38 | layout(local_size_x = 32, local_size_y = 2) in; 39 | #extension GL_EXT_shader_8bit_storage : enable // Using uint_8 ... 40 | ivec2 SampleSizzled() { 41 | // Sampling Swizzling 42 | // Convert 32x2 to 8x8, where the sampling will follow how invocation are done in a subgroup. 43 | // layout(local_size_x = 32, local_size_y = 2) in; 44 | ivec2 base = ivec2(gl_WorkGroupID.xy) * 8; 45 | ivec2 subset = ivec2(int(gl_LocalInvocationID.x) & 1, int(gl_LocalInvocationID.x) / 2); 46 | subset += gl_LocalInvocationID.x >= 16 ? ivec2(2, -8) : ivec2(0, 0); 47 | subset += ivec2(gl_LocalInvocationID.y * 4, 0); 48 | return base + subset; 49 | } 50 | #endif 51 | 52 | uvec4 encodeGeometryInfo(State state, float depth) { 53 | uvec4 gInfo; 54 | gInfo.x = floatBitsToUint(depth); 55 | gInfo.y = compress_unit_vec(state.normal); 56 | gInfo.z = packUnorm4x8(vec4(state.mat.metallic, state.mat.roughness, (state.mat.ior-1.0) / MAX_IOR_MINUS_ONE, state.mat.transmission)); 57 | gInfo.w = packUnorm4x8(vec4(state.mat.albedo, 1.0)) & 0xFFFFFF; //agbr 58 | gInfo.w += hash8bit(state.matID); 59 | return gInfo; 60 | } 61 | 62 | void updateGeometryAlbedo(inout uvec4 gInfo, vec3 albedo) { 63 | uint matId = gInfo.w & 0xff000000u; 64 | gInfo.w = (packUnorm4x8(vec4(albedo, 1.0)) & 0x00ffffffu) | matId; 65 | } 66 | 67 | vec2 createMotionVector(vec3 wpos) { 68 | vec4 proj = sceneCamera.lastProjView * vec4(wpos, 1.0); 69 | vec3 ndc = proj.xyz / proj.w; 70 | return ndc.xy * 0.5 + 0.5; 71 | } 72 | 73 | ivec2 createMotionIndex(vec3 wpos) { 74 | return ivec2(createMotionVector(wpos) * vec2(rtxState.size)); 75 | } 76 | 77 | void generateGeometryAndReservoir(Ray r) { 78 | int index = imageCoords.y * rtxState.size.x + imageCoords.x; 79 | ClosestHit(r); 80 | 81 | DirectReservoir resv; 82 | resvReset(resv); 83 | 84 | if (prd.hitT >= INFINITY * 0.8) { 85 | uvec4 gInfo = uvec4(floatBitsToUint(INFINITY), 0, 0, InvalidMatId); 86 | updateGeometryAlbedo(gInfo, EnvRadiance(r.direction)); 87 | imageStore(thisGbuffer, imageCoords, gInfo); 88 | imageStore(motionVector, imageCoords, ivec4(0, 0, 0, 0)); 89 | thisDirectResv[index] = resv; 90 | return; 91 | } 92 | State state = GetState(prd, r.direction); 93 | GetMaterials(state, r); 94 | 95 | ivec2 motionIdx = createMotionIndex(state.position); 96 | imageStore(motionVector, imageCoords, ivec4(motionIdx, 0, 0)); 97 | 98 | uvec4 gInfo = encodeGeometryInfo(state, prd.hitT); 99 | 100 | if (rtxState.debugging_mode > eIndirectStage) { 101 | updateGeometryAlbedo(gInfo, DebugInfo(state)); 102 | } 103 | else if (state.isEmitter) { 104 | updateGeometryAlbedo(gInfo, state.mat.emission); 105 | } 106 | else { 107 | vec3 wo = -r.direction; 108 | vec3 direct = vec3(0.0); 109 | vec3 albedo = state.mat.albedo; 110 | state.mat.albedo = vec3(1.0); 111 | 112 | int sampleNum = (rtxState.ReSTIRState == eNone) ? 1 : rtxState.RISSampleNum; 113 | 114 | for (int i = 0; i < rtxState.RISSampleNum; i++) { 115 | LightSample lsample; 116 | float p = SampleDirectLightNoVisibility(state.position, lsample); 117 | 118 | vec3 pHat = lsample.Li * Eval(state, wo, state.ffnormal, lsample.wi, dummyPdf) * absDot(state.ffnormal, lsample.wi); 119 | float weight = resvToScalar(pHat / p); 120 | 121 | if (IsPdfInvalid(p) || isnan(weight)) { 122 | weight = 0.0; 123 | } 124 | resvUpdate(resv, lsample, weight, rand(prd.seed)); 125 | } 126 | LightSample lsample = resv.lightSample; 127 | Ray shadowRay; 128 | shadowRay.origin = OffsetRay(state.position, state.ffnormal); 129 | shadowRay.direction = lsample.wi; 130 | 131 | if (Occlusion(shadowRay, state, lsample.dist)) { 132 | resv.weight = 0.0; 133 | } 134 | } 135 | imageStore(thisGbuffer, imageCoords, gInfo); 136 | thisDirectResv[index] = resv; 137 | } 138 | 139 | void main() { 140 | ivec2 imageRes = rtxState.size; 141 | imageCoords = ivec2(gl_GlobalInvocationID.xy); //SampleSizzled(); 142 | if (imageCoords.x >= imageRes.x || imageCoords.y >= imageRes.y) { 143 | return; 144 | } 145 | 146 | prd.seed = tea(rtxState.size.x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x, rtxState.time); 147 | Ray ray = raySpawn(imageCoords, ivec2(imageRes)); 148 | 149 | generateGeometryAndReservoir(ray); 150 | } -------------------------------------------------------------------------------- /shaders/direct_reuse.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_GOOGLE_include_directive : enable 5 | #extension GL_EXT_scalar_block_layout : enable 6 | #extension GL_EXT_ray_tracing : enable 7 | #extension GL_EXT_ray_query : enable 8 | #extension GL_ARB_shader_clock : enable // Using clockARB 9 | #extension GL_EXT_shader_image_load_formatted : enable // The folowing extension allow to pass images as function parameters 10 | 11 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 12 | #extension GL_EXT_buffer_reference2 : require 13 | 14 | #define DEBUG_SAVE(x) imageStore(thisDirectResultImage, imageCoords, vec4(x, 1.0)); return; 15 | 16 | #include "host_device.h" 17 | 18 | layout(push_constant) uniform _RtxState { 19 | RtxState rtxState; 20 | }; 21 | 22 | #include "globals.glsl" 23 | 24 | PtPayload prd; 25 | ShadowHitPayload shadow_payload; 26 | ivec2 imageCoords; 27 | 28 | #include "layouts.glsl" 29 | #include "random.glsl" 30 | #include "common.glsl" 31 | #include "traceray_rq.glsl" 32 | 33 | #include "pathtrace.glsl" 34 | 35 | #define FIREFLIES 1 36 | 37 | #ifndef SWIZZLED 38 | layout(local_size_x = 8, local_size_y = 8) in; 39 | #else 40 | layout(local_size_x = 32, local_size_y = 2) in; 41 | #extension GL_EXT_shader_8bit_storage : enable // Using uint_8 ... 42 | ivec2 SampleSizzled() { 43 | // Sampling Swizzling 44 | // Convert 32x2 to 8x8, where the sampling will follow how invocation are done in a subgroup. 45 | // layout(local_size_x = 32, local_size_y = 2) in; 46 | ivec2 base = ivec2(gl_WorkGroupID.xy) * 8; 47 | ivec2 subset = ivec2(int(gl_LocalInvocationID.x) & 1, int(gl_LocalInvocationID.x) / 2); 48 | subset += gl_LocalInvocationID.x >= 16 ? ivec2(2, -8) : ivec2(0, 0); 49 | subset += ivec2(gl_LocalInvocationID.y * 4, 0); 50 | return base + subset; 51 | } 52 | #endif 53 | 54 | bool findTemporalNeighbor( 55 | vec3 norm, float depth, float reprojDepth, uint matId, ivec2 lastCoord, out DirectReservoir resv 56 | ) { 57 | vec3 pnorm; float pdepth; uint matHash; 58 | 59 | if (!inBound(lastCoord, ivec2(2, 0), rtxState.size)) { 60 | return false; 61 | } 62 | loadLastGeometryInfo(lastCoord, pnorm, pdepth, matHash); 63 | if (inBound(lastCoord, rtxState.size)) { 64 | if (hash8bit(matId) == matHash) { 65 | if (dot(norm, pnorm) > 0.9 && reprojDepth < pdepth * 1.05) { 66 | resv = lastDirectResv[lastCoord.y * rtxState.size.x + lastCoord.x]; 67 | return true; 68 | } 69 | } 70 | } 71 | /* 72 | for (int i = -1; i <= 1; i++) { 73 | for (int j = -1; j <= 1; j++) { 74 | ivec2 coord = iLastCoord + ivec2(i, j); 75 | loadLastGeometryInfo(coord, pnorm, pdepth, matHash); 76 | if (!inBound(coord, ivec2(2, 0), rtxState.size)) { 77 | continue; 78 | } 79 | else if (hash8bit(matId) != matHash) 80 | continue; 81 | else if (dot(norm, pnorm) < 0.9 || reprojDepth > pdepth * 1.05) { 82 | continue; 83 | } 84 | resv = lastDirectResv[coord.y * rtxState.size.x + coord.x]; 85 | //resv = lastDirectResv[iLastCoord.y * rtxState.size.x + iLastCoord.x]; 86 | return true; 87 | } 88 | } 89 | */ 90 | return false; 91 | } 92 | 93 | vec3 PHatDirect(DirectReservoir resv, State state, vec3 wo) { 94 | return resv.lightSample.Li * Eval(state, wo, state.ffnormal, resv.lightSample.wi, dummyPdf) * 95 | absDot(state.ffnormal, resv.lightSample.wi); 96 | } 97 | 98 | float BigWDirect(DirectReservoir resv, State state, vec3 wo) { 99 | return resv.weight / (resvToScalar(PHatDirect(resv, state, wo)) * float(resv.num)); 100 | } 101 | 102 | void main() { 103 | imageCoords = ivec2(gl_GlobalInvocationID.xy); //SampleSizzled(); 104 | if (imageCoords.x >= rtxState.size.x || imageCoords.y >= rtxState.size.y) { 105 | return; 106 | } 107 | int index = imageCoords.y * rtxState.size.x + imageCoords.x; 108 | 109 | prd.seed = tea(index + rtxState.size.x * rtxState.size.y, rtxState.time); 110 | Ray ray = raySpawn(imageCoords, rtxState.size); 111 | 112 | State state; 113 | float depth; 114 | if (!getDirectStateFromGBuffer(thisGbuffer, ray, state, depth)) { 115 | imageStore(thisDirectResultImage, imageCoords, vec4(0.0)); 116 | return; 117 | } 118 | state.mat.albedo = vec3(1.0); 119 | 120 | vec3 direct = vec3(0.0); 121 | DirectReservoir resv = thisDirectResv[index]; 122 | 123 | LightSample lsample = resv.lightSample; 124 | vec3 wo = -ray.direction; 125 | ivec2 motionIdx = imageLoad(motionVector, imageCoords).xy; 126 | 127 | if (rtxState.ReSTIRState == eTemporal || rtxState.ReSTIRState == eSpatiotemporal) { 128 | float reprojDepth = length(sceneCamera.lastPosition - state.position); 129 | DirectReservoir temporal; 130 | 131 | if (findTemporalNeighbor(state.normal, depth, reprojDepth, state.matID, motionIdx, temporal)) { 132 | if (!resvInvalid(temporal)) { 133 | resvMerge(resv, temporal, rand(prd.seed)); 134 | } 135 | } 136 | } 137 | 138 | if (!resvInvalid(resv)) { 139 | vec3 LiBSDF = lsample.Li * Eval(state, wo, state.ffnormal, lsample.wi, dummyPdf); 140 | //DEBUG_SAVE(vec3(resv.weight) / float(resv.num)) 141 | //direct = LiBSDF / resvToScalar(LiBSDF) * resv.weight / float(resv.num); 142 | //direct = vec3(resv.weight) / float(resv.num); 143 | direct = lsample.Li; 144 | } 145 | resvClamp(resv, rtxState.RISSampleNum * rtxState.reservoirClamp); 146 | resvCheckValidity(resv); 147 | 148 | if (isnan(direct.x) || isnan(direct.y) || isnan(direct.z)) { 149 | direct = vec3(0.0); 150 | } 151 | thisDirectResv[index] = resv; 152 | imageStore(thisDirectResultImage, imageCoords, vec4(HDRToLDR(clampRadiance(direct)), 1.0)); 153 | } -------------------------------------------------------------------------------- /shaders/direct_stage.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_GOOGLE_include_directive : enable 5 | #extension GL_EXT_scalar_block_layout : enable 6 | #extension GL_EXT_ray_tracing : enable 7 | #extension GL_EXT_ray_query : enable 8 | #extension GL_ARB_shader_clock : enable // Using clockARB 9 | #extension GL_EXT_shader_image_load_formatted : enable // The folowing extension allow to pass images as function parameters 10 | 11 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 12 | #extension GL_EXT_buffer_reference2 : require 13 | 14 | #include "host_device.h" 15 | 16 | layout(push_constant) uniform _RtxState { 17 | RtxState rtxState; 18 | }; 19 | 20 | #include "globals.glsl" 21 | 22 | PtPayload prd; 23 | ShadowHitPayload shadow_payload; 24 | ivec2 imageCoords; 25 | 26 | #include "layouts.glsl" 27 | #include "random.glsl" 28 | #include "common.glsl" 29 | #include "traceray_rq.glsl" 30 | 31 | #include "pathtrace.glsl" 32 | 33 | #define FIREFLIES 1 34 | 35 | layout(local_size_x = RayTraceBlockSizeX, local_size_y = RayTraceBlockSizeY) in; 36 | 37 | uvec4 encodeGeometryInfo(State state, float depth) { 38 | uvec4 gInfo; 39 | gInfo.x = floatBitsToUint(depth); 40 | gInfo.y = compress_unit_vec(state.normal); 41 | gInfo.z = packUnorm4x8(vec4(state.mat.metallic, state.mat.roughness, (state.mat.ior-1.0) / MAX_IOR_MINUS_ONE, state.mat.transmission)); 42 | gInfo.w = packUnorm4x8(vec4(state.mat.albedo, 1.0)) & 0xFFFFFF; //agbr 43 | gInfo.w += hash8bit(state.matID); 44 | return gInfo; 45 | } 46 | 47 | bool findTemporalNeighbor( 48 | vec3 norm, float depth, float reprojDepth, uint matId, ivec2 lastCoord, out DirectReservoir resv 49 | ) { 50 | vec3 pnorm; float pdepth; uint matHash; 51 | 52 | if (!inBound(lastCoord, ivec2(2, 0), rtxState.size)) { 53 | return false; 54 | } 55 | loadLastGeometryInfo(lastCoord, pnorm, pdepth, matHash); 56 | if (inBound(lastCoord, rtxState.size)) { 57 | if (hash8bit(matId) == matHash) { 58 | if (dot(norm, pnorm) > 0.9 && reprojDepth < pdepth * 1.05) { 59 | resv = lastDirectResv[lastCoord.y * rtxState.size.x + lastCoord.x]; 60 | return true; 61 | } 62 | } 63 | } 64 | /* 65 | for (int i = -1; i <= 1; i++) { 66 | for (int j = -1; j <= 1; j++) { 67 | ivec2 coord = iLastCoord + ivec2(i, j); 68 | loadLastGeometryInfo(coord, pnorm, pdepth, matHash); 69 | if (!inBound(coord, ivec2(2, 0), rtxState.size)) { 70 | continue; 71 | } 72 | else if (hash8bit(matId) != matHash) 73 | continue; 74 | else if (dot(norm, pnorm) < 0.9 || reprojDepth > pdepth * 1.05) { 75 | continue; 76 | } 77 | resv = lastDirectResv[coord.y * rtxState.size.x + coord.x]; 78 | //resv = lastDirectResv[iLastCoord.y * rtxState.size.x + iLastCoord.x]; 79 | return true; 80 | } 81 | } 82 | */ 83 | return false; 84 | } 85 | 86 | bool findSpatialNeighbor(vec3 norm, float depth, uint matId, out DirectReservoir resv) { 87 | const float Radius = 30.0; 88 | 89 | vec2 p = toConcentricDisk(vec2(rand(prd.seed), rand(prd.seed))); 90 | int px = int(float(imageCoords.x + p.x) + 0.5); 91 | int py = int(float(imageCoords.y + p.y) + 0.5); 92 | int pidx = py * rtxState.size.x + px; 93 | 94 | vec3 pnorm; float pdepth; 95 | loadThisGeometryInfo(imageCoords, pnorm, pdepth); 96 | 97 | bool diff = false; 98 | if (!inBound(ivec2(px, py), rtxState.size)) { 99 | return false; 100 | } 101 | else if (dot(norm, pnorm) < 0.5 || abs(depth - pdepth) > depth * 0.1) { 102 | return false; 103 | } 104 | resv = tempDirectResv[pidx]; 105 | return true; 106 | } 107 | 108 | bool mergeSpatialNeighbors(vec3 norm, float depth, uint matId, out DirectReservoir resv) { 109 | bool valid = false; 110 | resvReset(resv); 111 | for (int i = 0; i < 5; i++) { 112 | DirectReservoir spatial; 113 | if (findSpatialNeighbor(norm, depth, matId, spatial)) { 114 | if (!resvInvalid(spatial)) { 115 | resvMerge(resv, spatial, rand(prd.seed)); 116 | valid = true; 117 | } 118 | } 119 | } 120 | return valid; 121 | } 122 | 123 | void saveNewReservoir(DirectReservoir resv) { 124 | thisDirectResv[imageCoords.y * rtxState.size.x + imageCoords.x] = resv; 125 | } 126 | 127 | void cacheTempReservoir(DirectReservoir resv) { 128 | tempDirectResv[imageCoords.y * rtxState.size.x + imageCoords.x] = resv; 129 | } 130 | 131 | vec2 createMotionVector(vec3 wpos) { 132 | vec4 proj = sceneCamera.lastProjView * vec4(wpos, 1.0); 133 | vec3 ndc = proj.xyz / proj.w; 134 | return ndc.xy * 0.5 + 0.5; 135 | } 136 | 137 | ivec2 createMotionIndex(vec3 wpos) { 138 | return ivec2(createMotionVector(wpos) * vec2(rtxState.size)); 139 | } 140 | 141 | vec3 PHatDirect(DirectReservoir resv, State state, vec3 wo) { 142 | return resv.lightSample.Li * Eval(state, wo, state.ffnormal, resv.lightSample.wi, dummyPdf) * 143 | absDot(state.ffnormal, resv.lightSample.wi); 144 | } 145 | 146 | float BigWDirect(DirectReservoir resv, State state, vec3 wo) { 147 | return resv.weight / (resvToScalar(PHatDirect(resv, state, wo)) * float(resv.num)); 148 | } 149 | 150 | vec3 ReSTIRDirect(Ray r) { 151 | int index = imageCoords.y * rtxState.size.x + imageCoords.x; 152 | ClosestHit(r); 153 | 154 | if (prd.hitT >= INFINITY) { 155 | imageStore(thisGbuffer, imageCoords, uvec4(floatBitsToUint(INFINITY), 0, 0, InvalidMatId)); 156 | imageStore(motionVector, imageCoords, ivec4(0, 0, 0, 0)); 157 | return EnvRadiance(r.direction); 158 | } 159 | State state = GetState(prd, r.direction); 160 | GetMaterials(state, r); 161 | 162 | ivec2 motionIdx = createMotionIndex(state.position); 163 | uvec4 gInfo = encodeGeometryInfo(state, prd.hitT); 164 | imageStore(motionVector, imageCoords, ivec4(motionIdx, 0, 0)); 165 | imageStore(thisGbuffer, imageCoords, gInfo); 166 | barrier(); 167 | 168 | if (rtxState.debugging_mode > eIndirectStage) { 169 | return DebugInfo(state); 170 | } 171 | 172 | if (state.isEmitter) { 173 | return state.mat.emission; 174 | } 175 | 176 | vec3 wo = -r.direction; 177 | vec3 direct = vec3(0.0); 178 | vec3 albedo = state.mat.albedo; 179 | state.mat.albedo = vec3(1.0); 180 | 181 | if (rtxState.ReSTIRState == eNone) { 182 | direct = DirectLight(state, wo); 183 | } 184 | else { 185 | DirectReservoir resv; 186 | resvReset(resv); 187 | 188 | for (int i = 0; i < rtxState.RISSampleNum; i++) { 189 | LightSample lsample; 190 | float p = SampleDirectLightNoVisibility(state.position, lsample); 191 | 192 | vec3 pHat = lsample.Li * Eval(state, wo, state.ffnormal, lsample.wi, dummyPdf) * abs(dot(state.ffnormal, lsample.wi)); 193 | float weight = resvToScalar(pHat / p); 194 | 195 | if (IsPdfInvalid(p) || isnan(weight)) { 196 | weight = 0.0; 197 | } 198 | resvUpdate(resv, lsample, weight, rand(prd.seed)); 199 | } 200 | LightSample lsample = resv.lightSample; 201 | Ray shadowRay; 202 | shadowRay.origin = OffsetRay(state.position, state.ffnormal); 203 | shadowRay.direction = lsample.wi; 204 | 205 | if (Occlusion(shadowRay, state, lsample.dist)) { 206 | resv.weight = 0.0; 207 | } 208 | 209 | if (rtxState.ReSTIRState == eTemporal || rtxState.ReSTIRState == eSpatiotemporal) { 210 | float reprojDepth = length(sceneCamera.lastPosition - state.position); 211 | DirectReservoir temporal; 212 | if (findTemporalNeighbor(state.normal, prd.hitT, reprojDepth, state.matID, motionIdx, temporal)) { 213 | if (!resvInvalid(temporal)) { 214 | resvMerge(resv, temporal, rand(prd.seed)); 215 | } 216 | } 217 | } 218 | 219 | DirectReservoir tempResv = resv; 220 | resvCheckValidity(tempResv); 221 | resvClamp(tempResv, rtxState.RISSampleNum * rtxState.reservoirClamp); 222 | saveNewReservoir(tempResv); 223 | 224 | if (rtxState.ReSTIRState == eSpatial || rtxState.ReSTIRState == eSpatiotemporal) { 225 | DirectReservoir spatial; 226 | resvReset(spatial); 227 | resvCheckValidity(resv); 228 | barrier(); 229 | 230 | cacheTempReservoir(resv); 231 | barrier(); 232 | 233 | DirectReservoir spatialAggregate; 234 | if (mergeSpatialNeighbors(state.normal, prd.hitT, state.matID, spatialAggregate)) { 235 | if (!resvInvalid(spatialAggregate)) { 236 | resvMerge(spatial, spatialAggregate, rand(prd.seed)); 237 | } 238 | } 239 | resvCheckValidity(resv); 240 | barrier(); 241 | 242 | cacheTempReservoir(resv); 243 | barrier(); 244 | 245 | if (mergeSpatialNeighbors(state.normal, prd.hitT, state.matID, spatialAggregate)) { 246 | if (!resvInvalid(spatialAggregate)) { 247 | resvMerge(spatial, spatialAggregate, rand(prd.seed)); 248 | } 249 | } 250 | 251 | if (!resvInvalid(spatial)) { 252 | //resvClamp(spatial, 128); 253 | resvMerge(resv, spatial, rand(prd.seed)); 254 | } 255 | } 256 | lsample = resv.lightSample; 257 | 258 | if (!resvInvalid(resv)) { 259 | vec3 LiBsdf = lsample.Li * Eval(state, wo, state.ffnormal, lsample.wi, dummyPdf); 260 | direct = LiBsdf / resvToScalar(LiBsdf) * resv.weight / float(resv.num); 261 | } 262 | } 263 | 264 | if (isnan(direct.x) || isnan(direct.y) || isnan(direct.z)) { 265 | direct = vec3(0.0); 266 | } 267 | vec3 res = clampRadiance(state.mat.emission + direct); 268 | res = HDRToLDR(res); 269 | return res; 270 | } 271 | 272 | void main() { 273 | ivec2 imageRes = rtxState.size; 274 | imageCoords = ivec2(gl_GlobalInvocationID.xy); 275 | if (imageCoords.x >= imageRes.x || imageCoords.y >= imageRes.y) { 276 | return; 277 | } 278 | 279 | prd.seed = tea(rtxState.size.x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x, rtxState.time); 280 | Ray ray = raySpawn(imageCoords, ivec2(imageRes)); 281 | 282 | vec3 radiance = ReSTIRDirect(ray); 283 | vec3 pixelColor = clampRadiance(radiance); 284 | #if DENOISER_DIRECT_BILATERAL 285 | imageStore(denoiseDirTempA, imageCoords, vec4(pixelColor, 1)); 286 | #else 287 | imageStore(thisDirectResultImage, imageCoords, vec4(pixelColor, 1)); 288 | #endif 289 | } -------------------------------------------------------------------------------- /shaders/env_sampling.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | //------------------------------------------------------------------------------------------------- 21 | // This file has the functions to sample the environment 22 | 23 | 24 | #ifndef ENV_SAMPLING_GLSL 25 | #define ENV_SAMPLING_GLSL 26 | 27 | 28 | #include "globals.glsl" 29 | #include "common.glsl" 30 | 31 | #include "sun_and_sky.glsl" 32 | 33 | 34 | //------------------------------------------------------------------------------------------------- 35 | // Environment Sampling (HDR) 36 | // See: https://arxiv.org/pdf/1901.05423.pdf 37 | //------------------------------------------------------------------------------------------------- 38 | vec3 Environment_sample(sampler2D lat_long_tex, in vec3 randVal, out vec3 to_light, out float pdf) 39 | { 40 | 41 | // Uniformly pick a texel index idx in the environment map 42 | vec3 xi = randVal; 43 | uvec2 tsize = textureSize(lat_long_tex, 0); 44 | uint width = tsize.x; 45 | uint height = tsize.y; 46 | 47 | const uint size = width * height; 48 | const uint idx = min(uint(xi.x * float(size)), size - 1); 49 | 50 | // Fetch the sampling data for that texel, containing the ratio q between its 51 | // emitted radiance and the average of the environment map, the texel alias, 52 | // the probability distribution function (PDF) values for that texel and its 53 | // alias 54 | ImptSampData sample_data = envSamplingData[idx]; 55 | 56 | uint env_idx; 57 | 58 | if(xi.y < sample_data.q) 59 | { 60 | // If the random variable is lower than the intensity ratio q, we directly pick 61 | // this texel, and renormalize the random variable for later use. The PDF is the 62 | // one of the texel itself 63 | env_idx = idx; 64 | xi.y /= sample_data.q; 65 | pdf = sample_data.pdf; 66 | } 67 | else 68 | { 69 | // Otherwise we pick the alias of the texel, renormalize the random variable and use 70 | // the PDF of the alias 71 | env_idx = sample_data.alias; 72 | xi.y = (xi.y - sample_data.q) / (1.0f - sample_data.q); 73 | pdf = sample_data.aliasPdf; 74 | } 75 | 76 | // Compute the 2D integer coordinates of the texel 77 | const uint px = env_idx % width; 78 | uint py = env_idx / width; 79 | 80 | // Uniformly sample the solid angle subtended by the pixel. 81 | // Generate both the UV for texture lookup and a direction in spherical coordinates 82 | const float u = float(px + xi.y) / float(width); 83 | const float phi = u * (2.0f * M_PI) - M_PI; 84 | float sin_phi = sin(phi); 85 | float cos_phi = cos(phi); 86 | 87 | const float step_theta = M_PI / float(height); 88 | const float theta0 = float(py) * step_theta; 89 | const float cos_theta = cos(theta0) * (1.0f - xi.z) + cos(theta0 + step_theta) * xi.z; 90 | const float theta = acos(cos_theta); 91 | const float sin_theta = sin(theta); 92 | const float v = theta * M_1_OVER_PI; 93 | 94 | // Convert to a light direction vector in Cartesian coordinates 95 | to_light = vec3(cos_phi * sin_theta, cos_theta, sin_phi * sin_theta); 96 | 97 | // Lookup the environment value using bilinear filtering 98 | return texture(lat_long_tex, vec2(u, v)).xyz; 99 | } 100 | 101 | 102 | //----------------------------------------------------------------------- 103 | // Sampling the HDR environment or Sun and Sky 104 | //----------------------------------------------------------------------- 105 | vec4 EnvSample(inout vec3 radiance) 106 | { 107 | vec3 lightDir; 108 | float pdf; 109 | 110 | // Sun & Sky or HDR 111 | if(_sunAndSky.in_use == 1) 112 | { 113 | // #TODO: find proper light direction + PDF 114 | float sun_radius = (0.00465f * 10.0f) * _sunAndSky.sun_disk_scale; 115 | vec3 T, B; 116 | CreateCoordinateSystem(_sunAndSky.sun_direction, T, B); 117 | vec3 dir; 118 | dir.x = rand(prd.seed) * sun_radius; 119 | dir.y = rand(prd.seed) * sun_radius; 120 | dir.z = sqrt(max(0.0, 1.0 - dir.x * dir.x - dir.y * dir.y)); 121 | 122 | lightDir = normalize(T * dir.x + B * dir.y + _sunAndSky.sun_direction * dir.z); 123 | radiance = sun_and_sky(_sunAndSky, lightDir); 124 | pdf = 0.5; 125 | } 126 | else 127 | { 128 | // Sampling the HDR with importance sampling 129 | vec3 randVal = vec3(rand(prd.seed), rand(prd.seed), rand(prd.seed)); 130 | radiance = Environment_sample(environmentTexture, randVal, lightDir, pdf); 131 | } 132 | 133 | radiance *= rtxState.hdrMultiplier; 134 | return vec4(lightDir, pdf); 135 | } 136 | 137 | #endif // ENV_SAMPLING_GLSL 138 | -------------------------------------------------------------------------------- /shaders/gbuffer.comp: -------------------------------------------------------------------------------- 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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | //------------------------------------------------------------------------------------------------- 21 | // Ray Query compute shader implementating the path tracer. 22 | 23 | #version 460 24 | #extension GL_ARB_separate_shader_objects : enable 25 | #extension GL_EXT_nonuniform_qualifier : enable 26 | #extension GL_GOOGLE_include_directive : enable 27 | #extension GL_EXT_scalar_block_layout : enable 28 | #extension GL_EXT_ray_tracing : enable 29 | #extension GL_EXT_ray_query : enable 30 | #extension GL_ARB_shader_clock : enable // Using clockARB 31 | #extension GL_EXT_shader_image_load_formatted : enable // The folowing extension allow to pass images as function parameters 32 | 33 | #extension GL_NV_shader_sm_builtins : require // Debug - gl_WarpIDNV, gl_SMIDNV 34 | #extension GL_ARB_gpu_shader_int64 : enable // Debug - heatmap value 35 | #extension GL_EXT_shader_realtime_clock : enable // Debug - heatmap timing 36 | 37 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 38 | #extension GL_EXT_buffer_reference2 : require 39 | #extension GL_EXT_debug_printf : enable 40 | 41 | #include "host_device.h" 42 | 43 | layout(push_constant) uniform _RtxState { 44 | RtxState rtxState; 45 | }; 46 | 47 | #include "globals.glsl" 48 | 49 | PtPayload prd; 50 | ShadowHitPayload shadow_payload; 51 | ivec2 imageCoords; 52 | 53 | #include "layouts.glsl" 54 | #include "random.glsl" 55 | #include "common.glsl" 56 | #include "traceray_rq.glsl" 57 | 58 | #include "pathtrace.glsl" 59 | 60 | #define FIREFLIES 1 61 | 62 | //-------------------------------------------------------------------------------------------------- 63 | //-------------------------------------------------------------------------------------------------- 64 | #ifndef SWIZZLED 65 | layout(local_size_x = 8, local_size_y = 8) in; 66 | #else 67 | layout(local_size_x = 32, local_size_y = 2) in; 68 | #extension GL_EXT_shader_8bit_storage : enable // Using uint_8 ... 69 | ivec2 SampleSizzled() { 70 | // Sampling Swizzling 71 | // Convert 32x2 to 8x8, where the sampling will follow how invocation are done in a subgroup. 72 | // layout(local_size_x = 32, local_size_y = 2) in; 73 | ivec2 base = ivec2(gl_WorkGroupID.xy) * 8; 74 | ivec2 subset = ivec2(int(gl_LocalInvocationID.x) & 1, int(gl_LocalInvocationID.x) / 2); 75 | subset += gl_LocalInvocationID.x >= 16 ? ivec2(2, -8) : ivec2(0, 0); 76 | subset += ivec2(gl_LocalInvocationID.y * 4, 0); 77 | return base + subset; 78 | } 79 | #endif 80 | 81 | /* 82 | void main() { 83 | // uint64_t start = clockRealtimeEXT(); // Debug - Heatmap 84 | 85 | ivec2 imageRes = rtxState.size; 86 | imageCoords = ivec2(gl_GlobalInvocationID.xy); //SampleSizzled(); 87 | 88 | prd.seed = tea(rtxState.size.x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x, rtxState.time); 89 | 90 | vec3 pixelColor = vec3(0); 91 | 92 | Ray ray = raySpawn(imageCoords, ivec2(imageRes)); 93 | 94 | vec3 radiance = DirectSample(ray); 95 | 96 | float lum = dot(radiance, vec3(0.212671f, 0.715160f, 0.072169f)); 97 | if(lum > rtxState.fireflyClampThreshold) { 98 | radiance *= rtxState.fireflyClampThreshold / lum; 99 | } 100 | pixelColor += radiance; 101 | 102 | if(rtxState.frame > 0) { 103 | // Do accumulation over time 104 | vec3 old_color = imageLoad(lastDirectResultImage, imageCoords).xyz; 105 | vec3 new_result = mix(old_color, pixelColor, 1.0f / float(rtxState.frame + 1)); 106 | //imageStore(thisDirectResultImage, imageCoords, vec4(new_result, 1)); 107 | imageStore(thisDirectResultImage, imageCoords, vec4(pixelColor, 1.0)); 108 | } else { 109 | // First frame, replace the value in the buffer 110 | imageStore(thisDirectResultImage, imageCoords, vec4(pixelColor, 1)); 111 | } 112 | } 113 | */ 114 | 115 | void main() { 116 | } -------------------------------------------------------------------------------- /shaders/globals.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | //------------------------------------------------------------------------------------------------- 22 | // This file as all constant, global values and structures not shared with CPP 23 | 24 | #ifndef GLOBALS_GLSL 25 | #define GLOBALS_GLSL 1 26 | 27 | #define PI 3.14159265358979323 28 | #define TWO_PI 6.28318530717958648 29 | #define INFINITY 1e28 30 | #define EPS 0.0001 31 | 32 | #define SPECULAR_THRESHOLD 0.1 33 | 34 | //precision highp int; 35 | precision highp float; 36 | 37 | const float M_PI = 3.14159265358979323846; // pi 38 | const float M_TWO_PI = 6.28318530717958648; // 2*pi 39 | const float M_PI_2 = 1.57079632679489661923; // pi/2 40 | const float M_PI_4 = 0.785398163397448309616; // pi/4 41 | const float M_1_OVER_PI = 0.318309886183790671538; // 1/pi 42 | const float M_2_OVER_PI = 0.636619772367581343076; // 2/pi 43 | 44 | 45 | #define RngStateType uint // Random type 46 | 47 | //----------------------------------------------------------------------- 48 | struct Ray 49 | { 50 | vec3 origin; 51 | vec3 direction; 52 | }; 53 | 54 | 55 | struct PtPayload 56 | { 57 | uint seed; 58 | float hitT; 59 | int primitiveID; 60 | int instanceID; 61 | int instanceCustomIndex; 62 | vec2 baryCoord; 63 | mat4x3 objectToWorld; 64 | mat4x3 worldToObject; 65 | }; 66 | 67 | struct ShadowHitPayload 68 | { 69 | RngStateType seed; 70 | bool isHit; 71 | }; 72 | 73 | // This material is the shading material after applying textures and any 74 | // other operation. This structure is filled in gltfmaterial.glsl 75 | struct Material 76 | { 77 | vec3 albedo; 78 | vec3 emission; 79 | float metallic; 80 | float ior; 81 | float roughness; 82 | float transmission; 83 | }; 84 | 85 | // From shading state, this is the structure pass to the eval functions 86 | struct State 87 | { 88 | int depth; 89 | float eta; 90 | 91 | vec3 position; 92 | vec3 normal; 93 | vec3 tangent; 94 | vec3 bitangent; 95 | vec3 ffnormal; 96 | vec2 texCoord; 97 | 98 | bool isEmitter; 99 | 100 | uint matID; 101 | Material mat; 102 | 103 | float area; 104 | }; 105 | 106 | const uint InvalidMatId = 0xff000000u; 107 | 108 | //----------------------------------------------------------------------- 109 | struct BsdfSampleRec 110 | { 111 | vec3 L; 112 | vec3 f; 113 | float pdf; 114 | }; 115 | 116 | //----------------------------------------------------------------------- 117 | struct LightSampleRec 118 | { 119 | vec3 surfacePos; 120 | vec3 normal; 121 | vec3 emission; 122 | float pdf; 123 | }; 124 | 125 | 126 | #endif // GLOBALS_GLSL 127 | -------------------------------------------------------------------------------- /shaders/gltf_material.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | //------------------------------------------------------------------------------------------------- 22 | // This file is resolving the material input GltfShadeMaterial, metallic-roughness, 23 | // specular-glossiness, textures and other thing and set the State Material values 24 | // which are used for the shading. 25 | 26 | 27 | #ifndef GLTFMATERIAL_GLSL 28 | #define GLTFMATERIAL_GLSL 1 29 | 30 | #include "env_sampling.glsl" 31 | 32 | //----------------------------------------------------------------------- 33 | #define SRGB_FAST_APPROXIMATION 1 34 | // sRGB to linear approximation 35 | // see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html 36 | //----------------------------------------------------------------------- 37 | vec4 SRGBtoLINEAR(vec4 srgbIn) 38 | { 39 | #ifdef SRGB_FAST_APPROXIMATION 40 | vec3 linOut = pow(srgbIn.xyz, vec3(2.2)); 41 | #else //SRGB_FAST_APPROXIMATION 42 | vec3 bLess = step(vec3(0.04045), srgbIn.xyz); 43 | vec3 linOut = mix(srgbIn.xyz / vec3(12.92), pow((srgbIn.xyz + vec3(0.055)) / vec3(1.055), vec3(2.4)), bLess); 44 | #endif //SRGB_FAST_APPROXIMATION 45 | return vec4(linOut, srgbIn.w); 46 | } 47 | 48 | 49 | //----------------------------------------------------------------------- 50 | // Retrieve the diffuse and specular color base on the shading model: Metal-Roughness or Specular-Glossiness 51 | //----------------------------------------------------------------------- 52 | void GetMetallicRoughness(inout State state, in GltfShadeMaterial material) 53 | { 54 | // KHR_materials_ior 55 | // float dielectricSpecular = (material.ior - 1) / (material.ior + 1); 56 | // dielectricSpecular *= dielectricSpecular; 57 | 58 | float perceptualRoughness = 0.0; 59 | float metallic = 0.0; 60 | vec4 baseColor = vec4(0.0, 0.0, 0.0, 1.0); 61 | // vec3 f0 = vec3(dielectricSpecular); 62 | 63 | // Metallic and Roughness material properties are packed together 64 | // In glTF, these factors can be specified by fixed scalar values 65 | // or from a metallic-roughness map 66 | perceptualRoughness = material.pbrRoughnessFactor; 67 | metallic = material.pbrMetallicFactor; 68 | if(material.pbrMetallicRoughnessTexture > -1) 69 | { 70 | // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. 71 | // This layout intentionally reserves the 'r' channel for (optional) occlusion map data 72 | vec4 mrSample = textureLod(texturesMap[nonuniformEXT(material.pbrMetallicRoughnessTexture)], state.texCoord, 0); 73 | perceptualRoughness = mrSample.g * perceptualRoughness; 74 | metallic = mrSample.b * metallic; 75 | } 76 | 77 | // The albedo may be defined from a base texture or a flat color 78 | baseColor = material.pbrBaseColorFactor; 79 | if(material.pbrBaseColorTexture > -1) 80 | { 81 | baseColor *= SRGBtoLINEAR(textureLod(texturesMap[nonuniformEXT(material.pbrBaseColorTexture)], state.texCoord, 0)); 82 | } 83 | 84 | // baseColor.rgb = mix(baseColor.rgb * (vec3(1.0) - f0), vec3(0), metallic); 85 | // Specular color (ior 1.4) 86 | // f0 = mix(vec3(dielectricSpecular), baseColor.xyz, metallic); 87 | 88 | state.mat.albedo = baseColor.xyz; 89 | state.mat.metallic = metallic; 90 | state.mat.roughness = perceptualRoughness; 91 | } 92 | 93 | //------------------------------------------------------------------------------------------------- 94 | // Specular-Glossiness converter 95 | // See: // https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows/js/three.pbrUtilities.js#L34 96 | //------------------------------------------------------------------------------------------------- 97 | const float c_MinReflectance = 0.04; 98 | 99 | //----------------------------------------------------------------------- 100 | //----------------------------------------------------------------------- 101 | float getPerceivedBrightness(vec3 vector) 102 | { 103 | return sqrt(0.299 * vector.r * vector.r + 0.587 * vector.g * vector.g + 0.114 * vector.b * vector.b); 104 | } 105 | 106 | //----------------------------------------------------------------------- 107 | //----------------------------------------------------------------------- 108 | float solveMetallic(vec3 diffuse, vec3 specular, float oneMinusSpecularStrength) 109 | //----------------------------------------------------------------------- 110 | { 111 | float specularBrightness = getPerceivedBrightness(specular); 112 | 113 | if(specularBrightness < c_MinReflectance) 114 | { 115 | return 0.0; 116 | } 117 | 118 | float diffuseBrightness = getPerceivedBrightness(diffuse); 119 | 120 | float a = c_MinReflectance; 121 | float b = diffuseBrightness * oneMinusSpecularStrength / (1.0 - c_MinReflectance) + specularBrightness - 2.0 * c_MinReflectance; 122 | float c = c_MinReflectance - specularBrightness; 123 | float D = max(b * b - 4.0 * a * c, 0); 124 | 125 | return clamp((-b + sqrt(D)) / (2.0 * a), 0.0, 1.0); 126 | } 127 | 128 | //----------------------------------------------------------------------- 129 | //----------------------------------------------------------------------- 130 | void GetMaterials(inout State state, in Ray r) 131 | { 132 | GltfShadeMaterial material = materials[state.matID]; 133 | 134 | // Uv Transform 135 | mat3 TBN = mat3(state.tangent, state.bitangent, state.normal); 136 | 137 | // Perturbating the normal if a normal map is present 138 | if(material.normalTexture > -1) 139 | { 140 | vec3 normalVector = textureLod(texturesMap[nonuniformEXT(material.normalTexture)], state.texCoord, 0).xyz; 141 | normalVector = normalize(normalVector * 2.0 - 1.0); 142 | normalVector *= vec3(material.normalTextureScale, material.normalTextureScale, 1.0); 143 | state.normal = normalize(TBN * normalVector); 144 | state.ffnormal = dot(state.normal, r.direction) <= 0.0 ? state.normal : -state.normal; 145 | CreateCoordinateSystem(state.ffnormal, state.tangent, state.bitangent); 146 | } 147 | 148 | // Emissive term 149 | state.mat.emission = material.emissiveFactor; 150 | if(material.emissiveTexture > -1) 151 | state.mat.emission *= 152 | SRGBtoLINEAR(textureLod(texturesMap[nonuniformEXT(material.emissiveTexture)], state.texCoord, 0)).rgb; 153 | if ((state.mat.emission.x + state.mat.emission.y + state.mat.emission.z) > 1e-3) state.isEmitter = true; 154 | else state.isEmitter = false; 155 | 156 | // Basic material 157 | // if(material.shadingModel == MATERIAL_METALLICROUGHNESS) 158 | GetMetallicRoughness(state, material); 159 | // else 160 | // GetSpecularGlossiness(state, material); 161 | 162 | // Clamping roughness 163 | state.mat.roughness = max(state.mat.roughness, 0.001); 164 | 165 | 166 | // KHR_materials_transmission 167 | state.mat.transmission = material.transmissionFactor; 168 | if(material.transmissionTexture > -1) 169 | { 170 | state.mat.transmission *= textureLod(texturesMap[nonuniformEXT(material.transmissionTexture)], state.texCoord, 0).r; 171 | } 172 | 173 | // KHR_materials_ior 174 | state.mat.ior = material.ior; 175 | state.eta = dot(state.normal, state.ffnormal) > 0.0 ? (1.0 / state.mat.ior) : state.mat.ior; 176 | } 177 | 178 | #endif // GLTFMATERIAL_GLSL 179 | -------------------------------------------------------------------------------- /shaders/host_device.h: -------------------------------------------------------------------------------- 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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | /* 21 | Various structure used by CPP and GLSL 22 | */ 23 | 24 | #ifndef COMMON_HOST_DEVICE 25 | #define COMMON_HOST_DEVICE 26 | 27 | #define INDIRECT_PRE_UPSCALE 0 28 | #define DENOISER_DIRECT_BILATERAL 0 29 | #define DENOISER_INDIRECT_BILATERAL 0 30 | 31 | const int RayTraceBlockSizeX = 8; 32 | const int RayTraceBlockSizeY = 8; 33 | 34 | const int DenoiseBlockSizeX = 8; 35 | const int DenoiseBlockSizeY = 8; 36 | 37 | const int ComposeBlockSizeX = 8; 38 | const int ComposeBlockSizeY = 8; 39 | 40 | #define CEIL_DIV(x, y) (x + y - 1) / y 41 | 42 | #ifdef __cplusplus 43 | #include 44 | #include "nvmath/nvmath.h" 45 | // GLSL Type 46 | using ivec2 = nvmath::vec2i; 47 | using vec2 = nvmath::vec2f; 48 | using vec3 = nvmath::vec3f; 49 | using vec4 = nvmath::vec4f; 50 | using mat4 = nvmath::mat4f; 51 | using uint = unsigned int; 52 | using uvec4 = nvmath::vec4ui; 53 | using uvec2 = nvmath::vec2ui; 54 | #endif 55 | 56 | // clang-format off 57 | #ifdef __cplusplus // Descriptor binding helper for C++ and GLSL 58 | #define START_ENUM(a) \ 59 | enum a \ 60 | { 61 | #define END_ENUM() } 62 | #else 63 | #define START_ENUM(a) const uint 64 | #define END_ENUM() 65 | #endif 66 | 67 | // Sets 68 | START_ENUM(SetBindings) 69 | S_ACCEL = 0, // Acceleration structure 70 | S_OUT = 1, // Offscreen output image 71 | S_SCENE = 2, // Scene data 72 | S_ENV = 3, // Environment / Sun & Sky 73 | S_RAYQ = 4, // Ray query renderer 74 | S_WF = 5, // Wavefront extra data 75 | sDenoise = 6 76 | END_ENUM(); 77 | 78 | // Acceleration Structure - Set 0 79 | START_ENUM(AccelBindings) 80 | eTlas = 0 81 | END_ENUM(); 82 | 83 | // Output image - Set 1 84 | START_ENUM(OutputBindings) 85 | eDirectSampler = 0, // As sampler 86 | eIndirectSampler = 1, // As sampler 87 | eLastDirectResult = 2, // As storage 88 | eLastIndirectResult = 3, // As storage 89 | eThisDirectResult = 4, // As storage 90 | eThisIndirectResult = 5 // As storage 91 | END_ENUM(); 92 | 93 | // Scene Data - Set 2 94 | START_ENUM(SceneBindings) 95 | eCamera = 0, 96 | eMaterials = 1, 97 | eInstData = 2, 98 | ePuncLights = 3, 99 | eTrigLights = 4, 100 | eLightBufInfo = 5, 101 | eTextures = 6 // must be last elem 102 | END_ENUM(); 103 | 104 | // Environment - Set 3 105 | START_ENUM(EnvBindings) 106 | eSunSky = 0, 107 | eHdr = 1, 108 | eImpSamples = 2 109 | END_ENUM(); 110 | 111 | // Ray Query - Set 4 112 | START_ENUM(RayQBindings) 113 | eLastGbuffer = 0, 114 | eThisGbuffer = 1, 115 | eLastDirectResv = 2, 116 | eThisDirectResv = 3, 117 | eTempDirectResv = 4, 118 | eLastIndirectResv = 5, 119 | eThisIndirectResv = 6, 120 | eTempIndirectResv = 7, 121 | eMotionVector = 8, 122 | eDenoiseDirTempA = 9, 123 | eDenoiseDirTempB = 10, 124 | eDenoiseIndTempA = 11, 125 | eDenoiseIndTempB = 12 126 | END_ENUM(); 127 | 128 | START_ENUM(DebugMode) 129 | eNoDebug = 0, // 130 | eDirectStage = 1, // 131 | eIndirectStage = 2, // 132 | eBaseColor = 3, // 133 | eNormal = 4, // 134 | eDepth = 5, // 135 | eMetallic = 6, // 136 | eEmissive = 7, // 137 | eRoughness = 8, // 138 | eTexcoord = 9 // 139 | END_ENUM(); 140 | // clang-format on 141 | 142 | START_ENUM(ReSTIRState) 143 | eNone = 0, 144 | eRIS = 1, 145 | eSpatial = 2, 146 | eTemporal = 3, 147 | eSpatiotemporal = 4 148 | END_ENUM(); 149 | 150 | // Camera of the scene 151 | #define CAMERA_NEAR 0.001f 152 | #define CAMERA_FAR 1000.0f 153 | struct SceneCamera 154 | { 155 | mat4 viewInverse; 156 | mat4 projInverse; 157 | mat4 projView; 158 | mat4 lastView; 159 | mat4 lastProjView; 160 | vec3 lastPosition; 161 | //float focalDist; 162 | //float aperture; 163 | // Extra 164 | int nbLights; 165 | }; 166 | 167 | struct VertexAttributes 168 | { 169 | vec3 position; 170 | uint normal; // compressed using oct 171 | vec2 texcoord; // Tangent handiness, stored in LSB of .y 172 | uint tangent; // compressed using oct 173 | uint color; // RGBA 174 | }; 175 | 176 | // GLTF material 177 | #define MATERIAL_METALLICROUGHNESS 0 178 | #define MATERIAL_SPECULARGLOSSINESS 1 179 | #define ALPHA_OPAQUE 0 180 | #define ALPHA_MASK 1 181 | #define ALPHA_BLEND 2 182 | #define MAX_IOR_MINUS_ONE 3.f 183 | struct GltfShadeMaterial 184 | { 185 | vec4 pbrBaseColorFactor; 186 | 187 | int pbrBaseColorTexture; 188 | float pbrMetallicFactor; 189 | float pbrRoughnessFactor; 190 | int pbrMetallicRoughnessTexture; 191 | 192 | int emissiveTexture; 193 | vec3 emissiveFactor; 194 | 195 | int normalTexture; 196 | float normalTextureScale; 197 | float transmissionFactor; 198 | int transmissionTexture; 199 | 200 | float ior; 201 | int alphaMode; 202 | float alphaCutoff; 203 | int pad; 204 | }; 205 | 206 | // Use with PushConstant 207 | struct RtxState 208 | { 209 | int frame; // Current frame, start at 0 210 | int maxDepth; // How deep the path is 211 | int modulate; 212 | float fireflyClampThreshold; // to cut fireflies 213 | 214 | float hdrMultiplier; // To brightening the scene 215 | int debugging_mode; // See DebugMode 216 | float environmentProb; // Used in direct light importance sampling 217 | uint time; // How long has the app been running. miliseconds. 218 | 219 | int ReSTIRState; 220 | int RISSampleNum; 221 | int reservoirClamp; 222 | int accumulate; 223 | 224 | ivec2 size; // rendering size 225 | float envMapLuminIntegInv; 226 | float lightLuminIntegInv; 227 | int MIS; 228 | 229 | float sigLuminDirect; 230 | float sigNormalDirect; 231 | float sigDepthDirect; 232 | int denoise; 233 | 234 | float sigLuminIndirect; 235 | float sigNormalIndirect; 236 | float sigDepthIndirect; 237 | int denoiseLevel; 238 | }; 239 | 240 | // Structure used for retrieving the primitive information in the closest hit 241 | // using gl_InstanceCustomIndexNV 242 | struct InstanceData 243 | { 244 | uint64_t vertexAddress; 245 | uint64_t indexAddress; 246 | int materialIndex; 247 | }; 248 | 249 | // KHR_lights_punctual extension. 250 | // see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual 251 | 252 | const int LightType_Directional = 0; 253 | const int LightType_Point = 1; 254 | const int LightType_Spot = 2; 255 | 256 | // custom light source for direct light importance sampling 257 | const int LightType_Triangle = 3; 258 | 259 | // ReSTIR 260 | struct LightSample { 261 | vec3 Li; 262 | vec3 wi; 263 | float dist; 264 | }; 265 | 266 | struct GISample { 267 | vec3 L; 268 | vec3 xv, nv; 269 | vec3 xs, ns; 270 | float pHat; 271 | }; 272 | 273 | struct DirectReservoir { 274 | LightSample lightSample; 275 | uint num; 276 | float weight; 277 | }; 278 | 279 | struct IndirectReservoir { 280 | GISample giSample; 281 | uint num; 282 | float weight; 283 | float bigW; 284 | }; 285 | 286 | // acceleration structure for importance sampling - pre-computed 287 | struct ImptSampData 288 | { 289 | int alias; 290 | float q; 291 | float pdf; 292 | float aliasPdf; 293 | }; 294 | 295 | struct PuncLight // point, spot, or directional light. 296 | { 297 | int type; 298 | vec3 direction; 299 | 300 | float intensity; 301 | vec3 color; 302 | 303 | vec3 position; 304 | float range; 305 | 306 | float outerConeCos; 307 | float innerConeCos; 308 | vec2 padding; 309 | 310 | ImptSampData impSamp; 311 | }; 312 | 313 | struct TrigLight 314 | { // triangles of emissive meshes 315 | uint matIndex; 316 | uint transformIndex; 317 | vec3 v0; 318 | vec3 v1; 319 | vec3 v2; 320 | vec2 uv0; 321 | vec2 uv1; 322 | vec2 uv2; 323 | ImptSampData impSamp; 324 | vec3 pad; 325 | }; 326 | 327 | struct LightBufInfo 328 | { 329 | uint puncLightSize; 330 | uint trigLightSize; 331 | float trigSampProb; 332 | int pad; 333 | }; 334 | 335 | // Tonemapper used in post.frag 336 | struct Tonemapper 337 | { 338 | float brightness; 339 | float contrast; 340 | float saturation; 341 | float vignette; 342 | 343 | float avgLum; 344 | float zoom; 345 | vec2 renderingRatio; 346 | 347 | int autoExposure; 348 | float Ywhite; // Burning white 349 | float key; // Log-average luminance 350 | int pad; 351 | }; 352 | 353 | struct SunAndSky 354 | { 355 | vec3 rgb_unit_conversion; 356 | float multiplier; 357 | 358 | float haze; 359 | float redblueshift; 360 | float saturation; 361 | float horizon_height; 362 | 363 | vec3 ground_color; 364 | float horizon_blur; 365 | 366 | vec3 night_color; 367 | float sun_disk_intensity; 368 | 369 | vec3 sun_direction; 370 | float sun_disk_scale; 371 | 372 | float sun_glow_intensity; 373 | int y_is_up; 374 | int physically_scaled_sun; 375 | int in_use; 376 | }; 377 | 378 | #endif // COMMON_HOST_DEVICE 379 | -------------------------------------------------------------------------------- /shaders/indirect_stage.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_ARB_separate_shader_objects : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_GOOGLE_include_directive : enable 5 | #extension GL_EXT_scalar_block_layout : enable 6 | #extension GL_EXT_ray_tracing : enable 7 | #extension GL_EXT_ray_query : enable 8 | #extension GL_ARB_shader_clock : enable // Using clockARB 9 | #extension GL_EXT_shader_image_load_formatted : enable // The folowing extension allow to pass images as function parameters 10 | 11 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 12 | #extension GL_EXT_buffer_reference2 : require 13 | 14 | #include "host_device.h" 15 | 16 | layout(push_constant) uniform _RtxState { 17 | RtxState rtxState; 18 | }; 19 | 20 | #include "globals.glsl" 21 | 22 | PtPayload prd; 23 | ShadowHitPayload shadow_payload; 24 | ivec2 imageCoords; 25 | 26 | #include "layouts.glsl" 27 | #include "random.glsl" 28 | #include "common.glsl" 29 | #include "traceray_rq.glsl" 30 | 31 | #include "pathtrace.glsl" 32 | 33 | #define FIREFLIES 1 34 | #define TILED_MULTIBOUNCE 1 35 | #define FETCH_GEOM_CHECK_4_SUBPIXELS 0 36 | 37 | layout(local_size_x = RayTraceBlockSizeX, local_size_y = RayTraceBlockSizeY) in; 38 | 39 | #if TILED_MULTIBOUNCE 40 | shared bool multiBounce; 41 | #else 42 | const bool multiBounce = true; 43 | #endif 44 | 45 | const float MultiBounceProb = 0.25; 46 | 47 | ivec2 indSize() { 48 | return rtxState.size / 2; 49 | } 50 | 51 | uvec2 encodeMaterialInfo(State state) { 52 | uvec2 matInfo; 53 | matInfo.x = packUnorm4x8(vec4(state.mat.metallic, state.mat.roughness, (state.mat.ior-1.0) / MAX_IOR_MINUS_ONE, state.mat.transmission)); 54 | matInfo.y = packUnorm4x8(vec4(state.mat.albedo, 1.0)) & 0xFFFFFF; //agbr 55 | matInfo.y += hash8bit(state.matID); 56 | return matInfo; 57 | } 58 | 59 | float MIS(float f, float g) { 60 | return (rtxState.MIS > 0) ? powerHeuristic(f, g) : 1.0; 61 | } 62 | 63 | float pHatIndirect(GISample giSample, State state, vec3 wo) { 64 | return resvToScalar(giSample.L); 65 | 66 | vec3 wi = normalize(giSample.xs - giSample.xv); 67 | return resvToScalar(giSample.L * BSDF(state, wo, state.ffnormal, wi) * satDot(giSample.nv, wi)); 68 | } 69 | 70 | float bigWIndirect(IndirectReservoir resv, State state, vec3 wo) { 71 | return resv.weight / (pHatIndirect(resv.giSample, state, wo) * float(resv.num)); 72 | } 73 | 74 | bool findTemporalNeighbor( 75 | vec3 norm, float depth, float reprojDepth, uint matId, ivec2 lastCoord, inout IndirectReservoir resv 76 | ) { 77 | vec3 pnorm; float pdepth; uint matHash; 78 | 79 | loadLastGeometryInfo(lastCoord, pnorm, pdepth, matHash); 80 | ivec2 coord = lastCoord / 2; 81 | 82 | if (inBound(coord, indSize())) { 83 | if (hash8bit(matId) == matHash) { 84 | if (dot(norm, pnorm) > 0.5 && reprojDepth < pdepth * 1.1) { 85 | resv = lastIndirectResv[coord.y * indSize().x + coord.x]; 86 | return true; 87 | } 88 | } 89 | } 90 | /* 91 | for (int i = 0; i < 2; i++) { 92 | for (int j = 0; j < 2; j++) { 93 | ivec2 coord = (lastCoord + ivec2(i, j)) / 2; 94 | loadLastGeometryInfo(lastCoord + ivec2(i, j), pnorm, pdepth, matHash); 95 | 96 | if (inBound(coord, indSize())) { 97 | if (hash8bit(matId) == matHash) { 98 | if (dot(norm, pnorm) > 0.9 && reprojDepth < pdepth * 1.05) { 99 | resv = lastIndirectResv[coord.y * indSize().x + coord.x]; 100 | return true; 101 | } 102 | } 103 | } 104 | } 105 | } 106 | */ 107 | return false; 108 | } 109 | 110 | GISample newGISample() { 111 | GISample giSample; 112 | giSample.nv = vec3(100.0); 113 | giSample.L = vec3(0.0); 114 | return giSample; 115 | } 116 | 117 | bool GISampleValid(GISample giSample) { 118 | return giSample.nv.x < 1.1 && !hasNan(giSample.L); 119 | } 120 | 121 | void saveNewReservoir(IndirectReservoir resv) { 122 | thisIndirectResv[imageCoords.y * indSize().x + imageCoords.x] = resv; 123 | } 124 | 125 | void cacheTempReservoir(IndirectReservoir resv) { 126 | tempIndirectResv[imageCoords.y * indSize().x + imageCoords.x] = resv; 127 | } 128 | 129 | void pathTraceIndirect( 130 | State state, Ray ray, 131 | out float primSamplePdf, out vec3 primWo, out State primState, out GISample giSample 132 | ) { 133 | vec3 throughput = vec3(multiBounce ? 4.0 : 1.0); 134 | primWo = -ray.direction; 135 | primState = state; 136 | giSample = newGISample(); 137 | 138 | state.mat.albedo = vec3(1.0); 139 | 140 | for (int depth = 1; depth <= rtxState.maxDepth; depth++) { 141 | vec3 wo = -ray.direction; 142 | 143 | if (depth > 1 && rtxState.MIS > 0) { 144 | vec3 Li, wi; 145 | float lightPdf = SampleDirectLight(state, Li, wi); 146 | 147 | if (!IsPdfInvalid(lightPdf)) { 148 | float BSDFPdf = Pdf(state, wo, state.ffnormal, wi); 149 | float weight = MIS(lightPdf, BSDFPdf); 150 | giSample.L += Li * BSDF(state, wo, state.ffnormal, wi) * absDot(state.ffnormal, wi) * 151 | throughput / lightPdf * weight; 152 | } 153 | } 154 | 155 | vec3 sampleWi; 156 | float samplePdf; 157 | vec3 sampleBSDF = Sample(state, wo, state.ffnormal, sampleWi, samplePdf, prd.seed); 158 | 159 | if (IsPdfInvalid(samplePdf)) { 160 | break; 161 | } 162 | 163 | if (depth > 1) { 164 | if (!multiBounce) { 165 | return; 166 | } 167 | throughput *= sampleBSDF / samplePdf * absDot(state.ffnormal, sampleWi); 168 | } 169 | else { 170 | primSamplePdf = samplePdf; 171 | giSample.xv = state.position; 172 | giSample.nv = state.ffnormal; 173 | } 174 | 175 | ray.origin = OffsetRay(state.position, state.ffnormal); 176 | ray.direction = sampleWi; 177 | 178 | ClosestHit(ray); 179 | 180 | if (prd.hitT >= INFINITY - 1e-4) { 181 | if (depth > 1) { 182 | float lightPdf; 183 | vec3 Li = EnvEval(sampleWi, lightPdf); 184 | float weight = MIS(samplePdf, lightPdf); 185 | giSample.L += Li * throughput * weight; 186 | } 187 | else { 188 | // Hack here. To let samples from the infinity light able to be temporally reused 189 | // giSample.matInfo = uvec2(0xFFFFFFFF, 0xFFFFFFFF); 190 | giSample.xs = state.position + sampleWi * INFINITY * 0.8; 191 | giSample.ns = -sampleWi; 192 | } 193 | break; 194 | } 195 | 196 | state = GetState(prd, ray.direction); 197 | GetMaterials(state, ray); 198 | 199 | if (state.isEmitter) { 200 | if (depth > 1) { 201 | float lightPdf; 202 | vec3 Li = LightEval(state, prd.hitT, sampleWi, lightPdf); 203 | float weight = MIS(samplePdf, lightPdf); 204 | giSample.L += Li * throughput * weight; 205 | } 206 | else { 207 | giSample.xs = state.position; 208 | giSample.ns = state.ffnormal; 209 | } 210 | break; 211 | } 212 | 213 | if (depth == 1) { 214 | giSample.xs = state.position; 215 | giSample.ns = state.ffnormal; 216 | } 217 | 218 | #ifndef RR 219 | float rrPcont = (1 >= RR_DEPTH) ? min(max(throughput.x, max(throughput.y, throughput.z)) * state.eta * state.eta + 0.001, 0.95) : 1.0; 220 | if (rand(prd.seed) >= rrPcont) { 221 | break; 222 | } 223 | throughput /= rrPcont; 224 | #endif 225 | } 226 | } 227 | 228 | vec3 ReSTIRIndirect(float dist, float primSamplePdf, vec3 primWo, State primState, GISample giSample) { 229 | vec3 indirect = vec3(0.0); 230 | 231 | IndirectReservoir resv; 232 | resvReset(resv); 233 | // temporal reuse 234 | if (rtxState.ReSTIRState == eTemporal || rtxState.ReSTIRState == eSpatiotemporal) { 235 | float reprojDepth = length(sceneCamera.lastPosition - primState.position); 236 | ivec2 motionIdx = imageLoad(motionVector, imageCoords * 2).xy; 237 | findTemporalNeighbor(primState.ffnormal, dist, reprojDepth, primState.matID, motionIdx, resv); 238 | } 239 | 240 | float sampleWeight = 0.0; 241 | if (GISampleValid(giSample)) { 242 | giSample.pHat = pHatIndirect(giSample, primState, primWo); 243 | sampleWeight = (giSample.pHat / primSamplePdf); 244 | if (isnan(sampleWeight) || sampleWeight < 0.0) { 245 | sampleWeight = 0.0; 246 | } 247 | } 248 | resvUpdate(resv, giSample, sampleWeight, rand(prd.seed)); 249 | 250 | resvCheckValidity(resv); 251 | resvClamp(resv, rtxState.reservoirClamp * 2); 252 | saveNewReservoir(resv); 253 | 254 | giSample = resv.giSample; 255 | if (!resvInvalid(resv) && GISampleValid(giSample)) { 256 | vec3 primWi = normalize(giSample.xs - giSample.xv); 257 | primState.mat.albedo = vec3(1.0); 258 | 259 | indirect = giSample.L * BSDF(primState, primWo, giSample.nv, primWi) * satDot(giSample.nv, primWi) * 260 | bigWIndirect(resv, primState, primWo); 261 | 262 | //indirect = giSample.L / giSample.pHat * resv.weight / float(resv.num); 263 | //indirect *= BSDF(primState, primWo, giSample.nv, primWi) * absDot(giSample.nv, primWi); 264 | } 265 | vec3 res = clampRadiance(indirect); 266 | res = HDRToLDR(res); 267 | return res; 268 | } 269 | 270 | void main() { 271 | imageCoords = ivec2(gl_GlobalInvocationID.xy); 272 | if (!inBound(imageCoords, indSize())) { 273 | return; 274 | } 275 | ivec2 p00 = imageCoords * 2 + ivec2(0, 0); 276 | ivec2 p10 = imageCoords * 2 + ivec2(1, 0); 277 | ivec2 p11 = imageCoords * 2 + ivec2(1, 1); 278 | ivec2 p01 = imageCoords * 2 + ivec2(0, 1); 279 | 280 | prd.seed = tea(indSize().x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x, rtxState.time); 281 | Ray ray = raySpawn(imageCoords, indSize()); 282 | 283 | #if TILED_MULTIBOUNCE 284 | if (gl_LocalInvocationIndex == 0) { 285 | multiBounce = rand(prd.seed) < MultiBounceProb; 286 | } 287 | barrier(); 288 | #endif 289 | 290 | State state; 291 | float depth; 292 | if (!getIndirectStateFromGBuffer(thisGbuffer, ray, state, depth)) { 293 | imageStore(denoiseIndTempA, imageCoords, vec4(0.0)); 294 | return; 295 | } 296 | #if FETCH_GEOM_CHECK_4_SUBPIXELS 297 | state.position += state.ffnormal * 2e-2; 298 | #else 299 | state.position += state.ffnormal * 2e-2; 300 | #endif 301 | float primSamplePdf; vec3 primWo; State primState; GISample giSample; 302 | 303 | pathTraceIndirect(state, ray, primSamplePdf, primWo, primState, giSample); 304 | vec3 pixelColor = ReSTIRIndirect(depth, primSamplePdf, primWo, primState, giSample); 305 | 306 | pixelColor = clampRadiance(pixelColor); 307 | vec4 c00 = vec4(pixelColor, 1.0); 308 | imageStore(denoiseIndTempA, imageCoords, c00); 309 | } 310 | -------------------------------------------------------------------------------- /shaders/layouts.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | //------------------------------------------------------------------------------------------------- 21 | // This file holds the layout used by all ray tracing shaders 22 | 23 | 24 | #ifndef LAYOUTS_GLSL 25 | #define LAYOUTS_GLSL 1 26 | 27 | 28 | // C++ shared structures and binding 29 | #include "host_device.h" 30 | 31 | //---------------------------------------------- 32 | // Descriptor Set Layout 33 | //---------------------------------------------- 34 | 35 | 36 | // clang-format off 37 | layout(set = S_ACCEL, binding = eTlas) uniform accelerationStructureEXT topLevelAS; 38 | // 39 | layout(set = S_OUT, binding = eLastDirectResult) uniform readonly image2D lastDirectResultImage; 40 | layout(set = S_OUT, binding = eLastIndirectResult) uniform readonly image2D lastIndirectResultImage; 41 | 42 | layout(set = S_OUT, binding = eThisDirectResult) uniform image2D thisDirectResultImage; 43 | layout(set = S_OUT, binding = eThisIndirectResult) uniform image2D thisIndirectResultImage; 44 | // 45 | layout(set = S_SCENE, binding = eInstData, scalar) buffer _InstanceInfo { InstanceData geoInfo[]; }; 46 | layout(set = S_SCENE, binding = eCamera, scalar) uniform _SceneCamera { SceneCamera sceneCamera; }; 47 | layout(set = S_SCENE, binding = eMaterials, scalar) buffer _MaterialBuffer { GltfShadeMaterial materials[]; }; 48 | layout(set = S_SCENE, binding = ePuncLights,scalar) buffer _PuncLights { PuncLight puncLights[]; }; 49 | layout(set = S_SCENE, binding = eTrigLights,scalar) buffer _TrigLights { TrigLight trigLights[]; }; 50 | layout(set = S_SCENE, binding = eLightBufInfo ) uniform _LightBufInfo { LightBufInfo lightBufInfo; }; 51 | layout(set = S_SCENE, binding = eTextures ) uniform sampler2D texturesMap[]; 52 | // 53 | layout(set = S_ENV, binding = eSunSky, scalar) uniform _SSBuffer { SunAndSky _sunAndSky; }; 54 | layout(set = S_ENV, binding = eHdr) uniform sampler2D environmentTexture; 55 | layout(set = S_ENV, binding = eImpSamples, scalar) buffer _EnvSampBuffer { ImptSampData envSamplingData[]; }; 56 | 57 | layout(set = S_RAYQ, binding = eLastGbuffer) uniform readonly uimage2D lastGbuffer; 58 | layout(set = S_RAYQ, binding = eThisGbuffer) uniform uimage2D thisGbuffer; 59 | layout(set = S_RAYQ, binding = eMotionVector) uniform iimage2D motionVector; 60 | 61 | layout(set = S_RAYQ, binding = eLastDirectResv, scalar) buffer _LastDirectResv { DirectReservoir lastDirectResv[]; }; 62 | layout(set = S_RAYQ, binding = eThisDirectResv, scalar) buffer _ThisDirectResv { DirectReservoir thisDirectResv[]; }; 63 | layout(set = S_RAYQ, binding = eTempDirectResv, scalar) buffer _TempDirectResv { DirectReservoir tempDirectResv[]; }; 64 | 65 | layout(set = S_RAYQ, binding = eLastIndirectResv, scalar) buffer _LastIndirectResv { IndirectReservoir lastIndirectResv[]; }; 66 | layout(set = S_RAYQ, binding = eThisIndirectResv, scalar) buffer _ThisIndirectResv { IndirectReservoir thisIndirectResv[]; }; 67 | layout(set = S_RAYQ, binding = eTempIndirectResv, scalar) buffer _TempIndirectResv { IndirectReservoir tempIndirectResv[]; }; 68 | 69 | layout(set = S_RAYQ, binding = eDenoiseDirTempA) uniform image2D denoiseDirTempA; 70 | layout(set = S_RAYQ, binding = eDenoiseDirTempB) uniform image2D denoiseDirTempB; 71 | layout(set = S_RAYQ, binding = eDenoiseIndTempA) uniform image2D denoiseIndTempA; 72 | layout(set = S_RAYQ, binding = eDenoiseIndTempB) uniform image2D denoiseIndTempB; 73 | 74 | layout(buffer_reference, scalar) buffer Vertices { VertexAttributes v[]; }; 75 | layout(buffer_reference, scalar) buffer Indices { uvec3 i[]; }; 76 | 77 | // clang-format on 78 | 79 | 80 | #endif // LAYOUTS_GLSL 81 | -------------------------------------------------------------------------------- /shaders/passthrough.vert: -------------------------------------------------------------------------------- 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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | //------------------------------------------------------------------------------------------------- 21 | // Draw a triangle larger than the screen 22 | 23 | #version 450 24 | layout(location = 0) out vec2 v_texCoord; 25 | void main() 26 | { 27 | v_texCoord = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); 28 | gl_Position = vec4(v_texCoord * 2.0f - 1.0f, 1.0f, 1.0f); 29 | } 30 | -------------------------------------------------------------------------------- /shaders/pbr_metallicworkflow.glsl: -------------------------------------------------------------------------------- 1 | #ifndef PBR_METALLICWORKFLOW_GLSL 2 | #define PBR_METALLICWORKFLOW_GLSL 3 | 4 | #include "globals.glsl" 5 | #include "random.glsl" 6 | #include "common.glsl" 7 | 8 | const float Pi = M_PI; 9 | const float PiInv = 1.0 / Pi; 10 | 11 | mat3 localRefMatrix(vec3 n) { 12 | vec3 t = (abs(n.y) > 0.9999) ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); 13 | vec3 b = normalize(cross(n, t)); 14 | t = cross(b, n); 15 | return mat3(t, b, n); 16 | } 17 | 18 | vec3 localToWorld(vec3 n, vec3 v) { 19 | return normalize(localRefMatrix(n) * v); 20 | } 21 | 22 | vec3 sampleHemisphereCosine(vec3 n, vec2 r) { 23 | vec2 d = toConcentricDisk(r); 24 | float z = sqrt(1.0 - dot(d, d)); 25 | return localToWorld(n, vec3(d, z)); 26 | } 27 | 28 | float satDot(vec3 a, vec3 b) { 29 | return max(dot(a, b), 0.0); 30 | } 31 | 32 | float absDot(vec3 a, vec3 b) { 33 | return abs(dot(a, b)); 34 | } 35 | 36 | vec3 FresnelSchlick(float cosTheta, vec3 f0) { 37 | float cos4 = 1.0 - cosTheta; 38 | cos4 *= cos4; 39 | cos4 *= cos4; 40 | return mix(f0, vec3(1.0), cos4 * (1.0 - cosTheta)); 41 | } 42 | 43 | float SchlickG(float cosTheta, float alpha) { 44 | float a = alpha * 0.5; 45 | return cosTheta / (cosTheta * (1.0 - a) + a); 46 | } 47 | 48 | float SmithG(float cosWo, float cosWi, float alpha) { 49 | return SchlickG(abs(cosWo), alpha) * SchlickG(abs(cosWi), alpha); 50 | } 51 | 52 | float GTR2Distrib(float cosTheta, float alpha) { 53 | if (cosTheta < 1e-6) { 54 | return 0.0; 55 | } 56 | float aa = alpha * alpha; 57 | float nom = aa; 58 | float denom = cosTheta * cosTheta * (aa - 1.0) + 1.0; 59 | denom = denom * denom * Pi; 60 | return nom / denom; 61 | } 62 | 63 | float GTR2Pdf(vec3 n, vec3 m, vec3 wo, float alpha) { 64 | return GTR2Distrib(dot(n, m), alpha) * SchlickG(dot(n, wo), alpha) * absDot(m, wo) / absDot(n, wo); 65 | } 66 | 67 | vec3 GTR2Sample(vec3 n, vec3 wo, float alpha, vec2 r) { 68 | mat3 transMat = localRefMatrix(n); 69 | mat3 transInv = inverse(transMat); 70 | 71 | vec3 vh = normalize((transInv * wo) * vec3(alpha, alpha, 1.0)); 72 | 73 | float lenSq = vh.x * vh.x + vh.y * vh.y; 74 | vec3 t = lenSq > 0.0 ? vec3(-vh.y, vh.x, 0.0) / sqrt(lenSq) : vec3(1.0, 0.0, 0.0); 75 | vec3 b = cross(vh, t); 76 | 77 | vec2 p = toConcentricDisk(r); 78 | float s = 0.5 * (vh.z + 1.0); 79 | p.y = (1.0 - s) * sqrt(1.0 - p.x * p.x) + s * p.y; 80 | 81 | vec3 h = t * p.x + b * p.y + vh * sqrt(max(0.0, 1.0 - dot(p, p))); 82 | h = vec3(h.x * alpha, h.y * alpha, max(0.0, h.z)); 83 | return normalize(transMat * h); 84 | } 85 | 86 | vec3 metallicWorkflowBSDF(State state, vec3 n, vec3 wo, vec3 wi) { 87 | vec3 baseColor = state.mat.albedo; 88 | float roughness = state.mat.roughness; 89 | float metallic = state.mat.metallic; 90 | 91 | //float alpha = roughness * roughness; 92 | float alpha = roughness; 93 | vec3 h = normalize(wo + wi); 94 | 95 | float cosO = dot(n, wo); 96 | float cosI = dot(n, wi); 97 | if (cosI * cosO < 1e-7f) { 98 | return vec3(0.0); 99 | } 100 | 101 | vec3 f = FresnelSchlick(dot(h, wo), mix(vec3(.08f), baseColor, metallic)); 102 | float g = SmithG(cosO, cosI, alpha); 103 | float d = GTR2Distrib(dot(n, h), alpha); 104 | 105 | return mix(baseColor * PiInv * (1.0 - metallic), vec3(g * d / (4.0 * cosI * cosO)), f); 106 | } 107 | 108 | float metallicWorkflowPdf(State state, vec3 n, vec3 wo, vec3 wi) { 109 | vec3 baseColor = state.mat.albedo; 110 | float roughness = state.mat.roughness; 111 | float metallic = state.mat.metallic; 112 | //float alpha = roughness * roughness; 113 | float alpha = roughness; 114 | 115 | vec3 h = normalize(wo + wi); 116 | return mix( 117 | satDot(n, wi) * PiInv, 118 | GTR2Pdf(n, h, wo, alpha) / (4.0 * absDot(h, wo)), 119 | 1.0 / (2.0 - metallic) 120 | ); 121 | } 122 | 123 | vec3 metallicWorkflowEval(State state, vec3 n, vec3 wo, vec3 wi, out float pdf) { 124 | vec3 baseColor = state.mat.albedo; 125 | float roughness = state.mat.roughness; 126 | float metallic = state.mat.metallic; 127 | 128 | //float alpha = roughness * roughness; 129 | float alpha = roughness; 130 | vec3 h = normalize(wo + wi); 131 | 132 | float cosO = dot(n, wo); 133 | float cosI = dot(n, wi); 134 | if (cosI * cosO < 1e-7f) { 135 | return vec3(0.0); 136 | } 137 | 138 | vec3 f = FresnelSchlick(dot(h, wo), mix(vec3(.08f), baseColor, metallic)); 139 | float g = SmithG(cosO, cosI, alpha); 140 | float d = GTR2Distrib(dot(n, h), alpha); 141 | 142 | pdf = mix(satDot(n, wi) * PiInv, GTR2Pdf(n, h, wo, alpha) / (4.0 * absDot(h, wo)), 1.0 / (2.0 - metallic)); 143 | return mix(baseColor * PiInv * (1.0 - metallic), vec3(g * d / (4.0 * cosI * cosO)), f); 144 | } 145 | 146 | float metallicWorkflowSample(State state, vec3 n, vec3 wo, vec3 r, out vec3 bsdf, out vec3 dir) { 147 | float roughness = state.mat.roughness; 148 | float metallic = state.mat.metallic; 149 | //float alpha = roughness * roughness; 150 | float alpha = roughness; 151 | 152 | if (r.z > (1.0 / (2.0 - metallic))) { 153 | dir = sampleHemisphereCosine(n, r.xy); 154 | } 155 | else { 156 | vec3 h = GTR2Sample(n, wo, alpha, r.xy); 157 | dir = -reflect(wo, h); 158 | } 159 | 160 | if (dot(n, dir) < 0.0) { 161 | return InvalidPdf; 162 | } 163 | else { 164 | bsdf = metallicWorkflowBSDF(state, n, wo, dir); 165 | return metallicWorkflowPdf(state, n, wo, dir); 166 | } 167 | } 168 | 169 | vec3 metallicWorkflowSample(State state, vec3 n, vec3 wo, vec3 r, out vec3 dir, out float pdf) { 170 | vec3 bsdf; 171 | pdf = metallicWorkflowSample(state, n, wo, r, bsdf, dir); 172 | return bsdf; 173 | } 174 | 175 | #endif -------------------------------------------------------------------------------- /shaders/post.frag: -------------------------------------------------------------------------------- 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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | //------------------------------------------------------------------------------------------------- 21 | // This is called by the post process shader to display the result of ray tracing. 22 | // It applied a tonemapper and do dithering on the image to avoid banding. 23 | 24 | #version 450 25 | #extension GL_GOOGLE_include_directive : enable 26 | #extension GL_EXT_debug_printf : enable 27 | #extension GL_ARB_gpu_shader_int64 : enable // Shader reference 28 | 29 | #define TONEMAP_UNCHARTED 30 | #include "random.glsl" 31 | #include "compress.glsl" 32 | #include "tonemapping.glsl" 33 | #include "host_device.h" 34 | 35 | layout(location = 0) in vec2 uvCoords; 36 | layout(location = 0) out vec4 fragColor; 37 | 38 | layout(set = 0, binding = 0) uniform sampler2D inDirectImage; 39 | layout(set = 0, binding = 1) uniform sampler2D inIndirectImage; 40 | 41 | layout(push_constant) uniform _PushConstant { 42 | Tonemapper tm; 43 | int debugging_mode; 44 | }; 45 | 46 | vec2 indCoord; 47 | 48 | // http://www.thetenthplanet.de/archives/5367 49 | // Apply dithering to hide banding artifacts. 50 | vec3 dither(vec3 linear_color, vec3 noise, float quant) { 51 | vec3 c0 = floor(linearTosRGB(linear_color) / quant) * quant; 52 | vec3 c1 = c0 + quant; 53 | vec3 discr = mix(sRGBToLinear(c0), sRGBToLinear(c1), noise); 54 | return mix(c0, c1, lessThan(discr, linear_color)); 55 | } 56 | 57 | // http://user.ceng.metu.edu.tr/~akyuz/files/hdrgpu.pdf 58 | const mat3 RGB2XYZ = mat3(0.4124564, 0.3575761, 0.1804375, 0.2126729, 0.7151522, 0.0721750, 0.0193339, 0.1191920, 0.9503041); 59 | float luminance(vec3 color) { 60 | return dot(color, vec3(0.2126f, 0.7152f, 0.0722f)); //color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722; 61 | } 62 | 63 | vec3 toneExposure(vec3 RGB, float logAvgLum) { 64 | vec3 XYZ = RGB2XYZ * RGB; 65 | float Y = (tm.key / logAvgLum) * XYZ.y; 66 | float Yd = (Y * (1.0 + Y / (tm.Ywhite * tm.Ywhite))) / (1.0 + Y); 67 | return RGB / XYZ.y * Yd; 68 | } 69 | 70 | vec3 toneLocalExposure(vec3 RGB, float logAvgLum) { 71 | vec3 XYZ = RGB2XYZ * RGB; 72 | float Y = (tm.key / logAvgLum) * XYZ.y; 73 | float La; // local adaptation luminance 74 | float factor = tm.key / logAvgLum; 75 | float epsilon = 0.05, phi = 2.0; 76 | float scale[7] = float[7](1, 2, 4, 8, 16, 32, 64); 77 | for(int i = 0; i < 7; ++i) { 78 | float v1; 79 | if(debugging_mode == eDirectStage) 80 | v1 = luminance(texture(inDirectImage, uvCoords * tm.zoom, i).rgb) * factor; 81 | else if(debugging_mode == eIndirectStage) 82 | v1 = luminance(texture(inIndirectImage, indCoord * tm.zoom, i).rgb) * factor; 83 | else 84 | v1 = luminance(texture(inDirectImage, uvCoords * tm.zoom, i).rgb + texture(inIndirectImage, indCoord * tm.zoom, i).rgb) * factor; 85 | float v2; 86 | if(debugging_mode == eDirectStage) 87 | v2 = luminance(texture(inDirectImage, uvCoords * tm.zoom, i + 1).rgb) * factor; 88 | else if(debugging_mode == eIndirectStage) 89 | v2 = luminance(texture(inIndirectImage, indCoord * tm.zoom, i + 1).rgb) * factor; 90 | else 91 | v2 == luminance(texture(inDirectImage, uvCoords * tm.zoom, i + 1).rgb + texture(inDirectImage, indCoord * tm.zoom, i + 1).rgb) * factor; 92 | if(abs(v1 - v2) / ((tm.key * pow(2, phi) / (scale[i] * scale[i])) + v1) > epsilon) { 93 | La = v1; 94 | break; 95 | } else 96 | La = v2; 97 | } 98 | float Yd = Y / (1.0 + La); 99 | 100 | return RGB / XYZ.y * Yd; 101 | } 102 | 103 | void main() { 104 | indCoord = uvCoords; 105 | 106 | if (debugging_mode == eDepth){ 107 | float depth = texture(inDirectImage, uvCoords * tm.zoom).w; 108 | depth *= pow(2, tm.brightness); 109 | depth += tm.saturation; 110 | depth = clamp(pow(depth, 1.0 / tm.contrast), 0.f, 1.f); 111 | fragColor = vec4(depth, depth, depth, 1.0); 112 | } 113 | else if(debugging_mode > eIndirectStage) { 114 | vec3 color = texture(inDirectImage, indCoord * tm.zoom).xyz; 115 | if (debugging_mode == eBaseColor) 116 | color = clamp(pow(color, vec3(0.45454545454545)), 0, 1); 117 | fragColor = vec4(color, 1.0); 118 | } 119 | else { 120 | // Raw result of ray tracing 121 | vec4 hdr; 122 | if(debugging_mode == eDirectStage) { 123 | hdr = texture(inDirectImage, uvCoords * tm.zoom).rgba; 124 | } 125 | else if(debugging_mode == eIndirectStage) { 126 | hdr = texture(inIndirectImage, indCoord * tm.zoom).rgba; 127 | } 128 | else { 129 | hdr = texture(inDirectImage, uvCoords * tm.zoom).rgba + texture(inIndirectImage, indCoord * tm.zoom).rgba; 130 | } 131 | 132 | hdr.w = 1.0; 133 | if(((tm.autoExposure >> 0) & 1) == 1) { 134 | vec4 avg; // Get the average value of the image 135 | if(debugging_mode == eDirectStage) { 136 | avg = textureLod(inDirectImage, vec2(0.5), 20); 137 | } 138 | else if(debugging_mode == eIndirectStage) { 139 | avg = textureLod(inIndirectImage, vec2(0.5), 20); 140 | } 141 | else { 142 | avg = (textureLod(inDirectImage, vec2(0.5), 20) + textureLod(inIndirectImage, vec2(0.5), 20)); 143 | } 144 | avg.w = 1.0; 145 | float avgLum2 = luminance(avg.rgb); // Find the luminance 146 | if(((tm.autoExposure >> 1) & 1) == 1) { 147 | hdr.rgb = toneLocalExposure(hdr.rgb, avgLum2); // Adjust exposure 148 | } 149 | else { 150 | hdr.rgb = toneExposure(hdr.rgb, avgLum2); // Adjust exposure 151 | } 152 | } 153 | 154 | // Tonemap + Linear to sRgb 155 | vec3 color = toneMap(hdr.rgb, tm.avgLum); 156 | 157 | // Remove banding 158 | uvec3 r = pcg3d(uvec3(gl_FragCoord.xy, 0)); 159 | vec3 noise = uintBitsToFloat(0x3f800000 | (r >> 9)) - 1.0f; 160 | color = dither(sRGBToLinear(color), noise, 1. / 255.); 161 | 162 | //contrast 163 | color = clamp(mix(vec3(0.5), color, tm.contrast), 0, 1); 164 | // brighness 165 | color = pow(color, vec3(1.0 / tm.brightness)); 166 | // saturation 167 | vec3 i = vec3(dot(color, vec3(0.299, 0.587, 0.114))); 168 | color = mix(i, color, tm.saturation); 169 | // vignette 170 | vec2 uv = ((uvCoords * tm.renderingRatio) - 0.5) * 2.0; 171 | color *= 1.0 - dot(uv, uv) * tm.vignette; 172 | 173 | fragColor.xyz = color; 174 | fragColor.w = 1.0; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /shaders/punctual.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | //------------------------------------------------------------------------------------------------- 21 | // This file has functions for punctual lights 22 | 23 | #ifndef PUNCTUAL_GLSL 24 | #define PUNCTUAL_GLSL 25 | 26 | 27 | // https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_lights_punctual/README.md#range-property 28 | float getRangeAttenuation(float range, float distance) 29 | { 30 | if(range <= 0.0) 31 | { 32 | // negative range means unlimited 33 | return 1.0; 34 | } 35 | return max(min(1.0 - pow(distance / range, 4.0), 1.0), 0.0) / pow(distance, 2.0); 36 | } 37 | 38 | // https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_lights_punctual/README.md#inner-and-outer-cone-angles 39 | float getSpotAttenuation(vec3 pointToLight, vec3 spotDirection, float outerConeCos, float innerConeCos) 40 | { 41 | float actualCos = dot(normalize(spotDirection), normalize(-pointToLight)); 42 | if(actualCos > outerConeCos) 43 | { 44 | if(actualCos < innerConeCos) 45 | { 46 | return smoothstep(outerConeCos, innerConeCos, actualCos); 47 | } 48 | return 1.0; 49 | } 50 | return 0.0; 51 | } 52 | 53 | // vec3 getPunctualRadianceSubsurface(vec3 n, vec3 v, vec3 l, float scale, float distortion, float power, vec3 color, float thickness) 54 | // { 55 | // vec3 distortedHalfway = l + n * distortion; 56 | // float backIntensity = max(0.0, dot(v, -distortedHalfway)); 57 | // float reverseDiffuse = pow(clamp(0.0, 1.0, backIntensity), power) * scale; 58 | // return (reverseDiffuse + color) * (1.0 - thickness); 59 | // } 60 | 61 | // vec3 getPunctualRadianceTransmission(vec3 n, vec3 v, vec3 l, float alphaRoughness, float ior, vec3 f0) 62 | // { 63 | // vec3 r = refract(-v, n, 1.0 / ior); 64 | // vec3 h = normalize(l - r); 65 | // float NdotL = clampedDot(-n, l); 66 | // float NdotV = clampedDot(n, -r); 67 | 68 | // float Vis = V_GGX(clampedDot(-n, l), NdotV, alphaRoughness); 69 | // float D = D_GGX(clampedDot(r, l), alphaRoughness); 70 | 71 | // return NdotL * f0 * Vis * D; 72 | // } 73 | 74 | // vec3 getPunctualRadianceClearCoat(vec3 clearcoatNormal, vec3 v, vec3 l, vec3 h, float VdotH, vec3 f0, vec3 f90, float clearcoatRoughness) 75 | // { 76 | // float NdotL = clampedDot(clearcoatNormal, l); 77 | // float NdotV = clampedDot(clearcoatNormal, v); 78 | // float NdotH = clampedDot(clearcoatNormal, h); 79 | // return NdotL * BRDF_specularGGX(f0, f90, clearcoatRoughness * clearcoatRoughness, VdotH, NdotL, NdotV, NdotH); 80 | // } 81 | 82 | // vec3 getPunctualRadianceSheen(vec3 sheenColor, float sheenIntensity, float sheenRoughness, float NdotL, float NdotV, float NdotH) 83 | // { 84 | // return NdotL * BRDF_specularSheen(sheenColor, sheenIntensity, sheenRoughness, NdotL, NdotV, NdotH); 85 | // } 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /shaders/random.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | //------------------------------------------------------------------------------------------------- 21 | // This file has random functions. 22 | // Usage: 23 | // - initialize the seed using tea(), with a value that is different for each pixel and each frame. 24 | // - use rnd() with the seed 25 | 26 | #ifndef RANDOM_GLSL 27 | #define RANDOM_GLSL 1 28 | 29 | //----------------------------------------------------------------------- 30 | // Generate a random unsigned int from two unsigned int values, using 16 pairs 31 | // of rounds of the Tiny Encryption Algorithm. See Zafar, Olano, and Curtis, 32 | // "GPU Random Numbers via the Tiny Encryption Algorithm" 33 | //----------------------------------------------------------------------- 34 | uint tea(in uint val0, in uint val1) 35 | { 36 | uint v0 = val0; 37 | uint v1 = val1; 38 | uint s0 = 0; 39 | 40 | for(uint n = 0; n < 16; n++) 41 | { 42 | s0 += 0x9e3779b9; 43 | v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4); 44 | v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e); 45 | } 46 | 47 | return v0; 48 | } 49 | 50 | uint initRandom(in uvec2 resolution, in uvec2 screenCoord, in uint frame) 51 | { 52 | return tea(screenCoord.y * resolution.x + screenCoord.x, frame); 53 | } 54 | 55 | 56 | //----------------------------------------------------------------------- 57 | // https://www.pcg-random.org/ 58 | //----------------------------------------------------------------------- 59 | uint pcg(inout uint state) 60 | { 61 | uint prev = state * 747796405u + 2891336453u; 62 | uint word = ((prev >> ((prev >> 28u) + 4u)) ^ prev) * 277803737u; 63 | state = prev; 64 | return (word >> 22u) ^ word; 65 | } 66 | 67 | //----------------------------------------------------------------------- 68 | //----------------------------------------------------------------------- 69 | uvec2 pcg2d(uvec2 v) 70 | { 71 | v = v * 1664525u + 1013904223u; 72 | v.x += v.y * 1664525u; 73 | v.y += v.x * 1664525u; 74 | v = v ^ (v >> 16u); 75 | v.x += v.y * 1664525u; 76 | v.y += v.x * 1664525u; 77 | v = v ^ (v >> 16u); 78 | return v; 79 | } 80 | 81 | uvec3 pcg3d(uvec3 v) 82 | { 83 | v = v * 1664525u + uvec3(1013904223u); 84 | v.x += v.y * v.z; 85 | v.y += v.z * v.x; 86 | v.z += v.x * v.y; 87 | v ^= v >> uvec3(16u); 88 | v.x += v.y * v.z; 89 | v.y += v.z * v.x; 90 | v.z += v.x * v.y; 91 | return v; 92 | } 93 | 94 | 95 | //----------------------------------------------------------------------- 96 | // Generate a random float in [0, 1) given the previous RNG state 97 | //----------------------------------------------------------------------- 98 | float rand(inout uint seed) 99 | { 100 | uint r = pcg(seed); 101 | return uintBitsToFloat(0x3f800000 | (r >> 9)) - 1.0f; 102 | } 103 | 104 | vec2 rand2(inout uint prev) 105 | { 106 | return vec2(rand(prev), rand(prev)); 107 | } 108 | 109 | #endif // RANDOM_GLSL 110 | -------------------------------------------------------------------------------- /shaders/reservoir.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RESERVOIR_GLSL 2 | #define RESERVOIR_GLSL 3 | 4 | #include "host_device.h" 5 | 6 | float resvToScalar(vec3 x) { 7 | //return length(x); 8 | return luminance(x); 9 | } 10 | 11 | void resvReset(inout DirectReservoir resv) { 12 | resv.num = 0; 13 | resv.weight = 0; 14 | } 15 | 16 | void resvReset(inout IndirectReservoir resv) { 17 | resv.num = 0; 18 | resv.weight = 0; 19 | resv.bigW = 0; 20 | } 21 | 22 | void resvUpdateBigW(inout IndirectReservoir resv, float pHat) { 23 | resv.bigW = resv.weight / (float(resv.num) * pHat); 24 | } 25 | 26 | bool resvInvalid(DirectReservoir resv) { 27 | return isnan(resv.weight) || resv.weight < 0.0; 28 | } 29 | 30 | bool resvInvalid(IndirectReservoir resv) { 31 | return isnan(resv.weight) || resv.weight < 0.0; 32 | } 33 | 34 | void resvCheckValidity(inout DirectReservoir resv) { 35 | if (resvInvalid(resv)) { 36 | resvReset(resv); 37 | } 38 | } 39 | 40 | void resvCheckValidity(inout IndirectReservoir resv) { 41 | if (resvInvalid(resv)) { 42 | resvReset(resv); 43 | } 44 | } 45 | 46 | void resvUpdate(inout DirectReservoir resv, LightSample newSample, float newWeight, float r) { 47 | resv.weight += newWeight; 48 | resv.num += 1; 49 | if (r * resv.weight < newWeight) { 50 | resv.lightSample = newSample; 51 | } 52 | } 53 | 54 | void resvUpdate(inout IndirectReservoir resv, GISample newSample, float newWeight, float r) { 55 | resv.weight += newWeight; 56 | resv.num += 1; 57 | if (r * resv.weight < newWeight) { 58 | resv.giSample = newSample; 59 | } 60 | } 61 | 62 | void resvMerge(inout IndirectReservoir resv, IndirectReservoir rhs, float pHat, float r) { 63 | uint num = resv.num; 64 | resvUpdate(resv, rhs.giSample, pHat * rhs.bigW * float(rhs.num), r); 65 | resv.num = num + rhs.num; 66 | } 67 | 68 | void resvMerge(inout DirectReservoir resv, DirectReservoir rhs, float r) { 69 | resv.weight += rhs.weight; 70 | resv.num += rhs.num; 71 | if (r * resv.weight < rhs.weight) { 72 | resv.lightSample = rhs.lightSample; 73 | } 74 | } 75 | 76 | void resvMerge(inout IndirectReservoir resv, IndirectReservoir rhs, float r) { 77 | resv.weight += rhs.weight; 78 | resv.num += rhs.num; 79 | if (r * resv.weight < rhs.weight) { 80 | resv.giSample = rhs.giSample; 81 | } 82 | } 83 | 84 | void resvPreClampedMerge(inout DirectReservoir resv, DirectReservoir rhs, float r, int clamp) { 85 | if (rhs.num > 0 && resv.num > 0 && rhs.num > (clamp - 1) * resv.num) { 86 | rhs.weight *= float(clamp - 1) * float(resv.num) / float(rhs.num); 87 | rhs.num = (clamp - 1) * resv.num; 88 | } 89 | resvMerge(resv, rhs, r); 90 | } 91 | 92 | void resvPreClampedMerge(inout IndirectReservoir resv, IndirectReservoir rhs, float r, int clamp) { 93 | if (rhs.num > 0 && resv.num > 0 && rhs.num > (clamp - 1) * resv.num) { 94 | rhs.weight *= float(clamp - 1) * float(resv.num) / float(rhs.num); 95 | rhs.num = (clamp - 1) * resv.num; 96 | } 97 | resvMerge(resv, rhs, r); 98 | } 99 | 100 | void resvPreClampedMerge20(inout DirectReservoir resv, DirectReservoir rhs, float r) { 101 | if (rhs.num > 0 && resv.num > 0 && rhs.num > 19 * resv.num) { 102 | rhs.weight *= float(19) * float(resv.num) / float(rhs.num); 103 | rhs.num = 19 * resv.num; 104 | } 105 | resvMerge(resv, rhs, r); 106 | } 107 | 108 | void resvPreClampedMerge20(inout IndirectReservoir resv, IndirectReservoir rhs, float r) { 109 | if (rhs.num > 0 && resv.num > 0 && rhs.num > 19 * resv.num) { 110 | rhs.weight *= float(19) * float(resv.num) / float(rhs.num); 111 | rhs.num = 19 * resv.num; 112 | } 113 | resvMerge(resv, rhs, r); 114 | } 115 | 116 | void resvClamp(inout DirectReservoir resv, int clamp) { 117 | if (resv.num > clamp) { 118 | resv.weight *= float(clamp) / float(resv.num); 119 | resv.num = clamp; 120 | } 121 | } 122 | 123 | void resvClamp(inout IndirectReservoir resv, int clamp) { 124 | if (resv.num > clamp) { 125 | resv.weight *= float(clamp) / float(resv.num); 126 | resv.num = clamp; 127 | } 128 | } 129 | 130 | // 32bit Li, 32bit direction, 24bit weight, 16bit num, 24bit dist 131 | // untested 132 | // uvec4 encodeReservoir(DirectReservoir resv) { 133 | // uvec4 pack; 134 | // resv.num = resv.num & 0xFFFF; 135 | // pack.x = packUnormYCbCr(resv.lightSample.Li); 136 | // pack.y = compress_unit_vec(resv.lightSample.wi); 137 | // pack.z = resv.num >> 8; 138 | // pack.z += floatBitsToUint(resv.weight) & 0xFFFFFF00; 139 | // pack.w = resv.num << 24; 140 | // pack.w += floatBitsToUint(resv.lightSample.dist) >> 8; 141 | // return pack; 142 | // } 143 | 144 | // DirectReservoir decodeReservoir(uvec4 pack) { 145 | // DirectReservoir resv; 146 | // resv.lightSample.Li = unpackUnormYCbCr(pack.x); 147 | // resv.lightSample.wi = decompress_unit_vec(pack.y); 148 | // resv.weight = uintBitsToFloat(pack.z & 0xFFFFFF00); 149 | // resv.lightSample.dist = uintBitsToFloat(pack.w << 8); 150 | // resv.num = (pack.z & 0xFF) + (pack.w >> 24); 151 | // return resv; 152 | // } 153 | 154 | #endif 155 | -------------------------------------------------------------------------------- /shaders/shade_state.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | //------------------------------------------------------------------------------------------------- 21 | // This file finds the geometric information used for shader. 22 | // From the payload (hit information), retrive the position, normal, uv, .. 23 | 24 | #ifndef SHADE_STATE_GLSL 25 | #define SHADE_STATE_GLSL 26 | 27 | 28 | #include "compress.glsl" 29 | #include "layouts.glsl" 30 | 31 | //----------------------------------------------------------------------- 32 | // Return the tangent and binormal from the incoming normal 33 | //----------------------------------------------------------------------- 34 | void CreateTangent(in vec3 N, out vec3 Nt, out vec3 Nb) 35 | { 36 | Nt = normalize(((abs(N.z) > 0.99999f) ? vec3(-N.x * N.y, 1.0f - N.y * N.y, -N.y * N.z) : 37 | vec3(-N.x * N.z, -N.y * N.z, 1.0f - N.z * N.z))); 38 | Nb = cross(Nt, N); 39 | } 40 | 41 | 42 | // Shading information used by the material 43 | struct ShadeState 44 | { 45 | vec3 normal; 46 | vec3 geom_normal; 47 | vec3 position; 48 | vec2 text_coords[1]; 49 | vec3 tangent_u[1]; 50 | vec3 tangent_v[1]; 51 | vec3 color; 52 | uint matIndex; 53 | }; 54 | 55 | /// Resetting the LSB of the V component (used by tangent handiness) 56 | vec2 decode_texture(vec2 t) 57 | { 58 | return vec2(t.x, uintBitsToFloat(floatBitsToUint(t.y) & ~1)); 59 | } 60 | 61 | //----------------------------------------------------------------------- 62 | //----------------------------------------------------------------------- 63 | ShadeState GetShadeState(in PtPayload hstate) 64 | { 65 | ShadeState sstate; 66 | 67 | const uint idGeo = hstate.instanceCustomIndex; // Geometry of this instance 68 | const uint idPrim = hstate.primitiveID; // Triangle ID 69 | const vec3 bary = vec3(1.0 - hstate.baryCoord.x - hstate.baryCoord.y, hstate.baryCoord.x, hstate.baryCoord.y); 70 | 71 | // Primitive buffer addresses 72 | Indices indices = Indices(geoInfo[idGeo].indexAddress); 73 | Vertices vertices = Vertices(geoInfo[idGeo].vertexAddress); 74 | 75 | // Indices of this triangle primitive. 76 | uvec3 tri = indices.i[idPrim]; 77 | 78 | // All vertex attributes of the triangle. 79 | VertexAttributes attr0 = vertices.v[tri.x]; 80 | VertexAttributes attr1 = vertices.v[tri.y]; 81 | VertexAttributes attr2 = vertices.v[tri.z]; 82 | 83 | // Getting the material index on this geometry 84 | const uint matIndex = max(0, geoInfo[idGeo].materialIndex); // material of primitive mesh 85 | 86 | // Vertex of the triangle 87 | const vec3 pos0 = attr0.position.xyz; 88 | const vec3 pos1 = attr1.position.xyz; 89 | const vec3 pos2 = attr2.position.xyz; 90 | const vec3 position = pos0 * bary.x + pos1 * bary.y + pos2 * bary.z; 91 | const vec3 world_position = vec3(hstate.objectToWorld * vec4(position, 1.0)); 92 | 93 | // Normal 94 | vec3 nrm0 = decompress_unit_vec(attr0.normal); 95 | vec3 nrm1 = decompress_unit_vec(attr1.normal); 96 | vec3 nrm2 = decompress_unit_vec(attr2.normal); 97 | vec3 normal = normalize(nrm0 * bary.x + nrm1 * bary.y + nrm2 * bary.z); 98 | vec3 world_normal = normalize(vec3(normal * hstate.worldToObject)); 99 | vec3 geom_normal = normalize(cross(pos1 - pos0, pos2 - pos0)); 100 | vec3 wgeom_normal = normalize(vec3(geom_normal * hstate.worldToObject)); 101 | 102 | // Tangent and Binormal 103 | float h0 = (floatBitsToInt(attr0.texcoord.y) & 1) == 1 ? 1.0f : -1.0f; // Handiness stored in the less 104 | float h1 = (floatBitsToInt(attr1.texcoord.y) & 1) == 1 ? 1.0f : -1.0f; // significative bit of the 105 | float h2 = (floatBitsToInt(attr2.texcoord.y) & 1) == 1 ? 1.0f : -1.0f; // texture coord V 106 | 107 | const vec4 tng0 = vec4(decompress_unit_vec(attr0.tangent.x), h0); 108 | const vec4 tng1 = vec4(decompress_unit_vec(attr1.tangent.x), h1); 109 | const vec4 tng2 = vec4(decompress_unit_vec(attr2.tangent.x), h2); 110 | vec3 tangent = (tng0.xyz * bary.x + tng1.xyz * bary.y + tng2.xyz * bary.z); 111 | tangent.xyz = normalize(tangent.xyz); 112 | vec3 world_tangent = normalize(vec3(mat4(hstate.objectToWorld) * vec4(tangent.xyz, 0))); 113 | world_tangent = normalize(world_tangent - dot(world_tangent, world_normal) * world_normal); 114 | vec3 world_binormal = cross(world_normal, world_tangent) * tng0.w; 115 | 116 | // TexCoord 117 | 118 | const vec2 uv0 = decode_texture(attr0.texcoord); 119 | const vec2 uv1 = decode_texture(attr1.texcoord); 120 | const vec2 uv2 = decode_texture(attr2.texcoord); 121 | const vec2 texcoord0 = uv0 * bary.x + uv1 * bary.y + uv2 * bary.z; 122 | 123 | // Colors 124 | const vec4 col0 = unpackUnorm4x8(attr0.color); // RGBA in uint to 4 x float 125 | const vec4 col1 = unpackUnorm4x8(attr1.color); 126 | const vec4 col2 = unpackUnorm4x8(attr2.color); 127 | const vec4 color = col0 * bary.x + col1 * bary.y + col2 * bary.z; 128 | 129 | sstate.normal = world_normal; 130 | sstate.geom_normal = wgeom_normal; 131 | sstate.position = world_position; 132 | sstate.text_coords[0] = texcoord0; 133 | sstate.tangent_u[0] = world_tangent; 134 | sstate.tangent_v[0] = world_binormal; 135 | sstate.color = color.rgb; 136 | sstate.matIndex = matIndex; 137 | 138 | // Move normal to same side as geometric normal 139 | if(dot(sstate.normal, sstate.geom_normal) <= 0) 140 | { 141 | sstate.normal *= -1.0f; 142 | } 143 | 144 | return sstate; 145 | } 146 | 147 | State GetState(PtPayload hstate, vec3 rayDir) 148 | { 149 | State state; 150 | 151 | const uint idGeo = hstate.instanceCustomIndex; // Geometry of this instance 152 | const uint idPrim = hstate.primitiveID; // Triangle ID 153 | const vec3 bary = vec3(1.0 - hstate.baryCoord.x - hstate.baryCoord.y, hstate.baryCoord.x, hstate.baryCoord.y); 154 | 155 | // Primitive buffer addresses 156 | Indices indices = Indices(geoInfo[idGeo].indexAddress); 157 | Vertices vertices = Vertices(geoInfo[idGeo].vertexAddress); 158 | 159 | // Indices of this triangle primitive. 160 | uvec3 tri = indices.i[idPrim]; 161 | 162 | // All vertex attributes of the triangle. 163 | VertexAttributes attr0 = vertices.v[tri.x]; 164 | VertexAttributes attr1 = vertices.v[tri.y]; 165 | VertexAttributes attr2 = vertices.v[tri.z]; 166 | 167 | // Getting the material index on this geometry 168 | const uint matIndex = max(0, geoInfo[idGeo].materialIndex); // material of primitive mesh 169 | 170 | // Vertex of the triangle 171 | const vec3 pos0 = attr0.position.xyz; 172 | const vec3 pos1 = attr1.position.xyz; 173 | const vec3 pos2 = attr2.position.xyz; 174 | const vec3 position = pos0 * bary.x + pos1 * bary.y + pos2 * bary.z; 175 | const vec3 world_position = vec3(hstate.objectToWorld * vec4(position, 1.0)); 176 | 177 | vec3 wpos0 = vec3(hstate.objectToWorld * vec4(pos0, 1.0)); 178 | vec3 wpos1 = vec3(hstate.objectToWorld * vec4(pos1, 1.0)); 179 | vec3 wpos2 = vec3(hstate.objectToWorld * vec4(pos2, 1.0)); 180 | 181 | // Normal 182 | vec3 nrm0 = decompress_unit_vec(attr0.normal); 183 | vec3 nrm1 = decompress_unit_vec(attr1.normal); 184 | vec3 nrm2 = decompress_unit_vec(attr2.normal); 185 | vec3 normal = normalize(nrm0 * bary.x + nrm1 * bary.y + nrm2 * bary.z); 186 | vec3 world_normal = normalize(vec3(normal * hstate.worldToObject)); 187 | vec3 geom_normal = normalize(cross(pos1 - pos0, pos2 - pos0)); 188 | vec3 wgeom_normal = normalize(vec3(geom_normal * hstate.worldToObject)); 189 | 190 | // Tangent and Binormal 191 | float h0 = (floatBitsToInt(attr0.texcoord.y) & 1) == 1 ? 1.0f : -1.0f; // Handiness stored in the less 192 | float h1 = (floatBitsToInt(attr1.texcoord.y) & 1) == 1 ? 1.0f : -1.0f; // significative bit of the 193 | float h2 = (floatBitsToInt(attr2.texcoord.y) & 1) == 1 ? 1.0f : -1.0f; // texture coord V 194 | 195 | const vec4 tng0 = vec4(decompress_unit_vec(attr0.tangent.x), h0); 196 | const vec4 tng1 = vec4(decompress_unit_vec(attr1.tangent.x), h1); 197 | const vec4 tng2 = vec4(decompress_unit_vec(attr2.tangent.x), h2); 198 | vec3 tangent = (tng0.xyz * bary.x + tng1.xyz * bary.y + tng2.xyz * bary.z); 199 | tangent.xyz = normalize(tangent.xyz); 200 | vec3 world_tangent = normalize(vec3(mat4(hstate.objectToWorld) * vec4(tangent.xyz, 0))); 201 | world_tangent = normalize(world_tangent - dot(world_tangent, world_normal) * world_normal); 202 | vec3 world_binormal = cross(world_normal, world_tangent) * tng0.w; 203 | 204 | // TexCoord 205 | 206 | const vec2 uv0 = decode_texture(attr0.texcoord); 207 | const vec2 uv1 = decode_texture(attr1.texcoord); 208 | const vec2 uv2 = decode_texture(attr2.texcoord); 209 | const vec2 texcoord0 = uv0 * bary.x + uv1 * bary.y + uv2 * bary.z; 210 | 211 | state.position = world_position; 212 | state.normal = (dot(world_normal, wgeom_normal) > 0.0) ? world_normal : -world_normal; 213 | state.ffnormal = dot(state.normal, rayDir) <= 0.0 ? state.normal : -state.normal; 214 | state.texCoord = texcoord0; 215 | state.tangent = world_tangent; 216 | state.bitangent = world_binormal; 217 | state.matID = matIndex; 218 | state.area = length(cross(wpos1 - wpos0, wpos2 - wpos0)) * 0.5; 219 | 220 | return state; 221 | } 222 | 223 | #endif // SHADE_STATE_GLSL 224 | -------------------------------------------------------------------------------- /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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | //------------------------------------------------------------------------------------------------- 21 | // Functions implementing various tonemappers 22 | // 23 | 24 | const float GAMMA = 2.2; 25 | const float INV_GAMMA = 1.0 / GAMMA; 26 | 27 | // linear to sRGB approximation 28 | // see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html 29 | vec3 linearTosRGB(vec3 color) 30 | { 31 | return pow(color, vec3(INV_GAMMA)); 32 | } 33 | 34 | // sRGB to linear approximation 35 | // see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html 36 | vec3 sRGBToLinear(vec3 srgbIn) 37 | { 38 | return vec3(pow(srgbIn.xyz, vec3(GAMMA))); 39 | } 40 | 41 | vec4 sRGBToLinear(vec4 srgbIn) 42 | { 43 | return vec4(sRGBToLinear(srgbIn.xyz), srgbIn.w); 44 | } 45 | 46 | // Uncharted 2 tone map 47 | // see: http://filmicworlds.com/blog/filmic-tonemapping-operators/ 48 | vec3 toneMapUncharted2Impl(vec3 color) 49 | { 50 | const float A = 0.15; 51 | const float B = 0.50; 52 | const float C = 0.10; 53 | const float D = 0.20; 54 | const float E = 0.02; 55 | const float F = 0.30; 56 | return ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F; 57 | } 58 | 59 | vec3 toneMapUncharted(vec3 color) 60 | { 61 | const float W = 11.2; 62 | color = toneMapUncharted2Impl(color * 2.0); 63 | vec3 whiteScale = 1.0 / toneMapUncharted2Impl(vec3(W)); 64 | return linearTosRGB(color * whiteScale); 65 | } 66 | 67 | // Hejl Richard tone map 68 | // see: http://filmicworlds.com/blog/filmic-tonemapping-operators/ 69 | vec3 toneMapHejlRichard(vec3 color) 70 | { 71 | color = max(vec3(0.0), color - vec3(0.004)); 72 | return (color * (6.2 * color + .5)) / (color * (6.2 * color + 1.7) + 0.06); 73 | } 74 | 75 | // ACES tone map 76 | // see: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ 77 | vec3 toneMapACES(vec3 color) 78 | { 79 | const float A = 2.51; 80 | const float B = 0.03; 81 | const float C = 2.43; 82 | const float D = 0.59; 83 | const float E = 0.14; 84 | return linearTosRGB(clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0)); 85 | } 86 | 87 | 88 | vec3 toneMap(vec3 color, float u_Exposure) 89 | { 90 | color *= u_Exposure; 91 | 92 | #ifdef TONEMAP_UNCHARTED 93 | return toneMapUncharted(color); 94 | #endif 95 | 96 | #ifdef TONEMAP_HEJLRICHARD 97 | return toneMapHejlRichard(color); 98 | #endif 99 | 100 | #ifdef TONEMAP_ACES 101 | return toneMapACES(color); 102 | #endif 103 | 104 | return linearTosRGB(color); 105 | } 106 | -------------------------------------------------------------------------------- /shaders/traceray_rq.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | //------------------------------------------------------------------------------------------------- 22 | // This file has the Ray Query functions for Closest-Hit and Any-Hit shader. 23 | // The RTX pipeline implementation of thoses functions are in traceray_rtx. 24 | // This is used in pathtrace.glsl (Ray-Generation shader) 25 | 26 | #include "shade_state.glsl" 27 | 28 | //---------------------------------------------------------- 29 | // Testing if the hit is opaque or alpha-transparent 30 | // Return true is opaque 31 | //---------------------------------------------------------- 32 | bool HitTest(in rayQueryEXT rayQuery, in Ray r) 33 | { 34 | int InstanceCustomIndexEXT = rayQueryGetIntersectionInstanceCustomIndexEXT(rayQuery, false); 35 | int PrimitiveID = rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, false); 36 | 37 | // Retrieve the Primitive mesh buffer information 38 | InstanceData pinfo = geoInfo[InstanceCustomIndexEXT]; 39 | const uint matIndex = max(0, pinfo.materialIndex); // material of primitive mesh 40 | GltfShadeMaterial mat = materials[matIndex]; 41 | 42 | //// Back face culling defined by material 43 | //bool front_face = rayQueryGetIntersectionFrontFaceEXT(rayQuery, false); 44 | //if(mat.doubleSided == 0 && front_face == false) 45 | //{ 46 | // return false; 47 | //} 48 | 49 | //// Early out if there is no opacity function 50 | //if(mat.alphaMode == ALPHA_OPAQUE) 51 | //{ 52 | // return true; 53 | //} 54 | 55 | float baseColorAlpha = mat.pbrBaseColorFactor.a; 56 | if(mat.pbrBaseColorTexture > -1) 57 | { 58 | const uint idGeo = InstanceCustomIndexEXT; // Geometry of this instance 59 | const uint idPrim = PrimitiveID; // Triangle ID 60 | 61 | // Primitive buffer addresses 62 | Indices indices = Indices(geoInfo[idGeo].indexAddress); 63 | Vertices vertices = Vertices(geoInfo[idGeo].vertexAddress); 64 | 65 | // Indices of this triangle primitive. 66 | uvec3 tri = indices.i[idPrim]; 67 | 68 | // All vertex attributes of the triangle. 69 | VertexAttributes attr0 = vertices.v[tri.x]; 70 | VertexAttributes attr1 = vertices.v[tri.y]; 71 | VertexAttributes attr2 = vertices.v[tri.z]; 72 | 73 | // Get the texture coordinate 74 | vec2 bary = rayQueryGetIntersectionBarycentricsEXT(rayQuery, false); 75 | const vec3 barycentrics = vec3(1.0 - bary.x - bary.y, bary.x, bary.y); 76 | const vec2 uv0 = attr0.texcoord; 77 | const vec2 uv1 = attr1.texcoord; 78 | const vec2 uv2 = attr2.texcoord; 79 | vec2 texcoord0 = uv0 * barycentrics.x + uv1 * barycentrics.y + uv2 * barycentrics.z; 80 | 81 | // Uv Transform 82 | texcoord0 = texcoord0.xy; 83 | 84 | baseColorAlpha *= texture(texturesMap[nonuniformEXT(mat.pbrBaseColorTexture)], texcoord0).a; 85 | } 86 | 87 | float opacity; 88 | if(mat.alphaMode == ALPHA_MASK) 89 | { 90 | opacity = baseColorAlpha > mat.alphaCutoff ? 1.0 : 0.0; 91 | } 92 | else 93 | { 94 | opacity = baseColorAlpha; 95 | } 96 | 97 | // do alpha blending the stochastically way 98 | if(rand(prd.seed) > opacity) 99 | return false; 100 | 101 | return true; 102 | } 103 | 104 | //----------------------------------------------------------------------- 105 | // Shoot a ray and return the information of the closest hit, in the 106 | // PtPayload structure (PRD) 107 | // 108 | void ClosestHit(Ray r) 109 | { 110 | uint rayFlags = gl_RayFlagsCullBackFacingTrianglesEXT; // gl_RayFlagsNoneEXT 111 | prd.hitT = INFINITY; 112 | 113 | // Initializes a ray query object but does not start traversal 114 | rayQueryEXT rayQuery; 115 | rayQueryInitializeEXT(rayQuery, // 116 | topLevelAS, // acceleration structure 117 | rayFlags, // rayFlags 118 | 0xFF, // cullMask 119 | r.origin, // ray origin 120 | 0.0, // ray min range 121 | r.direction, // ray direction 122 | INFINITY); // ray max range 123 | 124 | // Start traversal: return false if traversal is complete 125 | while(rayQueryProceedEXT(rayQuery)) 126 | { 127 | if(rayQueryGetIntersectionTypeEXT(rayQuery, false) == gl_RayQueryCandidateIntersectionTriangleEXT) 128 | { 129 | if(HitTest(rayQuery, r)) 130 | { 131 | rayQueryConfirmIntersectionEXT(rayQuery); // The hit was opaque 132 | } 133 | } 134 | } 135 | 136 | bool hit = (rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT); 137 | if(hit) 138 | { 139 | prd.hitT = rayQueryGetIntersectionTEXT(rayQuery, true); 140 | prd.primitiveID = rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true); 141 | prd.instanceID = rayQueryGetIntersectionInstanceIdEXT(rayQuery, true); 142 | prd.instanceCustomIndex = rayQueryGetIntersectionInstanceCustomIndexEXT(rayQuery, true); 143 | prd.baryCoord = rayQueryGetIntersectionBarycentricsEXT(rayQuery, true); 144 | prd.objectToWorld = rayQueryGetIntersectionObjectToWorldEXT(rayQuery, true); 145 | prd.worldToObject = rayQueryGetIntersectionWorldToObjectEXT(rayQuery, true); 146 | } 147 | } 148 | 149 | 150 | //----------------------------------------------------------------------- 151 | // Shadow ray - return true if a ray hits anything 152 | // 153 | bool AnyHit(Ray r, float maxDist) 154 | { 155 | shadow_payload.isHit = true; // Asume hit, will be set to false if hit nothing (miss shader) 156 | shadow_payload.seed = prd.seed; // don't care for the update - but won't affect the rahit shader 157 | uint rayFlags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT | gl_RayFlagsCullBackFacingTrianglesEXT; 158 | 159 | // Initializes a ray query object but does not start traversal 160 | rayQueryEXT rayQuery; 161 | rayQueryInitializeEXT(rayQuery, // 162 | topLevelAS, // acceleration structure 163 | rayFlags, // rayFlags 164 | 0xFF, // cullMask 165 | r.origin, // ray origin 166 | 0.0, // ray min range 167 | r.direction, // ray direction 168 | maxDist); // ray max range 169 | 170 | // Start traversal: return false if traversal is complete 171 | while(rayQueryProceedEXT(rayQuery)) 172 | { 173 | if(rayQueryGetIntersectionTypeEXT(rayQuery, false) == gl_RayQueryCandidateIntersectionTriangleEXT) 174 | { 175 | if(HitTest(rayQuery, r)) 176 | { 177 | rayQueryConfirmIntersectionEXT(rayQuery); // The hit was opaque 178 | } 179 | } 180 | } 181 | 182 | 183 | // add to ray contribution from next event estimation 184 | return (rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT); 185 | } 186 | -------------------------------------------------------------------------------- /src/accelstruct.cpp: -------------------------------------------------------------------------------- 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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | /* 22 | * The Acceleration structure class will holds the scene made of BLASes an TLASes. 23 | * - It expect a scene in a format of GltfScene 24 | * - Each glTF primitive mesh will be in a separate BLAS 25 | * - All BLASes are using one single Hit shader 26 | * - It creates a descriptorSet holding the TLAS 27 | * 28 | */ 29 | 30 | 31 | #include "accelstruct.hpp" 32 | #include "nvvk/raytraceKHR_vk.hpp" 33 | #include "shaders/host_device.h" 34 | #include "tools.hpp" 35 | 36 | #include 37 | #include 38 | 39 | void AccelStructure::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t familyIndex, nvvk::ResourceAllocator* allocator) 40 | { 41 | m_device = device; 42 | m_pAlloc = allocator; 43 | m_queueIndex = familyIndex; 44 | m_debug.setup(device); 45 | m_rtBuilder.setup(m_device, allocator, familyIndex); 46 | } 47 | 48 | void AccelStructure::destroy() 49 | { 50 | m_rtBuilder.destroy(); 51 | vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); 52 | vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); 53 | } 54 | 55 | void AccelStructure::create(nvh::GltfScene& gltfScene, const std::vector& vertex, const std::vector& index) 56 | { 57 | MilliTimer timer; 58 | LOGI("Create acceleration structure \n"); 59 | destroy(); // reset 60 | 61 | createBottomLevelAS(gltfScene, vertex, index); 62 | createTopLevelAS(gltfScene); 63 | createRtDescriptorSet(); 64 | timer.print(); 65 | } 66 | 67 | 68 | //-------------------------------------------------------------------------------------------------- 69 | // Converting a GLTF primitive in the Raytracing Geometry used for the BLAS 70 | // 71 | nvvk::RaytracingBuilderKHR::BlasInput AccelStructure::primitiveToGeometry(const nvh::GltfPrimMesh& prim, VkBuffer vertex, VkBuffer index) 72 | { 73 | // Building part 74 | VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; 75 | info.buffer = vertex; 76 | VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); 77 | info.buffer = index; 78 | VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); 79 | 80 | VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; 81 | triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; 82 | triangles.vertexData.deviceAddress = vertexAddress; 83 | triangles.vertexStride = sizeof(VertexAttributes); 84 | triangles.indexType = VK_INDEX_TYPE_UINT32; 85 | triangles.indexData.deviceAddress = indexAddress; 86 | triangles.maxVertex = prim.vertexCount; 87 | //triangles.transformData = ({}); 88 | 89 | // Setting up the build info of the acceleration 90 | VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; 91 | asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; 92 | asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit 93 | asGeom.geometry.triangles = triangles; 94 | 95 | VkAccelerationStructureBuildRangeInfoKHR offset; 96 | offset.firstVertex = 0; 97 | offset.primitiveCount = prim.indexCount / 3; 98 | offset.primitiveOffset = 0; 99 | offset.transformOffset = 0; 100 | 101 | nvvk::RaytracingBuilderKHR::BlasInput input; 102 | input.asGeometry.emplace_back(asGeom); 103 | input.asBuildOffsetInfo.emplace_back(offset); 104 | return input; 105 | } 106 | 107 | //-------------------------------------------------------------------------------------------------- 108 | // 109 | // 110 | void AccelStructure::createBottomLevelAS(nvh::GltfScene& gltfScene, 111 | const std::vector& vertex, 112 | const std::vector& index) 113 | { 114 | // BLAS - Storing each primitive in a geometry 115 | uint32_t prim_idx{0}; 116 | std::vector allBlas; 117 | allBlas.reserve(gltfScene.m_primMeshes.size()); 118 | for(nvh::GltfPrimMesh& primMesh : gltfScene.m_primMeshes) 119 | { 120 | auto geo = primitiveToGeometry(primMesh, vertex[prim_idx].buffer, index[prim_idx].buffer); 121 | allBlas.push_back({geo}); 122 | prim_idx++; 123 | } 124 | LOGI(" BLAS(%d)", allBlas.size()); 125 | m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR 126 | | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR); 127 | } 128 | 129 | //-------------------------------------------------------------------------------------------------- 130 | // 131 | // 132 | void AccelStructure::createTopLevelAS(nvh::GltfScene& gltfScene) 133 | { 134 | std::vector tlas; 135 | tlas.reserve(gltfScene.m_nodes.size()); 136 | 137 | for(auto& node : gltfScene.m_nodes) 138 | { 139 | // Flags 140 | VkGeometryInstanceFlagsKHR flags{}; 141 | nvh::GltfPrimMesh& primMesh = gltfScene.m_primMeshes[node.primMesh]; 142 | nvh::GltfMaterial& mat = gltfScene.m_materials[primMesh.materialIndex]; 143 | 144 | // Always opaque, no need to use anyhit (faster) 145 | if(mat.alphaMode == 0 || (mat.baseColorFactor.w == 1.0f && mat.baseColorTexture == -1)) 146 | flags |= VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR; 147 | // Need to skip the cull flag in traceray_rtx for double sided materials 148 | if(mat.doubleSided == 1) 149 | flags |= VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; 150 | 151 | VkAccelerationStructureInstanceKHR rayInst{}; 152 | rayInst.transform = nvvk::toTransformMatrixKHR(node.worldMatrix); 153 | rayInst.instanceCustomIndex = node.primMesh; // gl_InstanceCustomIndexEXT: to find which primitive 154 | rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(node.primMesh); 155 | rayInst.flags = flags; 156 | rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects 157 | rayInst.mask = 0xFF; 158 | tlas.emplace_back(rayInst); 159 | } 160 | LOGI(" TLAS(%d)", tlas.size()); 161 | m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); 162 | } 163 | 164 | //-------------------------------------------------------------------------------------------------- 165 | // Descriptor set holding the TLAS 166 | // 167 | void AccelStructure::createRtDescriptorSet() 168 | { 169 | VkShaderStageFlags flags = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR 170 | | VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; 171 | nvvk::DescriptorSetBindings bind; 172 | bind.addBinding({AccelBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, flags}); // TLAS 173 | 174 | m_rtDescPool = bind.createPool(m_device); 175 | CREATE_NAMED_VK(m_rtDescSetLayout, bind.createLayout(m_device)); 176 | CREATE_NAMED_VK(m_rtDescSet, nvvk::allocateDescriptorSet(m_device, m_rtDescPool, m_rtDescSetLayout)); 177 | 178 | 179 | VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); 180 | 181 | VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; 182 | descASInfo.accelerationStructureCount = 1; 183 | descASInfo.pAccelerationStructures = &tlas; 184 | 185 | std::vector writes; 186 | writes.emplace_back(bind.makeWrite(m_rtDescSet, AccelBindings::eTlas, &descASInfo)); 187 | vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); 188 | } 189 | -------------------------------------------------------------------------------- /src/accelstruct.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | #pragma once 22 | #include "nvh/gltfscene.hpp" 23 | #include "nvvk/resourceallocator_vk.hpp" 24 | #include "nvvk/descriptorsets_vk.hpp" 25 | #include "nvvk/raytraceKHR_vk.hpp" 26 | 27 | 28 | /* 29 | 30 | This is for uploading a glTF scene to an acceleration structure. 31 | - setup as usual 32 | - create passing the glTF scene and the buffer of vertices and indices pre-constructed 33 | - retrieve the TLAS with getTlas 34 | - get the descriptor set and layout 35 | 36 | */ 37 | class AccelStructure 38 | { 39 | public: 40 | void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t familyIndex, nvvk::ResourceAllocator* allocator); 41 | void destroy(); 42 | void create(nvh::GltfScene& gltfScene, const std::vector& vertex, const std::vector& index); 43 | 44 | VkAccelerationStructureKHR getTlas() { return m_rtBuilder.getAccelerationStructure(); } 45 | VkDescriptorSetLayout getDescLayout() { return m_rtDescSetLayout; } 46 | VkDescriptorSet getDescSet() { return m_rtDescSet; } 47 | 48 | private: 49 | nvvk::RaytracingBuilderKHR::BlasInput primitiveToGeometry(const nvh::GltfPrimMesh& prim, VkBuffer vertex, VkBuffer index); 50 | void createBottomLevelAS(nvh::GltfScene& gltfScene, const std::vector& vertex, const std::vector& index); 51 | void createTopLevelAS(nvh::GltfScene& gltfScene); 52 | void createRtDescriptorSet(); 53 | 54 | 55 | // Setup 56 | nvvk::ResourceAllocator* m_pAlloc{nullptr}; // Allocator for buffer, images, acceleration structures 57 | nvvk::DebugUtil m_debug; // Utility to name objects 58 | VkDevice m_device{nullptr}; 59 | uint32_t m_queueIndex{0}; 60 | 61 | nvvk::RaytracingBuilderKHR m_rtBuilder; 62 | 63 | VkDescriptorPool m_rtDescPool{VK_NULL_HANDLE}; 64 | VkDescriptorSetLayout m_rtDescSetLayout{VK_NULL_HANDLE}; 65 | VkDescriptorSet m_rtDescSet{VK_NULL_HANDLE}; 66 | }; 67 | -------------------------------------------------------------------------------- /src/alias_table.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | struct BinomialDistrib { 7 | T prob; 8 | int failId; 9 | }; 10 | 11 | /** 12 | * Transform a discrete distribution to a set of binomial distributions 13 | * so that an O(1) sampling approach can be applied 14 | */ 15 | template 16 | struct DiscreteSampler1D { 17 | using DistribT = BinomialDistrib; 18 | 19 | DiscreteSampler1D() = default; 20 | 21 | DiscreteSampler1D(std::vector values) { 22 | for (const auto& val : values) { 23 | sumAll += val; 24 | } 25 | T sumInv = static_cast(values.size()) / sumAll; 26 | 27 | for (auto& val : values) { 28 | val *= sumInv; 29 | } 30 | 31 | binomDistribs.resize(values.size()); 32 | std::vector stackGtOne(values.size() * 2); 33 | std::vector stackLsOne(values.size() * 2); 34 | int topGtOne = 0; 35 | int topLsOne = 0; 36 | 37 | for (int i = 0; i < values.size(); i++) { 38 | auto& val = values[i]; 39 | (val > static_cast(1) ? stackGtOne[topGtOne++] : stackLsOne[topLsOne++]) = DistribT{ val, i }; 40 | } 41 | 42 | while (topGtOne && topLsOne) { 43 | DistribT gt = stackGtOne[--topGtOne]; 44 | DistribT ls = stackLsOne[--topLsOne]; 45 | 46 | binomDistribs[ls.failId] = DistribT{ ls.prob, gt.failId }; 47 | // Place ls in the table, and "fill" the rest of probability with gt.prob 48 | gt.prob -= (static_cast(1) - ls.prob); 49 | // See if gt.prob is still greater than 1 that it needs more iterations to 50 | // be splitted to different binomial distributions 51 | (gt.prob > static_cast(1) ? stackGtOne[topGtOne++] : stackLsOne[topLsOne++]) = gt; 52 | } 53 | 54 | for (int i = topGtOne - 1; i >= 0; i--) { 55 | DistribT gt = stackGtOne[i]; 56 | binomDistribs[gt.failId] = gt; 57 | } 58 | 59 | for (int i = topLsOne - 1; i >= 0; i--) { 60 | DistribT ls = stackLsOne[i]; 61 | binomDistribs[ls.failId] = ls; 62 | } 63 | } 64 | 65 | void clear() { 66 | binomDistribs.clear(); 67 | sumAll = static_cast(0); 68 | } 69 | 70 | int sample(float r1, float r2) { 71 | int passId = int(float(binomDistribs.size()) * r1); 72 | DistribT distrib = binomDistribs[passId]; 73 | return (r2 < distrib.prob) ? passId : distrib.failId; 74 | } 75 | 76 | std::vector binomDistribs; 77 | T sumAll = static_cast(0); 78 | }; 79 | 80 | template 81 | struct DiscreteSampler2D { 82 | using DistribT = BinomialDistrib; 83 | 84 | DiscreteSampler2D() = default; 85 | 86 | DiscreteSampler2D(const T* data, int width, int height) { 87 | columnSamplers.resize(height); 88 | std::vector sumRows(height); 89 | std::vector rowData(width); 90 | 91 | for (int i = 0; i < height; i++) { 92 | for (int j = 0; j < width; j++) { 93 | sumRows[i] += data[i * width + j]; 94 | } 95 | float sumRowInv = static_cast(1) / sumRows[i]; 96 | 97 | for (int j = 0; j < width; j++) { 98 | rowData[j] = data[i * width + j] * sumRowInv; 99 | } 100 | columnSamplers[i] = DiscreteSampler1D(rowData); 101 | sumAll += sumRows[i]; 102 | } 103 | 104 | T sumAllInv = static_cast(1) / sumAll; 105 | for (int i = 0; i < height; i++) { 106 | sumRows[i] *= sumAllInv; 107 | } 108 | rowSampler = DiscreteSampler1D(sumRows); 109 | } 110 | 111 | void clear() { 112 | columnSamplers.clear(); 113 | rowSampler.clear(); 114 | sumAll = static_cast(0); 115 | } 116 | 117 | std::pair sample(float r1, float r2, float r3, float r4) { 118 | int row = rowSampler.sample(r1, r2); 119 | int column = columnSamplers[row].sample(r3, r4); 120 | return { row, column }; 121 | } 122 | 123 | std::vector> columnSamplers; 124 | DiscreteSampler1D rowSampler; 125 | T sumAll = static_cast(0); 126 | }; 127 | -------------------------------------------------------------------------------- /src/hdr_sampling.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | #pragma once 22 | ////////////////////////////////////////////////////////////////////////// 23 | 24 | #include 25 | #include 26 | 27 | 28 | #include "nvvk/debug_util_vk.hpp" 29 | #include "nvvk/images_vk.hpp" 30 | #include "nvvk/resourceallocator_vk.hpp" 31 | #include "shaders/host_device.h" 32 | #include "tools.hpp" 33 | 34 | //-------------------------------------------------------------------------------------------------- 35 | // Load an environment image (HDR) and create an acceleration structure for 36 | // important light sampling. 37 | class HdrSampling 38 | { 39 | public: 40 | HdrSampling() = default; 41 | 42 | void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t familyIndex, nvvk::ResourceAllocator* allocator); 43 | void loadEnvironment(const std::string& hrdImage); 44 | 45 | 46 | void destroy(); 47 | float getIntegral() { return m_integral; } 48 | float getAverage() { return m_average; } 49 | 50 | // Resources 51 | nvvk::Texture m_texHdr; 52 | nvvk::Buffer m_accelImpSmpl; 53 | 54 | private: 55 | VkDevice m_device{VK_NULL_HANDLE}; 56 | uint32_t m_familyIndex{0}; 57 | nvvk::ResourceAllocator* m_alloc{nullptr}; 58 | nvvk::DebugUtil m_debug; 59 | 60 | float m_integral{1.f}; 61 | float m_average{1.f}; 62 | 63 | 64 | float buildAliasmap(const std::vector& data, std::vector& accel); 65 | std::vector createEnvironmentAccel(const float* pixels, VkExtent2D& size); 66 | }; 67 | -------------------------------------------------------------------------------- /src/queue.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 | 21 | #pragma once 22 | #include "vulkan/vulkan_core.h" 23 | 24 | 25 | namespace nvvk { 26 | // Holding the queue created at Vulkan context creation, using nvvk::Context 27 | struct Queue 28 | { 29 | VkQueue queue{VK_NULL_HANDLE}; 30 | uint32_t familyIndex{~0u}; 31 | uint32_t queueIndex{~0u}; 32 | }; 33 | 34 | } // namespace nvvk 35 | -------------------------------------------------------------------------------- /src/render_output.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | //-------------------------------------------------------------------------------------------------- 21 | // This creates the image in floating point, holding the result of ray tracing. 22 | // It also creates a pipeline for drawing this image from HDR to LDR applying a tonemapper 23 | // 24 | 25 | 26 | #pragma once 27 | 28 | #include "nvmath/nvmath.h" 29 | 30 | #include "nvvk/resourceallocator_vk.hpp" 31 | #include "nvvk/debug_util_vk.hpp" 32 | #include "nvvk/descriptorsets_vk.hpp" 33 | #include "shaders/host_device.h" 34 | 35 | #include 36 | 37 | class RenderOutput 38 | { 39 | public: 40 | struct PushConstant { 41 | Tonemapper tm; 42 | int debugging_mode; 43 | } m_push; 44 | Tonemapper m_tm{ 45 | 1.0f, // brightness; 46 | 1.0f, // contrast; 47 | 1.0f, // saturation; 48 | 0.0f, // vignette; 49 | 1.0f, // avgLum; 50 | 1.0f, // zoom; 51 | {1.0f, 1.0f}, // renderingRatio; 52 | 0, // autoExposure; 53 | 0.5f, // Ywhite; // Burning white 54 | 0.5f, // key; // Log-average luminance 55 | }; 56 | Tonemapper m_depthTm{ 57 | 0.0f, // exposure; 58 | 2.2f, // gamma; 59 | 0.0f, // alpha; 60 | }; 61 | 62 | public: 63 | void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t familyIndex, nvvk::ResourceAllocator* allocator, uint32_t imageCount); 64 | void destroy(); 65 | void create(const VkExtent2D& size, const VkRenderPass& renderPass); 66 | void update(const VkExtent2D& size); 67 | void run(VkCommandBuffer cmdBuf, const RtxState& state, float zoom, vec2 ratio, int frames); 68 | void genMipmap(VkCommandBuffer cmdBuf); 69 | 70 | VkDescriptorSetLayout getDescLayout() { return m_postDescSetLayout; } 71 | VkDescriptorSet getDescSet(int frames) { return m_postDescSet[(frames + 1) % 2]; } 72 | 73 | private: 74 | void createOffscreenRender(const VkExtent2D& size); 75 | void createPostPipeline(const VkRenderPass& renderPass); 76 | void createPostDescriptor(); 77 | 78 | uint32_t m_imageCount; 79 | 80 | nvvk::DescriptorSetBindings m_bind; 81 | VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; 82 | VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; 83 | std::array m_postDescSet{VK_NULL_HANDLE}; 84 | VkPipeline m_postPipeline{VK_NULL_HANDLE}; 85 | VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; 86 | //nvvk::Texture m_offscreenColor; 87 | std::array m_directResult; 88 | std::array m_indirectResult; 89 | //VkFormat m_offscreenColorFormat{VkFormat::eR16G16B16A16Sfloat}; // Darkening the scene over 5000 iterations 90 | 91 | // Direct: RGB color and light source distance 92 | // Indirect: RGB color and screen depth 93 | VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; 94 | VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // Will be replaced by best supported format 95 | 96 | 97 | // Setup 98 | nvvk::ResourceAllocator* m_pAlloc; // Allocator for buffer, images, acceleration structures 99 | nvvk::DebugUtil m_debug; // Utility to name objects 100 | VkDevice m_device; 101 | uint32_t m_queueIndex; 102 | 103 | VkExtent2D m_size{}; 104 | }; 105 | -------------------------------------------------------------------------------- /src/renderer.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | #pragma once 22 | 23 | #include "nvvk/resourceallocator_vk.hpp" 24 | #include "nvvk/debug_util_vk.hpp" 25 | #include "nvvk/descriptorsets_vk.hpp" 26 | #include "nvvk/profiler_vk.hpp" 27 | #include "nvvk/images_vk.hpp" 28 | #include "nvmath/nvmath.h" 29 | 30 | #include "shaders/host_device.h" 31 | #include "scene.hpp" 32 | 33 | #include 34 | 35 | /* 36 | 37 | Creating the Compute ray query renderer 38 | * Requiring: 39 | - Acceleration structure (AccelSctruct / Tlas) 40 | - An image (Post StoreImage) 41 | - The glTF scene (vertex, index, materials, ... ) 42 | 43 | * Usage 44 | - setup as usual 45 | - create 46 | - run 47 | */ 48 | 49 | class Renderer 50 | { 51 | public: 52 | void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t familyIndex, nvvk::ResourceAllocator* allocator, uint32_t imageCount); 53 | void destroy(); 54 | void create(const VkExtent2D& size, std::vector rtDescSetLayouts, Scene* scene); 55 | void run(const VkCommandBuffer& cmdBuf, const RtxState& state, nvvk::ProfilerVK& profiler, std::vector descSets, int frames); 56 | const std::string name() { return std::string("RQ"); } 57 | void update(const VkExtent2D& size); 58 | void createBuffer(); 59 | void createImage(); 60 | void createDescriptorSet(); 61 | void updateDescriptorSet(); 62 | 63 | private: 64 | uint32_t m_nbHit{0}; 65 | uint32_t m_imageCount; 66 | 67 | private: 68 | // Setup 69 | 70 | nvvk::ResourceAllocator* m_pAlloc{nullptr}; // Allocator for buffer, images, acceleration structures 71 | nvvk::DebugUtil m_debug; // Utility to name objects 72 | VkDevice m_device{VK_NULL_HANDLE}; 73 | uint32_t m_queueIndex{0}; 74 | 75 | //std::array m_buffer; 76 | std::array m_gbuffer; 77 | std::array m_denoiseTempBuf; 78 | 79 | std::array m_directReservoir; 80 | std::array m_indirectReservoir; 81 | 82 | nvvk::Image m_directOutput; 83 | nvvk::Image m_indirectOutput; 84 | 85 | nvvk::Buffer m_directTempResv; 86 | nvvk::Buffer m_indirectTempResv; 87 | 88 | // Depth 32bit, Normal 32bit, Metallic 8bit, Roughness 8bit, IOR 8bit, Transmission 8bit, Albedo 24bit, Hashed Material ID 8bit 89 | VkFormat m_gbufferFormat{ VK_FORMAT_R32G32B32A32_UINT }; 90 | VkFormat m_denoiseTempFormat{ VK_FORMAT_R32G32B32A32_SFLOAT }; 91 | 92 | nvvk::Texture m_motionVector; 93 | //VkFormat m_motionVectorFormat{ VK_FORMAT_R16G16_SFLOAT }; 94 | VkFormat m_motionVectorFormat{ VK_FORMAT_R16G16_SINT }; 95 | 96 | // The luminance can be compressed to 32bit YCbCr 97 | // The unit vector can also be compressed to 32bit 98 | nvvk::DescriptorSetBindings m_bind; 99 | VkDescriptorPool m_descPool{ VK_NULL_HANDLE }; 100 | VkDescriptorSetLayout m_descSetLayout{ VK_NULL_HANDLE }; 101 | std::array m_descSet{ VK_NULL_HANDLE }; 102 | 103 | VkPipelineLayout m_pipelineLayout{ VK_NULL_HANDLE }; 104 | 105 | VkPipeline m_directPipeline{ VK_NULL_HANDLE }; 106 | VkPipeline m_directGenPipeline{ VK_NULL_HANDLE }; 107 | VkPipeline m_directReusePipeline{ VK_NULL_HANDLE }; 108 | VkPipeline m_indirectPipeline{ VK_NULL_HANDLE }; 109 | 110 | VkPipeline m_denoiseDirectPipeline{ VK_NULL_HANDLE }; 111 | VkPipeline m_denoiseIndirectPipeline{ VK_NULL_HANDLE }; 112 | 113 | VkPipeline m_composePipeline{ VK_NULL_HANDLE }; 114 | 115 | VkExtent2D m_size{}; 116 | int m_frameInd = 0; 117 | }; 118 | -------------------------------------------------------------------------------- /src/sample_example.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | #pragma once 22 | #include "hdr_sampling.hpp" 23 | #include "nvvk/gizmos_vk.hpp" 24 | #include "renderer.hpp" 25 | 26 | /* 27 | 28 | Structure of the application 29 | 30 | +--------------------------------------------+ 31 | | SampleExample | 32 | +--------+-----------------------------------+ 33 | | Pick | RtxPipeline | other ? ... | 34 | +--------+---------+-------------------------+ 35 | | TLAS | | 36 | +------------------+ Offscreen | 37 | | Scene | | 38 | +------------------+-------------------------+ 39 | 40 | */ 41 | 42 | 43 | // #define ALLOC_DMA <--- This is in the CMakeLists.txt 44 | #include "nvvk/resourceallocator_vk.hpp" 45 | #if defined(ALLOC_DMA) 46 | #include 47 | typedef nvvk::ResourceAllocatorDma Allocator; 48 | #elif defined(ALLOC_VMA) 49 | #include 50 | typedef nvvk::ResourceAllocatorVma Allocator; 51 | #else 52 | typedef nvvk::ResourceAllocatorDedicated Allocator; 53 | #endif 54 | 55 | #define CPP // For sun_and_sky 56 | 57 | #include "nvh/gltfscene.hpp" 58 | #include "nvvk/appbase_vk.hpp" 59 | #include "nvvk/debug_util_vk.hpp" 60 | #include "nvvk/profiler_vk.hpp" 61 | #include "nvvk/raytraceKHR_vk.hpp" 62 | #include "nvvk/raypicker_vk.hpp" 63 | 64 | #include "accelstruct.hpp" 65 | #include "render_output.hpp" 66 | #include "renderer.hpp" 67 | #include "scene.hpp" 68 | #include "shaders/host_device.h" 69 | 70 | #include "imgui_internal.h" 71 | #include "queue.hpp" 72 | 73 | #include 74 | 75 | class SampleGUI; 76 | 77 | //-------------------------------------------------------------------------------------------------- 78 | // Simple rasterizer of OBJ objects 79 | // - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` 80 | // - It is possible to have many `ObjInstance` referencing the same `ObjModel` 81 | // - Rendering is done in an offscreen framebuffer 82 | // - The image of the framebuffer is displayed in post-process in a full-screen quad 83 | // 84 | class SampleExample : public nvvk::AppBaseVk 85 | { 86 | friend SampleGUI; 87 | 88 | public: 89 | 90 | enum Queues 91 | { 92 | eGCT0, 93 | eGCT1, 94 | eCompute, 95 | eTransfer 96 | }; 97 | 98 | 99 | void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, const std::vector& queues); 100 | 101 | bool isBusy() { return m_busy; } 102 | void createDescriptorSetLayout(); 103 | void createUniformBuffer(); 104 | void destroyResources(); 105 | void loadAssets(const char* filename); 106 | void loadEnvironmentHdr(const std::string& hdrFilename); 107 | void loadScene(const std::string& filename); 108 | void onFileDrop(const char* filename) override; 109 | void onKeyboard(int key, int scancode, int action, int mods) override; 110 | void onMouseButton(int button, int action, int mods) override; 111 | void onMouseMotion(int x, int y) override; 112 | void onResize(int /*w*/, int /*h*/) override; 113 | void renderGui(nvvk::ProfilerVK& profiler); 114 | void createRender(); 115 | void resetFrame(); 116 | void screenPicking(); 117 | void updateFrame(); 118 | void updateHdrDescriptors(); 119 | void updateUniformBuffer(const VkCommandBuffer& cmdBuf); 120 | 121 | Scene m_scene; 122 | AccelStructure m_accelStruct; 123 | RenderOutput m_offscreen; 124 | HdrSampling m_skydome; 125 | nvvk::AxisVK m_axis; 126 | nvvk::RayPickerKHR m_picker; 127 | 128 | //std::unique_ptr m_pRender; 129 | std::unique_ptr m_pRender; 130 | 131 | nvvk::Buffer m_sunAndSkyBuffer; 132 | 133 | // Graphic pipeline 134 | VkDescriptorPool m_descPool{ VK_NULL_HANDLE }; 135 | VkDescriptorSetLayout m_descSetLayout{ VK_NULL_HANDLE }; 136 | VkDescriptorSet m_descSet{ VK_NULL_HANDLE }; 137 | nvvk::DescriptorSetBindings m_bind; 138 | 139 | Allocator m_alloc; // Allocator for buffer, images, acceleration structures 140 | nvvk::DebugUtil m_debug; // Utility to name objects 141 | 142 | 143 | VkRect2D m_renderRegion{}; 144 | void setRenderRegion(const VkRect2D& size); 145 | 146 | // #Post 147 | void createOffscreenRender(); 148 | void drawPost(VkCommandBuffer cmdBuf); 149 | 150 | // #VKRay 151 | void renderScene(const VkCommandBuffer& cmdBuf, nvvk::ProfilerVK& profiler); 152 | 153 | 154 | RtxState m_rtxState{ 155 | 0, // frame; 156 | 4, // maxDepth; 157 | 1, // modulate 158 | 1, // fireflyClampThreshold; 159 | 160 | 1, // hdrMultiplier; 161 | 0, // debugging_mode; 162 | 0.25f, //environmentProb 163 | 0, //time 164 | 165 | eTemporal, // ReSTIRState 166 | 4, // RISSampleNum 167 | 80, // clamp 168 | 0, // accumulate 169 | 170 | {0, 0}, // size; 171 | 0, // environment map luminance integral inverse 172 | 0, 173 | true, // MIS 174 | 175 | 0.4f, 176 | 0.1f, 177 | 0.02f, 178 | true, // denoiser params 179 | 180 | 4.f, 181 | 0.4f, 182 | 1.f, 183 | 0 184 | }; 185 | 186 | SunAndSky m_sunAndSky{ 187 | {1, 1, 1}, // rgb_unit_conversion; 188 | 0.0000101320f, // multiplier; 189 | 0.0f, // haze; 190 | 0.0f, // redblueshift; 191 | 1.0f, // saturation; 192 | 0.0f, // horizon_height; 193 | {0.4f, 0.4f, 0.4f}, // ground_color; 194 | 0.1f, // horizon_blur; 195 | {0.0, 0.0, 0.01f}, // night_color; 196 | 0.8f, // sun_disk_intensity; 197 | {0.00, 0.78, 0.62f}, // sun_direction; 198 | 5.0f, // sun_disk_scale; 199 | 1.0f, // sun_glow_intensity; 200 | 1, // y_is_up; 201 | 1, // physically_scaled_sun; 202 | 0, // in_use; 203 | }; 204 | 205 | int m_maxFrames{ 1000000 }; 206 | int m_totalFrames{ -1 }; 207 | bool m_showAxis{ true }; 208 | bool m_descaling{ false }; 209 | int m_descalingLevel{ 1 }; 210 | bool m_busy{ false }; 211 | std::string m_busyReasonText; 212 | 213 | std::shared_ptr m_gui; 214 | 215 | std::chrono::steady_clock::time_point m_start_time; 216 | }; 217 | -------------------------------------------------------------------------------- /src/sample_gui.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 | #include "nvvk/profiler_vk.hpp" 22 | 23 | 24 | //-------------------------------------------------------------------------------------------------- 25 | // This implements all graphical user interface of SampleExample. 26 | class SampleExample; // Forward declaration 27 | 28 | class SampleGUI 29 | { 30 | public: 31 | SampleGUI(SampleExample* _s) 32 | : _se(_s) 33 | { 34 | } 35 | void render(nvvk::ProfilerVK& profiler); 36 | void titleBar(); 37 | void menuBar(); 38 | void showBusyWindow(); 39 | 40 | private: 41 | bool guiCamera(); 42 | bool guiRayTracing(); 43 | bool guiTonemapper(); 44 | bool guiEnvironment(); 45 | bool guiStatistics(); 46 | bool guiProfiler(nvvk::ProfilerVK& profiler); 47 | bool guiGpuMeasures(); 48 | 49 | SampleExample* _se{nullptr}; 50 | }; 51 | 52 | -------------------------------------------------------------------------------- /src/scene.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | #pragma once 21 | 22 | 23 | //-------------------------------------------------------------------------------------------------- 24 | // - Loading and storing the glTF scene 25 | // - Creates the buffers and descriptor set for the scene 26 | 27 | 28 | #include 29 | 30 | #include "nvh/gltfscene.hpp" 31 | #include "nvvk/resourceallocator_vk.hpp" 32 | #include "nvvk/debug_util_vk.hpp" 33 | #include "nvvk/descriptorsets_vk.hpp" 34 | #include "queue.hpp" 35 | 36 | 37 | class Scene 38 | { 39 | public: 40 | enum EBuffer 41 | { 42 | eCameraMat, 43 | eMaterial, 44 | eInstData, 45 | ePuncLights, 46 | eTrigLights, 47 | // eTrigLightTransforms, 48 | eLightBufInfo, 49 | //eGbuffer 50 | }; 51 | 52 | 53 | enum EBuffers 54 | { 55 | eVertex, 56 | eIndex, 57 | }; 58 | 59 | public: 60 | void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, const nvvk::Queue& queue, nvvk::ResourceAllocator* allocator); 61 | bool load(const std::string& filename); 62 | 63 | void createInstanceDataBuffer(VkCommandBuffer cmdBuf, nvh::GltfScene& gltf); 64 | void createVertexBuffer(VkCommandBuffer cmdBuf, const nvh::GltfScene& gltf); 65 | void setCameraFromScene(const std::string& filename, const nvh::GltfScene& gltf); 66 | bool loadGltfScene(const std::string& filename, tinygltf::Model& tmodel); 67 | void createPuncLightBuffer(VkCommandBuffer cmdBuf, const nvh::GltfScene& gltf); 68 | void createTrigLightBuffer(VkCommandBuffer cmdBuf, const nvh::GltfScene& gltf, const tinygltf::Model& gltfModel); 69 | void createMaterialBuffer(VkCommandBuffer cmdBuf, const nvh::GltfScene& gltf); 70 | void destroy(); 71 | void updateCamera(const VkCommandBuffer& cmdBuf, VkExtent2D size); 72 | 73 | 74 | VkDescriptorSetLayout getDescLayout() { return m_descSetLayout; } 75 | VkDescriptorSet getDescSet() { return m_descSet; } 76 | nvh::GltfScene& getScene() { return m_gltf; } 77 | nvh::GltfStats& getStat() { return m_stats; } 78 | const std::vector& getBuffers(EBuffers b) { return m_buffers[b]; } 79 | const std::string& getSceneName() const { return m_sceneName; } 80 | SceneCamera& getCamera() { return m_camera; } 81 | 82 | float m_puncLightWeight{ 0.f }; 83 | float m_trigLightWeight{ 0.f }; 84 | private: 85 | void createTextureImages(VkCommandBuffer cmdBuf, tinygltf::Model& gltfModel); 86 | void createDescriptorSet(const nvh::GltfScene& gltf); 87 | 88 | nvh::GltfScene m_gltf; 89 | nvh::GltfStats m_stats; 90 | 91 | std::string m_sceneName; 92 | SceneCamera m_camera{}; 93 | 94 | // Setup 95 | nvvk::ResourceAllocator* m_pAlloc; // Allocator for buffer, images, acceleration structures 96 | nvvk::DebugUtil m_debug; // Utility to name objects 97 | VkDevice m_device; 98 | nvvk::Queue m_queue; 99 | 100 | // Resources 101 | std::array m_buffer; // For single buffer 102 | std::array, 2> m_buffers; // For array of buffers (vertex/index) 103 | std::vector m_textures; // vector of all textures of the scene 104 | std::vector> m_images; // vector of all images of the scene 105 | std::vector m_defaultTextures; // for cleanup 106 | 107 | 108 | VkDescriptorPool m_descPool{ VK_NULL_HANDLE }; 109 | VkDescriptorSetLayout m_descSetLayout{ VK_NULL_HANDLE }; 110 | VkDescriptorSet m_descSet{ VK_NULL_HANDLE }; 111 | 112 | // Direct light importance sampling 113 | LightBufInfo m_lightBufInfo; 114 | float createPuncLightImptSampAccel(std::vector& puncLights, const nvh::GltfScene& gltf); 115 | float createTrigLightImptSampAccel(std::vector& trigLights, const nvh::GltfScene& gltf, const tinygltf::Model& gltfModel); 116 | float computeTrigIntensity(const TrigLight& trig, const nvh::GltfMaterial& mtl, const tinygltf::Model& gltfModel); 117 | }; 118 | -------------------------------------------------------------------------------- /src/tiny_gltf.cpp: -------------------------------------------------------------------------------- 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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | /* 22 | * Dummy: just for the implementation of tiny_gltf 23 | */ 24 | 25 | // Visual Studio warnings 26 | #ifdef _MSC_VER 27 | #pragma warning(disable : 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen 28 | #endif 29 | 30 | #define TINYGLTF_IMPLEMENTATION 31 | #define STB_IMAGE_IMPLEMENTATION 32 | #define STB_IMAGE_WRITE_IMPLEMENTATION 33 | #define TINYGLTF_NO_EXTERNAL_IMAGE 34 | #include "tiny_gltf.h" 35 | -------------------------------------------------------------------------------- /src/tools.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) 2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | #pragma once 22 | 23 | #ifndef TOOLS_H 24 | #define TOOLS_H 25 | 26 | // Utility to time the execution of something resetting the timer 27 | // on each elapse call 28 | // Usage: 29 | // { 30 | // MilliTimer timer; 31 | // ... stuff ... 32 | // double time_elapse = timer.elapse(); 33 | // } 34 | #include 35 | #include 36 | #include 37 | 38 | #include "nvh/nvprint.hpp" 39 | #include "nvh/timesampler.hpp" 40 | 41 | struct MilliTimer : public nvh::Stopwatch 42 | { 43 | void print() { LOGI(" --> (%5.3f ms)\n", elapsed()); } 44 | }; 45 | 46 | 47 | // Formating with local number representation 48 | template 49 | std::string FormatNumbers(T value) 50 | { 51 | std::stringstream ss; 52 | ss.imbue(std::locale("")); 53 | ss << std::fixed << value; 54 | return ss.str(); 55 | } 56 | 57 | template 58 | inline float luminance(const T& color) 59 | { 60 | return color[0] * 0.2126f + color[1] * 0.7152f + color[2] * 0.0722f; 61 | } 62 | 63 | 64 | 65 | #endif 66 | --------------------------------------------------------------------------------