Using final KHR ray tracing extension: VK_KHR_acceleration_structure, VK_KHR_ray_tracing_pipeline and VK_KHR_ray_query

This commit is contained in:
mklefrancois 2020-11-23 11:33:51 +01:00
parent 7179569ec3
commit b26ff92473
80 changed files with 2446 additions and 2351 deletions

View file

@ -1,37 +1,42 @@
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
project(vk_raytracing_tutorial) 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 CMakeLists_include.txt yet
# if(NOT BASE_DIRECTORY)
if(NOT BASE_DIRECTORY) # if not defined, it means this cmake file was called as the first entry point and not included
# check if the external repository is outside or inside the project (as a sub-module)
# testing the file CMakeLists_include.txt because when sub-modules are not cloned, the folders are still there...
# we also assume here that if shared_sources is there, shared_external is, too...
SET(BASE_DIRECTORY "" CACHE FILEPATH "folder containing shared_sources") SET(BASE_DIRECTORY "" CACHE FILEPATH "folder containing shared_sources")
SET(ADD_SUBDIR_BELOW 1) SET(ADD_SUBDIR_BELOW 1)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/shared_sources/CMakeLists_include.txt) find_path(BASE_DIRECTORY2
SET(BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) NAMES shared_sources
elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../shared_sources/CMakeLists_include.txt) PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}
SET(BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/..) REQUIRED
elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../../shared_sources/CMakeLists_include.txt) DOC "Couldn't find shared_source directory'"
SET(BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../..) )
else() SET(BASE_DIRECTORY ${BASE_DIRECTORY2} )
endif()
endif(NOT BASE_DIRECTORY)
if(EXISTS ${BASE_DIRECTORY}/shared_sources/CMakeLists_include.txt)
INCLUDE(${BASE_DIRECTORY}/shared_sources/CMakeLists_include.txt)
else()
Message(FATAL_ERROR "could not find base directory, please set BASE_DIRECTORY to folder containing shared_sources")
endif() endif()
## Various functions and macros REQUIRED
include(${BASE_DIRECTORY}/shared_sources/CMakeLists_include.txt)
set(TUTO_KHR_DIR ${CMAKE_CURRENT_SOURCE_DIR})
# presets and utility functions used in all CMakeLists
include(utilities.cmake)
#--------------------------------------------------------------------------------------------------
# Package shared by all projects
_add_package_VulkanSDK() _add_package_VulkanSDK()
_add_package_OpenGL() _add_package_OpenGL()
_add_package_ImGUI() _add_package_ImGUI()
_add_package_ZLIB() _add_package_ZLIB()
_add_shared_sources_lib() _add_shared_sources_lib()
message(STATUS "COPY ${CMAKE_CURRENT_SOURCE_DIR}/media to ${EXECUTABLE_OUTPUT_PATH}")
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/media DESTINATION ${EXECUTABLE_OUTPUT_PATH})
#--------------------------------------------------------------------------------------------------
# Sub examples
add_subdirectory(ray_tracing__advance) add_subdirectory(ray_tracing__advance)
add_subdirectory(ray_tracing__before) add_subdirectory(ray_tracing__before)
add_subdirectory(ray_tracing__simple) add_subdirectory(ray_tracing__simple)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 497 KiB

After

Width:  |  Height:  |  Size: 336 KiB

Before After
Before After

View file

@ -9,6 +9,14 @@ Besides the current repository, you will also need to clone or download the foll
* [shared_sources](https://github.com/nvpro-samples/shared_sources): The primary framework that all samples depend on. * [shared_sources](https://github.com/nvpro-samples/shared_sources): The primary framework that all samples depend on.
* [shared_external](https://github.com/nvpro-samples/shared_external): Third party libraries that are provided pre-compiled, mostly for Windows x64 / MSVC. * [shared_external](https://github.com/nvpro-samples/shared_external): Third party libraries that are provided pre-compiled, mostly for Windows x64 / MSVC.
Cloning all repositories
~~~~~
git clone https://github.com/nvpro-samples/shared_sources.git
git clone https://github.com/nvpro-samples/shared_external.git
git clone https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR.git
~~~~~
The directory structure should be looking like this: The directory structure should be looking like this:
~~~~ ~~~~
@ -44,7 +52,7 @@ Vulkan driver.
The CMakefile will use other makefiles from `shared_sources` and look for Vulkan environment variables for the installation of the SDK. Therefore, it is important to have all the above installed before running Cmake in the The CMakefile will use other makefiles from `shared_sources` and look for Vulkan environment variables for the installation of the SDK. Therefore, it is important to have all the above installed before running Cmake in the
`vk_raytracing_tutorial_KHR` directory. `vk_raytracing_tutorial_KHR` directory.
:warning: **Note:** If you are using your own Vulkan header files, it is possible to overide the default search path. **Note:** If you are using your own Vulkan header files, it is possible to overide the default search path.
Modify `VULKAN > VULKAN_HEADERS_OVERRIDE_INCLUDE_DIR` to the path to beta vulkan headers. Modify `VULKAN > VULKAN_HEADERS_OVERRIDE_INCLUDE_DIR` to the path to beta vulkan headers.
## Starting From Extra Tutorial ## Starting From Extra Tutorial

View file

@ -218,11 +218,11 @@ The size of each group can be described as follows:
~~~~ C++ ~~~~ C++
// Sizes // Sizes
uint32_t rayGenSize = baseAlignment; uint32_t rayGenSize = groupSizeAligned;
uint32_t missSize = baseAlignment; uint32_t missSize = groupSizeAligned;
uint32_t hitSize = uint32_t hitSize =
ROUND_UP(groupHandleSize + static_cast<int>(sizeof(HitRecordBuffer)), baseAlignment); nvh::align_up(groupHandleSize + static_cast<int>(sizeof(HitRecordBuffer)), groupSizeAligned);
uint32_t newSbtSize = rayGenSize + 2 * missSize + 2 * hitSize; uint32_t newSbtSize = rayGenSize + 2 * missSize + 3 * hitSize;
~~~~ ~~~~
Then write the new SBT like this, where only Hit 1 has extra data. Then write the new SBT like this, where only Hit 1 has extra data.
@ -258,21 +258,23 @@ Then change the call to `m_alloc.createBuffer` to create the SBT buffer from `sb
m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, vk::BufferUsageFlagBits::eRayTracingKHR); m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, vk::BufferUsageFlagBits::eRayTracingKHR);
~~~~ ~~~~
Note: we are using this `define` for rounding up to the correct alignment
~~~~ C++
#ifndef ROUND_UP
#define ROUND_UP(v, powerOf2Alignment) (((v) + (powerOf2Alignment)-1) & ~((powerOf2Alignment)-1))
#endif
~~~~
## `raytrace` ## `raytrace`
Finally, since the size of the hit group is now larger than just the handle, we need to set the new value of the hit group stride in `HelloVulkan::raytrace`. Finally, since the size of the hit group is now larger than just the handle,
we need to set the new value of the hit group stride in `HelloVulkan::raytrace`.
~~~~ C++ ~~~~ C++
vk::DeviceSize hitGroupStride = vk::DeviceSize hitGroupSize =
ROUND_UP(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer), progOffset); nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer),
m_rtProperties.shaderGroupBaseAlignment);
std::array<Stride, 4> strideAddresses{
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
Stride{sbtAddress + 3u * groupSize, hitGroupSize, hitGroupSize * 3}, // hit
Stride{0u, 0u, 0u}}; // callable
~~~~ ~~~~
!!! Note: !!! Note:

View file

@ -36,78 +36,90 @@ verbosity and its potential for errors.
# Environment Setup # Environment Setup
**The preferred way** to download the project (including NVVK) is to use the
nvpro-samples `build_all` script.
In a command line, clone the `nvpro-samples/build_all` repository from
https://github.com/nvpro-samples/build_all:
~~~~~
git clone https://github.com/nvpro-samples/build_all.git
~~~~~
Then open the `build_all` folder and run either `clone_all.bat` (Windows) or
`clone_all.sh` (Linux).
**If you want to clone as few repositories as possible**, open a command line,
and run the following commands to clone the repositories you need:
~~~~~
git clone https://github.com/nvpro-samples/shared_sources.git
git clone https://github.com/nvpro-samples/shared_external.git
git clone https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR.git
~~~~~
## Generating the Solution
One typical way to store the build system is to create a `build` directory below the
main project. You can use CMake-GUI or do the following steps.
~~~~~
cd vk_raytracing_tutorial_KHR
mkdir build
cd build
cmake ..
~~~~~
## Beta Installation ## Beta Installation
The SDK 1.2.135 and up which can be found under https://vulkan.lunarg.com/sdk/home will work with this project. The SDK 1.2.161 and up which can be found under https://vulkan.lunarg.com/sdk/home will work with this project.
Nevertheless, if you are in the Beta period, it is suggested to install and compile all of the following and replace Nevertheless, if you are in the Beta period, it is suggested to install and compile all of the following and replace
with the current environment. with the current environment.
* Latest driver: https://developer.nvidia.com/vulkan-driver * Latest driver: https://developer.nvidia.com/vulkan-driver
* Latest Vulkan headers: https://github.com/KhronosGroup/Vulkan-Headers * Vulkan headers: https://github.com/KhronosGroup/Vulkan-Headers
* Latest glslangValidator: https://github.com/KhronosGroup/glslang * Validator: https://github.com/KhronosGroup/Vulkan-ValidationLayers
* Vulkan-Hpp: https://github.com/KhronosGroup/Vulkan-Hpp
## Structure
This tutorial is a modification of [`ray_tracing__before`](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/tree/master/ray_tracing__before), which loads are render OBJ scenes with Vulkan rasterizer.
All following instructions are based on the modification of this project.
The directory `ray_tracing__simple` is the end result of this tutorial.
Besides the current repository, you will also need to clone or download the following repositories:
* [shared_sources](https://github.com/nvpro-samples/shared_sources): The primary framework that all samples depend on.
* [shared_external](https://github.com/nvpro-samples/shared_external): Third party libraries that are provided pre-compiled, mostly for Windows x64 / MSVC.
The directory structure should be looking like:
**********************************************************
* \
* |
* +-- 📂 shared_external
* |
* +-- 📂 shared_sources
* |
* +-- 📂 vk_raytracing_tutorial_KHR
* | |
* | +-- 📂 ray_tracing__before
* | |
* | ⋮
* |
* ⋮
**********************************************************
!!! Warning
**Run CMake** in vk_raytracing_tutorial_KHR.
!!! Warning Beta
Modify `VULKAN > VULKAN_HEADERS_OVERRIDE_INCLUDE_DIR` to the path to beta vulkan headers.
!!! 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>
`namespace VULKAN_HPP_NAMESPACE` to `namespace vk` `namespace VULKAN_HPP_NAMESPACE` to `namespace vk`
The starting project is a simple framework allowing us to load OBJ files and rasterize them # Compiling & Running
Open the solution located in the build directory, then compile and run `vk_ray_tracing__before_KHR`.
This will be the starting point of the tutorial. This project is a simple framework allowing us to load OBJ files and rasterize them
using Vulkan. using Vulkan.
![First Run](Images/resultRasterCube.png width="350px") ![First Run](Images/resultRasterCube.png width="350px")
The following steps in the tutorial will be modifying this project
`vk_ray_tracing__before_KHR` and will add support for ray tracing. The
end result of the tutorial is the project `vk_ray_tracing__simple_KHR`.
It is possible to look in that project if something went wrong.
The project `vk_ray_tracing__simple_KHR` will be the starting point for the
extra tutorials.
# Ray Tracing Setup # Ray Tracing Setup
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 request ray tracing capabilities, we need to explicitly To be able to use ray tracing, we will need VK_KHR_ACCELERATION_STRUCTURE and VK_KHR_RAY_TRACING_PIPELINE.
add the Those extensions have also dependencies on other extension, therefore all the following
[VK_KHR_ray_tracing](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_ray_tracing.html) extensions will need to be added.
extension as well as its various dependencies.
```` C ```` C
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
@ -115,11 +127,10 @@ contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
```` ````
Before creating the device, a linked structure of features must past. Not all extensions requires a set of features, but Before creating the device, a linked structure of features must past. Not all extensions
ray tracing features must be enabled before the creation of the device. By providing requires a set of features, but ray tracing features must be enabled before the creation of the device.
`raytracingFeature`, the context creation will query the capable features for ray tracing and will use the By providing `accelFeature`, and `rtPipelineFeature`, the context creation will query the capable features
filled structure to create the device. for ray tracing and will use the filled structure to create the device.
In the `HelloVulkan` class in `hello_vulkan.h`, add an initialization function and a member storing the capabilities of In the `HelloVulkan` class in `hello_vulkan.h`, add an initialization function and a member storing the capabilities of
the GPU for ray tracing: the GPU for ray tracing:
@ -127,8 +138,9 @@ the GPU for ray tracing:
```` C ```` C
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; 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 ie. the number of nested ray tracing calls that can be performed from a single ray. This can be seen as the number
@ -144,15 +156,17 @@ creating the shader binding table in a later section.
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
} }
```` ````
## main ## main
In `main.cpp`, in the `main()` function, we call the initialization method right after `helloVk.updateDescriptorSet();` In `main.cpp`, in the `main()` function, we call the initialization method right after
`helloVk.updateDescriptorSet();`
```` C ```` C
// #VKRay // #VKRay
@ -188,12 +202,11 @@ This sample loads an OBJ file and stores its indices, vertices and material data
model is referenced by an `ObjInstance` structure which also contains the transformation matrix of that particular model is referenced by an `ObjInstance` structure which also contains the transformation matrix of that particular
instance. For ray tracing the `ObjModel` and `ObjInstance` will then naturally fit the BLAS and TLAS, respectively. instance. For ray tracing the `ObjModel` and `ObjInstance` will then naturally fit the BLAS and TLAS, respectively.
To simplify the ray tracing setup we use a helper class containing utility functions for acceleration structure builds. To simplify the ray tracing setup we use a helper class containing utility functions for
In the header file, include the`raytrace_vkpp` helper acceleration structure builds. In the header file, include the`raytrace_vkpp` helper
```` C ```` C
// #VKRay // #VKRay
#define ALLOC_DEDICATED
#include "nvvk/raytrace_vk.hpp" #include "nvvk/raytrace_vk.hpp"
```` ````
@ -224,11 +237,12 @@ nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model);
Its implementation will fill three structures Its implementation will fill three structures
* vk::AccelerationStructureCreateGeometryTypeInfoKHR: that defines how the AS will be constructed. * vk::AccelerationStructureGeometryTrianglesDataKHR: defines the data from which the AS will be constructed.
* vk::AccelerationStructureGeometryKHR: the geometry for build the AS, in this case, from triangles. * vk::AccelerationStructureGeometryKHR: the geometry type for building the AS, in this case, from triangles.
* vk::AccelerationStructureBuildOffsetInfoKHR: the offset, which correspond to the actual wanted geometry when building. * vk::AccelerationStructureBuildRangeInfoKHR: the offset, which correspond to the actual wanted geometry when building.
Multiple of the above structure can be combined to create a single blas. In this example, the array will always be a length of one. Multiple of the above structure can be combined to create a single blas. In this example,
the 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
potential optimization. potential optimization.
@ -239,44 +253,37 @@ potential optimization.
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
// Setting up the creation info of acceleration structure
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles
asCreate.setMaxVertexCount(model.nbVertices);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
// Building part // Building part
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
uint32_t maxPrimitiveCount = model.nbIndices / 3;
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj)); triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
// Setting up the build info of the acceleration // Setting up the build info of the acceleration
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
// The primitive itself // The primitive itself
vk::AccelerationStructureBuildOffsetInfoKHR offset; vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(maxPrimitiveCount);
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
// Our blas is only one geometry, but could be made of many geometries // Our blas is only one geometry, but could be made of many geometries
nvvk::RaytracingBuilderKHR::Blas blas; nvvk::RaytracingBuilderKHR::Blas blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
@ -825,8 +832,8 @@ void HelloVulkan::createRtDescriptorSet()
{}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral};
std::vector<vk::WriteDescriptorSet> writes; std::vector<vk::WriteDescriptorSet> writes;
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo));
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, imageInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo));
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
```` ````
@ -840,26 +847,26 @@ index buffers. Even though the vertex and index buffers will only be used by the
descriptor set as they semantically fit the Scene descriptor set. descriptor set as they semantically fit the Scene descriptor set.
```` C ```` C
// Camera matrices (binding = 0) // Camera matrices (binding = 0)
m_descSetLayoutBind.addBinding( m_descSetLayoutBind.addBinding(
vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR));
// Materials (binding = 1) // Materials (binding = 1)
m_descSetLayoutBind.addBinding( m_descSetLayoutBind.addBinding(
vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR));
// Scene description (binding = 2) // Scene description (binding = 2)
m_descSetLayoutBind.addBinding( // m_descSetLayoutBind.addBinding( //
vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR));
// Textures (binding = 3) // Textures (binding = 3)
m_descSetLayoutBind.addBinding( m_descSetLayoutBind.addBinding(
vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR));
// Materials (binding = 4) // Materials (binding = 4)
m_descSetLayoutBind.addBinding( m_descSetLayoutBind.addBinding(
vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR)); vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR));
// Storing vertices (binding = 5) // Storing vertices (binding = 5)
m_descSetLayoutBind.addBinding( // m_descSetLayoutBind.addBinding( //
vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR));
// Storing indices (binding = 6) // Storing indices (binding = 6)
m_descSetLayoutBind.addBinding( // m_descSetLayoutBind.addBinding( //
vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR));
```` ````
@ -884,14 +891,23 @@ We set the actual contents of the descriptor set by adding those buffers in `upd
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data()));
```` ````
Originally the buffers containing the vertices and indices were only used by the rasterization pipeline. The ray tracing Originally the buffers containing the vertices and indices were only used by the rasterization pipeline.
will need to use those buffers as storage buffers. We update the usage of the buffers in `loadModel`: The ray tracing will need to use those buffers as storage buffers (`VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT`),
the address to those buffers are needed to fill the `VkAccelerationStructureGeometryTrianglesDataKHR` structure,
and because they are use for constructing the acceleration structure, they also need
the `VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR` flag.
We update the usage of the buffers in `loadModel`:
```` C ```` C
model.vertexBuffer = model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices, vkBU::eVertexBuffer | vkBU::eStorageBuffer); m_alloc.createBuffer(cmdBuf, loader.m_vertices,
model.indexBuffer = vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
m_alloc.createBuffer(cmdBuf, loader.m_indices, vkBU::eIndexBuffer | vkBU::eStorageBuffer); | vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
```` ````
!!! Note: Array of Buffers !!! Note: Array of Buffers
@ -1076,10 +1092,10 @@ void HelloVulkan::createRtPipeline()
vk::ShaderModule raygenSM = vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM = vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -1114,7 +1130,7 @@ shaders.
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); 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,
@ -1192,9 +1208,10 @@ call as a miss. Note that it is preferable to keep the recursion level as low as
formulation instead. formulation instead.
```` C ```` C
rayPipelineInfo.setMaxRecursionDepth(1); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(1); // Ray depth
rayPipelineInfo.setLayout(m_rtPipelineLayout); rayPipelineInfo.setLayout(m_rtPipelineLayout);
m_rtPipeline = m_device.createRayTracingPipelineKHR({}, rayPipelineInfo); m_rtPipeline = static_cast<const vk::Pipeline&>(
m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
```` ````
Once the pipeline has been created we discard the shader modules: Once the pipeline has been created we discard the shader modules:
@ -1279,23 +1296,29 @@ 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()); // 3 shaders: raygen, 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 baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * baseAlignment; uint32_t sbtSize = groupCount * groupSizeAligned;
```` ````
We then fetch the handles to the shader groups of the pipeline, and let the allocator allocate the device memory and We then fetch the handles to the shader groups of the pipeline, and let the allocator
copy the handles into the SBT: allocate the device memory and copy the handles into the SBT. Note that SBT buffer need the
`VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR` flag and since we will need the address
of SBT buffer, therefore the buffer need also the `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` flag.
```` C ```` C
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
// Write the handles in the SBT // Write the handles in the SBT
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, m_rtSBTBuffer = m_alloc.createBuffer(
vk::MemoryPropertyFlagBits::eHostVisible sbtSize,
| vk::MemoryPropertyFlagBits::eHostCoherent); vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddress
| vk::BufferUsageFlagBits::eShaderBindingTableKHR,
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
// Write the handles in the SBT // Write the handles in the SBT
@ -1304,7 +1327,7 @@ copy the handles into the SBT:
for(uint32_t g = 0; g < groupCount; g++) for(uint32_t g = 0; g < groupCount; g++)
{ {
memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
pData += baseAlignment; pData += groupSizeAligned;
} }
m_alloc.unmap(m_rtSBTBuffer); m_alloc.unmap(m_rtSBTBuffer);
@ -1366,12 +1389,21 @@ each shader. In our case the stride is simply the size of a shader group handle,
shader-group-specific data within the SBT, resulting in a larger stride. shader-group-specific data within the SBT, resulting in a larger stride.
```` C ```` C
vk::DeviceSize progSize = m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier // Size of a program identifier
vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer uint32_t groupSize =
vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceSize missStride = progSize; uint32_t groupStride = groupSize;
vk::DeviceSize hitGroupOffset = 2u * progSize; // Jump over the previous shaders vk::DeviceSize hitGroupSize =
vk::DeviceSize hitGroupStride = progSize; nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer),
m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
using Stride = vk::StridedDeviceAddressRegionKHR;
std::array<Stride, 4> strideAddresses{
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
Stride{sbtAddress + 3u * groupSize, hitGroupSize, hitGroupSize * 3}, // hit
Stride{0u, 0u, 0u}}; // callable
```` ````
@ -1382,18 +1414,8 @@ three parameters are equivalent to the grid size of a compute launch, and repres
we want to trace one ray per pixel, the grid size has the width and height of the output image, and a depth of 1. we want to trace one ray per pixel, the grid size has the width and height of the output image, and a depth of 1.
```` C ```` C
vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
&strideAddresses[3], //
const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset,
progSize, sbtSize};
const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset,
progSize, sbtSize};
const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset,
progSize, sbtSize};
const vk::StridedBufferRegionKHR callableShaderBindingTable;
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable,
&callableShaderBindingTable, //
m_size.width, m_size.height, 1); // m_size.width, m_size.height, 1); //
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
@ -1823,8 +1845,8 @@ The OBJ model is loaded in `main.cpp` by calling `helloVk.loadModel`. Let's load
```` C ```` C
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
```` ````
Since that model is larger, we can change the `CameraManip.setLookat` call to Since that model is larger, we can change the `CameraManip.setLookat` call to
@ -1860,7 +1882,7 @@ In the body of `createRtPipeline`, we need to define the new miss shader right a
// simply indicates that no occlusion has been found // simply indicates that no occlusion has been found
vk::ShaderModule shadowmissSM = vk::ShaderModule shadowmissSM =
nvvk::createShaderModule(m_device, nvvk::createShaderModule(m_device,
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths)); nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
```` ````
@ -1880,7 +1902,7 @@ The pipeline now has to allow shooting rays from the closest hit program, which
// hit points of the camera rays, hence a recursion level of 2. This number should be kept as low // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low
// as possible for performance reasons. Even recursive ray tracing should be flattened into a loop // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop
// in the ray generation to avoid deep recursion. // in the ray generation to avoid deep recursion.
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
```` ````
At the end of the method, we destroy the shader module for the shadow miss shader: At the end of the method, we destroy the shader module for the shadow miss shader:

