Bulk update NvPro-Samples 03/18/21
This commit is contained in:
parent
a2b80ab819
commit
2da588b7e6
113 changed files with 3529 additions and 1508 deletions
|
|
@ -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
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
**/spv/*.spv
|
||||||
|
/build/*
|
||||||
|
|
@ -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")
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||

|

|
||||||
|
|
||||||
# NVIDIA Vulkan Ray Tracing Tutorials
|
# NVIDIA Vulkan Ray Tracing Tutorials
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 |
|
|
@ -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**
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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/)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
(insert vkrt_tutorial.md.html here)
|
(insert vkrt_tutorial.md.html here)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
|
|
||||||
# Environment Setup
|
# Environment Setup
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
|
||||||
# Environment Setup
|
# Environment Setup
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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**
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
|
||||||
|
|
@ -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**
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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**
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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**
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)},
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Ray Tracing Animation - Tutorial
|
# Ray Tracing Animation - Tutorial
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||

|

|
||||||
|
|
@ -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);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
80
ray_tracing_ao/CMakeLists.txt
Normal file
80
ray_tracing_ao/CMakeLists.txt
Normal 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
491
ray_tracing_ao/README.md
Normal file
|
|
@ -0,0 +1,491 @@
|
||||||
|
# G-Buffer and Ambient Occlusion - Tutorial
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The following are the buffers are they can be seen in [NSight Graphics](https://developer.nvidia.com/nsight-graphics).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 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));
|
||||||
|
~~~~
|
||||||
|
|
||||||
913
ray_tracing_ao/hello_vulkan.cpp
Normal file
913
ray_tracing_ao/hello_vulkan.cpp
Normal 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;
|
||||||
|
}
|
||||||
174
ray_tracing_ao/hello_vulkan.h
Normal file
174
ray_tracing_ao/hello_vulkan.h
Normal 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};
|
||||||
|
};
|
||||||
BIN
ray_tracing_ao/images/Hemisphere_sampling.png
Normal file
BIN
ray_tracing_ao/images/Hemisphere_sampling.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
ray_tracing_ao/images/Tuto_Ao_workflow.png
Normal file
BIN
ray_tracing_ao/images/Tuto_Ao_workflow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
BIN
ray_tracing_ao/images/buffers.png
Normal file
BIN
ray_tracing_ao/images/buffers.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
ray_tracing_ao/images/ray_tracing_ao.png
Normal file
BIN
ray_tracing_ao/images/ray_tracing_ao.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 188 KiB |
342
ray_tracing_ao/main.cpp
Normal file
342
ray_tracing_ao/main.cpp
Normal 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;
|
||||||
|
}
|
||||||
123
ray_tracing_ao/shaders/ao.comp
Normal file
123
ray_tracing_ao/shaders/ao.comp
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
90
ray_tracing_ao/shaders/frag_shader.frag
Normal file
90
ray_tracing_ao/shaders/frag_shader.frag
Normal 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)));
|
||||||
|
}
|
||||||
15
ray_tracing_ao/shaders/passthrough.vert
Normal file
15
ray_tracing_ao/shaders/passthrough.vert
Normal 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);
|
||||||
|
}
|
||||||
23
ray_tracing_ao/shaders/post.frag
Normal file
23
ray_tracing_ao/shaders/post.frag
Normal 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));
|
||||||
|
}
|
||||||
190
ray_tracing_ao/shaders/raycommon.glsl
Normal file
190
ray_tracing_ao/shaders/raycommon.glsl
Normal 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));
|
||||||
|
}
|
||||||
61
ray_tracing_ao/shaders/vert_shader.vert
Normal file
61
ray_tracing_ao/shaders/vert_shader.vert
Normal 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);
|
||||||
|
}
|
||||||
58
ray_tracing_ao/shaders/wavefront.glsl
Normal file
58
ray_tracing_ao/shaders/wavefront.glsl
Normal 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);
|
||||||
|
}
|
||||||
|
|
@ -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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Callable Shaders - Tutorial
|
# Callable Shaders - Tutorial
|
||||||
|
|
||||||

|

|
||||||
<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);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# NVIDIA Vulkan Ray Tracing Tutorial - glTF Scene
|
# NVIDIA Vulkan Ray Tracing Tutorial - glTF Scene
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
111
ray_tracing_indirect/CMakeLists.txt
Normal file
111
ray_tracing_indirect/CMakeLists.txt
Normal 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}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
@ -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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# NVIDIA Vulkan Ray Tracing Tutorial
|
# NVIDIA Vulkan Ray Tracing Tutorial
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Intersection Shader - Tutorial
|
# Intersection Shader - Tutorial
|
||||||
|
|
||||||

|

|
||||||
<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);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Jitter Camera - Tutorial
|
# Jitter Camera - Tutorial
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Multiple Closest Hit Shaders - Tutorial
|
# Multiple Closest Hit Shaders - Tutorial
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
@ -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`
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue