├── .gitignore ├── CMakeLists.txt ├── CONTRIBUTING ├── LICENSE ├── README.md ├── docs ├── Denoiser-renderLoop.png ├── GPU_Trace.png ├── after.png ├── before.png ├── denoiser_off.png ├── denoiser_on.png ├── nsight-sys_1.png ├── nsight-sys_2.png ├── optix_denoiser.png ├── optix_denoiser_th.jpg └── thumb.png ├── media ├── NVIDIA_logo.png ├── NVIDIA_logo2.ktx2 ├── NVIDIA_logo2.png ├── about.txt ├── cornellBox.bin ├── cornellBox.gltf ├── cube.bin ├── cube.gltf ├── cubeTextured.bin ├── cubeTextured.gltf ├── cubeTexturedKtx.gltf ├── env3.hdr ├── fruit.jpg ├── fruit.ktx2 ├── license_meet_mat.txt ├── meet_mat.glb ├── shader_ball.bin ├── shader_ball.gltf ├── spruit_sunrise_1k.hdr └── std_env.hdr ├── optix_denoiser ├── CMakeLists.txt ├── shaders │ ├── compress.glsl │ ├── cpy_to_buffer.comp │ ├── cpy_to_img.comp │ ├── device_host.h │ ├── dh_bindings.h │ ├── gbuffers.rchit │ ├── gbuffers.rmiss │ ├── get_hit.glsl │ ├── pathtrace.rahit │ ├── pathtrace.rchit │ ├── pathtrace.rgen │ ├── pathtrace.rmiss │ └── payload.glsl └── src │ ├── denoiser.cpp │ ├── denoiser.hpp │ ├── optix_denoiser.cpp │ └── tinygltf_impl.cpp └── test.py /.gitignore: -------------------------------------------------------------------------------- 1 | shaders/*.spv 2 | /build/* 3 | autogen/* 4 | spv/* 5 | optix_denoiser/_autogen/ 6 | /_install 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Common default Cmake header for Nvpro-core samples 2 | cmake_minimum_required(VERSION 3.15.0 FATAL_ERROR) 3 | get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) 4 | project(${PROJECT_NAME} LANGUAGES C CXX) 5 | 6 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 7 | set(CMAKE_CXX_STANDARD 20) 8 | 9 | #-------------------------------------------------------------------------------------------------- 10 | # look for nvpro_core 1) as a sub-folder 2) at some other locations 11 | # this cannot be put anywhere else since we still didn't find setup.cmake yet 12 | if(NOT BASE_DIRECTORY) 13 | find_path(BASE_DIRECTORY 14 | NAMES nvpro_core/cmake/setup.cmake 15 | PATHS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../.. 16 | REQUIRED 17 | DOC "Directory containing nvpro_core" 18 | ) 19 | endif() 20 | 21 | ## Various functions and macros REQUIRED 22 | if(EXISTS ${BASE_DIRECTORY}/nvpro_core/cmake/setup.cmake) 23 | include(${BASE_DIRECTORY}/nvpro_core/cmake/setup.cmake) 24 | include(${BASE_DIRECTORY}/nvpro_core/cmake/utilities.cmake) 25 | else() 26 | message(FATAL_ERROR "could not find base directory, please set BASE_DIRECTORY to folder containing nvpro_core") 27 | endif() 28 | 29 | set(NVPRO_CORE_DIR ${BASE_DIRECTORY}/nvpro_core) 30 | 31 | if(MSVC) 32 | add_definitions(/wd26812) # 'enum class' over 'enum' 33 | add_definitions(/wd26451) # Arithmetic overflow, casting 4 byte value to 8 byte value 34 | endif() 35 | 36 | 37 | 38 | #-------------------------------------------------------------------------------------------------- 39 | # Add example 40 | add_subdirectory(optix_denoiser) 41 | 42 | #-------------------------------------------------------------------------------------------------- 43 | # Install - copying the media directory 44 | message(STATUS "COPY ${CMAKE_CURRENT_SOURCE_DIR}/media to ${OUTPUT_PATH}") 45 | file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/media DESTINATION ${OUTPUT_PATH}) 46 | install(DIRECTORY "media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}") 47 | install(DIRECTORY "media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug") 48 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | https://developercertificate.org/ 2 | 3 | Developer Certificate of Origin 4 | Version 1.1 5 | 6 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 7 | 8 | Everyone is permitted to copy and distribute verbatim copies of this 9 | license document, but changing it is not allowed. 10 | 11 | 12 | Developer's Certificate of Origin 1.1 13 | 14 | By making a contribution to this project, I certify that: 15 | 16 | (a) The contribution was created in whole or in part by me and I 17 | have the right to submit it under the open source license 18 | indicated in the file; or 19 | 20 | (b) The contribution is based upon previous work that, to the best 21 | of my knowledge, is covered under an appropriate open source 22 | license and I have the right under that license to submit that 23 | work with modifications, whether created in whole or in part 24 | by me, under the same open source license (unless I am 25 | permitted to submit under a different license), as indicated 26 | in the file; or 27 | 28 | (c) The contribution was provided directly to me by some other 29 | person who certified (a), (b) or (c) and I have not modified 30 | it. 31 | 32 | (d) I understand and agree that this project and the contribution 33 | are public and that a record of the contribution (including all 34 | personal information I submit with it, including my sign-off) is 35 | maintained indefinitely and may be redistributed consistent with 36 | this project or the open source license(s) involved. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # VK_DENOISE 3 | 4 | ![](docs/optix_denoiser.png) 5 | 6 | This example is ray tracing a glTF scene using a path tracing technique and focus on the denoiser. Path-tracing is generally very noisy for the first frames and using a denoiser helps getting a converged image quicker. For the denoiser, we will be using the [Optix7 denoiser](https://developer.nvidia.com/optix-denoiser). 7 | 8 | The OptiX denoiser is using Cuda, so our image will need to be shared between Vulkan and Cuda. The denoiser is actually requiring linear images, which are not available to Vulkan, so instead of directly sharing the images, we are creating buffers which are shared between Vulkan and Cuda and we are copying the image to the buffer, converting them to linear images. 9 | 10 | ## SDKs 11 | 12 | This project needs two external SDK. Follow the default installation and re-run CMake. If the path aren't found, you may need to delete the cache and re-run. 13 | 14 | * [OptiX 7.3+](https://developer.nvidia.com/designworks/optix/download) 15 | * [Cuda 10.x](https://developer.nvidia.com/cuda-downloads) 16 | 17 | 18 | ## Rendering 19 | 20 | The ray tracer will release two new G-Buffers, albedo and normal. When entering the OptiX world, images are copied into buffers because OptiX denoising only works on linear images and in Vulkan they are tiled optimized. Once denoised, the OptiX image/buffer is copied back into Vulkan before being displayed. 21 | 22 | ![img](docs/Denoiser-renderLoop.png) 23 | 24 | 25 | ## External Memory 26 | 27 | Only the buffers, which are the linear-image copy of the default tiled image, are created with the external memory flag. For the allocation, we are using a derived class of the dedicated allocator, which is adding the flag decoration on the buffer allocation and memory allocation. See also the examples on interop: and . 28 | 29 | ## Timeline Semaphore 30 | 31 | The denoiser is using Cuda and rendering is done with Vulkan, if we would simply add all Vulkan commands to a single command buffer, we would not be synchronized and the image to display will be sometime denoised, sometime not. We could add a hard synchronization on the CPU, making sure the ray traced is finished, denoised the image, wait for it, then display. But this would be losing a lot of the GPU cycle. Instead, we are adding a Vulkan timeline semaphore to signal when the ray traced image is rendered and transferred the buffer and a Cuda wait semaphore to hold the execution of the denoiser on the GPU. We add the inverse process at the end of the denoiser with a Cuda semaphore signaling the image is denoised and on Vulkan a wait semaphore to copy the buffer back to an image, tonemap it and display. 32 | 33 | ![vk_denoise2](docs/GPU_Trace.png) 34 | 35 | ### Nsight System 36 | 37 | The following image was done using [Nsight System](https://developer.nvidia.com/nsight-systems), which is at the time of writing those lines, the only tool which can inspect both Vulkan ray tracing and Cuda simultaneously. In the following image; the rendering was set to start denoising the image after 10 iterations. It is quicker to render and not denoising each frame. Also, sometimes the denoiser is not that great with the first few frames, as the image is too noisy to reconstruct it correctly. After 10 frames, the denoiser will be apply on frame #11. Because the frame #11 is really long to do, the in-flight frames will be displayed before it even finishes. 38 | 39 | ![vk_denoise2](docs/nsight-sys_1.png) 40 | 41 | This is a closeup on what is happening while denoising a frame. The first command buffer gets the ray tracing and image copy commands and is submitted. The Cuda wait semaphore is done before calling the OptiX denoiser. Cuda commands are called, but they won't be executed before the ray tracing is completed. At the end of cuda, Vulkan waits to take back the control and the second command buffer, which is transferring the buffer to image, tonemap and display will be executed. 42 | 43 | ![vk_denoise2](docs/nsight-sys_2.png) 44 | 45 | ## Possible Modifications 46 | 47 | The denoiser is setup to use RGB, ALBEDO and NORMAL buffers. All three buffers help getting a clearer image faster, but it is also possible to use only RGB + ALBEDO or RGB only. This information to the denoiser is done in `DenoiserOptix::initOptiX()`. By modifying the `inputKind` and re-running the example, you can see how the denoiser is behaving. Using all three buffers is especially useful with images having texture details, bumps, cracks and other fine details. 48 | 49 | The other modification would be to tonemap the image before sending it to the denoiser and use the LDR denoiser training set. This could be better in some cases, as the training set was done on a less high variance, but this might not give radical improvements. 50 | 51 | ## Results 52 | 53 | After 5000 iterations, there are still residual noise in the image. The denoiser helps removing it. 54 | 55 | ### Denoiser OFF 56 | 57 | ![vk_denoise](docs/denoiser_off.png) 58 | 59 | ### Denoiser ON 60 | 61 | ![vk_denoise2](docs/denoiser_on.png) 62 | 63 | ### Denoiser OFF 64 | 65 | ![vk_denoise](docs/before.png) 66 | 67 | ### Denoiser ON 68 | 69 | ![vk_denoise2](docs/after.png) 70 | 71 | Tags: 72 | 73 | - raytracing, path-tracing, GLTF, HDR, tonemapper, picking, BLAS, TLAS, PBR material, denoising, Cuda, interop 74 | 75 | Extensions: 76 | 77 | - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_NV_RAY_TRACING_EXTENSION_NAME, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, VK_KHR_MAINTENANCE3_EXTENSION_NAME, VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, 78 | VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, 79 | VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, 80 | VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, 81 | VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 82 | VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, 83 | VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, 84 | VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, 85 | VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME, 86 | VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME, 87 | 88 | Author: [Martin-Karl Lefrançois](https://developer.nvidia.com/blog/author/mlefrancois/) 89 | -------------------------------------------------------------------------------- /docs/Denoiser-renderLoop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/docs/Denoiser-renderLoop.png -------------------------------------------------------------------------------- /docs/GPU_Trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/docs/GPU_Trace.png -------------------------------------------------------------------------------- /docs/after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/docs/after.png -------------------------------------------------------------------------------- /docs/before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/docs/before.png -------------------------------------------------------------------------------- /docs/denoiser_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/docs/denoiser_off.png -------------------------------------------------------------------------------- /docs/denoiser_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/docs/denoiser_on.png -------------------------------------------------------------------------------- /docs/nsight-sys_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/docs/nsight-sys_1.png -------------------------------------------------------------------------------- /docs/nsight-sys_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/docs/nsight-sys_2.png -------------------------------------------------------------------------------- /docs/optix_denoiser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/docs/optix_denoiser.png -------------------------------------------------------------------------------- /docs/optix_denoiser_th.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/docs/optix_denoiser_th.jpg -------------------------------------------------------------------------------- /docs/thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/docs/thumb.png -------------------------------------------------------------------------------- /media/NVIDIA_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/NVIDIA_logo.png -------------------------------------------------------------------------------- /media/NVIDIA_logo2.ktx2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/NVIDIA_logo2.ktx2 -------------------------------------------------------------------------------- /media/NVIDIA_logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/NVIDIA_logo2.png -------------------------------------------------------------------------------- /media/about.txt: -------------------------------------------------------------------------------- 1 | Some HDR are from https://polyhaven.com/ -------------------------------------------------------------------------------- /media/cornellBox.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/cornellBox.bin -------------------------------------------------------------------------------- /media/cornellBox.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "accessors": [ 3 | { 4 | "bufferView": 0, 5 | "componentType": 5126, 6 | "count": 24, 7 | "max": [ 8 | 5.0, 9 | 5.0, 10 | 0.05000000074505806 11 | ], 12 | "min": [ 13 | -5.0, 14 | -5.0, 15 | -0.05000000074505806 16 | ], 17 | "type": "VEC3" 18 | }, 19 | { 20 | "bufferView": 1, 21 | "componentType": 5126, 22 | "count": 24, 23 | "type": "VEC3" 24 | }, 25 | { 26 | "bufferView": 2, 27 | "componentType": 5126, 28 | "count": 24, 29 | "type": "VEC2" 30 | }, 31 | { 32 | "bufferView": 3, 33 | "componentType": 5125, 34 | "count": 36, 35 | "type": "SCALAR" 36 | }, 37 | { 38 | "bufferView": 4, 39 | "componentType": 5126, 40 | "count": 24, 41 | "max": [ 42 | 5.0, 43 | 0.05000000074505806, 44 | 5.0 45 | ], 46 | "min": [ 47 | -5.0, 48 | -0.05000000074505806, 49 | -5.0 50 | ], 51 | "type": "VEC3" 52 | }, 53 | { 54 | "bufferView": 5, 55 | "componentType": 5126, 56 | "count": 24, 57 | "type": "VEC3" 58 | }, 59 | { 60 | "bufferView": 6, 61 | "componentType": 5126, 62 | "count": 24, 63 | "type": "VEC2" 64 | }, 65 | { 66 | "bufferView": 7, 67 | "componentType": 5125, 68 | "count": 36, 69 | "type": "SCALAR" 70 | }, 71 | { 72 | "bufferView": 8, 73 | "componentType": 5126, 74 | "count": 24, 75 | "max": [ 76 | 0.05000000074505806, 77 | 5.0, 78 | 5.0 79 | ], 80 | "min": [ 81 | -0.05000000074505806, 82 | -5.0, 83 | -5.0 84 | ], 85 | "type": "VEC3" 86 | }, 87 | { 88 | "bufferView": 9, 89 | "componentType": 5126, 90 | "count": 24, 91 | "type": "VEC3" 92 | }, 93 | { 94 | "bufferView": 10, 95 | "componentType": 5126, 96 | "count": 24, 97 | "type": "VEC2" 98 | }, 99 | { 100 | "bufferView": 11, 101 | "componentType": 5125, 102 | "count": 36, 103 | "type": "SCALAR" 104 | }, 105 | { 106 | "bufferView": 12, 107 | "componentType": 5126, 108 | "count": 24, 109 | "max": [ 110 | 0.5, 111 | 0.05000000074505806, 112 | 0.5 113 | ], 114 | "min": [ 115 | -0.5, 116 | -0.05000000074505806, 117 | -0.5 118 | ], 119 | "type": "VEC3" 120 | }, 121 | { 122 | "bufferView": 13, 123 | "componentType": 5126, 124 | "count": 24, 125 | "type": "VEC3" 126 | }, 127 | { 128 | "bufferView": 14, 129 | "componentType": 5126, 130 | "count": 24, 131 | "type": "VEC2" 132 | }, 133 | { 134 | "bufferView": 15, 135 | "componentType": 5125, 136 | "count": 36, 137 | "type": "SCALAR" 138 | }, 139 | { 140 | "bufferView": 16, 141 | "componentType": 5126, 142 | "count": 24, 143 | "max": [ 144 | 0.5, 145 | 0.5, 146 | 0.5 147 | ], 148 | "min": [ 149 | -0.5, 150 | -0.5, 151 | -0.5 152 | ], 153 | "type": "VEC3" 154 | }, 155 | { 156 | "bufferView": 17, 157 | "componentType": 5126, 158 | "count": 24, 159 | "type": "VEC3" 160 | }, 161 | { 162 | "bufferView": 18, 163 | "componentType": 5126, 164 | "count": 24, 165 | "type": "VEC2" 166 | }, 167 | { 168 | "bufferView": 19, 169 | "componentType": 5125, 170 | "count": 36, 171 | "type": "SCALAR" 172 | }, 173 | { 174 | "bufferView": 20, 175 | "componentType": 5126, 176 | "count": 24, 177 | "max": [ 178 | 1.25, 179 | 3.0, 180 | 1.25 181 | ], 182 | "min": [ 183 | -1.25, 184 | -3.0, 185 | -1.25 186 | ], 187 | "type": "VEC3" 188 | }, 189 | { 190 | "bufferView": 21, 191 | "componentType": 5126, 192 | "count": 24, 193 | "type": "VEC3" 194 | }, 195 | { 196 | "bufferView": 22, 197 | "componentType": 5126, 198 | "count": 24, 199 | "type": "VEC2" 200 | }, 201 | { 202 | "bufferView": 23, 203 | "componentType": 5125, 204 | "count": 36, 205 | "type": "SCALAR" 206 | }, 207 | { 208 | "bufferView": 24, 209 | "componentType": 5126, 210 | "count": 8320, 211 | "max": [ 212 | 1.0, 213 | 1.0, 214 | 1.0 215 | ], 216 | "min": [ 217 | -1.0, 218 | -1.0, 219 | -1.0 220 | ], 221 | "type": "VEC3" 222 | }, 223 | { 224 | "bufferView": 25, 225 | "componentType": 5126, 226 | "count": 8320, 227 | "type": "VEC3" 228 | }, 229 | { 230 | "bufferView": 26, 231 | "componentType": 5126, 232 | "count": 8320, 233 | "type": "VEC2" 234 | }, 235 | { 236 | "bufferView": 27, 237 | "componentType": 5125, 238 | "count": 24954, 239 | "type": "SCALAR" 240 | }, 241 | { 242 | "bufferView": 28, 243 | "componentType": 5126, 244 | "count": 8320, 245 | "max": [ 246 | 1.0, 247 | 1.0, 248 | 1.0 249 | ], 250 | "min": [ 251 | -1.0, 252 | -1.0, 253 | -1.0 254 | ], 255 | "type": "VEC3" 256 | }, 257 | { 258 | "bufferView": 29, 259 | "componentType": 5126, 260 | "count": 8320, 261 | "type": "VEC3" 262 | }, 263 | { 264 | "bufferView": 30, 265 | "componentType": 5126, 266 | "count": 8320, 267 | "type": "VEC2" 268 | }, 269 | { 270 | "bufferView": 31, 271 | "componentType": 5125, 272 | "count": 24954, 273 | "type": "SCALAR" 274 | } 275 | ], 276 | "asset": { 277 | "copyright": "NVIDIA Corporation", 278 | "generator": "Iray glTF plugin", 279 | "version": "2.0" 280 | }, 281 | "bufferViews": [ 282 | { 283 | "buffer": 0, 284 | "byteLength": 288, 285 | "byteStride": 12 286 | }, 287 | { 288 | "buffer": 0, 289 | "byteLength": 288, 290 | "byteOffset": 288, 291 | "byteStride": 12 292 | }, 293 | { 294 | "buffer": 0, 295 | "byteLength": 192, 296 | "byteOffset": 576, 297 | "byteStride": 8 298 | }, 299 | { 300 | "buffer": 0, 301 | "byteLength": 144, 302 | "byteOffset": 768 303 | }, 304 | { 305 | "buffer": 0, 306 | "byteLength": 288, 307 | "byteOffset": 912, 308 | "byteStride": 12 309 | }, 310 | { 311 | "buffer": 0, 312 | "byteLength": 288, 313 | "byteOffset": 1200, 314 | "byteStride": 12 315 | }, 316 | { 317 | "buffer": 0, 318 | "byteLength": 192, 319 | "byteOffset": 1488, 320 | "byteStride": 8 321 | }, 322 | { 323 | "buffer": 0, 324 | "byteLength": 144, 325 | "byteOffset": 1680 326 | }, 327 | { 328 | "buffer": 0, 329 | "byteLength": 288, 330 | "byteOffset": 1824, 331 | "byteStride": 12 332 | }, 333 | { 334 | "buffer": 0, 335 | "byteLength": 288, 336 | "byteOffset": 2112, 337 | "byteStride": 12 338 | }, 339 | { 340 | "buffer": 0, 341 | "byteLength": 192, 342 | "byteOffset": 2400, 343 | "byteStride": 8 344 | }, 345 | { 346 | "buffer": 0, 347 | "byteLength": 144, 348 | "byteOffset": 2592 349 | }, 350 | { 351 | "buffer": 0, 352 | "byteLength": 288, 353 | "byteOffset": 2736, 354 | "byteStride": 12 355 | }, 356 | { 357 | "buffer": 0, 358 | "byteLength": 288, 359 | "byteOffset": 3024, 360 | "byteStride": 12 361 | }, 362 | { 363 | "buffer": 0, 364 | "byteLength": 192, 365 | "byteOffset": 3312, 366 | "byteStride": 8 367 | }, 368 | { 369 | "buffer": 0, 370 | "byteLength": 144, 371 | "byteOffset": 3504 372 | }, 373 | { 374 | "buffer": 0, 375 | "byteLength": 288, 376 | "byteOffset": 3648, 377 | "byteStride": 12 378 | }, 379 | { 380 | "buffer": 0, 381 | "byteLength": 288, 382 | "byteOffset": 3936, 383 | "byteStride": 12 384 | }, 385 | { 386 | "buffer": 0, 387 | "byteLength": 192, 388 | "byteOffset": 4224, 389 | "byteStride": 8 390 | }, 391 | { 392 | "buffer": 0, 393 | "byteLength": 144, 394 | "byteOffset": 4416 395 | }, 396 | { 397 | "buffer": 0, 398 | "byteLength": 288, 399 | "byteOffset": 4560, 400 | "byteStride": 12 401 | }, 402 | { 403 | "buffer": 0, 404 | "byteLength": 288, 405 | "byteOffset": 4848, 406 | "byteStride": 12 407 | }, 408 | { 409 | "buffer": 0, 410 | "byteLength": 192, 411 | "byteOffset": 5136, 412 | "byteStride": 8 413 | }, 414 | { 415 | "buffer": 0, 416 | "byteLength": 144, 417 | "byteOffset": 5328 418 | }, 419 | { 420 | "buffer": 0, 421 | "byteLength": 99840, 422 | "byteOffset": 5472, 423 | "byteStride": 12 424 | }, 425 | { 426 | "buffer": 0, 427 | "byteLength": 99840, 428 | "byteOffset": 105312, 429 | "byteStride": 12 430 | }, 431 | { 432 | "buffer": 0, 433 | "byteLength": 66560, 434 | "byteOffset": 205152, 435 | "byteStride": 8 436 | }, 437 | { 438 | "buffer": 0, 439 | "byteLength": 99816, 440 | "byteOffset": 271712 441 | }, 442 | { 443 | "buffer": 0, 444 | "byteLength": 99840, 445 | "byteOffset": 371528, 446 | "byteStride": 12 447 | }, 448 | { 449 | "buffer": 0, 450 | "byteLength": 99840, 451 | "byteOffset": 471368, 452 | "byteStride": 12 453 | }, 454 | { 455 | "buffer": 0, 456 | "byteLength": 66560, 457 | "byteOffset": 571208, 458 | "byteStride": 8 459 | }, 460 | { 461 | "buffer": 0, 462 | "byteLength": 99816, 463 | "byteOffset": 637768 464 | } 465 | ], 466 | "buffers": [ 467 | { 468 | "byteLength": 737584, 469 | "uri": "cornellBox.bin" 470 | } 471 | ], 472 | "cameras": [ 473 | { 474 | "extras": { 475 | "attributes_iray": { 476 | "mip_burn_highlights": 0.699999988079071, 477 | "mip_burn_highlights_per_component": false, 478 | "mip_camera_shutter": 4.0, 479 | "mip_cm2_factor": 1.0, 480 | "mip_crush_blacks": 0.5, 481 | "mip_f_number": 1.0, 482 | "mip_film_iso": 100.0, 483 | "mip_gamma": 2.200000047683716, 484 | "mip_saturation": 1.0, 485 | "mip_vignetting": 0.0, 486 | "mip_whitepoint": [ 487 | 1.0, 488 | 1.0, 489 | 1.0, 490 | 1.0 491 | ], 492 | "tm_enable_tonemapper": true, 493 | "tm_tonemapper": "mia_exposure_photographic" 494 | }, 495 | "resolution": [ 496 | 640, 497 | 480 498 | ] 499 | }, 500 | "name": "default", 501 | "perspective": { 502 | "aspectRatio": 1.3333333333333333, 503 | "yfov": 0.7175414562225342, 504 | "zfar": 1000.0, 505 | "znear": 0.1 506 | }, 507 | "type": "perspective" 508 | } 509 | ], 510 | "extensions": { 511 | "NV_materials_mdl": { 512 | "modules": [ 513 | "mdl::base", 514 | "mdl::gltf_support", 515 | "mdl::nvidia::core_definitions", 516 | "mdl::state" 517 | ], 518 | "shaders": [ 519 | { 520 | "arguments": { 521 | "texture": 0 522 | }, 523 | "definition": "mdl::base::environment_spherical(texture_2d)", 524 | "name": "env_shd" 525 | }, 526 | { 527 | "arguments": { 528 | "metallic_factor": 0.0 529 | }, 530 | "definition": "mdl::gltf_support::gltf_material", 531 | "hash": [ 532 | "0x2b557fab", 533 | "0x5f2f13b5", 534 | "0x5dbe3123", 535 | "0x469f59c1" 536 | ], 537 | "name": "cube_instance_material" 538 | }, 539 | { 540 | "arguments": { 541 | "metallic_factor": 0.0 542 | }, 543 | "definition": "mdl::gltf_support::gltf_material", 544 | "hash": [ 545 | "0x2b557fab", 546 | "0x5f2f13b5", 547 | "0x5dbe3123", 548 | "0x469f59c1" 549 | ], 550 | "name": "cube_instance_2_material" 551 | }, 552 | { 553 | "arguments": { 554 | "base_color_factor": [ 555 | 0.054592281579971313, 556 | 1.0, 557 | 0.0 558 | ] 559 | }, 560 | "definition": "mdl::gltf_support::gltf_material", 561 | "hash": [ 562 | "0x2b557fab", 563 | "0x5f2f13b5", 564 | "0x5dbe3123", 565 | "0x469f59c1" 566 | ], 567 | "name": "gltf_material_mat" 568 | }, 569 | { 570 | "arguments": { 571 | "base_color_factor": [ 572 | 1.0, 573 | 0.0, 574 | 0.00010718735575210303 575 | ], 576 | "metallic_factor": 0.0 577 | }, 578 | "definition": "mdl::gltf_support::gltf_material", 579 | "hash": [ 580 | "0x2b557fab", 581 | "0x5f2f13b5", 582 | "0x5dbe3123", 583 | "0x469f59c1" 584 | ], 585 | "name": "cube_instance_5_material" 586 | }, 587 | { 588 | "arguments": { 589 | "emissive_factor": [ 590 | 10.0, 591 | 10.0, 592 | 10.0 593 | ], 594 | "metallic_factor": 0.0, 595 | "roughness_factor": 0.0 596 | }, 597 | "definition": "mdl::gltf_support::gltf_material", 598 | "hash": [ 599 | "0x2b557fab", 600 | "0x5f2f13b5", 601 | "0x5dbe3123", 602 | "0x469f59c1" 603 | ], 604 | "name": "cube_instance_8_material" 605 | }, 606 | { 607 | "arguments": { 608 | "normal=": 7 609 | }, 610 | "definition": "mdl::nvidia::core_definitions::flex_material", 611 | "hash": [ 612 | "0xcdccb2f5", 613 | "0xccfa4281", 614 | "0x41aa45c6", 615 | "0x53936269" 616 | ], 617 | "name": "cube_instance_14_material" 618 | }, 619 | { 620 | "definition": "mdl::state::normal()", 621 | "name": "mdl::state::normal_801" 622 | }, 623 | { 624 | "definition": "mdl::gltf_support::gltf_material", 625 | "hash": [ 626 | "0x2b557fab", 627 | "0x5f2f13b5", 628 | "0x5dbe3123", 629 | "0x469f59c1" 630 | ], 631 | "name": "cube_instance_16_material" 632 | }, 633 | { 634 | "arguments": { 635 | "normal=": 10 636 | }, 637 | "definition": "mdl::nvidia::core_definitions::thick_glass", 638 | "hash": [ 639 | "0x45a51489", 640 | "0x068b105e", 641 | "0xcfed7f3b", 642 | "0x1b45b4f8" 643 | ], 644 | "name": "sphere_instance_material" 645 | }, 646 | { 647 | "definition": "mdl::state::normal()", 648 | "name": "mdl::state::normal_804" 649 | }, 650 | { 651 | "arguments": { 652 | "roughness_factor": 0.0 653 | }, 654 | "definition": "mdl::gltf_support::gltf_material", 655 | "hash": [ 656 | "0x2b557fab", 657 | "0x5f2f13b5", 658 | "0x5dbe3123", 659 | "0x469f59c1" 660 | ], 661 | "name": "sphere_instance_22_material" 662 | } 663 | ] 664 | } 665 | }, 666 | "extensionsUsed": [ 667 | "NV_materials_mdl", 668 | "KHR_lights_punctual" 669 | ], 670 | "materials": [ 671 | { 672 | "doubleSided": true, 673 | "extensions": { 674 | "NV_materials_mdl": { 675 | "mdl_shader": 1 676 | } 677 | }, 678 | "name": "cube_instance_material", 679 | "pbrMetallicRoughness": { 680 | "metallicFactor": 0.0 681 | } 682 | }, 683 | { 684 | "doubleSided": true, 685 | "extensions": { 686 | "NV_materials_mdl": { 687 | "mdl_shader": 2 688 | } 689 | }, 690 | "name": "cube_instance_2_material", 691 | "pbrMetallicRoughness": { 692 | "metallicFactor": 0.0 693 | } 694 | }, 695 | { 696 | "doubleSided": true, 697 | "extensions": { 698 | "NV_materials_mdl": { 699 | "mdl_shader": 3 700 | } 701 | }, 702 | "name": "gltf_material_mat", 703 | "pbrMetallicRoughness": { 704 | "baseColorFactor": [ 705 | 0.054592281579971313, 706 | 1.0, 707 | 0.0, 708 | 1.0 709 | ] 710 | } 711 | }, 712 | { 713 | "doubleSided": true, 714 | "extensions": { 715 | "NV_materials_mdl": { 716 | "mdl_shader": 4 717 | } 718 | }, 719 | "name": "cube_instance_5_material", 720 | "pbrMetallicRoughness": { 721 | "baseColorFactor": [ 722 | 1.0, 723 | 0.0, 724 | 0.00010718735575210303, 725 | 1.0 726 | ], 727 | "metallicFactor": 0.0 728 | } 729 | }, 730 | { 731 | "doubleSided": true, 732 | "emissiveFactor": [ 733 | 3.0, 734 | 3.0, 735 | 3.0 736 | ], 737 | "extensions": { 738 | "NV_materials_mdl": { 739 | "mdl_shader": 5 740 | } 741 | }, 742 | "name": "cube_instance_8_material", 743 | "pbrMetallicRoughness": { 744 | "metallicFactor": 0.0, 745 | "roughnessFactor": 0.0 746 | } 747 | }, 748 | { 749 | "doubleSided": true, 750 | "extensions": { 751 | "NV_materials_mdl": { 752 | "mdl_shader": 6 753 | } 754 | }, 755 | "name": "cube_instance_14_material", 756 | "pbrMetallicRoughness": { 757 | "baseColorFactor": [ 758 | 0.5, 759 | 0.5, 760 | 0.5, 761 | 1.0 762 | ] 763 | } 764 | }, 765 | { 766 | "doubleSided": true, 767 | "extensions": { 768 | "NV_materials_mdl": { 769 | "mdl_shader": 8 770 | } 771 | }, 772 | "name": "cube_instance_16_material" 773 | }, 774 | { 775 | "alphaMode": "BLEND", 776 | "doubleSided": true, 777 | "extensions": { 778 | "NV_materials_mdl": { 779 | "mdl_shader": 9 780 | } 781 | }, 782 | "name": "sphere_instance_material", 783 | "pbrMetallicRoughness": { 784 | "baseColorFactor": [ 785 | 0.949999988079071, 786 | 0.949999988079071, 787 | 0.949999988079071, 788 | 0.3 789 | ], 790 | "roughnessFactor": 0.0 791 | } 792 | }, 793 | { 794 | "doubleSided": true, 795 | "extensions": { 796 | "NV_materials_mdl": { 797 | "mdl_shader": 11 798 | } 799 | }, 800 | "name": "sphere_instance_22_material", 801 | "pbrMetallicRoughness": { 802 | "roughnessFactor": 0.0 803 | } 804 | } 805 | ], 806 | "meshes": [ 807 | { 808 | "name": "cube", 809 | "primitives": [ 810 | { 811 | "attributes": { 812 | "NORMAL": 1, 813 | "POSITION": 0, 814 | "TEXCOORD_0": 2 815 | }, 816 | "indices": 3, 817 | "material": 0, 818 | "mode": 4 819 | } 820 | ] 821 | }, 822 | { 823 | "name": "cube_1", 824 | "primitives": [ 825 | { 826 | "attributes": { 827 | "NORMAL": 5, 828 | "POSITION": 4, 829 | "TEXCOORD_0": 6 830 | }, 831 | "indices": 7, 832 | "material": 1, 833 | "mode": 4 834 | } 835 | ] 836 | }, 837 | { 838 | "name": "cube_4", 839 | "primitives": [ 840 | { 841 | "attributes": { 842 | "NORMAL": 9, 843 | "POSITION": 8, 844 | "TEXCOORD_0": 10 845 | }, 846 | "indices": 11, 847 | "material": 2, 848 | "mode": 4 849 | } 850 | ] 851 | }, 852 | { 853 | "name": "cube_4", 854 | "primitives": [ 855 | { 856 | "attributes": { 857 | "NORMAL": 9, 858 | "POSITION": 8, 859 | "TEXCOORD_0": 10 860 | }, 861 | "indices": 11, 862 | "material": 3, 863 | "mode": 4 864 | } 865 | ] 866 | }, 867 | { 868 | "name": "cube_7", 869 | "primitives": [ 870 | { 871 | "attributes": { 872 | "NORMAL": 13, 873 | "POSITION": 12, 874 | "TEXCOORD_0": 14 875 | }, 876 | "indices": 15, 877 | "material": 4, 878 | "mode": 4 879 | } 880 | ] 881 | }, 882 | { 883 | "name": "cube_13", 884 | "primitives": [ 885 | { 886 | "attributes": { 887 | "NORMAL": 17, 888 | "POSITION": 16, 889 | "TEXCOORD_0": 18 890 | }, 891 | "indices": 19, 892 | "material": 5, 893 | "mode": 4 894 | } 895 | ] 896 | }, 897 | { 898 | "name": "cube_15", 899 | "primitives": [ 900 | { 901 | "attributes": { 902 | "NORMAL": 21, 903 | "POSITION": 20, 904 | "TEXCOORD_0": 22 905 | }, 906 | "indices": 23, 907 | "material": 6, 908 | "mode": 4 909 | } 910 | ] 911 | }, 912 | { 913 | "name": "sphere", 914 | "primitives": [ 915 | { 916 | "attributes": { 917 | "NORMAL": 25, 918 | "POSITION": 24, 919 | "TEXCOORD_0": 26 920 | }, 921 | "indices": 27, 922 | "material": 7, 923 | "mode": 4 924 | } 925 | ] 926 | }, 927 | { 928 | "name": "sphere_21", 929 | "primitives": [ 930 | { 931 | "attributes": { 932 | "NORMAL": 29, 933 | "POSITION": 28, 934 | "TEXCOORD_0": 30 935 | }, 936 | "indices": 31, 937 | "material": 8, 938 | "mode": 4 939 | } 940 | ] 941 | } 942 | ], 943 | "nodes": [ 944 | { 945 | "camera": 0, 946 | "extras": { 947 | "attributes_iray": { 948 | "iview:fkey": -1, 949 | "iview:fov": 53.130104064941406, 950 | "iview:interest": [ 951 | 0.0, 952 | 0.0, 953 | 0.0 954 | ], 955 | "iview:position": [ 956 | 0.0, 957 | 0.0, 958 | 19.99209213256836 959 | ], 960 | "iview:roll": 0.0, 961 | "iview:up": [ 962 | 0.0, 963 | 1.0, 964 | 0.0 965 | ] 966 | } 967 | }, 968 | "matrix": [ 969 | 1.0, 970 | 0.0, 971 | 0.0, 972 | 0.0, 973 | 0.0, 974 | 1.0, 975 | 0.0, 976 | 0.0, 977 | -0.0, 978 | -0.0, 979 | 1.0, 980 | -0.0, 981 | 0.0, 982 | 0.0, 983 | 19.992091970966317, 984 | 1.0 985 | ], 986 | "name": "CamInst" 987 | }, 988 | { 989 | "extras": { 990 | "attributes_iray": { 991 | "caustic": true, 992 | "caustic_cast": true, 993 | "caustic_recv": true, 994 | "face_back": true, 995 | "face_front": true, 996 | "finalgather": true, 997 | "finalgather_cast": true, 998 | "finalgather_recv": true, 999 | "globillum": true, 1000 | "globillum_cast": true, 1001 | "globillum_recv": true, 1002 | "label": 6740987, 1003 | "pickable": true, 1004 | "reflection_cast": true, 1005 | "reflection_recv": true, 1006 | "refraction_cast": true, 1007 | "refraction_recv": true, 1008 | "shadow_cast": true, 1009 | "shadow_recv": true, 1010 | "transparency_cast": true, 1011 | "transparency_recv": true, 1012 | "visible": true 1013 | } 1014 | }, 1015 | "matrix": [ 1016 | 1.0, 1017 | 0.0, 1018 | 0.0, 1019 | 0.0, 1020 | 0.0, 1021 | 1.0, 1022 | 0.0, 1023 | 0.0, 1024 | 0.0, 1025 | 0.0, 1026 | 1.0, 1027 | 0.0, 1028 | -0.0, 1029 | -0.0, 1030 | -5.0, 1031 | 1.0 1032 | ], 1033 | "mesh": 0, 1034 | "name": "cube_instance" 1035 | }, 1036 | { 1037 | "extras": { 1038 | "attributes_iray": { 1039 | "caustic": true, 1040 | "caustic_cast": true, 1041 | "caustic_recv": true, 1042 | "face_back": true, 1043 | "face_front": true, 1044 | "finalgather": true, 1045 | "finalgather_cast": true, 1046 | "finalgather_recv": true, 1047 | "globillum": true, 1048 | "globillum_cast": true, 1049 | "globillum_recv": true, 1050 | "label": 11403449, 1051 | "pickable": true, 1052 | "reflection_cast": true, 1053 | "reflection_recv": true, 1054 | "refraction_cast": true, 1055 | "refraction_recv": true, 1056 | "shadow_cast": true, 1057 | "shadow_recv": true, 1058 | "transparency_cast": true, 1059 | "transparency_recv": true, 1060 | "visible": true 1061 | } 1062 | }, 1063 | "matrix": [ 1064 | 1.0, 1065 | 0.0, 1066 | 0.0, 1067 | 0.0, 1068 | 0.0, 1069 | 1.0, 1070 | 0.0, 1071 | 0.0, 1072 | 0.0, 1073 | 0.0, 1074 | 1.0, 1075 | 0.0, 1076 | -0.0, 1077 | -5.0, 1078 | -0.0, 1079 | 1.0 1080 | ], 1081 | "mesh": 1, 1082 | "name": "cube_instance_2" 1083 | }, 1084 | { 1085 | "extras": { 1086 | "attributes_iray": { 1087 | "caustic": true, 1088 | "caustic_cast": true, 1089 | "caustic_recv": true, 1090 | "face_back": true, 1091 | "face_front": true, 1092 | "finalgather": true, 1093 | "finalgather_cast": true, 1094 | "finalgather_recv": true, 1095 | "globillum": true, 1096 | "globillum_cast": true, 1097 | "globillum_recv": true, 1098 | "label": 3789598, 1099 | "pickable": true, 1100 | "reflection_cast": true, 1101 | "reflection_recv": true, 1102 | "refraction_cast": true, 1103 | "refraction_recv": true, 1104 | "shadow_cast": true, 1105 | "shadow_recv": true, 1106 | "transparency_cast": true, 1107 | "transparency_recv": true, 1108 | "visible": true 1109 | } 1110 | }, 1111 | "matrix": [ 1112 | 1.0, 1113 | 0.0, 1114 | 0.0, 1115 | 0.0, 1116 | -0.0, 1117 | 1.0, 1118 | -0.0, 1119 | -0.0, 1120 | 0.0, 1121 | 0.0, 1122 | 1.0, 1123 | 0.0, 1124 | 0.0, 1125 | 5.0, 1126 | 0.0, 1127 | 1.0 1128 | ], 1129 | "mesh": 1, 1130 | "name": "cube_instance_3" 1131 | }, 1132 | { 1133 | "extras": { 1134 | "attributes_iray": { 1135 | "caustic": true, 1136 | "caustic_cast": true, 1137 | "caustic_recv": true, 1138 | "face_back": true, 1139 | "face_front": true, 1140 | "finalgather": true, 1141 | "finalgather_cast": true, 1142 | "finalgather_recv": true, 1143 | "globillum": true, 1144 | "globillum_cast": true, 1145 | "globillum_recv": true, 1146 | "label": 14125590, 1147 | "pickable": true, 1148 | "reflection_cast": true, 1149 | "reflection_recv": true, 1150 | "refraction_cast": true, 1151 | "refraction_recv": true, 1152 | "shadow_cast": true, 1153 | "shadow_recv": true, 1154 | "transparency_cast": true, 1155 | "transparency_recv": true, 1156 | "visible": true 1157 | } 1158 | }, 1159 | "matrix": [ 1160 | 1.0, 1161 | 0.0, 1162 | 0.0, 1163 | 0.0, 1164 | 0.0, 1165 | 1.0, 1166 | 0.0, 1167 | 0.0, 1168 | 0.0, 1169 | 0.0, 1170 | 1.0, 1171 | 0.0, 1172 | -5.0, 1173 | -0.0, 1174 | -0.0, 1175 | 1.0 1176 | ], 1177 | "mesh": 2, 1178 | "name": "cube_instance_5" 1179 | }, 1180 | { 1181 | "extras": { 1182 | "attributes_iray": { 1183 | "caustic": true, 1184 | "caustic_cast": true, 1185 | "caustic_recv": true, 1186 | "face_back": true, 1187 | "face_front": true, 1188 | "finalgather": true, 1189 | "finalgather_cast": true, 1190 | "finalgather_recv": true, 1191 | "globillum": true, 1192 | "globillum_cast": true, 1193 | "globillum_recv": true, 1194 | "label": 1448622, 1195 | "pickable": true, 1196 | "reflection_cast": true, 1197 | "reflection_recv": true, 1198 | "refraction_cast": true, 1199 | "refraction_recv": true, 1200 | "shadow_cast": true, 1201 | "shadow_recv": true, 1202 | "transparency_cast": true, 1203 | "transparency_recv": true, 1204 | "visible": true 1205 | } 1206 | }, 1207 | "matrix": [ 1208 | 1.0, 1209 | -0.0, 1210 | -0.0, 1211 | -0.0, 1212 | 0.0, 1213 | 1.0, 1214 | 0.0, 1215 | 0.0, 1216 | 0.0, 1217 | 0.0, 1218 | 1.0, 1219 | 0.0, 1220 | 5.0, 1221 | 0.0, 1222 | 0.0, 1223 | 1.0 1224 | ], 1225 | "mesh": 3, 1226 | "name": "cube_instance_6" 1227 | }, 1228 | { 1229 | "extras": { 1230 | "attributes_iray": { 1231 | "caustic": true, 1232 | "caustic_cast": true, 1233 | "caustic_recv": true, 1234 | "face_back": true, 1235 | "face_front": true, 1236 | "finalgather": true, 1237 | "finalgather_cast": true, 1238 | "finalgather_recv": true, 1239 | "globillum": true, 1240 | "globillum_cast": true, 1241 | "globillum_recv": true, 1242 | "label": 144522, 1243 | "pickable": true, 1244 | "reflection_cast": true, 1245 | "reflection_recv": true, 1246 | "refraction_cast": true, 1247 | "refraction_recv": true, 1248 | "shadow_cast": true, 1249 | "shadow_recv": true, 1250 | "transparency_cast": true, 1251 | "transparency_recv": true, 1252 | "visible": true 1253 | } 1254 | }, 1255 | "matrix": [ 1256 | 3.0, 1257 | 0.0, 1258 | 0.0, 1259 | 0.0, 1260 | -0.0, 1261 | 1.0000000000000022, 1262 | -0.0, 1263 | -0.0, 1264 | 0.0, 1265 | 0.0, 1266 | 3.0, 1267 | 0.0, 1268 | 0.0, 1269 | 4.626189558760184, 1270 | 0.0, 1271 | 1.0 1272 | ], 1273 | "mesh": 4, 1274 | "name": "cube_instance_8" 1275 | }, 1276 | { 1277 | "extras": { 1278 | "attributes_iray": { 1279 | "caustic": true, 1280 | "caustic_cast": true, 1281 | "caustic_recv": true, 1282 | "face_back": true, 1283 | "face_front": true, 1284 | "finalgather": true, 1285 | "finalgather_cast": true, 1286 | "finalgather_recv": true, 1287 | "globillum": true, 1288 | "globillum_cast": true, 1289 | "globillum_recv": true, 1290 | "label": 16672517, 1291 | "pickable": true, 1292 | "reflection_cast": true, 1293 | "reflection_recv": true, 1294 | "refraction_cast": true, 1295 | "refraction_recv": true, 1296 | "shadow_cast": true, 1297 | "shadow_recv": true, 1298 | "transparency_cast": true, 1299 | "transparency_recv": true, 1300 | "visible": true 1301 | } 1302 | }, 1303 | "matrix": [ 1304 | 1.4339410908776151, 1305 | -0.0, 1306 | -2.0478801107224793, 1307 | -0.0, 1308 | -3.172065784643304e-16, 1309 | 2.4999999999999996, 1310 | -4.758098676964956e-16, 1311 | 0.0, 1312 | 2.0478801107224793, 1313 | 0.0, 1314 | 1.4339410908776151, 1315 | 0.0, 1316 | 3.0, 1317 | -3.5, 1318 | 1.6790000000000003, 1319 | 1.0 1320 | ], 1321 | "mesh": 5, 1322 | "name": "cube_instance_14" 1323 | }, 1324 | { 1325 | "extras": { 1326 | "attributes_iray": { 1327 | "caustic": true, 1328 | "caustic_cast": true, 1329 | "caustic_recv": true, 1330 | "face_back": true, 1331 | "face_front": true, 1332 | "finalgather": true, 1333 | "finalgather_cast": true, 1334 | "finalgather_recv": true, 1335 | "globillum": true, 1336 | "globillum_cast": true, 1337 | "globillum_recv": true, 1338 | "label": 59962, 1339 | "pickable": true, 1340 | "reflection_cast": true, 1341 | "reflection_recv": true, 1342 | "refraction_cast": true, 1343 | "refraction_recv": true, 1344 | "shadow_cast": true, 1345 | "shadow_recv": true, 1346 | "transparency_cast": true, 1347 | "transparency_recv": true, 1348 | "visible": true 1349 | } 1350 | }, 1351 | "matrix": [ 1352 | 0.9986295347545739, 1353 | 0.0, 1354 | -0.05233595624294368, 1355 | 0.0, 1356 | 0.0, 1357 | 1.0, 1358 | 0.0, 1359 | 0.0, 1360 | 0.052335956242943835, 1361 | 0.0, 1362 | 0.9986295347545738, 1363 | 0.0, 1364 | -2.5, 1365 | -2.0, 1366 | -2.0, 1367 | 1.0 1368 | ], 1369 | "mesh": 6, 1370 | "name": "cube_instance_16" 1371 | }, 1372 | { 1373 | "extras": { 1374 | "attributes_iray": { 1375 | "caustic": true, 1376 | "caustic_cast": true, 1377 | "caustic_recv": true, 1378 | "face_back": true, 1379 | "face_front": true, 1380 | "finalgather": true, 1381 | "finalgather_cast": true, 1382 | "finalgather_recv": true, 1383 | "globillum": true, 1384 | "globillum_cast": true, 1385 | "globillum_recv": true, 1386 | "label": 16188119, 1387 | "pickable": true, 1388 | "reflection_cast": true, 1389 | "reflection_recv": true, 1390 | "refraction_cast": true, 1391 | "refraction_recv": true, 1392 | "shadow_cast": true, 1393 | "shadow_recv": true, 1394 | "transparency_cast": true, 1395 | "transparency_recv": true, 1396 | "visible": true 1397 | } 1398 | }, 1399 | "matrix": [ 1400 | 1.0, 1401 | 0.0, 1402 | 0.0, 1403 | 0.0, 1404 | 0.0, 1405 | 1.0, 1406 | 0.0, 1407 | 0.0, 1408 | 0.0, 1409 | 0.0, 1410 | 1.0, 1411 | 0.0, 1412 | 3.3113, 1413 | -1.0, 1414 | 0.0876, 1415 | 1.0 1416 | ], 1417 | "mesh": 7, 1418 | "name": "sphere_instance" 1419 | }, 1420 | { 1421 | "extras": { 1422 | "attributes_iray": { 1423 | "caustic": true, 1424 | "caustic_cast": true, 1425 | "caustic_recv": true, 1426 | "face_back": true, 1427 | "face_front": true, 1428 | "finalgather": true, 1429 | "finalgather_cast": true, 1430 | "finalgather_recv": true, 1431 | "globillum": true, 1432 | "globillum_cast": true, 1433 | "globillum_recv": true, 1434 | "label": 14590298, 1435 | "pickable": true, 1436 | "reflection_cast": true, 1437 | "reflection_recv": true, 1438 | "refraction_cast": true, 1439 | "refraction_recv": true, 1440 | "shadow_cast": true, 1441 | "shadow_recv": true, 1442 | "transparency_cast": true, 1443 | "transparency_recv": true, 1444 | "visible": true 1445 | } 1446 | }, 1447 | "matrix": [ 1448 | 1.0, 1449 | 0.0, 1450 | 0.0, 1451 | 0.0, 1452 | 0.0, 1453 | 1.0, 1454 | 0.0, 1455 | 0.0, 1456 | 0.0, 1457 | 0.0, 1458 | 1.0, 1459 | 0.0, 1460 | -3.0, 1461 | -4.0, 1462 | 3.0, 1463 | 1.0 1464 | ], 1465 | "mesh": 8, 1466 | "name": "sphere_instance_22" 1467 | } 1468 | ], 1469 | "scene": 0, 1470 | "scenes": [ 1471 | { 1472 | "extras": { 1473 | "attributes_iray": { 1474 | "IVP_color": [ 1475 | 1.0, 1476 | 0.0, 1477 | 0.0, 1478 | 1.0 1479 | ], 1480 | "depth": 4, 1481 | "depth_cutout": 16, 1482 | "depth_reflect": 4, 1483 | "depth_transp": 4, 1484 | "environment_dome_depth": 200.0, 1485 | "environment_dome_ground": false, 1486 | "environment_dome_ground_glossiness": 0.0, 1487 | "environment_dome_ground_legacy_reflection": false, 1488 | "environment_dome_ground_position": [ 1489 | 0.0, 1490 | 0.0, 1491 | 0.0 1492 | ], 1493 | "environment_dome_ground_reflectivity": [ 1494 | 1.0, 1495 | 1.0, 1496 | 1.0, 1497 | 1.0 1498 | ], 1499 | "environment_dome_ground_shadow_intensity": 1.0, 1500 | "environment_dome_ground_texturescale": 1.0, 1501 | "environment_dome_height": 200.0, 1502 | "environment_dome_mode": "infinite", 1503 | "environment_dome_position": [ 1504 | 0.0, 1505 | 0.0, 1506 | 0.0 1507 | ], 1508 | "environment_dome_radius": 100.0, 1509 | "environment_dome_rotation_angle": 0.0, 1510 | "environment_dome_width": 200.0, 1511 | "environment_function=": 0, 1512 | "environment_function_intensity": 1.0, 1513 | "iray_instancing": "off", 1514 | "iview::hdr_ev": 0.0, 1515 | "iview::inline_color": [ 1516 | 1.0, 1517 | 0.0, 1518 | 0.0, 1519 | 1.0 1520 | ], 1521 | "iview::inline_width": 1.0, 1522 | "iview::magnifier_size": 300, 1523 | "iview::offset": 10.0, 1524 | "iview::outline_color": [ 1525 | 0.0, 1526 | 0.0, 1527 | 0.0, 1528 | 1.0 1529 | ], 1530 | "iview::outline_width": 2.0, 1531 | "iview::overview": true, 1532 | "iview::zoom_factor": 1.0, 1533 | "iview:sunsky:active": true, 1534 | "iview:sunsky:date": "Tue Jun 16 2020", 1535 | "iview:sunsky:dst": true, 1536 | "iview:sunsky:latitude": 37.31999969482422, 1537 | "iview:sunsky:longitude": -122.02999877929688, 1538 | "iview:sunsky:time": "12:00:00", 1539 | "iview:sunsky:timezone": "America/Los_Angeles", 1540 | "progressive_rendering_max_samples": 10, 1541 | "samples": 4.0, 1542 | "shadow_cast": true, 1543 | "shadow_recv": true 1544 | } 1545 | }, 1546 | "nodes": [ 1547 | 0, 1548 | 1, 1549 | 2, 1550 | 3, 1551 | 4, 1552 | 5, 1553 | 6, 1554 | 7, 1555 | 8, 1556 | 9, 1557 | 10 1558 | ] 1559 | } 1560 | ], 1561 | "textures": [ 1562 | { 1563 | "extras": { 1564 | "gamma": 0.0 1565 | }, 1566 | "name": "tex", 1567 | "source": 0 1568 | } 1569 | ] 1570 | } 1571 | -------------------------------------------------------------------------------- /media/cube.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/cube.bin -------------------------------------------------------------------------------- /media/cube.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "accessors": [ 3 | { 4 | "bufferView": 0, 5 | "componentType": 5126, 6 | "count": 24, 7 | "max": [ 8 | 0.5, 9 | 0.5, 10 | 0.5 11 | ], 12 | "min": [ 13 | -0.5, 14 | -0.5, 15 | -0.5 16 | ], 17 | "type": "VEC3" 18 | }, 19 | { 20 | "bufferView": 1, 21 | "componentType": 5126, 22 | "count": 24, 23 | "type": "VEC3" 24 | }, 25 | { 26 | "bufferView": 2, 27 | "componentType": 5126, 28 | "count": 24, 29 | "type": "VEC2" 30 | }, 31 | { 32 | "bufferView": 3, 33 | "componentType": 5125, 34 | "count": 36, 35 | "type": "SCALAR" 36 | } 37 | ], 38 | "asset": { 39 | "copyright": "NVIDIA Corporation", 40 | "generator": "Iray glTF plugin", 41 | "version": "2.0" 42 | }, 43 | "bufferViews": [ 44 | { 45 | "buffer": 0, 46 | "byteLength": 288, 47 | "byteStride": 12 48 | }, 49 | { 50 | "buffer": 0, 51 | "byteLength": 288, 52 | "byteOffset": 288, 53 | "byteStride": 12 54 | }, 55 | { 56 | "buffer": 0, 57 | "byteLength": 192, 58 | "byteOffset": 576, 59 | "byteStride": 8 60 | }, 61 | { 62 | "buffer": 0, 63 | "byteLength": 144, 64 | "byteOffset": 768 65 | } 66 | ], 67 | "buffers": [ 68 | { 69 | "byteLength": 912, 70 | "uri": "cube.bin" 71 | } 72 | ], 73 | "cameras": [ 74 | { 75 | "name": "default", 76 | "perspective": { 77 | "aspectRatio": 1.3333333730697632, 78 | "yfov": 0.7417964935302734, 79 | "zfar": 1000.0, 80 | "znear": 0.1 81 | }, 82 | "type": "perspective" 83 | } 84 | ], 85 | "materials": [ 86 | { 87 | "doubleSided": true, 88 | "name": "cube_instance_material" 89 | } 90 | ], 91 | "meshes": [ 92 | { 93 | "name": "cube", 94 | "primitives": [ 95 | { 96 | "attributes": { 97 | "NORMAL": 1, 98 | "POSITION": 0, 99 | "TEXCOORD_0": 2 100 | }, 101 | "indices": 3, 102 | "material": 0, 103 | "mode": 4 104 | } 105 | ] 106 | } 107 | ], 108 | "nodes": [ 109 | { 110 | "camera": 0, 111 | "matrix": [ 112 | 0.7349284364472454, 113 | -0.0, 114 | -0.6781446698907297, 115 | -0.0, 116 | -0.3874752425954602, 117 | 0.8206887657283436, 118 | -0.41992009499769933, 119 | -0.0, 120 | 0.5565457121178783, 121 | 0.5713754893301669, 122 | 0.6031475114065514, 123 | 0.0, 124 | 1.730909784565274, 125 | 1.7770317938104678, 126 | 1.8758457864260285, 127 | 1.0 128 | ], 129 | "name": "CamInst" 130 | }, 131 | { 132 | "mesh": 0, 133 | "name": "cube_instance" 134 | } 135 | ], 136 | "scene": 0, 137 | "scenes": [ 138 | { 139 | "nodes": [ 140 | 0, 141 | 1 142 | ] 143 | } 144 | ] 145 | } 146 | -------------------------------------------------------------------------------- /media/cubeTextured.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/cubeTextured.bin -------------------------------------------------------------------------------- /media/cubeTextured.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "accessors": [ 3 | { 4 | "bufferView": 0, 5 | "componentType": 5126, 6 | "count": 24, 7 | "max": [ 8 | 0.5, 9 | 0.5, 10 | 0.5 11 | ], 12 | "min": [ 13 | -0.5, 14 | -0.5, 15 | -0.5 16 | ], 17 | "type": "VEC3" 18 | }, 19 | { 20 | "bufferView": 1, 21 | "componentType": 5126, 22 | "count": 24, 23 | "type": "VEC3" 24 | }, 25 | { 26 | "bufferView": 2, 27 | "componentType": 5126, 28 | "count": 24, 29 | "type": "VEC2" 30 | }, 31 | { 32 | "bufferView": 3, 33 | "componentType": 5125, 34 | "count": 36, 35 | "type": "SCALAR" 36 | } 37 | ], 38 | "asset": { 39 | "copyright": "NVIDIA Corporation", 40 | "generator": "Iray glTF plugin", 41 | "version": "2.0" 42 | }, 43 | "bufferViews": [ 44 | { 45 | "buffer": 0, 46 | "byteLength": 288, 47 | "byteStride": 12 48 | }, 49 | { 50 | "buffer": 0, 51 | "byteLength": 288, 52 | "byteOffset": 288, 53 | "byteStride": 12 54 | }, 55 | { 56 | "buffer": 0, 57 | "byteLength": 192, 58 | "byteOffset": 576, 59 | "byteStride": 8 60 | }, 61 | { 62 | "buffer": 0, 63 | "byteLength": 144, 64 | "byteOffset": 768 65 | } 66 | ], 67 | "buffers": [ 68 | { 69 | "byteLength": 912, 70 | "uri": "cubeTextured.bin" 71 | } 72 | ], 73 | "cameras": [ 74 | { 75 | "name": "default", 76 | "perspective": { 77 | "aspectRatio": 1.3333333730697632, 78 | "yfov": 0.7417964935302734, 79 | "zfar": 1000.0, 80 | "znear": 0.1 81 | }, 82 | "type": "perspective" 83 | } 84 | ], 85 | "images": [ 86 | { 87 | "name": "img_1", 88 | "uri": "NVIDIA_logo2.png" 89 | } 90 | ], 91 | "materials": [ 92 | { 93 | "doubleSided": true, 94 | "name": "cube_instance_material", 95 | "pbrMetallicRoughness": { 96 | "baseColorTexture": { 97 | "index": 0 98 | } 99 | } 100 | } 101 | ], 102 | "meshes": [ 103 | { 104 | "name": "cube", 105 | "primitives": [ 106 | { 107 | "attributes": { 108 | "NORMAL": 1, 109 | "POSITION": 0, 110 | "TEXCOORD_0": 2 111 | }, 112 | "indices": 3, 113 | "material": 0, 114 | "mode": 4 115 | } 116 | ] 117 | } 118 | ], 119 | "nodes": [ 120 | { 121 | "camera": 0, 122 | "matrix": [ 123 | 0.7349284364472454, 124 | -0.0, 125 | -0.6781446698907297, 126 | -0.0, 127 | -0.3874752425954602, 128 | 0.8206887657283436, 129 | -0.41992009499769933, 130 | -0.0, 131 | 0.5565457121178783, 132 | 0.5713754893301669, 133 | 0.6031475114065514, 134 | 0.0, 135 | 1.730909784565274, 136 | 1.7770317938104678, 137 | 1.8758457864260285, 138 | 1.0 139 | ], 140 | "name": "CamInst" 141 | }, 142 | { 143 | "mesh": 0, 144 | "name": "cube_instance" 145 | } 146 | ], 147 | "scene": 0, 148 | "scenes": [ 149 | { 150 | "nodes": [ 151 | 0, 152 | 1 153 | ] 154 | } 155 | ], 156 | "textures": [ 157 | { 158 | "name": "tex_2", 159 | "source": 0 160 | } 161 | ] 162 | } 163 | -------------------------------------------------------------------------------- /media/cubeTexturedKtx.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "accessors": [ 3 | { 4 | "bufferView": 0, 5 | "componentType": 5126, 6 | "count": 24, 7 | "max": [ 8 | 0.5, 9 | 0.5, 10 | 0.5 11 | ], 12 | "min": [ 13 | -0.5, 14 | -0.5, 15 | -0.5 16 | ], 17 | "type": "VEC3" 18 | }, 19 | { 20 | "bufferView": 1, 21 | "componentType": 5126, 22 | "count": 24, 23 | "type": "VEC3" 24 | }, 25 | { 26 | "bufferView": 2, 27 | "componentType": 5126, 28 | "count": 24, 29 | "type": "VEC2" 30 | }, 31 | { 32 | "bufferView": 3, 33 | "componentType": 5125, 34 | "count": 36, 35 | "type": "SCALAR" 36 | } 37 | ], 38 | "asset": { 39 | "copyright": "NVIDIA Corporation", 40 | "generator": "Iray glTF plugin", 41 | "version": "2.0" 42 | }, 43 | "bufferViews": [ 44 | { 45 | "buffer": 0, 46 | "byteLength": 288, 47 | "byteStride": 12 48 | }, 49 | { 50 | "buffer": 0, 51 | "byteLength": 288, 52 | "byteOffset": 288, 53 | "byteStride": 12 54 | }, 55 | { 56 | "buffer": 0, 57 | "byteLength": 192, 58 | "byteOffset": 576, 59 | "byteStride": 8 60 | }, 61 | { 62 | "buffer": 0, 63 | "byteLength": 144, 64 | "byteOffset": 768 65 | } 66 | ], 67 | "buffers": [ 68 | { 69 | "byteLength": 912, 70 | "uri": "cubeTextured.bin" 71 | } 72 | ], 73 | "cameras": [ 74 | { 75 | "name": "default", 76 | "perspective": { 77 | "aspectRatio": 1.3333333730697632, 78 | "yfov": 0.7417964935302734, 79 | "zfar": 1000.0, 80 | "znear": 0.1 81 | }, 82 | "type": "perspective" 83 | } 84 | ], 85 | "images": [ 86 | { 87 | "name": "img_1", 88 | "uri": "NVIDIA_logo2.ktx2" 89 | } 90 | ], 91 | "materials": [ 92 | { 93 | "doubleSided": true, 94 | "name": "cube_instance_material", 95 | "pbrMetallicRoughness": { 96 | "baseColorTexture": { 97 | "index": 0 98 | } 99 | } 100 | } 101 | ], 102 | "meshes": [ 103 | { 104 | "name": "cube", 105 | "primitives": [ 106 | { 107 | "attributes": { 108 | "NORMAL": 1, 109 | "POSITION": 0, 110 | "TEXCOORD_0": 2 111 | }, 112 | "indices": 3, 113 | "material": 0, 114 | "mode": 4 115 | } 116 | ] 117 | } 118 | ], 119 | "nodes": [ 120 | { 121 | "camera": 0, 122 | "matrix": [ 123 | 0.7349284364472454, 124 | -0.0, 125 | -0.6781446698907297, 126 | -0.0, 127 | -0.3874752425954602, 128 | 0.8206887657283436, 129 | -0.41992009499769933, 130 | -0.0, 131 | 0.5565457121178783, 132 | 0.5713754893301669, 133 | 0.6031475114065514, 134 | 0.0, 135 | 1.730909784565274, 136 | 1.7770317938104678, 137 | 1.8758457864260285, 138 | 1.0 139 | ], 140 | "name": "CamInst" 141 | }, 142 | { 143 | "mesh": 0, 144 | "name": "cube_instance" 145 | } 146 | ], 147 | "scene": 0, 148 | "scenes": [ 149 | { 150 | "nodes": [ 151 | 0, 152 | 1 153 | ] 154 | } 155 | ], 156 | "textures": [ 157 | { 158 | "name": "tex_2", 159 | "source": 0 160 | } 161 | ] 162 | } 163 | -------------------------------------------------------------------------------- /media/env3.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/env3.hdr -------------------------------------------------------------------------------- /media/fruit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/fruit.jpg -------------------------------------------------------------------------------- /media/fruit.ktx2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/fruit.ktx2 -------------------------------------------------------------------------------- /media/license_meet_mat.txt: -------------------------------------------------------------------------------- 1 | Model Information: 2 | * title: Meet MAT 3 | * source: https://sketchfab.com/3d-models/meet-mat-6d467069570e48c99a5fd5e6db53561b 4 | * author: Adobe substance 3D (https://sketchfab.com/substance3D) 5 | 6 | Model License: 7 | * license type: CC-BY-NC-4.0 (http://creativecommons.org/licenses/by-nc/4.0/) 8 | * requirements: Author must be credited. No commercial use. 9 | 10 | If you use this 3D model in your project be sure to copy paste this credit wherever you share it: 11 | This work is based on "Meet MAT" (https://sketchfab.com/3d-models/meet-mat-6d467069570e48c99a5fd5e6db53561b) by Adobe substance 3D (https://sketchfab.com/substance3D) licensed under CC-BY-NC-4.0 (http://creativecommons.org/licenses/by-nc/4.0/) -------------------------------------------------------------------------------- /media/meet_mat.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/meet_mat.glb -------------------------------------------------------------------------------- /media/shader_ball.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/shader_ball.bin -------------------------------------------------------------------------------- /media/shader_ball.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "accessors": [ 3 | { 4 | "bufferView": 0, 5 | "componentType": 5126, 6 | "count": 8093, 7 | "max": [ 8 | 1.3013720512390137, 9 | 1.0, 10 | 1.2017070055007935 11 | ], 12 | "min": [ 13 | -1.0, 14 | -1.045469045639038, 15 | -1.2017070055007935 16 | ], 17 | "type": "VEC3" 18 | }, 19 | { 20 | "bufferView": 1, 21 | "componentType": 5126, 22 | "count": 8093, 23 | "type": "VEC3" 24 | }, 25 | { 26 | "bufferView": 2, 27 | "componentType": 5126, 28 | "count": 8093, 29 | "type": "VEC2" 30 | }, 31 | { 32 | "bufferView": 3, 33 | "componentType": 5125, 34 | "count": 28350, 35 | "type": "SCALAR" 36 | } 37 | ], 38 | "asset": { 39 | "copyright": "NVIDIA Corporation", 40 | "generator": "Iray glTF plugin", 41 | "version": "2.0" 42 | }, 43 | "bufferViews": [ 44 | { 45 | "buffer": 0, 46 | "byteLength": 97116, 47 | "byteStride": 12 48 | }, 49 | { 50 | "buffer": 0, 51 | "byteLength": 97116, 52 | "byteOffset": 97116, 53 | "byteStride": 12 54 | }, 55 | { 56 | "buffer": 0, 57 | "byteLength": 64744, 58 | "byteOffset": 194232, 59 | "byteStride": 8 60 | }, 61 | { 62 | "buffer": 0, 63 | "byteLength": 113400, 64 | "byteOffset": 258976 65 | } 66 | ], 67 | "buffers": [ 68 | { 69 | "byteLength": 372376, 70 | "uri": "shader_ball.bin" 71 | } 72 | ], 73 | "cameras": [ 74 | { 75 | "extensions": { 76 | "NV_attributes_iray": { 77 | "attributes": [ 78 | { 79 | "name": "mip_burn_highlights", 80 | "type": "Float32", 81 | "value": 0.699999988079071 82 | }, 83 | { 84 | "name": "mip_lens_focus", 85 | "type": "Float32", 86 | "value": 0.0 87 | }, 88 | { 89 | "name": "mip_lens_radius", 90 | "type": "Float32", 91 | "value": 0.0 92 | }, 93 | { 94 | "name": "mip_crush_blacks", 95 | "type": "Float32", 96 | "value": 0.5 97 | }, 98 | { 99 | "name": "mip_f_number", 100 | "type": "Float32", 101 | "value": 2.0 102 | }, 103 | { 104 | "name": "mip_saturation", 105 | "type": "Float32", 106 | "value": 1.0 107 | }, 108 | { 109 | "name": "mip_cm2_factor", 110 | "type": "Float32", 111 | "value": 1.0 112 | }, 113 | { 114 | "name": "mip_vignetting", 115 | "type": "Float32", 116 | "value": 0.0 117 | }, 118 | { 119 | "name": "mip_burn_highlights_per_component", 120 | "type": "Boolean", 121 | "value": false 122 | }, 123 | { 124 | "name": "mip_gamma", 125 | "type": "Float32", 126 | "value": 2.200000047683716 127 | }, 128 | { 129 | "name": "mip_whitepoint", 130 | "type": "Color", 131 | "value": [ 132 | 1.0, 133 | 1.0, 134 | 1.0, 135 | 0.02716049551963806 136 | ] 137 | }, 138 | { 139 | "name": "mip_film_iso", 140 | "type": "Float32", 141 | "value": 100.0 142 | }, 143 | { 144 | "name": "mip_lens_thickness", 145 | "type": "Float32", 146 | "value": 0.0 147 | }, 148 | { 149 | "name": "tm_tonemapper", 150 | "type": "String", 151 | "value": "mia_exposure_photographic" 152 | }, 153 | { 154 | "name": "mip_camera_shutter", 155 | "type": "Float32", 156 | "value": 0.30778610706329346 157 | } 158 | ] 159 | } 160 | }, 161 | "extras": { 162 | "resolution": [ 163 | 640, 164 | 480 165 | ] 166 | }, 167 | "name": "default", 168 | "perspective": { 169 | "aspectRatio": 1.3333333730697632, 170 | "yfov": 0.7362615466117859, 171 | "zfar": 10000.0, 172 | "znear": 0.10000000149011612 173 | }, 174 | "type": "perspective" 175 | } 176 | ], 177 | "extensions": { 178 | "NV_materials_mdl": { 179 | "modules": [ 180 | "::base", 181 | "::gltf_support" 182 | ], 183 | "shaders": [ 184 | { 185 | "arguments": [ 186 | { 187 | "name": "texture", 188 | "value": 0 189 | } 190 | ], 191 | "definition": "::base::environment_spherical(texture_2d)", 192 | "name": "env_shd_8" 193 | }, 194 | { 195 | "arguments": [ 196 | { 197 | "name": "roughness_factor", 198 | "value": 0.5 199 | } 200 | ], 201 | "definition": "::gltf_support::gltf_material(color,texture_2d,int,float,float,texture_2d,int,texture_2d,int,int,float,float,texture_2d,int,float,texture_2d,int,texture_2d,int,int,color,texture_2d,int,texture_2d,float,int,::gltf_support::gltf_alpha_mode,float,float)", 202 | "name": "blinn2SG" 203 | } 204 | ] 205 | } 206 | }, 207 | "extensionsUsed": [ 208 | "NV_materials_mdl", 209 | "KHR_lights_punctual", 210 | "NV_attributes_iray" 211 | ], 212 | "images": [ 213 | { 214 | "name": "sample3.hdr", 215 | "uri": "shader_ballAssets\\sample3.hdr" 216 | } 217 | ], 218 | "materials": [ 219 | { 220 | "doubleSided": true, 221 | "extensions": { 222 | "NV_materials_mdl": { 223 | "mdl_shader": 1 224 | } 225 | }, 226 | "name": "blinn2SG", 227 | "pbrMetallicRoughness": { 228 | "roughnessFactor": 0.6 229 | } 230 | } 231 | ], 232 | "meshes": [ 233 | { 234 | "name": "polySurfaceShape11", 235 | "primitives": [ 236 | { 237 | "attributes": { 238 | "NORMAL": 1, 239 | "POSITION": 0, 240 | "TEXCOORD_0": 2 241 | }, 242 | "indices": 3, 243 | "material": 0, 244 | "mode": 4 245 | } 246 | ] 247 | } 248 | ], 249 | "nodes": [ 250 | { 251 | "camera": 0, 252 | "extensions": { 253 | "NV_attributes_iray": { 254 | "attributes": [ 255 | { 256 | "name": "iview:up", 257 | "type": "Float32<3>", 258 | "value": [ 259 | 0.0, 260 | 1.0, 261 | 0.0 262 | ] 263 | }, 264 | { 265 | "name": "iview:roll", 266 | "type": "Float32", 267 | "value": 0.0 268 | }, 269 | { 270 | "name": "iview:fkey", 271 | "type": "Sint32", 272 | "value": -1 273 | }, 274 | { 275 | "name": "iview:interest", 276 | "type": "Float32<3>", 277 | "value": [ 278 | -0.12095838040113449, 279 | -0.08095555752515793, 280 | 0.13380166888237 281 | ] 282 | }, 283 | { 284 | "name": "iview:position", 285 | "type": "Float32<3>", 286 | "value": [ 287 | -5.412760257720947, 288 | 3.007869243621826, 289 | -2.9272520542144775 290 | ] 291 | }, 292 | { 293 | "name": "iview:fov", 294 | "type": "Float32", 295 | "value": 54.432228088378906 296 | } 297 | ] 298 | } 299 | }, 300 | "matrix": [ 301 | -0.5007145417658573, 302 | 1.3190265968514163e-07, 303 | 0.8656126938498631, 304 | 0.0, 305 | 0.39035914223452695, 306 | 0.892542810433716, 307 | 0.22580404539530088, 308 | 0.0, 309 | -0.7725953983820218, 310 | 0.45096394842012943, 311 | -0.44690939069551067, 312 | -0.0, 313 | -5.4127602684444795, 314 | 3.0078693000514987, 315 | -2.9272519782591875, 316 | 1.0 317 | ], 318 | "name": "persp" 319 | }, 320 | { 321 | "extensions": { 322 | "NV_attributes_iray": { 323 | "attributes": [ 324 | { 325 | "name": "caustic", 326 | "type": "Boolean", 327 | "value": true 328 | }, 329 | { 330 | "name": "caustic_cast", 331 | "type": "Boolean", 332 | "value": true 333 | }, 334 | { 335 | "name": "caustic_recv", 336 | "type": "Boolean", 337 | "value": true 338 | }, 339 | { 340 | "name": "globillum", 341 | "type": "Boolean", 342 | "value": true 343 | }, 344 | { 345 | "name": "globillum_cast", 346 | "type": "Boolean", 347 | "value": true 348 | }, 349 | { 350 | "name": "globillum_recv", 351 | "type": "Boolean", 352 | "value": true 353 | }, 354 | { 355 | "name": "label", 356 | "type": "Sint32", 357 | "value": 6740987 358 | } 359 | ] 360 | } 361 | }, 362 | "mesh": 0, 363 | "name": "polySurface11" 364 | } 365 | ], 366 | "scene": 0, 367 | "scenes": [ 368 | { 369 | "extensions": { 370 | "NV_attributes_iray": { 371 | "attributes": [ 372 | { 373 | "name": "transparency_cast", 374 | "type": "Boolean", 375 | "value": true 376 | }, 377 | { 378 | "name": "transparency_recv", 379 | "type": "Boolean", 380 | "value": true 381 | }, 382 | { 383 | "name": "reflection_recv", 384 | "type": "Boolean", 385 | "value": true 386 | }, 387 | { 388 | "name": "refraction_recv", 389 | "type": "Boolean", 390 | "value": true 391 | }, 392 | { 393 | "name": "shadow_cast", 394 | "type": "Boolean", 395 | "value": true 396 | }, 397 | { 398 | "name": "shadow_recv", 399 | "type": "Boolean", 400 | "value": true 401 | }, 402 | { 403 | "name": "finalgather_recv", 404 | "type": "Boolean", 405 | "value": true 406 | }, 407 | { 408 | "name": "face_front", 409 | "type": "Boolean", 410 | "value": true 411 | }, 412 | { 413 | "name": "face_back", 414 | "type": "Boolean", 415 | "value": true 416 | }, 417 | { 418 | "name": "label", 419 | "type": "Sint32", 420 | "value": 8 421 | }, 422 | { 423 | "name": "samples", 424 | "type": "Float32", 425 | "value": 1.0 426 | }, 427 | { 428 | "name": "samples_adaptivity", 429 | "type": "Float32", 430 | "value": 1.0 431 | }, 432 | { 433 | "name": "filter", 434 | "type": "Sint32", 435 | "value": 2 436 | }, 437 | { 438 | "name": "radius", 439 | "type": "Float32", 440 | "value": 1.5 441 | }, 442 | { 443 | "name": "fg_mode", 444 | "type": "Sint32", 445 | "value": 0 446 | }, 447 | { 448 | "name": "ca_mode", 449 | "type": "Sint32", 450 | "value": 0 451 | }, 452 | { 453 | "name": "gi_mode", 454 | "type": "Sint32", 455 | "value": 0 456 | }, 457 | { 458 | "name": "progressive_rendering_converged_pixel_ratio", 459 | "type": "Float32", 460 | "value": 0.9998999834060669 461 | }, 462 | { 463 | "name": "iview::inline_width", 464 | "type": "Float32", 465 | "value": 1.0 466 | }, 467 | { 468 | "name": "iray_bloom_filtering_radius", 469 | "type": "Float32", 470 | "value": 0.009999999776482582 471 | }, 472 | { 473 | "name": "iview::magnifier_size", 474 | "type": "Sint32", 475 | "value": 300 476 | }, 477 | { 478 | "name": "environment_dome_depth", 479 | "type": "Float32", 480 | "value": 1000.0 481 | }, 482 | { 483 | "name": "environment_dome_ground_shadow_intensity", 484 | "type": "Float32", 485 | "value": 1.0 486 | }, 487 | { 488 | "name": "progressive_rendering_filtering", 489 | "type": "Boolean", 490 | "value": false 491 | }, 492 | { 493 | "name": "progressive_rendering_quality_enabled", 494 | "type": "Boolean", 495 | "value": true 496 | }, 497 | { 498 | "name": "environment_function_intensity", 499 | "type": "Float32", 500 | "value": 1.0 501 | }, 502 | { 503 | "name": "environment_dome_height", 504 | "type": "Float32", 505 | "value": 1000.0 506 | }, 507 | { 508 | "name": "iview:sunsky:latitude", 509 | "type": "Float32", 510 | "value": 37.31999969482422 511 | }, 512 | { 513 | "name": "iview::outline_width", 514 | "type": "Float32", 515 | "value": 2.0 516 | }, 517 | { 518 | "name": "iview::zoom_factor", 519 | "type": "Float32", 520 | "value": 1.0 521 | }, 522 | { 523 | "name": "iview:sunsky:active", 524 | "type": "Boolean", 525 | "value": true 526 | }, 527 | { 528 | "name": "iray_optix_prime", 529 | "type": "Boolean", 530 | "value": true 531 | }, 532 | { 533 | "name": "iray_architectural_sampler", 534 | "type": "Boolean", 535 | "value": false 536 | }, 537 | { 538 | "name": "iview:sunsky:dst", 539 | "type": "Boolean", 540 | "value": false 541 | }, 542 | { 543 | "name": "progressive_rendering_max_samples", 544 | "type": "Sint32", 545 | "value": 999999 546 | }, 547 | { 548 | "call": 0, 549 | "name": "environment_function", 550 | "type": "Ref" 551 | }, 552 | { 553 | "name": "iview::offset", 554 | "type": "Float32", 555 | "value": 10.0 556 | }, 557 | { 558 | "name": "iray_bloom_filtering_threshold", 559 | "type": "Float32", 560 | "value": 0.8999999761581421 561 | }, 562 | { 563 | "name": "environment_dome_ground", 564 | "type": "Boolean", 565 | "value": true 566 | }, 567 | { 568 | "name": "iray_instancing", 569 | "type": "String", 570 | "value": "off" 571 | }, 572 | { 573 | "name": "iray_caustic_sampler", 574 | "type": "Boolean", 575 | "value": false 576 | }, 577 | { 578 | "name": "iray_firefly_filter", 579 | "type": "Boolean", 580 | "value": true 581 | }, 582 | { 583 | "name": "iview:sunsky:date", 584 | "type": "String", 585 | "value": "Thu Feb 12 2015" 586 | }, 587 | { 588 | "name": "iview::overview", 589 | "type": "Boolean", 590 | "value": true 591 | }, 592 | { 593 | "name": "iview:sunsky:timezone", 594 | "type": "String", 595 | "value": "America/Los_Angeles" 596 | }, 597 | { 598 | "name": "iview:sunsky:longitude", 599 | "type": "Float32", 600 | "value": -122.02999877929688 601 | }, 602 | { 603 | "name": "iray_degrain_filtering", 604 | "type": "Sint32", 605 | "value": 0 606 | }, 607 | { 608 | "name": "IVP_color", 609 | "type": "Color", 610 | "value": [ 611 | 1.0, 612 | 0.0, 613 | 0.0, 614 | 1.0 615 | ] 616 | }, 617 | { 618 | "name": "environment_dome_width", 619 | "type": "Float32", 620 | "value": 1000.0 621 | }, 622 | { 623 | "name": "iray_restricted_realism_mode", 624 | "type": "Boolean", 625 | "value": false 626 | }, 627 | { 628 | "name": "iray_bloom_filtering_brightness_scale", 629 | "type": "Float32", 630 | "value": 1.0 631 | }, 632 | { 633 | "name": "irradiance_min", 634 | "type": "Float32", 635 | "value": 0.0 636 | }, 637 | { 638 | "name": "environment_dome_mode", 639 | "type": "String", 640 | "value": "infinite" 641 | }, 642 | { 643 | "name": "iview:sunsky:time", 644 | "type": "String", 645 | "value": "12:00:00" 646 | }, 647 | { 648 | "name": "environment_dome_ground_texturescale", 649 | "type": "Float32", 650 | "value": -5.0 651 | }, 652 | { 653 | "name": "iray_max_path_length", 654 | "type": "Sint32", 655 | "value": 23 656 | }, 657 | { 658 | "name": "environment_dome_rotation_angle", 659 | "type": "Float32", 660 | "value": 0.0 661 | }, 662 | { 663 | "name": "environment_dome_position", 664 | "type": "Float32<3>", 665 | "value": [ 666 | 0.0, 667 | -1.0499999523162842, 668 | 0.0 669 | ] 670 | }, 671 | { 672 | "name": "progressive_samples_per_motion_sample", 673 | "type": "Sint32", 674 | "value": 0 675 | }, 676 | { 677 | "name": "progressive_rendering_quality", 678 | "type": "Float32", 679 | "value": 1.0 680 | }, 681 | { 682 | "name": "environment_lighting_blur", 683 | "type": "Boolean", 684 | "value": false 685 | }, 686 | { 687 | "name": "iray_bloom_filtering", 688 | "type": "Boolean", 689 | "value": false 690 | }, 691 | { 692 | "name": "irradiance_max", 693 | "type": "Float32", 694 | "value": 120000.0 695 | }, 696 | { 697 | "name": "iray_degrain_filtering_blur_difference", 698 | "type": "Float32", 699 | "value": 0.05000000074505806 700 | }, 701 | { 702 | "name": "environment_dome_radius", 703 | "type": "Float32", 704 | "value": 1000.0 705 | }, 706 | { 707 | "name": "iray_black_pixel_filtering_max_frame", 708 | "type": "Sint32", 709 | "value": 16 710 | }, 711 | { 712 | "name": "irradiance_auto", 713 | "type": "Boolean", 714 | "value": true 715 | }, 716 | { 717 | "name": "progressive_rendering_min_samples", 718 | "type": "Sint32", 719 | "value": 1 720 | }, 721 | { 722 | "name": "iray_degrain_filtering_radius", 723 | "type": "Sint32", 724 | "value": 3 725 | }, 726 | { 727 | "name": "progressive_rendering_max_time", 728 | "type": "Sint32", 729 | "value": 999999 730 | }, 731 | { 732 | "name": "environment_dome_ground_position", 733 | "type": "Float32<3>", 734 | "value": [ 735 | 0.0, 736 | -1.0499999523162842, 737 | 0.0 738 | ] 739 | }, 740 | { 741 | "name": "environment_dome_rotation_axis", 742 | "type": "Float32<3>", 743 | "value": [ 744 | 0.0, 745 | 1.0, 746 | 0.0 747 | ] 748 | }, 749 | { 750 | "name": "iview::inline_color", 751 | "type": "Color", 752 | "value": [ 753 | 1.0, 754 | 0.0, 755 | 0.0, 756 | 1.0 757 | ] 758 | }, 759 | { 760 | "name": "iview::outline_color", 761 | "type": "Color", 762 | "value": [ 763 | 0.0, 764 | 0.0, 765 | 0.0, 766 | 1.0 767 | ] 768 | } 769 | ] 770 | } 771 | }, 772 | "nodes": [ 773 | 0, 774 | 1 775 | ] 776 | } 777 | ], 778 | "textures": [ 779 | { 780 | "extras": { 781 | "gamma": 0.0 782 | }, 783 | "name": "tex", 784 | "source": 0 785 | } 786 | ] 787 | } 788 | -------------------------------------------------------------------------------- /media/spruit_sunrise_1k.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/spruit_sunrise_1k.hdr -------------------------------------------------------------------------------- /media/std_env.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvpro-samples/vk_optix_denoise/fec3a0f16eee09f77dde049ae76e67c1f3dd5058/media/std_env.hdr -------------------------------------------------------------------------------- /optix_denoiser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------- 2 | # Executable 3 | #------------------------------------------------------------------------- 4 | set(PROJECT_NAME vk_denoise) 5 | message(STATUS "-------------------------------") 6 | message(STATUS "Processing Project ${PROJECT_NAME}:") 7 | 8 | # Finding CUDA Toolkit 9 | find_package(CUDAToolkit) 10 | if(NOT CUDAToolkit_FOUND) 11 | message(WARNING "Project ${PROJECT_NAME} NOT built: CUDA Toolkit not found. Please provide CUDAToolkit_ROOT to the CMake invocation.") 12 | return() 13 | endif() 14 | 15 | _add_package_Optix7() 16 | _add_package_VulkanSDK() 17 | _add_package_ImGUI() 18 | _add_nvpro_core_lib() 19 | 20 | file(GLOB SOURCE_FILES src/*.cpp src/*.hpp src/*.h) 21 | add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) 22 | 23 | _add_project_definitions(${PROJECT_NAME}) 24 | 25 | set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) 26 | set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) 27 | 28 | target_include_directories(${PROJECT_NAME} PRIVATE ${SAMPLES_COMMON_DIR} ${ADVANCE_DIR}) 29 | target_compile_definitions(${PROJECT_NAME} PRIVATE IMGUI_DEFINE_MATH_OPERATORS) 30 | source_group("Other" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) 31 | 32 | # Adding libraries + Cuda library (LIBRARIES_OPTIMIZED) 33 | target_link_libraries (${PROJECT_NAME} 34 | CUDA::cudart 35 | CUDA::cuda_driver 36 | # All nvpro-core dependencies 37 | nvpro_core # " " 38 | optimized ${LIBRARIES_OPTIMIZED} # " " 39 | debug ${LIBRARIES_DEBUG} # " " 40 | ${PLATFORM_LIBRARIES} # " " 41 | ${UNIXLINKLIBS} # " " 42 | ) 43 | 44 | if(MSVC) 45 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 46 | endif() 47 | target_include_directories(${PROJECT_NAME} PRIVATE ${OPTIX_INCLUDE_DIR}) 48 | 49 | 50 | #-------------------------------------------------------------------------------------------------- 51 | # Shaders in project 52 | # 53 | set(SHD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/shaders) 54 | 55 | # Local shaders 56 | file(GLOB SHD_HDR ${SHD_DIR}/*.glsl ${SHD_DIR}/*.h) 57 | file(GLOB SHD_SRC ${SHD_DIR}/*.vert ${SHD_DIR}/*.frag ${SHD_DIR}/*.rgen ${SHD_DIR}/*.rchit ${SHD_DIR}/*.rahit ${SHD_DIR}/*.rmiss ${SHD_DIR}/*.comp) 58 | 59 | # Compiling shaders to Spir-V header 60 | compile_glsl( 61 | SOURCE_FILES ${SHD_SRC} 62 | HEADER_FILES ${SHD_HDR} 63 | DST "${CMAKE_CURRENT_SOURCE_DIR}/_autogen" 64 | VULKAN_TARGET "vulkan1.3" 65 | HEADER ON 66 | DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} 67 | FLAGS -I${SHD_DIR} -I${NVPRO_CORE_DIR} -g 68 | ) 69 | 70 | target_sources(${PROJECT_NAME} PRIVATE ${GLSL_SOURCES} ${GLSL_HEADERS}) 71 | source_group("Shaders/src" FILES ${GLSL_SOURCES} ) 72 | source_group("Shaders/hdr" FILES ${GLSL_HEADERS} ) 73 | 74 | # Copy binary 75 | _finalize_target( ${PROJECT_NAME} ) -------------------------------------------------------------------------------- /optix_denoiser/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 | -------------------------------------------------------------------------------- /optix_denoiser/shaders/cpy_to_buffer.comp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | #version 460 21 | #extension GL_GOOGLE_include_directive : enable 22 | #extension GL_EXT_shader_image_load_formatted : enable 23 | 24 | 25 | // clang-format off 26 | layout(set = 0, binding = 0) uniform image2D g_color; 27 | layout(set = 0, binding = 1) uniform image2D g_albedo; 28 | layout(set = 0, binding = 2) uniform image2D g_normal; 29 | 30 | layout(set = 0, binding = 3) buffer _buf0 { vec4 g_buffer0[]; }; 31 | layout(set = 0, binding = 4) buffer _buf1 { vec4 g_buffer1[]; }; 32 | layout(set = 0, binding = 5) buffer _buf2 { vec4 g_buffer2[]; }; 33 | // clang-format on 34 | 35 | 36 | #define GRID_SIZE 16 37 | layout(local_size_x = GRID_SIZE, local_size_y = GRID_SIZE) in; 38 | 39 | 40 | void main() 41 | { 42 | ivec2 imgSize = imageSize(g_color); 43 | ivec2 coord = ivec2(gl_GlobalInvocationID.xy); 44 | if(coord.x >= imgSize.x || coord.y >= imgSize.y) // Check limits 45 | return; 46 | 47 | uint linear = coord.y * imgSize.x + coord.x; 48 | 49 | g_buffer0[linear] = imageLoad(g_color, coord); 50 | g_buffer1[linear] = imageLoad(g_albedo, coord); 51 | vec4 nrm = imageLoad(g_normal, coord); 52 | nrm.xyz = (nrm.xyz * 2.0) - 1.0; // Converting to [-1..1] 53 | g_buffer2[linear] = nrm; 54 | } 55 | -------------------------------------------------------------------------------- /optix_denoiser/shaders/cpy_to_img.comp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | #version 460 21 | #extension GL_GOOGLE_include_directive : enable 22 | #extension GL_EXT_shader_image_load_formatted : enable 23 | 24 | 25 | // clang-format off 26 | layout(set = 0, binding = 0) uniform image2D inImage0; 27 | layout(set = 0, binding = 1) buffer _buf0 { vec4 buff0[]; }; 28 | // clang-format on 29 | 30 | #define GRID_SIZE 16 31 | layout(local_size_x = GRID_SIZE, local_size_y = GRID_SIZE) in; 32 | 33 | 34 | void main() 35 | { 36 | ivec2 imgSize = imageSize(inImage0); 37 | ivec2 coord = ivec2(gl_GlobalInvocationID.xy); 38 | if(coord.x >= imgSize.x || coord.y >= imgSize.y) // Check limits 39 | return; 40 | 41 | uint linear = coord.y * imgSize.x + coord.x; 42 | 43 | imageStore(inImage0, coord, buff0[linear]); 44 | } 45 | -------------------------------------------------------------------------------- /optix_denoiser/shaders/device_host.h: -------------------------------------------------------------------------------- 1 | #ifndef HOST_DEVICE_H 2 | #define HOST_DEVICE_H 3 | 4 | #ifdef __cplusplus 5 | using mat4 = glm::mat4; 6 | using vec4 = glm::vec4; 7 | using vec3 = glm::vec3; 8 | #endif // __cplusplus 9 | 10 | #include "nvvkhl/shaders/dh_lighting.h" 11 | 12 | struct PushConstant 13 | { 14 | int frame; // For RTX 15 | int maxDepth; // For RTX 16 | int maxSamples; // For RTX 17 | int materialId; // For raster 18 | int instanceId; 19 | }; 20 | 21 | 22 | #define MAX_NB_LIGHTS 1 23 | #define GRID_SIZE 16 24 | 25 | struct FrameInfo 26 | { 27 | mat4 proj; 28 | mat4 view; 29 | mat4 projInv; 30 | mat4 viewInv; 31 | vec4 clearColor; 32 | vec3 camPos; 33 | float envRotation; 34 | float maxLuminance; 35 | }; 36 | 37 | 38 | #endif // HOST_DEVICE_H 39 | -------------------------------------------------------------------------------- /optix_denoiser/shaders/dh_bindings.h: -------------------------------------------------------------------------------- 1 | #ifndef HD_BINDINGS_H 2 | #define HD_BINDINGS_H 3 | 4 | // clang-format off 5 | #ifdef __cplusplus // Descriptor binding helper for C++ and GLSL 6 | #define START_BINDING(a) enum a { 7 | #define END_BINDING() } 8 | #define INLINE inline 9 | #else 10 | #define START_BINDING(a) const uint 11 | #define END_BINDING() 12 | #define INLINE 13 | #endif 14 | 15 | 16 | START_BINDING(SceneBindings) 17 | eFrameInfo = 0, 18 | eSceneDesc = 1, 19 | eTextures = 2 20 | END_BINDING(); 21 | 22 | START_BINDING(RtxBindings) 23 | eTlas = 0, 24 | eOutImage = 1, 25 | eOutAlbedo = 2, 26 | eOutNormal = 3 27 | END_BINDING(); 28 | 29 | START_BINDING(DeferredBindings) 30 | eDeferredOutImage = 0, 31 | eDeferredData = 1 32 | END_BINDING(); 33 | 34 | START_BINDING(PostBindings) 35 | ePostImage = 0 36 | END_BINDING(); 37 | 38 | 39 | 40 | #endif // HD_BINDINGS_H 41 | -------------------------------------------------------------------------------- /optix_denoiser/shaders/gbuffers.rchit: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | #version 460 21 | #extension GL_EXT_ray_tracing : require 22 | #extension GL_EXT_nonuniform_qualifier : enable 23 | #extension GL_EXT_scalar_block_layout : enable 24 | #extension GL_GOOGLE_include_directive : enable 25 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 26 | #extension GL_EXT_buffer_reference2 : require 27 | 28 | #include "device_host.h" 29 | #include "payload.glsl" 30 | #include "dh_bindings.h" 31 | 32 | #include "nvvkhl/shaders/constants.h" 33 | #include "nvvkhl/shaders/ggx.h" 34 | #include "nvvkhl/shaders/dh_sky.h" 35 | #include "nvvkhl/shaders/dh_hdr.h" 36 | #include "nvvkhl/shaders/dh_scn_desc.h" 37 | #include "nvvkhl/shaders/pbr_mat_struct.h" 38 | #include "nvvkhl/shaders/vertex_accessor.h" 39 | 40 | 41 | hitAttributeEXT vec2 attribs; 42 | 43 | // clang-format off 44 | layout(location = 1) rayPayloadInEXT GbufferPayload payloadGbuf; 45 | 46 | layout(buffer_reference, scalar) readonly buffer Materials { GltfShadeMaterial m[]; }; 47 | 48 | layout(set = 1, binding = eFrameInfo) uniform FrameInfo_ { FrameInfo frameInfo; }; 49 | layout(set = 1, binding = eSceneDesc) readonly buffer SceneDesc_ { SceneDescription sceneDesc; }; 50 | layout(set = 1, binding = eTextures) uniform sampler2D texturesMap[]; // all textures 51 | // clang-format on 52 | 53 | 54 | #include "nvvkhl/shaders/pbr_mat_eval.h" 55 | #include "compress.glsl" 56 | 57 | //----------------------------------------------------------------------- 58 | // Hit state information 59 | struct HitState 60 | { 61 | vec3 nrm; 62 | vec2 uv; 63 | vec3 tangent; 64 | vec3 bitangent; 65 | float bitangentSign; 66 | }; 67 | 68 | 69 | //----------------------------------------------------------------------- 70 | //----------------------------------------------------------------------- 71 | HitState GetHitState(RenderPrimitive renderPrim) 72 | { 73 | HitState hit; 74 | 75 | // Barycentric coordinate on the triangle 76 | const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); 77 | 78 | // Getting the 3 indices of the triangle (local) 79 | uvec3 triangleIndex = getTriangleIndices(renderPrim, gl_PrimitiveID); 80 | 81 | // Position 82 | // const vec3 pos0 = v0.position.xyz; 83 | // const vec3 pos1 = v1.position.xyz; 84 | // const vec3 pos2 = v2.position.xyz; 85 | // const vec3 position = pos0 * barycentrics.x + pos1 * barycentrics.y + pos2 * barycentrics.z; 86 | // hit.pos = vec3(gl_ObjectToWorldEXT * vec4(position, 1.0)); 87 | 88 | // Normal 89 | const vec3 nrm0 = getVertexNormal(renderPrim, triangleIndex.x); 90 | const vec3 nrm1 = getVertexNormal(renderPrim, triangleIndex.y); 91 | const vec3 nrm2 = getVertexNormal(renderPrim, triangleIndex.z); 92 | const vec3 normal = normalize(nrm0 * barycentrics.x + nrm1 * barycentrics.y + nrm2 * barycentrics.z); 93 | const vec3 worldNormal = normalize(vec3(normal * gl_WorldToObjectEXT)); 94 | // const vec3 geomNormal = normalize(cross(pos1 - pos0, pos2 - pos0)); 95 | hit.nrm = dot(worldNormal, gl_WorldRayDirectionEXT) <= 0.0 ? worldNormal : -worldNormal; // Front-face 96 | 97 | // TexCoord 98 | const vec2 uv0 = getVertexTexCoord0(renderPrim, triangleIndex.x); 99 | const vec2 uv1 = getVertexTexCoord0(renderPrim, triangleIndex.y); 100 | const vec2 uv2 = getVertexTexCoord0(renderPrim, triangleIndex.z); 101 | hit.uv = uv0 * barycentrics.x + uv1 * barycentrics.y + uv2 * barycentrics.z; 102 | 103 | // Tangent - Bitangent 104 | const vec4 tng0 = getVertexTangent(renderPrim, triangleIndex.x); 105 | const vec4 tng1 = getVertexTangent(renderPrim, triangleIndex.y); 106 | const vec4 tng2 = getVertexTangent(renderPrim, triangleIndex.z); 107 | vec3 tangent = normalize(tng0.xyz * barycentrics.x + tng1.xyz * barycentrics.y + tng2.xyz * barycentrics.z); 108 | vec3 world_tangent = normalize(vec3(tangent * gl_WorldToObjectEXT)); 109 | vec3 world_binormal = cross(worldNormal, world_tangent) * tng0.w; 110 | hit.tangent = world_tangent; 111 | hit.bitangent = world_binormal; 112 | hit.bitangentSign = tng0.w; 113 | 114 | return hit; 115 | } 116 | 117 | 118 | //----------------------------------------------------------------------- 119 | // Returning the G-Buffer informations 120 | //----------------------------------------------------------------------- 121 | void main() 122 | { 123 | // Retrieve the Primitive mesh buffer information 124 | RenderNode renderNode = RenderNodeBuf(sceneDesc.renderNodeAddress)._[gl_InstanceID]; 125 | RenderPrimitive renderPrim = RenderPrimitiveBuf(sceneDesc.renderPrimitiveAddress)._[gl_InstanceCustomIndexEXT]; 126 | 127 | HitState hit = GetHitState(renderPrim); 128 | 129 | // Scene materials 130 | uint matIndex = max(0, renderNode.materialID); // material of primitive mesh 131 | Materials materials = Materials(sceneDesc.materialAddress); 132 | 133 | // Material of the object and evaluated material (includes textures) 134 | GltfShadeMaterial mat = materials.m[matIndex]; 135 | PbrMaterial pbrMat = evaluateMaterial(mat, hit.nrm, hit.tangent, hit.bitangent, hit.uv); 136 | 137 | payloadGbuf.packAlbedo = packUnorm4x8(vec4(pbrMat.baseColor, pbrMat.opacity)); 138 | //payloadGbuf.packAlbedo = packUnorm4x8(mat.pbrBaseColorFactor); 139 | payloadGbuf.packNormal = compress_unit_vec(pbrMat.N); 140 | } 141 | -------------------------------------------------------------------------------- /optix_denoiser/shaders/gbuffers.rmiss: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | #version 460 21 | 22 | #extension GL_EXT_ray_tracing : require 23 | 24 | 25 | void main() {} 26 | -------------------------------------------------------------------------------- /optix_denoiser/shaders/get_hit.glsl: -------------------------------------------------------------------------------- 1 | // This function returns the geometric information at hit point 2 | // Note: depends on the buffer layout PrimMeshInfo 3 | 4 | #ifndef GETHIT_GLSL 5 | #define GETHIT_GLSL 6 | 7 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 8 | 9 | #include "nvvkhl/shaders/ray_util.h" 10 | #include "nvvkhl/shaders/vertex_accessor.h" 11 | 12 | precision highp float; 13 | 14 | //----------------------------------------------------------------------- 15 | // Hit state information 16 | struct HitState 17 | { 18 | vec3 pos; 19 | vec3 nrm; 20 | vec3 geonrm; 21 | vec2 uv; 22 | vec3 tangent; 23 | vec3 bitangent; 24 | float bitangentSign; 25 | }; 26 | 27 | 28 | //----------------------------------------------------------------------- 29 | //----------------------------------------------------------------------- 30 | HitState getHitState(RenderPrimitive renderPrim) 31 | { 32 | HitState hit; 33 | 34 | // Barycentric coordinate on the triangle 35 | const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); 36 | 37 | // Getting the 3 indices of the triangle (local) 38 | uvec3 triangleIndex = getTriangleIndices(renderPrim, gl_PrimitiveID); 39 | 40 | 41 | // Triangle info 42 | const vec3 pos0 = getVertexPosition(renderPrim, triangleIndex.x); 43 | const vec3 pos1 = getVertexPosition(renderPrim, triangleIndex.y); 44 | const vec3 pos2 = getVertexPosition(renderPrim, triangleIndex.z); 45 | const vec3 nrm0 = getVertexNormal(renderPrim, triangleIndex.x); 46 | const vec3 nrm1 = getVertexNormal(renderPrim, triangleIndex.y); 47 | const vec3 nrm2 = getVertexNormal(renderPrim, triangleIndex.z); 48 | const vec2 uv0 = getVertexTexCoord0(renderPrim, triangleIndex.x); 49 | const vec2 uv1 = getVertexTexCoord0(renderPrim, triangleIndex.y); 50 | const vec2 uv2 = getVertexTexCoord0(renderPrim, triangleIndex.z); 51 | vec4 tng0 = getVertexTangent(renderPrim, triangleIndex.x); 52 | vec4 tng1 = getVertexTangent(renderPrim, triangleIndex.y); 53 | vec4 tng2 = getVertexTangent(renderPrim, triangleIndex.z); 54 | 55 | // Position 56 | hit.pos = mixBary(pos0, pos1, pos2, barycentrics); 57 | hit.pos = pointOffset(hit.pos, pos0, pos1, pos2, nrm0, nrm1, nrm2, barycentrics); // Shadow offset position - hacking shadow terminator 58 | hit.pos = vec3(gl_ObjectToWorldEXT * vec4(hit.pos, 1.0)); 59 | 60 | // Normal 61 | hit.nrm = normalize(mixBary(nrm0, nrm1, nrm2, barycentrics)); 62 | hit.nrm = normalize(vec3(hit.nrm * gl_WorldToObjectEXT)); 63 | hit.geonrm = normalize(cross(pos1 - pos0, pos2 - pos0)); 64 | hit.geonrm = normalize(vec3(hit.geonrm * gl_WorldToObjectEXT)); 65 | 66 | // TexCoord 67 | hit.uv = mixBary(uv0, uv1, uv2, barycentrics); 68 | 69 | // Tangent - Bitangent 70 | if(!hasVertexTangent(renderPrim)) 71 | { 72 | vec4 t = makeFastTangent(hit.nrm); 73 | tng0 = t; 74 | tng1 = t; 75 | tng2 = t; 76 | } 77 | 78 | hit.tangent = normalize(mixBary(tng0.xyz, tng1.xyz, tng2.xyz, barycentrics)); 79 | hit.tangent = vec3(gl_ObjectToWorldEXT * vec4(hit.tangent, 0.0)); 80 | hit.tangent = normalize(hit.tangent - hit.nrm * dot(hit.nrm, hit.tangent)); 81 | hit.bitangent = cross(hit.nrm, hit.tangent) * tng0.w; 82 | hit.bitangentSign = tng0.w; 83 | 84 | // Adjusting normal 85 | const vec3 V = -gl_WorldRayDirectionEXT; 86 | if(dot(hit.geonrm, V) < 0) // Flip if back facing 87 | hit.geonrm = -hit.geonrm; 88 | 89 | // If backface 90 | if(dot(hit.geonrm, hit.nrm) < 0) // Make Normal and GeoNormal on the same side 91 | { 92 | hit.nrm = -hit.nrm; 93 | hit.tangent = -hit.tangent; 94 | hit.bitangent = -hit.bitangent; 95 | } 96 | 97 | return hit; 98 | } 99 | 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /optix_denoiser/shaders/pathtrace.rahit: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2024, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2024, NVIDIA CORPORATION. 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | #version 460 21 | #extension GL_EXT_ray_tracing : require 22 | #extension GL_EXT_nonuniform_qualifier : enable 23 | #extension GL_EXT_scalar_block_layout : enable 24 | #extension GL_GOOGLE_include_directive : enable 25 | #extension GL_EXT_shader_explicit_arithmetic_types_int8 : enable 26 | #extension GL_EXT_shader_explicit_arithmetic_types_int16 : enable 27 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 28 | #extension GL_EXT_buffer_reference2 : require 29 | 30 | #include "device_host.h" 31 | #include "dh_bindings.h" 32 | #include "payload.glsl" 33 | #include "nvvkhl/shaders/random.h" 34 | #include "nvvkhl/shaders/dh_scn_desc.h" 35 | #include "nvvkhl/shaders/vertex_accessor.h" 36 | 37 | // clang-format off 38 | layout(location = 0) rayPayloadInEXT HitPayload payload; 39 | 40 | layout(buffer_reference, scalar) readonly buffer Materials { GltfShadeMaterial m[]; }; 41 | 42 | layout(set = 1, binding = eFrameInfo) uniform FrameInfo_ { FrameInfo frameInfo; }; 43 | layout(set = 1, binding = eSceneDesc) readonly buffer SceneDesc_ { SceneDescription sceneDesc; }; 44 | layout(set = 1, binding = eTextures) uniform sampler2D texturesMap[]; // all textures 45 | 46 | layout(push_constant) uniform RtxPushConstant_ { PushConstant pc; }; 47 | 48 | // clang-format on 49 | 50 | hitAttributeEXT vec2 attribs; 51 | 52 | 53 | //----------------------------------------------------------------------- 54 | // Hit state information 55 | struct HitState 56 | { 57 | vec2 uv; 58 | }; 59 | 60 | 61 | //----------------------------------------------------------------------- 62 | //----------------------------------------------------------------------- 63 | HitState GetHitState(RenderPrimitive renderPrim) 64 | { 65 | HitState hit; 66 | 67 | // Barycentric coordinate on the triangle 68 | const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); 69 | 70 | // Getting the 3 indices of the triangle (local) 71 | uvec3 triangleIndex = getTriangleIndices(renderPrim, gl_PrimitiveID); 72 | 73 | hit.uv = getInterpolatedVertexTexCoord0(renderPrim, triangleIndex, barycentrics); 74 | 75 | return hit; 76 | } 77 | 78 | //----------------------------------------------------------------------- 79 | //----------------------------------------------------------------------- 80 | void main() 81 | { 82 | // Retrieve the Primitive mesh buffer information 83 | RenderNode renderNode = RenderNodeBuf(sceneDesc.renderNodeAddress)._[gl_InstanceID]; 84 | RenderPrimitive renderPrim = RenderPrimitiveBuf(sceneDesc.renderPrimitiveAddress)._[gl_InstanceCustomIndexEXT]; 85 | 86 | // Scene materials 87 | uint matIndex = max(0, renderNode.materialID); // material of primitive mesh 88 | Materials materials = Materials(sceneDesc.materialAddress); 89 | GltfShadeMaterial mat = materials.m[matIndex]; 90 | 91 | float baseColorAlpha = mat.pbrBaseColorFactor.a; 92 | if(mat.pbrBaseColorTexture.index > -1) 93 | { 94 | HitState hit = GetHitState(renderPrim); 95 | 96 | baseColorAlpha *= texture(texturesMap[nonuniformEXT(mat.pbrBaseColorTexture.index)], hit.uv).a; 97 | } 98 | 99 | float opacity; 100 | if(mat.alphaMode == ALPHA_MASK) 101 | { 102 | opacity = baseColorAlpha > mat.alphaCutoff ? 1.0 : 0.0; 103 | } 104 | else 105 | { 106 | opacity = baseColorAlpha; 107 | } 108 | 109 | // Do alpha blending the stochastically way 110 | if(rand(payload.seed) > opacity) 111 | ignoreIntersectionEXT; 112 | } 113 | -------------------------------------------------------------------------------- /optix_denoiser/shaders/pathtrace.rchit: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2024, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2024, NVIDIA CORPORATION. 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | #version 460 21 | #extension GL_EXT_ray_tracing : require 22 | #extension GL_EXT_nonuniform_qualifier : enable 23 | #extension GL_EXT_scalar_block_layout : enable 24 | #extension GL_GOOGLE_include_directive : enable 25 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 26 | #extension GL_EXT_buffer_reference2 : require 27 | 28 | #include "device_host.h" 29 | #include "dh_bindings.h" 30 | #include "payload.glsl" 31 | 32 | #include "nvvkhl/shaders/constants.h" 33 | #include "nvvkhl/shaders/ggx.h" 34 | #include "nvvkhl/shaders/dh_sky.h" 35 | #include "nvvkhl/shaders/dh_hdr.h" 36 | #include "nvvkhl/shaders/dh_scn_desc.h" 37 | #include "nvvkhl/shaders/random.h" 38 | #include "nvvkhl/shaders/bsdf_functions.h" 39 | #include "nvvkhl/shaders/vertex_accessor.h" 40 | 41 | 42 | hitAttributeEXT vec2 attribs; 43 | 44 | #include "get_hit.glsl" 45 | 46 | // clang-format off 47 | layout(location = 0) rayPayloadInEXT HitPayload payload; 48 | 49 | layout(buffer_reference, scalar) readonly buffer Materials { GltfShadeMaterial m[]; }; 50 | 51 | 52 | layout(set = 0, binding = eTlas ) uniform accelerationStructureEXT topLevelAS; 53 | layout(set = 1, binding = eFrameInfo) uniform FrameInfo_ { FrameInfo frameInfo; }; 54 | layout(set = 1, binding = eSceneDesc) readonly buffer SceneDesc_ { SceneDescription sceneDesc; }; 55 | layout(set = 1, binding = eTextures) uniform sampler2D texturesMap[]; // all textures 56 | layout(set = 2, binding = eImpSamples, scalar) buffer _EnvAccel { EnvAccel envSamplingData[]; }; 57 | layout(set = 2, binding = eHdr) uniform sampler2D hdrTexture; 58 | 59 | layout(push_constant) uniform RtxPushConstant_ { PushConstant pc; }; 60 | // clang-format on 61 | 62 | // Includes depending on layout description 63 | #include "nvvkhl/shaders/pbr_mat_eval.h" // texturesMap 64 | #include "nvvkhl/shaders/hdr_env_sampling.h" 65 | 66 | 67 | void stopPath() 68 | { 69 | payload.hitT = INFINITE; 70 | } 71 | 72 | struct ShadingResult 73 | { 74 | vec3 weight; 75 | vec3 radiance; 76 | vec3 rayOrigin; 77 | vec3 rayDirection; 78 | }; 79 | 80 | // -------------------------------------------------------------------- 81 | // Sampling the Sun or the HDR 82 | // - Returns 83 | // The contribution divided by PDF 84 | // The direction to the light source 85 | // The PDF 86 | // 87 | vec3 sampleLights(in HitState state, inout uint seed, out vec3 dirToLight, out float lightPdf) 88 | { 89 | vec3 rand_val = vec3(rand(seed), rand(seed), rand(seed)); 90 | vec4 radiance_pdf = environmentSample(hdrTexture, rand_val, dirToLight); 91 | vec3 radiance = radiance_pdf.xyz; 92 | lightPdf = radiance_pdf.w; 93 | 94 | // Apply rotation and environment intensity 95 | dirToLight = rotate(dirToLight, vec3(0, 1, 0), frameInfo.envRotation); 96 | radiance *= frameInfo.clearColor.xyz; 97 | 98 | // Return radiance over pdf 99 | return radiance / lightPdf; 100 | } 101 | 102 | 103 | //----------------------------------------------------------------------- 104 | //----------------------------------------------------------------------- 105 | ShadingResult shading(in PbrMaterial pbrMat, in HitState hit) 106 | { 107 | ShadingResult result; 108 | 109 | vec3 to_eye = -gl_WorldRayDirectionEXT; 110 | 111 | result.radiance = pbrMat.emissive; // Emissive material 112 | 113 | 114 | // Light contribution; can be environment or punctual lights 115 | vec3 contribution = vec3(0); 116 | vec3 dirToLight = vec3(0); 117 | float lightPdf = 0.F; 118 | vec3 lightRadianceOverPdf = sampleLights(hit, payload.seed, dirToLight, lightPdf); 119 | 120 | const bool nextEventValid = (dot(dirToLight, hit.geonrm) > 0.0f) && lightPdf != 0.0f; 121 | 122 | // Evaluate BSDF 123 | if(nextEventValid) 124 | { 125 | BsdfEvaluateData evalData; 126 | evalData.k1 = -gl_WorldRayDirectionEXT; 127 | evalData.k2 = dirToLight; 128 | evalData.xi = vec3(rand(payload.seed), rand(payload.seed), rand(payload.seed)); 129 | bsdfEvaluate(evalData, pbrMat); 130 | 131 | if(evalData.pdf > 0.0) 132 | { 133 | const float mis_weight = lightPdf / (lightPdf + evalData.pdf); 134 | 135 | // sample weight 136 | const vec3 w = lightRadianceOverPdf * mis_weight; 137 | contribution += w * evalData.bsdf_diffuse; 138 | contribution += w * evalData.bsdf_glossy; 139 | } 140 | } 141 | 142 | // Sample BSDF 143 | { 144 | BsdfSampleData sampleData; 145 | sampleData.k1 = -gl_WorldRayDirectionEXT; // outgoing direction 146 | sampleData.xi = vec3(rand(payload.seed), rand(payload.seed), rand(payload.seed)); 147 | bsdfSample(sampleData, pbrMat); 148 | 149 | if(sampleData.event_type == BSDF_EVENT_ABSORB) 150 | { 151 | stopPath(); 152 | return result; // Need to add the contribution ? 153 | } 154 | 155 | result.weight = sampleData.bsdf_over_pdf; 156 | result.rayDirection = sampleData.k2; 157 | vec3 offsetDir = dot(result.rayDirection, hit.geonrm) > 0 ? hit.geonrm : -hit.geonrm; 158 | result.rayOrigin = offsetRay(hit.pos, offsetDir); 159 | 160 | 161 | } 162 | 163 | if(nextEventValid) 164 | { 165 | // Shadow ray - stop at the first intersection, don't invoke the closest hit shader (fails for transparent objects) 166 | uint ray_flag = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT | gl_RayFlagsCullBackFacingTrianglesEXT; 167 | payload.hitT = 0.0F; 168 | traceRayEXT(topLevelAS, ray_flag, 0xFF, 0, 0, 0, result.rayOrigin, 0.001, dirToLight, INFINITE, 0); 169 | // If hitting nothing, add light contribution 170 | if(payload.hitT == INFINITE) 171 | result.radiance += contribution; 172 | payload.hitT = gl_HitTEXT; 173 | } 174 | 175 | return result; 176 | } 177 | 178 | 179 | //----------------------------------------------------------------------- 180 | //----------------------------------------------------------------------- 181 | void main() 182 | { 183 | // Retrieve the Primitive mesh buffer information 184 | RenderNode renderNode = RenderNodeBuf(sceneDesc.renderNodeAddress)._[gl_InstanceID]; 185 | RenderPrimitive rprim = RenderPrimitiveBuf(sceneDesc.renderPrimitiveAddress)._[gl_InstanceCustomIndexEXT]; 186 | 187 | HitState hit = getHitState(rprim); 188 | 189 | // Scene materials 190 | uint matIndex = max(0, renderNode.materialID); // material of primitive mesh 191 | Materials materials = Materials(sceneDesc.materialAddress); 192 | 193 | // Material of the object and evaluated material (includes textures) 194 | GltfShadeMaterial mat = materials.m[matIndex]; 195 | MeshState mesh = MeshState(hit.nrm, hit.tangent, hit.bitangent, hit.geonrm, vec2[2](hit.uv, hit.uv), false/*isInside*/); 196 | PbrMaterial pbrMat = evaluateMaterial(mat, mesh); 197 | 198 | payload.hitT = gl_HitTEXT; 199 | ShadingResult result = shading(pbrMat, hit); 200 | 201 | payload.weight = result.weight; 202 | payload.contrib = result.radiance; 203 | payload.rayOrigin = result.rayOrigin; 204 | payload.rayDirection = result.rayDirection; 205 | 206 | // -- Debug -- 207 | // payload.contrib = hit.nrm * .5 + .5; 208 | // payload.contrib = matEval.albedo.xyz; 209 | // payload.contrib = mat.pbrBaseColorFactor.xyz; 210 | // payload.contrib = matEval.tangent * .5 + .5; 211 | // payload.contrib = vec3(matEval.metallic); 212 | // payload.contrib = vec3(matEval.roughness); 213 | // stopRay(); 214 | } 215 | -------------------------------------------------------------------------------- /optix_denoiser/shaders/pathtrace.rgen: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | #version 460 20 | #extension GL_EXT_ray_tracing : require 21 | #extension GL_GOOGLE_include_directive : enable 22 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 23 | #extension GL_EXT_shader_image_load_formatted : enable // The folowing extension allow to pass images as function parameters 24 | 25 | #include "device_host.h" 26 | #include "dh_bindings.h" 27 | #include "payload.glsl" 28 | #include "nvvkhl/shaders/random.h" 29 | #include "nvvkhl/shaders/constants.h" 30 | #include "compress.glsl" 31 | 32 | // clang-format off 33 | layout(location = 0) rayPayloadEXT HitPayload payload; 34 | layout(location = 1) rayPayloadEXT GbufferPayload payloadGbuf; 35 | 36 | layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; 37 | // #OPTIX_D 38 | layout(set = 0, binding = eOutImage) uniform image2D image; 39 | layout(set = 0, binding = eOutAlbedo) uniform image2D gAlbedo; 40 | layout(set = 0, binding = eOutNormal) uniform image2D gNormal; 41 | 42 | layout(set = 1, binding = eFrameInfo) uniform FrameInfo_ { FrameInfo frameInfo; }; 43 | // clang-format on 44 | 45 | layout(push_constant) uniform RtxPushConstant_ 46 | { 47 | PushConstant pc; 48 | }; 49 | 50 | // #OPTIX_D 51 | vec4 gUnpackedAlbedo = vec4(0); 52 | vec3 gUnpackedNormal = vec3(0); 53 | 54 | //----------------------------------------------------------------------- 55 | // Sampling the pixel 56 | //----------------------------------------------------------------------- 57 | vec3 samplePixel(inout uint seed) 58 | { 59 | // Subpixel jitter: send the ray through a different position inside the pixel each time, to provide antialiasing. 60 | vec2 subpixel_jitter = pc.frame == 0 ? vec2(0.5f, 0.5f) : vec2(rand(seed), rand(seed)); 61 | 62 | const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + subpixel_jitter; 63 | const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); 64 | const vec2 d = inUV * 2.0 - 1.0; 65 | 66 | const vec4 origin = frameInfo.viewInv * vec4(0.0, 0.0, 0.0, 1.0); 67 | const vec4 target = frameInfo.projInv * vec4(d.x, d.y, 0.01, 1.0); 68 | const vec4 direction = frameInfo.viewInv * vec4(normalize(target.xyz), 0.0); 69 | const uint rayFlags = gl_RayFlagsCullBackFacingTrianglesEXT; 70 | const float tMin = 0.001; 71 | const float tMax = INFINITE; 72 | 73 | payload.contrib = vec3(0.0, 0.0, 0.0); 74 | payload.weight = vec3(1.0, 1.0, 1.0); 75 | payload.seed = seed; 76 | payload.hitT = INFINITE; 77 | payload.rayOrigin = origin.xyz; 78 | payload.rayDirection = direction.xyz; 79 | 80 | vec3 weightAccum = vec3(1.0, 1.0, 1.0); 81 | vec3 contribAccum = vec3(0.0, 0.0, 0.0); 82 | 83 | for(int depth = 0; depth < pc.maxDepth; depth++) 84 | { 85 | traceRayEXT(topLevelAS, // acceleration structure 86 | rayFlags, // rayFlags 87 | 0xFF, // cullMask 88 | 0, // sbtRecordOffset 89 | 0, // sbtRecordStride 90 | 0, // missIndex 91 | payload.rayOrigin, // ray origin 92 | tMin, // ray min range 93 | payload.rayDirection, // ray direction 94 | tMax, // ray max range 95 | 0 // payload (location = 0) 96 | ); 97 | // Accumulating results 98 | contribAccum += payload.contrib * weightAccum; 99 | weightAccum *= payload.weight; 100 | 101 | // Stopping recursion 102 | if(payload.hitT == INFINITE) 103 | break; 104 | 105 | // Russian-Roulette 106 | float rrPcont = min(max(weightAccum.x, max(weightAccum.y, weightAccum.z)) + 0.001, 0.95); 107 | if(rand(payload.seed) >= rrPcont) 108 | break; // paths with low throughput that won't contribute 109 | weightAccum /= rrPcont; 110 | } 111 | 112 | // Removing fireflies 113 | float lum = dot(contribAccum, vec3(0.212671f, 0.715160f, 0.072169f)); 114 | if(lum > frameInfo.maxLuminance) 115 | { 116 | contribAccum *= frameInfo.maxLuminance / lum; 117 | } 118 | 119 | seed = payload.seed; 120 | return contribAccum; 121 | } 122 | 123 | 124 | //----------------------------------------------------------------------- 125 | // Trace a single ray in the middle of the pixel to retrieve the 126 | // Albedo and normal. Also, forcing all objects to be opaque 127 | //----------------------------------------------------------------------- 128 | // #OPTIX_D 129 | void traceAlbedo() 130 | { 131 | const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5f, 0.5f); 132 | const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); 133 | const vec2 d = inUV * 2.0 - 1.0; 134 | 135 | const vec4 origin = frameInfo.viewInv * vec4(0.0, 0.0, 0.0, 1.0); 136 | const vec4 target = frameInfo.projInv * vec4(d.x, d.y, 0.01, 1.0); 137 | const vec4 direction = frameInfo.viewInv * vec4(normalize(target.xyz), 0.0); 138 | const uint rayFlags = gl_RayFlagsOpaqueEXT; 139 | const float tMin = 0.001; 140 | const float tMax = INFINITE; 141 | 142 | payloadGbuf.packAlbedo = 0; 143 | payloadGbuf.packNormal = 0; 144 | 145 | traceRayEXT(topLevelAS, // acceleration structure 146 | rayFlags, // rayFlags 147 | 0xFF, // cullMask 148 | 1, // sbtRecordOffset --- Using the Gbuffer.rchit 149 | 0, // sbtRecordStride 150 | 1, // missIndex --- Using the Gbuffer.rmiss 151 | origin.xyz, // ray origin 152 | tMin, // ray min range 153 | direction.xyz, // ray direction 154 | tMax, // ray max range 155 | 1 // payload --- Using the GbufferPayload 156 | ); 157 | 158 | gUnpackedAlbedo = unpackUnorm4x8(payloadGbuf.packAlbedo); 159 | gUnpackedNormal = decompress_unit_vec(payloadGbuf.packNormal); 160 | } 161 | 162 | 163 | void main() 164 | { 165 | // Initialize the random number 166 | uint seed = xxhash32(uvec3(gl_LaunchIDEXT.xy, pc.frame)); 167 | 168 | // Sampling n times the pixel 169 | vec3 contribAccum = vec3(0.0, 0.0, 0.0); 170 | for(uint s = 0; s < pc.maxSamples; s++) 171 | { 172 | contribAccum += samplePixel(seed); 173 | } 174 | contribAccum /= pc.maxSamples; 175 | 176 | // Saving result 177 | if(pc.frame == 0) 178 | { // First frame, replace the value in the buffer 179 | imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(contribAccum, 1.f)); 180 | 181 | // #OPTIX_D 182 | // G-Buffers 183 | traceAlbedo(); 184 | imageStore(gAlbedo, ivec2(gl_LaunchIDEXT.xy), gUnpackedAlbedo); 185 | gUnpackedNormal = (gUnpackedNormal * vec3(0.5)) + vec3(0.5); // converting to [0..1] 186 | imageStore(gNormal, ivec2(gl_LaunchIDEXT.xy), vec4(gUnpackedNormal, 1)); 187 | } 188 | else 189 | { // Do accumulation over time 190 | float a = 1.0f / float(pc.frame + 1); 191 | vec3 old_color = imageLoad(image, ivec2(gl_LaunchIDEXT.xy)).xyz; 192 | imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(mix(old_color, contribAccum, a), 1.f)); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /optix_denoiser/shaders/pathtrace.rmiss: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | #version 460 21 | #extension GL_EXT_ray_tracing : require 22 | #extension GL_GOOGLE_include_directive : enable 23 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require 24 | 25 | #include "device_host.h" 26 | #include "dh_bindings.h" 27 | #include "payload.glsl" 28 | #include "nvvkhl/shaders/dh_sky.h" 29 | #include "nvvkhl/shaders/constants.h" 30 | #include "nvvkhl/shaders/func.h" 31 | #include "nvvkhl/shaders/dh_hdr.h" 32 | 33 | layout(location = 0) rayPayloadInEXT HitPayload payload; 34 | 35 | layout(set = 1, binding = eFrameInfo) uniform FrameInfo_ 36 | { 37 | FrameInfo frameInfo; 38 | }; 39 | layout(set = 2, binding = eHdr) uniform sampler2D hdrTexture; 40 | 41 | 42 | void main() 43 | { 44 | // Adding HDR lookup 45 | vec3 dir = rotate(gl_WorldRayDirectionEXT, vec3(0, 1, 0), -frameInfo.envRotation); 46 | vec2 uv = getSphericalUv(dir); // See sampling.glsl 47 | vec3 env = texture(hdrTexture, uv).rgb; 48 | payload.contrib = env * frameInfo.clearColor.xyz; 49 | 50 | payload.hitT = INFINITE; // Ending trace 51 | } 52 | -------------------------------------------------------------------------------- /optix_denoiser/shaders/payload.glsl: -------------------------------------------------------------------------------- 1 | #ifndef PAYLOAD_H 2 | #define PAYLOAD_H 3 | 4 | precision highp float; 5 | 6 | #define MISS_DEPTH 1000 7 | 8 | 9 | struct HitPayload 10 | { 11 | uint seed; 12 | float hitT; 13 | vec3 contrib; 14 | vec3 weight; 15 | vec3 rayOrigin; 16 | vec3 rayDirection; 17 | }; 18 | 19 | HitPayload initPayload() 20 | { 21 | HitPayload p; 22 | p.seed = 0U; 23 | p.hitT = 0.F; 24 | p.contrib = vec3(0.F); 25 | p.weight = vec3(1.F); 26 | p.rayOrigin = vec3(0.F); 27 | p.rayDirection = vec3(0.F, 0.F, -1.F); 28 | return p; 29 | } 30 | 31 | // #OPTIX_D 32 | struct GbufferPayload 33 | { 34 | uint packAlbedo; 35 | uint packNormal; 36 | }; 37 | 38 | #endif // PAYLOAD_H -------------------------------------------------------------------------------- /optix_denoiser/src/denoiser.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2025, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | #ifdef NVP_SUPPORTS_OPTIX7 21 | 22 | 23 | #include 24 | 25 | #include "vulkan/vulkan.h" 26 | 27 | #include "optix.h" 28 | #include "optix_function_table_definition.h" 29 | #include "optix_stubs.h" 30 | 31 | #include "denoiser.hpp" 32 | 33 | #include "imgui/imgui_helper.h" 34 | #include "nvvk/commands_vk.hpp" 35 | #include "stb_image_write.h" 36 | #include "nvvk/descriptorsets_vk.hpp" 37 | #include "nvvk/debug_util_vk.hpp" 38 | #include "nvh/fileoperations.hpp" 39 | #include "nvvk/shaders_vk.hpp" 40 | 41 | 42 | #include "_autogen/cpy_to_img.comp.h" 43 | #include "_autogen/cpy_to_buffer.comp.h" 44 | 45 | 46 | // Choose how to transfer images: 1 for a faster compute shader, 47 | // or 0 value to use a simpler Vulkan command. The Vulkan way is simpler 48 | // but about 5 times slower than the compute shader. 49 | #define USE_COMPUTE_SHADER_TO_COPY 1 50 | 51 | #define GRID_SIZE 16 52 | inline VkExtent2D getGridSize(const VkExtent2D& size) 53 | { 54 | return VkExtent2D{(size.width + (GRID_SIZE - 1)) / GRID_SIZE, (size.height + (GRID_SIZE - 1)) / GRID_SIZE}; 55 | } 56 | 57 | 58 | DenoiserOptix::DenoiserOptix(nvvk::Context* ctx) 59 | { 60 | setup(ctx->m_device, ctx->m_physicalDevice, ctx->m_queueGCT.familyIndex); 61 | } 62 | 63 | //-------------------------------------------------------------------------------------------------- 64 | // The denoiser will take an image, will convert it to a buffer (compatible with Cuda) 65 | // will denoise the buffer, and put back the buffer to an image. 66 | // 67 | // To make this working, it is important that the VkDeviceMemory associated with the buffer 68 | // has the 'export' functionality. 69 | 70 | 71 | void DenoiserOptix::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueIndex) 72 | { 73 | m_queueIndex = queueIndex; 74 | m_device = device; 75 | m_physicalDevice = physicalDevice; 76 | 77 | m_memAlloc.init(device, physicalDevice); 78 | m_allocEx.init(device, physicalDevice, &m_memAlloc); 79 | m_debug.setup(device); 80 | } 81 | 82 | //-------------------------------------------------------------------------------------------------- 83 | // Initializing OptiX and creating the Denoiser instance 84 | // 85 | bool DenoiserOptix::initOptiX(const OptixDenoiserOptions& options, OptixPixelFormat pixelFormat, bool hdr) 86 | { 87 | // Initialize CUDA 88 | CUDA_CHECK(cudaFree(nullptr)); 89 | 90 | CUcontext cu_ctx = nullptr; // zero means take the current context 91 | OPTIX_CHECK(optixInit()); 92 | 93 | OptixDeviceContextOptions optixoptions = {}; 94 | optixoptions.logCallbackFunction = &contextLogCb; 95 | optixoptions.logCallbackLevel = 4; 96 | 97 | OPTIX_CHECK(optixDeviceContextCreate(cu_ctx, &optixoptions, &m_optixDevice)); 98 | OPTIX_CHECK(optixDeviceContextSetLogCallback(m_optixDevice, contextLogCb, nullptr, 4)); 99 | 100 | m_pixelFormat = pixelFormat; 101 | switch(pixelFormat) 102 | { 103 | 104 | case OPTIX_PIXEL_FORMAT_FLOAT3: 105 | m_sizeofPixel = static_cast(3 * sizeof(float)); 106 | m_denoiserAlpha = OPTIX_DENOISER_ALPHA_MODE_COPY; 107 | break; 108 | case OPTIX_PIXEL_FORMAT_FLOAT4: 109 | m_sizeofPixel = static_cast(4 * sizeof(float)); 110 | #if OPTIX_VERSION >= 80000 111 | m_denoiserAlpha = OPTIX_DENOISER_ALPHA_MODE_DENOISE; 112 | #else 113 | m_denoiserAlpha = OPTIX_DENOISER_ALPHA_MODE_ALPHA_AS_AOV; 114 | #endif 115 | break; 116 | case OPTIX_PIXEL_FORMAT_UCHAR3: 117 | m_sizeofPixel = static_cast(3 * sizeof(uint8_t)); 118 | m_denoiserAlpha = OPTIX_DENOISER_ALPHA_MODE_COPY; 119 | break; 120 | case OPTIX_PIXEL_FORMAT_UCHAR4: 121 | m_sizeofPixel = static_cast(4 * sizeof(uint8_t)); 122 | #if OPTIX_VERSION >= 80000 123 | m_denoiserAlpha = OPTIX_DENOISER_ALPHA_MODE_DENOISE; 124 | #else 125 | m_denoiserAlpha = OPTIX_DENOISER_ALPHA_MODE_ALPHA_AS_AOV; 126 | #endif 127 | break; 128 | case OPTIX_PIXEL_FORMAT_HALF3: 129 | m_sizeofPixel = static_cast(3 * sizeof(uint16_t)); 130 | m_denoiserAlpha = OPTIX_DENOISER_ALPHA_MODE_COPY; 131 | break; 132 | case OPTIX_PIXEL_FORMAT_HALF4: 133 | m_sizeofPixel = static_cast(4 * sizeof(uint16_t)); 134 | #if OPTIX_VERSION >= 80000 135 | m_denoiserAlpha = OPTIX_DENOISER_ALPHA_MODE_DENOISE; 136 | #else 137 | m_denoiserAlpha = OPTIX_DENOISER_ALPHA_MODE_ALPHA_AS_AOV; 138 | #endif 139 | break; 140 | default: 141 | assert(!"unsupported"); 142 | break; 143 | } 144 | 145 | 146 | // This is to use RGB + Albedo + Normal 147 | m_denoiserOptions = options; 148 | OptixDenoiserModelKind model_kind = hdr ? OPTIX_DENOISER_MODEL_KIND_HDR : OPTIX_DENOISER_MODEL_KIND_LDR; 149 | model_kind = OPTIX_DENOISER_MODEL_KIND_AOV; 150 | OPTIX_CHECK(optixDenoiserCreate(m_optixDevice, model_kind, &m_denoiserOptions, &m_denoiser)); 151 | 152 | 153 | return true; 154 | } 155 | 156 | //-------------------------------------------------------------------------------------------------- 157 | // Denoising the image in input and saving the denoised image in the output 158 | // 159 | void DenoiserOptix::denoiseImageBuffer(uint64_t& fenceValue, float blendFactor /*= 0.0f*/) 160 | { 161 | try 162 | { 163 | OptixPixelFormat pixel_format = m_pixelFormat; 164 | auto sizeof_pixel = m_sizeofPixel; 165 | uint32_t row_stride_in_bytes = sizeof_pixel * m_imageSize.width; 166 | 167 | //std::vector inputLayer; // Order: RGB, Albedo, Normal 168 | 169 | // Create and set our OptiX layers 170 | OptixDenoiserLayer layer = {}; 171 | // Input 172 | layer.input.data = (CUdeviceptr)m_pixelBufferIn[0].cudaPtr; 173 | layer.input.width = m_imageSize.width; 174 | layer.input.height = m_imageSize.height; 175 | layer.input.rowStrideInBytes = row_stride_in_bytes; 176 | layer.input.pixelStrideInBytes = m_sizeofPixel; 177 | layer.input.format = pixel_format; 178 | 179 | // Output 180 | layer.output.data = (CUdeviceptr)m_pixelBufferOut.cudaPtr; 181 | layer.output.width = m_imageSize.width; 182 | layer.output.height = m_imageSize.height; 183 | layer.output.rowStrideInBytes = row_stride_in_bytes; 184 | layer.output.pixelStrideInBytes = sizeof(float) * 4; 185 | layer.output.format = pixel_format; 186 | 187 | 188 | OptixDenoiserGuideLayer guide_layer = {}; 189 | // albedo 190 | if(m_denoiserOptions.guideAlbedo != 0u) 191 | { 192 | guide_layer.albedo.data = (CUdeviceptr)m_pixelBufferIn[1].cudaPtr; 193 | guide_layer.albedo.width = m_imageSize.width; 194 | guide_layer.albedo.height = m_imageSize.height; 195 | guide_layer.albedo.rowStrideInBytes = row_stride_in_bytes; 196 | guide_layer.albedo.pixelStrideInBytes = m_sizeofPixel; 197 | guide_layer.albedo.format = pixel_format; 198 | } 199 | 200 | // normal 201 | if(m_denoiserOptions.guideNormal != 0u) 202 | { 203 | guide_layer.normal.data = (CUdeviceptr)m_pixelBufferIn[2].cudaPtr; 204 | guide_layer.normal.width = m_imageSize.width; 205 | guide_layer.normal.height = m_imageSize.height; 206 | guide_layer.normal.rowStrideInBytes = row_stride_in_bytes; 207 | guide_layer.normal.pixelStrideInBytes = m_sizeofPixel; 208 | guide_layer.normal.format = pixel_format; 209 | } 210 | 211 | // Wait from Vulkan (Copy to Buffer) 212 | cudaExternalSemaphoreWaitParams wait_params{}; 213 | wait_params.flags = 0; 214 | wait_params.params.fence.value = fenceValue; 215 | cudaWaitExternalSemaphoresAsync(&m_semaphore.cu, &wait_params, 1, nullptr); 216 | 217 | if(m_dIntensity != 0) 218 | { 219 | OPTIX_CHECK(optixDenoiserComputeIntensity(m_denoiser, m_cuStream, &layer.input, m_dIntensity, m_dScratchBuffer, 220 | m_denoiserSizes.withoutOverlapScratchSizeInBytes)); 221 | } 222 | 223 | OptixDenoiserParams denoiser_params{}; 224 | #if OPTIX_VERSION < 80000 225 | denoiser_params.denoiseAlpha = m_denoiserAlpha; 226 | #endif 227 | denoiser_params.hdrIntensity = m_dIntensity; 228 | denoiser_params.blendFactor = blendFactor; 229 | 230 | 231 | // Execute the denoiser 232 | OPTIX_CHECK(optixDenoiserInvoke(m_denoiser, m_cuStream, &denoiser_params, m_dStateBuffer, 233 | m_denoiserSizes.stateSizeInBytes, &guide_layer, &layer, 1, 0, 0, m_dScratchBuffer, 234 | m_denoiserSizes.withoutOverlapScratchSizeInBytes)); 235 | 236 | 237 | CUDA_CHECK(cudaDeviceSynchronize()); // Making sure the denoiser is done 238 | CUDA_CHECK(cudaStreamSynchronize(m_cuStream)); 239 | 240 | cudaExternalSemaphoreSignalParams sig_params{}; 241 | sig_params.flags = 0; 242 | sig_params.params.fence.value = ++fenceValue; 243 | cudaSignalExternalSemaphoresAsync(&m_semaphore.cu, &sig_params, 1, m_cuStream); 244 | } 245 | catch(const std::exception& e) 246 | { 247 | std::cout << e.what() << std::endl; 248 | } 249 | } 250 | 251 | //-------------------------------------------------------------------------------------------------- 252 | // Converting all images to buffers used by the denoiser 253 | // 254 | void DenoiserOptix::imageToBuffer(const VkCommandBuffer& cmdBuf, const std::vector& imgIn) 255 | { 256 | LABEL_SCOPE_VK(cmdBuf); 257 | 258 | #if USE_COMPUTE_SHADER_TO_COPY 259 | copyImageToBuffer(cmdBuf, imgIn); 260 | #else 261 | VkBufferImageCopy region = { 262 | .imageSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .layerCount = 1}, 263 | .imageExtent = {.width = m_imageSize.width, .height = m_imageSize.height, .depth = 1}, 264 | }; 265 | 266 | for(int i = 0; i < static_cast(imgIn.size()); i++) 267 | { 268 | nvvk::cmdBarrierImageLayout(cmdBuf, imgIn[i].image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); 269 | vkCmdCopyImageToBuffer(cmdBuf, imgIn[i].image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_pixelBufferIn[i].bufVk.buffer, 1, ®ion); 270 | nvvk::cmdBarrierImageLayout(cmdBuf, imgIn[i].image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); 271 | } 272 | #endif 273 | } 274 | 275 | 276 | //-------------------------------------------------------------------------------------------------- 277 | // Converting the output buffer to the image 278 | // 279 | void DenoiserOptix::bufferToImage(const VkCommandBuffer& cmdBuf, nvvk::Texture* imgOut) 280 | { 281 | LABEL_SCOPE_VK(cmdBuf); 282 | 283 | #if USE_COMPUTE_SHADER_TO_COPY 284 | copyBufferToImage(cmdBuf, imgOut); 285 | #else 286 | VkBufferImageCopy region = { 287 | .imageSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .layerCount = 1}, 288 | .imageExtent = {.width = m_imageSize.width, .height = m_imageSize.height, .depth = 1}, 289 | }; 290 | 291 | nvvk::cmdBarrierImageLayout(cmdBuf, imgOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 292 | vkCmdCopyBufferToImage(cmdBuf, m_pixelBufferOut.bufVk.buffer, imgOut->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); 293 | nvvk::cmdBarrierImageLayout(cmdBuf, imgOut->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); 294 | #endif 295 | } 296 | 297 | 298 | //-------------------------------------------------------------------------------------------------- 299 | // 300 | // 301 | void DenoiserOptix::destroy() 302 | { 303 | // Cleanup resources 304 | optixDenoiserDestroy(m_denoiser); 305 | optixDeviceContextDestroy(m_optixDevice); 306 | 307 | vkDestroySemaphore(m_device, m_semaphore.vk, nullptr); 308 | m_semaphore.vk = VK_NULL_HANDLE; 309 | 310 | destroyBuffer(); 311 | for(auto& d : m_desc) 312 | { 313 | vkDestroyDescriptorPool(m_device, d.pool, nullptr); 314 | vkDestroyDescriptorSetLayout(m_device, d.layout, nullptr); 315 | d.pool = VK_NULL_HANDLE; 316 | d.layout = VK_NULL_HANDLE; 317 | } 318 | for(auto& p : m_pipelines) 319 | { 320 | vkDestroyPipeline(m_device, p.p, nullptr); 321 | vkDestroyPipelineLayout(m_device, p.layout, nullptr); 322 | p.p = VK_NULL_HANDLE; 323 | p.layout = VK_NULL_HANDLE; 324 | } 325 | } 326 | 327 | //-------------------------------------------------------------------------------------------------- 328 | // 329 | // 330 | void DenoiserOptix::destroyBuffer() 331 | { 332 | for(auto& p : m_pixelBufferIn) 333 | p.destroy(m_allocEx); 334 | m_pixelBufferOut.destroy(m_allocEx); 335 | 336 | if(m_dStateBuffer != 0) 337 | { 338 | CUDA_CHECK(cudaFree((void*)m_dStateBuffer)); 339 | m_dStateBuffer = 0; 340 | } 341 | if(m_dScratchBuffer != 0) 342 | { 343 | CUDA_CHECK(cudaFree((void*)m_dScratchBuffer)); 344 | m_dScratchBuffer = 0; 345 | } 346 | if(m_dIntensity != 0) 347 | { 348 | CUDA_CHECK(cudaFree((void*)m_dIntensity)); 349 | m_dIntensity = 0; 350 | } 351 | if(m_dMinRGB != 0) 352 | { 353 | CUDA_CHECK(cudaFree((void*)m_dMinRGB)); 354 | m_dMinRGB = 0; 355 | } 356 | } 357 | 358 | //-------------------------------------------------------------------------------------------------- 359 | // UI specific for the denoiser 360 | // 361 | bool DenoiserOptix::uiSetup() 362 | { 363 | bool modified = false; 364 | if(ImGui::CollapsingHeader("Denoiser", ImGuiTreeNodeFlags_DefaultOpen)) 365 | { 366 | modified |= ImGuiH::Control::Checkbox("Denoise", "", reinterpret_cast(&m_denoisedMode)); 367 | modified |= ImGuiH::Control::Slider("Start Frame", "Frame at which the denoiser starts to be applied", 368 | &m_startDenoiserFrame, nullptr, ImGuiH::Control::Flags::Normal, 0, 99); 369 | } 370 | return modified; 371 | } 372 | 373 | //-------------------------------------------------------------------------------------------------- 374 | // Allocating all the buffers in which the images will be transfered. 375 | // The buffers are shared with Cuda, therefore OptiX can denoised them 376 | // 377 | void DenoiserOptix::allocateBuffers(const VkExtent2D& imgSize) 378 | { 379 | m_imageSize = imgSize; 380 | 381 | destroyBuffer(); 382 | 383 | VkDeviceSize buffer_size = static_cast(m_imageSize.width) * m_imageSize.height * 4 * sizeof(float); 384 | VkBufferUsageFlags usage{VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT}; 385 | 386 | { // Color 387 | m_pixelBufferIn[0].bufVk = m_allocEx.createBuffer(buffer_size, usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); 388 | createBufferCuda(m_pixelBufferIn[0]); // Exporting the buffer to Cuda handle and pointers 389 | NAME_VK(m_pixelBufferIn[0].bufVk.buffer); 390 | } 391 | 392 | // Albedo 393 | { 394 | m_pixelBufferIn[1].bufVk = m_allocEx.createBuffer(buffer_size, usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); 395 | createBufferCuda(m_pixelBufferIn[1]); 396 | NAME_VK(m_pixelBufferIn[1].bufVk.buffer); 397 | } 398 | // Normal 399 | { 400 | m_pixelBufferIn[2].bufVk = m_allocEx.createBuffer(buffer_size, usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); 401 | createBufferCuda(m_pixelBufferIn[2]); 402 | NAME_VK(m_pixelBufferIn[2].bufVk.buffer); 403 | } 404 | 405 | // Output image/buffer 406 | m_pixelBufferOut.bufVk = m_allocEx.createBuffer(buffer_size, usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); 407 | createBufferCuda(m_pixelBufferOut); 408 | NAME_VK(m_pixelBufferOut.bufVk.buffer); 409 | 410 | 411 | // Computing the amount of memory needed to do the denoiser 412 | OPTIX_CHECK(optixDenoiserComputeMemoryResources(m_denoiser, m_imageSize.width, m_imageSize.height, &m_denoiserSizes)); 413 | 414 | CUDA_CHECK(cudaMalloc((void**)&m_dStateBuffer, m_denoiserSizes.stateSizeInBytes)); 415 | CUDA_CHECK(cudaMalloc((void**)&m_dScratchBuffer, m_denoiserSizes.withoutOverlapScratchSizeInBytes)); 416 | CUDA_CHECK(cudaMalloc((void**)&m_dMinRGB, 4 * sizeof(float))); 417 | if(m_pixelFormat == OPTIX_PIXEL_FORMAT_FLOAT3 || m_pixelFormat == OPTIX_PIXEL_FORMAT_FLOAT4) 418 | CUDA_CHECK(cudaMalloc((void**)&m_dIntensity, sizeof(float))); 419 | 420 | OPTIX_CHECK(optixDenoiserSetup(m_denoiser, m_cuStream, m_imageSize.width, m_imageSize.height, m_dStateBuffer, 421 | m_denoiserSizes.stateSizeInBytes, m_dScratchBuffer, m_denoiserSizes.withoutOverlapScratchSizeInBytes)); 422 | } 423 | 424 | 425 | //-------------------------------------------------------------------------------------------------- 426 | // Get the Vulkan buffer and create the Cuda equivalent using the memory allocated in Vulkan 427 | // 428 | void DenoiserOptix::createBufferCuda(BufferCuda& buf) 429 | { 430 | nvvk::MemAllocator::MemInfo mem_info = m_allocEx.getMemoryAllocator()->getMemoryInfo(buf.bufVk.memHandle); 431 | #ifdef WIN32 432 | VkMemoryGetWin32HandleInfoKHR info{VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR}; 433 | info.memory = mem_info.memory; 434 | info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; 435 | vkGetMemoryWin32HandleKHR(m_device, &info, &buf.handle); 436 | #else 437 | VkMemoryGetFdInfoKHR info{VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR}; 438 | info.memory = mem_info.memory; 439 | info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; 440 | vkGetMemoryFdKHR(m_device, &info, &buf.handle); 441 | #endif 442 | 443 | VkMemoryRequirements memory_req{}; 444 | vkGetBufferMemoryRequirements(m_device, buf.bufVk.buffer, &memory_req); 445 | 446 | cudaExternalMemoryHandleDesc cuda_ext_mem_handle_desc{}; 447 | cuda_ext_mem_handle_desc.size = memory_req.size; 448 | #ifdef WIN32 449 | cuda_ext_mem_handle_desc.type = cudaExternalMemoryHandleTypeOpaqueWin32; 450 | cuda_ext_mem_handle_desc.handle.win32.handle = buf.handle; 451 | #else 452 | cuda_ext_mem_handle_desc.type = cudaExternalMemoryHandleTypeOpaqueFd; 453 | cuda_ext_mem_handle_desc.handle.fd = buf.handle; 454 | #endif 455 | 456 | cudaExternalMemory_t cuda_ext_mem_vertex_buffer{}; 457 | CUDA_CHECK(cudaImportExternalMemory(&cuda_ext_mem_vertex_buffer, &cuda_ext_mem_handle_desc)); 458 | 459 | #ifndef WIN32 460 | // fd got consumed 461 | cuda_ext_mem_handle_desc.handle.fd = -1; 462 | #endif 463 | 464 | cudaExternalMemoryBufferDesc cuda_ext_buffer_desc{}; 465 | cuda_ext_buffer_desc.offset = 0; 466 | cuda_ext_buffer_desc.size = memory_req.size; 467 | cuda_ext_buffer_desc.flags = 0; 468 | CUDA_CHECK(cudaExternalMemoryGetMappedBuffer(&buf.cudaPtr, cuda_ext_mem_vertex_buffer, &cuda_ext_buffer_desc)); 469 | } 470 | 471 | //-------------------------------------------------------------------------------------------------- 472 | // Creating the timeline semaphores for syncing with CUDA 473 | // 474 | void DenoiserOptix::createSemaphore() 475 | { 476 | #ifdef WIN32 477 | auto handle_type = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT; 478 | #else 479 | auto handle_type = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; 480 | #endif 481 | 482 | VkSemaphoreTypeCreateInfo timeline_create_info{.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, 483 | .semaphoreType = VK_SEMAPHORE_TYPE_BINARY, 484 | .initialValue = 0}; 485 | 486 | VkExportSemaphoreCreateInfo esci{.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR, 487 | .pNext = &timeline_create_info, 488 | .handleTypes = VkExternalSemaphoreHandleTypeFlags(handle_type)}; 489 | 490 | VkSemaphoreCreateInfo sci{.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, .pNext = &esci}; 491 | 492 | vkCreateSemaphore(m_device, &sci, nullptr, &m_semaphore.vk); 493 | 494 | #ifdef WIN32 495 | VkSemaphoreGetWin32HandleInfoKHR handle_info{VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR}; 496 | handle_info.handleType = handle_type; 497 | handle_info.semaphore = m_semaphore.vk; 498 | vkGetSemaphoreWin32HandleKHR(m_device, &handle_info, &m_semaphore.handle); 499 | #else 500 | VkSemaphoreGetFdInfoKHR handle_info{VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR}; 501 | handle_info.handleType = handle_type; 502 | handle_info.semaphore = m_semaphore.vk; 503 | vkGetSemaphoreFdKHR(m_device, &handle_info, &m_semaphore.handle); 504 | #endif 505 | 506 | 507 | cudaExternalSemaphoreHandleDesc external_semaphore_handle_desc{}; 508 | std::memset(&external_semaphore_handle_desc, 0, sizeof(external_semaphore_handle_desc)); 509 | external_semaphore_handle_desc.flags = 0; 510 | #ifdef WIN32 511 | external_semaphore_handle_desc.type = cudaExternalSemaphoreHandleTypeOpaqueWin32; 512 | external_semaphore_handle_desc.handle.win32.handle = static_cast(m_semaphore.handle); 513 | #else 514 | external_semaphore_handle_desc.type = cudaExternalSemaphoreHandleTypeOpaqueFd; 515 | external_semaphore_handle_desc.handle.fd = m_semaphore.handle; 516 | #endif 517 | 518 | CUDA_CHECK(cudaImportExternalSemaphore(&m_semaphore.cu, &external_semaphore_handle_desc)); 519 | } 520 | 521 | /// 522 | /// The second below is for the compute shaders, which copies images to buffers, or buffer to image 523 | /// 524 | void DenoiserOptix::createCopyPipeline() 525 | { 526 | { 527 | // Descriptor Set 528 | nvvk::DescriptorSetBindings bind; 529 | bind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); 530 | bind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); 531 | bind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); 532 | bind.addBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT); 533 | bind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT); 534 | bind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT); 535 | 536 | CREATE_NAMED_VK(m_desc[eCpyToBuffer].pool, bind.createPool(m_device, 1)); 537 | CREATE_NAMED_VK(m_desc[eCpyToBuffer].layout, bind.createLayout(m_device, VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR)); 538 | 539 | // Pipeline 540 | VkPipelineLayoutCreateInfo pipe_info{ 541 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 542 | .setLayoutCount = 1, 543 | .pSetLayouts = &m_desc[eCpyToBuffer].layout, 544 | }; 545 | vkCreatePipelineLayout(m_device, &pipe_info, nullptr, &m_pipelines[eCpyToBuffer].layout); 546 | NAME_VK(m_pipelines[eCpyToBuffer].layout); 547 | 548 | VkPipelineShaderStageCreateInfo stage_info{ 549 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 550 | .stage = VK_SHADER_STAGE_COMPUTE_BIT, 551 | .module = nvvk::createShaderModule(m_device, cpy_to_buffer_comp, sizeof(cpy_to_buffer_comp)), 552 | .pName = "main", 553 | }; 554 | 555 | VkComputePipelineCreateInfo comp_info{ 556 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, 557 | .stage = stage_info, 558 | .layout = m_pipelines[eCpyToBuffer].layout, 559 | }; 560 | 561 | vkCreateComputePipelines(m_device, {}, 1, &comp_info, nullptr, &m_pipelines[eCpyToBuffer].p); 562 | NAME_VK(m_pipelines[eCpyToBuffer].p); 563 | 564 | vkDestroyShaderModule(m_device, comp_info.stage.module, nullptr); 565 | } 566 | 567 | { 568 | // Descriptor Set 569 | nvvk::DescriptorSetBindings bind; 570 | bind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); 571 | bind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT); 572 | 573 | CREATE_NAMED_VK(m_desc[eCpyToImage].pool, bind.createPool(m_device, 1)); 574 | CREATE_NAMED_VK(m_desc[eCpyToImage].layout, bind.createLayout(m_device, VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR)); 575 | 576 | // Pipeline 577 | VkPipelineLayoutCreateInfo pipe_info{ 578 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 579 | .setLayoutCount = 1, 580 | .pSetLayouts = &m_desc[eCpyToImage].layout, 581 | }; 582 | vkCreatePipelineLayout(m_device, &pipe_info, nullptr, &m_pipelines[eCpyToImage].layout); 583 | NAME_VK(m_pipelines[eCpyToImage].layout); 584 | 585 | VkPipelineShaderStageCreateInfo stage_info{ 586 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 587 | .stage = VK_SHADER_STAGE_COMPUTE_BIT, 588 | .module = nvvk::createShaderModule(m_device, cpy_to_img_comp, sizeof(cpy_to_img_comp)), 589 | .pName = "main", 590 | }; 591 | 592 | VkComputePipelineCreateInfo comp_info{ 593 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, 594 | .stage = stage_info, 595 | .layout = m_pipelines[eCpyToImage].layout, 596 | }; 597 | vkCreateComputePipelines(m_device, {}, 1, &comp_info, nullptr, &m_pipelines[eCpyToImage].p); 598 | NAME_VK(m_pipelines[eCpyToImage].p); 599 | 600 | vkDestroyShaderModule(m_device, comp_info.stage.module, nullptr); 601 | } 602 | } 603 | 604 | VkWriteDescriptorSet makeWrite(const VkDescriptorSet& set, uint32_t bind, const VkDescriptorImageInfo* img) 605 | { 606 | VkWriteDescriptorSet wrt{ 607 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 608 | .dstSet = set, 609 | .dstBinding = bind, 610 | .dstArrayElement = 0, 611 | .descriptorCount = 1, 612 | .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 613 | .pImageInfo = img, 614 | }; 615 | return wrt; 616 | }; 617 | 618 | VkWriteDescriptorSet makeWrite(const VkDescriptorSet& set, uint32_t bind, const VkDescriptorBufferInfo* buf) 619 | { 620 | VkWriteDescriptorSet wrt{ 621 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 622 | .dstSet = set, 623 | .dstBinding = bind, 624 | .dstArrayElement = 0, 625 | .descriptorCount = 1, 626 | .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 627 | .pBufferInfo = buf, 628 | }; 629 | return wrt; 630 | }; 631 | 632 | //-------------------------------------------------------------------------------------------------- 633 | // Compute version of VkCmdCopyImageToBuffer 634 | // 635 | void DenoiserOptix::copyImageToBuffer(const VkCommandBuffer& cmd, const std::vector& imgIn) 636 | { 637 | LABEL_SCOPE_VK(cmd); 638 | 639 | VkDescriptorImageInfo img0 = imgIn[0].descriptor; 640 | VkDescriptorImageInfo img1 = imgIn[1].descriptor; 641 | VkDescriptorImageInfo img2 = imgIn[2].descriptor; 642 | VkDescriptorBufferInfo buf0 = {.buffer = m_pixelBufferIn[0].bufVk.buffer, .range = VK_WHOLE_SIZE}; 643 | VkDescriptorBufferInfo buf1 = {.buffer = m_pixelBufferIn[1].bufVk.buffer, .range = VK_WHOLE_SIZE}; 644 | VkDescriptorBufferInfo buf2 = {.buffer = m_pixelBufferIn[2].bufVk.buffer, .range = VK_WHOLE_SIZE}; 645 | 646 | std::vector writes; 647 | writes.emplace_back(makeWrite({}, 0, &img0)); 648 | writes.emplace_back(makeWrite({}, 1, &img1)); 649 | writes.emplace_back(makeWrite({}, 2, &img2)); 650 | writes.emplace_back(makeWrite({}, 3, &buf0)); 651 | writes.emplace_back(makeWrite({}, 4, &buf1)); 652 | writes.emplace_back(makeWrite({}, 5, &buf2)); 653 | vkCmdPushDescriptorSetKHR(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelines[eCpyToBuffer].layout, 0, 654 | static_cast(writes.size()), writes.data()); 655 | vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelines[eCpyToBuffer].p); 656 | auto grid = getGridSize(m_imageSize); 657 | vkCmdDispatch(cmd, grid.width, grid.height, 1); 658 | } 659 | 660 | 661 | //-------------------------------------------------------------------------------------------------- 662 | // Compute version of VkCmdCopyBufferToImage 663 | // 664 | void DenoiserOptix::copyBufferToImage(const VkCommandBuffer& cmd, const nvvk::Texture* imgIn) 665 | { 666 | VkDescriptorImageInfo img0 = imgIn->descriptor; 667 | VkDescriptorBufferInfo buf0 = {.buffer = m_pixelBufferOut.bufVk.buffer, .range = VK_WHOLE_SIZE}; 668 | 669 | std::vector writes; 670 | writes.emplace_back(makeWrite({}, 0, &img0)); 671 | writes.emplace_back(makeWrite({}, 1, &buf0)); 672 | vkCmdPushDescriptorSetKHR(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelines[eCpyToImage].layout, 0, 673 | static_cast(writes.size()), writes.data()); 674 | vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelines[eCpyToImage].p); 675 | auto grid = getGridSize(m_imageSize); 676 | vkCmdDispatch(cmd, grid.width, grid.height, 1); 677 | } 678 | 679 | 680 | #endif // !NVP_SUPPORTS_OPTIX7 681 | -------------------------------------------------------------------------------- /optix_denoiser/src/denoiser.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | #pragma once 22 | 23 | #ifdef NVP_SUPPORTS_OPTIX7 24 | 25 | 26 | #include 27 | #include // cerr 28 | #include // setw 29 | 30 | #include "nvvk/resourceallocator_vk.hpp" 31 | #include "nvvk/memallocator_dedicated_vk.hpp" 32 | 33 | #ifdef LINUX 34 | #include 35 | #endif 36 | 37 | #include 38 | #include 39 | 40 | #include "imgui.h" 41 | 42 | // for interop we use the dedicated allocator as well 43 | #include "nvvk/debug_util_vk.hpp" 44 | #include "nvvk/images_vk.hpp" 45 | #include "nvvk/context_vk.hpp" 46 | #include "optix_types.h" 47 | #include 48 | 49 | 50 | #define OPTIX_CHECK(call) \ 51 | do \ 52 | { \ 53 | OptixResult res = call; \ 54 | if(res != OPTIX_SUCCESS) \ 55 | { \ 56 | std::stringstream ss; \ 57 | ss << "Optix call (" << #call << " ) failed with code " << res << " (" __FILE__ << ":" << __LINE__ << ")\n"; \ 58 | std::cerr << ss.str().c_str() << std::endl; \ 59 | throw std::runtime_error(ss.str().c_str()); \ 60 | } \ 61 | } while(false) 62 | 63 | #define CUDA_CHECK(call) \ 64 | do \ 65 | { \ 66 | cudaError_t error = call; \ 67 | if(error != cudaSuccess) \ 68 | { \ 69 | std::stringstream ss; \ 70 | ss << "CUDA call (" << #call << " ) failed with code " << error << " (" __FILE__ << ":" << __LINE__ << ")\n"; \ 71 | throw std::runtime_error(ss.str().c_str()); \ 72 | } \ 73 | } while(false) 74 | 75 | #define OPTIX_CHECK_LOG(call) \ 76 | do \ 77 | { \ 78 | OptixResult res = call; \ 79 | if(res != OPTIX_SUCCESS) \ 80 | { \ 81 | std::stringstream ss; \ 82 | ss << "Optix call (" << #call << " ) failed with code " << res << " (" __FILE__ << ":" << __LINE__ << ")\nLog:\n" \ 83 | << log << "\n"; \ 84 | throw std::runtime_error(ss.str().c_str()); \ 85 | } \ 86 | } while(false) 87 | 88 | static void contextLogCb(unsigned int level, const char* tag, const char* message, void* /*cbdata */) 89 | { 90 | std::cerr << "[" << std::setw(2) << level << "][" << std::setw(12) << tag << "]: " << message << "\n"; 91 | } 92 | 93 | 94 | struct DenoiserOptix 95 | { 96 | 97 | DenoiserOptix() = default; 98 | explicit DenoiserOptix(nvvk::Context* ctx); 99 | ~DenoiserOptix() = default; 100 | 101 | void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueIndex); 102 | bool initOptiX(const OptixDenoiserOptions& options, OptixPixelFormat pixelFormat, bool hdr); 103 | void denoiseImageBuffer(uint64_t& fenceValue, float blendFactor = 0.0f); 104 | void createSemaphore(); 105 | 106 | void destroy(); 107 | void destroyBuffer(); 108 | 109 | bool uiSetup(); 110 | 111 | void allocateBuffers(const VkExtent2D& imgSize); 112 | void bufferToImage(const VkCommandBuffer& cmdBuf, nvvk::Texture* imgOut); 113 | void imageToBuffer(const VkCommandBuffer& cmdBuf, const std::vector& imgIn); 114 | 115 | void createCopyPipeline(); 116 | void copyImageToBuffer(const VkCommandBuffer& cmd, const std::vector& imgIn); 117 | void copyBufferToImage(const VkCommandBuffer& cmd, const nvvk::Texture* imgIn); 118 | 119 | VkSemaphore getTLSemaphore() const { return m_semaphore.vk; } 120 | 121 | // Ui 122 | int m_denoisedMode{1}; 123 | int m_startDenoiserFrame{0}; 124 | 125 | private: 126 | // Holding the Buffer for Cuda interop 127 | struct BufferCuda 128 | { 129 | nvvk::Buffer bufVk; // The Vulkan allocated buffer 130 | 131 | // Extra for Cuda 132 | #ifdef WIN32 133 | HANDLE handle = nullptr; // The Win32 handle 134 | #else 135 | int handle = -1; 136 | #endif 137 | void* cudaPtr = nullptr; 138 | 139 | void destroy(nvvk::ExportResourceAllocator& alloc) 140 | { 141 | alloc.destroy(bufVk); 142 | #ifdef WIN32 143 | CloseHandle(handle); 144 | handle = nullptr; 145 | #else 146 | if(handle != -1) 147 | { 148 | close(handle); 149 | handle = -1; 150 | } 151 | #endif 152 | } 153 | }; 154 | 155 | void createBufferCuda(BufferCuda& buf); 156 | 157 | 158 | // For synchronizing with Vulkan 159 | struct Semaphore 160 | { 161 | VkSemaphore vk{}; // Vulkan 162 | cudaExternalSemaphore_t cu{}; // Cuda version 163 | #ifdef WIN32 164 | HANDLE handle{INVALID_HANDLE_VALUE}; 165 | #else 166 | int handle{-1}; 167 | #endif 168 | } m_semaphore; 169 | 170 | OptixDeviceContext m_optixDevice = {}; 171 | OptixDenoiser m_denoiser = {}; 172 | OptixDenoiserOptions m_denoiserOptions = {}; 173 | OptixDenoiserSizes m_denoiserSizes = {}; 174 | OptixDenoiserAlphaMode m_denoiserAlpha = {OPTIX_DENOISER_ALPHA_MODE_COPY}; 175 | OptixPixelFormat m_pixelFormat = {}; 176 | 177 | CUdeviceptr m_dStateBuffer = {}; 178 | CUdeviceptr m_dScratchBuffer = {}; 179 | CUdeviceptr m_dIntensity = {}; 180 | CUdeviceptr m_dMinRGB = {}; 181 | CUstream m_cuStream = {}; 182 | 183 | VkExtent2D m_imageSize = {}; 184 | uint32_t m_sizeofPixel = {}; 185 | 186 | // Vulkan 187 | VkDevice m_device = {}; 188 | VkPhysicalDevice m_physicalDevice = {}; 189 | uint32_t m_queueIndex = {}; 190 | 191 | nvvk::DedicatedMemoryAllocator m_memAlloc; // Using dedicated allocations for simplicity 192 | nvvk::ExportResourceAllocator m_allocEx; // ResourceAllocator with export flag (interop) 193 | 194 | std::array m_pixelBufferIn; // RGB, Albedo, normal 195 | BufferCuda m_pixelBufferOut; // Result of the denoiser 196 | 197 | nvvk::DebugUtil m_debug; 198 | 199 | enum // The two compute shaders 200 | { 201 | eCpyToBuffer, 202 | eCpyToImage 203 | }; 204 | struct VulkanDescritors 205 | { 206 | VkDescriptorPool pool; 207 | VkDescriptorSetLayout layout; 208 | VkDescriptorSet set; 209 | }; 210 | std::array m_desc{}; 211 | 212 | struct VulkanPipelines 213 | { 214 | VkPipeline p; 215 | VkPipelineLayout layout; 216 | }; 217 | std::array m_pipelines{}; 218 | }; 219 | 220 | #endif // !NVP_SUPPORTS_OPTIX7 221 | -------------------------------------------------------------------------------- /optix_denoiser/src/tinygltf_impl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, 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-2022 NVIDIA CORPORATION 17 | * SPDX-License-Identifier: Apache-2.0 18 | */ 19 | 20 | 21 | #ifdef _MSC_VER 22 | #pragma warning(disable : 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen 23 | #endif 24 | 25 | #define TINYGLTF_IMPLEMENTATION 26 | #define STB_IMAGE_IMPLEMENTATION 27 | #define STB_IMAGE_WRITE_IMPLEMENTATION 28 | #define TINYGLTF_NO_EXTERNAL_IMAGE 29 | #include "tiny_gltf.h" 30 | 31 | #define TINYOBJLOADER_IMPLEMENTATION 32 | #include "tiny_obj_loader.h" 33 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | import argparse 6 | import subprocess 7 | import datetime 8 | from sys import platform 9 | 10 | # Global variables 11 | build_dir = "build/" 12 | install_dir = "_install/" 13 | build_commands = ["cmake", "--build", ".", "--config", "Release", "--parallel"] 14 | test_arguments = ["-test-frames", "100"] 15 | 16 | def header(name): 17 | """Print a header with a given name.""" 18 | print("") 19 | print("***************************************************************************") 20 | print(f" {name}") 21 | print("***************************************************************************") 22 | 23 | def create_directory_if_not_exists(directory): 24 | """Create a directory if it does not exist.""" 25 | if not os.path.exists(directory): 26 | os.makedirs(directory) 27 | 28 | def run_cmake(commands): 29 | """Run CMake commands.""" 30 | try: 31 | subprocess.run(commands, check=True) 32 | except subprocess.CalledProcessError as e: 33 | print(f"Error occurred while running CMake: {e}") 34 | 35 | def build(): 36 | """Build the project.""" 37 | header("BUILDING PROJECT") 38 | 39 | # Create build and install directories if they do not exist 40 | create_directory_if_not_exists(build_dir) 41 | create_directory_if_not_exists(install_dir) 42 | 43 | # Change to the build directory 44 | os.chdir(build_dir) 45 | 46 | # Run CMake to generate build files 47 | run_cmake(["cmake", ".."]) 48 | 49 | # Call cmake to build the release config in parallel 50 | run_cmake(build_commands) 51 | 52 | # Change back to the original directory 53 | os.chdir("..") 54 | 55 | # Call cmake to install 56 | run_cmake(["cmake", "--install", "build", "--prefix", install_dir]) 57 | 58 | def print_log_result(log_file): 59 | # Print last 3 lines of log file 60 | if os.path.exists(log_file): 61 | with open(log_file, "r") as file: 62 | lines = file.readlines() 63 | print("Results:") 64 | for line in lines[-3:]: 65 | print(line.strip()) 66 | 67 | def test(): 68 | """Run tests on the built executables.""" 69 | print("Executing test function") 70 | test_dir = os.path.join(install_dir, "bin_x64/") 71 | 72 | # Check if test directory exists 73 | if not os.path.exists(test_dir): 74 | print(f"Test directory '{test_dir}' does not exist.") 75 | return 76 | 77 | current_dir = os.getcwd() 78 | os.chdir(test_dir) 79 | 80 | # Find all executables in the test directory 81 | executables = [ 82 | f 83 | for f in os.listdir(".") 84 | if os.path.isfile(os.path.join(".", f)) and (f.endswith(".exe") or f.endswith("_app")) 85 | ] 86 | names_to_avoid = [] 87 | 88 | # Call each executable with options --test and --screenshot 89 | returncode = 0 90 | for executable in executables: 91 | executable_path = os.path.join(".", executable) 92 | args = [executable_path] 93 | 94 | if not any(name in executable for name in names_to_avoid): 95 | args += ["-test"] 96 | args += test_arguments 97 | args += ["-screenshot", "snap_" + executable[:-4] + ".jpg"] 98 | try: 99 | header(f"Testing '{executable}'") 100 | subprocess.run(args, check=True) 101 | log_file = "log_" + executable[:-4] + ".txt" 102 | print_log_result(log_file) 103 | 104 | except subprocess.CalledProcessError as e: 105 | print(f"Error occurred while testing: {e}") 106 | returncode = e.returncode 107 | 108 | os.chdir(current_dir) 109 | if returncode != 0: 110 | sys.exit(1) 111 | 112 | if __name__ == "__main__": 113 | # Create the parser 114 | parser = argparse.ArgumentParser() 115 | 116 | # Add the command line options 117 | parser.add_argument("--build", action="store_true", help="Execute build function") 118 | parser.add_argument("--test", action="store_true", help="Execute test function") 119 | 120 | # Parse the command line arguments 121 | args = parser.parse_args() 122 | 123 | if args.build: 124 | build() 125 | 126 | if args.test: 127 | test() 128 | 129 | # If no arguments provided, call all functions 130 | if not any(vars(args).values()): 131 | build() 132 | test() 133 | --------------------------------------------------------------------------------