View file

@ -1,31 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) SET(PROJNAME vk_${PROJNAME}_KHR)
Project(${PROJNAME}) Project(${PROJNAME})
Message(STATUS "-------------------------------") message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")
#####################################################################################
_add_project_definitions(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
SET(VULKAN_TARGET_ENV vulkan1.2) SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -44,41 +51,27 @@ foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -91,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -32,7 +32,6 @@ extern std::vector<std::string> defaultSearchPaths;
#define VMA_IMPLEMENTATION #define VMA_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "fileformats/stb_image.h" #include "fileformats/stb_image.h"
#include "obj_loader.h" #include "obj_loader.h"
@ -200,7 +199,7 @@ void HelloVulkan::updateDescriptorSet()
std::vector<vk::DescriptorImageInfo> diit; std::vector<vk::DescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.push_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
@ -234,8 +233,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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)},
@ -254,6 +253,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -280,10 +280,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices, m_alloc.createBuffer(cmdBuf, loader.m_vertices,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer = model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices, m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
@ -378,9 +380,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
std::stringstream o; std::stringstream o;
int texWidth, texHeight, texChannels; int texWidth, texHeight, texChannels;
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); 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}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -538,12 +541,16 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
void HelloVulkan::updateFrame() void HelloVulkan::updateFrame()
{ {
static nvmath::mat4f refCamMatrix; static nvmath::mat4f refCamMatrix;
static float refFov{CameraManip.getFov()};
auto& m = CameraManip.getMatrix(); const auto& m = CameraManip.getMatrix();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0) const auto fov = CameraManip.getFov();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || refFov != fov)
{ {
resetFrame(); resetFrame();
refCamMatrix = m; refCamMatrix = m;
refFov = fov;
} }
m_pushConstants.frame++; m_pushConstants.frame++;
} }

View file

@ -44,6 +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 <random> #include <random>
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -64,19 +65,17 @@ void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1; static int item = 1;
bool changed = false; bool changed = false;
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0"))
changed |= ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up;
CameraManip.getLookat(pos, eye, up);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
changed = true;
}
changed |= ImGui::RadioButton("Point", &helloVk.m_pushConstants.lightType, 0); changed |= ImGui::RadioButton("Point", &helloVk.m_pushConstants.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
changed |= ImGui::RadioButton("Spot", &helloVk.m_pushConstants.lightType, 1); changed |= ImGui::RadioButton("Spot", &helloVk.m_pushConstants.lightType, 1);
ImGui::SameLine(); ImGui::SameLine();
changed |= ImGui::RadioButton("Infinite", &helloVk.m_pushConstants.lightType, 2); changed |= ImGui::RadioButton("Infinite", &helloVk.m_pushConstants.lightType, 2);
if(helloVk.m_pushConstants.lightType < 2) if(helloVk.m_pushConstants.lightType < 2)
{ {
changed |= ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstants.lightPosition.x, changed |= ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstants.lightPosition.x,
@ -89,8 +88,8 @@ void renderUI(HelloVulkan& helloVk)
} }
if(helloVk.m_pushConstants.lightType < 2) if(helloVk.m_pushConstants.lightType < 2)
{ {
changed |= changed |= ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f,
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f, 500.f); 500.f);
} }
if(helloVk.m_pushConstants.lightType == 1) if(helloVk.m_pushConstants.lightType == 1)
{ {
@ -103,8 +102,9 @@ void renderUI(HelloVulkan& helloVk)
helloVk.m_pushConstants.lightSpotCutoff = cos(deg2rad(dCutoff)); helloVk.m_pushConstants.lightSpotCutoff = cos(deg2rad(dCutoff));
helloVk.m_pushConstants.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff)); helloVk.m_pushConstants.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff));
} }
changed |= ImGui::InputInt("Max Frames", &helloVk.m_maxFrames); }
helloVk.m_maxFrames = std::max(helloVk.m_maxFrames, 1);
changed |= ImGui::SliderInt("Max Frames", &helloVk.m_maxFrames, 1, 1000);
if(changed) if(changed)
helloVk.resetFrame(); helloVk.resetFrame();
} }
@ -134,7 +134,7 @@ int main(int argc, char** argv)
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
CameraManip.setLookat(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0)); CameraManip.setLookat({8.440, 9.041, -8.973}, {-2.462, 3.661, -0.286}, {0.000, 1.000, 0.000});
// Setup Vulkan // Setup Vulkan
if(!glfwVulkanSupported()) if(!glfwVulkanSupported())
@ -148,19 +148,16 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media NVPSystem::exePath() + "..",
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Enabling the extension feature
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature;
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef WIN32 #ifdef WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
@ -175,11 +172,17 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -199,7 +202,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -208,9 +211,9 @@ int main(int argc, char** argv)
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creating scene // Creating scene
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths), helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true),
nvmath::scale_mat4(nvmath::vec3f(0.5f)) nvmath::scale_mat4(nvmath::vec3f(0.5f))
* nvmath::translation_mat4(nvmath::vec3f(0.0f, 0.0f, 6.0f))); * nvmath::translation_mat4(nvmath::vec3f(0.0f, 0.0f, 6.0f)));
@ -222,7 +225,6 @@ int main(int argc, char** argv)
for(int n = 0; n < 50; ++n) for(int n = 0; n < 50; ++n)
{ {
ObjInstance inst; ObjInstance inst;
inst.objIndex = wusonIndex; inst.objIndex = wusonIndex;
inst.txtOffset = 0; inst.txtOffset = 0;
@ -284,14 +286,15 @@ int main(int argc, char** argv)
// Start the Dear ImGui frame // Start the Dear ImGui frame
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGui::NewFrame();
ImGuiH::Panel::Begin();
bool changed = false; bool changed = false;
// Edit 3 floats representing a color // Edit 3 floats representing a color
changed |= ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); changed |= ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
@ -304,7 +307,9 @@ int main(int argc, char** argv)
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render();
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// Start rendering the scene // Start rendering the scene
@ -357,6 +362,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
offscreen.draw(cmdBuff, helloVk.getSize()); offscreen.draw(cmdBuff, helloVk.getSize());
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

View file

@ -153,9 +153,9 @@ void Offscreen::createPipeline(vk::RenderPass& renderPass)
std::vector<std::string> paths = defaultSearchPaths; 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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_pipeline = pipelineGenerator.createPipeline(); m_pipeline = pipelineGenerator.createPipeline();

View file

@ -30,6 +30,7 @@
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvh/alignment.hpp"
#include "nvvk/shaders_vk.hpp" #include "nvvk/shaders_vk.hpp"
#include "obj_loader.h" #include "obj_loader.h"
@ -47,9 +48,10 @@ void Raytracer::setup(const vk::Device& device,
m_graphicsQueueIndex = queueFamily; m_graphicsQueueIndex = queueFamily;
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex);
m_debug.setup(device); m_debug.setup(device);
@ -69,45 +71,36 @@ void Raytracer::destroy()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Converting a OBJ primitive to the ray tracing geometry used for the BLAS
// //
nvvk::RaytracingBuilderKHR::Blas Raytracer::objectToVkGeometryKHR(const ObjModel& model) nvvk::RaytracingBuilderKHR::BlasInput Raytracer::objectToVkGeometryKHR(const ObjModel& model)
{ {
// Setting up the creation info of acceleration structure
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles
asCreate.setMaxVertexCount(model.nbVertices);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
// Building part // Building part
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj)); triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
// Setting up the build info of the acceleration // Setting up the build info of the acceleration
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
vk::AccelerationStructureBuildOffsetInfoKHR offset; vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
nvvk::RaytracingBuilderKHR::Blas blas; nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -116,18 +109,9 @@ nvvk::RaytracingBuilderKHR::Blas Raytracer::objectToVkGeometryKHR(const ObjModel
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Returning the ray tracing geometry used for the BLAS, containing all spheres // Returning the ray tracing geometry used for the BLAS, containing all spheres
// //
nvvk::RaytracingBuilderKHR::Blas Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj) nvvk::RaytracingBuilderKHR::BlasInput Raytracer::implicitToVkGeometryKHR(
const ImplInst& implicitObj)
{ {
// Setting up the creation info of acceleration structure
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eAabbs);
asCreate.setIndexType(vk::IndexType::eNoneKHR);
asCreate.setVertexFormat(vk::Format::eUndefined);
asCreate.setMaxPrimitiveCount(static_cast<uint32_t>(implicitObj.objImpl.size())); // Nb triangles
asCreate.setMaxVertexCount(0);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
vk::DeviceAddress dataAddress = m_device.getBufferAddress({implicitObj.implBuf.buffer}); vk::DeviceAddress dataAddress = m_device.getBufferAddress({implicitObj.implBuf.buffer});
vk::AccelerationStructureGeometryAabbsDataKHR aabbs; vk::AccelerationStructureGeometryAabbsDataKHR aabbs;
@ -135,21 +119,20 @@ nvvk::RaytracingBuilderKHR::Blas Raytracer::implicitToVkGeometryKHR(const ImplIn
aabbs.setStride(sizeof(ObjImplicit)); aabbs.setStride(sizeof(ObjImplicit));
// Setting up the build info of the acceleration // Setting up the build info of the acceleration
vk::AccelerationStructureGeometryKHR asGeom; VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
asGeom.setGeometryType(asCreate.geometryType); asGeom.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR;
asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit
asGeom.geometry.setAabbs(aabbs); asGeom.geometry.aabbs = aabbs;
vk::AccelerationStructureBuildOffsetInfoKHR offset; vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(static_cast<uint32_t>(implicitObj.objImpl.size())); // Nb aabb
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
nvvk::RaytracingBuilderKHR::Blas blas; nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -158,7 +141,7 @@ nvvk::RaytracingBuilderKHR::Blas Raytracer::implicitToVkGeometryKHR(const ImplIn
void Raytracer::createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& implicitObj) void Raytracer::createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& implicitObj)
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(models.size()); allBlas.reserve(models.size());
for(const auto& obj : models) for(const auto& obj : models)
{ {
@ -266,16 +249,15 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
vk::ShaderModule raygenSM = vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM = vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); 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 = vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -286,7 +268,7 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
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)); rg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(rg); m_rtShaderGroups.push_back(rg); // 0
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
@ -294,19 +276,19 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
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)); mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg); // 1
// Shadow Miss // Shadow Miss
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)); mg.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(mg); m_rtShaderGroups.push_back(mg); // 2
// Hit Group0 - Closest Hit + AnyHit // Hit Group0 - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
vk::ShaderModule ahitSM = vk::ShaderModule ahitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rahit.spv", true, paths)); 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,
@ -315,19 +297,19 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1)); hg.setClosestHitShader(static_cast<uint32_t>(stages.size() - 1));
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)); hg.setAnyHitShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); 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(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths)); nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true));
vk::ShaderModule ahit2SM = vk::ShaderModule ahit2SM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace2.rahit.spv", true, paths)); nvh::loadFile("shaders/raytrace2.rahit.spv", true, paths, true));
vk::ShaderModule rintSM = vk::ShaderModule rintSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rint.spv", true, paths)); 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,
@ -338,7 +320,7 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
hg.setAnyHitShader(static_cast<uint32_t>(stages.size() - 1)); hg.setAnyHitShader(static_cast<uint32_t>(stages.size() - 1));
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)); hg.setIntersectionShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(hg); m_rtShaderGroups.push_back(hg); // 4
} }
// Callable shaders // Callable shaders
@ -348,22 +330,23 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
vk::ShaderModule call0 = vk::ShaderModule call0 =
nvvk::createShaderModule(m_device, nvvk::createShaderModule(m_device,
nvh::loadFile("shaders/light_point.rcall.spv", true, paths)); nvh::loadFile("shaders/light_point.rcall.spv", true, paths, true));
vk::ShaderModule call1 = vk::ShaderModule call1 =
nvvk::createShaderModule(m_device, nvvk::createShaderModule(m_device,
nvh::loadFile("shaders/light_spot.rcall.spv", true, paths)); nvh::loadFile("shaders/light_spot.rcall.spv", true, paths, true));
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, true));
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)); callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); m_rtShaderGroups.push_back(callGroup); // 5
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)); callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); m_rtShaderGroups.push_back(callGroup); // 6
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)); callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
m_rtShaderGroups.push_back(callGroup); m_rtShaderGroups.push_back(callGroup); //7
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
@ -393,10 +376,10 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
rayPipelineInfo.setLayout(m_rtPipelineLayout); rayPipelineInfo.setLayout(m_rtPipelineLayout);
m_rtPipeline = m_rtPipeline = static_cast<const vk::Pipeline&>(
static_cast<const vk::Pipeline&>(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
m_device.destroy(raygenSM); m_device.destroy(raygenSM);
m_device.destroy(missSM); m_device.destroy(missSM);
@ -422,18 +405,24 @@ void Raytracer::createRtShaderBindingTable()
auto groupCount = auto groupCount =
static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, 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 baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * baseAlignment; uint32_t sbtSize = groupCount * groupSizeAligned;
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
assert(result == vk::Result::eSuccess);
// Write the handles in the SBT // Write the handles in the SBT
m_rtSBTBuffer = m_alloc->createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, m_rtSBTBuffer = m_alloc->createBuffer(
vk::MemoryPropertyFlagBits::eHostVisible sbtSize,
| vk::MemoryPropertyFlagBits::eHostCoherent); vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddress
| vk::BufferUsageFlagBits::eShaderBindingTableKHR,
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
// Write the handles in the SBT // Write the handles in the SBT
@ -442,7 +431,7 @@ void Raytracer::createRtShaderBindingTable()
for(uint32_t g = 0; g < groupCount; g++) for(uint32_t g = 0; g < groupCount; g++)
{ {
memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
pData += baseAlignment; pData += groupSizeAligned;
} }
m_alloc->unmap(m_rtSBTBuffer); m_alloc->unmap(m_rtSBTBuffer);
@ -479,27 +468,22 @@ void Raytracer::raytrace(const vk::CommandBuffer& cmdBuf,
| vk::ShaderStageFlagBits::eCallableKHR, | vk::ShaderStageFlagBits::eCallableKHR,
0, m_rtPushConstants); 0, m_rtPushConstants);
vk::DeviceSize progSize = // Size of a program identifier
m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier uint32_t groupSize =
vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen uint32_t groupStride = groupSize;
vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
vk::DeviceSize callableGroupOffset = 5u * progSize; // Jump over the previous shaders
vk::DeviceSize sbtSize = (vk::DeviceSize)m_rtShaderGroups.size() * progSize;
const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, using Stride = vk::StridedDeviceAddressRegionKHR;
progSize, sbtSize}; std::array<Stride, 4> strideAddresses{
const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
progSize, sbtSize}; Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 2}, // hit
progSize, sbtSize}; Stride{sbtAddress + 5u * groupSize, groupStride, groupSize * 3}}; // callable
const vk::StridedBufferRegionKHR callableShaderBindingTable = {
m_rtSBTBuffer.buffer, callableGroupOffset, progSize, sbtSize};
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
&callableShaderBindingTable, // &strideAddresses[3], //
size.width, size.height, 1); // size.width, size.height, 1); //
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }

View file

@ -43,8 +43,8 @@ public:
uint32_t queueFamily); uint32_t queueFamily);
void destroy(); void destroy();
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
nvvk::RaytracingBuilderKHR::Blas implicitToVkGeometryKHR(const ImplInst& implicitObj); nvvk::RaytracingBuilderKHR::BlasInput implicitToVkGeometryKHR(const ImplInst& implicitObj);
void createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& implicitObj); void createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& implicitObj);
void createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj); void createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj);
void createRtDescriptorSet(const vk::ImageView& outputImage); void createRtDescriptorSet(const vk::ImageView& outputImage);
@ -65,7 +65,7 @@ private:
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; vk::DescriptorPool m_rtDescPool;

View file

@ -3,7 +3,7 @@
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#include "raycommon.glsl" #include "raycommon.glsl"
layout(location = 0) callableDataInEXT rayLight cLight; layout(location = 3) callableDataInEXT rayLight cLight;
layout(push_constant) uniform Constants layout(push_constant) uniform Constants
{ {

View file

@ -3,7 +3,7 @@
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#include "raycommon.glsl" #include "raycommon.glsl"
layout(location = 0) callableDataInEXT rayLight cLight; layout(location = 3) callableDataInEXT rayLight cLight;
layout(push_constant) uniform Constants layout(push_constant) uniform Constants
{ {

View file

@ -3,7 +3,7 @@
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#include "raycommon.glsl" #include "raycommon.glsl"
layout(location = 0) callableDataInEXT rayLight cLight; layout(location = 3) callableDataInEXT rayLight cLight;
layout(push_constant) uniform Constants layout(push_constant) uniform Constants
{ {

View file

@ -30,7 +30,7 @@ void main()
uint seed = prd.seed; // We don't want to modify the PRD uint seed = prd.seed; // We don't want to modify the PRD
if(mat.dissolve == 0.0) if(mat.dissolve == 0.0)
ignoreIntersectionEXT(); ignoreIntersectionEXT;
else if(rnd(seed) > mat.dissolve) else if(rnd(seed) > mat.dissolve)
ignoreIntersectionEXT(); ignoreIntersectionEXT;
} }

View file

@ -36,7 +36,7 @@ layout(push_constant) uniform Constants
} }
pushC; pushC;
layout(location = 0) callableDataEXT rayLight cLight; layout(location = 3) callableDataEXT rayLight cLight;
void main() void main()
@ -97,7 +97,7 @@ void main()
cLight.outLightDistance = 10000000; cLight.outLightDistance = 10000000;
} }
#else #else
executeCallableEXT(pushC.lightType, 0); executeCallableEXT(pushC.lightType, 3);
#endif #endif
// Material of the object // Material of the object

