Bulk update NvPro-Samples 03/18/21

This commit is contained in:
Mathias Heyer 2021-03-18 15:00:48 -07:00
parent a2b80ab819
commit 2da588b7e6
113 changed files with 3529 additions and 1508 deletions

View file

@ -1,4 +1,4 @@
BasedOnStyle: LLVM BasedOnStyle: LLVM
AccessModifierOffset: '-2' AccessModifierOffset: '-2'
AlignAfterOpenBracket: Align AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: 'true' AlignConsecutiveAssignments: 'true'

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
**/spv/*.spv
/build/*

View file

@ -3,36 +3,36 @@ project(vk_raytracing_tutorial)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# look for shared_sources 1) as a sub-folder 2) at some other locations # look for shared_sources 1) as a sub-folder 2) at some other locations
# this cannot be put anywhere else since we still didn't find CMakeLists_include.txt yet # this cannot be put anywhere else since we still didn't find setup.cmake yet
if(NOT BASE_DIRECTORY) if(NOT BASE_DIRECTORY)
SET(BASE_DIRECTORY "" CACHE FILEPATH "folder containing shared_sources")
SET(ADD_SUBDIR_BELOW 1) find_path(BASE_DIRECTORY
find_path(BASE_DIRECTORY2 NAMES shared_sources/cmake/setup.cmake
NAMES shared_sources PATHS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../..
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}
REQUIRED REQUIRED
DOC "Couldn't find shared_source directory'" DOC "Directory containing shared_sources"
) )
SET(BASE_DIRECTORY ${BASE_DIRECTORY2} )
endif() endif()
## Various functions and macros REQUIRED ## Various functions and macros REQUIRED
include(${BASE_DIRECTORY}/shared_sources/CMakeLists_include.txt) if(EXISTS ${BASE_DIRECTORY}/shared_sources/cmake/setup.cmake)
include(${BASE_DIRECTORY}/shared_sources/cmake/setup.cmake)
include(${BASE_DIRECTORY}/shared_sources/cmake/utilities.cmake)
else()
message(FATAL_ERROR "could not find base directory, please set BASE_DIRECTORY to folder containing shared_sources")
endif()
set(TUTO_KHR_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(TUTO_KHR_DIR ${CMAKE_CURRENT_SOURCE_DIR})
# presets and utility functions used in all CMakeLists
include(utilities.cmake)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Package shared by all projects # Package shared by all projects
_add_package_VulkanSDK() _add_package_VulkanSDK()
_add_package_OpenGL()
_add_package_ImGUI() _add_package_ImGUI()
_add_package_ZLIB()
_add_shared_sources_lib() _add_shared_sources_lib()
message(STATUS "COPY ${CMAKE_CURRENT_SOURCE_DIR}/media to ${EXECUTABLE_OUTPUT_PATH}") message(STATUS "COPY ${CMAKE_CURRENT_SOURCE_DIR}/media to ${OUTPUT_PATH}")
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/media DESTINATION ${EXECUTABLE_OUTPUT_PATH}) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/media DESTINATION ${OUTPUT_PATH})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -51,5 +51,16 @@ add_subdirectory(ray_tracing_jitter_cam)
add_subdirectory(ray_tracing_manyhits) add_subdirectory(ray_tracing_manyhits)
add_subdirectory(ray_tracing_rayquery) add_subdirectory(ray_tracing_rayquery)
add_subdirectory(ray_tracing_reflections) add_subdirectory(ray_tracing_reflections)
add_subdirectory(ray_tracing_ao)
add_subdirectory(ray_tracing_indirect_scissor) add_subdirectory(ray_tracing_indirect_scissor)
#--------------------------------------------------------------------------------------------------
# Install - copying the media directory
install(DIRECTORY "media"
CONFIGURATIONS Release
DESTINATION "bin_${ARCH}")
install(DIRECTORY "media"
CONFIGURATIONS Debug
DESTINATION "bin_${ARCH}_debug")

View file

@ -1,4 +1,4 @@
![logo](http://nvidianews.nvidia.com/_ir/219/20157/NV_Designworks_logo_horizontal_greenblack.png) ![logo](http://nvidianews.nvidia.com/_ir/219/20157/NV_Designworks_logo_horizontal_greenblack.png)
# NVIDIA Vulkan Ray Tracing Tutorials # NVIDIA Vulkan Ray Tracing Tutorials

View file

@ -52,5 +52,5 @@ public:
std::vector<uint32_t> m_indices; std::vector<uint32_t> m_indices;
std::vector<MaterialObj> m_materials; std::vector<MaterialObj> m_materials;
std::vector<std::string> m_textures; std::vector<std::string> m_textures;
std::vector<uint32_t> m_matIndx; std::vector<int32_t> m_matIndx;
}; };

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 MiB

View file

@ -1,4 +1,4 @@
<meta charset="utf-8" lang="en"> <meta charset="utf-8" lang="en">
**Converting VK_NV_ray_tracing to VK_KHR_ray_tracing** **Converting VK_NV_ray_tracing to VK_KHR_ray_tracing**

View file

@ -1,2 +1,2 @@

# Start [Ray Tracing Tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/) # Start [Ray Tracing Tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/)

View file

@ -1,4 +1,4 @@
<meta charset="utf-8"> <meta charset="utf-8">
(insert vkrt_tutorial.md.html here) (insert vkrt_tutorial.md.html here)

View file

@ -1,4 +1,4 @@

# Environment Setup # Environment Setup

View file

@ -1,4 +1,4 @@
 <meta charset="utf-8"> <meta charset="utf-8">
# Environment Setup # Environment Setup

View file

@ -1,4 +1,4 @@
<meta charset="utf-8" lang="en"> <meta charset="utf-8" lang="en">
**NVIDIA Vulkan Ray Tracing Tutorial** **NVIDIA Vulkan Ray Tracing Tutorial**
**Animation** **Animation**
@ -132,7 +132,7 @@ This is absolutely needed, since otherwise the TLAS cannot be updated.
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
{ {
m_tlas.reserve(m_objInstance.size()); m_tlas.reserve(m_objInstance.size());
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilder::Instance rayInst; nvvk::RaytracingBuilder::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance

View file

@ -1,4 +1,4 @@
<meta charset="utf-8" lang="en"> <meta charset="utf-8" lang="en">
**NVIDIA Vulkan Ray Tracing Tutorial** **NVIDIA Vulkan Ray Tracing Tutorial**
**Anyhit Shaders** **Anyhit Shaders**
@ -118,10 +118,10 @@ In `createRtPipeline()`, after loading `raytrace.rchit.spv`, load `raytrace.rahi
add the any hit shader to the hit group add the any hit shader to the hit group
~~~~ C++ ~~~~ C++
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1)); hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"});
hg.setAnyHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
~~~~ ~~~~
@ -384,8 +384,8 @@ vk::ShaderModule ahit1SM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace_1.rahit.spv", true, paths)); nvh::loadFile("shaders/raytrace_1.rahit.spv", true, paths));
hg.setClosestHitShader(VK_SHADER_UNUSED_NV); // Not used by shadow (skipped) hg.setClosestHitShader(VK_SHADER_UNUSED_NV); // Not used by shadow (skipped)
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitNV, ahit1SM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitNV, ahit1SM, "main"});
hg.setAnyHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
~~~~ ~~~~

View file

@ -1,4 +1,4 @@
<meta charset="utf-8" lang="en"> <meta charset="utf-8" lang="en">
**NVIDIA Vulkan Ray Tracing Tutorial** **NVIDIA Vulkan Ray Tracing Tutorial**
**Instances** **Instances**
@ -79,14 +79,14 @@ In `HelloVulkan::createRtPipeline()`, immediately after adding the closest-hit s
vk::ShaderModule call2 = vk::ShaderModule call2 =
nvvk::createShaderModule(m_device, nvh::loadFile("shaders/light_inf.rcall.spv", true, paths)); nvvk::createShaderModule(m_device, nvh::loadFile("shaders/light_inf.rcall.spv", true, paths));
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"});
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); m_rtShaderGroups.push_back(callGroup);
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"});
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); m_rtShaderGroups.push_back(callGroup);
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"});
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); m_rtShaderGroups.push_back(callGroup);
~~~~ ~~~~

View file

@ -1,4 +1,4 @@
<meta charset="utf-8" lang="en"> <meta charset="utf-8" lang="en">
**NVIDIA Vulkan Ray Tracing Tutorial** **NVIDIA Vulkan Ray Tracing Tutorial**
**Trace Rays Indirect** **Trace Rays Indirect**
@ -673,7 +673,7 @@ void HelloVulkan::createTopLevelAS()
tlas.reserve(m_objInstance.size() + m_lanternCount); tlas.reserve(m_objInstance.size() + m_lanternCount);
// Add the OBJ instances. // Add the OBJ instances.
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance
@ -817,8 +817,8 @@ TLAS build.
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
// Lantern Primary Ray Hit Group // Lantern Primary Ray Hit Group
@ -830,8 +830,8 @@ TLAS build.
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
lanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternChitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternChitSM, "main"});
lanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(lanternHg); m_rtShaderGroups.push_back(lanternHg);
// ... // ...
@ -1121,8 +1121,8 @@ and add this code for loading the last 2 closest hit shaders after loading
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
lanternShadowObjHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowObjChitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowObjChitSM, "main"});
lanternShadowObjHg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(lanternShadowObjHg); m_rtShaderGroups.push_back(lanternShadowObjHg);
// Lantern Lantern Shadow Ray Hit Group // Lantern Lantern Shadow Ray Hit Group
@ -1134,8 +1134,8 @@ and add this code for loading the last 2 closest hit shaders after loading
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
lanternShadowLanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowLanternChitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowLanternChitSM, "main"});
lanternShadowLanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(lanternShadowLanternHg); m_rtShaderGroups.push_back(lanternShadowLanternHg);
```` ````
@ -1149,7 +1149,7 @@ We need to destroy the added shader modules at the end of the function.
```` ````
Through all this, we still load shader stages in the same order as they will appear Through all this, we still load shader stages in the same order as they will appear
in the SBT in order to keep things simple (note `stages.size() - 1`). Add a comment in the SBT in order to keep things simple (note `stages.size()`). Add a comment
at the top of this function to help us keep track of all the new shaders. at the top of this function to help us keep track of all the new shaders.
```` C ```` C

View file

@ -1,4 +1,4 @@
<meta charset="utf-8" lang="en"> <meta charset="utf-8" lang="en">
**NVIDIA Vulkan Ray Tracing Tutorial** **NVIDIA Vulkan Ray Tracing Tutorial**
**Instances** **Instances**

View file

@ -1,4 +1,4 @@
<meta charset="utf-8" lang="en"> <meta charset="utf-8" lang="en">
**NVIDIA Vulkan Ray Tracing Tutorial** **NVIDIA Vulkan Ray Tracing Tutorial**
**Intersection Shader** **Intersection Shader**
@ -320,8 +320,8 @@ Here is how the two hit group looks like:
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
} }
@ -336,10 +336,10 @@ Here is how the two hit group looks like:
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1)); hg.setIntersectionShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"});
hg.setIntersectionShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
} }
~~~~ ~~~~

View file

@ -1,4 +1,4 @@
<meta charset="utf-8" lang="en"> <meta charset="utf-8" lang="en">
**NVIDIA Vulkan Ray Tracing Tutorial** **NVIDIA Vulkan Ray Tracing Tutorial**
**Antialiasing** **Antialiasing**

View file

@ -1,4 +1,4 @@
<meta charset="utf-8" lang="en"> <meta charset="utf-8" lang="en">
**NVIDIA Vulkan Ray Tracing Tutorial** **NVIDIA Vulkan Ray Tracing Tutorial**
**Multiple Closest Hit Shaders** **Multiple Closest Hit Shaders**
@ -68,8 +68,8 @@ Then add a new hit group group immediately after adding the first hit group:
~~~~ C++ ~~~~ C++
// Second group // Second group
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
~~~~ ~~~~

View file

@ -1,4 +1,4 @@
<meta charset="utf-8" lang="en"> <meta charset="utf-8" lang="en">
**NVIDIA Vulkan Ray Tracing Tutorial** **NVIDIA Vulkan Ray Tracing Tutorial**
**Ray Query** **Ray Query**

View file

@ -1,4 +1,4 @@
<meta charset="utf-8" lang="en"> <meta charset="utf-8" lang="en">
**NVIDIA Vulkan Ray Tracing Tutorial** **NVIDIA Vulkan Ray Tracing Tutorial**
**Reflections** **Reflections**

View file

@ -1,4 +1,4 @@
 <meta charset="utf-8"> <meta charset="utf-8">
**NVIDIA Vulkan Ray Tracing Tutorial** **NVIDIA Vulkan Ray Tracing Tutorial**
<small> <small>
By [Martin-Karl Lefrançois](https://devblogs.nvidia.com/author/mlefrancois/), By [Martin-Karl Lefrançois](https://devblogs.nvidia.com/author/mlefrancois/),
@ -8,7 +8,7 @@ By [Martin-Karl Lefrançois](https://devblogs.nvidia.com/author/mlefrancois/),
The focus of this document and the provided code is to showcase a basic integration of The focus of this document and the provided code is to showcase a basic integration of
ray tracing within an existing Vulkan sample, using the ray tracing within an existing Vulkan sample, using the
[`VK_KHR_ray_tracing`](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VK_KHR_ray_tracing) [`VK_KHR_ray_tracing_pipeline`](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VK_KHR_ray_tracing_pipeline)
extension. This tutorial starts from a basic Vulkan application and provides step-by-step instructions to modify and add extension. This tutorial starts from a basic Vulkan application and provides step-by-step instructions to modify and add
methods and functions. The sections are organized by components, with subsections identifying the modified functions. methods and functions. The sections are organized by components, with subsections identifying the modified functions.
@ -69,17 +69,13 @@ cd build
cmake .. cmake ..
~~~~~ ~~~~~
## Beta Installation ## Tools Installation
The SDK 1.2.161 and up which can be found under https://vulkan.lunarg.com/sdk/home will work with this project. You need a graphics card with support for the `VK_KHR_ray_tracing_pipeline` extension.
For NVIDIA graphics cards, you need a [Vulkan driver](https://developer.nvidia.com/vulkan-driver)
released in 2021 or later.
Nevertheless, if you are in the Beta period, it is suggested to install and compile all of the following and replace The Vulkan SDK 1.2.161 and up which can be found under https://vulkan.lunarg.com/sdk/home will work with this project.
with the current environment.
* Latest *beta* driver: https://developer.nvidia.com/vulkan-driver
* Vulkan headers: https://github.com/KhronosGroup/Vulkan-Headers
* Validator: https://github.com/KhronosGroup/Vulkan-ValidationLayers
* Vulkan-Hpp: https://github.com/KhronosGroup/Vulkan-Hpp
!!! Tip Visual Assist !!! Tip Visual Assist
To get auto-completion, edit vulkan.hpp and change two places from:<br> To get auto-completion, edit vulkan.hpp and change two places from:<br>
@ -108,7 +104,7 @@ extra tutorials.
Go to the `main` function of the `main.cpp` file, and find where we request Vulkan extensions with Go to the `main` function of the `main.cpp` file, and find where we request Vulkan extensions with
`nvvk::ContextCreateInfo`. `nvvk::ContextCreateInfo`.
To be able to use ray tracing, we will need VK_KHR_ACCELERATION_STRUCTURE and VK_KHR_RAY_TRACING_PIPELINE. To be able to use ray tracing, we will need `VK_KHR_ACCELERATION_STRUCTURE` and `VK_KHR_RAY_TRACING_PIPELINE`.
Those extensions have also dependencies on other extension, therefore all the following Those extensions have also dependencies on other extension, therefore all the following
extensions will need to be added. extensions will need to be added.
@ -159,7 +155,7 @@ vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
At the end of `hello_vulkan.cpp`, add the body of `initRayTracing()`, which will query the ray tracing capabilities At the end of `hello_vulkan.cpp`, add the body of `initRayTracing()`, which will query the ray tracing capabilities
of the GPU using this extension. In particular, it will obtain the maximum recursion depth, of the GPU using this extension. In particular, it will obtain the maximum recursion depth,
ie. the number of nested ray tracing calls that can be performed from a single ray. This can be seen as the number i.e. the number of nested ray tracing calls that can be performed from a single ray. This can be seen as the number
of times a ray can bounce in the scene in a recursive path tracer. Note that for performance purposes, recursion of times a ray can bounce in the scene in a recursive path tracer. Note that for performance purposes, recursion
should in practice be kept to a minimum, favoring a loop formulation. This also queries the shader header size, should in practice be kept to a minimum, favoring a loop formulation. This also queries the shader header size,
needed in a later section for creating the shader binding table. needed in a later section for creating the shader binding table.
@ -256,7 +252,7 @@ m_rtBuilder.setup(m_device, m_alloc, m_graphicsQueueIndex);
This selects the simple one-`VkDeviceMemory`-per-object strategy, which is easier to understand for This selects the simple one-`VkDeviceMemory`-per-object strategy, which is easier to understand for
teaching purposes but not practical for production use. teaching purposes but not practical for production use.
## Bottom-Level Acceleration Structureg ## Bottom-Level Acceleration Structure
The first step of building a BLAS object consists in converting the geometry data of an `ObjModel` into The first step of building a BLAS object consists in converting the geometry data of an `ObjModel` into
multiple structures consumed by the AS builder. We are holding all those structures under multiple structures consumed by the AS builder. We are holding all those structures under
@ -294,7 +290,7 @@ Its implementation will fill three structures that will eventually be passed to
<!-- and I would have appreciated a crude analogy. --> <!-- and I would have appreciated a crude analogy. -->
Multiple of the above structure can be combined in arrays and built into a single blas. In this example, Multiple of the above structure can be combined in arrays and built into a single BLAS. In this example,
this array will always be a length of one. this array will always be a length of one.
Note that we consider all objects opaque for now, and indicate this to the builder for Note that we consider all objects opaque for now, and indicate this to the builder for
@ -508,7 +504,7 @@ Now that we know the maximum scratch memory needed, we allocate a scratch buffer
VkDeviceAddress scratchAddress = vkGetBufferDeviceAddress(m_device, &bufferInfo); VkDeviceAddress scratchAddress = vkGetBufferDeviceAddress(m_device, &bufferInfo);
```` ````
To know the size that the BLAS is really taking, we use queries and setting the type to `VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR`. To know the size that the BLAS is really taking, we use queries of the type `VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR`.
This is needed if we want to compact the acceleration structure in a second step. By default, the This is needed if we want to compact the acceleration structure in a second step. By default, the
memory allocated by the creation of the acceleration structure has the size of the worst case. After creation, memory allocated by the creation of the acceleration structure has the size of the worst case. After creation,
the real space can be smaller, and it is possible to copy the acceleration structure to one that is the real space can be smaller, and it is possible to copy the acceleration structure to one that is
@ -534,7 +530,7 @@ TDR if the job was too heavy.
Note the barrier after each Note the barrier after each
build call: this is required as we reuse the scratch space across builds, and hence need to ensure build call: this is required as we reuse the scratch space across builds, and hence need to ensure
the previous build has completed before starting the next. We could have used multiple scratch buffers, the previous build has completed before starting the next. We could have used multiple scratch buffers,
but it would have been expensive memory wise, and the device can only build one BLAS at a time, so we but it would have been expensive memory wise, and the device can only build one BLAS at a time, so it
wouldn't be faster. wouldn't be faster.
```` C ```` C
@ -691,7 +687,7 @@ void HelloVulkan::createTopLevelAS()
{ {
std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas; std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_objInstance.size());
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance
@ -1269,15 +1265,15 @@ void HelloVulkan::createRtPipeline()
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); m_rtShaderGroups.push_back(rg);
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
```` ````
@ -1301,8 +1297,8 @@ shaders.
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
```` ````
@ -1806,10 +1802,8 @@ We now trace the ray itself by calling `traceRayEXT`. This takes as arguments
`hitGroupId` `hitGroupId`
(`VkAccelerationStructureInstanceKHR::instanceShaderBindingTableRecordOffset`) (`VkAccelerationStructureInstanceKHR::instanceShaderBindingTableRecordOffset`)
of each instance is used to look up a hit group in the SBT's hit of each instance is used to look up a hit group in the SBT's hit
group array. Since we only have one hit group, both are set to group array. Since we only have one hit group, both are set to 0. The details of this are rather complicated; you can read more in [Will Usher's article](https://www.willusher.io/graphics/2019/11/20/the-sbt-three-ways).
0. The details of this are rather complicated; you can read more <!-- Not sure why but Markdeep adds an extra bullet point if I split the above line -->
in <a href="https://www.willusher.io/graphics/2019/11/20/the-sbt-three-ways">Will
Usher's article</a>.
* `missIndex`, the index, within the miss shader group array of the SBT, of the shader to call if no intersection is found. * `missIndex`, the index, within the miss shader group array of the SBT, of the shader to call if no intersection is found.
@ -2145,8 +2139,8 @@ After pushing the miss shader `missSM`, we also push the miss shader for the sha
```` C ```` C
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
```` ````

View file

@ -28,30 +28,13 @@ file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories(${TUTO_KHR_DIR}/common) include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# compile_glsl_directory(
SET(VULKAN_TARGET_ENV vulkan1.2) SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
UNSET(GLSL_SOURCES) DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
UNSET(SPV_OUTPUT) VULKAN_TARGET "vulkan1.2"
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -59,7 +42,7 @@ list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -68,7 +51,7 @@ target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES}) source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES}) source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES}) source_group("Shader_Files" FILES ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -87,25 +70,8 @@ endforeach(RELEASELIB)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.) # copies binaries that need to be put next to the exe files (ZLib, etc.)
# #
_copy_binaries_to_target( ${PROJNAME} ) _finalize_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -1,4 +1,4 @@
# NVIDIA Vulkan Ray Tracing Tutorial # NVIDIA Vulkan Ray Tracing Tutorial
This example is the combination of all tutorials. This example is the combination of all tutorials.

View file

@ -84,7 +84,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreen.setup(device, &m_alloc, queueFamily); m_offscreen.setup(device, physicalDevice, &m_alloc, queueFamily);
m_raytrace.setup(device, physicalDevice, &m_alloc, queueFamily); m_raytrace.setup(device, physicalDevice, &m_alloc, queueFamily);
} }
@ -105,8 +105,8 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; vk::Buffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader auto uboUsageStages =
| vk::PipelineStageFlagBits::eRayTracingShaderKHR; vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; vk::BufferMemoryBarrier beforeBarrier;
@ -115,9 +115,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.setBuffer(deviceUBO);
beforeBarrier.setOffset(0); beforeBarrier.setOffset(0);
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
@ -131,9 +129,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
afterBarrier.setBuffer(deviceUBO); afterBarrier.setBuffer(deviceUBO);
afterBarrier.setOffset(0); afterBarrier.setOffset(0);
afterBarrier.setSize(sizeof hostUBO); afterBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
} }
@ -251,8 +247,8 @@ void HelloVulkan::createGraphicsPipeline()
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreen.renderPass()); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreen.renderPass());
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions(std::vector<vk::VertexInputAttributeDescription>{ gpb.addAttributeDescriptions(std::vector<vk::VertexInputAttributeDescription>{
{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)},

View file

@ -34,7 +34,7 @@
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_glfw.h" #include "imgui/backends/imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
@ -44,7 +44,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
#include "imgui_camera_widget.h" #include "imgui/extras/imgui_camera_widget.h"
#include <random> #include <random>
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -144,15 +144,13 @@ int main(int argc, char** argv)
} }
// setup some basic things for the sample, logging file for example // setup some basic things for the sample, logging file for example
NVPSystem system(argv[0], PROJECT_NAME); NVPSystem system(PROJECT_NAME);
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, NVPSystem::exePath() + PROJECT_RELDIRECTORY,
PROJECT_ABSDIRECTORY "..", NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
NVPSystem::exePath(), std::string(PROJECT_NAME),
NVPSystem::exePath() + "..",
NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
@ -365,7 +363,7 @@ int main(int argc, char** argv)
offscreen.draw(cmdBuf, helloVk.getSize()); offscreen.draw(cmdBuf, helloVk.getSize());
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuf, ImGui::GetDrawData()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); cmdBuf.endRenderPass();
} }

View file

@ -39,12 +39,16 @@ extern std::vector<std::string> defaultSearchPaths;
// Post-processing // Post-processing
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void Offscreen::setup(const vk::Device& device, nvvk::Allocator* allocator, uint32_t queueFamily) void Offscreen::setup(const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
nvvk::Allocator* allocator,
uint32_t queueFamily)
{ {
m_device = device; m_device = device;
m_alloc = allocator; m_alloc = allocator;
m_graphicsQueueIndex = queueFamily; m_graphicsQueueIndex = queueFamily;
m_debug.setup(m_device); m_debug.setup(m_device);
m_depthFormat = nvvk::findDepthFormat(physicalDevice);
} }
void Offscreen::destroy() void Offscreen::destroy()
@ -150,12 +154,11 @@ void Offscreen::createPipeline(vk::RenderPass& renderPass)
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_pipelineLayout, renderPass); nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_pipelineLayout, renderPass);
pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_pipeline = pipelineGenerator.createPipeline(); m_pipeline = pipelineGenerator.createPipeline();

View file

@ -40,7 +40,10 @@
class Offscreen class Offscreen
{ {
public: public:
void setup(const vk::Device& device, nvvk::Allocator* allocator, uint32_t queueFamily); void setup(const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
nvvk::Allocator* allocator,
uint32_t queueFamily);
void destroy(); void destroy();
void createFramebuffer(VkExtent2D& size); void createFramebuffer(VkExtent2D& size);
@ -66,7 +69,7 @@ private:
nvvk::Texture m_colorTexture; nvvk::Texture m_colorTexture;
vk::Format m_colorFormat{vk::Format::eR32G32B32A32Sfloat}; vk::Format m_colorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_depthTexture; nvvk::Texture m_depthTexture;
vk::Format m_depthFormat{vk::Format::eD32Sfloat}; vk::Format m_depthFormat;
nvvk::Allocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures nvvk::Allocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures
vk::Device m_device; vk::Device m_device;

View file

@ -246,19 +246,15 @@ void Raytracer::updateRtDescriptorSet(const vk::ImageView& outputImage)
// //
void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout) void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
{ {
std::vector<std::string> paths = defaultSearchPaths; vk::ShaderModule raygenSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
vk::ShaderModule raygenSM = vk::ShaderModule missSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true));
// The second miss shader is invoked when a shadow ray misses the geometry. It // The second miss shader is invoked when a shadow ray misses the geometry. It
// simply indicates that no occlusion has been found // simply indicates that no occlusion has been found
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -267,60 +263,55 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); // 0 m_rtShaderGroups.push_back(rg); // 0
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); // 1 m_rtShaderGroups.push_back(mg); // 1
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); // 2 m_rtShaderGroups.push_back(mg); // 2
// Hit Group0 - Closest Hit + AnyHit // Hit Group0 - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::ShaderModule ahitSM = nvvk::createShaderModule(
vk::ShaderModule ahitSM = m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true));
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rahit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1)); hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"});
hg.setAnyHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); // 3 m_rtShaderGroups.push_back(hg); // 3
// Hit Group1 - Closest Hit + Intersection (procedural) // Hit Group1 - Closest Hit + Intersection (procedural)
vk::ShaderModule chit2SM = vk::ShaderModule chit2SM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true)); vk::ShaderModule ahit2SM = nvvk::createShaderModule(
vk::ShaderModule ahit2SM = m_device, nvh::loadFile("spv/raytrace2.rahit.spv", true, defaultSearchPaths, true));
nvvk::createShaderModule(m_device, // vk::ShaderModule rintSM = nvvk::createShaderModule(
nvh::loadFile("shaders/raytrace2.rahit.spv", true, paths, true)); m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true));
vk::ShaderModule rintSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rint.spv", true, paths, true));
{ {
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1)); hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahit2SM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahit2SM, "main"});
hg.setAnyHitShader(static_cast<uint32_t>(stages.size() - 1)); hg.setIntersectionShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"});
hg.setIntersectionShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); // 4 m_rtShaderGroups.push_back(hg); // 4
} }
@ -329,24 +320,21 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
vk::ShaderModule call0 = vk::ShaderModule call0 = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/light_point.rcall.spv", true, paths, true)); vk::ShaderModule call1 = nvvk::createShaderModule(
vk::ShaderModule call1 = m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
nvvk::createShaderModule(m_device, vk::ShaderModule call2 = nvvk::createShaderModule(
nvh::loadFile("shaders/light_spot.rcall.spv", true, paths, true)); m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
vk::ShaderModule call2 =
nvvk::createShaderModule(m_device,
nvh::loadFile("shaders/light_inf.rcall.spv", true, paths, true));
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"});
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); // 5 m_rtShaderGroups.push_back(callGroup); // 5
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"});
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); // 6 m_rtShaderGroups.push_back(callGroup); // 6
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"});
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); //7 m_rtShaderGroups.push_back(callGroup); //7

View file

@ -31,27 +31,11 @@ include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# compile_glsl_directory(
SET(VULKAN_TARGET_ENV vulkan1.2) SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
UNSET(GLSL_SOURCES) DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
UNSET(SPV_OUTPUT) VULKAN_TARGET "vulkan1.2"
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -59,7 +43,7 @@ list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -68,7 +52,7 @@ target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES}) source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES}) source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES}) source_group("Shader_Files" FILES ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -87,25 +71,8 @@ endforeach(RELEASELIB)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.) # copies binaries that need to be put next to the exe files (ZLib, etc.)
# #
_copy_binaries_to_target( ${PROJNAME} ) _finalize_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -1,4 +1,4 @@
# NVIDIA Vulkan Ray Tracing Tutorial # NVIDIA Vulkan Ray Tracing Tutorial
This example is a simple OBJ viewer in Vulkan, without any ray tracing functionality. This example is a simple OBJ viewer in Vulkan, without any ray tracing functionality.
It is the starting point of the ray tracing tutorial, the source of the application in which ray tracing will be added. It is the starting point of the ray tracing tutorial, the source of the application in which ray tracing will be added.

View file

@ -64,6 +64,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBase::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -90,9 +91,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.setBuffer(deviceUBO);
beforeBarrier.setOffset(0); beforeBarrier.setOffset(0);
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
@ -106,9 +105,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
afterBarrier.setBuffer(deviceUBO); afterBarrier.setBuffer(deviceUBO);
afterBarrier.setOffset(0); afterBarrier.setOffset(0);
afterBarrier.setSize(sizeof hostUBO); afterBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
} }
@ -203,8 +200,8 @@ void HelloVulkan::createGraphicsPipeline()
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions(std::vector<vk::VertexInputAttributeDescription>{ gpb.addAttributeDescriptions(std::vector<vk::VertexInputAttributeDescription>{
{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)},
@ -554,13 +551,12 @@ void HelloVulkan::createPostPipeline()
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
m_renderPass); m_renderPass);
pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline(); m_postPipeline = pipelineGenerator.createPipeline();

View file

@ -128,5 +128,5 @@ public:
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; vk::Format m_offscreenDepthFormat;
}; };

View file

@ -34,10 +34,10 @@
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_glfw.h" #include "imgui/backends/imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui_camera_widget.h" #include "imgui/extras/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
@ -113,15 +113,13 @@ int main(int argc, char** argv)
} }
// setup some basic things for the sample, logging file for example // setup some basic things for the sample, logging file for example
NVPSystem system(argv[0], PROJECT_NAME); NVPSystem system(PROJECT_NAME);
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, NVPSystem::exePath() + PROJECT_RELDIRECTORY,
PROJECT_ABSDIRECTORY "..", NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
NVPSystem::exePath(), std::string(PROJECT_NAME),
NVPSystem::exePath() + "..",
NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
@ -260,7 +258,7 @@ int main(int argc, char** argv)
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuf, ImGui::GetDrawData()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); cmdBuf.endRenderPass();
} }

View file

@ -31,27 +31,11 @@ include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# compile_glsl_directory(
SET(VULKAN_TARGET_ENV vulkan1.2) SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
UNSET(GLSL_SOURCES) DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
UNSET(SPV_OUTPUT) VULKAN_TARGET "vulkan1.2"
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -59,7 +43,7 @@ list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -68,7 +52,7 @@ target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES}) source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES}) source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES}) source_group("Shader_Files" FILES ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -87,25 +71,9 @@ endforeach(RELEASELIB)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.) # copies binaries that need to be put next to the exe files (ZLib, etc.)
# #
_copy_binaries_to_target( ${PROJNAME} ) _finalize_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -1,4 +1,4 @@
# NVIDIA Vulkan Ray Tracing Tutorial # NVIDIA Vulkan Ray Tracing Tutorial
This example is the result of the ray tracing tutorial. This example is the result of the ray tracing tutorial.
The tutorial is adding ray tracing capability to an OBJ rasterizer in Vulkan The tutorial is adding ray tracing capability to an OBJ rasterizer in Vulkan

View file

@ -68,6 +68,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBase::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -87,8 +88,8 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; vk::Buffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader auto uboUsageStages =
| vk::PipelineStageFlagBits::eRayTracingShaderKHR; vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; vk::BufferMemoryBarrier beforeBarrier;
@ -97,9 +98,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.setBuffer(deviceUBO);
beforeBarrier.setOffset(0); beforeBarrier.setOffset(0);
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
@ -113,9 +112,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
afterBarrier.setBuffer(deviceUBO); afterBarrier.setBuffer(deviceUBO);
afterBarrier.setOffset(0); afterBarrier.setOffset(0);
afterBarrier.setSize(sizeof hostUBO); afterBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
} }
@ -223,8 +220,8 @@ void HelloVulkan::createGraphicsPipeline()
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions(std::vector<vk::VertexInputAttributeDescription>{ gpb.addAttributeDescriptions(std::vector<vk::VertexInputAttributeDescription>{
{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)},
@ -584,13 +581,12 @@ void HelloVulkan::createPostPipeline()
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
m_renderPass); m_renderPass);
pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline(); m_postPipeline = pipelineGenerator.createPipeline();
@ -727,7 +723,7 @@ void HelloVulkan::createTopLevelAS()
{ {
std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas; std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_objInstance.size());
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance
@ -793,19 +789,15 @@ void HelloVulkan::updateRtDescriptorSet()
// //
void HelloVulkan::createRtPipeline() void HelloVulkan::createRtPipeline()
{ {
std::vector<std::string> paths = defaultSearchPaths; vk::ShaderModule raygenSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
vk::ShaderModule raygenSM = vk::ShaderModule missSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true));
// The second miss shader is invoked when a shadow ray misses the geometry. It // The second miss shader is invoked when a shadow ray misses the geometry. It
// simply indicates that no occlusion has been found // simply indicates that no occlusion has been found
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -814,31 +806,30 @@ void HelloVulkan::createRtPipeline()
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); m_rtShaderGroups.push_back(rg);
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
@ -875,8 +866,10 @@ void HelloVulkan::createRtPipeline()
m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
// Spec only guarantees 1 level of "recursion". Check for that sad possibility here. // Spec only guarantees 1 level of "recursion". Check for that sad possibility here.
if (m_rtProperties.maxRayRecursionDepth <= 1) { if(m_rtProperties.maxRayRecursionDepth <= 1)
throw std::runtime_error("Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); {
throw std::runtime_error(
"Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)");
} }
m_device.destroy(raygenSM); m_device.destroy(raygenSM);

View file

@ -130,7 +130,7 @@ public:
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; vk::Format m_offscreenDepthFormat;
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();

View file

@ -34,10 +34,10 @@
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_glfw.h" #include "imgui/backends/imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui_camera_widget.h" #include "imgui/extras/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
@ -109,15 +109,13 @@ int main(int argc, char** argv)
} }
// setup some basic things for the sample, logging file for example // setup some basic things for the sample, logging file for example
NVPSystem system(argv[0], PROJECT_NAME); NVPSystem system(PROJECT_NAME);
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, NVPSystem::exePath() + PROJECT_RELDIRECTORY,
PROJECT_ABSDIRECTORY "..", NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
NVPSystem::exePath(), std::string(PROJECT_NAME),
NVPSystem::exePath() + "..",
NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
@ -289,7 +287,7 @@ int main(int argc, char** argv)
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuf, ImGui::GetDrawData()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); cmdBuf.endRenderPass();
} }

View file

@ -31,27 +31,11 @@ include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# compile_glsl_directory(
SET(VULKAN_TARGET_ENV vulkan1.2) SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
UNSET(GLSL_SOURCES) DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
UNSET(SPV_OUTPUT) VULKAN_TARGET "vulkan1.2"
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -59,7 +43,7 @@ list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -68,7 +52,7 @@ target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES}) source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES}) source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES}) source_group("Shader_Files" FILES ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -87,25 +71,8 @@ endforeach(RELEASELIB)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.) # copies binaries that need to be put next to the exe files (ZLib, etc.)
# #
_copy_binaries_to_target( ${PROJNAME} ) _finalize_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -1,4 +1,4 @@
# Ray Tracing Animation - Tutorial # Ray Tracing Animation - Tutorial
![](images/animation2.gif) ![](images/animation2.gif)
@ -122,7 +122,7 @@ This is absolutely needed, since otherwise the TLAS cannot be updated.
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
{ {
m_tlas.reserve(m_objInstance.size()); m_tlas.reserve(m_objInstance.size());
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilder::Instance rayInst; nvvk::RaytracingBuilder::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance

View file

@ -68,6 +68,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBase::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -87,8 +88,8 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; vk::Buffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader auto uboUsageStages =
| vk::PipelineStageFlagBits::eRayTracingShaderKHR; vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; vk::BufferMemoryBarrier beforeBarrier;
@ -97,9 +98,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.setBuffer(deviceUBO);
beforeBarrier.setOffset(0); beforeBarrier.setOffset(0);
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
@ -113,9 +112,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
afterBarrier.setBuffer(deviceUBO); afterBarrier.setBuffer(deviceUBO);
afterBarrier.setOffset(0); afterBarrier.setOffset(0);
afterBarrier.setSize(sizeof hostUBO); afterBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
} }
@ -223,8 +220,8 @@ void HelloVulkan::createGraphicsPipeline()
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)},
{1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)},
@ -590,13 +587,12 @@ void HelloVulkan::createPostPipeline()
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
m_renderPass); m_renderPass);
pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline(); m_postPipeline = pipelineGenerator.createPipeline();
@ -719,7 +715,7 @@ void HelloVulkan::createBottomLevelAS()
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
{ {
m_tlas.reserve(m_objInstance.size()); m_tlas.reserve(m_objInstance.size());
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance
@ -788,19 +784,15 @@ void HelloVulkan::updateRtDescriptorSet()
// //
void HelloVulkan::createRtPipeline() void HelloVulkan::createRtPipeline()
{ {
std::vector<std::string> paths = defaultSearchPaths; vk::ShaderModule raygenSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
vk::ShaderModule raygenSM = vk::ShaderModule missSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true));
// The second miss shader is invoked when a shadow ray misses the geometry. It // The second miss shader is invoked when a shadow ray misses the geometry. It
// simply indicates that no occlusion has been found // simply indicates that no occlusion has been found
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -809,31 +801,30 @@ void HelloVulkan::createRtPipeline()
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); m_rtShaderGroups.push_back(rg);
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
@ -882,7 +873,7 @@ void HelloVulkan::createRtPipeline()
void HelloVulkan::createRtShaderBindingTable() void HelloVulkan::createRtShaderBindingTable()
{ {
auto groupCount = auto groupCount =
static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit static_cast<uint32_t>(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, chit
uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier
uint32_t groupSizeAligned = uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
@ -1050,7 +1041,7 @@ void HelloVulkan::createCompPipelines()
vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout}; vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout};
computePipelineCreateInfo.stage = nvvk::createShaderStageInfo( computePipelineCreateInfo.stage = nvvk::createShaderStageInfo(
m_device, nvh::loadFile("shaders/anim.comp.spv", true, defaultSearchPaths, true), m_device, nvh::loadFile("spv/anim.comp.spv", true, defaultSearchPaths, true),
VK_SHADER_STAGE_COMPUTE_BIT); VK_SHADER_STAGE_COMPUTE_BIT);
m_compPipeline = static_cast<const vk::Pipeline&>( m_compPipeline = static_cast<const vk::Pipeline&>(
m_device.createComputePipeline({}, computePipelineCreateInfo)); m_device.createComputePipeline({}, computePipelineCreateInfo));

View file

@ -129,7 +129,7 @@ public:
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; vk::Format m_offscreenDepthFormat;
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();

View file

@ -33,10 +33,10 @@
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_glfw.h" #include "imgui/backends/imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui_camera_widget.h" #include "imgui/extras/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
@ -110,15 +110,13 @@ int main(int argc, char** argv)
} }
// setup some basic things for the sample, logging file for example // setup some basic things for the sample, logging file for example
NVPSystem system(argv[0], PROJECT_NAME); NVPSystem system(PROJECT_NAME);
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, NVPSystem::exePath() + PROJECT_RELDIRECTORY,
PROJECT_ABSDIRECTORY "..", NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
NVPSystem::exePath(), std::string(PROJECT_NAME),
NVPSystem::exePath() + "..",
NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
@ -304,7 +302,7 @@ int main(int argc, char** argv)
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuf, ImGui::GetDrawData()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); cmdBuf.endRenderPass();
} }

View file

@ -31,27 +31,11 @@ include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# compile_glsl_directory(
SET(VULKAN_TARGET_ENV vulkan1.2) SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
UNSET(GLSL_SOURCES) DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
UNSET(SPV_OUTPUT) VULKAN_TARGET "vulkan1.2"
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -59,7 +43,7 @@ list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -68,7 +52,7 @@ target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES}) source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES}) source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES}) source_group("Shader_Files" FILES ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -87,25 +71,8 @@ endforeach(RELEASELIB)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.) # copies binaries that need to be put next to the exe files (ZLib, etc.)
# #
_copy_binaries_to_target( ${PROJNAME} ) _finalize_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -1,4 +1,4 @@
# Any Hit Shaders - Tutorial # Any Hit Shaders - Tutorial
<small>Authors: [Martin-Karl Lefrançois](https://devblogs.nvidia.com/author/mlefrancois/), Neil Bickford </small> <small>Authors: [Martin-Karl Lefrançois](https://devblogs.nvidia.com/author/mlefrancois/), Neil Bickford </small>
![](../docs/Images/anyhit.png) ![](../docs/Images/anyhit.png)
@ -116,10 +116,10 @@ In `createRtPipeline()`, after loading `raytrace.rchit.spv`, load `raytrace.rahi
add the any hit shader to the hit group add the any hit shader to the hit group
~~~~ C++ ~~~~ C++
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1)); hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"});
hg.setAnyHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
~~~~ ~~~~
@ -382,8 +382,8 @@ vk::ShaderModule ahit1SM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace_1.rahit.spv", true, paths)); nvh::loadFile("shaders/raytrace_1.rahit.spv", true, paths));
hg.setClosestHitShader(VK_SHADER_UNUSED_NV); // Not used by shadow (skipped) hg.setClosestHitShader(VK_SHADER_UNUSED_NV); // Not used by shadow (skipped)
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitNV, ahit1SM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitNV, ahit1SM, "main"});
hg.setAnyHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
~~~~ ~~~~

View file

@ -68,6 +68,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBase::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -87,8 +88,8 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; vk::Buffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader auto uboUsageStages =
| vk::PipelineStageFlagBits::eRayTracingShaderKHR; vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; vk::BufferMemoryBarrier beforeBarrier;
@ -97,9 +98,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.setBuffer(deviceUBO);
beforeBarrier.setOffset(0); beforeBarrier.setOffset(0);
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
@ -113,9 +112,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
afterBarrier.setBuffer(deviceUBO); afterBarrier.setBuffer(deviceUBO);
afterBarrier.setOffset(0); afterBarrier.setOffset(0);
afterBarrier.setSize(sizeof hostUBO); afterBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
} }
@ -226,8 +223,8 @@ void HelloVulkan::createGraphicsPipeline()
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)},
{1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)},
@ -587,13 +584,12 @@ void HelloVulkan::createPostPipeline()
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
m_renderPass); m_renderPass);
pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline(); m_postPipeline = pipelineGenerator.createPipeline();
@ -717,7 +713,7 @@ void HelloVulkan::createTopLevelAS()
{ {
std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas; std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_objInstance.size());
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance
@ -783,19 +779,15 @@ void HelloVulkan::updateRtDescriptorSet()
// //
void HelloVulkan::createRtPipeline() void HelloVulkan::createRtPipeline()
{ {
std::vector<std::string> paths = defaultSearchPaths; vk::ShaderModule raygenSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
vk::ShaderModule raygenSM = vk::ShaderModule missSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true));
// The second miss shader is invoked when a shadow ray misses the geometry. It // The second miss shader is invoked when a shadow ray misses the geometry. It
// simply indicates that no occlusion has been found // simply indicates that no occlusion has been found
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -804,45 +796,42 @@ void HelloVulkan::createRtPipeline()
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); m_rtShaderGroups.push_back(rg);
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
// Payload 0 // Payload 0
vk::ShaderModule chitSM = vk::ShaderModule chitSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::ShaderModule ahitSM = nvvk::createShaderModule(
vk::ShaderModule ahitSM = m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true));
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rahit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1)); hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"});
hg.setAnyHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
// Payload 1 // Payload 1
vk::ShaderModule ahit1SM = vk::ShaderModule ahit1SM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace_1.rahit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace_1.rahit.spv", true, paths, true));
hg.setClosestHitShader(VK_SHADER_UNUSED_KHR); // Not used by shadow (skipped) hg.setClosestHitShader(VK_SHADER_UNUSED_KHR); // Not used by shadow (skipped)
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahit1SM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahit1SM, "main"});
hg.setAnyHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
@ -891,7 +880,7 @@ void HelloVulkan::createRtPipeline()
void HelloVulkan::createRtShaderBindingTable() void HelloVulkan::createRtShaderBindingTable()
{ {
auto groupCount = auto groupCount =
static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit static_cast<uint32_t>(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, chit, 2 ahit
uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier
uint32_t groupSizeAligned = uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);

View file

@ -129,7 +129,7 @@ public:
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; vk::Format m_offscreenDepthFormat;
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();

View file

@ -33,10 +33,10 @@
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_glfw.h" #include "imgui/backends/imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui_camera_widget.h" #include "imgui/extras/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
@ -109,15 +109,13 @@ int main(int argc, char** argv)
} }
// setup some basic things for the sample, logging file for example // setup some basic things for the sample, logging file for example
NVPSystem system(argv[0], PROJECT_NAME); NVPSystem system(PROJECT_NAME);
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, NVPSystem::exePath() + PROJECT_RELDIRECTORY,
PROJECT_ABSDIRECTORY "..", NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
NVPSystem::exePath(), std::string(PROJECT_NAME),
NVPSystem::exePath() + "..",
NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
@ -292,7 +290,7 @@ int main(int argc, char** argv)
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuf, ImGui::GetDrawData()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); cmdBuf.endRenderPass();
} }

View file

@ -0,0 +1,80 @@
#*****************************************************************************
# Copyright 2020 NVIDIA Corporation. All rights reserved.
#*****************************************************************************
cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#--------------------------------------------------------------------------------------------------
# Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
#--------------------------------------------------------------------------------------------------
# C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
_add_project_definitions(${PROJNAME})
#--------------------------------------------------------------------------------------------------
# Source files for this project
#
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories(${TUTO_KHR_DIR}/common)
#--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build
compile_glsl_directory(
SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
VULKAN_TARGET "vulkan1.2"
DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES}
)
#--------------------------------------------------------------------------------------------------
# Sources
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#--------------------------------------------------------------------------------------------------
# Sub-folders in Visual Studio
#
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES})
source_group("Shaders Src" FILES ${GLSL_SOURCES})
source_group("Shaders Hdr" FILES ${GLSL_HEADERS})
#--------------------------------------------------------------------------------------------------
# Linkage
#
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
foreach(DEBUGLIB ${LIBRARIES_DEBUG})
target_link_libraries(${PROJNAME} debug ${DEBUGLIB})
endforeach(DEBUGLIB)
foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB)
#--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.)
#
_finalize_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")

491
ray_tracing_ao/README.md Normal file
View file

@ -0,0 +1,491 @@
# G-Buffer and Ambient Occlusion - Tutorial
![](images/ray_tracing_ao.png)
## Tutorial ([Setup](../docs/setup.md))
This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR).
This extension to the tutorial is showing how G-Buffers from the fragment shader, can be used in a compute shader to cast ambient occlusion rays using
ray queries [(GLSL_EXT_ray_query)](https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GLSL_EXT_ray_query.txt).
We are using some previous extensions of the tutorial to create this one.
* The usage of `ray query` is from [ray_tracing_rayquery](../ray_tracing_rayquery)
* The notion of accumulated frames, is comming from [ray_tracing_jitter_cam](../ray_tracing_jitter_cam)
* The creation and dispatch of compute shader was inspired from [ray_tracing_animation](../ray_tracing_animation)
## Workflow
The fragment shader no longer just writes to an RGBA buffer for the colored image, but also writes to a G-buffer the position and normal for each fragment.
Then a compute shader takes the G-buffer and sends random ambient occlusion rays into the hemisphere formed by position and normal.
![](images/Hemisphere_sampling.png)
The compute shader reads and stores into the AO buffer. It reads the previous information to cumulate it over time and store the accumulated value. Finally, the post shader is slightly modified to include the AO buffer and multiply its value by the RGBA color frame before tonemapping and writing to the frame buffer.
![](images/Tuto_Ao_workflow.png)
The following are the buffers are they can be seen in [NSight Graphics](https://developer.nvidia.com/nsight-graphics).
![](images/buffers.png)
## G-Buffer
The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `vk::Format::eR32G32B32A32Sfloat` to store the position and normal and one `vk::Format::eR32Sfloat` for the ambient occlusion.
~~~~ C++
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
{
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32G32B32A32Sfloat,
vk::ImageUsageFlagBits::eColorAttachment
| vk::ImageUsageFlagBits::eSampled
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_gBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_debug.setObjectName(m_gBuffer.image, "G-Buffer");
}
// The ambient occlusion result (r32)
{
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32Sfloat,
vk::ImageUsageFlagBits::eColorAttachment
| vk::ImageUsageFlagBits::eSampled
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_aoBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_debug.setObjectName(m_aoBuffer.image, "aoBuffer");
}
~~~~
Add the `nvvk::Texture` members for `m_gBuffer` and `m_aoBuffer` to the class and to the destructor function, and don't forget to set the right image layout.
The render pass for the fragment shader will need two color buffers, therefore we need to modify the offscreen framebuffer attachments.
```
// Creating the frame buffer for offscreen
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView,
m_gBuffer.descriptor.imageView,
m_offscreenDepth.descriptor.imageView};
```
### Renderpass
This means that the renderpass in `main()` will have to be modified as well. The clear color will need to have 3 entries (2 color + 1 depth)
```
vk::ClearValue clearValues[3];
```
Since the clear value will be re-used by the offscreen (3 attachments) and the post/UI (2 attachments), we will set the clear values in each section.
```
// Offscreen render pass
{
clearValues[1].setColor(std::array<float, 4>{0, 0, 0, 0});
clearValues[2].setDepthStencil({1.0f, 0});
```
```
// 2nd rendering pass: tone mapper, UI
{
clearValues[1].setDepthStencil({1.0f, 0});
```
### Fragment shader
The fragment shader can now write into two different textures.
We are omitting the code to compress and decompress the XYZ normal to and from a single unsigned integer, but you can find the code in [raycommon.glsl](shaders/raycommon.glsl)
```
// Outgoing
layout(location = 0) out vec4 outColor;
layout(location = 1) out vec4 outGbuffer;
...
outGbuffer.rgba = vec4(worldPos, uintBitsToFloat(CompressUnitVec(N)));
```
## Ray Tracing
As for the [ray_tracing_rayquery](../ray_tracing_rayquery) sample, we use the VK_KHR_acceleration_structure extension to generate the ray tracing acceleration structure, while the ray tracing itself is carried out in a compute shader. This section remains unchanged compared to the rayquery example.
## Compute Shader
The compute shader will take the G-Buffer containing the position and normal and will randomly shot rays in the hemisphere defined by the normal.
### Descriptor
The shader takes two inputs, the G-Buffer and the TLAS, and has one output, the AO buffer:
~~~ C++
//--------------------------------------------------------------------------------------------------
// Compute shader descriptor
//
void HelloVulkan::createCompDescriptors()
{
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] G-Buffer
0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [out] AO
1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] TLAS
2, vk::DescriptorType::eAccelerationStructureKHR, 1, vk::ShaderStageFlagBits::eCompute));
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
m_compDescSet = nvvk::allocateDescriptorSet(m_device, m_compDescPool, m_compDescSetLayout);
}
~~~
### Descriptor Update
The function `updateCompDescriptors()` is done separately from the descriptor, because it can happen that some resources
are re-created, therefore their address isn't valid and we need to set those values back to the decriptors. For example,
when resizing the window and the G-Buffer and AO buffer are resized.
~~~ C++
//--------------------------------------------------------------------------------------------------
// Setting up the values to the descriptors
//
void HelloVulkan::updateCompDescriptors()
{
std::vector<vk::WriteDescriptorSet> writes;
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor));
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor));
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo{1, &tlas};
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo));
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
}
~~~~
### Pipeline
The creation of the pipeline is identical to the animation tutorial, but we will push a structure to the pushConstant
instead of a single float.
The information we will push, will allow us to play with the AO algorithm.
~~~~ C++
struct AoControl
{
float rtao_radius{2.0f}; // Length of the ray
int rtao_samples{4}; // Nb samples at each iteration
float rtao_power{2.0f}; // Darkness is stronger for more hits
int rtao_distance_based{1}; // Attenuate based on distance
int frame{0}; // Current frame
};
~~~~
### Dispatch Compute
The first thing we are doing in the `runCompute` is to call `updateFrame()` (see [jitter cam](../ray_tracing_jitter_cam)).
This sets the current frame index, which allows us to accumulate AO samples over time.
Next, we are adding a `vk::ImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader.
~~~~ C++
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer
// before the compute shader is using the buffer
vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
vk::ImageMemoryBarrier imgMemBarrier;
imgMemBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
imgMemBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
imgMemBarrier.setImage(m_gBuffer.image);
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
imgMemBarrier.setSubresourceRange(range);
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader,
vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
~~~~
Folowing is the call to dispatch the compute shader
~~~~ C++
// Preparing for the compute shader
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline);
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0,
{m_compDescSet}, {});
// Sending the push constant information
aoControl.frame = m_frame;
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0,
sizeof(AoControl), &aoControl);
// Dispatching the shader
cmdBuf.dispatch((m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE,
(m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
~~~~
Then we are adding a final barrier to make sure the compute shader is done
writing the AO so that the fragment shader (post) can use it.
~~~~ C++
// Adding a barrier to be sure the compute shader has finished
// writing to the AO buffer before the post shader is using it
imgMemBarrier.setImage(m_aoBuffer.image);
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
imgMemBarrier.setSubresourceRange(range);
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eFragmentShader,
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
~~~~
## Update Frame
The following functions were added to tell which frame we are rendering.
The function `updateFrame()` is called only once per frame, and we are doing this in runCompute()/
And the `resetFrame()` should be called whenever the image is changed, like in `onResize()` or
after modifying the GUI related to the AO.
~~~~ C++
//--------------------------------------------------------------------------------------------------
// If the camera matrix has changed, resets the frame otherwise, increments frame.
//
void HelloVulkan::updateFrame()
{
static nvmath::mat4f refCamMatrix;
static float fov = 0;
auto& m = CameraManip.getMatrix();
auto f = CameraManip.getFov();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || f != fov)
{
resetFrame();
refCamMatrix = m;
fov = f;
}
m_frame++;
}
void HelloVulkan::resetFrame()
{
m_frame = -1;
}
~~~~
## Compute Shader
The compute shader, which can be found under [ao.comp](shaders/ao.comp) is using the [ray query](https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GLSL_EXT_ray_query.txt) extension.
The first thing in `main()` is to check if the invocation is not exceeding the size of the image.
~~~~
void main()
{
float occlusion = 0.0;
ivec2 size = imageSize(inImage);
// Check if not outside boundaries
if(gl_GlobalInvocationID.x >= size.x || gl_GlobalInvocationID.y >= size.y)
return;
~~~~
The seed of the random number sequence is initialized using the TEA algorithm, while the random number themselves will be generated using PCG.
This is a fine when many random numbers are generated from this seed, but tea isn't a random
number generator and if you use only one sample per pixel, you will see correlation and the AO will not look fine because it won't
sample uniformly the entire hemisphere. This could be resolved if the seed was kept over frame, but for this example, we will use
this simple technique.
~~~~
// Initialize the random number
uint seed = tea(size.x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x, frame_number);
~~~~
Secondly, we are retrieving the position and normal stored in the fragment shader.
~~~~
// Retrieving position and normal
vec4 gBuffer = imageLoad(inImage, ivec2(gl_GlobalInvocationID.xy));
~~~~
The G-Buffer was cleared and we will sample the hemisphere only if a fragment was rendered. In `w`
we stored the compressed normal, which is nonzero only if a normal was actually stored into the pixel.
Note that while this compression introduces some level of quantization, it does not result in visible artifacts in this example.
The `OffsetRay` can be found in [raycommon.glsl](shaders/raycommon.glsl), and was taken from [Ray Tracing Gems, Ch. 6](http://www.realtimerendering.com/raytracinggems/unofficial_RayTracingGems_v1.7.pdf). This is a convenient way to avoid finding manually the appropriate minimum offset.
~~~~
// Shooting rays only if a fragment was rendered
if(gBuffer != vec4(0))
{
vec3 origin = gBuffer.xyz;
vec3 normal = decompress_unit_vec(floatBitsToUint(gBuffer.w));
vec3 direction;
// Move origin slightly away from the surface to avoid self-occlusion
origin = OffsetRay(origin, normal);
~~~~
From the normal, we generate the basis (tangent and bitangent) which will be used for sampling.
The function `compute_default_basis` is also in [raycommon.glsl](shaders/raycommon.glsl)
~~~~
// Finding the basis (tangent and bitangent) from the normal
vec3 n, tangent, bitangent;
compute_default_basis(normal, tangent, bitangent);
~~~~
Then we are sampling the hemisphere `rtao_samples` time, using a [cosine weighted sampling](https://people.cs.kuleuven.be/~philip.dutre/GI/)
~~~~
// Sampling hemiphere n-time
for(int i = 0; i < rtao_samples; i++)
{
// Cosine sampling
float r1 = rnd(seed);
float r2 = rnd(seed);
float sq = sqrt(1.0 - r2);
float phi = 2 * M_PI * r1;
vec3 direction = vec3(cos(phi) * sq, sin(phi) * sq, sqrt(r2));
direction = direction.x * tangent + direction.y * bitangent + direction.z * normal;
// Initializes a ray query object but does not start traversal
rayQueryEXT rayQuery;
occlusion += TraceRay(rayQuery, origin, direction);
}
~~~~
The function `TraceRay` is a very simple way to send a shadow ray using ray query.
For any type of shadow, we don't care which object we hit as long as the ray hit something
before maximum length. For this, we can set the flag to `gl_RayFlagsTerminateOnFirstHitEXT`.
But there is a case where we may want to know the distance of the hit from the closest hit, in this case
the flag is set to `gl_RayFlagsNoneEXT`.
The function returns 0 if it didn't hit anything or a value between 0 and 1, depending on how close the
hit was. It will return 1 if `rtao_distance_based == 0`
~~~~
//----------------------------------------------------------------------------
// Tracing a ray and returning the weight based on the distance of the hit
//
float TraceRay(in rayQueryEXT rayQuery, in vec3 origin, in vec3 direction)
{
uint flags = gl_RayFlagsNoneEXT;
if(rtao_distance_based == 0)
flags = gl_RayFlagsTerminateOnFirstHitEXT;
rayQueryInitializeEXT(rayQuery, topLevelAS, flags, 0xFF, origin, 0.0f, direction, rtao_radius);
// Start traversal: return false if traversal is complete
while(rayQueryProceedEXT(rayQuery))
{
}
// Returns type of committed (true) intersection
if(rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT)
{
// Got an intersection == Shadow
if(rtao_distance_based == 0)
return 1;
float length = 1 - (rayQueryGetIntersectionTEXT(rayQuery, true) / rtao_radius);
return length; // * length;
}
return 0;
}
~~~~
Similar to the camera jitter example, the result is stored at frame 0 and accumulate over time.
~~~~
// Writting out the AO
if(frame_number == 0)
{
imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), vec4(occlusion));
}
else
{
// Accumulating over time
float old_ao = imageLoad(outImage, ivec2(gl_GlobalInvocationID.xy)).x;
float new_result = mix(old_ao, occlusion, 1.0f / float(frame_number));
imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), vec4(new_result));
}
}
## IMGUI addition
In `main()`, we have added some controls to modify the behavior of how the AO is computed. Immediately after the call to `renderUI`,
the following code as added.
~~~~ C++
ImGui::SetNextTreeNodeOpen(true, ImGuiCond_Once);
if(ImGui::CollapsingHeader("Ambient Occlusion"))
{
bool changed{false};
changed |= ImGui::SliderFloat("Radius", &aoControl.rtao_radius, 0, 5);
changed |= ImGui::SliderInt("Rays per Pixel", &aoControl.rtao_samples, 1, 64);
changed |= ImGui::SliderFloat("Power", &aoControl.rtao_power, 1, 5);
changed |= ImGui::Checkbox("Distanced Based", (bool*)&aoControl.rtao_distance_based);
if(changed)
helloVk.resetFrame();
}
~~~~
We have also have added `AoControl aoControl;` somwhere in main() and passing the information to the execution of the compute shader.
~~~~
// Rendering Scene
{
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass();
helloVk.runCompute(cmdBuf, aoControl);
}
~~~~
## Post shader
The post shader will combine the result of the fragment (color) and the result of the compute shader (ao).
In `createPostDescriptor` we will need to add the descriptor
~~~~
m_postDescSetLayoutBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
~~~~
And the equivalent in `updatePostDescriptorSet`
~~~~
writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));
~~~~
### Post.frag
Then in the fragment shader of the post process, we need to add the layout for the AO image
~~~~
layout(set = 0, binding = 1) uniform sampler2D aoTxt;
~~~~
And the image will now be returned as the following
~~~~
vec4 color = texture(noisyTxt, uv);
float ao = texture(aoTxt, uv).x;
fragColor = pow(color * ao, vec4(gamma));
~~~~

View file

@ -0,0 +1,913 @@
/* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of NVIDIA CORPORATION nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sstream>
#include <vulkan/vulkan.hpp>
extern std::vector<std::string> defaultSearchPaths;
#define STB_IMAGE_IMPLEMENTATION
#include "fileformats/stb_image.h"
#include "obj_loader.h"
#include "hello_vulkan.h"
#include "nvh//cameramanipulator.hpp"
#include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/pipeline_vk.hpp"
#include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp"
#include "nvvk/renderpasses_vk.hpp"
#include "nvvk/shaders_vk.hpp"
// Holding the camera matrices
struct CameraMatrices
{
nvmath::mat4f view;
nvmath::mat4f proj;
nvmath::mat4f viewInverse;
// #VKRay
nvmath::mat4f projInverse;
};
//--------------------------------------------------------------------------------------------------
// Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images
//
void HelloVulkan::setup(const vk::Instance& instance,
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily)
{
AppBase::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice);
m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
}
//--------------------------------------------------------------------------------------------------
// Called at each frame to update the camera matrix
//
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
{
// Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {};
hostUBO.view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
// #VKRay
hostUBO.projInverse = nvmath::invert(hostUBO.proj);
// UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages =
vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier;
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead);
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite);
beforeBarrier.setBuffer(deviceUBO);
beforeBarrier.setOffset(0);
beforeBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns).
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO);
// Making sure the updated UBO will be visible.
vk::BufferMemoryBarrier afterBarrier;
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite);
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
afterBarrier.setBuffer(deviceUBO);
afterBarrier.setOffset(0);
afterBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
}
//--------------------------------------------------------------------------------------------------
// Describing the layout pushed when rendering
//
void HelloVulkan::createDescriptorSetLayout()
{
using vkDS = vk::DescriptorSetLayoutBinding;
using vkDT = vk::DescriptorType;
using vkSS = vk::ShaderStageFlagBits;
uint32_t nbTxt = static_cast<uint32_t>(m_textures.size());
uint32_t nbObj = static_cast<uint32_t>(m_objModel.size());
// Camera matrices (binding = 0)
m_descSetLayoutBind.addBinding(vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex));
// Materials (binding = 1)
m_descSetLayoutBind.addBinding(vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eFragment));
// Scene description (binding = 2)
m_descSetLayoutBind.addBinding(vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment));
// Textures (binding = 3)
m_descSetLayoutBind.addBinding(vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment));
// Materials (binding = 4)
m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment));
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
m_descPool = m_descSetLayoutBind.createPool(m_device, 1);
m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout);
}
//--------------------------------------------------------------------------------------------------
// Setting up the buffers in the descriptor set
//
void HelloVulkan::updateDescriptorSet()
{
std::vector<vk::WriteDescriptorSet> writes;
// Camera matrices and scene description
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
// All material buffers, 1 buffer per OBJ
std::vector<vk::DescriptorBufferInfo> dbiMat;
std::vector<vk::DescriptorBufferInfo> dbiMatIdx;
std::vector<vk::DescriptorBufferInfo> dbiVert;
std::vector<vk::DescriptorBufferInfo> dbiIdx;
for(auto& obj : m_objModel)
{
dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE);
dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE);
dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE);
dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE);
}
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
// All texture samplers
std::vector<vk::DescriptorImageInfo> diit;
for(auto& texture : m_textures)
{
diit.emplace_back(texture.descriptor);
}
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
// Writing the information
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
}
//--------------------------------------------------------------------------------------------------
// Creating the pipeline layout
//
void HelloVulkan::createGraphicsPipeline()
{
using vkSS = vk::ShaderStageFlagBits;
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
sizeof(ObjPushConstant)};
// Creating the Pipeline Layout
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
vk::DescriptorSetLayout descSetLayout(m_descSetLayout);
pipelineLayoutCreateInfo.setSetLayoutCount(1);
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout);
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Creating the Pipeline
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)},
{1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)},
{2, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, color)},
{3, 0, vk::Format::eR32G32Sfloat, offsetof(VertexObj, texCoord)}});
vk::PipelineColorBlendAttachmentState res;
res.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG
| vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
gpb.addBlendAttachmentState(res);
m_graphicsPipeline = gpb.createPipeline();
m_debug.setObjectName(m_graphicsPipeline, "Graphics");
}
//--------------------------------------------------------------------------------------------------
// Loading the OBJ file and setting up all buffers
//
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
{
using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader;
loader.loadModel(filename);
// Converting from Srgb to linear
for(auto& m : loader.m_materials)
{
m.ambient = nvmath::pow(m.ambient, 2.2f);
m.diffuse = nvmath::pow(m.diffuse, 2.2f);
m.specular = nvmath::pow(m.specular, 2.2f);
}
ObjInstance instance;
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.transform = transform;
instance.transformIT = nvmath::transpose(nvmath::invert(transform));
instance.txtOffset = static_cast<uint32_t>(m_textures.size());
ObjModel model;
model.nbIndices = static_cast<uint32_t>(loader.m_indices.size());
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
// Create the buffers on Device and copy vertices, indices and materials
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found
createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging();
std::string objNb = std::to_string(instance.objIndex);
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb).c_str()));
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb).c_str()));
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb).c_str()));
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb).c_str()));
m_objModel.emplace_back(model);
m_objInstance.emplace_back(instance);
}
//--------------------------------------------------------------------------------------------------
// Creating the uniform buffer holding the camera matrices
// - Buffer is host visible
//
void HelloVulkan::createUniformBuffer()
{
using vkBU = vk::BufferUsageFlagBits;
using vkMP = vk::MemoryPropertyFlagBits;
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
}
//--------------------------------------------------------------------------------------------------
// Create a storage buffer containing the description of the scene elements
// - Which geometry is used by which instance
// - Transformation
// - Offset for texture
//
void HelloVulkan::createSceneDescriptionBuffer()
{
using vkBU = vk::BufferUsageFlagBits;
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer);
cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
}
//--------------------------------------------------------------------------------------------------
// Creating all textures and samplers
//
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
const std::vector<std::string>& textures)
{
using vkIU = vk::ImageUsageFlagBits;
vk::SamplerCreateInfo samplerCreateInfo{
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
samplerCreateInfo.setMaxLod(FLT_MAX);
vk::Format format = vk::Format::eR8G8B8A8Srgb;
// If no textures are present, create a dummy one to accommodate the pipeline layout
if(textures.empty() && m_textures.empty())
{
nvvk::Texture texture;
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
vk::DeviceSize bufferSize = sizeof(color);
auto imgSize = vk::Extent2D(1, 1);
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the VKImage
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined,
vk::ImageLayout::eShaderReadOnlyOptimal);
m_textures.push_back(texture);
}
else
{
// Uploading all images
for(const auto& texture : textures)
{
std::stringstream o;
int texWidth, texHeight, texChannels;
o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels =
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
stbi_uc* pixels = stbi_pixels;
// Handle failure
if(!stbi_pixels)
{
texWidth = texHeight = 1;
texChannels = 4;
pixels = reinterpret_cast<stbi_uc*>(color.data());
}
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
auto imgSize = vk::Extent2D(texWidth, texHeight);
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true);
{
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
vk::ImageViewCreateInfo ivInfo =
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
m_textures.push_back(texture);
}
stbi_image_free(stbi_pixels);
}
}
}
//--------------------------------------------------------------------------------------------------
// Destroying all allocations
//
void HelloVulkan::destroyResources()
{
m_device.destroy(m_graphicsPipeline);
m_device.destroy(m_pipelineLayout);
m_device.destroy(m_descPool);
m_device.destroy(m_descSetLayout);
m_alloc.destroy(m_cameraMat);
m_alloc.destroy(m_sceneDesc);
for(auto& m : m_objModel)
{
m_alloc.destroy(m.vertexBuffer);
m_alloc.destroy(m.indexBuffer);
m_alloc.destroy(m.matColorBuffer);
m_alloc.destroy(m.matIndexBuffer);
}
for(auto& t : m_textures)
{
m_alloc.destroy(t);
}
//#Post
m_device.destroy(m_postPipeline);
m_device.destroy(m_postPipelineLayout);
m_device.destroy(m_postDescPool);
m_device.destroy(m_postDescSetLayout);
m_alloc.destroy(m_offscreenColor);
m_alloc.destroy(m_gBuffer);
m_alloc.destroy(m_aoBuffer);
m_alloc.destroy(m_offscreenDepth);
m_device.destroy(m_offscreenRenderPass);
m_device.destroy(m_offscreenFramebuffer);
// Compute
m_device.destroy(m_compDescPool);
m_device.destroy(m_compDescSetLayout);
m_device.destroy(m_compPipeline);
m_device.destroy(m_compPipelineLayout);
// #VKRay
m_rtBuilder.destroy();
}
//--------------------------------------------------------------------------------------------------
// Drawing the scene in raster mode
//
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf)
{
using vkPBP = vk::PipelineBindPoint;
using vkSS = vk::ShaderStageFlagBits;
vk::DeviceSize offset{0};
m_debug.beginLabel(cmdBuf, "Rasterize");
// Dynamic Viewport
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
// Drawing all triangles
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline);
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {});
for(int i = 0; i < m_objInstance.size(); ++i)
{
auto& inst = m_objInstance[i];
auto& model = m_objModel[inst.objIndex];
m_pushConstant.instanceId = i; // Telling which instance is drawn
cmdBuf.pushConstants<ObjPushConstant>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
m_pushConstant);
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset});
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32);
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0);
}
m_debug.endLabel(cmdBuf);
}
//--------------------------------------------------------------------------------------------------
// Handling resize of the window
//
void HelloVulkan::onResize(int /*w*/, int /*h*/)
{
createOffscreenRender();
updatePostDescriptorSet();
updateCompDescriptors();
resetFrame();
}
//////////////////////////////////////////////////////////////////////////
// Post-processing
//////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// Creating an offscreen frame buffer and the associated render pass
//
void HelloVulkan::createOffscreenRender()
{
m_alloc.destroy(m_offscreenColor);
m_alloc.destroy(m_gBuffer);
m_alloc.destroy(m_aoBuffer);
m_alloc.destroy(m_offscreenDepth);
// Creating the color image
{
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
vk::ImageUsageFlagBits::eColorAttachment
| vk::ImageUsageFlagBits::eSampled
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_debug.setObjectName(m_offscreenColor.image, "offscreen");
}
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
{
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32G32B32A32Sfloat,
vk::ImageUsageFlagBits::eColorAttachment
| vk::ImageUsageFlagBits::eSampled
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_gBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_debug.setObjectName(m_gBuffer.image, "G-Buffer");
}
// The ambient occlusion result (r32)
{
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32Sfloat,
vk::ImageUsageFlagBits::eColorAttachment
| vk::ImageUsageFlagBits::eSampled
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_aoBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_debug.setObjectName(m_aoBuffer.image, "aoBuffer");
}
// Creating the depth buffer
auto depthCreateInfo =
nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat,
vk::ImageUsageFlagBits::eDepthStencilAttachment);
{
nvvk::Image image = m_alloc.createImage(depthCreateInfo);
vk::ImageViewCreateInfo depthStencilView;
depthStencilView.setViewType(vk::ImageViewType::e2D);
depthStencilView.setFormat(m_offscreenDepthFormat);
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1});
depthStencilView.setImage(image.image);
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
}
// Setting the image layout for both color and depth
{
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
auto cmdBuf = genCmdBuf.createCommandBuffer();
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined,
vk::ImageLayout::eGeneral);
nvvk::cmdBarrierImageLayout(cmdBuf, m_gBuffer.image, vk::ImageLayout::eUndefined,
vk::ImageLayout::eGeneral);
nvvk::cmdBarrierImageLayout(cmdBuf, m_aoBuffer.image, vk::ImageLayout::eUndefined,
vk::ImageLayout::eGeneral);
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined,
vk::ImageLayout::eDepthStencilAttachmentOptimal,
vk::ImageAspectFlagBits::eDepth);
genCmdBuf.submitAndWait(cmdBuf);
}
// Creating a renderpass for the offscreen
if(!m_offscreenRenderPass)
{
m_offscreenRenderPass =
nvvk::createRenderPass(m_device,
{m_offscreenColorFormat, m_offscreenColorFormat}, // RGBA + G-Buffer
m_offscreenDepthFormat, 1, true, true, vk::ImageLayout::eGeneral,
vk::ImageLayout::eGeneral);
}
// Creating the frame buffer for offscreen
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView,
m_gBuffer.descriptor.imageView,
m_offscreenDepth.descriptor.imageView};
m_device.destroy(m_offscreenFramebuffer);
vk::FramebufferCreateInfo info;
info.setRenderPass(m_offscreenRenderPass);
info.setAttachmentCount(static_cast<int>(attachments.size()));
info.setPAttachments(attachments.data());
info.setWidth(m_size.width);
info.setHeight(m_size.height);
info.setLayers(1);
m_offscreenFramebuffer = m_device.createFramebuffer(info);
}
//--------------------------------------------------------------------------------------------------
// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more
//
void HelloVulkan::createPostPipeline()
{
// Push constants in the fragment shader
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)};
// Creating the pipeline layout
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
pipelineLayoutCreateInfo.setSetLayoutCount(1);
pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout);
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
m_renderPass);
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline();
m_debug.setObjectName(m_postPipeline, "post");
}
//--------------------------------------------------------------------------------------------------
// The descriptor layout is the description of the data that is passed to the vertex or the
// fragment program.
//
void HelloVulkan::createPostDescriptor()
{
using vkDS = vk::DescriptorSetLayoutBinding;
using vkDT = vk::DescriptorType;
using vkSS = vk::ShaderStageFlagBits;
m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
m_postDescSetLayoutBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
}
//--------------------------------------------------------------------------------------------------
// Update the output
//
void HelloVulkan::updatePostDescriptorSet()
{
std::vector<vk::WriteDescriptorSet> writes;
writes.push_back(
m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor));
writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
}
//--------------------------------------------------------------------------------------------------
// Draw a full screen quad with the attached image
//
void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
{
m_debug.beginLabel(cmdBuf, "Post");
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
cmdBuf.pushConstants<float>(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0,
aspectRatio);
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline);
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0,
m_postDescSet, {});
cmdBuf.draw(3, 1, 0, 0);
m_debug.endLabel(cmdBuf);
}
//////////////////////////////////////////////////////////////////////////
// Raytracing, creation of BLAS and TLAS
//////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// Initialize Vulkan ray tracing
// #VKRay
void HelloVulkan::initRayTracing()
{
// Requesting ray tracing properties
auto properties =
m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
}
//--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS
//
nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{
// Building part
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress);
triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
// Setting up the build info of the acceleration
vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
asGeom.geometry.setTriangles(triangles);
// The primitive itself
vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0);
offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
offset.setPrimitiveOffset(0);
offset.setTransformOffset(0);
// Our blas is only one geometry, but could be made of many geometries
nvvk::RaytracingBuilderKHR::BlasInput input;
input.asGeometry.emplace_back(asGeom);
input.asBuildOffsetInfo.emplace_back(offset);
return input;
}
//--------------------------------------------------------------------------------------------------
//
//
void HelloVulkan::createBottomLevelAS()
{
// BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(m_objModel.size());
for(const auto& obj : m_objModel)
{
auto blas = objectToVkGeometryKHR(obj);
// We could add more geometry in each BLAS, but we add only one for now
allBlas.emplace_back(blas);
}
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
}
void HelloVulkan::createTopLevelAS()
{
std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas;
tlas.reserve(m_objInstance.size());
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{
nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance
rayInst.instanceCustomId = i; // gl_InstanceCustomIndexEXT
rayInst.blasId = m_objInstance[i].objIndex;
rayInst.hitGroupId = 0; // We will use the same hit group for all objects
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
tlas.emplace_back(rayInst);
}
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
}
//////////////////////////////////////////////////////////////////////////
// Compute shader from ANIMATION tutorial
//////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// Compute shader descriptor
//
void HelloVulkan::createCompDescriptors()
{
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] G-Buffer
0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [out] AO
1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] TLAS
2, vk::DescriptorType::eAccelerationStructureKHR, 1, vk::ShaderStageFlagBits::eCompute));
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
m_compDescSet = nvvk::allocateDescriptorSet(m_device, m_compDescPool, m_compDescSetLayout);
}
//--------------------------------------------------------------------------------------------------
// Setting up the values to the descriptors
//
void HelloVulkan::updateCompDescriptors()
{
std::vector<vk::WriteDescriptorSet> writes;
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor));
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor));
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo{1, &tlas};
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo));
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
}
//--------------------------------------------------------------------------------------------------
// Creating the pipeline: shader ...
//
void HelloVulkan::createCompPipelines()
{
// pushing time
vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eCompute, 0, sizeof(AoControl)};
vk::PipelineLayoutCreateInfo layout_info{{}, 1, &m_compDescSetLayout, 1, &push_constants};
m_compPipelineLayout = m_device.createPipelineLayout(layout_info);
vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout};
computePipelineCreateInfo.stage =
nvvk::createShaderStageInfo(m_device,
nvh::loadFile("spv/ao.comp.spv", true, defaultSearchPaths, true),
VK_SHADER_STAGE_COMPUTE_BIT);
m_compPipeline = static_cast<const vk::Pipeline&>(
m_device.createComputePipeline({}, computePipelineCreateInfo));
m_device.destroy(computePipelineCreateInfo.stage.module);
}
//--------------------------------------------------------------------------------------------------
// Running compute shader
//
#define GROUP_SIZE 16 // Same group size as in compute shader
void HelloVulkan::runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl)
{
updateFrame();
// Stop by default after 100'000 samples
if(m_frame * aoControl.rtao_samples > aoControl.max_samples)
return;
m_debug.beginLabel(cmdBuf, "Compute");
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer
// before the compute shader is using the buffer
vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
vk::ImageMemoryBarrier imgMemBarrier;
imgMemBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
imgMemBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
imgMemBarrier.setImage(m_gBuffer.image);
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
imgMemBarrier.setSubresourceRange(range);
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader,
vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
// Preparing for the compute shader
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline);
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0,
{m_compDescSet}, {});
// Sending the push constant information
aoControl.frame = m_frame;
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0,
sizeof(AoControl), &aoControl);
// Dispatching the shader
cmdBuf.dispatch((m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE,
(m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
// Adding a barrier to be sure the compute shader has finished
// writing to the AO buffer before the post shader is using it
imgMemBarrier.setImage(m_aoBuffer.image);
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
imgMemBarrier.setSubresourceRange(range);
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eFragmentShader,
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
m_debug.endLabel(cmdBuf);
}
//////////////////////////////////////////////////////////////////////////
// Reset from JITTER CAM tutorial
//////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// If the camera matrix has changed, resets the frame otherwise, increments frame.
//
void HelloVulkan::updateFrame()
{
static nvmath::mat4f refCamMatrix;
static float fov = 0;
auto& m = CameraManip.getMatrix();
auto f = CameraManip.getFov();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || f != fov)
{
resetFrame();
refCamMatrix = m;
fov = f;
}
m_frame++;
}
void HelloVulkan::resetFrame()
{
m_frame = -1;
}

View file

@ -0,0 +1,174 @@
/* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of NVIDIA CORPORATION nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define NVVK_ALLOC_DEDICATED
#include "nvvk/allocator_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp"
// #VKRay
#include "nvvk/raytraceKHR_vk.hpp"
struct AoControl
{
float rtao_radius{2.0f}; // Length of the ray
int rtao_samples{4}; // Nb samples at each iteration
float rtao_power{3.0f}; // Darkness is stronger for more hits
int rtao_distance_based{1}; // Attenuate based on distance
int frame{0}; // Current frame
int max_samples{100'000}; // Max samples before it stops
};
//--------------------------------------------------------------------------------------------------
// Simple rasterizer of OBJ objects
// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance`
// - It is possible to have many `ObjInstance` referencing the same `ObjModel`
// - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad
//
class HelloVulkan : public nvvk::AppBase
{
public:
void setup(const vk::Instance& instance,
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout();
void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet();
void createUniformBuffer();
void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf,
const std::vector<std::string>& textures);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override;
void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff);
// The OBJ model
struct ObjModel
{
uint32_t nbIndices{0};
uint32_t nbVertices{0};
nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex'
nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles
nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material'
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
};
// Instance of the OBJ
struct ObjInstance
{
uint32_t objIndex{0}; // Reference to the `m_objModel`
uint32_t txtOffset{0}; // Offset in `m_textures`
nvmath::mat4f transform{1}; // Position of the instance
nvmath::mat4f transformIT{1}; // Inverse transpose
};
// Information pushed at each draw call
struct ObjPushConstant
{
nvmath::vec3f lightPosition{3.5f, 8.f, 5.f};
int instanceId{0}; // To retrieve the transformation matrix
float lightIntensity{100.f};
int lightType{0}; // 0: point, 1: infinite
};
ObjPushConstant m_pushConstant;
// Array of objects and instances in the scene
std::vector<ObjModel> m_objModel;
std::vector<ObjInstance> m_objInstance;
// Graphic pipeline
vk::PipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::AllocatorDedicated m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects
// #Post
void createOffscreenRender();
void createPostPipeline();
void createPostDescriptor();
void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool;
vk::DescriptorSetLayout m_postDescSetLayout;
vk::DescriptorSet m_postDescSet;
vk::Pipeline m_postPipeline;
vk::PipelineLayout m_postPipelineLayout;
vk::RenderPass m_offscreenRenderPass;
vk::Framebuffer m_offscreenFramebuffer;
nvvk::Texture m_offscreenColor;
nvvk::Texture m_gBuffer;
nvvk::Texture m_aoBuffer;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat;
// #Tuto_rayquery
void initRayTracing();
nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
void createBottomLevelAS();
void createTopLevelAS();
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder;
// #Tuto_animation
void createCompDescriptors();
void updateCompDescriptors();
void createCompPipelines();
void runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl);
nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
vk::DescriptorPool m_compDescPool;
vk::DescriptorSetLayout m_compDescSetLayout;
vk::DescriptorSet m_compDescSet;
vk::Pipeline m_compPipeline;
vk::PipelineLayout m_compPipelineLayout;
// #Tuto_jitter_cam
void updateFrame();
void resetFrame();
int m_frame{0};
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

342
ray_tracing_ao/main.cpp Normal file
View file

@ -0,0 +1,342 @@
/* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of NVIDIA CORPORATION nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// ImGui - standalone example application for Glfw + Vulkan, using programmable
// pipeline If you are new to ImGui, see examples/README.txt and documentation
// at the top of imgui.cpp.
#include <array>
#include <iostream>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui.h"
#include "imgui/backends/imgui_impl_glfw.h"
#include "hello_vulkan.h"
#include "imgui/extras/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp"
//////////////////////////////////////////////////////////////////////////
#define UNUSED(x) (void)(x)
//////////////////////////////////////////////////////////////////////////
// Default search path for shaders
std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions
static void onErrorCallback(int error, const char* description)
{
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
}
// Extra UI
void renderUI(HelloVulkan& helloVk)
{
ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light"))
{
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1);
ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f);
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720;
//--------------------------------------------------------------------------------------------------
// Application Entry
//
int main(int argc, char** argv)
{
UNUSED(argc);
// Setup GLFW window
glfwSetErrorCallback(onErrorCallback);
if(!glfwInit())
{
return 1;
}
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window =
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
CameraManip.setLookat(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0));
// Setup Vulkan
if(!glfwVulkanSupported())
{
printf("GLFW: Vulkan Not Supported\n");
return 1;
}
// setup some basic things for the sample, logging file for example
NVPSystem system(PROJECT_NAME);
// Search path for shaders and other media
defaultSearchPaths = {
NVPSystem::exePath() + PROJECT_RELDIRECTORY,
NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
std::string(PROJECT_NAME),
};
// Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
#endif
contextInfo.addInstanceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeatures);
vk::PhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures;
contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures);
// Creating Vulkan base application
nvvk::Context vkctx{};
vkctx.initInstance(contextInfo);
// Find all compatible devices
auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo);
assert(!compatibleDevices.empty());
// Use a compatible device
vkctx.initDevice(compatibleDevices[0], contextInfo);
// Create example
HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer();
helloVk.createRenderPass();
helloVk.createFrameBuffers();
// Setup Imgui
helloVk.initGUI(0); // Using sub-pass 0
// Creation of the example
nvmath::mat4f t = nvmath::translation_mat4(nvmath::vec3f{0, 0.0, 0});
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true), t);
//helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
helloVk.createOffscreenRender();
helloVk.createDescriptorSetLayout();
helloVk.createGraphicsPipeline();
helloVk.createUniformBuffer();
helloVk.createSceneDescriptionBuffer();
// #VKRay
helloVk.initRayTracing();
helloVk.createBottomLevelAS();
helloVk.createTopLevelAS();
// Need the Top level AS
helloVk.updateDescriptorSet();
helloVk.createPostDescriptor();
helloVk.createPostPipeline();
helloVk.updatePostDescriptorSet();
helloVk.createCompDescriptors();
helloVk.updateCompDescriptors();
helloVk.createCompPipelines();
nvmath::vec4f clearColor = nvmath::vec4f(0, 0, 0, 0);
helloVk.setupGlfwCallbacks(window);
ImGui_ImplGlfw_InitForVulkan(window, true);
AoControl aoControl;
// Main loop
while(!glfwWindowShouldClose(window))
{
try
{
glfwPollEvents();
if(helloVk.isMinimized())
continue;
// Start the Dear ImGui frame
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Show UI window.
if(helloVk.showGui())
{
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
renderUI(helloVk);
ImGui::SetNextTreeNodeOpen(true, ImGuiCond_Once);
if(ImGui::CollapsingHeader("Ambient Occlusion"))
{
bool changed{false};
changed |= ImGui::SliderFloat("Radius", &aoControl.rtao_radius, 0, 5);
changed |= ImGui::SliderInt("Rays per Pixel", &aoControl.rtao_samples, 1, 64);
changed |= ImGui::SliderFloat("Power", &aoControl.rtao_power, 1, 5);
changed |= ImGui::InputInt("Max Samples", &aoControl.max_samples);
changed |= ImGui::Checkbox("Distanced Based", (bool*)&aoControl.rtao_distance_based);
if(changed)
helloVk.resetFrame();
}
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
}
// Start rendering the scene
helloVk.prepareFrame();
// Start command buffer of this frame
auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
// Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen
vk::ClearValue clearValues[3];
clearValues[0].setColor(
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
// Offscreen render pass
{
clearValues[1].setColor(std::array<float, 4>{0, 0, 0, 0});
clearValues[2].setDepthStencil({1.0f, 0});
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
offscreenRenderPassBeginInfo.setClearValueCount(3);
offscreenRenderPassBeginInfo.setPClearValues(clearValues);
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
// Rendering Scene
{
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass();
helloVk.runCompute(cmdBuf, aoControl);
}
}
// 2nd rendering pass: tone mapper, UI
{
clearValues[1].setDepthStencil({1.0f, 0});
vk::RenderPassBeginInfo postRenderPassBeginInfo;
postRenderPassBeginInfo.setClearValueCount(2);
postRenderPassBeginInfo.setPClearValues(clearValues);
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper
helloVk.drawPost(cmdBuf);
// Rendering UI
ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass();
}
// Submit for display
cmdBuf.end();
helloVk.submitFrame();
}
catch(const std::system_error& e)
{
if(e.code() == vk::Result::eErrorDeviceLost)
{
#if _WIN32
MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1);
#endif
}
std::cout << e.what() << std::endl;
return e.code().value();
}
}
// Cleanup
helloVk.getDevice().waitIdle();
helloVk.destroyResources();
helloVk.destroy();
vkctx.deinit();
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}

View file

@ -0,0 +1,123 @@
#version 460
#extension GL_ARB_separate_shader_objects : enable
#extension GL_EXT_nonuniform_qualifier : enable
#extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_scalar_block_layout : enable
#extension GL_EXT_ray_tracing : enable
#extension GL_EXT_ray_query : enable
#include "raycommon.glsl"
const int GROUP_SIZE = 16;
layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE) in;
layout(set = 0, binding = 0, rgba32f) uniform image2D inImage;
layout(set = 0, binding = 1, r32f) uniform image2D outImage;
layout(set = 0, binding = 2) uniform accelerationStructureEXT topLevelAS;
// See AoControl
layout(push_constant) uniform params_
{
float rtao_radius;
int rtao_samples;
float rtao_power;
int rtao_distance_based;
int frame_number;
int max_samples;
};
//----------------------------------------------------------------------------
// Tracing a ray and returning the weight based on the distance of the hit
//
float TraceRay(in rayQueryEXT rayQuery, in vec3 origin, in vec3 direction)
{
uint flags = gl_RayFlagsNoneEXT;
if(rtao_distance_based == 0)
flags = gl_RayFlagsTerminateOnFirstHitEXT;
rayQueryInitializeEXT(rayQuery, topLevelAS, flags, 0xFF, origin, 0.0f, direction, rtao_radius);
// Start traversal: return false if traversal is complete
while(rayQueryProceedEXT(rayQuery))
{
}
// Returns type of committed (true) intersection
if(rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT)
{
// Got an intersection == Shadow
if(rtao_distance_based == 0)
return 1;
float length = 1 - (rayQueryGetIntersectionTEXT(rayQuery, true) / rtao_radius);
return length; // * length;
}
return 0;
}
void main()
{
float occlusion = 0.0;
ivec2 size = imageSize(inImage);
// Check if not outside boundaries
if(gl_GlobalInvocationID.x >= size.x || gl_GlobalInvocationID.y >= size.y)
return;
// Initialize the random number
uint seed = tea(size.x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x, frame_number);
// Retrieving position and normal
vec4 gBuffer = imageLoad(inImage, ivec2(gl_GlobalInvocationID.xy));
// Shooting rays only if a fragment was rendered
if(gBuffer != vec4(0))
{
vec3 origin = gBuffer.xyz;
vec3 normal = DecompressUnitVec(floatBitsToUint(gBuffer.w));
vec3 direction;
// Move origin slightly away from the surface to avoid self-occlusion
origin = OffsetRay(origin, normal);
// Finding the basis (tangent and bitangent) from the normal
vec3 n, tangent, bitangent;
ComputeDefaultBasis(normal, tangent, bitangent);
// Sampling hemiphere n-time
for(int i = 0; i < rtao_samples; i++)
{
// Cosine sampling
float r1 = rnd(seed);
float r2 = rnd(seed);
float sq = sqrt(1.0 - r2);
float phi = 2 * M_PI * r1;
vec3 direction = vec3(cos(phi) * sq, sin(phi) * sq, sqrt(r2));
direction = direction.x * tangent + direction.y * bitangent + direction.z * normal;
// Initializes a ray query object but does not start traversal
rayQueryEXT rayQuery;
occlusion += TraceRay(rayQuery, origin, direction);
}
// Computing occlusion
occlusion = 1 - (occlusion / rtao_samples);
occlusion = pow(clamp(occlusion, 0, 1), rtao_power);
}
// Writting out the AO
if(frame_number == 0)
{
imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), vec4(occlusion));
}
else
{
// Accumulating over time
float old_ao = imageLoad(outImage, ivec2(gl_GlobalInvocationID.xy)).x;
float new_result = mix(old_ao, occlusion, 1.0f / float(frame_number + 1));
imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), vec4(new_result));
}
}

View file

@ -0,0 +1,90 @@
#version 460
#extension GL_ARB_separate_shader_objects : enable
#extension GL_EXT_nonuniform_qualifier : enable
#extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_scalar_block_layout : enable
#extension GL_EXT_ray_tracing : enable
#extension GL_EXT_ray_query : enable
#include "raycommon.glsl"
#include "wavefront.glsl"
layout(push_constant) uniform shaderInformation
{
vec3 lightPosition;
uint instanceId;
float lightIntensity;
int lightType;
}
pushC;
// clang-format off
// Incoming
//layout(location = 0) flat in int matIndex;
layout(location = 1) in vec2 fragTexCoord;
layout(location = 2) in vec3 fragNormal;
layout(location = 3) in vec3 viewDir;
layout(location = 4) in vec3 worldPos;
// Outgoing
layout(location = 0) out vec4 outColor;
layout(location = 1) out vec4 outGbuffer;
// Buffers
layout(binding = 1, scalar) buffer MatColorBufferObject { WaveFrontMaterial m[]; } materials[];
layout(binding = 2, scalar) buffer ScnDesc { sceneDesc i[]; } scnDesc;
layout(binding = 3) uniform sampler2D[] textureSamplers;
layout(binding = 4, scalar) buffer MatIndex { int i[]; } matIdx[];
//layout(binding = 7, set = 0) uniform accelerationStructureEXT topLevelAS;
// clang-format on
void main()
{
// Object of this instance
int objId = scnDesc.i[pushC.instanceId].objId;
// Material of the object
int matIndex = matIdx[nonuniformEXT(objId)].i[gl_PrimitiveID];
WaveFrontMaterial mat = materials[nonuniformEXT(objId)].m[matIndex];
vec3 N = normalize(fragNormal);
// Vector toward light
vec3 L;
float lightDistance;
float lightIntensity = pushC.lightIntensity;
if(pushC.lightType == 0)
{
vec3 lDir = pushC.lightPosition - worldPos;
float d = length(lDir);
lightIntensity = pushC.lightIntensity / (d * d);
L = normalize(lDir);
lightDistance = d;
}
else
{
L = normalize(pushC.lightPosition - vec3(0));
lightDistance = 10000;
}
// Diffuse
vec3 diffuse = computeDiffuse(mat, L, N);
diffuse = vec3(1);
// if(mat.textureId >= 0)
// {
// int txtOffset = scnDesc.i[pushC.instanceId].txtOffset;
// uint txtId = txtOffset + mat.textureId;
// vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz;
// diffuse *= diffuseTxt;
// }
//lightIntensity = 1;
// Specular
vec3 specular = vec3(0); //computeSpecular(mat, viewDir, L, N);
lightIntensity = 1;
// Result
outColor = vec4(lightIntensity * (diffuse + specular), 1);
outGbuffer.rgba = vec4(worldPos, uintBitsToFloat(CompressUnitVec(N)));
}

View file

@ -0,0 +1,15 @@
#version 450
layout (location = 0) out vec2 outUV;
out gl_PerVertex
{
vec4 gl_Position;
};
void main()
{
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f);
}

View file

@ -0,0 +1,23 @@
#version 450
layout(location = 0) in vec2 outUV;
layout(location = 0) out vec4 fragColor;
layout(set = 0, binding = 0) uniform sampler2D noisyTxt;
layout(set = 0, binding = 1) uniform sampler2D aoTxt;
layout(push_constant) uniform shaderInformation
{
float aspectRatio;
}
pushc;
void main()
{
vec2 uv = outUV;
float gamma = 1. / 2.2;
vec4 color = texture(noisyTxt, uv);
float ao = texture(aoTxt, uv).x;
fragColor = pow(color * ao, vec4(gamma));
}

View file

@ -0,0 +1,190 @@
/* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of NVIDIA CORPORATION nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//-
// This utility compresses a normal(x,y,z) to a uint and decompresses it
#define C_Stack_Max 3.402823466e+38f
uint CompressUnitVec(vec3 nv)
{
// map to octahedron and then flatten to 2D (see 'Octahedron Environment Maps' by Engelhardt & Dachsbacher)
if((nv.x < C_Stack_Max) && !isinf(nv.x))
{
const float d = 32767.0f / (abs(nv.x) + abs(nv.y) + abs(nv.z));
int x = int(roundEven(nv.x * d));
int y = int(roundEven(nv.y * d));
if(nv.z < 0.0f)
{
const int maskx = x >> 31;
const int masky = y >> 31;
const int tmp = 32767 + maskx + masky;
const int tmpx = x;
x = (tmp - (y ^ masky)) ^ maskx;
y = (tmp - (tmpx ^ maskx)) ^ masky;
}
uint packed = (uint(y + 32767) << 16) | uint(x + 32767);
if(packed == ~0u)
return ~0x1u;
return packed;
}
else
{
return ~0u;
}
}
float ShortToFloatM11(const int v) // linearly maps a short 32767-32768 to a float -1-+1 //!! opt.?
{
return (v >= 0) ? (uintBitsToFloat(0x3F800000u | (uint(v) << 8)) - 1.0f) :
(uintBitsToFloat((0x80000000u | 0x3F800000u) | (uint(-v) << 8)) + 1.0f);
}
vec3 DecompressUnitVec(uint packed)
{
if(packed != ~0u) // sanity check, not needed as isvalid_unit_vec is called earlier
{
int x = int(packed & 0xFFFFu) - 32767;
int y = int(packed >> 16) - 32767;
const int maskx = x >> 31;
const int masky = y >> 31;
const int tmp0 = 32767 + maskx + masky;
const int ymask = y ^ masky;
const int tmp1 = tmp0 - (x ^ maskx);
const int z = tmp1 - ymask;
float zf;
if(z < 0)
{
x = (tmp0 - ymask) ^ maskx;
y = tmp1 ^ masky;
zf = uintBitsToFloat((0x80000000u | 0x3F800000u) | (uint(-z) << 8)) + 1.0f;
}
else
{
zf = uintBitsToFloat(0x3F800000u | (uint(z) << 8)) - 1.0f;
}
return normalize(vec3(ShortToFloatM11(x), ShortToFloatM11(y), zf));
}
else
{
return vec3(C_Stack_Max);
}
}
//-------------------------------------------------------------------------------------------------
// Avoiding self intersections (see Ray Tracing Gems, Ch. 6)
//
vec3 OffsetRay(in vec3 p, in vec3 n)
{
const float intScale = 256.0f;
const float floatScale = 1.0f / 65536.0f;
const float origin = 1.0f / 32.0f;
ivec3 of_i = ivec3(intScale * n.x, intScale * n.y, intScale * n.z);
vec3 p_i = vec3(intBitsToFloat(floatBitsToInt(p.x) + ((p.x < 0) ? -of_i.x : of_i.x)),
intBitsToFloat(floatBitsToInt(p.y) + ((p.y < 0) ? -of_i.y : of_i.y)),
intBitsToFloat(floatBitsToInt(p.z) + ((p.z < 0) ? -of_i.z : of_i.z)));
return vec3(abs(p.x) < origin ? p.x + floatScale * n.x : p_i.x, //
abs(p.y) < origin ? p.y + floatScale * n.y : p_i.y, //
abs(p.z) < origin ? p.z + floatScale * n.z : p_i.z);
}
//////////////////////////// AO //////////////////////////////////////
#define EPS 0.05
const float M_PI = 3.141592653589;
void ComputeDefaultBasis(const vec3 normal, out vec3 x, out vec3 y)
{
// ZAP's default coordinate system for compatibility
vec3 z = normal;
const float yz = -z.y * z.z;
y = normalize(((abs(z.z) > 0.99999f) ? vec3(-z.x * z.y, 1.0f - z.y * z.y, yz) :
vec3(-z.x * z.z, yz, 1.0f - z.z * z.z)));
x = cross(y, z);
}
//-------------------------------------------------------------------------------------------------
// Random
//-------------------------------------------------------------------------------------------------
// Generate a random unsigned int from two unsigned int values, using 16 pairs
// of rounds of the Tiny Encryption Algorithm. See Zafar, Olano, and Curtis,
// "GPU Random Numbers via the Tiny Encryption Algorithm"
uint tea(uint val0, uint val1)
{
uint v0 = val0;
uint v1 = val1;
uint s0 = 0;
for(uint n = 0; n < 16; n++)
{
s0 += 0x9e3779b9;
v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4);
v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e);
}
return v0;
}
uvec2 pcg2d(uvec2 v)
{
v = v * 1664525u + 1013904223u;
v.x += v.y * 1664525u;
v.y += v.x * 1664525u;
v = v ^ (v >> 16u);
v.x += v.y * 1664525u;
v.y += v.x * 1664525u;
v = v ^ (v >> 16u);
return v;
}
// Generate a random unsigned int in [0, 2^24) given the previous RNG state
// using the Numerical Recipes linear congruential generator
uint lcg(inout uint prev)
{
uint LCG_A = 1664525u;
uint LCG_C = 1013904223u;
prev = (LCG_A * prev + LCG_C);
return prev & 0x00FFFFFF;
}
// Generate a random float in [0, 1) given the previous RNG state
float rnd(inout uint seed)
{
return (float(lcg(seed)) / float(0x01000000));
}

View file

@ -0,0 +1,61 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_EXT_scalar_block_layout : enable
#extension GL_GOOGLE_include_directive : enable
#include "wavefront.glsl"
// clang-format off
layout(binding = 2, set = 0, scalar) buffer ScnDesc { sceneDesc i[]; } scnDesc;
// clang-format on
layout(binding = 0) uniform UniformBufferObject
{
mat4 view;
mat4 proj;
mat4 viewI;
}
ubo;
layout(push_constant) uniform shaderInformation
{
vec3 lightPosition;
uint instanceId;
float lightIntensity;
int lightType;
}
pushC;
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec3 inColor;
layout(location = 3) in vec2 inTexCoord;
//layout(location = 0) flat out int matIndex;
layout(location = 1) out vec2 fragTexCoord;
layout(location = 2) out vec3 fragNormal;
layout(location = 3) out vec3 viewDir;
layout(location = 4) out vec3 worldPos;
out gl_PerVertex
{
vec4 gl_Position;
};
void main()
{
mat4 objMatrix = scnDesc.i[pushC.instanceId].transfo;
mat4 objMatrixIT = scnDesc.i[pushC.instanceId].transfoIT;
vec3 origin = vec3(ubo.viewI * vec4(0, 0, 0, 1));
worldPos = vec3(objMatrix * vec4(inPosition, 1.0));
viewDir = vec3(worldPos - origin);
fragTexCoord = inTexCoord;
fragNormal = vec3(objMatrixIT * vec4(inNormal, 0.0));
// matIndex = inMatID;
gl_Position = ubo.proj * ubo.view * vec4(worldPos, 1.0);
}

View file

@ -0,0 +1,58 @@
struct Vertex
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
struct sceneDesc
{
int objId;
int txtOffset;
mat4 transfo;
mat4 transfoIT;
};
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
{
// Lambertian
float dotNL = max(dot(normal, lightDir), 0.0);
vec3 c = mat.diffuse * dotNL;
if(mat.illum >= 1)
c += mat.ambient;
return c;
}
vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal)
{
if(mat.illum < 2)
return vec3(0);
// Compute specular only if not in shadow
const float kPi = 3.14159265;
const float kShininess = max(mat.shininess, 4.0);
// Specular
const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi);
vec3 V = normalize(-viewDir);
vec3 R = reflect(-lightDir, normal);
float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess);
return vec3(mat.specular * specular);
}

View file

@ -31,27 +31,11 @@ include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# compile_glsl_directory(
SET(VULKAN_TARGET_ENV vulkan1.2) SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
UNSET(GLSL_SOURCES) DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
UNSET(SPV_OUTPUT) VULKAN_TARGET "vulkan1.2"
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -59,7 +43,7 @@ list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -68,7 +52,7 @@ target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES}) source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES}) source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES}) source_group("Shader_Files" FILES ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -87,25 +71,8 @@ endforeach(RELEASELIB)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.) # copies binaries that need to be put next to the exe files (ZLib, etc.)
# #
_copy_binaries_to_target( ${PROJNAME} ) _finalize_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -1,4 +1,4 @@
# Callable Shaders - Tutorial # Callable Shaders - Tutorial
![](images/callable.png) ![](images/callable.png)
<small>Author: [Martin-Karl Lefrançois](https://devblogs.nvidia.com/author/mlefrancois/)</small> <small>Author: [Martin-Karl Lefrançois](https://devblogs.nvidia.com/author/mlefrancois/)</small>
@ -78,14 +78,14 @@ In `HelloVulkan::createRtPipeline()`, immediately after adding the closest-hit s
vk::ShaderModule call2 = vk::ShaderModule call2 =
nvvk::createShaderModule(m_device, nvh::loadFile("shaders/light_inf.rcall.spv", true, paths)); nvvk::createShaderModule(m_device, nvh::loadFile("shaders/light_inf.rcall.spv", true, paths));
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"});
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); m_rtShaderGroups.push_back(callGroup);
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"});
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); m_rtShaderGroups.push_back(callGroup);
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"});
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); m_rtShaderGroups.push_back(callGroup);
~~~~ ~~~~

View file

@ -68,6 +68,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBase::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -87,8 +88,8 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; vk::Buffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader auto uboUsageStages =
| vk::PipelineStageFlagBits::eRayTracingShaderKHR; vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; vk::BufferMemoryBarrier beforeBarrier;
@ -97,9 +98,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.setBuffer(deviceUBO);
beforeBarrier.setOffset(0); beforeBarrier.setOffset(0);
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
@ -113,9 +112,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
afterBarrier.setBuffer(deviceUBO); afterBarrier.setBuffer(deviceUBO);
afterBarrier.setOffset(0); afterBarrier.setOffset(0);
afterBarrier.setSize(sizeof hostUBO); afterBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
} }
@ -223,8 +220,8 @@ void HelloVulkan::createGraphicsPipeline()
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)},
{1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)},
@ -583,13 +580,12 @@ void HelloVulkan::createPostPipeline()
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
m_renderPass); m_renderPass);
pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline(); m_postPipeline = pipelineGenerator.createPipeline();
@ -715,7 +711,7 @@ void HelloVulkan::createTopLevelAS()
{ {
std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas; std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_objInstance.size());
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance
@ -781,19 +777,15 @@ void HelloVulkan::updateRtDescriptorSet()
// //
void HelloVulkan::createRtPipeline() void HelloVulkan::createRtPipeline()
{ {
std::vector<std::string> paths = defaultSearchPaths; vk::ShaderModule raygenSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
vk::ShaderModule raygenSM = vk::ShaderModule missSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true));
// The second miss shader is invoked when a shadow ray misses the geometry. It // The second miss shader is invoked when a shadow ray misses the geometry. It
// simply indicates that no occlusion has been found // simply indicates that no occlusion has been found
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -802,31 +794,30 @@ void HelloVulkan::createRtPipeline()
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); m_rtShaderGroups.push_back(rg);
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
// Callable shaders // Callable shaders
@ -834,24 +825,21 @@ void HelloVulkan::createRtPipeline()
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
vk::ShaderModule call0 = vk::ShaderModule call0 = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/light_point.rcall.spv", true, paths, true)); vk::ShaderModule call1 = nvvk::createShaderModule(
vk::ShaderModule call1 = m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
nvvk::createShaderModule(m_device, vk::ShaderModule call2 = nvvk::createShaderModule(
nvh::loadFile("shaders/light_spot.rcall.spv", true, paths, true)); m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
vk::ShaderModule call2 =
nvvk::createShaderModule(m_device,
nvh::loadFile("shaders/light_inf.rcall.spv", true, paths, true));
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"});
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); m_rtShaderGroups.push_back(callGroup);
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"});
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); m_rtShaderGroups.push_back(callGroup);
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"});
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); m_rtShaderGroups.push_back(callGroup);
@ -905,7 +893,7 @@ void HelloVulkan::createRtPipeline()
void HelloVulkan::createRtShaderBindingTable() void HelloVulkan::createRtShaderBindingTable()
{ {
auto groupCount = auto groupCount =
static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit static_cast<uint32_t>(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, chit, 3 call
uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier
uint32_t groupSizeAligned = uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);

View file

@ -133,7 +133,7 @@ public:
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; vk::Format m_offscreenDepthFormat;
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();

View file

@ -33,11 +33,11 @@
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui_camera_widget.h" #include "imgui.h"
#include "imgui/backends/imgui_impl_glfw.h"
#include "imgui/extras/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
@ -126,15 +126,13 @@ int main(int argc, char** argv)
} }
// setup some basic things for the sample, logging file for example // setup some basic things for the sample, logging file for example
NVPSystem system(argv[0], PROJECT_NAME); NVPSystem system(PROJECT_NAME);
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, NVPSystem::exePath() + PROJECT_RELDIRECTORY,
PROJECT_ABSDIRECTORY "..", NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
NVPSystem::exePath(), std::string(PROJECT_NAME),
NVPSystem::exePath() + "..",
NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
@ -304,7 +302,7 @@ int main(int argc, char** argv)
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuf, ImGui::GetDrawData()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); cmdBuf.endRenderPass();
} }

View file

@ -31,27 +31,11 @@ include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# compile_glsl_directory(
SET(VULKAN_TARGET_ENV vulkan1.2) SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
UNSET(GLSL_SOURCES) DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
UNSET(SPV_OUTPUT) VULKAN_TARGET "vulkan1.2"
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -59,7 +43,7 @@ list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -68,7 +52,7 @@ target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES}) source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES}) source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES}) source_group("Shader_Files" FILES ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -87,25 +71,8 @@ endforeach(RELEASELIB)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.) # copies binaries that need to be put next to the exe files (ZLib, etc.)
# #
_copy_binaries_to_target( ${PROJNAME} ) _finalize_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -1,4 +1,4 @@
# NVIDIA Vulkan Ray Tracing Tutorial - glTF Scene # NVIDIA Vulkan Ray Tracing Tutorial - glTF Scene
![img](images/vk_ray_tracing_gltf_KHR.png) ![img](images/vk_ray_tracing_gltf_KHR.png)

View file

@ -73,6 +73,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBase::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -92,8 +93,8 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; vk::Buffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader auto uboUsageStages =
| vk::PipelineStageFlagBits::eRayTracingShaderKHR; vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; vk::BufferMemoryBarrier beforeBarrier;
@ -102,9 +103,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.setBuffer(deviceUBO);
beforeBarrier.setOffset(0); beforeBarrier.setOffset(0);
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
@ -118,9 +117,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
afterBarrier.setBuffer(deviceUBO); afterBarrier.setBuffer(deviceUBO);
afterBarrier.setOffset(0); afterBarrier.setOffset(0);
afterBarrier.setSize(sizeof hostUBO); afterBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
} }
@ -214,8 +211,8 @@ void HelloVulkan::createGraphicsPipeline()
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescriptions( gpb.addBindingDescriptions(
{{0, sizeof(nvmath::vec3)}, {1, sizeof(nvmath::vec3)}, {2, sizeof(nvmath::vec2)}}); {{0, sizeof(nvmath::vec3)}, {1, sizeof(nvmath::vec3)}, {2, sizeof(nvmath::vec2)}});
gpb.addAttributeDescriptions({ gpb.addAttributeDescriptions({
@ -272,7 +269,7 @@ void HelloVulkan::loadScene(const std::string& filename)
for(auto& m : m_gltfScene.m_materials) for(auto& m : m_gltfScene.m_materials)
{ {
shadeMaterials.emplace_back( shadeMaterials.emplace_back(
GltfShadeMaterial{m.pbrBaseColorFactor, m.pbrBaseColorTexture, m.emissiveFactor}); GltfShadeMaterial{m.baseColorFactor, m.baseColorTexture, m.emissiveFactor});
} }
m_materialBuffer = m_alloc.createBuffer(cmdBuf, shadeMaterials, vkBU::eStorageBuffer); m_materialBuffer = m_alloc.createBuffer(cmdBuf, shadeMaterials, vkBU::eStorageBuffer);
@ -565,13 +562,12 @@ void HelloVulkan::createPostPipeline()
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
m_renderPass); m_renderPass);
pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline(); m_postPipeline = pipelineGenerator.createPipeline();
@ -770,19 +766,15 @@ void HelloVulkan::updateRtDescriptorSet()
// //
void HelloVulkan::createRtPipeline() void HelloVulkan::createRtPipeline()
{ {
std::vector<std::string> paths = defaultSearchPaths; vk::ShaderModule raygenSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/pathtrace.rgen.spv", true, defaultSearchPaths, true));
vk::ShaderModule raygenSM = vk::ShaderModule missSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/pathtrace.rmiss.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/pathtrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/pathtrace.rmiss.spv", true, paths, true));
// The second miss shader is invoked when a shadow ray misses the geometry. It // The second miss shader is invoked when a shadow ray misses the geometry. It
// simply indicates that no occlusion has been found // simply indicates that no occlusion has been found
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -791,31 +783,30 @@ void HelloVulkan::createRtPipeline()
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); m_rtShaderGroups.push_back(rg);
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/pathtrace.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/pathtrace.rchit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
@ -865,7 +856,7 @@ void HelloVulkan::createRtPipeline()
void HelloVulkan::createRtShaderBindingTable() void HelloVulkan::createRtShaderBindingTable()
{ {
auto groupCount = auto groupCount =
static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit static_cast<uint32_t>(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, chit
uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier
uint32_t groupSizeAligned = uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);

View file

@ -124,7 +124,7 @@ public:
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; vk::Format m_offscreenDepthFormat;
// #VKRay // #VKRay
nvvk::RaytracingBuilderKHR::BlasInput primitiveToGeometry(const nvh::GltfPrimMesh& prim); nvvk::RaytracingBuilderKHR::BlasInput primitiveToGeometry(const nvh::GltfPrimMesh& prim);

View file

@ -34,10 +34,10 @@
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_glfw.h" #include "imgui/backends/imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui_camera_widget.h" #include "imgui/extras/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
@ -109,14 +109,13 @@ int main(int argc, char** argv)
} }
// setup some basic things for the sample, logging file for example // setup some basic things for the sample, logging file for example
NVPSystem system(argv[0], PROJECT_NAME); NVPSystem system(PROJECT_NAME);
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, NVPSystem::exePath() + PROJECT_RELDIRECTORY,
PROJECT_ABSDIRECTORY "..", NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
NVPSystem::exePath(), std::string(PROJECT_NAME),
NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
@ -285,7 +284,7 @@ int main(int argc, char** argv)
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuf, ImGui::GetDrawData()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); cmdBuf.endRenderPass();
} }

View file

@ -0,0 +1,111 @@
#*****************************************************************************
# Copyright 2020 NVIDIA Corporation. All rights reserved.
#*****************************************************************************
cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#--------------------------------------------------------------------------------------------------
# Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
#--------------------------------------------------------------------------------------------------
# C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
_add_project_definitions(${PROJNAME})
#--------------------------------------------------------------------------------------------------
# Source files for this project
#
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories(${TUTO_KHR_DIR}/common)
#--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build
#
SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
)
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#--------------------------------------------------------------------------------------------------
# Sources
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
#--------------------------------------------------------------------------------------------------
# Sub-folders in Visual Studio
#
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES})
#--------------------------------------------------------------------------------------------------
# Linkage
#
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
foreach(DEBUGLIB ${LIBRARIES_DEBUG})
target_link_libraries(${PROJNAME} debug ${DEBUGLIB})
endforeach(DEBUGLIB)
foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB)
#--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.)
#
_copy_binaries_to_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -31,27 +31,11 @@ include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# compile_glsl_directory(
SET(VULKAN_TARGET_ENV vulkan1.2) SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
UNSET(GLSL_SOURCES) DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
UNSET(SPV_OUTPUT) VULKAN_TARGET "vulkan1.2"
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -59,7 +43,7 @@ list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -68,7 +52,7 @@ target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES}) source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES}) source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES}) source_group("Shader_Files" FILES ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -87,25 +71,8 @@ endforeach(RELEASELIB)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.) # copies binaries that need to be put next to the exe files (ZLib, etc.)
# #
_copy_binaries_to_target( ${PROJNAME} ) _finalize_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -1,4 +1,4 @@
# NVIDIA Vulkan Trace Rays Indirect Tutorial # NVIDIA Vulkan Trace Rays Indirect Tutorial
This is an extension of the [Vulkan ray tracing tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/). This is an extension of the [Vulkan ray tracing tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/).
We will discuss the `vkCmdTraceRaysIndirectKHR` command, which allows the We will discuss the `vkCmdTraceRaysIndirectKHR` command, which allows the

View file

@ -68,6 +68,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBase::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -220,8 +221,8 @@ void HelloVulkan::createGraphicsPipeline()
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions(std::vector<vk::VertexInputAttributeDescription>{ gpb.addAttributeDescriptions(std::vector<vk::VertexInputAttributeDescription>{
{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)},
@ -597,13 +598,12 @@ void HelloVulkan::createPostPipeline()
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
m_renderPass); m_renderPass);
pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline(); m_postPipeline = pipelineGenerator.createPipeline();
@ -901,7 +901,7 @@ void HelloVulkan::createTopLevelAS()
tlas.reserve(m_objInstance.size() + m_lanternCount); tlas.reserve(m_objInstance.size() + m_lanternCount);
// Add the OBJ instances. // Add the OBJ instances.
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance
@ -1036,27 +1036,22 @@ void HelloVulkan::updateRtDescriptorSet()
// 8 ===================================================================================== // 8 =====================================================================================
void HelloVulkan::createRtPipeline() void HelloVulkan::createRtPipeline()
{ {
std::vector<std::string> paths = defaultSearchPaths; vk::ShaderModule raygenSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
// Miss shader 0 invoked when a primary ray doesn't hit geometry. Fills in clear color. // Miss shader 0 invoked when a primary ray doesn't hit geometry. Fills in clear color.
vk::ShaderModule missSM = vk::ShaderModule missSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true));
// Miss shader 1 is invoked when a shadow ray (for the main scene light) // Miss shader 1 is invoked when a shadow ray (for the main scene light)
// misses the geometry. It simply indicates that no occlusion has been found. // misses the geometry. It simply indicates that no occlusion has been found.
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
// Miss shader 2 is invoked when a shadow ray for lantern lighting misses the // Miss shader 2 is invoked when a shadow ray for lantern lighting misses the
// lantern. It shouldn't be invoked, but I include it just in case. // lantern. It shouldn't be invoked, but I include it just in case.
vk::ShaderModule lanternmissSM = vk::ShaderModule lanternmissSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("spv/lanternShadow.rmiss.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/lanternShadow.rmiss.spv", true, paths, true));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -1064,74 +1059,71 @@ void HelloVulkan::createRtPipeline()
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); m_rtShaderGroups.push_back(rg);
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Lantern Miss // Lantern Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, lanternmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, lanternmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// OBJ Primary Ray Hit Group - Closest Hit + AnyHit (not used) // OBJ Primary Ray Hit Group - Closest Hit + AnyHit (not used)
vk::ShaderModule chitSM = vk::ShaderModule chitSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
// Lantern Primary Ray Hit Group // Lantern Primary Ray Hit Group
vk::ShaderModule lanternChitSM = vk::ShaderModule lanternChitSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/lantern.rchit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR lanternHg{ vk::RayTracingShaderGroupCreateInfoKHR lanternHg{
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
lanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternChitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternChitSM, "main"});
lanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(lanternHg); m_rtShaderGroups.push_back(lanternHg);
// OBJ Lantern Shadow Ray Hit Group // OBJ Lantern Shadow Ray Hit Group
vk::ShaderModule lanternShadowObjChitSM = nvvk::createShaderModule( vk::ShaderModule lanternShadowObjChitSM = nvvk::createShaderModule(
m_device, // m_device, nvh::loadFile("spv/lanternShadowObj.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/lanternShadowObj.rchit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR lanternShadowObjHg{ vk::RayTracingShaderGroupCreateInfoKHR lanternShadowObjHg{
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
lanternShadowObjHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowObjChitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowObjChitSM, "main"});
lanternShadowObjHg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(lanternShadowObjHg); m_rtShaderGroups.push_back(lanternShadowObjHg);
// Lantern Lantern Shadow Ray Hit Group // Lantern Lantern Shadow Ray Hit Group
vk::ShaderModule lanternShadowLanternChitSM = nvvk::createShaderModule( vk::ShaderModule lanternShadowLanternChitSM =
m_device, // nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadowLantern.rchit.spv", true,
nvh::loadFile("shaders/lanternShadowLantern.rchit.spv", true, paths, true)); defaultSearchPaths, true));
vk::RayTracingShaderGroupCreateInfoKHR lanternShadowLanternHg{ vk::RayTracingShaderGroupCreateInfoKHR lanternShadowLanternHg{
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
lanternShadowLanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back( stages.push_back(
{{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowLanternChitSM, "main"}); {{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowLanternChitSM, "main"});
lanternShadowLanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(lanternShadowLanternHg); m_rtShaderGroups.push_back(lanternShadowLanternHg);
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
@ -1257,7 +1249,7 @@ void HelloVulkan::createLanternIndirectCompPipeline()
// Compile compute shader and package as stage. // Compile compute shader and package as stage.
vk::ShaderModule computeShader = nvvk::createShaderModule( vk::ShaderModule computeShader = nvvk::createShaderModule(
m_device, // m_device, //
nvh::loadFile("shaders/lanternIndirect.comp.spv", true, defaultSearchPaths, true)); nvh::loadFile("spv/lanternIndirect.comp.spv", true, defaultSearchPaths, true));
vk::PipelineShaderStageCreateInfo stageInfo; vk::PipelineShaderStageCreateInfo stageInfo;
stageInfo.setStage(vk::ShaderStageFlagBits::eCompute); stageInfo.setStage(vk::ShaderStageFlagBits::eCompute);
stageInfo.setModule(computeShader); stageInfo.setModule(computeShader);

View file

@ -60,10 +60,7 @@ public:
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const vk::CommandBuffer& cmdBuf,
const std::vector<std::string>& textures); const std::vector<std::string>& textures);
nvmath::mat4 getViewMatrix() nvmath::mat4 getViewMatrix() { return CameraManip.getMatrix(); }
{
return CameraManip.getMatrix();
}
static constexpr float nearZ = 0.1f; static constexpr float nearZ = 0.1f;
nvmath::mat4 getProjMatrix() nvmath::mat4 getProjMatrix()
@ -172,7 +169,7 @@ public:
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; vk::Format m_offscreenDepthFormat;
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();

View file

@ -34,10 +34,10 @@
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_glfw.h" #include "imgui/backends/imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui_camera_widget.h" #include "imgui/extras/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
@ -110,15 +110,13 @@ int main(int argc, char** argv)
} }
// setup some basic things for the sample, logging file for example // setup some basic things for the sample, logging file for example
NVPSystem system(argv[0], PROJECT_NAME); NVPSystem system(PROJECT_NAME);
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, NVPSystem::exePath() + PROJECT_RELDIRECTORY,
PROJECT_ABSDIRECTORY "..", NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
NVPSystem::exePath(), std::string(PROJECT_NAME),
NVPSystem::exePath() + "..",
NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
@ -180,14 +178,14 @@ int main(int argc, char** argv)
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.addLantern({ 8.000f, 1.100f, 3.600f}, {1.0f, 0.0f, 0.0f}, 0.4f, 4.0f); helloVk.addLantern({8.000f, 1.100f, 3.600f}, {1.0f, 0.0f, 0.0f}, 0.4f, 4.0f);
helloVk.addLantern({ 8.000f, 0.600f, 3.900f}, {0.0f, 1.0f, 0.0f}, 0.4f, 4.0f); helloVk.addLantern({8.000f, 0.600f, 3.900f}, {0.0f, 1.0f, 0.0f}, 0.4f, 4.0f);
helloVk.addLantern({ 8.000f, 1.100f, 4.400f}, {0.0f, 0.0f, 1.0f}, 0.4f, 4.0f); helloVk.addLantern({8.000f, 1.100f, 4.400f}, {0.0f, 0.0f, 1.0f}, 0.4f, 4.0f);
helloVk.addLantern({ 1.730f, 1.812f, -1.604f}, {0.0f, 0.4f, 0.4f}, 0.4f, 4.0f); helloVk.addLantern({1.730f, 1.812f, -1.604f}, {0.0f, 0.4f, 0.4f}, 0.4f, 4.0f);
helloVk.addLantern({ 1.730f, 1.862f, 1.916f}, {0.0f, 0.2f, 0.4f}, 0.3f, 3.0f); helloVk.addLantern({1.730f, 1.862f, 1.916f}, {0.0f, 0.2f, 0.4f}, 0.3f, 3.0f);
helloVk.addLantern({-2.000f, 1.900f, -0.700f}, {0.8f, 0.8f, 0.6f}, 0.4f, 3.9f); helloVk.addLantern({-2.000f, 1.900f, -0.700f}, {0.8f, 0.8f, 0.6f}, 0.4f, 3.9f);
helloVk.addLantern({ 0.100f, 0.080f, -2.392f}, {1.0f, 0.0f, 1.0f}, 0.5f, 5.0f); helloVk.addLantern({0.100f, 0.080f, -2.392f}, {1.0f, 0.0f, 1.0f}, 0.5f, 5.0f);
helloVk.addLantern({ 1.948f, 0.080f, 0.598f}, {1.0f, 1.0f, 1.0f}, 0.6f, 6.0f); helloVk.addLantern({1.948f, 0.080f, 0.598f}, {1.0f, 1.0f, 1.0f}, 0.6f, 6.0f);
helloVk.addLantern({-2.300f, 0.080f, 2.100f}, {0.0f, 0.7f, 0.0f}, 0.6f, 6.0f); helloVk.addLantern({-2.300f, 0.080f, 2.100f}, {0.0f, 0.7f, 0.0f}, 0.6f, 6.0f);
helloVk.addLantern({-1.400f, 4.300f, 0.150f}, {1.0f, 1.0f, 0.0f}, 0.7f, 7.0f); helloVk.addLantern({-1.400f, 4.300f, 0.150f}, {1.0f, 1.0f, 0.0f}, 0.7f, 7.0f);
@ -301,7 +299,7 @@ int main(int argc, char** argv)
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuf, ImGui::GetDrawData()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); cmdBuf.endRenderPass();
} }

View file

@ -31,27 +31,11 @@ include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# compile_glsl_directory(
SET(VULKAN_TARGET_ENV vulkan1.2) SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
UNSET(GLSL_SOURCES) DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
UNSET(SPV_OUTPUT) VULKAN_TARGET "vulkan1.2"
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -59,7 +43,7 @@ list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -68,7 +52,7 @@ target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES}) source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES}) source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES}) source_group("Shader_Files" FILES ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -87,25 +71,8 @@ endforeach(RELEASELIB)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.) # copies binaries that need to be put next to the exe files (ZLib, etc.)
# #
_copy_binaries_to_target( ${PROJNAME} ) _finalize_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -1,4 +1,4 @@
# NVIDIA Vulkan Ray Tracing Tutorial # NVIDIA Vulkan Ray Tracing Tutorial
![img](images/instances.png) ![img](images/instances.png)

View file

@ -84,6 +84,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
m_alloc.init(device, physicalDevice, m_memAllocator); m_alloc.init(device, physicalDevice, m_memAllocator);
#endif #endif
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -103,8 +104,8 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; vk::Buffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader auto uboUsageStages =
| vk::PipelineStageFlagBits::eRayTracingShaderKHR; vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; vk::BufferMemoryBarrier beforeBarrier;
@ -113,9 +114,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.setBuffer(deviceUBO);
beforeBarrier.setOffset(0); beforeBarrier.setOffset(0);
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
@ -129,9 +128,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
afterBarrier.setBuffer(deviceUBO); afterBarrier.setBuffer(deviceUBO);
afterBarrier.setOffset(0); afterBarrier.setOffset(0);
afterBarrier.setSize(sizeof hostUBO); afterBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
} }
@ -239,8 +236,8 @@ void HelloVulkan::createGraphicsPipeline()
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)},
{1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)},
@ -605,13 +602,12 @@ void HelloVulkan::createPostPipeline()
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
m_renderPass); m_renderPass);
pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline(); m_postPipeline = pipelineGenerator.createPipeline();
@ -735,7 +731,7 @@ void HelloVulkan::createTopLevelAS()
{ {
std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas; std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_objInstance.size());
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance
@ -801,19 +797,15 @@ void HelloVulkan::updateRtDescriptorSet()
// //
void HelloVulkan::createRtPipeline() void HelloVulkan::createRtPipeline()
{ {
std::vector<std::string> paths = defaultSearchPaths; vk::ShaderModule raygenSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
vk::ShaderModule raygenSM = vk::ShaderModule missSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true));
// The second miss shader is invoked when a shadow ray misses the geometry. It // The second miss shader is invoked when a shadow ray misses the geometry. It
// simply indicates that no occlusion has been found // simply indicates that no occlusion has been found
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -822,31 +814,30 @@ void HelloVulkan::createRtPipeline()
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); m_rtShaderGroups.push_back(rg);
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
@ -895,7 +886,7 @@ void HelloVulkan::createRtPipeline()
void HelloVulkan::createRtShaderBindingTable() void HelloVulkan::createRtShaderBindingTable()
{ {
auto groupCount = auto groupCount =
static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit static_cast<uint32_t>(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, chit
uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier
uint32_t groupSizeAligned = uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);

View file

@ -142,7 +142,7 @@ public:
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; vk::Format m_offscreenDepthFormat;
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();

View file

@ -35,10 +35,10 @@
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_glfw.h" #include "imgui/backends/imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui_camera_widget.h" #include "imgui/extras/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
@ -110,15 +110,13 @@ int main(int argc, char** argv)
} }
// setup some basic things for the sample, logging file for example // setup some basic things for the sample, logging file for example
NVPSystem system(argv[0], PROJECT_NAME); NVPSystem system(PROJECT_NAME);
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, NVPSystem::exePath() + PROJECT_RELDIRECTORY,
PROJECT_ABSDIRECTORY "..", NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
NVPSystem::exePath(), std::string(PROJECT_NAME),
NVPSystem::exePath() + "..",
NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
@ -304,7 +302,7 @@ int main(int argc, char** argv)
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuf, ImGui::GetDrawData()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); cmdBuf.endRenderPass();
} }

View file

@ -31,27 +31,11 @@ include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# compile_glsl_directory(
SET(VULKAN_TARGET_ENV vulkan1.2) SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
UNSET(GLSL_SOURCES) DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
UNSET(SPV_OUTPUT) VULKAN_TARGET "vulkan1.2"
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -59,7 +43,7 @@ list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -68,7 +52,7 @@ target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES}) source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES}) source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES}) source_group("Shader_Files" FILES ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -87,25 +71,8 @@ endforeach(RELEASELIB)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.) # copies binaries that need to be put next to the exe files (ZLib, etc.)
# #
_copy_binaries_to_target( ${PROJNAME} ) _finalize_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -1,4 +1,4 @@
# Intersection Shader - Tutorial # Intersection Shader - Tutorial
![](images/intersection.png) ![](images/intersection.png)
<small>Author: [Martin-Karl Lefrançois](https://devblogs.nvidia.com/author/mlefrancois/)</small> <small>Author: [Martin-Karl Lefrançois](https://devblogs.nvidia.com/author/mlefrancois/)</small>
@ -315,8 +315,8 @@ Here is how the two hit group looks like:
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
} }
@ -331,10 +331,10 @@ Here is how the two hit group looks like:
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1)); hg.setIntersectionShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"});
hg.setIntersectionShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
} }
~~~~ ~~~~

View file

@ -69,6 +69,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBase::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -88,8 +89,8 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; vk::Buffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader auto uboUsageStages =
| vk::PipelineStageFlagBits::eRayTracingShaderKHR; vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; vk::BufferMemoryBarrier beforeBarrier;
@ -98,9 +99,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.setBuffer(deviceUBO);
beforeBarrier.setOffset(0); beforeBarrier.setOffset(0);
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
@ -114,9 +113,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
afterBarrier.setBuffer(deviceUBO); afterBarrier.setBuffer(deviceUBO);
afterBarrier.setOffset(0); afterBarrier.setOffset(0);
afterBarrier.setSize(sizeof hostUBO); afterBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
} }
@ -233,8 +230,8 @@ void HelloVulkan::createGraphicsPipeline()
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)},
{1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)},
@ -598,13 +595,12 @@ void HelloVulkan::createPostPipeline()
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
m_renderPass); m_renderPass);
pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline(); m_postPipeline = pipelineGenerator.createPipeline();
@ -831,7 +827,7 @@ void HelloVulkan::createTopLevelAS()
{ {
std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas; std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_objInstance.size());
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance
@ -909,19 +905,15 @@ void HelloVulkan::updateRtDescriptorSet()
// //
void HelloVulkan::createRtPipeline() void HelloVulkan::createRtPipeline()
{ {
std::vector<std::string> paths = defaultSearchPaths; vk::ShaderModule raygenSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
vk::ShaderModule raygenSM = vk::ShaderModule missSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true));
// The second miss shader is invoked when a shadow ray misses the geometry. It // The second miss shader is invoked when a shadow ray misses the geometry. It
// simply indicates that no occlusion has been found // simply indicates that no occlusion has been found
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -930,50 +922,47 @@ void HelloVulkan::createRtPipeline()
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); m_rtShaderGroups.push_back(rg);
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Hit Group0 - Closest Hit // Hit Group0 - Closest Hit
vk::ShaderModule chitSM = vk::ShaderModule chitSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
{ {
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
} }
// Hit Group1 - Closest Hit + Intersection (procedural) // Hit Group1 - Closest Hit + Intersection (procedural)
vk::ShaderModule chit2SM = vk::ShaderModule chit2SM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true)); vk::ShaderModule rintSM = nvvk::createShaderModule(
vk::ShaderModule rintSM = m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true));
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rint.spv", true, paths, true));
{ {
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1)); hg.setIntersectionShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"});
hg.setIntersectionShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
} }
@ -1025,7 +1014,7 @@ void HelloVulkan::createRtPipeline()
void HelloVulkan::createRtShaderBindingTable() void HelloVulkan::createRtShaderBindingTable()
{ {
auto groupCount = auto groupCount =
static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit static_cast<uint32_t>(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, 2 chit, rint
uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier
uint32_t groupSizeAligned = uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);

View file

@ -129,7 +129,7 @@ public:
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; vk::Format m_offscreenDepthFormat;
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();

View file

@ -34,10 +34,10 @@
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_glfw.h" #include "imgui/backends/imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui_camera_widget.h" #include "imgui/extras/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
@ -110,14 +110,13 @@ int main(int argc, char** argv)
} }
// setup some basic things for the sample, logging file for example // setup some basic things for the sample, logging file for example
NVPSystem system(argv[0], PROJECT_NAME); NVPSystem system(PROJECT_NAME);
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, NVPSystem::exePath() + PROJECT_RELDIRECTORY,
PROJECT_ABSDIRECTORY "..", NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
NVPSystem::exePath(), std::string(PROJECT_NAME),
NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
@ -288,7 +287,7 @@ int main(int argc, char** argv)
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuf, ImGui::GetDrawData()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); cmdBuf.endRenderPass();
} }

View file

@ -31,27 +31,11 @@ include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# compile_glsl_directory(
SET(VULKAN_TARGET_ENV vulkan1.2) SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
UNSET(GLSL_SOURCES) DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
UNSET(SPV_OUTPUT) VULKAN_TARGET "vulkan1.2"
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -59,7 +43,7 @@ list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -68,7 +52,7 @@ target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES}) source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES}) source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES}) source_group("Shader_Files" FILES ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -87,25 +71,8 @@ endforeach(RELEASELIB)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.) # copies binaries that need to be put next to the exe files (ZLib, etc.)
# #
_copy_binaries_to_target( ${PROJNAME} ) _finalize_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -1,4 +1,4 @@
# Jitter Camera - Tutorial # Jitter Camera - Tutorial
![](images/antialiasing.png) ![](images/antialiasing.png)

View file

@ -68,6 +68,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBase::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -87,8 +88,8 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; vk::Buffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader auto uboUsageStages =
| vk::PipelineStageFlagBits::eRayTracingShaderKHR; vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; vk::BufferMemoryBarrier beforeBarrier;
@ -97,9 +98,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.setBuffer(deviceUBO);
beforeBarrier.setOffset(0); beforeBarrier.setOffset(0);
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
@ -113,9 +112,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
afterBarrier.setBuffer(deviceUBO); afterBarrier.setBuffer(deviceUBO);
afterBarrier.setOffset(0); afterBarrier.setOffset(0);
afterBarrier.setSize(sizeof hostUBO); afterBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
} }
@ -223,8 +220,8 @@ void HelloVulkan::createGraphicsPipeline()
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)},
{1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)},
@ -584,13 +581,12 @@ void HelloVulkan::createPostPipeline()
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
m_renderPass); m_renderPass);
pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline(); m_postPipeline = pipelineGenerator.createPipeline();
@ -714,7 +710,7 @@ void HelloVulkan::createTopLevelAS()
{ {
std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas; std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_objInstance.size());
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance
@ -780,19 +776,15 @@ void HelloVulkan::updateRtDescriptorSet()
// //
void HelloVulkan::createRtPipeline() void HelloVulkan::createRtPipeline()
{ {
std::vector<std::string> paths = defaultSearchPaths; vk::ShaderModule raygenSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
vk::ShaderModule raygenSM = vk::ShaderModule missSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true));
// The second miss shader is invoked when a shadow ray misses the geometry. It // The second miss shader is invoked when a shadow ray misses the geometry. It
// simply indicates that no occlusion has been found // simply indicates that no occlusion has been found
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -801,31 +793,30 @@ void HelloVulkan::createRtPipeline()
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); m_rtShaderGroups.push_back(rg);
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
@ -874,7 +865,7 @@ void HelloVulkan::createRtPipeline()
void HelloVulkan::createRtShaderBindingTable() void HelloVulkan::createRtShaderBindingTable()
{ {
auto groupCount = auto groupCount =
static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit static_cast<uint32_t>(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, chit
uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier
uint32_t groupSizeAligned = uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);

View file

@ -129,7 +129,7 @@ public:
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; vk::Format m_offscreenDepthFormat;
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();

View file

@ -34,10 +34,10 @@
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_glfw.h" #include "imgui/backends/imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui_camera_widget.h" #include "imgui/extras/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
@ -117,15 +117,13 @@ int main(int argc, char** argv)
} }
// setup some basic things for the sample, logging file for example // setup some basic things for the sample, logging file for example
NVPSystem system(argv[0], PROJECT_NAME); NVPSystem system(PROJECT_NAME);
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, NVPSystem::exePath() + PROJECT_RELDIRECTORY,
PROJECT_ABSDIRECTORY "..", NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
NVPSystem::exePath(), std::string(PROJECT_NAME),
NVPSystem::exePath() + "..",
NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
@ -301,7 +299,7 @@ int main(int argc, char** argv)
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuf, ImGui::GetDrawData()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); cmdBuf.endRenderPass();
} }

View file

@ -31,27 +31,11 @@ include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# compile_glsl_directory(
SET(VULKAN_TARGET_ENV vulkan1.2) SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
UNSET(GLSL_SOURCES) DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
UNSET(SPV_OUTPUT) VULKAN_TARGET "vulkan1.2"
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.comp"
"shaders/*.frag"
"shaders/*.vert"
"shaders/*.rchit"
"shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss"
"shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -59,7 +43,7 @@ list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -68,7 +52,7 @@ target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
source_group("Sources" FILES ${SOURCE_FILES}) source_group("Sources" FILES ${SOURCE_FILES})
source_group("Headers" FILES ${HEADER_FILES}) source_group("Headers" FILES ${HEADER_FILES})
source_group("Shader_Files" FILES ${GLSL_SOURCES}) source_group("Shader_Files" FILES ${GLSL_SOURCES} ${GLSL_HEADERS})
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
@ -87,25 +71,8 @@ endforeach(RELEASELIB)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# copies binaries that need to be put next to the exe files (ZLib, etc.) # copies binaries that need to be put next to the exe files (ZLib, etc.)
# #
_copy_binaries_to_target( ${PROJNAME} ) _finalize_target( ${PROJNAME} )
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -1,4 +1,4 @@
# Multiple Closest Hit Shaders - Tutorial # Multiple Closest Hit Shaders - Tutorial
![](images/manyhits.png) ![](images/manyhits.png)
@ -21,11 +21,12 @@ Then you can change the `helloVk.loadModel` calls to the following:
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true), helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true),
nvmath::translation_mat4(nvmath::vec3f(-1, 0, 0))); nvmath::translation_mat4(nvmath::vec3f(-1, 0, 0)));
HelloVulkan::ObjInstance inst;
inst.objIndex = 0; HelloVulkan::ObjInstance inst = helloVk.m_objInstance[0]; // Instance the wuson object
inst.transform = nvmath::translation_mat4(nvmath::vec3f(1, 0, 0)); inst.transform = nvmath::translation_mat4(nvmath::vec3f(1, 0, 0));
inst.transformIT = nvmath::transpose(nvmath::invert(inst.transform)); inst.transformIT = nvmath::transpose(nvmath::invert(inst.transform));
helloVk.m_objInstance.push_back(inst); helloVk.m_objInstance.push_back(inst); // Adding an instance of the wuson
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
~~~~ ~~~~
@ -67,8 +68,8 @@ Then add a new hit group group immediately after adding the first hit group:
~~~~ C++ ~~~~ C++
// Second group // Second group
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
~~~~ ~~~~
@ -315,11 +316,12 @@ The following modification will add another entry to the SBT with a different co
In the description of the scene in `main`, we will tell the `wuson` models to use hit groups 1 and 2 respectively, and to have different colors. In the description of the scene in `main`, we will tell the `wuson` models to use hit groups 1 and 2 respectively, and to have different colors.
~~~~ C++ ~~~~ C++
helloVk.m_objInstance[0].hitgroup = 1; // Hit shader record info
helloVk.m_objInstance[1].hitgroup = 2;
helloVk.m_hitShaderRecord.resize(2); helloVk.m_hitShaderRecord.resize(2);
helloVk.m_hitShaderRecord[0].color = nvmath::vec4f(0, 1, 0, 0); // Green helloVk.m_hitShaderRecord[0].color = nvmath::vec4f(0, 1, 0, 0); // Green
helloVk.m_hitShaderRecord[1].color = nvmath::vec4f(0, 1, 1, 0); // Cyan helloVk.m_hitShaderRecord[1].color = nvmath::vec4f(0, 1, 1, 0); // Cyan
helloVk.m_objInstance[0].hitgroup = 1; // wuson 0
helloVk.m_objInstance[1].hitgroup = 2; // wuson 1
~~~~ ~~~~
### `createRtShaderBindingTable` ### `createRtShaderBindingTable`

View file

@ -67,6 +67,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBase::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -86,8 +87,8 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; vk::Buffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader auto uboUsageStages =
| vk::PipelineStageFlagBits::eRayTracingShaderKHR; vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; vk::BufferMemoryBarrier beforeBarrier;
@ -96,9 +97,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.setBuffer(deviceUBO);
beforeBarrier.setOffset(0); beforeBarrier.setOffset(0);
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
@ -112,9 +111,7 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
afterBarrier.setBuffer(deviceUBO); afterBarrier.setBuffer(deviceUBO);
afterBarrier.setOffset(0); afterBarrier.setOffset(0);
afterBarrier.setSize(sizeof hostUBO); afterBarrier.setSize(sizeof hostUBO);
cmdBuf.pipelineBarrier( cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
vk::PipelineStageFlagBits::eTransfer,
uboUsageStages,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
} }
@ -222,8 +219,8 @@ void HelloVulkan::createGraphicsPipeline()
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)},
{1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)},
@ -582,13 +579,12 @@ void HelloVulkan::createPostPipeline()
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
m_renderPass); m_renderPass);
pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline(); m_postPipeline = pipelineGenerator.createPipeline();
@ -712,7 +708,7 @@ void HelloVulkan::createTopLevelAS()
{ {
std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas; std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_objInstance.size());
for(int i = 0; i < static_cast<int>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance
@ -778,19 +774,15 @@ void HelloVulkan::updateRtDescriptorSet()
// //
void HelloVulkan::createRtPipeline() void HelloVulkan::createRtPipeline()
{ {
std::vector<std::string> paths = defaultSearchPaths; vk::ShaderModule raygenSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
vk::ShaderModule raygenSM = vk::ShaderModule missSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true));
// The second miss shader is invoked when a shadow ray misses the geometry. It // The second miss shader is invoked when a shadow ray misses the geometry. It
// simply indicates that no occlusion has been found // simply indicates that no occlusion has been found
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -799,38 +791,36 @@ void HelloVulkan::createRtPipeline()
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); m_rtShaderGroups.push_back(rg);
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg);
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, // m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::ShaderModule chit2SM = nvvk::createShaderModule(
vk::ShaderModule chit2SM = m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
// Second group // Second group
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitNV, chit2SM, "main"}); hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1)); stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg);
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
@ -880,7 +870,7 @@ void HelloVulkan::createRtPipeline()
void HelloVulkan::createRtShaderBindingTable() void HelloVulkan::createRtShaderBindingTable()
{ {
auto groupCount = auto groupCount =
static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit static_cast<uint32_t>(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, 2 chit
uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier
uint32_t groupSizeAligned = m_rtProperties.shaderGroupBaseAlignment; uint32_t groupSizeAligned = m_rtProperties.shaderGroupBaseAlignment;

View file

@ -130,7 +130,7 @@ public:
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; vk::Format m_offscreenDepthFormat;
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();

Some files were not shown because too many files have changed in this diff Show more