View file

@ -26,7 +26,7 @@ void main()
uint seed = prd.seed; // We don't want to modify the PRD uint seed = prd.seed; // We don't want to modify the PRD
if(mat.dissolve == 0.0) if(mat.dissolve == 0.0)
ignoreIntersectionEXT(); ignoreIntersectionEXT;
else if(rnd(seed) > mat.dissolve) else if(rnd(seed) > mat.dissolve)
ignoreIntersectionEXT(); ignoreIntersectionEXT;
} }

View file

@ -37,7 +37,7 @@ layout(push_constant) uniform Constants
} }
pushC; pushC;
layout(location = 0) callableDataEXT rayLight cLight; layout(location = 3) callableDataEXT rayLight cLight;
void main() void main()
@ -71,7 +71,7 @@ void main()
} }
cLight.inHitPosition = worldPos; cLight.inHitPosition = worldPos;
executeCallableEXT(pushC.lightType, 0); executeCallableEXT(pushC.lightType, 3);
// Material of the object // Material of the object
WaveFrontMaterial mat = materials[nonuniformEXT(gl_InstanceCustomIndexEXT)].m[impl.matId]; WaveFrontMaterial mat = materials[nonuniformEXT(gl_InstanceCustomIndexEXT)].m[impl.matId];

View file

@ -1,30 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
Project(${PROJNAME})
Message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:")
##################################################################################### #--------------------------------------------------------------------------------------------------
_add_project_definitions(${PROJNAME}) # C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#####################################################################################
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) SET(VULKAN_TARGET_ENV vulkan1.2)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -34,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.vert" "shaders/*.vert"
"shaders/*.rchit" "shaders/*.rchit"
"shaders/*.rahit" "shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss" "shaders/*.rmiss"
"shaders/*.rgen" "shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES}) foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -88,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -174,8 +174,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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)},
@ -194,6 +194,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -293,7 +294,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
auto imgSize = vk::Extent2D(1, 1); auto imgSize = vk::Extent2D(1, 1);
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the dummy texure // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
@ -311,9 +312,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
std::stringstream o; std::stringstream o;
int texWidth, texHeight, texChannels; int texWidth, texHeight, texChannels;
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); 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}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -527,9 +529,9 @@ void HelloVulkan::createPostPipeline()
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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true),
vk::ShaderStageFlagBits::eFragment); vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline(); m_postPipeline = pipelineGenerator.createPipeline();

View file

@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "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"
@ -62,19 +63,16 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1; ImGuiH::CameraWidget();
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up;
CameraManip.getLookat(pos, eye, up);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
}
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f);
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); 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);
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -119,19 +117,16 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media NVPSystem::exePath() + "..",
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Enabling the extension feature
vk::PhysicalDeviceDescriptorIndexingFeaturesEXT indexFeature;
vk::PhysicalDeviceScalarBlockLayoutFeaturesEXT scalarFeature;
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo; nvvk::ContextCreateInfo contextInfo;
contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32 #ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
@ -143,8 +138,8 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, false, &indexFeature); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME, false, &scalarFeature); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -164,7 +159,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -173,7 +168,7 @@ int main(int argc, char** argv)
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true));
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
helloVk.createDescriptorSetLayout(); helloVk.createDescriptorSetLayout();
@ -206,13 +201,15 @@ int main(int argc, char** argv)
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render(); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// Start rendering the scene // Start rendering the scene
@ -259,6 +256,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
helloVk.drawPost(cmdBuff); helloVk.drawPost(cmdBuff);
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

View file

@ -1,32 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
Project(${PROJNAME})
Message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:")
##################################################################################### #--------------------------------------------------------------------------------------------------
_add_project_definitions(${PROJNAME}) # C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#####################################################################################
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
SET(VULKAN_TARGET_ENV vulkan1.2) SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.vert" "shaders/*.vert"
"shaders/*.rchit" "shaders/*.rchit"
"shaders/*.rahit" "shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss" "shaders/*.rmiss"
"shaders/*.rgen" "shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES}) foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -35,6 +35,7 @@ extern std::vector<std::string> defaultSearchPaths;
#include "obj_loader.h" #include "obj_loader.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "nvh/alignment.hpp"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
@ -54,6 +55,7 @@ struct CameraMatrices
nvmath::mat4f projInverse; nvmath::mat4f projInverse;
}; };
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
@ -161,7 +163,7 @@ void HelloVulkan::updateDescriptorSet()
std::vector<vk::DescriptorImageInfo> diit; std::vector<vk::DescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.push_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
@ -192,8 +194,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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)},
@ -212,6 +214,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -238,10 +241,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices, m_alloc.createBuffer(cmdBuf, loader.m_vertices,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer = model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices, m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
@ -314,7 +319,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
auto imgSize = vk::Extent2D(1, 1); auto imgSize = vk::Extent2D(1, 1);
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the dummy texure // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
@ -332,7 +337,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
std::stringstream o; std::stringstream o;
int texWidth, texHeight, texChannels; int texWidth, texHeight, texChannels;
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_uc* stbi_pixels =
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
@ -554,9 +559,9 @@ void HelloVulkan::createPostPipeline()
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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, 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();
@ -620,55 +625,49 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Converting a OBJ primitive to the ray tracing geometry used for the BLAS
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
// Setting up the creation info of acceleration structure
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles
asCreate.setMaxVertexCount(model.nbVertices);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
// Building part // Building part
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
uint32_t maxPrimitiveCount = model.nbIndices / 3;
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj)); triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
// Setting up the build info of the acceleration // Setting up the build info of the acceleration
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
// The primitive itself // The primitive itself
vk::AccelerationStructureBuildOffsetInfoKHR offset; vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(maxPrimitiveCount);
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
// Our blas is only one geometry, but could be made of many geometries // Our blas is only one geometry, but could be made of many geometries
nvvk::RaytracingBuilderKHR::Blas blas; nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
@ -680,7 +679,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod
void HelloVulkan::createBottomLevelAS() void HelloVulkan::createBottomLevelAS()
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(m_objModel.size()); allBlas.reserve(m_objModel.size());
for(const auto& obj : m_objModel) for(const auto& obj : m_objModel)
{ {
@ -766,16 +765,15 @@ void HelloVulkan::createRtPipeline()
vk::ShaderModule raygenSM = vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM = vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); 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 = vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -802,7 +800,7 @@ void HelloVulkan::createRtPipeline()
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); 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,
@ -838,10 +836,10 @@ void HelloVulkan::createRtPipeline()
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
rayPipelineInfo.setLayout(m_rtPipelineLayout); rayPipelineInfo.setLayout(m_rtPipelineLayout);
m_rtPipeline = m_rtPipeline = static_cast<const vk::Pipeline&>(
static_cast<const vk::Pipeline&>(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
m_device.destroy(raygenSM); m_device.destroy(raygenSM);
m_device.destroy(missSM); m_device.destroy(missSM);
@ -860,18 +858,23 @@ 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()); // 3 shaders: raygen, 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 baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * baseAlignment; uint32_t sbtSize = groupCount * groupSizeAligned;
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
assert(result == vk::Result::eSuccess);
// Write the handles in the SBT // Write the handles in the SBT
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, m_rtSBTBuffer = m_alloc.createBuffer(
vk::MemoryPropertyFlagBits::eHostVisible sbtSize,
| vk::MemoryPropertyFlagBits::eHostCoherent); vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddress
| vk::BufferUsageFlagBits::eShaderBindingTableKHR,
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
// Write the handles in the SBT // Write the handles in the SBT
@ -880,7 +883,7 @@ void HelloVulkan::createRtShaderBindingTable()
for(uint32_t g = 0; g < groupCount; g++) for(uint32_t g = 0; g < groupCount; g++)
{ {
memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
pData += baseAlignment; pData += groupSizeAligned;
} }
m_alloc.unmap(m_rtSBTBuffer); m_alloc.unmap(m_rtSBTBuffer);
@ -909,24 +912,21 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
| vk::ShaderStageFlagBits::eMissKHR, | vk::ShaderStageFlagBits::eMissKHR,
0, m_rtPushConstants); 0, m_rtPushConstants);
vk::DeviceSize progSize = // Size of a program identifier
m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier uint32_t groupSize =
vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen uint32_t groupStride = groupSize;
vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); using Stride = vk::StridedDeviceAddressRegionKHR;
std::array<Stride, 4> strideAddresses{
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit
Stride{0u, 0u, 0u}}; // callable
const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
progSize, sbtSize}; &strideAddresses[3], //
const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset,
progSize, sbtSize};
const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset,
progSize, sbtSize};
const vk::StridedBufferRegionKHR callableShaderBindingTable;
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable,
&callableShaderBindingTable, //
m_size.width, m_size.height, 1); // m_size.width, m_size.height, 1); //

View file

@ -134,7 +134,7 @@ public:
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
void createRtDescriptorSet(); void createRtDescriptorSet();
@ -144,7 +144,7 @@ public:
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; vk::DescriptorPool m_rtDescPool;

View file

@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "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"
@ -61,19 +62,16 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1; ImGuiH::CameraWidget();
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up;
CameraManip.getLookat(pos, eye, up);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
}
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f);
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); 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);
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -115,17 +113,16 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media NVPSystem::exePath() + "..",
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef WIN32 #ifdef WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
@ -138,8 +135,12 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
@ -165,7 +166,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -174,8 +175,8 @@ int main(int argc, char** argv)
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
@ -220,15 +221,18 @@ int main(int argc, char** argv)
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render();
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// Start rendering the scene // Start rendering the scene
@ -281,6 +285,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
helloVk.drawPost(cmdBuff); helloVk.drawPost(cmdBuff);
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

View file

@ -1,32 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
Project(${PROJNAME})
Message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:")
##################################################################################### #--------------------------------------------------------------------------------------------------
_add_project_definitions(${PROJNAME}) # C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#####################################################################################
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
SET(VULKAN_TARGET_ENV vulkan1.2) SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.vert" "shaders/*.vert"
"shaders/*.rchit" "shaders/*.rchit"
"shaders/*.rahit" "shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss" "shaders/*.rmiss"
"shaders/*.rgen" "shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES}) foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -6,7 +6,7 @@
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 implement two animation methods: animating only the transformation matrices, and animating the geometry itself. We will implement two animation methods: only the transformation matrices, and animating the geometry itself.
## Animating the Matrices ## Animating the Matrices
@ -76,13 +76,10 @@ Next, we update the buffer that describes the scene, which is used by the raster
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
genCmdBuf.submitAndWait(cmdBuf); genCmdBuf.submitAndWait(cmdBuf);
m_alloc.destroy(stagingBuffer); m_alloc.destroy(stagingBuffer);
m_rtBuilder.updateTlasMatrices(m_tlas);
m_rtBuilder.updateBlas(2);
} }
~~~~ ~~~~
:warning: **Note:** **Note:**
We could have used `cmdBuf.updateBuffer<ObjInstance>(m_sceneDesc.buffer, 0, m_objInstance)` to We could have used `cmdBuf.updateBuffer<ObjInstance>(m_sceneDesc.buffer, 0, m_objInstance)` to
update the buffer, but this function only works for buffers with less than 65,536 bytes. If we had 2000 Wuson models, this update the buffer, but this function only works for buffers with less than 65,536 bytes. If we had 2000 Wuson models, this
call wouldn't work. call wouldn't work.
@ -153,144 +150,22 @@ In the `for` loop, add at the end
The last point is to call the update at the end of the function. The last point is to call the update at the end of the function.
~~~~ C++ ~~~~ C++
m_rtBuilder.updateTlasMatrices(m_tlas); m_rtBuilder.buildTlas(m_tlas, m_rtFlags, true);
~~~~ ~~~~
![](images/animation1.gif) ![](images/animation1.gif)
### nvvk::RaytracingBuilder::updateTlasMatrices (Implementation) ### nvvk::RaytracingBuilder::buildTlas (Implementation)
We currently use `nvvk::RaytracingBuilder` to update the matrices for convenience, but We are using `nvvk::RaytracingBuilder` to update the matrices for convenience. There
this could be done more efficiently if one kept some of the buffer and memory references. Using a is only a small variation with constructing the matrices and updating them. The main
memory allocator, such as the one described in the [Many Objects Tutorial](vkrt_tuto_instances.md.htm), differences are:
could also be an alternative for avoiding multiple reallocations. Here's the implementation of `nvvk::RaytracingBuilder::updateTlasMatrices`.
#### Staging Buffer * The `VkAccelerationStructureBuildGeometryInfoKHR` mode will be set to `VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR`
* We will **not** create the acceleration structure, but reuse it.
* The source and destination of `VkAccelerationStructureCreateInfoKHR` will both use the previously created acceleration structure.
As in the rasterizer, the data needs to be staged before it can be copied to the buffer used for What is happening is the buffer containing all matrices will be updated and the `vkCmdBuildAccelerationStructuresKHR` will update the acceleration in place.
building the TLAS.
~~~~ C++
void updateTlasMatrices(const std::vector<Instance>& instances)
{
VkDeviceSize bufferSize = instances.size() * sizeof(VkAccelerationStructureInstanceKHR);
// Create a staging buffer on the host to upload the new instance data
nvvkBuffer stagingBuffer = m_alloc.createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
#if defined(ALLOC_VMA)
VmaMemoryUsage::VMA_MEMORY_USAGE_CPU_TO_GPU
#else
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
#endif
);
// Copy the instance data into the staging buffer
auto* gInst = reinterpret_cast<VkAccelerationStructureInstanceKHR*>(m_alloc.map(stagingBuffer));
for(int i = 0; i < instances.size(); i++)
{
gInst[i] = instanceToVkGeometryInstanceKHR(instances[i]);
}
m_alloc.unmap(stagingBuffer);
~~~~
#### Scratch Memory
Building the TLAS always needs scratch memory, and so we need to request it. If
we hadn't set the `eAllowUpdate` flag, the returned size would be zero and the rest of the code
would fail.
~~~~ C++
// Compute the amount of scratch memory required by the AS builder to update
VkAccelerationStructureMemoryRequirementsInfoKHR memoryRequirementsInfo{
VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR};
memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_KHR;
memoryRequirementsInfo.accelerationStructure = m_tlas.as.accel;
memoryRequirementsInfo.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR;
VkMemoryRequirements2 reqMem{VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2};
vkGetAccelerationStructureMemoryRequirementsKHR(m_device, &memoryRequirementsInfo, &reqMem);
VkDeviceSize scratchSize = reqMem.memoryRequirements.size;
// Allocate the scratch buffer
nvvkBuffer scratchBuffer =
m_alloc.createBuffer(scratchSize, VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
VkBufferDeviceAddressInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
bufferInfo.buffer = scratchBuffer.buffer;
VkDeviceAddress scratchAddress = vkGetBufferDeviceAddress(m_device, &bufferInfo);
~~~~
#### Update the Buffer
In a new command buffer, we copy the staging buffer to the device buffer and
add a barrier to make sure the memory finishes copying before updating the TLAS.
~~~~ C++
// Update the instance buffer on the device side and build the TLAS
nvvk::CommandPool genCmdBuf(m_device, m_queueIndex);
VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
VkBufferCopy region{0, 0, bufferSize};
vkCmdCopyBuffer(cmdBuf, stagingBuffer.buffer, m_instBuffer.buffer, 1, &region);
//VkBufferDeviceAddressInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
bufferInfo.buffer = m_instBuffer.buffer;
VkDeviceAddress instanceAddress = vkGetBufferDeviceAddress(m_device, &bufferInfo);
// Make sure the copy of the instance buffer are copied before triggering the
// acceleration structure build
VkMemoryBarrier barrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
0, 1, &barrier, 0, nullptr, 0, nullptr);
~~~~
#### Update Acceleration Structure
We update the TLAS using the same acceleration structure for source and
destination to update it in place, and using the VK_TRUE parameter to trigger the update.
~~~~ C++
VkAccelerationStructureGeometryDataKHR geometry{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR};
geometry.instances.arrayOfPointers = VK_FALSE;
geometry.instances.data.deviceAddress = instanceAddress;
VkAccelerationStructureGeometryKHR topASGeometry{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
topASGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
topASGeometry.geometry = geometry;
const VkAccelerationStructureGeometryKHR* pGeometry = &topASGeometry;
VkAccelerationStructureBuildGeometryInfoKHR topASInfo{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR};
topASInfo.flags = m_tlas.flags;
topASInfo.update = VK_TRUE;
topASInfo.srcAccelerationStructure = m_tlas.as.accel;
topASInfo.dstAccelerationStructure = m_tlas.as.accel;
topASInfo.geometryArrayOfPointers = VK_FALSE;
topASInfo.geometryCount = 1;
topASInfo.ppGeometries = &pGeometry;
topASInfo.scratchData.deviceAddress = scratchAddress;
uint32_t nbInstances = (uint32_t)instances.size();
VkAccelerationStructureBuildOffsetInfoKHR buildOffsetInfo = {nbInstances, 0, 0, 0};
const VkAccelerationStructureBuildOffsetInfoKHR* pBuildOffsetInfo = &buildOffsetInfo;
// Build the TLAS
// Update the acceleration structure. Note the VK_TRUE parameter to trigger the update,
// and the existing TLAS being passed and updated in place
vkCmdBuildAccelerationStructureKHR(cmdBuf, 1, &topASInfo, &pBuildOffsetInfo);
genCmdBuf.submitAndWait(cmdBuf);
~~~~
#### Cleanup
Finally, we release all temporary buffers.
~~~~ C++
m_alloc.destroy(scratchBuffer);
m_alloc.destroy(stagingBuffer);
}
~~~~
## BLAS Animation ## BLAS Animation
@ -484,14 +359,15 @@ In `main.cpp`, after the other resource creation functions, add the creation fun
helloVk.createCompPipelines(); helloVk.createCompPipelines();
~~~~ ~~~~
In the rendering loop, after the call to `animationInstances`, call the object animation function. In the rendering loop, **before** the call to `animationInstances`, call the object animation function.
~~~~ C++ ~~~~ C++
helloVk.animationObject(diff.count()); helloVk.animationObject(diff.count());
~~~~ ~~~~
:warning: **Note:** At this point, the object should be animated when using the rasterizer, but should still be immobile when using the ray tracer. **Note:** Always update the TLAS when BLAS are modified. This will make sure that the TLAS knows about the new bounding box sizes.
**Note:** At this point, the object should be animated when using the rasterizer, but should still be immobile when using the ray tracer.
## Update BLAS ## Update BLAS

View file

@ -39,6 +39,7 @@ extern std::vector<std::string> defaultSearchPaths;
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/pipeline_vk.hpp" #include "nvvk/pipeline_vk.hpp"
#include "nvh/alignment.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
@ -162,7 +163,7 @@ void HelloVulkan::updateDescriptorSet()
std::vector<vk::DescriptorImageInfo> diit; std::vector<vk::DescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.push_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
@ -193,8 +194,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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)},
@ -212,6 +213,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -238,10 +240,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices, m_alloc.createBuffer(cmdBuf, loader.m_vertices,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer = model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices, m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
@ -314,7 +318,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
auto imgSize = vk::Extent2D(1, 1); auto imgSize = vk::Extent2D(1, 1);
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the dummy texure // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
@ -332,9 +336,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
std::stringstream o; std::stringstream o;
int texWidth, texHeight, texChannels; int texWidth, texHeight, texChannels;
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); 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}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -560,9 +565,9 @@ void HelloVulkan::createPostPipeline()
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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, 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();
@ -626,49 +631,43 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Converting a OBJ primitive to the ray tracing geometry used for the BLAS
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles
asCreate.setMaxVertexCount(model.nbVertices);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj)); triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
// Consider the geometry opaque for optimization
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
vk::AccelerationStructureBuildOffsetInfoKHR offset; vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
nvvk::RaytracingBuilderKHR::Blas blas; nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -701,8 +700,10 @@ void HelloVulkan::createTopLevelAS()
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
m_tlas.emplace_back(rayInst); m_tlas.emplace_back(rayInst);
} }
m_rtBuilder.buildTlas(m_tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace
| vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate); m_rtFlags = vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace
| vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate;
m_rtBuilder.buildTlas(m_tlas, m_rtFlags);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -762,16 +763,15 @@ void HelloVulkan::createRtPipeline()
vk::ShaderModule raygenSM = vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM = vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); 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 = vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -798,7 +798,7 @@ void HelloVulkan::createRtPipeline()
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); 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,
@ -833,10 +833,10 @@ void HelloVulkan::createRtPipeline()
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
rayPipelineInfo.setLayout(m_rtPipelineLayout); rayPipelineInfo.setLayout(m_rtPipelineLayout);
m_rtPipeline = m_rtPipeline = static_cast<const vk::Pipeline&>(
static_cast<const vk::Pipeline&>(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
m_device.destroy(raygenSM); m_device.destroy(raygenSM);
m_device.destroy(missSM); m_device.destroy(missSM);
@ -855,18 +855,23 @@ 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()); // 3 shaders: raygen, 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 baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * baseAlignment; uint32_t sbtSize = groupCount * groupSizeAligned;
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
assert(result == vk::Result::eSuccess);
// Write the handles in the SBT // Write the handles in the SBT
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, m_rtSBTBuffer = m_alloc.createBuffer(
vk::MemoryPropertyFlagBits::eHostVisible sbtSize,
| vk::MemoryPropertyFlagBits::eHostCoherent); vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddress
| vk::BufferUsageFlagBits::eShaderBindingTableKHR,
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
// Write the handles in the SBT // Write the handles in the SBT
@ -875,7 +880,7 @@ void HelloVulkan::createRtShaderBindingTable()
for(uint32_t g = 0; g < groupCount; g++) for(uint32_t g = 0; g < groupCount; g++)
{ {
memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
pData += baseAlignment; pData += groupSizeAligned;
} }
m_alloc.unmap(m_rtSBTBuffer); m_alloc.unmap(m_rtSBTBuffer);
@ -904,23 +909,22 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
| vk::ShaderStageFlagBits::eMissKHR, | vk::ShaderStageFlagBits::eMissKHR,
0, m_rtPushConstants); 0, m_rtPushConstants);
vk::DeviceSize progSize =
m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier
vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer
vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen
vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders
vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size();
// m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... // Size of a program identifier
const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, uint32_t groupSize =
progSize, sbtSize}; nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, uint32_t groupStride = groupSize;
progSize, sbtSize}; vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset,
progSize, sbtSize}; using Stride = vk::StridedDeviceAddressRegionKHR;
const vk::StridedBufferRegionKHR callableShaderBindingTable; std::array<Stride, 4> strideAddresses{
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
&callableShaderBindingTable, // Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit
Stride{0u, 0u, 0u}}; // callable
cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
&strideAddresses[3], //
m_size.width, m_size.height, 1); // m_size.width, m_size.height, 1); //
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
@ -966,7 +970,7 @@ void HelloVulkan::animationInstances(float time)
genCmdBuf.submitAndWait(cmdBuf); genCmdBuf.submitAndWait(cmdBuf);
m_alloc.destroy(stagingBuffer); m_alloc.destroy(stagingBuffer);
m_rtBuilder.updateTlasMatrices(m_tlas); m_rtBuilder.buildTlas(m_tlas, m_rtFlags, true);
} }
void HelloVulkan::animationObject(float time) void HelloVulkan::animationObject(float time)
@ -1016,9 +1020,8 @@ void HelloVulkan::createCompPipelines()
m_compPipelineLayout = m_device.createPipelineLayout(layout_info); m_compPipelineLayout = m_device.createPipelineLayout(layout_info);
vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout}; vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout};
computePipelineCreateInfo.stage = computePipelineCreateInfo.stage = nvvk::createShaderStageInfo(
nvvk::createShaderStageInfo(m_device, m_device, nvh::loadFile("shaders/anim.comp.spv", true, defaultSearchPaths, true),
nvh::loadFile("shaders/anim.comp.spv", true, defaultSearchPaths),
VK_SHADER_STAGE_COMPUTE_BIT); VK_SHADER_STAGE_COMPUTE_BIT);
m_compPipeline = static_cast<const vk::Pipeline&>( m_compPipeline = static_cast<const vk::Pipeline&>(
m_device.createComputePipeline({}, computePipelineCreateInfo)); m_device.createComputePipeline({}, computePipelineCreateInfo));

View file

@ -133,7 +133,7 @@ public:
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
void createRtDescriptorSet(); void createRtDescriptorSet();
@ -143,7 +143,7 @@ public:
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; vk::DescriptorPool m_rtDescPool;
@ -155,7 +155,7 @@ public:
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
std::vector<nvvk::RaytracingBuilderKHR::Instance> m_tlas; std::vector<nvvk::RaytracingBuilderKHR::Instance> m_tlas;
std::vector<nvvk::RaytracingBuilderKHR::Blas> m_blas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> m_blas;
struct RtPushConstant struct RtPushConstant
{ {
@ -180,4 +180,6 @@ public:
vk::DescriptorSet m_compDescSet; vk::DescriptorSet m_compDescSet;
vk::Pipeline m_compPipeline; vk::Pipeline m_compPipeline;
vk::PipelineLayout m_compPipelineLayout; vk::PipelineLayout m_compPipelineLayout;
vk::BuildAccelerationStructureFlagsKHR m_rtFlags;
}; };

View file

@ -36,6 +36,7 @@
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "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"
@ -62,19 +63,16 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1; ImGuiH::CameraWidget();
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up;
CameraManip.getLookat(pos, eye, up);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
}
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f);
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); 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);
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -116,19 +114,16 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media NVPSystem::exePath() + "..",
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Enabling the extension feature
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature;
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32 #ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
@ -143,11 +138,16 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -167,7 +167,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -176,13 +176,13 @@ int main(int argc, char** argv)
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths), helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true),
nvmath::scale_mat4(nvmath::vec3f(2.f, 1.f, 2.f))); nvmath::scale_mat4(nvmath::vec3f(2.f, 1.f, 2.f)));
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true));
HelloVulkan::ObjInstance inst = helloVk.m_objInstance.back(); HelloVulkan::ObjInstance inst = helloVk.m_objInstance.back();
for(int i = 0; i < 5; i++) for(int i = 0; i < 5; i++)
helloVk.m_objInstance.push_back(inst); helloVk.m_objInstance.push_back(inst);
helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true));
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
@ -232,21 +232,23 @@ int main(int argc, char** argv)
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render(); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// #VK_animation // #VK_animation
std::chrono::duration<float> diff = std::chrono::system_clock::now() - start; std::chrono::duration<float> diff = std::chrono::system_clock::now() - start;
helloVk.animationInstances(diff.count());
helloVk.animationObject(diff.count()); helloVk.animationObject(diff.count());
helloVk.animationInstances(diff.count());
// Start rendering the scene // Start rendering the scene
helloVk.prepareFrame(); helloVk.prepareFrame();
@ -298,6 +300,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
helloVk.drawPost(cmdBuff); helloVk.drawPost(cmdBuff);
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

View file

@ -1,32 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
Project(${PROJNAME})
Message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:")
##################################################################################### #--------------------------------------------------------------------------------------------------
_add_project_definitions(${PROJNAME}) # C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#####################################################################################
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
SET(VULKAN_TARGET_ENV vulkan1.2) SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.vert" "shaders/*.vert"
"shaders/*.rchit" "shaders/*.rchit"
"shaders/*.rahit" "shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss" "shaders/*.rmiss"
"shaders/*.rgen" "shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES}) foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -17,7 +17,7 @@ The any hit shader can be useful for discarding intersections, such as for alpha
used for simple transparency. In this example we will show what is needed to do to add this shader type and to create a used for simple transparency. In this example we will show what is needed to do to add this shader type and to create a
transparency effect. transparency effect.
:warning: **Note:** **Note:**
This example is based on many elements from the [Antialiasing Tutorial](vkrt_tuto_jitter_cam.md.htm). This example is based on many elements from the [Antialiasing Tutorial](vkrt_tuto_jitter_cam.md.htm).
@ -49,7 +49,7 @@ layout(binding = 1, set = 1, scalar) buffer MatColorBufferObject { WaveFrontMate
// clang-format on // clang-format on
~~~~ ~~~~
:warning: **Note:** **Note:**
You can find the source of `random.glsl` in the Antialiasing Tutorial [here](../ray_tracing_jitter_cam/README.md#toc1.1). You can find the source of `random.glsl` in the Antialiasing Tutorial [here](../ray_tracing_jitter_cam/README.md#toc1.1).
@ -205,11 +205,11 @@ uint flags = gl_RayFlagsSkipClosestHitShaderEXT;
For a more interesting scene, you can replace the `helloVk.loadModel` calls in `main()` with the following scene: For a more interesting scene, you can replace the `helloVk.loadModel` calls in `main()` with the following scene:
~~~~ C++ ~~~~ C++
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths), helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true),
nvmath::scale_mat4(nvmath::vec3f(1.5f)) nvmath::scale_mat4(nvmath::vec3f(1.5f))
* nvmath::translation_mat4(nvmath::vec3f(0.0f, 1.0f, 0.0f))); * nvmath::translation_mat4(nvmath::vec3f(0.0f, 1.0f, 0.0f)));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
~~~~ ~~~~
## OBJ Materials ## OBJ Materials
@ -259,7 +259,7 @@ And we need to add the following to the ray tracing pipeline, a copy of the prev
Create two new files `raytrace_0.ahit` and `raytrace_1.ahit`, and rename `raytrace.ahit` to `raytrace_ahit.glsl` Create two new files `raytrace_0.ahit` and `raytrace_1.ahit`, and rename `raytrace.ahit` to `raytrace_ahit.glsl`
:warning: **Note:** **Note:**
Cmake need to be re-run to add the new files to the project. Cmake need to be re-run to add the new files to the project.
In `raytrace_0.ahit` add the following code In `raytrace_0.ahit` add the following code
@ -390,7 +390,7 @@ m_rtShaderGroups.push_back(hg);
At the end of the function, delete the shader module `ahit1SM`. At the end of the function, delete the shader module `ahit1SM`.
:warning: **Note:** Re-Run **Note:** Re-Run
Everything should work as before, but now it does it right. Everything should work as before, but now it does it right.

View file

@ -39,6 +39,7 @@ extern std::vector<std::string> defaultSearchPaths;
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/pipeline_vk.hpp" #include "nvvk/pipeline_vk.hpp"
#include "nvh/alignment.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
@ -165,7 +166,7 @@ void HelloVulkan::updateDescriptorSet()
std::vector<vk::DescriptorImageInfo> diit; std::vector<vk::DescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.push_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
@ -196,8 +197,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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)},
@ -215,6 +216,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -241,10 +243,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices, m_alloc.createBuffer(cmdBuf, loader.m_vertices,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer = model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices, m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
@ -317,7 +321,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
auto imgSize = vk::Extent2D(1, 1); auto imgSize = vk::Extent2D(1, 1);
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the dummy texure // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
@ -335,9 +339,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
std::stringstream o; std::stringstream o;
int texWidth, texHeight, texChannels; int texWidth, texHeight, texChannels;
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); 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}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -556,9 +561,9 @@ void HelloVulkan::createPostPipeline()
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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, 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();
@ -622,50 +627,43 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Converting a OBJ primitive to the ray tracing geometry used for the BLAS
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles
asCreate.setMaxVertexCount(model.nbVertices);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj)); triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // Avoid double hits asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // Avoid double hits
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
vk::AccelerationStructureBuildOffsetInfoKHR offset; vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(model.nbIndices / 3);
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
nvvk::RaytracingBuilderKHR::Blas blas; nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -673,7 +671,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod
void HelloVulkan::createBottomLevelAS() void HelloVulkan::createBottomLevelAS()
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(m_objModel.size()); allBlas.reserve(m_objModel.size());
for(const auto& obj : m_objModel) for(const auto& obj : m_objModel)
{ {
@ -759,16 +757,15 @@ void HelloVulkan::createRtPipeline()
vk::ShaderModule raygenSM = vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM = vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); 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 = vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -796,10 +793,10 @@ void HelloVulkan::createRtPipeline()
// Payload 0 // Payload 0
vk::ShaderModule chitSM = vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
vk::ShaderModule ahitSM = vk::ShaderModule ahitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rahit.spv", true, paths)); 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};
@ -812,7 +809,7 @@ void HelloVulkan::createRtPipeline()
// Payload 1 // Payload 1
vk::ShaderModule ahit1SM = 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, true));
hg.setClosestHitShader(VK_SHADER_UNUSED_KHR); // Not used by shadow (skipped) hg.setClosestHitShader(VK_SHADER_UNUSED_KHR); // Not used by shadow (skipped)
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)); hg.setAnyHitShader(static_cast<uint32_t>(stages.size() - 1));
@ -843,9 +840,9 @@ void HelloVulkan::createRtPipeline()
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
rayPipelineInfo.setLayout(m_rtPipelineLayout); rayPipelineInfo.setLayout(m_rtPipelineLayout);
m_rtPipeline = m_device.createRayTracingPipelineKHR({}, rayPipelineInfo).value; m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value;
m_device.destroy(raygenSM); m_device.destroy(raygenSM);
m_device.destroy(missSM); m_device.destroy(missSM);
@ -866,18 +863,23 @@ 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()); // 3 shaders: raygen, 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 baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * baseAlignment; uint32_t sbtSize = groupCount * groupSizeAligned;
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
assert(result == vk::Result::eSuccess);
// Write the handles in the SBT // Write the handles in the SBT
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, m_rtSBTBuffer = m_alloc.createBuffer(
vk::MemoryPropertyFlagBits::eHostVisible sbtSize,
| vk::MemoryPropertyFlagBits::eHostCoherent); vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR
| vk::BufferUsageFlagBits::eShaderBindingTableKHR,
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
// Write the handles in the SBT // Write the handles in the SBT
@ -886,7 +888,7 @@ void HelloVulkan::createRtShaderBindingTable()
for(uint32_t g = 0; g < groupCount; g++) for(uint32_t g = 0; g < groupCount; g++)
{ {
memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
pData += baseAlignment; pData += groupSizeAligned;
} }
m_alloc.unmap(m_rtSBTBuffer); m_alloc.unmap(m_rtSBTBuffer);
@ -919,24 +921,23 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
| vk::ShaderStageFlagBits::eMissKHR, | vk::ShaderStageFlagBits::eMissKHR,
0, m_rtPushConstants); 0, m_rtPushConstants);
vk::DeviceSize progSize = // Size of a program identifier
m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier uint32_t groupSize =
vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen uint32_t groupStride = groupSize;
vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size();
// m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... using Stride = vk::StridedDeviceAddressRegionKHR;
const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, std::array<Stride, 4> strideAddresses{
progSize, sbtSize}; Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
progSize, sbtSize}; Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit
const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, Stride{0u, 0u, 0u}}; // callable
progSize, sbtSize};
const vk::StridedBufferRegionKHR callableShaderBindingTable; cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, &strideAddresses[3], //
&callableShaderBindingTable, // m_size.width, m_size.height,
m_size.width, m_size.height, 1); // 1); //
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
@ -949,12 +950,16 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
void HelloVulkan::updateFrame() void HelloVulkan::updateFrame()
{ {
static nvmath::mat4f refCamMatrix; static nvmath::mat4f refCamMatrix;
static float refFov{CameraManip.getFov()};
auto& m = CameraManip.getMatrix(); const auto& m = CameraManip.getMatrix();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0) const auto fov = CameraManip.getFov();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || refFov != fov)
{ {
resetFrame(); resetFrame();
refCamMatrix = m; refCamMatrix = m;
refFov = fov;
} }
m_rtPushConstants.frame++; m_rtPushConstants.frame++;
} }

View file

@ -133,7 +133,7 @@ public:
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
void createRtDescriptorSet(); void createRtDescriptorSet();
@ -144,7 +144,7 @@ public:
void resetFrame(); void resetFrame();
void updateFrame(); void updateFrame();
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; vk::DescriptorPool m_rtDescPool;

View file

@ -36,6 +36,7 @@
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "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"
@ -61,19 +62,16 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1; ImGuiH::CameraWidget();
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up;
CameraManip.getLookat(pos, eye, up);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
}
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f);
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); 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);
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -115,19 +113,16 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media NVPSystem::exePath() + "..",
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Enabling the extension feature
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature;
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef WIN32 #ifdef WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
@ -141,8 +136,15 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
@ -166,7 +168,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -175,11 +177,11 @@ int main(int argc, char** argv)
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths), helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true),
nvmath::scale_mat4(nvmath::vec3f(1.5f)) nvmath::scale_mat4(nvmath::vec3f(1.5f))
* nvmath::translation_mat4(nvmath::vec3f(0.0f, 1.0f, 0.0f))); * nvmath::translation_mat4(nvmath::vec3f(0.0f, 1.0f, 0.0f)));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
@ -224,15 +226,17 @@ int main(int argc, char** argv)
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render(); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// Start rendering the scene // Start rendering the scene
@ -285,6 +289,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
helloVk.drawPost(cmdBuff); helloVk.drawPost(cmdBuff);
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

View file

@ -35,7 +35,7 @@ void main()
return; return;
if(mat.dissolve == 0.0) if(mat.dissolve == 0.0)
ignoreIntersectionEXT(); ignoreIntersectionEXT;
else if(rnd(prd.seed) > mat.dissolve) else if(rnd(prd.seed) > mat.dissolve)
ignoreIntersectionEXT(); ignoreIntersectionEXT;
} }

View file

@ -39,7 +39,7 @@ void main()
return; return;
if(mat.dissolve == 0.0) if(mat.dissolve == 0.0)
ignoreIntersectionEXT(); ignoreIntersectionEXT;
else if(rnd(prd.seed) > mat.dissolve) else if(rnd(prd.seed) > mat.dissolve)
ignoreIntersectionEXT(); ignoreIntersectionEXT;
} }

View file

@ -1,32 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
Project(${PROJNAME})
Message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:")
##################################################################################### #--------------------------------------------------------------------------------------------------
_add_project_definitions(${PROJNAME}) # C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#####################################################################################
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
SET(VULKAN_TARGET_ENV vulkan1.2) SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -36,6 +42,7 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.vert" "shaders/*.vert"
"shaders/*.rchit" "shaders/*.rchit"
"shaders/*.rahit" "shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss" "shaders/*.rmiss"
"shaders/*.rgen" "shaders/*.rgen"
"shaders/*.rcall" "shaders/*.rcall"
@ -44,41 +51,27 @@ foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -91,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -101,9 +101,9 @@ m_device.destroy(call2);
Here are the source of all shaders Here are the source of all shaders
* [light_point.rcall](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/blob/master/ray_tracing_callable/shaders/light_point.rcall) * [light_point.rcall](shaders/light_point.rcall)
* [light_spot.rcall](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/blob/master/ray_tracing_callable/shaders/light_spot.rcall) * [light_spot.rcall](shaders/light_spot.rcall)
* [light_inf.rcall](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/blob/master/ray_tracing_callable/shaders/light_inf.rcall) * [light_inf.rcall](shaders/light_inf.rcall)
### Passing Callable to traceRaysKHR ### Passing Callable to traceRaysKHR
@ -116,18 +116,18 @@ In `HelloVulkan::raytrace()`, we have to tell where the callable shader starts.
Therefore, the callable starts at `4 * progSize` Therefore, the callable starts at `4 * progSize`
~~~~ C++ ~~~~ C++
vk::DeviceSize callableGroupOffset = 4u * progSize; // Jump over the previous shaders std::array<stride, 4> strideAddresses{
vk::DeviceSize callableGroupStride = progSize; stride{sbtAddress + 0u * progSize, progSize, progSize * 1}, // raygen
stride{sbtAddress + 1u * progSize, progSize, progSize * 2}, // miss
stride{sbtAddress + 3u * progSize, progSize, progSize * 1}, // hit
stride{sbtAddress + 4u * progSize, progSize, progSize * 1}}; // callable
~~~~ ~~~~
Then we can call `traceRaysKHR` Then we can call `traceRaysKHR`
~~~~ C++ ~~~~ C++
const vk::StridedBufferRegionKHR callableShaderBindingTable = { cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
m_rtSBTBuffer.buffer, callableGroupOffset, progSize, sbtSize}; &strideAddresses[3], //
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable,
&callableShaderBindingTable, //
m_size.width, m_size.height, 1); // m_size.width, m_size.height, 1); //
~~~~ ~~~~

View file

@ -39,6 +39,7 @@ extern std::vector<std::string> defaultSearchPaths;
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/pipeline_vk.hpp" #include "nvvk/pipeline_vk.hpp"
#include "nvh/alignment.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
@ -162,7 +163,7 @@ void HelloVulkan::updateDescriptorSet()
std::vector<vk::DescriptorImageInfo> diit; std::vector<vk::DescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.push_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
@ -193,8 +194,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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)},
@ -212,6 +213,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -238,10 +240,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices, m_alloc.createBuffer(cmdBuf, loader.m_vertices,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer = model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices, m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
@ -314,7 +318,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
auto imgSize = vk::Extent2D(1, 1); auto imgSize = vk::Extent2D(1, 1);
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the dummy texure // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
@ -332,9 +336,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
std::stringstream o; std::stringstream o;
int texWidth, texHeight, texChannels; int texWidth, texHeight, texChannels;
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); 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}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -553,9 +558,9 @@ void HelloVulkan::createPostPipeline()
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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, 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();
@ -619,47 +624,46 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Converting a OBJ primitive to the ray tracing geometry used for the BLAS
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
nvvk::RaytracingBuilderKHR::Blas blas; nvvk::RaytracingBuilderKHR::BlasInput blas;
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles
asCreate.setMaxVertexCount(model.nbVertices);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj)); triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
// Consider the geometry opaque for optimization // Consider the geometry opaque for optimization
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
vk::AccelerationStructureBuildOffsetInfoKHR offset;
vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(model.nbIndices / 3);
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -667,7 +671,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod
void HelloVulkan::createBottomLevelAS() void HelloVulkan::createBottomLevelAS()
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(m_objModel.size()); allBlas.reserve(m_objModel.size());
for(const auto& obj : m_objModel) for(const auto& obj : m_objModel)
{ {
@ -753,16 +757,15 @@ void HelloVulkan::createRtPipeline()
vk::ShaderModule raygenSM = vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM = vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); 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 = vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -789,7 +792,7 @@ void HelloVulkan::createRtPipeline()
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); 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,
@ -805,12 +808,13 @@ void HelloVulkan::createRtPipeline()
vk::ShaderModule call0 = vk::ShaderModule call0 =
nvvk::createShaderModule(m_device, nvvk::createShaderModule(m_device,
nvh::loadFile("shaders/light_point.rcall.spv", true, paths)); nvh::loadFile("shaders/light_point.rcall.spv", true, paths, true));
vk::ShaderModule call1 = vk::ShaderModule call1 =
nvvk::createShaderModule(m_device, nvvk::createShaderModule(m_device,
nvh::loadFile("shaders/light_spot.rcall.spv", true, paths)); nvh::loadFile("shaders/light_spot.rcall.spv", true, paths, true));
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, true));
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)); callGroup.setGeneralShader(static_cast<uint32_t>(stages.size() - 1));
@ -850,10 +854,10 @@ void HelloVulkan::createRtPipeline()
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
rayPipelineInfo.setLayout(m_rtPipelineLayout); rayPipelineInfo.setLayout(m_rtPipelineLayout);
m_rtPipeline = m_rtPipeline = static_cast<const vk::Pipeline&>(
static_cast<const vk::Pipeline&>(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
m_device.destroy(raygenSM); m_device.destroy(raygenSM);
m_device.destroy(missSM); m_device.destroy(missSM);
@ -875,18 +879,23 @@ 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()); // 3 shaders: raygen, 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 baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * baseAlignment; uint32_t sbtSize = groupCount * groupSizeAligned;
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
assert(result == vk::Result::eSuccess);
// Write the handles in the SBT // Write the handles in the SBT
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, m_rtSBTBuffer = m_alloc.createBuffer(
vk::MemoryPropertyFlagBits::eHostVisible sbtSize,
| vk::MemoryPropertyFlagBits::eHostCoherent); vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR
| vk::BufferUsageFlagBits::eShaderBindingTableKHR,
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
// Write the handles in the SBT // Write the handles in the SBT
@ -895,7 +904,7 @@ void HelloVulkan::createRtShaderBindingTable()
for(uint32_t g = 0; g < groupCount; g++) for(uint32_t g = 0; g < groupCount; g++)
{ {
memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
pData += baseAlignment; pData += groupSizeAligned;
} }
m_alloc.unmap(m_rtSBTBuffer); m_alloc.unmap(m_rtSBTBuffer);
@ -928,28 +937,23 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
| vk::ShaderStageFlagBits::eCallableKHR, | vk::ShaderStageFlagBits::eCallableKHR,
0, m_rtPushConstants); 0, m_rtPushConstants);
vk::DeviceSize progSize = // Size of a program identifier
m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier uint32_t groupSize =
vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen uint32_t groupStride = groupSize;
vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
vk::DeviceSize hitGroupStride = progSize;
vk::DeviceSize callableGroupOffset = 4u * progSize; // Jump over the previous shaders
vk::DeviceSize callableGroupStride = progSize;
vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size();
const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, using Stride = vk::StridedDeviceAddressRegionKHR;
progSize, sbtSize}; std::array<Stride, 4> strideAddresses{
const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
progSize, sbtSize}; Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit
progSize, sbtSize}; Stride{sbtAddress + 4u * groupSize, groupStride, groupSize * 1}}; // callable
const vk::StridedBufferRegionKHR callableShaderBindingTable = {
m_rtSBTBuffer.buffer, callableGroupOffset, progSize, sbtSize};
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
&callableShaderBindingTable, // &strideAddresses[3], //
m_size.width, m_size.height, 1); // m_size.width, m_size.height, 1); //
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }

View file

@ -137,7 +137,7 @@ public:
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
void createRtDescriptorSet(); void createRtDescriptorSet();
@ -147,7 +147,7 @@ public:
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; vk::DescriptorPool m_rtDescPool;

View file

@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "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"
@ -61,19 +62,15 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1; ImGuiH::CameraWidget();
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) if(ImGui::CollapsingHeader("Light", ImGuiTreeNodeFlags_DefaultOpen))
{ {
nvmath::vec3f pos, eye, up;
CameraManip.getLookat(pos, eye, up);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
}
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Spot", &helloVk.m_pushConstant.lightType, 1); ImGui::RadioButton("Spot", &helloVk.m_pushConstant.lightType, 1);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 2); ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 2);
if(helloVk.m_pushConstant.lightType < 2) if(helloVk.m_pushConstant.lightType < 2)
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
if(helloVk.m_pushConstant.lightType > 0) if(helloVk.m_pushConstant.lightType > 0)
@ -91,6 +88,7 @@ void renderUI(HelloVulkan& helloVk)
helloVk.m_pushConstant.lightSpotCutoff = cos(deg2rad(dCutoff)); helloVk.m_pushConstant.lightSpotCutoff = cos(deg2rad(dCutoff));
helloVk.m_pushConstant.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff)); helloVk.m_pushConstant.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff));
} }
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -132,19 +130,16 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media NVPSystem::exePath() + "..",
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Enabling the extension feature
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature;
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32 #ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, false); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, false);
@ -159,11 +154,17 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -183,7 +184,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -192,8 +193,8 @@ int main(int argc, char** argv)
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
@ -238,15 +239,17 @@ int main(int argc, char** argv)
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render(); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// Start rendering the scene // Start rendering the scene
@ -299,6 +302,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
helloVk.drawPost(cmdBuff); helloVk.drawPost(cmdBuff);
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

View file

@ -1,32 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
Project(${PROJNAME})
Message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:")
##################################################################################### #--------------------------------------------------------------------------------------------------
_add_project_definitions(${PROJNAME}) # C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#####################################################################################
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
SET(VULKAN_TARGET_ENV vulkan1.2) SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.vert" "shaders/*.vert"
"shaders/*.rchit" "shaders/*.rchit"
"shaders/*.rahit" "shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss" "shaders/*.rmiss"
"shaders/*.rgen" "shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES}) foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -95,7 +95,7 @@ Then we will flatten the scene graph and grab the information we will need using
nvh::GltfAttributes::Normal | nvh::GltfAttributes::Texcoord_0); nvh::GltfAttributes::Normal | nvh::GltfAttributes::Texcoord_0);
~~~~ ~~~~
The next par is to allocate the buffers to hold the information, such as the positions, normals, texture coordinates, etc. The next part is to allocate the buffers to hold the information, such as the positions, normals, texture coordinates, etc.
~~~~C ~~~~C
m_vertexBuffer = m_vertexBuffer =
@ -145,35 +145,26 @@ The function is similar, only the input is different.
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::primitiveToGeometry(const nvh::GltfPrimMesh& prim) nvvk::RaytracingBuilderKHR::Blas HelloVulkan::primitiveToGeometry(const nvh::GltfPrimMesh& prim)
{ {
// Setting up the creation info of acceleration structure
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(prim.indexCount / 3); // Nb triangles
asCreate.setMaxVertexCount(prim.vertexCount);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
// Building part // Building part
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(nvmath::vec3f)); triangles.setVertexStride(sizeof(nvmath::vec3f));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(prim.vertexCount);
// Setting up the build info of the acceleration // Setting up the build info of the acceleration
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
vk::AccelerationStructureBuildRangeInfoKHR offset;
vk::AccelerationStructureBuildOffsetInfoKHR offset;
offset.setFirstVertex(prim.vertexOffset); offset.setFirstVertex(prim.vertexOffset);
offset.setPrimitiveCount(prim.indexCount / 3); offset.setPrimitiveCount(prim.indexCount / 3);
offset.setPrimitiveOffset(prim.firstIndex * sizeof(uint32_t)); offset.setPrimitiveOffset(prim.firstIndex * sizeof(uint32_t));
@ -181,7 +172,6 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::primitiveToGeometry(const nvh::Glt
nvvk::RaytracingBuilderKHR::Blas blas; nvvk::RaytracingBuilderKHR::Blas blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -283,7 +273,7 @@ Camera position
Scene Scene
~~~~C ~~~~C
helloVk.loadScene(nvh::findFile("media/scenes/cornellBox.gltf", defaultSearchPaths)); helloVk.loadScene(nvh::findFile("media/scenes/cornellBox.gltf", defaultSearchPaths, true));
~~~~ ~~~~
Light Position Light Position
@ -310,12 +300,16 @@ Add the following two functions in `hello_vulkan.cpp`:
void HelloVulkan::updateFrame() void HelloVulkan::updateFrame()
{ {
static nvmath::mat4f refCamMatrix; static nvmath::mat4f refCamMatrix;
static float refFov{CameraManip.getFov()};
auto& m = CameraManip.getMatrix(); const auto& m = CameraManip.getMatrix();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0) const auto fov = CameraManip.getFov();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || refFov != fov)
{ {
resetFrame(); resetFrame();
refCamMatrix = m; refCamMatrix = m;
refFov = fov;
} }
m_rtPushConstants.frame++; m_rtPushConstants.frame++;
} }
@ -505,7 +499,7 @@ First initialize the `payload` and variable to compute the accumulation.
Now the loop over the trace function, will be like the following. Now the loop over the trace function, will be like the following.
:warning: **Note:** the depth is hardcode, but could be a parameter to the `push constant`. **Note:** the depth is hardcode, but could be a parameter to the `push constant`.
~~~~C ~~~~C
for(; prd.depth < 10; prd.depth++) for(; prd.depth < 10; prd.depth++)
@ -528,6 +522,6 @@ Now the loop over the trace function, will be like the following.
} }
~~~~ ~~~~
:warning: **Note:** do not forget to use `hitValue` in the `imageStore`. **Note:** do not forget to use `hitValue` in the `imageStore`.

View file

@ -46,6 +46,7 @@ extern std::vector<std::string> defaultSearchPaths;
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
#include "nvvk/shaders_vk.hpp" #include "nvvk/shaders_vk.hpp"
#include "nvh/alignment.hpp"
#include "shaders/binding.glsl" #include "shaders/binding.glsl"
// Holding the camera matrices // Holding the camera matrices
@ -182,8 +183,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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({
@ -205,6 +206,7 @@ void HelloVulkan::loadScene(const std::string& filename)
tinygltf::TinyGLTF tcontext; tinygltf::TinyGLTF tcontext;
std::string warn, error; std::string warn, error;
LOGI("Loading file: %s", filename.c_str());
if(!tcontext.LoadASCIIFromFile(&tmodel, &error, &warn, filename)) if(!tcontext.LoadASCIIFromFile(&tmodel, &error, &warn, filename))
{ {
assert(!"Error while loading scene"); assert(!"Error while loading scene");
@ -223,10 +225,12 @@ void HelloVulkan::loadScene(const std::string& filename)
m_vertexBuffer = m_vertexBuffer =
m_alloc.createBuffer(cmdBuf, m_gltfScene.m_positions, m_alloc.createBuffer(cmdBuf, m_gltfScene.m_positions,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
m_indexBuffer = m_indexBuffer =
m_alloc.createBuffer(cmdBuf, m_gltfScene.m_indices, m_alloc.createBuffer(cmdBuf, m_gltfScene.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
m_normalBuffer = m_alloc.createBuffer(cmdBuf, m_gltfScene.m_normals, m_normalBuffer = m_alloc.createBuffer(cmdBuf, m_gltfScene.m_normals,
vkBU::eVertexBuffer | vkBU::eStorageBuffer); vkBU::eVertexBuffer | vkBU::eStorageBuffer);
m_uvBuffer = m_alloc.createBuffer(cmdBuf, m_gltfScene.m_texcoords0, m_uvBuffer = m_alloc.createBuffer(cmdBuf, m_gltfScene.m_texcoords0,
@ -525,9 +529,9 @@ void HelloVulkan::createPostPipeline()
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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, 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();
@ -591,54 +595,46 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a GLTF primitive in the Raytracing Geometry used for the BLAS // Converting a GLTF primitive in the Raytracing Geometry used for the BLAS
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::primitiveToGeometry(const nvh::GltfPrimMesh& prim) nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::primitiveToGeometry(
const nvh::GltfPrimMesh& prim)
{ {
// Setting up the creation info of acceleration structure
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(prim.indexCount / 3); // Nb triangles
asCreate.setMaxVertexCount(prim.vertexCount);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
// Building part // Building part
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(nvmath::vec3f)); triangles.setVertexStride(sizeof(nvmath::vec3f));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(prim.vertexCount);
// Setting up the build info of the acceleration // Setting up the build info of the acceleration
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
vk::AccelerationStructureBuildRangeInfoKHR offset;
vk::AccelerationStructureBuildOffsetInfoKHR offset;
offset.setFirstVertex(prim.vertexOffset); offset.setFirstVertex(prim.vertexOffset);
offset.setPrimitiveCount(prim.indexCount / 3); offset.setPrimitiveCount(prim.indexCount / 3);
offset.setPrimitiveOffset(prim.firstIndex * sizeof(uint32_t)); offset.setPrimitiveOffset(prim.firstIndex * sizeof(uint32_t));
offset.setTransformOffset(0); offset.setTransformOffset(0);
nvvk::RaytracingBuilderKHR::Blas blas; nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -649,7 +645,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::primitiveToGeometry(const nvh::Glt
void HelloVulkan::createBottomLevelAS() void HelloVulkan::createBottomLevelAS()
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(m_gltfScene.m_primMeshes.size()); allBlas.reserve(m_gltfScene.m_primMeshes.size());
for(auto& primMesh : m_gltfScene.m_primMeshes) for(auto& primMesh : m_gltfScene.m_primMeshes)
{ {
@ -738,16 +734,15 @@ void HelloVulkan::createRtPipeline()
vk::ShaderModule raygenSM = vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/pathtrace.rgen.spv", true, paths)); nvh::loadFile("shaders/pathtrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM = vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/pathtrace.rmiss.spv", true, paths)); 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 = vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -774,7 +769,7 @@ void HelloVulkan::createRtPipeline()
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/pathtrace.rchit.spv", true, paths)); 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,
@ -810,10 +805,10 @@ void HelloVulkan::createRtPipeline()
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
rayPipelineInfo.setLayout(m_rtPipelineLayout); rayPipelineInfo.setLayout(m_rtPipelineLayout);
m_rtPipeline = m_rtPipeline = static_cast<const vk::Pipeline&>(
static_cast<const vk::Pipeline&>(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
m_device.destroy(raygenSM); m_device.destroy(raygenSM);
m_device.destroy(missSM); m_device.destroy(missSM);
@ -832,18 +827,24 @@ 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()); // 3 shaders: raygen, 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 baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * baseAlignment; uint32_t sbtSize = groupCount * groupSizeAligned;
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
if(result != vk::Result::eSuccess)
LOGE("Fail getRayTracingShaderGroupHandlesKHR: %s", vk::to_string(result));
// Write the handles in the SBT // Write the handles in the SBT
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, m_rtSBTBuffer = m_alloc.createBuffer(
vk::MemoryPropertyFlagBits::eHostVisible sbtSize,
| vk::MemoryPropertyFlagBits::eHostCoherent); vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR
| vk::BufferUsageFlagBits::eShaderBindingTableKHR,
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
// Write the handles in the SBT // Write the handles in the SBT
@ -852,7 +853,7 @@ void HelloVulkan::createRtShaderBindingTable()
for(uint32_t g = 0; g < groupCount; g++) for(uint32_t g = 0; g < groupCount; g++)
{ {
memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
pData += baseAlignment; pData += groupSizeAligned;
} }
m_alloc.unmap(m_rtSBTBuffer); m_alloc.unmap(m_rtSBTBuffer);
@ -883,25 +884,23 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
| vk::ShaderStageFlagBits::eMissKHR, | vk::ShaderStageFlagBits::eMissKHR,
0, m_rtPushConstants); 0, m_rtPushConstants);
vk::DeviceSize progSize = // Size of a program identifier
m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier uint32_t groupSize =
vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen uint32_t groupStride = groupSize;
vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); using Stride = vk::StridedDeviceAddressRegionKHR;
std::array<Stride, 4> strideAddresses{
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit
Stride{0u, 0u, 0u}}; // callable
const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
progSize, sbtSize}; &strideAddresses[3], //
const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, m_size.width, m_size.height,
progSize, sbtSize}; 1); //
const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset,
progSize, sbtSize};
const vk::StridedBufferRegionKHR callableShaderBindingTable;
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable,
&callableShaderBindingTable, //
m_size.width, m_size.height, 1); //
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
@ -914,12 +913,16 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
void HelloVulkan::updateFrame() void HelloVulkan::updateFrame()
{ {
static nvmath::mat4f refCamMatrix; static nvmath::mat4f refCamMatrix;
static float refFov{CameraManip.getFov()};
auto& m = CameraManip.getMatrix(); const auto& m = CameraManip.getMatrix();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0) const auto fov = CameraManip.getFov();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || refFov != fov)
{ {
resetFrame(); resetFrame();
refCamMatrix = m; refCamMatrix = m;
refFov = fov;
} }
m_rtPushConstants.frame++; m_rtPushConstants.frame++;
} }

View file

@ -127,7 +127,7 @@ public:
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat};
// #VKRay // #VKRay
nvvk::RaytracingBuilderKHR::Blas primitiveToGeometry(const nvh::GltfPrimMesh& prim); nvvk::RaytracingBuilderKHR::BlasInput primitiveToGeometry(const nvh::GltfPrimMesh& prim);
void initRayTracing(); void initRayTracing();
void createBottomLevelAS(); void createBottomLevelAS();
@ -140,7 +140,7 @@ public:
void updateFrame(); void updateFrame();
void resetFrame(); void resetFrame();
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; vk::DescriptorPool m_rtDescPool;

View file

@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "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"
@ -61,19 +62,16 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1; ImGuiH::CameraWidget();
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up;
CameraManip.getLookat(pos, eye, up);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
}
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f);
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); 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);
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -115,18 +113,16 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 #ifdef WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
@ -138,13 +134,17 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_SHADER_CLOCK_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_SHADER_CLOCK_EXTENSION_NAME);
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
@ -166,7 +166,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -175,7 +175,7 @@ int main(int argc, char** argv)
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creation of the example // Creation of the example
helloVk.loadScene(nvh::findFile("media/scenes/cornellBox.gltf", defaultSearchPaths)); helloVk.loadScene(nvh::findFile("media/scenes/cornellBox.gltf", defaultSearchPaths, true));
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
@ -219,15 +219,17 @@ int main(int argc, char** argv)
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render(); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// Start rendering the scene // Start rendering the scene
@ -280,6 +282,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
helloVk.drawPost(cmdBuff); helloVk.drawPost(cmdBuff);
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

View file

@ -1,32 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
Project(${PROJNAME})
Message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:")
##################################################################################### #--------------------------------------------------------------------------------------------------
_add_project_definitions(${PROJNAME}) # C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#####################################################################################
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
SET(VULKAN_TARGET_ENV vulkan1.2) SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.vert" "shaders/*.vert"
"shaders/*.rchit" "shaders/*.rchit"
"shaders/*.rahit" "shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss" "shaders/*.rmiss"
"shaders/*.rgen" "shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES}) foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -30,9 +30,9 @@ Then replace the calls to `helloVk.loadModel` in `main()` by
~~~~ C++ ~~~~ C++
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
std::random_device rd; // Will be used to obtain a seed for the random number engine std::random_device rd; // Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
@ -55,7 +55,7 @@ Then replace the calls to `helloVk.loadModel` in `main()` by
} }
~~~~ ~~~~
:warning: **Note:** **Note:**
This will create 3 models (OBJ) and their instances, and then add 2000 instances This will create 3 models (OBJ) and their instances, and then add 2000 instances
distributed between green cubes and cubes with one color per face. distributed between green cubes and cubes with one color per face.
@ -73,7 +73,7 @@ Remove the previous code and replace it with the following
std::normal_distribution<float> disn(0.05f, 0.05f); std::normal_distribution<float> disn(0.05f, 0.05f);
for(int n = 0; n < 2000; ++n) for(int n = 0; n < 2000; ++n)
{ {
helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true));
HelloVulkan::ObjInstance& inst = helloVk.m_objInstance.back(); HelloVulkan::ObjInstance& inst = helloVk.m_objInstance.back();
float scale = fabsf(disn(gen)); float scale = fabsf(disn(gen));
@ -85,7 +85,7 @@ Remove the previous code and replace it with the following
inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform))); inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform)));
} }
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
~~~~ ~~~~
The example might still work, but the console will print the following error after loading 1363 objects. All other objects allocated after the 1363rd will fail to be displayed. The example might still work, but the console will print the following error after loading 1363 objects. All other objects allocated after the 1363rd will fail to be displayed.

View file

@ -41,6 +41,7 @@ extern std::vector<std::string> defaultSearchPaths;
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/pipeline_vk.hpp" #include "nvvk/pipeline_vk.hpp"
#include "nvh/alignment.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
@ -178,7 +179,7 @@ void HelloVulkan::updateDescriptorSet()
std::vector<vk::DescriptorImageInfo> diit; std::vector<vk::DescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.push_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
@ -209,8 +210,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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)},
@ -228,6 +229,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -254,10 +256,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices, m_alloc.createBuffer(cmdBuf, loader.m_vertices,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer = model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices, m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
@ -330,7 +334,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
auto imgSize = vk::Extent2D(1, 1); auto imgSize = vk::Extent2D(1, 1);
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the dummy texure // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
@ -348,9 +352,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
std::stringstream o; std::stringstream o;
int texWidth, texHeight, texChannels; int texWidth, texHeight, texChannels;
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); 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}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -575,9 +580,9 @@ void HelloVulkan::createPostPipeline()
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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, 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();
@ -641,47 +646,43 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Converting a OBJ primitive to the ray tracing geometry used for the BLAS
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
nvvk::RaytracingBuilderKHR::Blas blas;
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles
asCreate.setMaxVertexCount(model.nbVertices);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj)); triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
// Consider the geometry opaque for optimization
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
vk::AccelerationStructureBuildOffsetInfoKHR offset;
vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(model.nbIndices / 3); // nb triangles
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -689,7 +690,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod
void HelloVulkan::createBottomLevelAS() void HelloVulkan::createBottomLevelAS()
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(m_objModel.size()); allBlas.reserve(m_objModel.size());
for(const auto& obj : m_objModel) for(const auto& obj : m_objModel)
{ {
@ -775,16 +776,15 @@ void HelloVulkan::createRtPipeline()
vk::ShaderModule raygenSM = vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM = vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); 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 = vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -811,7 +811,7 @@ void HelloVulkan::createRtPipeline()
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); 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,
@ -846,10 +846,10 @@ void HelloVulkan::createRtPipeline()
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
rayPipelineInfo.setLayout(m_rtPipelineLayout); rayPipelineInfo.setLayout(m_rtPipelineLayout);
m_rtPipeline = m_rtPipeline = static_cast<const vk::Pipeline&>(
static_cast<const vk::Pipeline&>(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
m_device.destroy(raygenSM); m_device.destroy(raygenSM);
m_device.destroy(missSM); m_device.destroy(missSM);
@ -868,18 +868,23 @@ 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()); // 3 shaders: raygen, 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 baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * baseAlignment; uint32_t sbtSize = groupCount * groupSizeAligned;
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
assert(result == vk::Result::eSuccess);
// Write the handles in the SBT // Write the handles in the SBT
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, m_rtSBTBuffer = m_alloc.createBuffer(
vk::MemoryPropertyFlagBits::eHostVisible sbtSize,
| vk::MemoryPropertyFlagBits::eHostCoherent); vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR
| vk::BufferUsageFlagBits::eShaderBindingTableKHR,
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
// Write the handles in the SBT // Write the handles in the SBT
@ -888,7 +893,7 @@ void HelloVulkan::createRtShaderBindingTable()
for(uint32_t g = 0; g < groupCount; g++) for(uint32_t g = 0; g < groupCount; g++)
{ {
memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
pData += baseAlignment; pData += groupSizeAligned;
} }
m_alloc.unmap(m_rtSBTBuffer); m_alloc.unmap(m_rtSBTBuffer);
@ -917,25 +922,22 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
| vk::ShaderStageFlagBits::eMissKHR, | vk::ShaderStageFlagBits::eMissKHR,
0, m_rtPushConstants); 0, m_rtPushConstants);
vk::DeviceSize progSize = // Size of a program identifier
m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier uint32_t groupSize =
vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen uint32_t groupStride = groupSize;
vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size();
// m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... using Stride = vk::StridedDeviceAddressRegionKHR;
const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, std::array<Stride, 4> strideAddresses{
progSize, sbtSize}; Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
progSize, sbtSize}; Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit
const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, Stride{0u, 0u, 0u}}; // callable
progSize, sbtSize};
const vk::StridedBufferRegionKHR callableShaderBindingTable; cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, &strideAddresses[3], //
&callableShaderBindingTable, //
m_size.width, m_size.height, 1); // m_size.width, m_size.height, 1); //
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }

View file

@ -146,7 +146,7 @@ public:
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
void createRtDescriptorSet(); void createRtDescriptorSet();
@ -156,7 +156,7 @@ public:
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; vk::DescriptorPool m_rtDescPool;

View file

@ -38,6 +38,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "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"
@ -62,19 +63,16 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1; ImGuiH::CameraWidget();
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up;
CameraManip.getLookat(pos, eye, up);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
}
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f);
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); 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);
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -116,20 +114,17 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media NVPSystem::exePath() + "..",
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Enabling the extension feature
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature;
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 #ifdef WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
@ -143,11 +138,16 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -167,7 +167,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -182,7 +182,7 @@ int main(int argc, char** argv)
std::normal_distribution<float> disn(0.05f, 0.05f); std::normal_distribution<float> disn(0.05f, 0.05f);
for(int n = 0; n < 2000; ++n) for(int n = 0; n < 2000; ++n)
{ {
helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true));
HelloVulkan::ObjInstance& inst = helloVk.m_objInstance.back(); HelloVulkan::ObjInstance& inst = helloVk.m_objInstance.back();
float scale = fabsf(disn(gen)); float scale = fabsf(disn(gen));
@ -194,7 +194,7 @@ int main(int argc, char** argv)
inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform))); inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform)));
} }
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
helloVk.createDescriptorSetLayout(); helloVk.createDescriptorSetLayout();
@ -238,15 +238,17 @@ int main(int argc, char** argv)
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render(); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// Start rendering the scene // Start rendering the scene
@ -299,6 +301,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
helloVk.drawPost(cmdBuff); helloVk.drawPost(cmdBuff);
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

View file

@ -1,32 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
Project(${PROJNAME})
Message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:")
##################################################################################### #--------------------------------------------------------------------------------------------------
_add_project_definitions(${PROJNAME}) # C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#####################################################################################
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
SET(VULKAN_TARGET_ENV vulkan1.2) SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -39,46 +45,33 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.rint" "shaders/*.rint"
"shaders/*.rmiss" "shaders/*.rmiss"
"shaders/*.rgen" "shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES}) foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -91,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -190,11 +190,11 @@ In `main.cpp`, where we are loading the OBJ model, we can replace it with
~~~~ C++ ~~~~ C++
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.createSpheres(); helloVk.createSpheres();
~~~~ ~~~~
:warning: **Note:** it is possible to have more OBJ models, but the spheres will need to be added after all of them. **Note:** it is possible to have more OBJ models, but the spheres will need to be added after all of them.
The scene will be large, better to move the camera out The scene will be large, better to move the camera out
@ -248,7 +248,7 @@ Just before building the TLAS, we need to add the following
rayInst.instanceId = static_cast<uint32_t>(tlas.size()); // gl_InstanceID rayInst.instanceId = static_cast<uint32_t>(tlas.size()); // gl_InstanceID
rayInst.blasId = static_cast<uint32_t>(m_objModel.size()); rayInst.blasId = static_cast<uint32_t>(m_objModel.size());
rayInst.hitGroupId = 1; // We will use the same hit group for all objects rayInst.hitGroupId = 1; // We will use the same hit group for all objects
rayInst.flags = vk::GeometryInstanceFlagBitsKHR::eTriangleCullDisable; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
tlas.emplace_back(rayInst); tlas.emplace_back(rayInst);
} }
~~~~ ~~~~

View file

@ -43,6 +43,7 @@ extern std::vector<std::string> defaultSearchPaths;
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
#include "nvh/alignment.hpp"
#include "nvvk/shaders_vk.hpp" #include "nvvk/shaders_vk.hpp"
#include <random> #include <random>
@ -172,7 +173,7 @@ void HelloVulkan::updateDescriptorSet()
std::vector<vk::DescriptorImageInfo> diit; std::vector<vk::DescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.push_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
@ -203,8 +204,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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)},
@ -222,6 +223,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -248,10 +250,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices, m_alloc.createBuffer(cmdBuf, loader.m_vertices,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer = model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices, m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
@ -324,7 +328,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
auto imgSize = vk::Extent2D(1, 1); auto imgSize = vk::Extent2D(1, 1);
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the dummy texure // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
@ -342,9 +346,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
std::stringstream o; std::stringstream o;
int texWidth, texHeight, texChannels; int texWidth, texHeight, texChannels;
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); 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}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -568,9 +573,9 @@ void HelloVulkan::createPostPipeline()
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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, 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();
@ -634,50 +639,44 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Converting a OBJ primitive to the ray tracing geometry used for the BLAS
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles
asCreate.setMaxVertexCount(model.nbVertices);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj)); triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
// Setting up the build info of the acceleration // Setting up the build info of the acceleration
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
vk::AccelerationStructureBuildOffsetInfoKHR offset; vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
nvvk::RaytracingBuilderKHR::Blas blas; nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -685,37 +684,30 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Returning the ray tracing geometry used for the BLAS, containing all spheres // Returning the ray tracing geometry used for the BLAS, containing all spheres
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::sphereToVkGeometryKHR() nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::sphereToVkGeometryKHR()
{ {
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eAabbs);
asCreate.setMaxPrimitiveCount((uint32_t)m_spheres.size()); // Nb triangles
asCreate.setIndexType(vk::IndexType::eNoneKHR);
asCreate.setVertexFormat(vk::Format::eUndefined);
asCreate.setMaxVertexCount(0);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
vk::DeviceAddress dataAddress = m_device.getBufferAddress({m_spheresAabbBuffer.buffer}); vk::DeviceAddress dataAddress = m_device.getBufferAddress({m_spheresAabbBuffer.buffer});
vk::AccelerationStructureGeometryAabbsDataKHR aabbs; vk::AccelerationStructureGeometryAabbsDataKHR aabbs;
aabbs.setData(dataAddress); aabbs.setData(dataAddress);
aabbs.setStride(sizeof(Aabb)); aabbs.setStride(sizeof(Aabb));
// Setting up the build info of the acceleration // Setting up the build info of the acceleration (C version, c++ gives wrong type)
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom(vk::GeometryTypeKHR::eAabbs, aabbs,
asGeom.setGeometryType(asCreate.geometryType); vk::GeometryFlagBitsKHR::eOpaque);
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); //asGeom.geometryType = vk::GeometryTypeKHR::eAabbs;
asGeom.geometry.setAabbs(aabbs); //asGeom.flags = vk::GeometryFlagBitsKHR::eOpaque;
//asGeom.geometry.aabbs = aabbs;
vk::AccelerationStructureBuildOffsetInfoKHR offset;
vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount((uint32_t)m_spheres.size()); // Nb aabb
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
nvvk::RaytracingBuilderKHR::Blas blas; nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -754,11 +746,11 @@ void HelloVulkan::createSpheres(uint32_t nbSpheres)
// Creating two materials // Creating two materials
MaterialObj mat; MaterialObj mat;
mat.diffuse = vec3f(0, 1, 1); mat.diffuse = nvmath::vec3f(0, 1, 1);
std::vector<MaterialObj> materials; std::vector<MaterialObj> materials;
std::vector<int> matIdx(nbSpheres); std::vector<int> matIdx(nbSpheres);
materials.emplace_back(mat); materials.emplace_back(mat);
mat.diffuse = vec3f(1, 1, 0); mat.diffuse = nvmath::vec3f(1, 1, 0);
materials.emplace_back(mat); materials.emplace_back(mat);
// Assign a material to each sphere // Assign a material to each sphere
@ -787,7 +779,7 @@ void HelloVulkan::createSpheres(uint32_t nbSpheres)
void HelloVulkan::createBottomLevelAS() void HelloVulkan::createBottomLevelAS()
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(m_objModel.size()); allBlas.reserve(m_objModel.size());
for(const auto& obj : m_objModel) for(const auto& obj : m_objModel)
{ {
@ -892,16 +884,15 @@ void HelloVulkan::createRtPipeline()
vk::ShaderModule raygenSM = vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM = vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); 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 = vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -928,7 +919,7 @@ void HelloVulkan::createRtPipeline()
// Hit Group0 - Closest Hit // Hit Group0 - Closest Hit
vk::ShaderModule chitSM = vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
{ {
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
@ -942,10 +933,10 @@ void HelloVulkan::createRtPipeline()
// Hit Group1 - Closest Hit + Intersection (procedural) // Hit Group1 - Closest Hit + Intersection (procedural)
vk::ShaderModule chit2SM = vk::ShaderModule chit2SM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths)); nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true));
vk::ShaderModule rintSM = vk::ShaderModule rintSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rint.spv", true, paths)); 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,
@ -983,10 +974,10 @@ void HelloVulkan::createRtPipeline()
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
rayPipelineInfo.setLayout(m_rtPipelineLayout); rayPipelineInfo.setLayout(m_rtPipelineLayout);
m_rtPipeline = m_rtPipeline = static_cast<const vk::Pipeline&>(
static_cast<const vk::Pipeline&>(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
m_device.destroy(raygenSM); m_device.destroy(raygenSM);
m_device.destroy(missSM); m_device.destroy(missSM);
@ -1007,18 +998,23 @@ 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()); // 3 shaders: raygen, 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 baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * baseAlignment; uint32_t sbtSize = groupCount * groupSizeAligned;
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
assert(result == vk::Result::eSuccess);
// Write the handles in the SBT // Write the handles in the SBT
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, m_rtSBTBuffer = m_alloc.createBuffer(
vk::MemoryPropertyFlagBits::eHostVisible sbtSize,
| vk::MemoryPropertyFlagBits::eHostCoherent); vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR
| vk::BufferUsageFlagBits::eShaderBindingTableKHR,
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
// Write the handles in the SBT // Write the handles in the SBT
@ -1027,7 +1023,7 @@ void HelloVulkan::createRtShaderBindingTable()
for(uint32_t g = 0; g < groupCount; g++) for(uint32_t g = 0; g < groupCount; g++)
{ {
memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
pData += baseAlignment; pData += groupSizeAligned;
} }
m_alloc.unmap(m_rtSBTBuffer); m_alloc.unmap(m_rtSBTBuffer);
@ -1056,25 +1052,22 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
| vk::ShaderStageFlagBits::eMissKHR, | vk::ShaderStageFlagBits::eMissKHR,
0, m_rtPushConstants); 0, m_rtPushConstants);
vk::DeviceSize progSize = // Size of a program identifier
m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier uint32_t groupSize =
vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen uint32_t groupStride = groupSize;
vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size();
// m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... using Stride = vk::StridedDeviceAddressRegionKHR;
const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, std::array<Stride, 4> strideAddresses{
progSize, sbtSize}; Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
progSize, sbtSize}; Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit
const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, Stride{0u, 0u, 0u}}; // callable
progSize, sbtSize};
const vk::StridedBufferRegionKHR callableShaderBindingTable; cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, &strideAddresses[3], //
&callableShaderBindingTable, //
m_size.width, m_size.height, 1); // m_size.width, m_size.height, 1); //
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }

View file

@ -133,7 +133,7 @@ public:
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
void createRtDescriptorSet(); void createRtDescriptorSet();
@ -143,7 +143,7 @@ public:
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; vk::DescriptorPool m_rtDescPool;
@ -175,7 +175,7 @@ public:
nvmath::vec3f maximum; nvmath::vec3f maximum;
}; };
nvvk::RaytracingBuilderKHR::Blas sphereToVkGeometryKHR(); nvvk::RaytracingBuilderKHR::BlasInput sphereToVkGeometryKHR();
std::vector<Sphere> m_spheres; // All spheres std::vector<Sphere> m_spheres; // All spheres
nvvk::Buffer m_spheresBuffer; // Buffer holding the spheres nvvk::Buffer m_spheresBuffer; // Buffer holding the spheres

View file

@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "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"
@ -61,19 +62,16 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1; ImGuiH::CameraWidget();
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up;
CameraManip.getLookat(pos, eye, up);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
}
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -200.f, 200.f);
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 1000.f);
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); 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);
}
ImGui::Text("Nb Spheres and Cubes: %d", helloVk.m_spheres.size()); ImGui::Text("Nb Spheres and Cubes: %d", helloVk.m_spheres.size());
} }
@ -116,20 +114,16 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Enabling the extension feature
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature;
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 #ifdef WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
@ -143,11 +137,17 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -167,7 +167,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -176,8 +176,8 @@ int main(int argc, char** argv)
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creation of the example // Creation of the example
// helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); // helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.createSpheres(2000000); helloVk.createSpheres(2000000);
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
@ -222,15 +222,17 @@ int main(int argc, char** argv)
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render(); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// Start rendering the scene // Start rendering the scene
@ -283,6 +285,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
helloVk.drawPost(cmdBuff); helloVk.drawPost(cmdBuff);
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

View file

@ -1,32 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
Project(${PROJNAME})
Message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:")
##################################################################################### #--------------------------------------------------------------------------------------------------
_add_project_definitions(${PROJNAME}) # C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#####################################################################################
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
SET(VULKAN_TARGET_ENV vulkan1.2) SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.vert" "shaders/*.vert"
"shaders/*.rchit" "shaders/*.rchit"
"shaders/*.rahit" "shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss" "shaders/*.rmiss"
"shaders/*.rgen" "shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES}) foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -150,18 +150,22 @@ The implementation of `updateFrame` resets the frame counter if the camera has c
~~~~ C++ ~~~~ C++
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// If the camera matrix has changed, resets the frame. // If the camera matrix or the the fov has changed, resets the frame.
// otherwise, increments frame. // otherwise, increments frame.
// //
void HelloVulkan::updateFrame() void HelloVulkan::updateFrame()
{ {
static nvmath::mat4f refCamMatrix; static nvmath::mat4f refCamMatrix;
static float refFov{CameraManip.getFov()};
auto& m = CameraManip.getMatrix(); const auto& m = CameraManip.getMatrix();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0) const auto fov = CameraManip.getFov();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || refFov != fov)
{ {
resetFrame(); resetFrame();
refCamMatrix = m; refCamMatrix = m;
refFov = fov;
} }
m_rtPushConstants.frame++; m_rtPushConstants.frame++;
} }
@ -195,23 +199,20 @@ The frame number should also be reset when any parts of the scene change, such a
~~~~ C++ ~~~~ C++
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1;
bool changed = false; bool changed = false;
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0"))
changed |= ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up; auto& pc = helloVk.m_pushConstant;
CameraManip.getLookat(pos, eye, up); changed |= ImGui::RadioButton("Point", &pc.lightType, 0);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
changed = true;
}
changed |=
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
changed |=
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f);
changed |= ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
changed |= ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); changed |= ImGui::RadioButton("Infinite", &pc.lightType, 1);
changed |= ImGui::SliderFloat3("Position", &pc.lightPosition.x, -20.f, 20.f);
changed |= ImGui::SliderFloat("Intensity", &pc.lightIntensity, 0.f, 150.f);
}
if(changed) if(changed)
helloVk.resetFrame(); helloVk.resetFrame();
} }
@ -242,8 +243,7 @@ int m_maxFrames{100};
and also add a way to control it in `renderUI()`, making sure that `m_maxFrames` cannot be set below 1: and also add a way to control it in `renderUI()`, making sure that `m_maxFrames` cannot be set below 1:
~~~~ C++ ~~~~ C++
changed |= ImGui::InputInt("Max Frames", &helloVk.m_maxFrames); changed |= ImGui::SliderInt("Max Frames", &helloVk.m_maxFrames, 1, 100);
helloVk.m_maxFrames = std::max(helloVk.m_maxFrames, 1);
~~~~ ~~~~
Then in `raytrace()`, immediately after the call to `updateFrame()`, return if the current frame has exceeded the max frame. Then in `raytrace()`, immediately after the call to `updateFrame()`, return if the current frame has exceeded the max frame.

View file

@ -39,6 +39,7 @@ extern std::vector<std::string> defaultSearchPaths;
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/pipeline_vk.hpp" #include "nvvk/pipeline_vk.hpp"
#include "nvh/alignment.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
@ -162,7 +163,7 @@ void HelloVulkan::updateDescriptorSet()
std::vector<vk::DescriptorImageInfo> diit; std::vector<vk::DescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.push_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
@ -193,8 +194,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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)},
@ -212,6 +213,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -238,10 +240,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices, m_alloc.createBuffer(cmdBuf, loader.m_vertices,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer = model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices, m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
@ -314,7 +318,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
auto imgSize = vk::Extent2D(1, 1); auto imgSize = vk::Extent2D(1, 1);
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the dummy texure // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
@ -332,9 +336,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
std::stringstream o; std::stringstream o;
int texWidth, texHeight, texChannels; int texWidth, texHeight, texChannels;
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); 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}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -553,9 +558,9 @@ void HelloVulkan::createPostPipeline()
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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, 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();
@ -619,47 +624,43 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Converting a OBJ primitive to the ray tracing geometry used for the BLAS
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
nvvk::RaytracingBuilderKHR::Blas blas;
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles
asCreate.setMaxVertexCount(model.nbVertices);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj)); triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
// Consider the geometry opaque for optimization
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
vk::AccelerationStructureBuildOffsetInfoKHR offset;
vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -667,7 +668,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod
void HelloVulkan::createBottomLevelAS() void HelloVulkan::createBottomLevelAS()
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(m_objModel.size()); allBlas.reserve(m_objModel.size());
for(const auto& obj : m_objModel) for(const auto& obj : m_objModel)
{ {
@ -753,16 +754,15 @@ void HelloVulkan::createRtPipeline()
vk::ShaderModule raygenSM = vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM = vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); 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 = vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -789,7 +789,7 @@ void HelloVulkan::createRtPipeline()
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); 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,
@ -824,10 +824,10 @@ void HelloVulkan::createRtPipeline()
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
rayPipelineInfo.setLayout(m_rtPipelineLayout); rayPipelineInfo.setLayout(m_rtPipelineLayout);
m_rtPipeline = m_rtPipeline = static_cast<const vk::Pipeline&>(
static_cast<const vk::Pipeline&>(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
m_device.destroy(raygenSM); m_device.destroy(raygenSM);
m_device.destroy(missSM); m_device.destroy(missSM);
@ -846,18 +846,23 @@ 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()); // 3 shaders: raygen, 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 baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * baseAlignment; uint32_t sbtSize = groupCount * groupSizeAligned;
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
assert(result == vk::Result::eSuccess);
// Write the handles in the SBT // Write the handles in the SBT
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, m_rtSBTBuffer = m_alloc.createBuffer(
vk::MemoryPropertyFlagBits::eHostVisible sbtSize,
| vk::MemoryPropertyFlagBits::eHostCoherent); vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR
| vk::BufferUsageFlagBits::eShaderBindingTableKHR,
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
// Write the handles in the SBT // Write the handles in the SBT
@ -866,7 +871,7 @@ void HelloVulkan::createRtShaderBindingTable()
for(uint32_t g = 0; g < groupCount; g++) for(uint32_t g = 0; g < groupCount; g++)
{ {
memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
pData += baseAlignment; pData += groupSizeAligned;
} }
m_alloc.unmap(m_rtSBTBuffer); m_alloc.unmap(m_rtSBTBuffer);
@ -899,43 +904,44 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
| vk::ShaderStageFlagBits::eMissKHR, | vk::ShaderStageFlagBits::eMissKHR,
0, m_rtPushConstants); 0, m_rtPushConstants);
vk::DeviceSize progSize = // Size of a program identifier
m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier uint32_t groupSize =
vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen uint32_t groupStride = groupSize;
vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size();
// m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... using Stride = vk::StridedDeviceAddressRegionKHR;
const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, std::array<Stride, 4> strideAddresses{
progSize, sbtSize}; Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
progSize, sbtSize}; Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit
const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, Stride{0u, 0u, 0u}}; // callable
progSize, sbtSize};
const vk::StridedBufferRegionKHR callableShaderBindingTable; cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, &strideAddresses[3], //
&callableShaderBindingTable, //
m_size.width, m_size.height, 1); // m_size.width, m_size.height, 1); //
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// If the camera matrix has changed, resets the frame. // If the camera matrix or the the fov has changed, resets the frame.
// otherwise, increments frame. // otherwise, increments frame.
// //
void HelloVulkan::updateFrame() void HelloVulkan::updateFrame()
{ {
static nvmath::mat4f refCamMatrix; static nvmath::mat4f refCamMatrix;
static float refFov{CameraManip.getFov()};
auto& m = CameraManip.getMatrix(); const auto& m = CameraManip.getMatrix();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0) const auto fov = CameraManip.getFov();
if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || refFov != fov)
{ {
resetFrame(); resetFrame();
refCamMatrix = m; refCamMatrix = m;
refFov = fov;
} }
m_rtPushConstants.frame++; m_rtPushConstants.frame++;
} }

View file

@ -133,7 +133,7 @@ public:
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
void createRtDescriptorSet(); void createRtDescriptorSet();
@ -144,7 +144,7 @@ public:
void resetFrame(); void resetFrame();
void updateFrame(); void updateFrame();
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; vk::DescriptorPool m_rtDescPool;
@ -154,7 +154,7 @@ public:
vk::PipelineLayout m_rtPipelineLayout; vk::PipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; vk::Pipeline m_rtPipeline;
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
int m_maxFrames{100}; int m_maxFrames{10};
struct RtPushConstant struct RtPushConstant
{ {

View file

@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "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"
@ -61,25 +62,22 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1;
bool changed = false; bool changed = false;
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0"))
changed |= ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up; auto& pc = helloVk.m_pushConstant;
CameraManip.getLookat(pos, eye, up); changed |= ImGui::RadioButton("Point", &pc.lightType, 0);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
changed = true;
}
changed |=
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
changed |=
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f);
changed |= ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
changed |= ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); changed |= ImGui::RadioButton("Infinite", &pc.lightType, 1);
changed |= ImGui::InputInt("Max Frames", &helloVk.m_maxFrames);
helloVk.m_maxFrames = std::max(helloVk.m_maxFrames, 1); changed |= ImGui::SliderFloat3("Position", &pc.lightPosition.x, -20.f, 20.f);
changed |= ImGui::SliderFloat("Intensity", &pc.lightIntensity, 0.f, 150.f);
}
changed |= ImGui::SliderInt("Max Frames", &helloVk.m_maxFrames, 1, 100);
if(changed) if(changed)
helloVk.resetFrame(); helloVk.resetFrame();
} }
@ -123,20 +121,17 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media NVPSystem::exePath() + "..",
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Enabling the extension feature
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature;
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 #ifdef WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
@ -149,12 +144,18 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -174,7 +175,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -183,8 +184,8 @@ int main(int argc, char** argv)
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
@ -229,8 +230,9 @@ int main(int argc, char** argv)
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGuiH::Panel::Begin();
bool changed = false; bool changed = false;
// Edit 3 floats representing a color // Edit 3 floats representing a color
changed |= ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); changed |= ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
@ -242,7 +244,8 @@ int main(int argc, char** argv)
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render(); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// Start rendering the scene // Start rendering the scene
@ -295,6 +298,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
helloVk.drawPost(cmdBuff); helloVk.drawPost(cmdBuff);
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

View file

@ -1,32 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
Project(${PROJNAME})
Message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:")
##################################################################################### #--------------------------------------------------------------------------------------------------
_add_project_definitions(${PROJNAME}) # C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#####################################################################################
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
SET(VULKAN_TARGET_ENV vulkan1.2) SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.vert" "shaders/*.vert"
"shaders/*.rchit" "shaders/*.rchit"
"shaders/*.rahit" "shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss" "shaders/*.rmiss"
"shaders/*.rgen" "shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES}) foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -19,14 +19,14 @@ Then you can change the `helloVk.loadModel` calls to the following:
~~~~ C++ ~~~~ C++
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths), 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; HelloVulkan::ObjInstance inst;
inst.objIndex = 0; inst.objIndex = 0;
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);
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
~~~~ ~~~~
## Adding a new Closest Hit Shader ## Adding a new Closest Hit Shader
@ -60,7 +60,7 @@ This new shader needs to be added to the raytracing pipeline. So, in `createRtPi
~~~~ C++ ~~~~ C++
vk::ShaderModule chit2SM = vk::ShaderModule chit2SM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths)); nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true));
~~~~ ~~~~
Then add a new hit group group immediately after adding the first hit group: Then add a new hit group group immediately after adding the first hit group:
@ -103,7 +103,7 @@ struct sceneDesc
}; };
~~~~ ~~~~
:warning: **Note:** **Note:**
The solution will not automatically recompile the shaders after this change to `wavefront.glsl`; instead, you will need to recompile all of the SPIR-V shaders. The solution will not automatically recompile the shaders after this change to `wavefront.glsl`; instead, you will need to recompile all of the SPIR-V shaders.
### `hello_vulkan.cpp` ### `hello_vulkan.cpp`
@ -131,7 +131,7 @@ When creating the [Shader Binding Table](https://www.khronos.org/registry/vulkan
This information can be used to pass extra information to a shader, for each entry in the SBT. This information can be used to pass extra information to a shader, for each entry in the SBT.
:warning: **Note:** **Note:**
Since each entry in an SBT group must have the same size, each entry of the group has to have enough space to accommodate the largest element in the entire group. Since each entry in an SBT group must have the same size, each entry of the group has to have enough space to accommodate the largest element in the entire group.
The following diagram represents our current SBT, with the addition of some data to `HitGroup1`. As mentioned in the **note**, even if The following diagram represents our current SBT, with the addition of some data to `HitGroup1`. As mentioned in the **note**, even if
@ -184,7 +184,7 @@ void main()
} }
~~~~ ~~~~
:warning: **Note:** **Note:**
Adding a new shader requires to rerun CMake to added to the project compilation system. Adding a new shader requires to rerun CMake to added to the project compilation system.
@ -335,7 +335,7 @@ Finally, we need to add the new entry as well at the end of the buffer, reusing
pBuffer += hitSize; pBuffer += hitSize;
~~~~ ~~~~
:warning: **Note:** **Note:**
Adding entries like this can be error-prone and inconvenient for decent Adding entries like this can be error-prone and inconvenient for decent
scene sizes. Instead, it is recommended to wrap the storage of handles, data, scene sizes. Instead, it is recommended to wrap the storage of handles, data,
and size per group in a SBT utility to handle this automatically. and size per group in a SBT utility to handle this automatically.

View file

@ -39,16 +39,12 @@ extern std::vector<std::string> defaultSearchPaths;
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/pipeline_vk.hpp" #include "nvvk/pipeline_vk.hpp"
#include "nvh/alignment.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
#include "nvvk/shaders_vk.hpp" #include "nvvk/shaders_vk.hpp"
#ifndef ROUND_UP
#define ROUND_UP(v, powerOf2Alignment) (((v) + (powerOf2Alignment)-1) & ~((powerOf2Alignment)-1))
#endif
// Holding the camera matrices // Holding the camera matrices
struct CameraMatrices struct CameraMatrices
{ {
@ -197,8 +193,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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)},
@ -216,6 +212,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -242,10 +239,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices, m_alloc.createBuffer(cmdBuf, loader.m_vertices,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer = model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices, m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
@ -318,7 +317,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
auto imgSize = vk::Extent2D(1, 1); auto imgSize = vk::Extent2D(1, 1);
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the dummy texure // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
@ -336,7 +335,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
std::stringstream o; std::stringstream o;
int texWidth, texHeight, texChannels; int texWidth, texHeight, texChannels;
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_uc* stbi_pixels =
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
@ -558,9 +557,9 @@ void HelloVulkan::createPostPipeline()
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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, 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();
@ -624,47 +623,43 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Converting a OBJ primitive to the ray tracing geometry used for the BLAS
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
nvvk::RaytracingBuilderKHR::Blas blas;
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles
asCreate.setMaxVertexCount(model.nbVertices);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj)); triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
// Consider the geometry opaque for optimization
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
vk::AccelerationStructureBuildOffsetInfoKHR offset;
vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -672,7 +667,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod
void HelloVulkan::createBottomLevelAS() void HelloVulkan::createBottomLevelAS()
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(m_objModel.size()); allBlas.reserve(m_objModel.size());
for(const auto& obj : m_objModel) for(const auto& obj : m_objModel)
{ {
@ -758,16 +753,15 @@ void HelloVulkan::createRtPipeline()
vk::ShaderModule raygenSM = vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM = vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); 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 = vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -794,10 +788,10 @@ void HelloVulkan::createRtPipeline()
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
vk::ShaderModule chit2SM = vk::ShaderModule chit2SM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths)); 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,
@ -836,10 +830,10 @@ void HelloVulkan::createRtPipeline()
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
rayPipelineInfo.setLayout(m_rtPipelineLayout); rayPipelineInfo.setLayout(m_rtPipelineLayout);
m_rtPipeline = m_rtPipeline = static_cast<const vk::Pipeline&>(
static_cast<const vk::Pipeline&>(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
m_device.destroy(raygenSM); m_device.destroy(raygenSM);
m_device.destroy(missSM); m_device.destroy(missSM);
@ -859,14 +853,15 @@ 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()); // 3 shaders: raygen, 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 groupAlignSize = m_rtProperties.shaderGroupBaseAlignment; uint32_t groupSizeAligned = m_rtProperties.shaderGroupBaseAlignment;
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * groupAlignSize; uint32_t sbtSize = groupCount * groupSizeAligned;
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
assert(result == vk::Result::eSuccess);
// Retrieve the handle pointers // Retrieve the handle pointers
std::vector<uint8_t*> handles(groupCount); std::vector<uint8_t*> handles(groupCount);
@ -876,10 +871,10 @@ void HelloVulkan::createRtShaderBindingTable()
} }
// Sizes // Sizes
uint32_t rayGenSize = groupAlignSize; uint32_t rayGenSize = groupSizeAligned;
uint32_t missSize = groupAlignSize; uint32_t missSize = groupSizeAligned;
uint32_t hitSize = uint32_t hitSize =
ROUND_UP(groupHandleSize + static_cast<int>(sizeof(HitRecordBuffer)), groupAlignSize); nvh::align_up(groupHandleSize + static_cast<int>(sizeof(HitRecordBuffer)), groupSizeAligned);
uint32_t newSbtSize = rayGenSize + 2 * missSize + 3 * hitSize; uint32_t newSbtSize = rayGenSize + 2 * missSize + 3 * hitSize;
std::vector<uint8_t> sbtBuffer(newSbtSize); std::vector<uint8_t> sbtBuffer(newSbtSize);
@ -915,7 +910,9 @@ void HelloVulkan::createRtShaderBindingTable()
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, vk::BufferUsageFlagBits::eRayTracingKHR); m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer,
vk::BufferUsageFlagBits::eShaderDeviceAddressKHR
| vk::BufferUsageFlagBits::eShaderBindingTableKHR);
m_debug.setObjectName(m_rtSBTBuffer.buffer, "SBT"); m_debug.setObjectName(m_rtSBTBuffer.buffer, "SBT");
@ -946,26 +943,25 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
| vk::ShaderStageFlagBits::eMissKHR, | vk::ShaderStageFlagBits::eMissKHR,
0, m_rtPushConstants); 0, m_rtPushConstants);
vk::DeviceSize handleSize = m_rtProperties.shaderGroupHandleSize;
vk::DeviceSize alignSize = m_rtProperties.shaderGroupBaseAlignment;
vk::DeviceSize rayGenOffset = 0u * alignSize; // Start at the beginning of m_sbtBuffer // Size of a program identifier
vk::DeviceSize missOffset = 1u * alignSize; // Jump over raygen uint32_t groupSize =
vk::DeviceSize hitGroupOffset = 3u * alignSize; // Jump over the previous shaders nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceSize sbtSize = alignSize * (vk::DeviceSize)m_rtShaderGroups.size(); uint32_t groupStride = groupSize;
vk::DeviceSize hitGroupSize =
nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer),
m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
vk::DeviceSize hitGroupStride = ROUND_UP(handleSize + sizeof(HitRecordBuffer), alignSize); using Stride = vk::StridedDeviceAddressRegionKHR;
std::array<Stride, 4> strideAddresses{
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
Stride{sbtAddress + 3u * groupSize, hitGroupSize, hitGroupSize * 3}, // hit
Stride{0u, 0u, 0u}}; // callable
// m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, &strideAddresses[3], //
handleSize, sbtSize};
const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset,
handleSize, sbtSize};
const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset,
hitGroupStride, sbtSize};
const vk::StridedBufferRegionKHR callableShaderBindingTable;
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable,
&callableShaderBindingTable, //
m_size.width, m_size.height, 1); // m_size.width, m_size.height, 1); //

View file

@ -134,7 +134,7 @@ public:
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
void createRtDescriptorSet(); void createRtDescriptorSet();
@ -144,7 +144,7 @@ public:
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; vk::DescriptorPool m_rtDescPool;

View file

@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "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"
@ -60,19 +61,16 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1; ImGuiH::CameraWidget();
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up;
CameraManip.getLookat(pos, eye, up);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
}
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f);
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); 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);
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -114,20 +112,17 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media NVPSystem::exePath() + "..",
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Enabling the extension feature
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature;
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 #ifdef WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
@ -141,11 +136,17 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -165,7 +166,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -174,14 +175,14 @@ int main(int argc, char** argv)
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths), 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; HelloVulkan::ObjInstance inst;
inst.objIndex = 0; inst.objIndex = 0;
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);
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.m_objInstance[0].hitgroup = 1; helloVk.m_objInstance[0].hitgroup = 1;
helloVk.m_objInstance[1].hitgroup = 2; helloVk.m_objInstance[1].hitgroup = 2;
helloVk.m_hitShaderRecord.resize(2); helloVk.m_hitShaderRecord.resize(2);
@ -230,15 +231,17 @@ int main(int argc, char** argv)
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render(); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// Start rendering the scene // Start rendering the scene
@ -291,6 +294,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
helloVk.drawPost(cmdBuff); helloVk.drawPost(cmdBuff);
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

View file

@ -1,32 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
Project(${PROJNAME})
Message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:")
##################################################################################### #--------------------------------------------------------------------------------------------------
_add_project_definitions(${PROJNAME}) # C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#####################################################################################
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
SET(VULKAN_TARGET_ENV vulkan1.2) SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.vert" "shaders/*.vert"
"shaders/*.rchit" "shaders/*.rchit"
"shaders/*.rahit" "shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss" "shaders/*.rmiss"
"shaders/*.rgen" "shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES}) foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -47,7 +47,7 @@ You can safely remove all raytrace.* shaders
## Support for Fragment shader ## Support for Fragment shader
In `HelloVulkan::createDescriptorSetLayout`, add the acceleration structure to the description layout. In `HelloVulkan::createDescriptorSetLayout`, add the acceleration structure to the description layout to have access to the acceleration structure directly in the fragment shader.
~~~~ C++ ~~~~ C++
// The top level acceleration structure // The top level acceleration structure

View file

@ -163,7 +163,7 @@ void HelloVulkan::updateDescriptorSet()
std::vector<vk::DescriptorImageInfo> diit; std::vector<vk::DescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.push_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
@ -201,8 +201,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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)},
@ -220,6 +220,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -246,10 +247,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices, m_alloc.createBuffer(cmdBuf, loader.m_vertices,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer = model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices, m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
@ -340,9 +343,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
std::stringstream o; std::stringstream o;
int texWidth, texHeight, texChannels; int texWidth, texHeight, texChannels;
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); 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}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -554,9 +558,9 @@ void HelloVulkan::createPostPipeline()
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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, 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();
@ -620,55 +624,47 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Converting a OBJ primitive to the ray tracing geometry used for the BLAS
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
// Setting up the creation info of acceleration structure
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles
asCreate.setMaxVertexCount(model.nbVertices);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
// Building part // Building part
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj)); triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
// Setting up the build info of the acceleration // Setting up the build info of the acceleration
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
// The primitive itself // The primitive itself
vk::AccelerationStructureBuildOffsetInfoKHR offset; vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
// Our blas is only one geometry, but could be made of many geometries // Our blas is only one geometry, but could be made of many geometries
nvvk::RaytracingBuilderKHR::Blas blas; nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
@ -680,7 +676,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod
void HelloVulkan::createBottomLevelAS() void HelloVulkan::createBottomLevelAS()
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(m_objModel.size()); allBlas.reserve(m_objModel.size());
for(const auto& obj : m_objModel) for(const auto& obj : m_objModel)
{ {

View file

@ -133,10 +133,10 @@ public:
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
}; };

View file

@ -39,6 +39,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "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"
@ -63,19 +64,16 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1; ImGuiH::CameraWidget();
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up;
CameraManip.getLookat(pos, eye, up);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
}
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f);
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); 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);
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -117,20 +115,16 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Enabling the extension feature
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature;
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 #ifdef WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
@ -142,11 +136,16 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_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 // Creating Vulkan base application
@ -168,7 +167,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -177,8 +176,8 @@ int main(int argc, char** argv)
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
helloVk.createDescriptorSetLayout(); helloVk.createDescriptorSetLayout();
@ -220,14 +219,16 @@ int main(int argc, char** argv)
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render(); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// Start rendering the scene // Start rendering the scene
@ -275,6 +276,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
helloVk.drawPost(cmdBuff); helloVk.drawPost(cmdBuff);
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

View file

@ -1,32 +1,38 @@
cmake_minimum_required(VERSION 2.8) #*****************************************************************************
# 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) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) SET(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:")
Project(${PROJNAME})
Message(STATUS "-------------------------------")
Message(STATUS "Processing Project ${PROJNAME}:")
##################################################################################### #--------------------------------------------------------------------------------------------------
_add_project_definitions(${PROJNAME}) # C++ target and defines
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJNAME})
target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}")
#####################################################################################
#--------------------------------------------------------------------------------------------------
# Source files for this project # Source files for this project
# #
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
file(GLOB EXTRA_COMMON "../common/*.*") file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories("../common") include_directories(${TUTO_KHR_DIR}/common)
##################################################################################### #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
# #
# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES)
# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main())
#_compile_GLSL(<source(s)> <target spv> <LIST where files are appended>)
SET(VULKAN_TARGET_ENV vulkan1.2) SET(VULKAN_TARGET_ENV vulkan1.2)
UNSET(GLSL_SOURCES) UNSET(GLSL_SOURCES)
UNSET(SPV_OUTPUT) UNSET(SPV_OUTPUT)
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES
"shaders/*.vert" "shaders/*.vert"
"shaders/*.rchit" "shaders/*.rchit"
"shaders/*.rahit" "shaders/*.rahit"
"shaders/*.rint"
"shaders/*.rmiss" "shaders/*.rmiss"
"shaders/*.rgen" "shaders/*.rgen"
"shaders/*.rcall"
) )
foreach(GLSL ${GLSL_SOURCE_FILES}) foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME) get_filename_component(FILE_NAME ${GLSL} NAME)
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
endforeach(GLSL) endforeach(GLSL)
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
source_group(Shader_Files FILES ${GLSL_SOURCES})
##################################################################################### #--------------------------------------------------------------------------------------------------
# Executable # 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
# #
# if(WIN32 AND NOT GLUT_FOUND) source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
# add_definitions(/wd4996) #remove printf warning source_group("Sources" FILES ${SOURCE_FILES})
# add_definitions(/wd4244) #remove double to float conversion warning source_group("Headers" FILES ${HEADER_FILES})
# add_definitions(/wd4305) #remove double to float truncation warning source_group("Shader_Files" FILES ${GLSL_SOURCES})
# else()
# add_definitions(-fpermissive)
# endif()
add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES})
#_set_subsystem_console(${PROJNAME})
##################################################################################### #--------------------------------------------------------------------------------------------------
# common source code needed for this sample
#
source_group(common FILES
${COMMON_SOURCE_FILES}
${PACKAGE_SOURCE_FILES}
)
source_group("Source Files" FILES ${SOURCE_FILES})
# if(UNIX)
# set(UNIXLINKLIBS dl pthread)
# else()
# set(UNIXLINKLIBS)
# endif()
#####################################################################################
# Linkage # Linkage
# #
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
endforeach(RELEASELIB) 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} ) _copy_binaries_to_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") #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 ${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${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 Release DESTINATION "bin_${ARCH}/${PROJNAME}")
install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") #install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
#----------------------------------------------------------------------------------------------------
# Copying elements
# Media
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
# Spir-V Shaders
target_copy_to_output_dir(
TARGET ${PROJECT_NAME}
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
DEST_SUBFOLDER "${PROJECT_NAME}/"
FILES ${SPV_OUTPUT}
)

View file

@ -12,14 +12,14 @@ First, we will create a scene with two reflective planes and a multicolored cube
~~~~ C++ ~~~~ C++
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths), helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true),
nvmath::translation_mat4(nvmath::vec3f(-2, 0, 0)) nvmath::translation_mat4(nvmath::vec3f(-2, 0, 0))
* nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f))); * nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f)));
helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths), helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true),
nvmath::translation_mat4(nvmath::vec3f(2, 0, 0)) nvmath::translation_mat4(nvmath::vec3f(2, 0, 0))
* nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f))); * nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f)));
helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths), helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true),
nvmath::translation_mat4(nvmath::vec3f(0, -1, 0))); nvmath::translation_mat4(nvmath::vec3f(0, -1, 0)));
~~~~ ~~~~
@ -44,7 +44,7 @@ Vulkan ray tracing allows recursive calls to traceRayEXT, up to a limit defined
In `createRtPipeline()` in `hello_vulkan.cpp`, bring the maximum recursion depth up to 10, making sure not to exceed the physical device's maximum recursion limit: In `createRtPipeline()` in `hello_vulkan.cpp`, bring the maximum recursion depth up to 10, making sure not to exceed the physical device's maximum recursion limit:
~~~~ C++ ~~~~ C++
rayPipelineInfo.setMaxRecursionDepth( rayPipelineInfo.setMaxPipelineRayRecursionDepth(
std::max(10u, m_rtProperties.maxRecursionDepth)); // Ray depth std::max(10u, m_rtProperties.maxRecursionDepth)); // Ray depth
~~~~ ~~~~
@ -203,7 +203,7 @@ Since the ray generation shader now handles attenuation, we no longer need to at
Finally, we no longer need to have a deep recursion setting in `createRtPipeline` -- just a depth of 2, one for the initial ray generation segment and another for shadow rays. Finally, we no longer need to have a deep recursion setting in `createRtPipeline` -- just a depth of 2, one for the initial ray generation segment and another for shadow rays.
~~~~ C++ ~~~~ C++
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
~~~~ ~~~~
In `raytrace.rgen`, we can now make the maximum ray depth significantly larger -- such as 100, for instance -- without causing a device lost error. In `raytrace.rgen`, we can now make the maximum ray depth significantly larger -- such as 100, for instance -- without causing a device lost error.
@ -246,9 +246,9 @@ Then test for the value for when to stop
break; break;
~~~~ ~~~~
Finally, in `main.cpp` in the `renderUI` function, we will add a slider to control the value. Finally, in `main.cpp` after the `renderUI()` function call, we will add a slider to control the depth value.
~~~~ C++ ~~~~ C++
ImGui::SliderInt("Max Depth", &helloVk.m_rtPushConstants.maxDepth, 1, 100); ImGui::SliderInt("Max Depth", &helloVk.m_rtPushConstants.maxDepth, 1, 50);
~~~~ ~~~~

View file

@ -39,6 +39,7 @@ extern std::vector<std::string> defaultSearchPaths;
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/pipeline_vk.hpp" #include "nvvk/pipeline_vk.hpp"
#include "nvh/alignment.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
@ -193,8 +194,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), vkSS::eVertex); gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); gpb.addShader(nvh::loadFile("shaders/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)},
@ -212,6 +213,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -238,10 +240,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = model.vertexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_vertices, m_alloc.createBuffer(cmdBuf, loader.m_vertices,
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.indexBuffer = model.indexBuffer =
m_alloc.createBuffer(cmdBuf, loader.m_indices, m_alloc.createBuffer(cmdBuf, loader.m_indices,
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
@ -314,7 +318,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
auto imgSize = vk::Extent2D(1, 1); auto imgSize = vk::Extent2D(1, 1);
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the dummy texure // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
@ -332,9 +336,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
std::stringstream o; std::stringstream o;
int texWidth, texHeight, texChannels; int texWidth, texHeight, texChannels;
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); 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}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -553,9 +558,9 @@ void HelloVulkan::createPostPipeline()
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), pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true),
vk::ShaderStageFlagBits::eVertex); vk::ShaderStageFlagBits::eVertex);
pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, 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();
@ -619,47 +624,43 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, auto properties =
vk::PhysicalDeviceRayTracingPropertiesKHR>(); m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPropertiesKHR>(); vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Converting a OBJ primitive to the ray tracing geometry used for the BLAS
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
nvvk::RaytracingBuilderKHR::Blas blas;
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate;
asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles);
asCreate.setIndexType(vk::IndexType::eUint32);
asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat);
asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles
asCreate.setMaxVertexCount(model.nbVertices);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
triangles.setVertexFormat(asCreate.vertexFormat); triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress); triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj)); triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(asCreate.indexType); triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress); triangles.setIndexData(indexAddress);
triangles.setTransformData({}); triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
vk::AccelerationStructureGeometryKHR asGeom; vk::AccelerationStructureGeometryKHR asGeom;
asGeom.setGeometryType(asCreate.geometryType); asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
// Consider the geometry opaque for optimization
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
asGeom.geometry.setTriangles(triangles); asGeom.geometry.setTriangles(triangles);
vk::AccelerationStructureBuildOffsetInfoKHR offset;
vk::AccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.setFirstVertex(0);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
offset.setPrimitiveOffset(0); offset.setPrimitiveOffset(0);
offset.setTransformOffset(0); offset.setTransformOffset(0);
nvvk::RaytracingBuilderKHR::BlasInput blas;
blas.asGeometry.emplace_back(asGeom); blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset); blas.asBuildOffsetInfo.emplace_back(offset);
return blas; return blas;
} }
@ -667,7 +668,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod
void HelloVulkan::createBottomLevelAS() void HelloVulkan::createBottomLevelAS()
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(m_objModel.size()); allBlas.reserve(m_objModel.size());
for(const auto& obj : m_objModel) for(const auto& obj : m_objModel)
{ {
@ -753,16 +754,15 @@ void HelloVulkan::createRtPipeline()
vk::ShaderModule raygenSM = vk::ShaderModule raygenSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
vk::ShaderModule missSM = vk::ShaderModule missSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); 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 = vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
nvvk::createShaderModule(m_device, m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths));
std::vector<vk::PipelineShaderStageCreateInfo> stages; std::vector<vk::PipelineShaderStageCreateInfo> stages;
@ -789,7 +789,7 @@ void HelloVulkan::createRtPipeline()
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
vk::ShaderModule chitSM = vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); 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,
@ -824,10 +824,10 @@ void HelloVulkan::createRtPipeline()
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
rayPipelineInfo.setLayout(m_rtPipelineLayout); rayPipelineInfo.setLayout(m_rtPipelineLayout);
m_rtPipeline = m_rtPipeline = static_cast<const vk::Pipeline&>(
static_cast<const vk::Pipeline&>(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
m_device.destroy(raygenSM); m_device.destroy(raygenSM);
m_device.destroy(missSM); m_device.destroy(missSM);
@ -846,18 +846,23 @@ 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()); // 3 shaders: raygen, 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 baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment uint32_t groupSizeAligned =
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * baseAlignment; uint32_t sbtSize = groupCount * groupSizeAligned;
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
assert(result == vk::Result::eSuccess);
// Write the handles in the SBT // Write the handles in the SBT
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, m_rtSBTBuffer = m_alloc.createBuffer(
vk::MemoryPropertyFlagBits::eHostVisible sbtSize,
| vk::MemoryPropertyFlagBits::eHostCoherent); vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR
| vk::BufferUsageFlagBits::eShaderBindingTableKHR,
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
// Write the handles in the SBT // Write the handles in the SBT
@ -866,7 +871,7 @@ void HelloVulkan::createRtShaderBindingTable()
for(uint32_t g = 0; g < groupCount; g++) for(uint32_t g = 0; g < groupCount; g++)
{ {
memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
pData += baseAlignment; pData += groupSizeAligned;
} }
m_alloc.unmap(m_rtSBTBuffer); m_alloc.unmap(m_rtSBTBuffer);
@ -894,25 +899,22 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
| vk::ShaderStageFlagBits::eMissKHR, | vk::ShaderStageFlagBits::eMissKHR,
0, m_rtPushConstants); 0, m_rtPushConstants);
vk::DeviceSize progSize = // Size of a program identifier
m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier uint32_t groupSize =
vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen uint32_t groupStride = groupSize;
vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size();
// m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... using Stride = vk::StridedDeviceAddressRegionKHR;
const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, std::array<Stride, 4> strideAddresses{
progSize, sbtSize}; Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
progSize, sbtSize}; Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit
const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, Stride{0u, 0u, 0u}}; // callable
progSize, sbtSize};
const vk::StridedBufferRegionKHR callableShaderBindingTable; cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, &strideAddresses[3], //
&callableShaderBindingTable, //
m_size.width, m_size.height, 1); // m_size.width, m_size.height, 1); //
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }

View file

@ -133,7 +133,7 @@ public:
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
void createRtDescriptorSet(); void createRtDescriptorSet();
@ -143,7 +143,7 @@ public:
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; vk::DescriptorPool m_rtDescPool;

View file

@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "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"
@ -61,20 +62,16 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
static int item = 1; ImGuiH::CameraWidget();
if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) if(ImGui::CollapsingHeader("Light"))
{ {
nvmath::vec3f pos, eye, up;
CameraManip.getLookat(pos, eye, up);
up = nvmath::vec3f(item == 0, item == 1, item == 2);
CameraManip.setLookat(pos, eye, up);
}
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f);
ImGui::SliderInt("Max Depth", &helloVk.m_rtPushConstants.maxDepth, 1, 100);
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); 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);
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -116,20 +113,17 @@ int main(int argc, char** argv)
// Search path for shaders and other media // Search path for shaders and other media
defaultSearchPaths = { defaultSearchPaths = {
PROJECT_ABSDIRECTORY, // shaders NVPSystem::exePath(),
PROJECT_ABSDIRECTORY "../", // media NVPSystem::exePath() + "..",
PROJECT_NAME, // installed: shaders + media
NVPSystem::exePath() + std::string(PROJECT_NAME), NVPSystem::exePath() + std::string(PROJECT_NAME),
}; };
// Enabling the extension feature
vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature;
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 #ifdef WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
@ -143,11 +137,17 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -167,7 +167,7 @@ int main(int argc, char** argv)
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
vkctx.m_queueGCT.familyIndex); vkctx.m_queueGCT.familyIndex);
helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
helloVk.createFrameBuffers(); helloVk.createFrameBuffers();
@ -176,15 +176,14 @@ int main(int argc, char** argv)
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creation of the example // Creation of the example
// Creation of the example helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true),
helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths),
nvmath::translation_mat4(nvmath::vec3f(-2, 0, 0)) nvmath::translation_mat4(nvmath::vec3f(-2, 0, 0))
* nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f))); * nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f)));
helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths), helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true),
nvmath::translation_mat4(nvmath::vec3f(2, 0, 0)) nvmath::translation_mat4(nvmath::vec3f(2, 0, 0))
* nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f))); * nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f)));
helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths), helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true),
nvmath::translation_mat4(nvmath::vec3f(0, -1, 0))); nvmath::translation_mat4(nvmath::vec3f(0, -1, 0)));
@ -230,15 +229,18 @@ int main(int argc, char** argv)
helloVk.updateUniformBuffer(); helloVk.updateUniformBuffer();
// Show UI window. // Show UI window.
if(1 == 1) if(helloVk.showGui())
{ {
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::SliderInt("Max Depth", &helloVk.m_rtPushConstants.maxDepth, 1, 50);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Render(); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
} }
// Start rendering the scene // Start rendering the scene
@ -291,6 +293,7 @@ int main(int argc, char** argv)
// Rendering tonemapper // Rendering tonemapper
helloVk.drawPost(cmdBuff); helloVk.drawPost(cmdBuff);
// Rendering UI // Rendering UI
ImGui::Render();
ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData());
cmdBuff.endRenderPass(); cmdBuff.endRenderPass();
} }

50
utilities.cmake Normal file
View file

@ -0,0 +1,50 @@
# -------------------------------------------------------------------------------------------------
# function that copies a list of files into the target directory
#
# target_copy_to_output_dir(TARGET foo
# [RELATIVE <path_prefix>] # allows to keep the folder structure starting from this level
# FILES <absolute_file_path> [<absolute_file_path>]
# )
#
function(TARGET_COPY_TO_OUTPUT_DIR)
set(options)
set(oneValueArgs TARGET RELATIVE DEST_SUBFOLDER)
set(multiValueArgs FILES)
cmake_parse_arguments(TARGET_COPY_TO_OUTPUT_DIR "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
foreach(_ELEMENT ${TARGET_COPY_TO_OUTPUT_DIR_FILES} )
# handle absolute and relative paths
if(TARGET_COPY_TO_OUTPUT_DIR_RELATIVE)
set(_SOURCE_FILE ${TARGET_COPY_TO_OUTPUT_DIR_RELATIVE}/${_ELEMENT})
set(_FOLDER_PATH ${_ELEMENT})
else()
set(_SOURCE_FILE ${_ELEMENT})
get_filename_component(_FOLDER_PATH ${_ELEMENT} NAME)
set (_ELEMENT "")
endif()
# handle directories and files slightly different
if(IS_DIRECTORY ${_SOURCE_FILE})
if(MDL_LOG_FILE_DEPENDENCIES)
MESSAGE(STATUS "- folder to copy: ${_SOURCE_FILE}")
endif()
add_custom_command(
TARGET ${TARGET_COPY_TO_OUTPUT_DIR_TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${_SOURCE_FILE} $<TARGET_FILE_DIR:${TARGET_COPY_TO_OUTPUT_DIR_TARGET}>/${TARGET_COPY_TO_OUTPUT_DIR_DEST_SUBFOLDER}${_FOLDER_PATH}
)
else()
if(MDL_LOG_FILE_DEPENDENCIES)
MESSAGE(STATUS "- file to copy: ${_SOURCE_FILE}")
endif()
add_custom_command(
TARGET ${TARGET_COPY_TO_OUTPUT_DIR_TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_SOURCE_FILE} $<TARGET_FILE_DIR:${TARGET_COPY_TO_OUTPUT_DIR_TARGET}>/${TARGET_COPY_TO_OUTPUT_DIR_DEST_SUBFOLDER}${_ELEMENT}
)
endif()
endforeach()
endfunction()